CMQueryInterface

 (Available in 01 TS COM - TS_COM_DelegateIUnknown)

Purpose

Query the COM interface

Syntax

IF TS_Succeeded( oDelegateIUnknown:CMQueryInterface( 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 CMQueryInterface( pstruIID AS _WinGUID, poAIUnknown AS TS_AbstractIUnknown  ; ...
...PTR ) AS LONG PASCAL CLASS TS_DelegateIUnknown
LOCAL oCOMGlobalData AS _TS_COMGlobalData
LOCAL hResult AS LONG
   TSTrace Enter
   oCOMGlobalData:=_TS_ModuleGetCOMGlobalData( )
   #IFDEF TS_COMGLOBALDATA_CRITICALSECTION
      EnterCriticalSection( oCOMGlobalData:_COMGGeneralPurposeSection )
   #ENDIF
   IF SELF:FInit
      IF TS_ValidQueryInterfaceRequest( SELF:_AIUnknown, pStruIID ; ...
     ... , poAIUnknown, @hResult )
         #IFDEF TS_TRACETIMED_ENABLE
            _TS_TraceTimedEnter( TS_TT_SYM_EXTERNAL, TS_TT_SYM_IUNKNOWN, #QueryInterface  ; ...
           ... )
         #ENDIF
         hResult:=SELF:_AIUnknown:QueryInterface( pStruIID ; ...
        ... , poAIUnknown )
         #IFDEF TS_TRACETIMED_ENABLE
            _TS_TraceTimedLeave( TS_TT_SYM_EXTERNAL, TS_TT_SYM_IUNKNOWN, #QueryInterface  ; ...
           ... )
         #ENDIF
         DO CASE
         CASE hResult==E_NOINTERFACE
            IF TS_ShowNotSupportedInterfaces( )
               TS_DebOutSTRING( "Interface '"+TS_GUID2String( pStruIID )+"' not supported"  ; ...
              ... )
            END
         CASE TS_HFailed( hResult, TRUE )
            TSTrace Warning "SELF:_AIUnknown:QueryInterface(pStruIID,poAIUnknown)"
         END
      ELSE
         TSTrace Warning "!TS_ValidQueryInterfaceRequest(SELF:_AIUnknown,pStruIID" ; ...
        ... +",poAIUnknown,@hResult)"
         IF poAIUnknown<>NULL_PTR
            OBJECT( PTR( _CAST, poAIUnknown ) ):=NULL_OBJECT
         ELSE
            TSTrace Warning "poAIUnknown==NULL_PTR"
         END
         hResult:=E_FAIL
      END
   ELSE
      TSTrace Warning "!SELF:FInit"
      IF poAIUnknown<>NULL_PTR
         OBJECT( PTR( _CAST, poAIUnknown ) ):=NULL_OBJECT
      ELSE
         TSTrace Warning "poAIUnknown==NULL_PTR"
      END
      hResult:=E_FAIL
   END
   #IFDEF TS_COMGLOBALDATA_CRITICALSECTION
      LeaveCriticalSection( oCOMGlobalData:_COMGGeneralPurposeSection )
   #ENDIF
   TSTrace Leave
RETURN hResult