;*** interface IDataObject

	.386
	.model flat, stdcall
	option casemap:none ; case sensitive
	option proc:private

	.nolist
	.nocref
	include windows.inc
	include unknwn.inc
	include objidl.inc
	include oleidl.inc
	include olectl.inc
	include oaidl.inc
	include ocidl.inc
	include CatProp.inc

	include macros.inc
	include debugout.inc
	.list
	.cref

	include control.inc

	.const


CDataObjectVtbl label IDataObjectVtbl
	dd QueryInterface_, AddRef_, Release_
	dd GetData_, GetDataHere_, QueryGetData_, GetCanonicalFormatEtc_
	dd SetData_, EnumFormatEtc_, DAdvise_, DUnadvise_, EnumDAdvise_

Create@CEnumFormatEtc proto pobj:ptr ptr CEnumFormatEtc, cFE:DWORD, prgFE:DWORD

	.code

CastOffset textequ <offset CAsmCtrl.m_IDataObject>

	@MakeIUnknownStubs CastOffset

GetData_:
	sub dword ptr [esp+4], CastOffset
GetData proc uses ebx this_:ptr objectname, pFormatetc:ptr FORMATETC, pmedium:ptr STGMEDIUM

	mov ebx,this_
ifdef _DEBUG
	mov ecx, pFormatetc
	movzx edx, [ecx].FORMATETC.cfFormat
	DebugOut "IDataObject::GetData(%X[%X, %X, %X, %X, %X], %X)",\
		ecx, edx, [ecx].FORMATETC.ptd, [ecx].FORMATETC.dwAspect,\
		[ecx].FORMATETC.lindex, [ecx].FORMATETC.tymed, pmedium
endif
	invoke GlobalAlloc, GMEM_MOVEABLE or GMEM_ZEROINIT, 16
	.if ( eax )
		pushad
		lea esi, [ebx].CAsmCtrl.m_data2
		mov edi, eax
		movsd
		movsd
		movsd
		mov eax,0a0dh
		stosd
		popad
		mov ecx, pmedium
		mov [ecx].STGMEDIUM.tymed, TYMED_HGLOBAL
		mov [ecx].STGMEDIUM.hGlobal, eax
		mov [ecx].STGMEDIUM.pUnkForRelease, NULL
		mov eax, S_OK
	.else
		mov eax, E_OUTOFMEMORY
	.endif
	ret

GetData endp


GetDataHere_:
	sub dword ptr [esp+4], CastOffset
GetDataHere proc uses ebx this_:ptr objectname, pFormatEtc:ptr FORMATETC, pmedium:ptr STGMEDIUM

	DebugOut "IDataObject::GetDataHere(%X, %X)", pFormatEtc, pmedium
	mov ebx,this_
	return DV_E_FORMATETC

GetDataHere endp


QueryGetData_:
	sub dword ptr [esp+4], CastOffset
QueryGetData proc uses ebx this_:ptr objectname, pFormatEtc:ptr FORMATETC

	DebugOut "IDataObject::QueryGetData(%X)", pFormatEtc
	mov ebx,this_
	mov ecx, pFormatEtc
	.if (!ecx )
		return DV_E_FORMATETC
	.endif
	.if ([ecx].FORMATETC.lindex != -1 )
	   return DV_E_LINDEX
	.endif
	.if ([ecx].FORMATETC.dwAspect != DVASPECT_CONTENT )
	   return DV_E_DVASPECT
	.endif
	.if ([ecx].FORMATETC.tymed != TYMED_HGLOBAL )
	   return DV_E_TYMED
	.endif
	return S_OK

QueryGetData endp


GetCanonicalFormatEtc_:
	sub dword ptr [esp+4], CastOffset
GetCanonicalFormatEtc proc uses ebx this_:ptr objectname,
		pFormatetcIn:ptr FORMATETC, pFormatetcOut:ptr FORMATETC

	mov ebx,this_
	DebugOut "IDataObject::GetCanonicalFormatEtc(%X, %X)", pFormatetcIn, pFormatetcOut
	return E_UNEXPECTED

