QueryInterface

 (Available in 01 TS COM - TS_COM_IUnknown)

Purpose

CALLBACK: Query the COM interface

Syntax

IF TS_Succeeded( oInterfaseSafe:QueryInterface( pGUID, poAIUnknown ) )

Arguments

pstruIID
_WinGUID
poAIUnknown
TS_AbstractIUnknown PTR

Description

See MSDN documentation and/or 'Inside COM', it is adviced not to use this method and use 'AGetInterface()' instead.

MSDN ==== IUnknown::QueryInterface Returns a pointer to a specified interface on an object to which a client currently holds an interface pointer. This function must call IUnknown::AddRef on the pointer it returns.

HRESULT QueryInterface( REFIID iid, //Identifier of the requested interface void ** ppvObject //Address of output variable that receives the //interface pointer requested in iid );

Parameters iid [in] Identifier of the interface being requested.

ppvObject [out] Address of pointer variable that receives the interface pointer requested in riid. Upon successful return, *ppvObject contains the requested interface pointer to the object. If the object does not support the interface specified in iid, *ppvObject is set to NULL.

Return Value S_OK if the interface is supported, E_NOINTERFACE if not.

Remarks The QueryInterface method gives a client access to other interfaces on an object.

For any one object, a specific query for the IUnknown interface on any of the object's interfaces must always return the same pointer value. This allows a client to determine whether two pointers point to the same component by calling QueryInterface on both and comparing the results. It is specifically not the case that queries for interfaces (even the same interface through the same pointer) must return the same pointer value.

There are four requirements for implementations of QueryInterface (In these cases, "must succeed" means "must succeed barring catastrophic failure."):

1) The set of interfaces accessible on an object through IUnknown::QueryInterface must be static, not dynamic. This means that if a call to QueryInterface for a pointer to a specified interface succeeds the first time, it must succeed again, and if it fails the first time, it must fail on all subsequent queries.

2) It must be reflexive - if a client holds a pointer to an interface on an object, and queries for that interface, the call must succeed.

3) It must be symmetric - if a client holding a pointer to one interface queries successfully for another, a query through the obtained pointer for the first interface must succeed.

4) It must be transitive - if a client holding a pointer to one interface queries successfully for a second, and through that pointer queries successfully for a third interface, a query for the first interface through the pointer for the third interface must succeed.

Notes to Implementers Implementations of QueryInterface must never check ACLs. The main reason for this rule is because COM requires that an object supporting a particular interface always return success when queried for that interface. Another reason is that checking ACLs on QueryInterface does not provide any real security because any client who has access to a particular interface can hand it directly to another client without any calls back to the server. Also, because COM caches interface pointers, it does not call QueryInterface on the server every time a client does a query.

Returns

HResult

Source

METHOD QueryInterface( pstruIID AS _WinGUID, poAIUnknown AS TS_AbstractIUnknown PTR  ; ...
...) AS LONG PASCAL CLASS TS_IUnknown
LOCAL oCOMGlobalData AS _TS_COMGlobalData
LOCAL hResult AS LONG
   TSTrace Enter
   oCOMGlobalData:=_TS_ModuleGetCOMGlobalData( )
   IF TS_ValidQueryInterfaceRequest( SELF, pstruIID, poAIUnknown, @hResult )
      #IFDEF TS_COMGLOBALDATA_CRITICALSECTION
         EnterCriticalSection( oCOMGlobalData:_COMGGeneralPurposeSection  ; ...
        ... )
      #ENDIF
      IF SELF:_OuterAIUnknown<>NULL_OBJECT
         hResult:=SELF:_StandardQueryInterface( pstruIID, poAIUnknown  ; ...
        ... )
         DO CASE
         CASE hResult==E_FAIL
            OBJECT( PTR( _CAST, poAIUnknown ) ):=NULL_OBJECT
            hResult:=E_NOINTERFACE
         CASE hResult==E_NOINTERFACE
            #IFDEF TS_TRACETIMED_ENABLE
               _TS_TraceTimedEnter( TS_TT_SYM_EXTERNAL, TS_TT_SYM_OUTERAIUNKNOWN,  ; ...
              ... #QueryInterface )
            #ENDIF
            hResult:=SELF:_OuterAIUnknown:QueryInterface ; ...
           ... ( pstruIID, poAIUnknown )
            #IFDEF TS_TRACETIMED_ENABLE
               _TS_TraceTimedLeave( TS_TT_SYM_EXTERNAL, TS_TT_SYM_OUTERAIUNKNOWN,  ; ...
              ... #QueryInterface )
            #ENDIF
         END
      ELSE
         hResult:=SELF:_InternalQueryInterface( pstruIID, poAIUnknown  ; ...
        ... )
      END
      #IFDEF TS_COMGLOBALDATA_CRITICALSECTION
         LeaveCriticalSection( oCOMGlobalData:_COMGGeneralPurposeSection  ; ...
        ... )
      #ENDIF
   END
   TSTrace Leave
RETURN hResult