📄 cenumvar.asm
字号:
;--------------------------------------------------------------------------
; IEnumVariant implimentation
;
; this interface is meant to be a general purpose enumeration object.
; The object is created with a pointer to it's custom data list.
;--------------------------------------------------------------------------
; Implimentors data:
; the following items must be included in the implimentor's files:
;
; USEAGE:
;
; ; create an enumerator object
; invoke AllocObject, ADDR pIEnum, pObjectItem, NULL, ADDR pItemList
;
; pItemList referes to a IEnumVariantListHeader struct, followed by a
; series of variant types.
;
; EXAMPLE:
;
;IEnumVariantListHeader STRUCT
; cListSize DWORD 0 ; size of list in bytes
; ElementSize DWORD SIZEOF VARIANT ; size of one element in bytes
; cItems DWORD 0 ; size of list in elements
;IEnumVariantListHeader ENDS
; element1 VARTANT { }
; element2 VARTANT { }
; ...
; elementN VARTANT { }
;
;
;--------------------------------------------------------------------------
.NOLIST
.386
.model flat, stdcall ; 32 bit memory model
option casemap :none ; case sensitive
;--------------------------------------------------------------------------
include \masm32\include\windows.inc
include \masm32\include\oleaut32.inc
include \masm32\include\ole32.inc
include \masm32\include\masm32.inc
include \masm32\include\kernel32.inc
include \masm32\COM\include\oaidl.inc
include \masm32\COM\include\colib.inc
include cEnumVar.inc
PUBLIC EnumVariantClassItem
PUBLIC IID_IEnumVARIANT
PUBLIC vtIEnumVariant
PUBLIC IEnumVariantIMap
;--------------------------------------------------------------------------
.data
DeclareGuid IID_IEnumVARIANT
EnumVariantClassItem _EnumVariantClassItem { }
IEnumVariantIMap InterfaceItem {pIID_IEnumVARIANT, OFFSET vtIEnumVariant}
END_INTERFACE_MAP
vtIEnumVariant IEnumVariant { AddRef, Release, QueryInterface, , , , }
;--------------------------------------------------------------------------
.code
;--------------------------------------------------------------------------
; IEnumVariant implimentation
;--------------------------------------------------------------------------
CreateIEnumVariant PROC PUBLIC this_, pCustomData:DWORD
; Need to point our list
; to the correct place (**List in pCustomData)
pObjectData this_, ecx ; keep pData in ecx
mov eax, pCustomData
mov (IEnumVariantData PTR [ecx]).m_ppList, eax
; we use a 1-based list to keep automation script controllers happy
; (we also use NULL to indicate a bad list pointer)
; so reset the count
mov (IEnumVariantData PTR [ecx]).m_cCurrent, 1
xor eax, eax
ret
CreateIEnumVariant ENDP
;--------------------------------------------------------------------------
IEnumVariant_Clone PROC PUBLIC this_:DWORD, ppen:DWORD
LOCAL pData:DWORD, pClassItem:DWORD, pCustomData:DWORD, pObj:DWORD
; Creates another connection point enumerator with the same state
; as the current enumerator to iterate over the same list.
; walk to get the ClassItem reference
pObjectBase this_, ecx ; ref to the rairly used Object Data struct
mov eax, (ObjectData PTR[ecx]).m_pClassItem
mov pClassItem, eax
pObjectData this_, ecx ; keep pData in ecx
mov pData, eax
mov eax, (IEnumVariantData PTR[ecx]).m_ppList
mov pCustomData, eax
; create a brand-new object of our type
; it's identicle except for the internal count state
; because it's created as count = 1
invoke AllocObject, ppen, pClassItem, NULL, pCustomData
.IF_SUCCEEDED
; now we need to set the count to ours
mov ecx, pData
mov ecx, (IEnumVariantData PTR[ecx]).m_cCurrent
mov edx, ppen
mov edx, [edx]
mov pObj, edx ; put object reference where we can use it
coinvoke pObj, IEnumVariant, Skip, ecx
xor eax, eax ; return S_OK
;ELSE
; AllocObject failed, just return the same fauling retval
.ENDIF
ret
IEnumVariant_Clone ENDP
;--------------------------------------------------------------------------
IEnumVariant_Next PROC PUBLIC this_:DWORD, celt:DWORD,
rgelt:DWORD, pceltFetched:DWORD
LOCAL pNewList:DWORD, pData:DWORD, pListHeader:DWORD,pList:DWORD
LOCAL cCopyItems:DWORD, cCopyBytes:DWORD,pCurrentItem:DWORD
LOCAL retval:DWORD
; celt The number of elements to retrieve.
; rgelt The elements retrieved.
; pceltFetched The actual number of elements retrieved.
; cCopyBytes: count of bytes to return (sizeof DataCopy)
; cCopyItems: count of items to return
; pNewList: ptr to newly created heap for return params
; pCurrentItem: ptr to existing cCount item in list
; pData: ptr to object data area
; pListHeader: ptr to list of variants (header)
; pList: ptr to list of variants itself
; retval: holds the return val
;
; Retrieves the next celt items in the enumeration sequence.
; If there are fewer than the requested number of elements left
; in the sequence, it retrieves the remaining elements.
;
; The number of elements actually retrieved is returned through
; pceltFetched (unless the caller passed in NULL for that parameter),
; pointer to the number of elements actually supplied in rgelt.
; Caller can pass in NULL if celt is one.
;
; Return Value
; S_OK if the number of elements supplied is celt
; E_POINTER for the various pointer errors
; S_FALSE otherwise.
; pointer check
.IF !pceltFetched
.IF celt != 1
; pceltFetched may be = NULL only if celt = 1
mov eax, E_POINTER
ret
.ENDIF
.ENDIF
.IF !rgelt
; rgelt may be not be NULL
mov eax, E_POINTER
ret
.ENDIF
mov retval, S_OK
pObjectData this_, ecx ; keep pData in ecx
mov pData, ecx
mov eax, (IEnumVariantData PTR [ecx]).m_cCurrent
.IF eax == NULL
; we're all done, list pointer already beyond end of list
mov ecx, pceltFetched
xor eax, eax
mov [ecx], eax ; zero the rgelt return count
mov ecx, rgelt
mov [ecx], eax ; be nice, null the return pointer
mov eax, S_FALSE
ret
.ENDIF
; OK, so let's go to work
; get the list reference
mov ecx, pData
mov edx, (IEnumVariantData PTR [ecx]).m_ppList
mov edx, [edx] ; defererence the pointer (now have address of list itself in edx)
; and save them
mov pListHeader, edx
mov pList, edx
add pList, SIZEOF IEnumVariantListHeader
mov eax, celt
add eax, (IEnumVariantData PTR [ecx]).m_cCurrent
dec eax
mov ecx, (IEnumVariantListHeader PTR [edx]).cItems
.IF eax > ecx
; nope, don't have celt items left to send
; adjust the total
mov eax, (IEnumVariantListHeader PTR [edx]).cItems
mov ecx, pData
sub eax, (IEnumVariantData PTR [ecx]).m_cCurrent
inc eax
mov retval, S_FALSE
.ELSE
mov eax, celt
.ENDIF
; count in eax is now fine, use it
mov cCopyItems, eax
imul eax, SIZEOF VARIANT
mov cCopyBytes, eax
mov ecx, pData
mov eax, (IEnumVariantData PTR [ecx]).m_cCurrent
dec eax
imul eax, SIZEOF VARIANT
add eax, pList
mov pCurrentItem, eax
invoke CoTaskMemAlloc, cCopyBytes
mov pNewList, eax
mov ecx, rgelt
mov [ecx], eax ; set the rgelt returned list
invoke MemCopy, pCurrentItem, pNewList, cCopyBytes
; now increase current count
mov ecx, pData
mov eax, cCopyItems
add (IEnumVariantData PTR [ecx]).m_cCurrent, eax
; "Check for IUnk and Addref"
.WHILE cCopyItems > 0
mov ecx, pNewList
movsx eax, (VARIANT PTR [ecx]).vt
.IF (eax == VT_UNKNOWN) || (eax == VT_DISPATCH)
; oops, we got interface pointers here.
; gotta AddRef em before we return them (Rule A3)
mov ecx, (VARIANT PTR [ecx]).punkVal
coinvoke ecx, IUnknown, AddRef
.ENDIF
add pNewList, SIZEOF VARIANT
dec cCopyItems
.ENDW
mov eax, retval
ret
IEnumVariant_Next ENDP
;--------------------------------------------------------------------------
IEnumVariant_Skip PROC PUBLIC this_:DWORD, celt:DWORD
LOCAL pData:DWORD
; Instructs the enumerator to skip the next cConnections elements in
; the enumeration so that the next call to IEnumVariant::Next will not
; return those elements.
pObjectData this_, ecx ; keep pData in ecx
mov pData, eax
mov eax, (IEnumVariantData PTR [ecx]).m_cCurrent
.IF eax != NULL
; get list reference
mov edx, (IEnumVariantData PTR [ecx]).m_ppList
mov edx, [edx] ; defererence the pointer (now have address of list in edx)
; bump the index by celt
mov eax, celt
add (IEnumVariantData PTR [ecx]).m_cCurrent, eax
; see if we went too far
mov eax, (IEnumVariantListHeader PTR [edx]).cListSize
mov edx, (IEnumVariantData PTR [ecx]).m_cCurrent
.IF edx > eax
; we went past the end of our list,
; set the pointer to BAD (NULL)
mov (IEnumVariantData PTR [ecx]).m_cCurrent, NULL
.ENDIF
;ELSE
; we're all done, list pointer already beyond end of list
.ENDIF
xor eax, eax ; return S_OK
ret
IEnumVariant_Skip ENDP
;--------------------------------------------------------------------------
IEnumVariant_Reset PROC PUBLIC this_:DWORD
; Instructs the enumerator to position itself at the beginning
; of the list of elements.
pObjectData this_, ecx
; we use a 1-based list to keep automation script controllers happy
mov (IEnumVariantData PTR [ecx]).m_cCurrent, 1
xor eax, eax ; return S_OK
ret
IEnumVariant_Reset ENDP
;--------------------------------------------------------------------------
;ENDIF
end ;IEnumVariantImpl
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -