Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

943 lines
28 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1999 - 1999
  6. //
  7. // File: nodemgr.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "stdafx.h"
  11. #ifdef BUILD_FOR_1381
  12. #if defined(_UNICODE)
  13. inline LPOLESTR CharNextO(LPCOLESTR lp) {return CharNextW(lp);}
  14. #elif defined(OLE2ANSI)
  15. inline LPOLESTR CharNextO(LPCOLESTR lp) {return CharNext(lp);}
  16. #else
  17. //CharNextW doesn't work on Win95 so we use this
  18. inline LPOLESTR CharNextO(LPCOLESTR lp) {return (LPOLESTR)(lp+1);}
  19. #endif
  20. #endif
  21. #include "atlimpl.cpp"
  22. #include "atlwin.cpp"
  23. #include "atlctl.cpp"
  24. #include "initguid.h"
  25. #include "doccnfg.h"
  26. #include "NodeMgr.h"
  27. #include "msgview.h"
  28. #include "fldrsnap.h"
  29. #include "tasksymbol.h"
  30. #include "power.h"
  31. #include "viewext.h"
  32. #include "IconControl.h"
  33. #include "mmcprotocol.h"
  34. #ifdef _DEBUG
  35. #undef THIS_FILE
  36. static char THIS_FILE[] = __FILE__;
  37. #endif
  38. #define IID_DEFINED
  39. /*
  40. * define our own Win64 symbol to make it easy to include 64-bit only
  41. * code in the 32-bit build, so we can exercise some code on 32-bit Windows
  42. * where the debuggers are better
  43. */
  44. #ifdef _WIN64
  45. #define MMC_WIN64
  46. #endif
  47. DECLARE_INFOLEVEL(AMCNodeMgr)
  48. CComModule _Module;
  49. //############################################################################
  50. //############################################################################
  51. //
  52. // The nodemgr proxy exports to support IMMCClipboardDataObject interface marshalling.
  53. //
  54. //############################################################################
  55. //############################################################################
  56. extern "C" BOOL WINAPI NDMGRProxyDllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/);
  57. STDAPI NDMGRProxyDllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv);
  58. STDAPI NDMGRProxyDllCanUnloadNow(void);
  59. STDAPI NDMGRProxyDllRegisterServer(void);
  60. STDAPI NDMGRProxyDllUnregisterServer(void);
  61. //############################################################################
  62. //############################################################################
  63. //
  64. // Implementation of class CMMCVersionInfo
  65. //
  66. //############################################################################
  67. //############################################################################
  68. class CMMCVersionInfo:
  69. public IMMCVersionInfo,
  70. public CComObjectRoot,
  71. public CComCoClass<CMMCVersionInfo, &CLSID_MMCVersionInfo>
  72. {
  73. typedef CMMCVersionInfo ThisClass;
  74. public:
  75. BEGIN_COM_MAP(ThisClass)
  76. COM_INTERFACE_ENTRY(IMMCVersionInfo)
  77. END_COM_MAP()
  78. DECLARE_NOT_AGGREGATABLE(ThisClass)
  79. DECLARE_MMC_OBJECT_REGISTRATION (
  80. g_szMmcndmgrDll, // implementing DLL
  81. CLSID_MMCVersionInfo, // CLSID
  82. _T("MMCVersionInfo 1.0 Object"), // class name
  83. _T("NODEMGR.MMCVersionInfo.1"), // ProgID
  84. _T("NODEMGR.MMCVersionInfo")) // version-independent ProgID
  85. STDMETHOD(GetMMCVersion)(long *pVersionMajor, long *pVersionMinor)
  86. {
  87. DECLARE_SC(sc, TEXT("CMMCVersionInfo::GetMMCVersion"));
  88. sc = ScCheckPointers(pVersionMajor, pVersionMinor);
  89. if(sc)
  90. return sc.ToHr();
  91. *pVersionMajor = MMC_VERSION_MAJOR;
  92. *pVersionMinor = MMC_VERSION_MINOR;
  93. return sc.ToHr();
  94. }
  95. };
  96. /****************************************************************************/
  97. // forward declarations
  98. class CMMCEventConnector;
  99. /***************************************************************************\
  100. *
  101. * CLASS: CEventForwarder
  102. *
  103. * PURPOSE: Helper class. It is used to plug into AppEvents as an event sink
  104. * to forward received events to CMMCEventConnector class.
  105. * It implements IDispatch interface by:
  106. * - Having own implementation of QueryInterface
  107. * - Forwarding AddRef and Release to CMMCEventConnector's
  108. * WeakAddRef and WeakRelease
  109. * - Forwarding Invoke to CMMCEventConnector's ScInvokeOnSinks
  110. * - using CMMCEventConnector to imlement the rest of IDispatch
  111. * USAGE: Used as member object in CMMCEventConnector;
  112. *
  113. \***************************************************************************/
  114. class CEventForwarder : public IDispatch
  115. {
  116. public:
  117. CEventForwarder(CMMCEventConnector& connector) : m_Connector(connector)
  118. {
  119. static CMMCTypeInfoHolderWrapper wrapper(GetInfoHolder());
  120. }
  121. // IUnknown implementation
  122. STDMETHOD_(ULONG, AddRef)();
  123. STDMETHOD_(ULONG, Release)();
  124. STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject);
  125. // IDispatch implementation
  126. STDMETHOD(GetTypeInfoCount)( unsigned int FAR* pctinfo );
  127. STDMETHOD(GetTypeInfo)( unsigned int iTInfo, LCID lcid, ITypeInfo FAR* FAR* ppTInfo );
  128. STDMETHOD(GetIDsOfNames)( REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames,
  129. LCID lcid, DISPID FAR* rgDispId );
  130. STDMETHOD(Invoke)( DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags,
  131. DISPPARAMS FAR* pDispParams, VARIANT FAR* pVarResult,
  132. EXCEPINFO FAR* pExcepInfo, unsigned int FAR* puArgErr );
  133. private:
  134. CMMCEventConnector& m_Connector;
  135. static CComTypeInfoHolder m_TypeInfo;
  136. public:
  137. // the porpose of this static function is to ensure m_TypeInfo is a static variable,
  138. // since static wrapper will hold on its address - it must be always valid
  139. static CComTypeInfoHolder& GetInfoHolder() { return m_TypeInfo; }
  140. };
  141. /***************************************************************************\
  142. *
  143. * CLASS: CMMCEventConnector
  144. *
  145. * PURPOSE: Implementation of coclass AppEventsDHTMLConnector
  146. * Objects of this class are used as event source for application events,
  147. * in cases when it's easyier to have cocreatible object to connect to
  148. * these events and MMC application is already created (DHTML scripts)
  149. * Class does not generate event's itself, it plugs into Allpication
  150. * as an event sink for AppEvents dispinterface and keeps forwarding the events
  151. *
  152. \***************************************************************************/
  153. class CMMCEventConnector :
  154. public CMMCIDispatchImpl<_EventConnector, &CLSID_AppEventsDHTMLConnector>,
  155. public CComCoClass<CMMCEventConnector, &CLSID_AppEventsDHTMLConnector>,
  156. // support for connection points (script events)
  157. public IConnectionPointContainerImpl<CMMCEventConnector>,
  158. public IConnectionPointImpl<CMMCEventConnector, &DIID_AppEvents, CComDynamicUnkArray>,
  159. public INodeManagerProvideClassInfoImpl<&CLSID_AppEventsDHTMLConnector, &DIID_AppEvents, &LIBID_MMC20>,
  160. public IObjectSafetyImpl<CMMCEventConnector, INTERFACESAFE_FOR_UNTRUSTED_CALLER>
  161. {
  162. public:
  163. BEGIN_MMC_COM_MAP(CMMCEventConnector)
  164. COM_INTERFACE_ENTRY(IProvideClassInfo)
  165. COM_INTERFACE_ENTRY(IProvideClassInfo2)
  166. COM_INTERFACE_ENTRY(IConnectionPointContainer)
  167. COM_INTERFACE_ENTRY(IObjectSafety)
  168. END_MMC_COM_MAP()
  169. DECLARE_NOT_AGGREGATABLE(CMMCEventConnector)
  170. DECLARE_MMC_OBJECT_REGISTRATION (
  171. g_szMmcndmgrDll, // implementing DLL
  172. CLSID_AppEventsDHTMLConnector, // CLSID
  173. _T("AppEventsDHTMLConnector 1.0 Object"), // class name
  174. _T("NODEMGR.AppEventsDHTMLConnector.1"), // ProgID
  175. _T("NODEMGR.AppEventsDHTMLConnector")) // version-independent ProgID
  176. BEGIN_CONNECTION_POINT_MAP(CMMCEventConnector)
  177. CONNECTION_POINT_ENTRY(DIID_AppEvents)
  178. END_CONNECTION_POINT_MAP()
  179. private:
  180. public:
  181. CMMCEventConnector();
  182. ~CMMCEventConnector();
  183. ULONG InternalRelease(); // overriding the one from CComObjectRoot
  184. ULONG WeakAddRef();
  185. ULONG WeakRelease();
  186. STDMETHOD(ConnectTo)(PAPPLICATION Application);
  187. STDMETHOD(Disconnect)();
  188. // invokes same event w/ same params on all connected sinks
  189. ::SC ScInvokeOnSinks( DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags,
  190. DISPPARAMS FAR* pDispParams, VARIANT FAR* pVarResult,
  191. EXCEPINFO FAR* pExcepInfo, unsigned int FAR* puArgErr );
  192. private:
  193. CEventForwarder m_Forwarder;
  194. DWORD m_dwWeakRefs;
  195. DWORD m_dwCookie;
  196. IConnectionPointPtr m_spConnectionPoint;
  197. };
  198. //############################################################################
  199. //############################################################################
  200. //
  201. // COM Object map
  202. //
  203. //############################################################################
  204. //############################################################################
  205. BEGIN_OBJECT_MAP(ObjectMap)
  206. OBJECT_ENTRY(CLSID_MMCVersionInfo, CMMCVersionInfo)
  207. OBJECT_ENTRY(CLSID_TaskSymbol, CTaskSymbol)
  208. OBJECT_ENTRY(CLSID_NodeInit, CNodeInitObject)
  209. OBJECT_ENTRY(CLSID_ScopeTree, CScopeTree)
  210. OBJECT_ENTRY(CLSID_MMCDocConfig, CMMCDocConfig)
  211. OBJECT_ENTRY(CLSID_MessageView, CMessageView)
  212. OBJECT_ENTRY(CLSID_FolderSnapin, CFolderSnapin)
  213. OBJECT_ENTRY(CLSID_HTMLSnapin, CHTMLSnapin)
  214. OBJECT_ENTRY(CLSID_OCXSnapin, COCXSnapin)
  215. OBJECT_ENTRY(CLSID_ConsolePower, CConsolePower)
  216. OBJECT_ENTRY(CLSID_AppEventsDHTMLConnector, CMMCEventConnector)
  217. OBJECT_ENTRY(CLSID_ViewExtSnapin, CViewExtensionSnapin)
  218. OBJECT_ENTRY(CLSID_IconControl, CIconControl)
  219. OBJECT_ENTRY(CLSID_ComCacheCleanup, CMMCComCacheCleanup)
  220. OBJECT_ENTRY(CLSID_MMCProtocol, CMMCProtocol)
  221. END_OBJECT_MAP()
  222. CNodeMgrApp theApp;
  223. void CNodeMgrApp::Init()
  224. {
  225. DECLARE_SC(sc, TEXT("CNodeMgrApp::Init"));
  226. /* register the mmc:// protocol */
  227. /* the protocol is required for taskpads and pagebreaks */
  228. sc = CMMCProtocol::ScRegisterProtocol();
  229. if(sc)
  230. sc.TraceAndClear();
  231. }
  232. void CNodeMgrApp::DeInit()
  233. {
  234. SetSnapInsCache(NULL);
  235. }
  236. /***************************************************************************\
  237. *
  238. * METHOD: CNodeMgrApp::ScOnReleaseCachedOleObjects
  239. *
  240. * PURPOSE: Called prior to ole de-initialization to release any cached ole objects
  241. *
  242. * PARAMETERS:
  243. *
  244. * RETURNS:
  245. * SC - result code
  246. *
  247. \***************************************************************************/
  248. SC CNodeMgrApp::ScOnReleaseCachedOleObjects()
  249. {
  250. DECLARE_SC(sc, TEXT("CNodeMgrApp::ScOnReleaseCachedOleObjects"));
  251. // release snapin cache - thats all the class have cached...
  252. SetSnapInsCache(NULL);
  253. return sc;
  254. }
  255. void CNodeMgrApp::SetSnapInsCache(CSnapInsCache* pSIC)
  256. {
  257. if (m_pSnapInsCache != NULL)
  258. delete m_pSnapInsCache;
  259. m_pSnapInsCache = pSIC;
  260. }
  261. /////////////////////////////////////////////////////////////////////////////
  262. // DLL Entry Point
  263. extern "C"
  264. BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/)
  265. {
  266. if (dwReason == DLL_PROCESS_ATTACH)
  267. {
  268. // NATHAN FIX !!w
  269. //_set_new_handler( _standard_new_handler );
  270. _Module.Init(ObjectMap, hInstance);
  271. theApp.Init();
  272. DisableThreadLibraryCalls(hInstance);
  273. }
  274. else if (dwReason == DLL_PROCESS_DETACH)
  275. {
  276. theApp.DeInit();
  277. _Module.Term();
  278. }
  279. NDMGRProxyDllMain(hInstance, dwReason, NULL);
  280. return TRUE; // ok
  281. }
  282. /////////////////////////////////////////////////////////////////////////////
  283. // Used to determine whether the DLL can be unloaded by OLE
  284. STDAPI DllCanUnloadNow(void)
  285. {
  286. if (_Module.GetLockCount()!=0)
  287. return S_FALSE;
  288. return NDMGRProxyDllCanUnloadNow();
  289. }
  290. /////////////////////////////////////////////////////////////////////////////
  291. // Returns a class factory to create an object of the requested type
  292. STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
  293. {
  294. if (IsEqualIID(IID_IMMCClipboardDataObject, rclsid))
  295. return NDMGRProxyDllGetClassObject(rclsid, riid, ppv);
  296. return _Module.GetClassObject(rclsid, riid, ppv);
  297. }
  298. /////////////////////////////////////////////////////////////////////////////
  299. // DllRegisterServer - Adds entries to the system registry
  300. // Use own routine to register typelib because we don't want
  301. // a full pathname, just a module name
  302. static HRESULT RegisterTypeLib()
  303. {
  304. USES_CONVERSION;
  305. TCHAR szModule[_MAX_PATH+10] = { 0 };
  306. GetModuleFileName(_Module.GetModuleInstance(), szModule, _MAX_PATH);
  307. ITypeLib* pTypeLib;
  308. LPOLESTR lpszModule = T2OLE(szModule);
  309. HRESULT hr = LoadTypeLib(lpszModule, &pTypeLib);
  310. ASSERT(SUCCEEDED(hr));
  311. if (SUCCEEDED(hr))
  312. {
  313. hr = ::RegisterTypeLib(pTypeLib, const_cast<LPWSTR>(T2CW (g_szMmcndmgrDll)), NULL);
  314. ASSERT(SUCCEEDED(hr));
  315. }
  316. if (pTypeLib != NULL)
  317. pTypeLib->Release();
  318. return hr;
  319. }
  320. STDAPI DllRegisterServer(void)
  321. {
  322. DECLARE_SC (sc, _T("DllRegisterServer"));
  323. // registers objects
  324. sc = _Module.RegisterServer(FALSE);
  325. if (sc)
  326. {
  327. sc.Trace_();
  328. return ((sc = SELFREG_E_CLASS).ToHr());
  329. }
  330. CRegKeyEx regkeySoftware;
  331. CRegKeyEx regkeyMMC;
  332. CRegKeyEx regkeySnapIns;
  333. CRegKeyEx regkeyNodeTypes;
  334. if ((sc = regkeySoftware. ScOpen (HKEY_LOCAL_MACHINE, _T("Software\\Microsoft"))).IsError() ||
  335. (sc = regkeyMMC. ScCreate (regkeySoftware, _T("MMC"))). IsError() ||
  336. (sc = regkeySnapIns. ScCreate (regkeyMMC, _T("SnapIns"))). IsError() ||
  337. (sc = regkeyNodeTypes.ScCreate (regkeyMMC, _T("NodeTypes"))). IsError())
  338. {
  339. sc.Trace_();
  340. return ((sc = SELFREG_E_CLASS).ToHr());
  341. }
  342. sc = ::RegisterTypeLib();
  343. if (sc)
  344. {
  345. sc.Trace_();
  346. return ((sc = SELFREG_E_TYPELIB).ToHr());
  347. }
  348. sc = NDMGRProxyDllRegisterServer();
  349. if (sc)
  350. return sc.ToHr();
  351. /*
  352. * register mmc.exe to complete the process
  353. * note: mmc.exe is never unregistered
  354. */
  355. // fix to windows bug #233372. ntbug09, 11/28/00
  356. // [ mmc.exe launched from current directory, not from where it is supposed to be]
  357. // get the path of node manager dll
  358. TCHAR szPath[_MAX_PATH];
  359. DWORD dwPathLen = ::GetModuleFileName(_Module.GetModuleInstance(), szPath, countof(szPath) );
  360. szPath[countof(szPath) -1] = 0;
  361. // if node manager path is found - put same directory to mmc path
  362. tstring strMMCPath;
  363. if ( dwPathLen > 0 )
  364. {
  365. tstring strNodeMgr = szPath;
  366. int iLastSlashPos = strNodeMgr.rfind('\\');
  367. if (iLastSlashPos != tstring::npos)
  368. strMMCPath = strNodeMgr.substr(0, iLastSlashPos + 1);
  369. }
  370. else
  371. {
  372. sc = E_UNEXPECTED;
  373. sc.TraceAndClear(); // ignore and continue without a path
  374. }
  375. strMMCPath += _T("mmc.exe");
  376. #if defined(MMC_WIN64)
  377. LPCTSTR szRegParams = _T("-64 -RegServer");
  378. #else
  379. LPCTSTR szRegParams = _T("-32 -RegServer");
  380. #endif
  381. HINSTANCE hInst = ShellExecute (NULL, NULL, strMMCPath.c_str(), szRegParams,
  382. NULL, SW_SHOWNORMAL);
  383. if ((DWORD_PTR) hInst <= 32)
  384. {
  385. switch ((DWORD_PTR) hInst)
  386. {
  387. case 0:
  388. sc = E_OUTOFMEMORY;
  389. break;
  390. case ERROR_FILE_NOT_FOUND:
  391. case ERROR_PATH_NOT_FOUND:
  392. case ERROR_BAD_FORMAT:
  393. sc.FromWin32 ((DWORD_PTR) hInst);
  394. break;
  395. default:
  396. sc = E_FAIL;
  397. break;
  398. }
  399. return (sc.ToHr());
  400. }
  401. return (sc.ToHr());
  402. }
  403. /////////////////////////////////////////////////////////////////////////////
  404. // DllUnregisterServer - Adds entries to the system registry
  405. STDAPI DllUnregisterServer(void)
  406. {
  407. HRESULT hRes = S_OK;
  408. _Module.UnregisterServer();
  409. NDMGRProxyDllUnregisterServer();
  410. return hRes;
  411. }
  412. /***************************************************************************\
  413. *
  414. * STATIC OBJECT: CEventForwarder::m_TypeInfo
  415. *
  416. * PURPOSE: manages ITypeInfo used by CEventForwarder
  417. *
  418. \***************************************************************************/
  419. CComTypeInfoHolder CEventForwarder::m_TypeInfo =
  420. { &DIID_AppEvents, &LIBID_MMC20, 1, 0, NULL, 0, NULL, 0 };
  421. /***************************************************************************\
  422. *
  423. * METHOD: CEventForwarder::AddRef
  424. *
  425. * PURPOSE: Implements IUnknown::AddRef
  426. * This class is always contained within m_Connector, so it
  427. * relies on outer object to count the references.
  428. * To differentiate between regular references and those occuring
  429. * beacuse of connecting to the sink, it calls WeakAddRef,
  430. * not the regular AddRef on connector
  431. *
  432. * PARAMETERS:
  433. *
  434. * RETURNS:
  435. * ULONG - reference count
  436. *
  437. \***************************************************************************/
  438. STDMETHODIMP_(ULONG) CEventForwarder::AddRef()
  439. {
  440. return m_Connector.WeakAddRef();
  441. }
  442. /***************************************************************************\
  443. *
  444. * METHOD: CEventForwarder::Release
  445. *
  446. * PURPOSE: Implements IUnknown::Release
  447. * This class is always contained within m_Connector, so it
  448. * relies on outer object to count the references.
  449. * To differentiate between regular references and those occuring
  450. * beacuse of connecting to the sink, it calls WeakRelease,
  451. * not the regular Release on connector
  452. *
  453. * PARAMETERS:
  454. *
  455. * RETURNS:
  456. * ULONG - reference count
  457. *
  458. \***************************************************************************/
  459. STDMETHODIMP_(ULONG) CEventForwarder::Release()
  460. {
  461. return m_Connector.WeakRelease();
  462. }
  463. /***************************************************************************\
  464. *
  465. * METHOD: CEventForwarder::QueryInterface
  466. *
  467. * PURPOSE: Implements IUnknown::QueryInterface
  468. * returns self, when requested for IUnknow, IDispatch, AppEvents
  469. *
  470. * PARAMETERS:
  471. * REFIID iid
  472. * void ** ppvObject
  473. *
  474. * RETURNS:
  475. * SC - result code
  476. *
  477. \***************************************************************************/
  478. STDMETHODIMP CEventForwarder::QueryInterface(REFIID iid, void ** ppvObject)
  479. {
  480. DECLARE_SC(sc, TEXT(""));
  481. // parameter check
  482. sc = ScCheckPointers(ppvObject);
  483. if (sc)
  484. return sc.ToHr();
  485. // initialization
  486. *ppvObject = NULL;
  487. // check IID
  488. if (IsEqualGUID(iid, IID_IUnknown)
  489. || IsEqualGUID(iid, IID_IDispatch)
  490. || IsEqualGUID(iid, DIID_AppEvents))
  491. {
  492. *ppvObject = this;
  493. AddRef();
  494. return sc.ToHr();
  495. }
  496. // not an error - do not assign to sc
  497. return E_NOINTERFACE;
  498. }
  499. /***************************************************************************\
  500. *
  501. * METHOD: CEventForwarder::GetTypeInfoCount
  502. *
  503. * PURPOSE: implements method on IDispatch
  504. *
  505. * PARAMETERS:
  506. * unsigned int FAR* pctinfo
  507. *
  508. * RETURNS:
  509. * HRESULT - result code
  510. *
  511. \***************************************************************************/
  512. STDMETHODIMP CEventForwarder::GetTypeInfoCount( unsigned int FAR* pctinfo )
  513. {
  514. if (pctinfo == NULL) return E_INVALIDARG;
  515. *pctinfo = 1;
  516. return S_OK;
  517. }
  518. /***************************************************************************\
  519. *
  520. * METHOD: CEventForwarder::GetTypeInfo
  521. *
  522. * PURPOSE: implements method on IDispatch
  523. *
  524. * PARAMETERS:
  525. * unsigned int iTInfo
  526. * LCID lcid
  527. * ITypeInfo FAR* FAR* ppTInfo
  528. *
  529. * RETURNS:
  530. * HRESULT - result code
  531. *
  532. \***************************************************************************/
  533. STDMETHODIMP CEventForwarder::GetTypeInfo( unsigned int iTInfo, LCID lcid, ITypeInfo FAR* FAR* ppTInfo )
  534. {
  535. return m_TypeInfo.GetTypeInfo( iTInfo, lcid, ppTInfo );
  536. }
  537. /***************************************************************************\
  538. *
  539. * METHOD: CEventForwarder::GetIDsOfNames
  540. *
  541. * PURPOSE:implements method on IDispatch
  542. *
  543. * PARAMETERS:
  544. * riid
  545. * rgszNames
  546. * cNames
  547. * lcid
  548. * rgDispId
  549. *
  550. * RETURNS:
  551. * HRESULT - result code
  552. *
  553. \***************************************************************************/
  554. STDMETHODIMP CEventForwarder::GetIDsOfNames( REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames,
  555. LCID lcid, DISPID FAR* rgDispId )
  556. {
  557. return m_TypeInfo.GetIDsOfNames( riid, rgszNames, cNames, lcid, rgDispId );
  558. }
  559. /***************************************************************************\
  560. *
  561. * METHOD: CEventForwarder::Invoke
  562. *
  563. * PURPOSE: implements method on IDispatch. Forwards calls to connector.
  564. * In order to distinguish between calls made on itself, connector
  565. * must provide method, which has different name : ScInvokeOnSinks
  566. *
  567. * PARAMETERS:
  568. * DISPID dispIdMember
  569. * REFIID riid
  570. * LCID lcid
  571. * WORD wFlags
  572. * DISPPARAMS FAR* pDispParams
  573. * VARIANT FAR* pVarResult
  574. * EXCEPINFO FAR* pExcepInfo
  575. * unsigned int FAR* puArgErr
  576. *
  577. * RETURNS:
  578. * HRESULT - result code
  579. *
  580. \***************************************************************************/
  581. STDMETHODIMP CEventForwarder::Invoke( DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags,
  582. DISPPARAMS FAR* pDispParams, VARIANT FAR* pVarResult,
  583. EXCEPINFO FAR* pExcepInfo, unsigned int FAR* puArgErr )
  584. {
  585. DECLARE_SC(sc, TEXT("CEventForwarder::Invoke"));
  586. sc = m_Connector.ScInvokeOnSinks( dispIdMember, riid, lcid, wFlags, pDispParams,
  587. pVarResult, pExcepInfo, puArgErr );
  588. return sc.ToHr();
  589. }
  590. /***************************************************************************\
  591. *
  592. * METHOD: CMMCEventConnector::CMMCEventConnector
  593. *
  594. * PURPOSE: constructor
  595. *
  596. \***************************************************************************/
  597. CMMCEventConnector::CMMCEventConnector() :
  598. m_Forwarder(*this),
  599. m_dwCookie(0),
  600. m_dwWeakRefs(0)
  601. {
  602. }
  603. /***************************************************************************\
  604. *
  605. * METHOD: CMMCEventConnector::~CMMCEventConnector
  606. *
  607. * PURPOSE: Destructor
  608. *
  609. \***************************************************************************/
  610. CMMCEventConnector::~CMMCEventConnector()
  611. {
  612. Disconnect(); // most likely not needed. Just for sanity
  613. }
  614. /***************************************************************************\
  615. *
  616. * METHOD: CMMCEventConnector::InternalRelease
  617. *
  618. * PURPOSE: Overrides method from CComObjectRoot to detect when last "real"
  619. * reference is released. Refs made because of connecting to the
  620. * sink does not count - we would have a deadlock else
  621. *
  622. * PARAMETERS:
  623. *
  624. * RETURNS:
  625. * ULONG - ref count
  626. *
  627. \***************************************************************************/
  628. ULONG CMMCEventConnector::InternalRelease()
  629. {
  630. ULONG uRefsLeft = CComObjectRoot::InternalRelease();
  631. if ((uRefsLeft != 0) && (uRefsLeft == m_dwWeakRefs))
  632. {
  633. // seems like we are alive just because we still connected to the connection point
  634. // disconnect ( no-one uses it anyway )
  635. InternalAddRef(); // Addref to have balance
  636. Disconnect(); // disconnect from the connection point
  637. uRefsLeft = CComObjectRoot::InternalRelease(); // release again
  638. }
  639. return uRefsLeft;
  640. }
  641. /***************************************************************************\
  642. *
  643. * METHOD: CMMCEventConnector::WeakAddRef
  644. *
  645. * PURPOSE: counts reference from connection points. AddRefs regularly as well
  646. *
  647. * PARAMETERS:
  648. *
  649. * RETURNS:
  650. * ULONG - ref count
  651. *
  652. \***************************************************************************/
  653. ULONG CMMCEventConnector::WeakAddRef()
  654. {
  655. ++m_dwWeakRefs;
  656. return AddRef();
  657. }
  658. /***************************************************************************\
  659. *
  660. * METHOD: CMMCEventConnector::WeakRelease
  661. *
  662. * PURPOSE: counts reference from connection points. Releases regularly as well
  663. *
  664. * PARAMETERS:
  665. *
  666. * RETURNS:
  667. * ULONG - ref count
  668. *
  669. \***************************************************************************/
  670. ULONG CMMCEventConnector::WeakRelease()
  671. {
  672. --m_dwWeakRefs;
  673. return Release();
  674. }
  675. /***************************************************************************\
  676. *
  677. * METHOD: CMMCEventConnector::ScInvokeOnSinks
  678. *
  679. * PURPOSE: This method has a signature of IDispath::Invoke and is
  680. * called from connection point to inform about the event
  681. * Method's job is to fork the call to each own connected sink
  682. *
  683. * RETURNS:
  684. * SC - result code
  685. *
  686. \***************************************************************************/
  687. SC CMMCEventConnector::ScInvokeOnSinks( DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags,
  688. DISPPARAMS FAR* pDispParams, VARIANT FAR* pVarResult,
  689. EXCEPINFO FAR* pExcepInfo, unsigned int FAR* puArgErr )
  690. {
  691. DECLARE_SC(sc, TEXT("CMMCEventConnector::ScInvokeOnSinks"));
  692. // find connection point
  693. IConnectionPointPtr spConnectionPoint;
  694. sc = FindConnectionPoint(DIID_AppEvents, &spConnectionPoint);
  695. if (sc)
  696. return sc;
  697. // get connections
  698. IEnumConnectionsPtr spEnumConnections;
  699. sc = spConnectionPoint->EnumConnections(&spEnumConnections);
  700. if (sc)
  701. return sc.ToHr();
  702. // recheck the pointer
  703. sc = ScCheckPointers(spEnumConnections, E_UNEXPECTED);
  704. if (sc)
  705. return sc.ToHr();
  706. // reset iterator
  707. sc = spEnumConnections->Reset();
  708. if (sc)
  709. return sc.ToHr();
  710. // iterate thru sinks until Next returns S_FALSE.
  711. CONNECTDATA connectdata;
  712. SC sc_last_error;
  713. while (1) // will use <break> to exit
  714. {
  715. // get the next sink
  716. ZeroMemory(&connectdata, sizeof(connectdata));
  717. sc = spEnumConnections->Next( 1, &connectdata, NULL );
  718. if (sc)
  719. return sc.ToHr();
  720. // done if no more sinks
  721. if (sc == SC(S_FALSE))
  722. break;
  723. // recheck the pointer
  724. sc = ScCheckPointers(connectdata.pUnk, E_UNEXPECTED);
  725. if (sc)
  726. return sc.ToHr();
  727. // QI for IDispatch
  728. IDispatchPtr spDispatch = (IDispatch *)connectdata.pUnk;
  729. connectdata.pUnk->Release();
  730. // recheck the pointer
  731. sc = ScCheckPointers(spDispatch, E_UNEXPECTED);
  732. if (sc)
  733. return sc.ToHr();
  734. // invoke on the sink
  735. sc = spDispatch->Invoke( dispIdMember, riid, lcid, wFlags, pDispParams,
  736. pVarResult, pExcepInfo, puArgErr );
  737. if (sc)
  738. {
  739. sc_last_error = sc; // continue even if some calls failed
  740. sc.TraceAndClear();
  741. }
  742. }
  743. return sc_last_error.ToHr();
  744. }
  745. /***************************************************************************\
  746. *
  747. * METHOD: CMMCEventConnector::ConnectTo
  748. *
  749. * PURPOSE: Connects to Application object and starts forwarding its events
  750. *
  751. * PARAMETERS:
  752. * PAPPLICATION Application
  753. *
  754. * RETURNS:
  755. * SC - result code
  756. *
  757. \***************************************************************************/
  758. STDMETHODIMP CMMCEventConnector::ConnectTo(PAPPLICATION Application)
  759. {
  760. DECLARE_SC(sc, TEXT("ConnectTo"));
  761. // disconnect from former connections
  762. sc = Disconnect();
  763. if (sc)
  764. return sc.ToHr();
  765. // check if com object supports IConnectionPointContainer;
  766. IConnectionPointContainerPtr spContainer = Application;
  767. sc = ScCheckPointers(spContainer);
  768. if (sc)
  769. return sc.ToHr();
  770. // get connection point
  771. sc = spContainer->FindConnectionPoint(DIID_AppEvents, &m_spConnectionPoint);
  772. if (sc)
  773. return sc.ToHr();
  774. sc = m_spConnectionPoint->Advise(&m_Forwarder, &m_dwCookie);
  775. if (sc)
  776. return sc.ToHr();
  777. return S_OK;
  778. }
  779. /***************************************************************************\
  780. *
  781. * METHOD: CMMCEventConnector::Disconnect
  782. *
  783. * PURPOSE: Disconnects from connection point if is connected to one
  784. *
  785. * PARAMETERS:
  786. *
  787. * RETURNS:
  788. * HRESULT - result code
  789. *
  790. \***************************************************************************/
  791. STDMETHODIMP CMMCEventConnector::Disconnect()
  792. {
  793. DECLARE_SC(sc, TEXT("CMMCEventConnector::Disconnect"));
  794. if (m_dwCookie)
  795. {
  796. if (m_spConnectionPoint != NULL)
  797. {
  798. sc = m_spConnectionPoint->Unadvise(m_dwCookie);
  799. if (sc)
  800. sc.TraceAndClear();
  801. }
  802. m_dwCookie = 0;
  803. m_spConnectionPoint = NULL;
  804. }
  805. return sc.ToHr();
  806. }