GetCanonicalFormatEtc endp

SetData_:
	sub dword ptr [esp+4], CastOffset
SetData proc uses ebx this_:ptr objectname,
		pFormatetc:ptr FORMATETC, pmedium:ptr STGMEDIUM, fRelease:BOOL

	mov ebx,this_
	DebugOut "IDataObject::SetData(%X, %X, %u)", pFormatetc, pmedium, fRelease
	return E_NOTIMPL

SetData endp

myformat FORMATETC <CF_TEXT, NULL, DVASPECT_CONTENT,-1, TYMED_HGLOBAL>

EnumFormatEtc_:
	sub dword ptr [esp+4], CastOffset
EnumFormatEtc proc uses ebx this_:ptr objectname, dwDirection:DWORD, ppEnumFormatEtc: ptr ptr IEnumFORMATETC

	mov ebx,this_
	DebugOut "IDataObject::EnumFormatEtc(%u, %X)", dwDirection, ppEnumFormatEtc
if 1
;--- dlls may use OleRegEnumFormatEtc if they have listed their formats in the registry
;--- exes return OLE_S_USEREG instead
;	invoke OleRegEnumFormatEtc, addr CLSID_AsmCtrl, dwDirection, ppEnumFormatEtc
	invoke Create@CEnumFormatEtc, ppEnumFormatEtc, 1, offset myformat
	ret
else
	mov ecx, ppEnumFormatEtc
	mov dword ptr [ecx], NULL
	return E_NOTIMPL
endif

EnumFormatEtc endp

DAdvise_:
	sub dword ptr [esp+4], CastOffset
DAdvise proc uses ebx this_:ptr objectname, pFormatetc:ptr FORMATETC,
		advf:DWORD, pAdvSink: LPADVISESINK, pdwConnection:ptr DWORD

	mov ebx,this_
	assume ebx:ptr CAsmCtrl

	DebugOut "IDataObject::DAdvise(%X, %u, %X, %X)", pFormatetc, advf, pAdvSink, pdwConnection
	.if (![ebx].m_pDataAdviseHolder)
		invoke CreateDataAdviseHolder, addr [ebx].m_pDataAdviseHolder
	.endif
	.if ([ebx].m_pDataAdviseHolder)
		lea ecx, [ebx].m_IDataObject
		invoke vf([ebx].m_pDataAdviseHolder, IDataAdviseHolder, Advise), ecx, pFormatetc, advf, pAdvSink, pdwConnection
		ret
	.endif
	mov ecx, pdwConnection
	mov dword ptr [ecx], NULL
	return OLE_E_ADVISENOTSUPPORTED
	assume ebx:nothing

DAdvise endp

DUnadvise_:
	sub dword ptr [esp+4], CastOffset
DUnadvise proc uses ebx this_:ptr objectname, dwConnection:DWORD

	mov ebx,this_
	assume ebx:ptr CAsmCtrl

	DebugOut "IDataObject::DUnadvise(%X)", dwConnection
	.if ([ebx].m_pDataAdviseHolder)
		invoke vf([ebx].m_pDataAdviseHolder, IDataAdviseHolder, Unadvise), dwConnection
		ret
	.endif
	return OLE_E_ADVISENOTSUPPORTED
	assume ebx:nothing

DUnadvise endp

EnumDAdvise_:
	sub dword ptr [esp+4], CastOffset
EnumDAdvise proc uses ebx this_:ptr objectname, ppenumAdvise:ptr ptr IEnumSTATDATA

	mov ebx,this_
	assume ebx:ptr CAsmCtrl

	DebugOut "IDataObject::EnumDAdvise(%X)", ppenumAdvise
	.if ([ebx].m_pDataAdviseHolder)
		invoke vf([ebx].m_pDataAdviseHolder, IDataAdviseHolder, EnumAdvise), ppenumAdvise
		ret
	.endif
	mov ecx, ppenumAdvise
	mov dword ptr [ecx], NULL
	return OLE_E_ADVISENOTSUPPORTED
	assume ebx:nothing

EnumDAdvise endp

;--- IEnumFORMATETC helper interface

CEnumFormatEtc struct
m_IEnumFORMATETC IEnumFORMATETC <>
m_RefCnt   dd ?
m_iCur     dd ?	;Current element
m_cfe      dd ?	;Number of FORMATETCs
m_fe       FORMATETC 0 dup (<>)
CEnumFormatEtc ends

QueryInterface@IEnumFormatEtc proto :ptr CEnumFormatEtc, :REFIID, :ptr LPUNKNOWN
AddRef@IEnumFormatEtc proto :ptr CEnumFormatEtc
Release@IEnumFormatEtc proto :ptr CEnumFormatEtc

	.const

CEnumFormatEtcVtbl label IEnumFORMATETCVtbl
	dd QueryInterface@IEnumFormatEtc
	dd AddRef@IEnumFormatEtc
	dd Release@IEnumFormatEtc
	dd Next
	dd Skip
	dd Reset
	dd Clone

	.code

Create@CEnumFormatEtc proc uses ebx esi edi pobj:ptr ptr CEnumFormatEtc, cFE:DWORD, prgFE:DWORD

	DebugOut "Create@CEnumFormatEtc( %X, %X, %X )", pobj, cFE, prgFE
;---------------------- set *ppv to 0
	mov eax, pobj
	mov dword ptr [eax], 0
;---------------------- allocate object
	mov eax, cFE
	mov ecx,SIZEOF FORMATETC
	imul ecx
	add eax, sizeof CEnumFormatEtc
	invoke LocalAlloc, LMEM_FIXED or LMEM_ZEROINIT, eax
	.if (!eax)
;---------------------- alloc failed, so return
		mov eax, E_OUTOFMEMORY
		jmp exit
	.endif
	mov ebx, eax
	assume ebx:ptr CEnumFormatEtc
	mov [ebx].m_IEnumFORMATETC.lpVtbl, offset CEnumFormatEtcVtbl
	mov [ebx].m_RefCnt, 0
;--------------------------------- PERSONALISE
	mov [ebx].m_iCur, 0
	mov eax, cFE
	mov [ebx].m_cfe,eax

;--------------------------------- copy the array of FORMATETC
	mov ecx, sizeof FORMATETC
	imul ecx
	mov ecx, eax
	lea edi, [ebx].m_fe
	mov esi, prgFE
	cld
	rep movsb

	invoke QueryInterface@IEnumFormatEtc, ebx, addr IID_IEnumFORMATETC, pobj
	.if (eax != S_OK)
		push eax
		invoke LocalFree, ebx
		pop eax
	.endif
exit:
	DebugOut "Create@CEnumFormatEtc()=%X", eax
	ret
	assume ebx:nothing

Create@CEnumFormatEtc endp

;-----------------------------------------------------------------------------
;IUnknown methods
;
QueryInterface@IEnumFormatEtc proc this_:ptr CEnumFormatEtc, riid:REFIID, ppv:ptr LPUNKNOWN

	DebugOut "CEnumFormatEtc::QueryInterface(%X, %X)", riid, ppv
	invoke IsEqualGUID, riid, addr IID_IEnumFORMATETC
	test eax,eax
	jnz @F
	invoke IsEqualGUID, riid, addr IID_IUnknown
	test eax,eax
	jnz @F
	mov eax, ppv
	mov dword ptr [eax], NULL
	mov eax, E_NOINTERFACE
	jmp exit
@@:
	mov eax, this_
	mov ecx, ppv
	mov [ecx], eax
	invoke AddRef@IEnumFormatEtc, eax
	mov eax, S_OK
exit:
	ret

QueryInterface@IEnumFormatEtc endp

