CONNECT.CPP
/* 
 * CONNECT.CPP 
 * Patron Chapter 24 
 * 
 * Helper functions for working with connection points on objects 
 * and the event sets of those objects. 
 * 
 * Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved 
 * 
 * Kraig Brockschmidt, Microsoft 
 * Internet  :  kraigb@microsoft.com 
 * Compuserve:  >INTERNET:kraigb@microsoft.com 
 */ 
 
 
#include "patron.h" 
 
 
/* 
 * InterfaceConnect 
 * 
 * Purpose: 
 *  Connects some sink interface of a given IID to an object. 
 * 
 * Parameters: 
 *  pObj            LPUNKNOWN of the object to which we connect 
 *  riid            REFIID of the interface of the sink 
 *  pIUnknownSink   LPUNKNOWN of the caller's sink interface that 
 *                  is actually of the type matching riid 
 *  pdwConn         LPDWORD in which to return the connection key 
 * 
 * Return Value: 
 *  BOOL            TRUE if the function succeeded, FALSE otherwise. 
 */ 
 
BOOL InterfaceConnect(LPUNKNOWN pObj, REFIID riid 
    , LPUNKNOWN pIUnknownSink, LPDWORD pdwConn) 
    { 
    HRESULT                     hr; 
    LPCONNECTIONPOINTCONTAINER  pCPC; 
    LPCONNECTIONPOINT           pCP; 
 
    if (NULL==pObj || NULL==pIUnknownSink || NULL==pdwConn) 
        return FALSE; 
 
    hr=pObj->QueryInterface(IID_IConnectionPointContainer 
        , (PPVOID)&pCPC); 
 
    if (FAILED(hr)) 
        return FALSE; 
 
    hr=pCPC->FindConnectionPoint(riid, &pCP); 
 
    if (SUCCEEDED(hr)) 
        { 
        hr=pCP->Advise(pIUnknownSink, pdwConn); 
        pCP->Release(); 
        } 
 
    pCPC->Release(); 
    return SUCCEEDED(hr); 
    } 
 
 
 
/* 
 * InterfaceDisconnect 
 * 
 * Purpose: 
 *  Disconnects a prior connection to an object. 
 * 
 * Parameters: 
 *  pObj            LPUNKNOWN of the object from which to disconnect 
 *  riid            REFIID of the interface of the sink 
 *  pdwConn         LPDWORD containing the key returned by 
 *                  InterfaceConnect.  This function will zero the 
 *                  key on diconnect. 
 * 
 * Return Value: 
 *  BOOL            TRUE if the function succeeded, FALSE otherwise. 
 */ 
 
BOOL InterfaceDisconnect(LPUNKNOWN pObj, REFIID riid 
    , LPDWORD pdwConn) 
    { 
    HRESULT                     hr; 
    LPCONNECTIONPOINTCONTAINER  pCPC; 
    LPCONNECTIONPOINT           pCP; 
 
    if (NULL==pObj || NULL==pdwConn) 
        return FALSE; 
 
    if (0==*pdwConn) 
        return FALSE; 
 
    hr=pObj->QueryInterface(IID_IConnectionPointContainer 
        , (PPVOID)&pCPC); 
 
    if (FAILED(hr)) 
        return FALSE; 
 
    hr=pCPC->FindConnectionPoint(riid, &pCP); 
 
    if (SUCCEEDED(hr)) 
        { 
        hr=pCP->Unadvise(*pdwConn); 
 
        if (SUCCEEDED(hr)) 
            *pdwConn=0L; 
 
        pCP->Release(); 
        } 
 
    pCPC->Release(); 
    return SUCCEEDED(hr); 
    } 
 
 
 
 
 
 
/* 
 * ObjectTypeInfo 
 * 
 * Purpose: 
 *  Retrieves the ITypeInfo for the entire object from which 
 *  one can learn the IID of the event set and navigate to the 
 *  ITypeInfo for events, among other things. 
 * 
 * Parameters: 
 *  pObj            LPUNKNOWN of the object 
 *  ppITypeInfo     LPTYPEINFO * in which to return the ITypeInfo 
 *                  interface for the object's events. 
 * 
 * Return Value: 
 *  BOOL            TRUE if successful, FALSE otherwise. 
 */ 
 
