;-------------------------------------------------------------------------------
;  colibrary procedure NDQueryInterface
;
; -------------------------------------------------------
; This procedure was written by Ernest Murphy    9/27/00
;
; Copyright (c) 9/28/00  Ernest Murphy
; For educational use only. Any commercial re-use only by written license
;
; -------------------------------------------------------
.NOLIST
.386
.model flat, stdcall  ; 32 bit memory model
option casemap :none  ; case sensitive

include     mini_win.inc    ; 'just enough' of windows.inc (speeds build)
include     \masm32\include\ole32.inc
include     \masm32\include\oleaut32.inc
include     \masm32\COM\include\oaidl.inc
include     \masm32\COM\include\language.inc

include     colib.inc

externdef   IID_IUnknown:GUID
externdef   IID_IDispatch:GUID
PUBLIC        vtINDUnknown

.data
;-------------------------------------------------------------------------------
vtINDUnknown            IUnknown      \
                      { NDQueryInterface,
                        NDAddRef,
                        NDRelease  }


.LISTALL
.code
;-------------------------------------------------------------------------------

NDQueryInterface PROC PUBLIC this_:DWORD, iid:DWORD, ppv:DWORD

;-------------------------------------------------------------------------------
; implimentation of the non-delegated IUnknown::NDQueryInterface function
;
;  performs the NDQueryInterface function
;
; EXAMPLE:
;   coinvoke ppv, NDIUnknown, QueryInterface, ADDR iid, ADDR pv
;
; Uses: eax, ecx, edx
;
;
;-------------------------------------------------------------------------------
    LOCAL pBase:DWORD,  pClassItem:DWORD,  pIMap:DWORD
    LOCAL ICount:DWORD, pObjectEntry:DWORD, pcIMap:DWORD

    .IF !ppv
        mov ppv, 0
        mov eax, E_POINTER
        ret
    .ENDIF
    mov edx, this_                                  ; get object
    mov eax, (ObjectEntry PTR[edx]).m_pBase         ; walk to base data
                                                    ; interfaces we support
    mov pBase, eax
    invoke  IsEqualGUID, iid, pIID_IUnknown
    .IF (eax)
        ; asking for an IUnknown interface, return pUnkOuter
        mov edx, pBase
        mov eax, (ObjectData PTR[edx]).m_pUnkOuter
        mov ecx, ppv
        mov [ecx], eax
        jmp returnOK
    .ENDIF
    
    ; compute ObjectEntry0 point
    mov ecx, pBase
    mov eax, ecx
    mov edx, (ObjectData PTR[ecx]).m_pClassItem
    add eax, [edx].ClassItem.m_ObjectSize
    add eax, SIZEOF ObjectData
    mov pObjectEntry, eax

    ; check if our object support IDispatch
    mov ecx, (ObjectData PTR[ecx]).m_pClassItem
    mov pClassItem, ecx
    mov eax, (ClassItem PTR[ecx]).m_pIMap
    mov pIMap, eax
    mov pcIMap, eax
    mov eax, (ClassItem PTR[ecx]).m_Flags
    AND eax, DISPINTERFACE


    .IF (eax)
        ; check for a request for an IDispatch interface RQ, return ObjectEntry1
        invoke  IsEqualGUID, iid, pIID_IDispatch
        .IF eax
            ; IS an IDispatch request
            mov eax, pObjectEntry
            add eax, SIZEOF ObjectEntry                 ; cast to default interface
            mov ecx, ppv
            mov [ecx], eax
            jmp returnOK
        .ENDIF
    .ENDIF
    ; now we hunt thru our IMap
    mov ICount, 1
    mov ecx, pcIMap
    mov eax, (InterfaceItem PTR [ecx]).m_refiid
    .WHILE eax
        invoke  IsEqualGUID, iid, eax
        .IF !eax
            inc ICount
            ; no match, point to next element
            add pcIMap, SIZEOF InterfaceItem        ; point to next item
            mov ecx, pcIMap
            mov eax, (InterfaceItem PTR [ecx]).m_refiid
        .ELSE
            ; found a supported interface
            ; ICount indicates how far into the object we index
            mov eax, ICount
            imul eax, SIZEOF ObjectEntry
            add eax, pObjectEntry
            mov ecx, ppv
            mov [ecx], eax            
            mov edx, ppv
            mov edx, [edx]
returnOK:            
            ; inc the ref count for the new pointer *we* created
            coinvoke this_, IUnknown, AddRef
            xor eax, eax
            ret
        .ENDIF
    .ENDW
NoInterface:
    mov ecx, ppv
    mov eax, NULL
    mov [ecx], eax              ; good practice, always NULL bad pointers
                                ; in case client doesn't check the SCODE in hResult
    mov eax, E_NOINTERFACE      ; and signal interface is not supported here
    ret
NDQueryInterface ENDP
;-------------------------------------------------------------------------------

end