AddRef@IEnumFormatEtc proc uses ebx this_:ptr CEnumFormatEtc

	DebugOut "CEnumFormatEtc::AddRef"
	mov ebx,this_
	inc [ebx].CEnumFormatEtc.m_RefCnt
	mov eax, [ebx].CEnumFormatEtc.m_RefCnt
	ret

AddRef@IEnumFormatEtc endp


Release@IEnumFormatEtc proc uses ebx this_:ptr CEnumFormatEtc

	DebugOut "CEnumFormatEtc::Release"
	mov ebx,this_
;---------------------------- decrement the reference count
	dec [ebx].CEnumFormatEtc.m_RefCnt

;---------------------------- check to see if the reference count is zero.
;----------------------------  If it is, then destroy the object
	mov eax, [ebx].CEnumFormatEtc.m_RefCnt
	or eax, eax
	jnz @F
;---------------------------- free object data & object itself
	invoke LocalFree, ebx
@@:
	ret

Release@IEnumFormatEtc endp

;-----------------------------------------------------------------------------

;Returns the next element in the enumeration

Next proc uses ebx esi edi this_:ptr CEnumFormatEtc, cFE:DWORD, pFE:ptr FORMATETC, pulFE:ptr DWORD

local cReturn:DWORD

	DebugOut "CEnumFormatEtc::Next(%X, %X, %X)", cFE, pFE, pulFE
	mov ebx, this_
	assume ebx:ptr CEnumFormatEtc

	mov eax, pulFE
	or eax,eax
	jz @F
	mov DWORD PTR [eax],0
@@:
	mov eax, pFE
	or eax,eax
	jnz @F
	mov eax,S_FALSE
	jmp exit
@@:
	mov eax, [ebx].m_iCur
	mov ecx, [ebx].m_cfe
	cmp eax,ecx
	jb @F
	mov eax,S_FALSE 	;"eof" reached
	jmp exit
@@:
	mov cReturn, 0
	mov edi, pFE
	lea esi, [ebx].m_fe
	mov eax, [ebx].m_iCur
	mov ecx,SIZEOF FORMATETC
	imul ecx
	add esi,eax

	cld
	mov edx, [ebx].m_cfe
	.while [ebx].m_iCur < edx && cFE > 0
		mov ecx,SIZEOF FORMATETC
		rep movsb
		inc [ebx].m_iCur
		inc cReturn
		dec cFE
	.endw
	mov eax, pulFE
	or eax,eax
	jz @F
	mov ecx, cReturn
	sub ecx, cFE
	mov DWORD PTR [eax],ecx
@@:
	.if cFE
		mov eax,S_FALSE	;not all requested items were returned
	.else
		mov eax,S_OK
	.endif
exit:
	ret
	assume ebx:nothing

Next endp

;--- Skips the next n elements in the enumeration

Skip proc uses ebx this_:ptr CEnumFormatEtc, cSkip:DWORD

	DebugOut "CEnumFormatEtc::Skip(%X)", cSkip
	mov ebx, this_
	assume ebx:ptr CEnumFormatEtc

	mov eax, [ebx].m_iCur
	add eax, cSkip
	cmp eax, [ebx].m_cfe
	jb @F
	mov eax, S_FALSE
	jmp exit
@@:
	mov [ebx].m_iCur, eax
	mov eax, S_OK
exit:
	ret
	assume ebx:nothing

Skip endp

;Resets the current element index in the enumeration to zero

Reset proc this_:ptr CEnumFormatEtc
	DebugOut "CEnumFormatEtc::Reset()"
	mov eax, this_
	mov [eax].CEnumFormatEtc.m_iCur,0
	mov eax, S_OK
	ret
Reset endp

;Returns another IEnumFORMATETC with the same state as ourselves

Clone proc this_:ptr CEnumFormatEtc, ppEnum:ptr ptr IEnumFORMATETC
	DebugOut "CEnumFormatEtc::Clone(%X)", ppEnum
	mov eax, E_OUTOFMEMORY
	ret
Clone endp

	end