BOOL ObjectTypeInfo(LPUNKNOWN pObj, LPTYPEINFO *ppITypeInfo) 
    { 
    HRESULT             hr; 
    LPPROVIDECLASSINFO  pIProvideClassInfo; 
     
    if (NULL==pObj || NULL==ppITypeInfo) 
        return FALSE; 
 
    *ppITypeInfo=NULL; 
 
    /* 
     * Get the object's IProvideClassInfo and call the GetClassInfo 
     * method therein.  This will give us back the ITypeInfo for 
     * the entire object. 
     */ 
 
    hr=pObj->QueryInterface(IID_IProvideClassInfo 
        , (PPVOID)&pIProvideClassInfo); 
 
    if (FAILED(hr)) 
        return FALSE; 
 
    hr=pIProvideClassInfo->GetClassInfo(ppITypeInfo); 
    pIProvideClassInfo->Release(); 
 
    return SUCCEEDED(hr); 
    } 
 
 
 
 
/* 
 * ObjectTypeInfoEvents 
 * 
 * Purpose: 
 *  Retrieves the events type information from an object.  This is 
 *  defined to be the "default source" interface in the object's 
 *  type library. 
 * 
 * Parameters: 
 *  pObj            LPUNKNOWN of the object 
 *  ppITypeInfo     LPTYPEINFO * in which to return the ITypeInfo 
 *                  interface for the object's events. 
 * 
 * Return Value: 
 *  BOOL            TRUE if the event type lib exists, FALSE 
 *                  if not or on any other error. 
 */ 
 
BOOL ObjectTypeInfoEvents(LPUNKNOWN pObj, LPTYPEINFO *ppITypeInfo) 
    { 
    HRESULT             hr; 
    LPTYPEINFO          pITypeInfoAll; 
    LPTYPEATTR          pTA; 
 
    if (NULL==pObj || NULL==ppITypeInfo) 
        return FALSE; 
 
    if (!ObjectTypeInfo(pObj, &pITypeInfoAll)) 
        return FALSE; 
 
    /* 
     * We have the object's overall ITypeInfo in pITypeInfoAll. 
     * Now get the type attributes which will tell us the number of 
     * individual interfaces in this type library.  We then loop 
     * through the "implementation types" for all those interfaces 
     * calling GetImplTypeFlags, looking for the default source. 
     */ 
 
    *ppITypeInfo=NULL;  //Use this to determine success 
 
    if (SUCCEEDED(pITypeInfoAll->GetTypeAttr(&pTA))) 
        { 
        UINT        i; 
        int         iFlags; 
 
        for (i=0; i < pTA->cImplTypes; i++) 
            { 
            //Get the implementation type for this interface 
            hr=pITypeInfoAll->GetImplTypeFlags(i, &iFlags); 
 
            if (FAILED(hr)) 
                continue; 
 
            if ((iFlags & IMPLTYPEFLAG_FDEFAULT) 
                && (iFlags & IMPLTYPEFLAG_FSOURCE)) 
                { 
                HREFTYPE    hRefType=NULL; 
 
                /* 
                 * This is the interface we want.  Get a handle to 
                 * the type description from which we can then get 
                 * the ITypeInfo. 
                 */ 
                pITypeInfoAll->GetRefTypeOfImplType(i, &hRefType); 
                hr=pITypeInfoAll->GetRefTypeInfo(hRefType 
                    , ppITypeInfo); 
 
                break; 
                } 
            } 
 
        pITypeInfoAll->ReleaseTypeAttr(pTA); 
        } 
 
    pITypeInfoAll->Release(); 
    return (NULL!=*ppITypeInfo); 
    } 
 
 
 
 
 
 
/* 
 * ObjectEventsIID 
 * 
 * Purpose: 
 *  Determines the IID of the object's events interface so we 
 *  can ask for the right IConnectionPoint for events. 
 * 
 * Parameters: 
 *  pObj            LPUNKNOWN of the object 
 *  piid            IID * in which to return the IID for events 
 * 
 * Return Value: 
 *  BOOL            TRUE if successful, FALSE otherwise. 
 */ 
 
BOOL ObjectEventsIID(LPUNKNOWN pObj, IID *piid) 
    { 
    HRESULT             hr; 
    LPTYPEINFO          pITypeInfo; 
    LPTYPEATTR          pTA; 
 
    *piid=CLSID_NULL; 
 
    if (!ObjectTypeInfoEvents(pObj, &pITypeInfo)) 
        return FALSE; 
 
    hr=pITypeInfo->GetTypeAttr(&pTA); 
 
    if (SUCCEEDED(hr)) 
        { 
        *piid=pTA->guid; 
        pITypeInfo->ReleaseTypeAttr(pTA); 
        } 
 
    pITypeInfo->Release(); 
    return SUCCEEDED(hr); 
    }