|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1999 - 1999
//
// File: nodemgr.cpp
//
//--------------------------------------------------------------------------
#include "stdafx.h"
#ifdef BUILD_FOR_1381
#if defined(_UNICODE)
inline LPOLESTR CharNextO(LPCOLESTR lp) {return CharNextW(lp);} #elif defined(OLE2ANSI)
inline LPOLESTR CharNextO(LPCOLESTR lp) {return CharNext(lp);} #else
//CharNextW doesn't work on Win95 so we use this
inline LPOLESTR CharNextO(LPCOLESTR lp) {return (LPOLESTR)(lp+1);} #endif
#endif
#include "atlimpl.cpp"
#include "atlwin.cpp"
#include "atlctl.cpp"
#include "initguid.h"
#include "doccnfg.h"
#include "NodeMgr.h"
#include "msgview.h"
#include "fldrsnap.h"
#include "tasksymbol.h"
#include "power.h"
#include "viewext.h"
#include "IconControl.h"
#include "mmcprotocol.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__; #endif
#define IID_DEFINED
/*
* define our own Win64 symbol to make it easy to include 64-bit only * code in the 32-bit build, so we can exercise some code on 32-bit Windows * where the debuggers are better */ #ifdef _WIN64
#define MMC_WIN64
#endif
DECLARE_INFOLEVEL(AMCNodeMgr)
CComModule _Module;
//############################################################################
//############################################################################
//
// The nodemgr proxy exports to support IMMCClipboardDataObject interface marshalling.
//
//############################################################################
//############################################################################
extern "C" BOOL WINAPI NDMGRProxyDllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/); STDAPI NDMGRProxyDllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv); STDAPI NDMGRProxyDllCanUnloadNow(void); STDAPI NDMGRProxyDllRegisterServer(void); STDAPI NDMGRProxyDllUnregisterServer(void);
//############################################################################
//############################################################################
//
// Implementation of class CMMCVersionInfo
//
//############################################################################
//############################################################################
class CMMCVersionInfo: public IMMCVersionInfo, public CComObjectRoot, public CComCoClass<CMMCVersionInfo, &CLSID_MMCVersionInfo> { typedef CMMCVersionInfo ThisClass; public: BEGIN_COM_MAP(ThisClass) COM_INTERFACE_ENTRY(IMMCVersionInfo) END_COM_MAP()
DECLARE_NOT_AGGREGATABLE(ThisClass)
DECLARE_MMC_OBJECT_REGISTRATION ( g_szMmcndmgrDll, // implementing DLL
CLSID_MMCVersionInfo, // CLSID
_T("MMCVersionInfo 1.0 Object"), // class name
_T("NODEMGR.MMCVersionInfo.1"), // ProgID
_T("NODEMGR.MMCVersionInfo")) // version-independent ProgID
STDMETHOD(GetMMCVersion)(long *pVersionMajor, long *pVersionMinor) { DECLARE_SC(sc, TEXT("CMMCVersionInfo::GetMMCVersion"));
sc = ScCheckPointers(pVersionMajor, pVersionMinor); if(sc) return sc.ToHr();
*pVersionMajor = MMC_VERSION_MAJOR; *pVersionMinor = MMC_VERSION_MINOR;
return sc.ToHr(); } }; /****************************************************************************/ // forward declarations
class CMMCEventConnector;
/***************************************************************************\
* * CLASS: CEventForwarder * * PURPOSE: Helper class. It is used to plug into AppEvents as an event sink * to forward received events to CMMCEventConnector class. * It implements IDispatch interface by: * - Having own implementation of QueryInterface * - Forwarding AddRef and Release to CMMCEventConnector's * WeakAddRef and WeakRelease * - Forwarding Invoke to CMMCEventConnector's ScInvokeOnSinks * - using CMMCEventConnector to imlement the rest of IDispatch * USAGE: Used as member object in CMMCEventConnector; * \***************************************************************************/ class CEventForwarder : public IDispatch { public: CEventForwarder(CMMCEventConnector& connector) : m_Connector(connector) { static CMMCTypeInfoHolderWrapper wrapper(GetInfoHolder()); }
// IUnknown implementation
STDMETHOD_(ULONG, AddRef)(); STDMETHOD_(ULONG, Release)(); STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject);
// IDispatch implementation
STDMETHOD(GetTypeInfoCount)( unsigned int FAR* pctinfo ); STDMETHOD(GetTypeInfo)( unsigned int iTInfo, LCID lcid, ITypeInfo FAR* FAR* ppTInfo ); STDMETHOD(GetIDsOfNames)( REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgDispId ); STDMETHOD(Invoke)( DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR* pDispParams, VARIANT FAR* pVarResult, EXCEPINFO FAR* pExcepInfo, unsigned int FAR* puArgErr ); private: CMMCEventConnector& m_Connector; static CComTypeInfoHolder m_TypeInfo; public: // the porpose of this static function is to ensure m_TypeInfo is a static variable,
// since static wrapper will hold on its address - it must be always valid
static CComTypeInfoHolder& GetInfoHolder() { return m_TypeInfo; } };
/***************************************************************************\
* * CLASS: CMMCEventConnector * * PURPOSE: Implementation of coclass AppEventsDHTMLConnector * Objects of this class are used as event source for application events, * in cases when it's easyier to have cocreatible object to connect to * these events and MMC application is already created (DHTML scripts) * Class does not generate event's itself, it plugs into Allpication * as an event sink for AppEvents dispinterface and keeps forwarding the events * \***************************************************************************/ class CMMCEventConnector : public CMMCIDispatchImpl<_EventConnector, &CLSID_AppEventsDHTMLConnector>, public CComCoClass<CMMCEventConnector, &CLSID_AppEventsDHTMLConnector>, // support for connection points (script events)
public IConnectionPointContainerImpl<CMMCEventConnector>, public IConnectionPointImpl<CMMCEventConnector, &DIID_AppEvents, CComDynamicUnkArray>, public INodeManagerProvideClassInfoImpl<&CLSID_AppEventsDHTMLConnector, &DIID_AppEvents, &LIBID_MMC20>, public IObjectSafetyImpl<CMMCEventConnector, INTERFACESAFE_FOR_UNTRUSTED_CALLER> { public: BEGIN_MMC_COM_MAP(CMMCEventConnector) COM_INTERFACE_ENTRY(IProvideClassInfo) COM_INTERFACE_ENTRY(IProvideClassInfo2) COM_INTERFACE_ENTRY(IConnectionPointContainer) COM_INTERFACE_ENTRY(IObjectSafety) END_MMC_COM_MAP()
DECLARE_NOT_AGGREGATABLE(CMMCEventConnector)
DECLARE_MMC_OBJECT_REGISTRATION ( g_szMmcndmgrDll, // implementing DLL
CLSID_AppEventsDHTMLConnector, // CLSID
_T("AppEventsDHTMLConnector 1.0 Object"), // class name
_T("NODEMGR.AppEventsDHTMLConnector.1"), // ProgID
_T("NODEMGR.AppEventsDHTMLConnector")) // version-independent ProgID
BEGIN_CONNECTION_POINT_MAP(CMMCEventConnector) CONNECTION_POINT_ENTRY(DIID_AppEvents) END_CONNECTION_POINT_MAP()
private:
public: CMMCEventConnector(); ~CMMCEventConnector();
ULONG InternalRelease(); // overriding the one from CComObjectRoot
ULONG WeakAddRef(); ULONG WeakRelease();
STDMETHOD(ConnectTo)(PAPPLICATION Application); STDMETHOD(Disconnect)();
// invokes same event w/ same params on all connected sinks
::SC ScInvokeOnSinks( DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR* pDispParams, VARIANT FAR* pVarResult, EXCEPINFO FAR* pExcepInfo, unsigned int FAR* puArgErr );
private: CEventForwarder m_Forwarder; DWORD m_dwWeakRefs; DWORD m_dwCookie; IConnectionPointPtr m_spConnectionPoint; };
//############################################################################
//############################################################################
//
// COM Object map
//
//############################################################################
//############################################################################
BEGIN_OBJECT_MAP(ObjectMap) OBJECT_ENTRY(CLSID_MMCVersionInfo, CMMCVersionInfo) OBJECT_ENTRY(CLSID_TaskSymbol, CTaskSymbol) OBJECT_ENTRY(CLSID_NodeInit, CNodeInitObject) OBJECT_ENTRY(CLSID_ScopeTree, CScopeTree) OBJECT_ENTRY(CLSID_MMCDocConfig, CMMCDocConfig) OBJECT_ENTRY(CLSID_MessageView, CMessageView) OBJECT_ENTRY(CLSID_FolderSnapin, CFolderSnapin) OBJECT_ENTRY(CLSID_HTMLSnapin, CHTMLSnapin) OBJECT_ENTRY(CLSID_OCXSnapin, COCXSnapin) OBJECT_ENTRY(CLSID_ConsolePower, CConsolePower) OBJECT_ENTRY(CLSID_AppEventsDHTMLConnector, CMMCEventConnector) OBJECT_ENTRY(CLSID_ViewExtSnapin, CViewExtensionSnapin) OBJECT_ENTRY(CLSID_IconControl, CIconControl) OBJECT_ENTRY(CLSID_ComCacheCleanup, CMMCComCacheCleanup) OBJECT_ENTRY(CLSID_MMCProtocol, CMMCProtocol) END_OBJECT_MAP()
CNodeMgrApp theApp;
void CNodeMgrApp::Init() { DECLARE_SC(sc, TEXT("CNodeMgrApp::Init"));
/* register the mmc:// protocol */ /* the protocol is required for taskpads and pagebreaks */ sc = CMMCProtocol::ScRegisterProtocol(); if(sc) sc.TraceAndClear(); }
void CNodeMgrApp::DeInit() { SetSnapInsCache(NULL); }
/***************************************************************************\
* * METHOD: CNodeMgrApp::ScOnReleaseCachedOleObjects * * PURPOSE: Called prior to ole de-initialization to release any cached ole objects * * PARAMETERS: * * RETURNS: * SC - result code * \***************************************************************************/ SC CNodeMgrApp::ScOnReleaseCachedOleObjects() { DECLARE_SC(sc, TEXT("CNodeMgrApp::ScOnReleaseCachedOleObjects"));
// release snapin cache - thats all the class have cached...
SetSnapInsCache(NULL);
return sc; }
void CNodeMgrApp::SetSnapInsCache(CSnapInsCache* pSIC) { if (m_pSnapInsCache != NULL) delete m_pSnapInsCache;
m_pSnapInsCache = pSIC; }
/////////////////////////////////////////////////////////////////////////////
// DLL Entry Point
extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/) { if (dwReason == DLL_PROCESS_ATTACH) { // NATHAN FIX !!w
//_set_new_handler( _standard_new_handler );
_Module.Init(ObjectMap, hInstance); theApp.Init(); DisableThreadLibraryCalls(hInstance); } else if (dwReason == DLL_PROCESS_DETACH) { theApp.DeInit(); _Module.Term(); }
NDMGRProxyDllMain(hInstance, dwReason, NULL);
return TRUE; // ok
}
/////////////////////////////////////////////////////////////////////////////
// Used to determine whether the DLL can be unloaded by OLE
STDAPI DllCanUnloadNow(void) { if (_Module.GetLockCount()!=0) return S_FALSE;
return NDMGRProxyDllCanUnloadNow(); }
/////////////////////////////////////////////////////////////////////////////
// Returns a class factory to create an object of the requested type
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) { if (IsEqualIID(IID_IMMCClipboardDataObject, rclsid)) return NDMGRProxyDllGetClassObject(rclsid, riid, ppv);
return _Module.GetClassObject(rclsid, riid, ppv); }
/////////////////////////////////////////////////////////////////////////////
// DllRegisterServer - Adds entries to the system registry
// Use own routine to register typelib because we don't want
// a full pathname, just a module name
static HRESULT RegisterTypeLib() { USES_CONVERSION;
TCHAR szModule[_MAX_PATH+10] = { 0 };
GetModuleFileName(_Module.GetModuleInstance(), szModule, _MAX_PATH);
ITypeLib* pTypeLib; LPOLESTR lpszModule = T2OLE(szModule); HRESULT hr = LoadTypeLib(lpszModule, &pTypeLib); ASSERT(SUCCEEDED(hr));
if (SUCCEEDED(hr)) { hr = ::RegisterTypeLib(pTypeLib, const_cast<LPWSTR>(T2CW (g_szMmcndmgrDll)), NULL); ASSERT(SUCCEEDED(hr)); }
if (pTypeLib != NULL) pTypeLib->Release();
return hr; }
STDAPI DllRegisterServer(void) { DECLARE_SC (sc, _T("DllRegisterServer"));
// registers objects
sc = _Module.RegisterServer(FALSE); if (sc) { sc.Trace_(); return ((sc = SELFREG_E_CLASS).ToHr()); }
CRegKeyEx regkeySoftware; CRegKeyEx regkeyMMC; CRegKeyEx regkeySnapIns; CRegKeyEx regkeyNodeTypes;
if ((sc = regkeySoftware. ScOpen (HKEY_LOCAL_MACHINE, _T("Software\\Microsoft"))).IsError() || (sc = regkeyMMC. ScCreate (regkeySoftware, _T("MMC"))). IsError() || (sc = regkeySnapIns. ScCreate (regkeyMMC, _T("SnapIns"))). IsError() || (sc = regkeyNodeTypes.ScCreate (regkeyMMC, _T("NodeTypes"))). IsError()) { sc.Trace_(); return ((sc = SELFREG_E_CLASS).ToHr()); }
sc = ::RegisterTypeLib(); if (sc) { sc.Trace_(); return ((sc = SELFREG_E_TYPELIB).ToHr()); }
sc = NDMGRProxyDllRegisterServer(); if (sc) return sc.ToHr();
/*
* register mmc.exe to complete the process * note: mmc.exe is never unregistered */
// fix to windows bug #233372. ntbug09, 11/28/00
// [ mmc.exe launched from current directory, not from where it is supposed to be]
// get the path of node manager dll
TCHAR szPath[_MAX_PATH]; DWORD dwPathLen = ::GetModuleFileName(_Module.GetModuleInstance(), szPath, countof(szPath) ); szPath[countof(szPath) -1] = 0;
// if node manager path is found - put same directory to mmc path
tstring strMMCPath; if ( dwPathLen > 0 ) { tstring strNodeMgr = szPath; int iLastSlashPos = strNodeMgr.rfind('\\'); if (iLastSlashPos != tstring::npos) strMMCPath = strNodeMgr.substr(0, iLastSlashPos + 1); } else { sc = E_UNEXPECTED; sc.TraceAndClear(); // ignore and continue without a path
}
strMMCPath += _T("mmc.exe");
#if defined(MMC_WIN64)
LPCTSTR szRegParams = _T("-64 -RegServer"); #else
LPCTSTR szRegParams = _T("-32 -RegServer"); #endif
HINSTANCE hInst = ShellExecute (NULL, NULL, strMMCPath.c_str(), szRegParams, NULL, SW_SHOWNORMAL); if ((DWORD_PTR) hInst <= 32) { switch ((DWORD_PTR) hInst) { case 0: sc = E_OUTOFMEMORY; break;
case ERROR_FILE_NOT_FOUND: case ERROR_PATH_NOT_FOUND: case ERROR_BAD_FORMAT: sc.FromWin32 ((DWORD_PTR) hInst); break;
default: sc = E_FAIL; break; }
return (sc.ToHr()); }
return (sc.ToHr()); }
/////////////////////////////////////////////////////////////////////////////
// DllUnregisterServer - Adds entries to the system registry
STDAPI DllUnregisterServer(void) { HRESULT hRes = S_OK; _Module.UnregisterServer();
NDMGRProxyDllUnregisterServer();
return hRes; }
/***************************************************************************\
* * STATIC OBJECT: CEventForwarder::m_TypeInfo * * PURPOSE: manages ITypeInfo used by CEventForwarder * \***************************************************************************/ CComTypeInfoHolder CEventForwarder::m_TypeInfo = { &DIID_AppEvents, &LIBID_MMC20, 1, 0, NULL, 0, NULL, 0 };
/***************************************************************************\
* * METHOD: CEventForwarder::AddRef * * PURPOSE: Implements IUnknown::AddRef * This class is always contained within m_Connector, so it * relies on outer object to count the references. * To differentiate between regular references and those occuring * beacuse of connecting to the sink, it calls WeakAddRef, * not the regular AddRef on connector * * PARAMETERS: * * RETURNS: * ULONG - reference count * \***************************************************************************/ STDMETHODIMP_(ULONG) CEventForwarder::AddRef() { return m_Connector.WeakAddRef(); }
/***************************************************************************\
* * METHOD: CEventForwarder::Release * * PURPOSE: Implements IUnknown::Release * This class is always contained within m_Connector, so it * relies on outer object to count the references. * To differentiate between regular references and those occuring * beacuse of connecting to the sink, it calls WeakRelease, * not the regular Release on connector * * PARAMETERS: * * RETURNS: * ULONG - reference count * \***************************************************************************/ STDMETHODIMP_(ULONG) CEventForwarder::Release() { return m_Connector.WeakRelease(); }
/***************************************************************************\
* * METHOD: CEventForwarder::QueryInterface * * PURPOSE: Implements IUnknown::QueryInterface * returns self, when requested for IUnknow, IDispatch, AppEvents * * PARAMETERS: * REFIID iid * void ** ppvObject * * RETURNS: * SC - result code * \***************************************************************************/ STDMETHODIMP CEventForwarder::QueryInterface(REFIID iid, void ** ppvObject) { DECLARE_SC(sc, TEXT(""));
// parameter check
sc = ScCheckPointers(ppvObject); if (sc) return sc.ToHr();
// initialization
*ppvObject = NULL;
// check IID
if (IsEqualGUID(iid, IID_IUnknown) || IsEqualGUID(iid, IID_IDispatch) || IsEqualGUID(iid, DIID_AppEvents)) { *ppvObject = this; AddRef(); return sc.ToHr(); }
// not an error - do not assign to sc
return E_NOINTERFACE; }
/***************************************************************************\
* * METHOD: CEventForwarder::GetTypeInfoCount * * PURPOSE: implements method on IDispatch * * PARAMETERS: * unsigned int FAR* pctinfo * * RETURNS: * HRESULT - result code * \***************************************************************************/ STDMETHODIMP CEventForwarder::GetTypeInfoCount( unsigned int FAR* pctinfo ) { if (pctinfo == NULL) return E_INVALIDARG; *pctinfo = 1; return S_OK; }
/***************************************************************************\
* * METHOD: CEventForwarder::GetTypeInfo * * PURPOSE: implements method on IDispatch * * PARAMETERS: * unsigned int iTInfo * LCID lcid * ITypeInfo FAR* FAR* ppTInfo * * RETURNS: * HRESULT - result code * \***************************************************************************/ STDMETHODIMP CEventForwarder::GetTypeInfo( unsigned int iTInfo, LCID lcid, ITypeInfo FAR* FAR* ppTInfo ) { return m_TypeInfo.GetTypeInfo( iTInfo, lcid, ppTInfo ); }
/***************************************************************************\
* * METHOD: CEventForwarder::GetIDsOfNames * * PURPOSE:implements method on IDispatch * * PARAMETERS: * riid * rgszNames * cNames * lcid * rgDispId * * RETURNS: * HRESULT - result code * \***************************************************************************/ STDMETHODIMP CEventForwarder::GetIDsOfNames( REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgDispId ) { return m_TypeInfo.GetIDsOfNames( riid, rgszNames, cNames, lcid, rgDispId ); }
/***************************************************************************\
* * METHOD: CEventForwarder::Invoke * * PURPOSE: implements method on IDispatch. Forwards calls to connector. * In order to distinguish between calls made on itself, connector * must provide method, which has different name : ScInvokeOnSinks * * PARAMETERS: * DISPID dispIdMember * REFIID riid * LCID lcid * WORD wFlags * DISPPARAMS FAR* pDispParams * VARIANT FAR* pVarResult * EXCEPINFO FAR* pExcepInfo * unsigned int FAR* puArgErr * * RETURNS: * HRESULT - result code * \***************************************************************************/ STDMETHODIMP CEventForwarder::Invoke( DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR* pDispParams, VARIANT FAR* pVarResult, EXCEPINFO FAR* pExcepInfo, unsigned int FAR* puArgErr ) { DECLARE_SC(sc, TEXT("CEventForwarder::Invoke"));
sc = m_Connector.ScInvokeOnSinks( dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr ); return sc.ToHr(); }
/***************************************************************************\
* * METHOD: CMMCEventConnector::CMMCEventConnector * * PURPOSE: constructor * \***************************************************************************/ CMMCEventConnector::CMMCEventConnector() : m_Forwarder(*this), m_dwCookie(0), m_dwWeakRefs(0) { }
/***************************************************************************\
* * METHOD: CMMCEventConnector::~CMMCEventConnector * * PURPOSE: Destructor * \***************************************************************************/ CMMCEventConnector::~CMMCEventConnector() { Disconnect(); // most likely not needed. Just for sanity
}
/***************************************************************************\
* * METHOD: CMMCEventConnector::InternalRelease * * PURPOSE: Overrides method from CComObjectRoot to detect when last "real" * reference is released. Refs made because of connecting to the * sink does not count - we would have a deadlock else * * PARAMETERS: * * RETURNS: * ULONG - ref count * \***************************************************************************/ ULONG CMMCEventConnector::InternalRelease() { ULONG uRefsLeft = CComObjectRoot::InternalRelease();
if ((uRefsLeft != 0) && (uRefsLeft == m_dwWeakRefs)) { // seems like we are alive just because we still connected to the connection point
// disconnect ( no-one uses it anyway )
InternalAddRef(); // Addref to have balance
Disconnect(); // disconnect from the connection point
uRefsLeft = CComObjectRoot::InternalRelease(); // release again
}
return uRefsLeft; }
/***************************************************************************\
* * METHOD: CMMCEventConnector::WeakAddRef * * PURPOSE: counts reference from connection points. AddRefs regularly as well * * PARAMETERS: * * RETURNS: * ULONG - ref count * \***************************************************************************/ ULONG CMMCEventConnector::WeakAddRef() { ++m_dwWeakRefs; return AddRef(); }
/***************************************************************************\
* * METHOD: CMMCEventConnector::WeakRelease * * PURPOSE: counts reference from connection points. Releases regularly as well * * PARAMETERS: * * RETURNS: * ULONG - ref count * \***************************************************************************/ ULONG CMMCEventConnector::WeakRelease() { --m_dwWeakRefs; return Release(); }
/***************************************************************************\
* * METHOD: CMMCEventConnector::ScInvokeOnSinks * * PURPOSE: This method has a signature of IDispath::Invoke and is * called from connection point to inform about the event * Method's job is to fork the call to each own connected sink * * RETURNS: * SC - result code * \***************************************************************************/ SC CMMCEventConnector::ScInvokeOnSinks( DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR* pDispParams, VARIANT FAR* pVarResult, EXCEPINFO FAR* pExcepInfo, unsigned int FAR* puArgErr ) { DECLARE_SC(sc, TEXT("CMMCEventConnector::ScInvokeOnSinks"));
// find connection point
IConnectionPointPtr spConnectionPoint; sc = FindConnectionPoint(DIID_AppEvents, &spConnectionPoint); if (sc) return sc;
// get connections
IEnumConnectionsPtr spEnumConnections; sc = spConnectionPoint->EnumConnections(&spEnumConnections); if (sc) return sc.ToHr();
// recheck the pointer
sc = ScCheckPointers(spEnumConnections, E_UNEXPECTED); if (sc) return sc.ToHr();
// reset iterator
sc = spEnumConnections->Reset(); if (sc) return sc.ToHr();
// iterate thru sinks until Next returns S_FALSE.
CONNECTDATA connectdata; SC sc_last_error; while (1) // will use <break> to exit
{ // get the next sink
ZeroMemory(&connectdata, sizeof(connectdata)); sc = spEnumConnections->Next( 1, &connectdata, NULL ); if (sc) return sc.ToHr();
// done if no more sinks
if (sc == SC(S_FALSE)) break;
// recheck the pointer
sc = ScCheckPointers(connectdata.pUnk, E_UNEXPECTED); if (sc) return sc.ToHr();
// QI for IDispatch
IDispatchPtr spDispatch = (IDispatch *)connectdata.pUnk; connectdata.pUnk->Release();
// recheck the pointer
sc = ScCheckPointers(spDispatch, E_UNEXPECTED); if (sc) return sc.ToHr();
// invoke on the sink
sc = spDispatch->Invoke( dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr ); if (sc) { sc_last_error = sc; // continue even if some calls failed
sc.TraceAndClear(); } }
return sc_last_error.ToHr(); }
/***************************************************************************\
* * METHOD: CMMCEventConnector::ConnectTo * * PURPOSE: Connects to Application object and starts forwarding its events * * PARAMETERS: * PAPPLICATION Application * * RETURNS: * SC - result code * \***************************************************************************/ STDMETHODIMP CMMCEventConnector::ConnectTo(PAPPLICATION Application) { DECLARE_SC(sc, TEXT("ConnectTo"));
// disconnect from former connections
sc = Disconnect(); if (sc) return sc.ToHr();
// check if com object supports IConnectionPointContainer;
IConnectionPointContainerPtr spContainer = Application; sc = ScCheckPointers(spContainer); if (sc) return sc.ToHr();
// get connection point
sc = spContainer->FindConnectionPoint(DIID_AppEvents, &m_spConnectionPoint); if (sc) return sc.ToHr();
sc = m_spConnectionPoint->Advise(&m_Forwarder, &m_dwCookie); if (sc) return sc.ToHr();
return S_OK; }
/***************************************************************************\
* * METHOD: CMMCEventConnector::Disconnect * * PURPOSE: Disconnects from connection point if is connected to one * * PARAMETERS: * * RETURNS: * HRESULT - result code * \***************************************************************************/ STDMETHODIMP CMMCEventConnector::Disconnect() { DECLARE_SC(sc, TEXT("CMMCEventConnector::Disconnect"));
if (m_dwCookie) { if (m_spConnectionPoint != NULL) { sc = m_spConnectionPoint->Unadvise(m_dwCookie); if (sc) sc.TraceAndClear(); } m_dwCookie = 0; m_spConnectionPoint = NULL; }
return sc.ToHr(); }
|