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.

3749 lines
108 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1999
  5. //
  6. // File: amc.cpp
  7. //
  8. // Contents: The one and only app
  9. //
  10. // History: 01-Jan-96 TRomano Created
  11. // 16-Jul-96 WayneSc Add code to switch views
  12. //
  13. //--------------------------------------------------------------------------
  14. #include "stdafx.h"
  15. #include "AMC.h"
  16. #include "MainFrm.h"
  17. #include "ChildFrm.h"
  18. #include "AMCDoc.h"
  19. #include "AMCView.h"
  20. #include "amcdocmg.h"
  21. #include "sysmenu.h"
  22. #include <shlobj.h>
  23. #include "strings.h"
  24. #include "macros.h"
  25. #include "scripthost.h"
  26. #include "HtmlHelp.h"
  27. #include "scriptevents.h"
  28. #include "mmcutil.h"
  29. #include "guidhelp.h" // for CLSID relational operators
  30. #include "archpicker.h"
  31. #include "classreg.h"
  32. #define DECLSPEC_UUID(x) __declspec(uuid(x))
  33. #include "websnk.h"
  34. #include "websnk_i.c"
  35. // We aren't picking this up from winuser.h for some reason.
  36. #define ISOLATIONAWARE_NOSTATICIMPORT_MANIFEST_RESOURCE_ID MAKEINTRESOURCE(3)
  37. /*
  38. * define our own Win64 symbol to make it easy to include 64-bit only
  39. * code in the 32-bit build, so we can exercise some code on 32-bit Windows
  40. * where the debuggers are better
  41. */
  42. #ifdef _WIN64
  43. #define MMC_WIN64
  44. #endif
  45. #ifndef MMC_WIN64
  46. #include <wow64t.h> // for Wow64DisableFilesystemRedirector
  47. #endif
  48. /*
  49. * multimon.h is included by stdafx.h, without defining COMPILE_MULTIMON_STUBS
  50. * first. We need to include it again here after defining COMPILE_MULTIMON_STUBS
  51. * so we'll get the stub functions.
  52. */
  53. #if (_WIN32_WINNT < 0x0500)
  54. #define COMPILE_MULTIMON_STUBS
  55. #include <multimon.h>
  56. #endif
  57. #ifdef DBG
  58. CTraceTag tagEnableScriptEngines(_T("MMCScriptEngines"), _T("Enable"));
  59. CTraceTag tag32BitTransfer(_T("64/32-bit interop"), _T("64/32-bit interop"));
  60. #endif
  61. // Note: These strings do not need to be localizable.
  62. const TCHAR CAMCApp::m_szSettingsSection[] = _T("Settings");
  63. const TCHAR CAMCApp::m_szUserDirectoryEntry[] = _T("Save Location");
  64. bool CanCloseDoc(void);
  65. SC ScExpandEnvironmentStrings (CString& str);
  66. //############################################################################
  67. //############################################################################
  68. //
  69. // ATL Support
  70. //
  71. //############################################################################
  72. //############################################################################
  73. #include <atlimpl.cpp>
  74. #include <atlwin.cpp>
  75. // The one and only instance of CAtlGlobalModule
  76. CAtlGlobalModule _Module;
  77. //############################################################################
  78. //############################################################################
  79. //
  80. // Trace Tags
  81. //
  82. //############################################################################
  83. //############################################################################
  84. #ifdef DBG
  85. // enable this tag if you suspect memory corruption
  86. // and you don't mind things slowing way down
  87. BEGIN_TRACETAG(CDebugCRTCheck)
  88. void OnEnable()
  89. {
  90. _CrtSetDbgFlag (_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)
  91. | _CRTDBG_CHECK_ALWAYS_DF
  92. | _CRTDBG_DELAY_FREE_MEM_DF);
  93. }
  94. void OnDisable()
  95. {
  96. _CrtSetDbgFlag (_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)
  97. & ~(_CRTDBG_CHECK_ALWAYS_DF
  98. | _CRTDBG_DELAY_FREE_MEM_DF) );
  99. }
  100. END_TRACETAG(CDebugCRTCheck, TEXT("Debug CRTs"), TEXT("Memory Check - SLOW!"))
  101. CTraceTag tagAMCAppInit(TEXT("CAMCView"), TEXT("InitInstance"));
  102. CTraceTag tagATLLock(TEXT("ATL"), TEXT("Lock/Unlock")); // used by atlconui.h
  103. CTraceTag tagGDIBatching(TEXT("CAMCView"), TEXT("Disable Graphics/GDI Batching"));
  104. CTraceTag tagForceMirror(TEXT("Mirroring"), TEXT("Force MMC windows to be mirrored on non-mirrored systems"));
  105. #endif
  106. //############################################################################
  107. //############################################################################
  108. //
  109. // Implementation of class CMMCApplication - the root level
  110. // automation class
  111. //
  112. //############################################################################
  113. //############################################################################
  114. class CMMCApplication :
  115. public CMMCIDispatchImpl<_Application, &CLSID_Application>,
  116. public CComCoClass<CMMCApplication, &CLSID_Application>,
  117. // support for connection points (script events)
  118. public IConnectionPointContainerImpl<CMMCApplication>,
  119. public IConnectionPointImpl<CMMCApplication, &DIID_AppEvents, CComDynamicUnkArray>,
  120. public IProvideClassInfo2Impl<&CLSID_Application, &DIID_AppEvents, &LIBID_MMC20>
  121. {
  122. public:
  123. BEGIN_MMC_COM_MAP(CMMCApplication)
  124. COM_INTERFACE_ENTRY(IProvideClassInfo)
  125. COM_INTERFACE_ENTRY(IProvideClassInfo2)
  126. COM_INTERFACE_ENTRY(IConnectionPointContainer)
  127. END_MMC_COM_MAP()
  128. DECLARE_NOT_AGGREGATABLE(CMMCApplication)
  129. static HRESULT WINAPI UpdateRegistry(BOOL bRegister)
  130. {
  131. CObjectRegParams op (
  132. CLSID_Application,
  133. _T("mmc.exe"),
  134. _T("MMC Application Class"),
  135. _T("MMC20.Application.1"),
  136. _T("MMC20.Application"),
  137. _T("LocalServer32") );
  138. return (MMCUpdateRegistry (bRegister, &op, NULL));
  139. }
  140. //hooks into ATL's construction
  141. HRESULT InternalFinalConstructRelease(); // not FinalConstruct() - this is to work around a bogus ATL assert.
  142. BEGIN_CONNECTION_POINT_MAP(CMMCApplication)
  143. CONNECTION_POINT_ENTRY(DIID_AppEvents)
  144. END_CONNECTION_POINT_MAP()
  145. // overriden to do more job than the base class does
  146. virtual ::SC ScOnDisconnectObjects();
  147. private:
  148. //IMMCApplication
  149. public:
  150. void STDMETHODCALLTYPE Help();
  151. void STDMETHODCALLTYPE Quit();
  152. STDMETHOD(get_Document) (Document **ppDocument);
  153. STDMETHOD(Load) (BSTR bstrFilename);
  154. STDMETHOD(get_Frame) (Frame **ppFrame);
  155. STDMETHOD(get_Visible) (BOOL *pVisible);
  156. STDMETHOD(Show) ();
  157. STDMETHOD(Hide) ();
  158. STDMETHOD(get_UserControl) (PBOOL pUserControl);
  159. STDMETHOD(put_UserControl) (BOOL bUserControl);
  160. STDMETHOD(get_VersionMajor) (PLONG pVersionMajor);
  161. STDMETHOD(get_VersionMinor) (PLONG pVersionMinor);
  162. private:
  163. // Return the CAMCApp only if it is initialized. We do not want
  164. // object model methods to operate on app while initializing.
  165. CAMCApp *GetApp()
  166. {
  167. CAMCApp *pApp = AMCGetApp();
  168. if ( (! pApp) || (pApp->IsInitializing()) )
  169. return NULL;
  170. return pApp;
  171. }
  172. };
  173. //############################################################################
  174. //############################################################################
  175. //
  176. // Event map for application events
  177. //
  178. //############################################################################
  179. //############################################################################
  180. DISPATCH_CALL_MAP_BEGIN(AppEvents)
  181. DISPATCH_CALL1( OnQuit, PAPPLICATION )
  182. DISPATCH_CALL2( OnDocumentOpen, PDOCUMENT, BOOL)
  183. DISPATCH_CALL1( OnDocumentClose, PDOCUMENT )
  184. DISPATCH_CALL2( OnSnapInAdded, PDOCUMENT, PSNAPIN )
  185. DISPATCH_CALL2( OnSnapInRemoved, PDOCUMENT, PSNAPIN )
  186. DISPATCH_CALL1( OnNewView, PVIEW )
  187. DISPATCH_CALL1( OnViewClose, PVIEW )
  188. DISPATCH_CALL2( OnViewChange, PVIEW, PNODE );
  189. DISPATCH_CALL2( OnSelectionChange, PVIEW, PNODES )
  190. DISPATCH_CALL1( OnContextMenuExecuted, PMENUITEM );
  191. DISPATCH_CALL0( OnToolbarButtonClicked )
  192. DISPATCH_CALL1( OnListUpdated, PVIEW )
  193. DISPATCH_CALL_MAP_END()
  194. /*+-------------------------------------------------------------------------*
  195. *
  196. * CMMCApplication::InternalFinalConstructRelease
  197. *
  198. * PURPOSE: Hands the CAMCApp a pointer to the 'this' object.
  199. *
  200. *+-------------------------------------------------------------------------*/
  201. HRESULT
  202. CMMCApplication::InternalFinalConstructRelease()
  203. {
  204. DECLARE_SC(sc, TEXT("CMMCApplication::InternalFinalConstructRelease"));
  205. // Dont use GetApp, we need to get CAMCApp even if it is not fully initialized.
  206. CAMCApp *pApp = AMCGetApp();
  207. sc = ScCheckPointers(pApp);
  208. if(sc)
  209. return sc.ToHr(); // some wierd error.
  210. sc = pApp->ScRegister_Application(this);
  211. return sc.ToHr();
  212. }
  213. /*+-------------------------------------------------------------------------*
  214. *
  215. * CMMCApplication::GetFrame
  216. *
  217. * PURPOSE: A static function that hooks into the COM interface entry list
  218. * and allows a tear-off object to be created that implements the
  219. * Frame interface.
  220. *
  221. * PARAMETERS:
  222. * void* pv : Defined by ATL to hold a pointer to the CMMCApplication object
  223. * because this is a static method.
  224. * REFIID riid : As per QI
  225. * LPVOID* ppv : As per QI
  226. * DWORD dw : ignored
  227. *
  228. * RETURNS:
  229. * HRESULT WINAPI
  230. *
  231. *+-------------------------------------------------------------------------*/
  232. STDMETHODIMP
  233. CMMCApplication::get_Frame(Frame **ppFrame)
  234. {
  235. DECLARE_SC(sc, TEXT("CMMCApplication::get_Frame"));
  236. if(!ppFrame)
  237. {
  238. sc = E_POINTER;
  239. return sc.ToHr();
  240. }
  241. // get the app
  242. CAMCApp *pApp = GetApp();
  243. if(NULL == pApp)
  244. {
  245. sc = E_UNEXPECTED;
  246. return sc.ToHr();
  247. }
  248. CMainFrame *pMainFrame = pApp->GetMainFrame();
  249. if(!pMainFrame)
  250. {
  251. sc = E_UNEXPECTED;
  252. return sc.ToHr();
  253. }
  254. sc = pMainFrame->ScGetFrame(ppFrame);
  255. return sc.ToHr();
  256. }
  257. STDMETHODIMP
  258. CMMCApplication::get_Document(Document **ppDocument)
  259. {
  260. DECLARE_SC(sc, TEXT("CMMCApplication::get_Document"));
  261. CAMCDoc* const pDoc = CAMCDoc::GetDocument();
  262. ASSERT(ppDocument != NULL);
  263. if(ppDocument == NULL || (pDoc == NULL))
  264. {
  265. sc = E_POINTER;
  266. return sc.ToHr();
  267. }
  268. sc = pDoc->ScGetMMCDocument(ppDocument);
  269. if(sc)
  270. return sc.ToHr();
  271. return sc.ToHr();
  272. }
  273. /***************************************************************************\
  274. *
  275. * METHOD: CMMCApplication::Load
  276. *
  277. * PURPOSE: implements Application.Load for object model
  278. *
  279. * PARAMETERS:
  280. * BSTR bstrFilename - console file to load
  281. *
  282. * RETURNS:
  283. * SC - result code
  284. *
  285. \***************************************************************************/
  286. STDMETHODIMP
  287. CMMCApplication::Load(BSTR bstrFilename)
  288. {
  289. DECLARE_SC(sc, TEXT("CMMCApplication::Load"));
  290. CAMCApp *pApp = GetApp();
  291. sc = ScCheckPointers(pApp, E_UNEXPECTED);
  292. if (sc)
  293. return sc.ToHr();
  294. USES_CONVERSION;
  295. pApp->OpenDocumentFile(OLE2CT(bstrFilename));
  296. return sc.ToHr();
  297. }
  298. void
  299. STDMETHODCALLTYPE CMMCApplication::Help()
  300. {
  301. DECLARE_SC(sc, TEXT("CMMCApplication::Help"));
  302. CAMCApp *pApp = GetApp();
  303. if(NULL == pApp)
  304. {
  305. sc = E_UNEXPECTED;
  306. return;
  307. }
  308. sc = pApp->ScHelp();
  309. if(sc)
  310. return;
  311. return;
  312. }
  313. void
  314. STDMETHODCALLTYPE CMMCApplication::Quit()
  315. {
  316. SC sc;
  317. CAMCApp *pApp = GetApp();
  318. if(NULL == pApp)
  319. goto Error;
  320. // confiscate the control from user
  321. pApp->SetUnderUserControl(false);
  322. // get mainframe
  323. {
  324. CMainFrame * pMainFrame = pApp->GetMainFrame();
  325. if(NULL == pMainFrame)
  326. goto Error;
  327. // close it gracefully.
  328. pMainFrame->PostMessage(WM_CLOSE);
  329. }
  330. Cleanup:
  331. return;
  332. Error:
  333. sc = E_UNEXPECTED;
  334. TraceError(TEXT("CMMCApplication::Quit"), sc);
  335. goto Cleanup;
  336. }
  337. /*+-------------------------------------------------------------------------*
  338. *
  339. * CMMCApplication::get_VersionMajor
  340. *
  341. * PURPOSE: Returns the major version number for the installed version of MMC.
  342. *
  343. * PARAMETERS:
  344. * PLONG pVersionMajor :
  345. *
  346. * RETURNS:
  347. * HRESULT
  348. *
  349. *+-------------------------------------------------------------------------*/
  350. HRESULT
  351. CMMCApplication::get_VersionMajor(PLONG pVersionMajor)
  352. {
  353. DECLARE_SC(sc, TEXT("CMMCApplication::get_VersionMajor"));
  354. sc = ScCheckPointers(pVersionMajor);
  355. if(sc)
  356. return sc.ToHr();
  357. *pVersionMajor = MMC_VERSION_MAJOR;
  358. return sc.ToHr();
  359. }
  360. /*+-------------------------------------------------------------------------*
  361. *
  362. * CMMCApplication::get_VersionMinor
  363. *
  364. * PURPOSE: Returns the minor version number for the installed version of MMC.
  365. *
  366. * PARAMETERS:
  367. * PLONG pVersionMinor :
  368. *
  369. * RETURNS:
  370. * HRESULT
  371. *
  372. *+-------------------------------------------------------------------------*/
  373. HRESULT
  374. CMMCApplication::get_VersionMinor(PLONG pVersionMinor)
  375. {
  376. DECLARE_SC(sc, TEXT("CMMCApplication::get_VersionMinor"));
  377. sc = ScCheckPointers(pVersionMinor);
  378. if(sc)
  379. return sc.ToHr();
  380. *pVersionMinor = MMC_VERSION_MINOR;
  381. return sc.ToHr();
  382. }
  383. //+-------------------------------------------------------------------
  384. //
  385. // Member: CMMCApplication::get_Visible
  386. //
  387. // Synopsis: Returns the visible property
  388. //
  389. // Arguments: [PBOOL] - out bool
  390. //
  391. // Returns: HRESULT
  392. //
  393. //--------------------------------------------------------------------
  394. HRESULT CMMCApplication::get_Visible (PBOOL pbVisible)
  395. {
  396. DECLARE_SC(sc, _T("CMMCApplication::get_Visible"));
  397. sc = ScCheckPointers(pbVisible);
  398. if (sc)
  399. return sc.ToHr();
  400. // get the app
  401. CAMCApp *pApp = GetApp();
  402. sc = ScCheckPointers(pApp, E_UNEXPECTED);
  403. if (sc)
  404. return (sc.ToHr());
  405. CMainFrame *pMainFrame = pApp->GetMainFrame();
  406. sc = ScCheckPointers(pMainFrame, E_UNEXPECTED);
  407. if (sc)
  408. return (sc.ToHr());
  409. *pbVisible = pMainFrame->IsWindowVisible();
  410. return (sc.ToHr());
  411. }
  412. //+-------------------------------------------------------------------
  413. //
  414. // Member: CMMCApplication::Show
  415. //
  416. // Synopsis: Shows the application
  417. //
  418. // Arguments: None
  419. //
  420. // Returns: HRESULT
  421. //
  422. //--------------------------------------------------------------------
  423. HRESULT CMMCApplication::Show ()
  424. {
  425. DECLARE_SC(sc, _T("CMMCApplication::Show"));
  426. // get the app
  427. CAMCApp *pApp = GetApp();
  428. sc = ScCheckPointers(pApp, E_UNEXPECTED);
  429. if (sc)
  430. return (sc.ToHr());
  431. CMainFrame *pMainFrame = pApp->GetMainFrame();
  432. sc = ScCheckPointers(pMainFrame, E_UNEXPECTED);
  433. if (sc)
  434. return (sc.ToHr());
  435. sc = pMainFrame->ShowWindow(SW_SHOW);
  436. return (sc.ToHr());
  437. }
  438. //+-------------------------------------------------------------------
  439. //
  440. // Member: CMMCApplication::Hide
  441. //
  442. // Synopsis: Hides the application.
  443. //
  444. // Arguments: None
  445. //
  446. // Returns: HRESULT
  447. //
  448. // Note: If the user is under control (UserControl property is set)
  449. // then Hide fails.
  450. //
  451. //--------------------------------------------------------------------
  452. HRESULT CMMCApplication::Hide ()
  453. {
  454. DECLARE_SC(sc, _T("CMMCApplication::Hide"));
  455. // get the app
  456. CAMCApp *pApp = GetApp();
  457. sc = ScCheckPointers(pApp, E_UNEXPECTED);
  458. if (sc)
  459. return (sc.ToHr());
  460. // Cant hide if app is under user control.
  461. if (pApp->IsUnderUserControl())
  462. {
  463. sc = E_FAIL;
  464. return sc.ToHr();
  465. }
  466. CMainFrame *pMainFrame = pApp->GetMainFrame();
  467. sc = ScCheckPointers(pMainFrame, E_UNEXPECTED);
  468. if (sc)
  469. return (sc.ToHr());
  470. sc = pMainFrame->ShowWindow(SW_HIDE);
  471. return (sc.ToHr());
  472. }
  473. //+-------------------------------------------------------------------
  474. //
  475. // Member: CMMCApplication::get_UserControl
  476. //
  477. // Synopsis: Returns the UserControl property
  478. //
  479. // Arguments: PBOOL - out param.
  480. //
  481. // Returns: HRESULT
  482. //
  483. //--------------------------------------------------------------------
  484. HRESULT CMMCApplication::get_UserControl (PBOOL pbUserControl)
  485. {
  486. DECLARE_SC(sc, _T("CMMCApplication::get_UserControl"));
  487. sc = ScCheckPointers(pbUserControl);
  488. if (sc)
  489. return (sc.ToHr());
  490. // get the app
  491. CAMCApp *pApp = GetApp();
  492. sc = ScCheckPointers(pApp, E_UNEXPECTED);
  493. if (sc)
  494. return (sc.ToHr());
  495. *pbUserControl = pApp->IsUnderUserControl();
  496. return (sc.ToHr());
  497. }
  498. //+-------------------------------------------------------------------
  499. //
  500. // Member: CMMCApplication::put_UserControl
  501. //
  502. // Synopsis: Sets the UserControl property
  503. //
  504. // Arguments: BOOL
  505. //
  506. // Returns: HRESULT
  507. //
  508. //--------------------------------------------------------------------
  509. HRESULT CMMCApplication::put_UserControl (BOOL bUserControl)
  510. {
  511. DECLARE_SC(sc, _T("CMMCApplication::put_UserControl"));
  512. // get the app
  513. CAMCApp *pApp = GetApp();
  514. sc = ScCheckPointers(pApp, E_UNEXPECTED);
  515. if (sc)
  516. return (sc.ToHr());
  517. pApp->SetUnderUserControl(bUserControl);
  518. return (sc.ToHr());
  519. }
  520. /***************************************************************************\
  521. *
  522. * METHOD: CMMCApplication::ScOnDisconnectObjects
  523. *
  524. * PURPOSE: special disconnect implementation. For this object implementation
  525. * provided by the base class is not enough, since connection point
  526. * is an internal object which may also have strong references on it
  527. *
  528. * PARAMETERS:
  529. *
  530. * RETURNS:
  531. * SC - result code
  532. *
  533. \***************************************************************************/
  534. SC CMMCApplication::ScOnDisconnectObjects()
  535. {
  536. DECLARE_SC(sc, TEXT("CMMCApplication::ScOnDisconnectObjects"));
  537. // get the connection point container
  538. IConnectionPointContainerPtr spContainer(GetUnknown());
  539. sc = ScCheckPointers( spContainer, E_UNEXPECTED );
  540. if (sc)
  541. return sc;
  542. // get the connection point
  543. IConnectionPointPtr spConnectionPoint;
  544. sc = spContainer->FindConnectionPoint( DIID_AppEvents, &spConnectionPoint );
  545. if (sc)
  546. return sc;
  547. // cut connection point references
  548. sc = CoDisconnectObject( spConnectionPoint, 0/*dwReserved*/ );
  549. if (sc)
  550. return sc;
  551. // let the base class do the rest
  552. sc = CMMCIDispatchImplClass::ScOnDisconnectObjects();
  553. if (sc)
  554. return sc;
  555. return sc;
  556. }
  557. //############################################################################
  558. //############################################################################
  559. //
  560. // ATL GLobal Object Map
  561. //
  562. //############################################################################
  563. //############################################################################
  564. BEGIN_OBJECT_MAP(ObjectMap)
  565. OBJECT_ENTRY(CLSID_Application, CMMCApplication)
  566. END_OBJECT_MAP()
  567. /*+-------------------------------------------------------------------------*
  568. * CLockChildWindowUpdate
  569. *
  570. * Helper class whose constructor turns off redraw for all of the children
  571. * of the given window, and whose destructor turns redraw back on for all
  572. * of the windows for which it was turned off.
  573. *
  574. * This is used to prevent ugly transient drawing while opening console
  575. * files that take a long time to completely open (bug 150356).
  576. *--------------------------------------------------------------------------*/
  577. class CLockChildWindowUpdate
  578. {
  579. public:
  580. CLockChildWindowUpdate (CWnd* pwndLock) : m_pwndLock(pwndLock)
  581. {
  582. if (m_pwndLock != NULL)
  583. {
  584. CWnd* pwndChild;
  585. /*
  586. * turn off redraw for each child, saving the HWND for later
  587. * so we can turn it back on (we save the HWND instead of the
  588. * CWnd* because MFC might have returned a temporary object).
  589. */
  590. for (pwndChild = m_pwndLock->GetWindow (GW_CHILD);
  591. pwndChild != NULL;
  592. pwndChild = pwndChild->GetNextWindow())
  593. {
  594. pwndChild->SetRedraw (false);
  595. m_vChildren.push_back (pwndChild->GetSafeHwnd());
  596. }
  597. }
  598. }
  599. ~CLockChildWindowUpdate()
  600. {
  601. std::vector<HWND>::iterator it;
  602. /*
  603. * for every window for which we turned off redraw, turn it back on
  604. */
  605. for (it = m_vChildren.begin(); it != m_vChildren.end(); ++it)
  606. {
  607. HWND hWndChild = *it;
  608. if ( (hWndChild != NULL) && ::IsWindow(hWndChild) )
  609. {
  610. CWnd *pwndChild = CWnd::FromHandle(hWndChild);
  611. pwndChild->SetRedraw (true);
  612. pwndChild->RedrawWindow (NULL, NULL,
  613. RDW_INVALIDATE | RDW_UPDATENOW |
  614. RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN);
  615. }
  616. }
  617. }
  618. private:
  619. CWnd* const m_pwndLock;
  620. std::vector<HWND> m_vChildren;
  621. };
  622. //############################################################################
  623. //############################################################################
  624. //
  625. // Implementation of class CAMCMultiDocTemplate
  626. //
  627. //############################################################################
  628. //############################################################################
  629. class CAMCMultiDocTemplate : public CMultiDocTemplate
  630. {
  631. public:
  632. CAMCMultiDocTemplate(UINT nIDResource, CRuntimeClass* pDocClass,
  633. CRuntimeClass* pFrameClass, CRuntimeClass* pViewClass)
  634. : CMultiDocTemplate(nIDResource, pDocClass, pFrameClass, pViewClass)
  635. {
  636. }
  637. CDocument* OpenDocumentFile(LPCTSTR lpszPathName,
  638. BOOL bMakeVisible)
  639. {
  640. DECLARE_SC(sc, TEXT("CAMCMultiDocTemplate::OpenDocumentFile"));
  641. CAMCDoc* const pDoc = CAMCDoc::GetDocument();
  642. if (pDoc && (!pDoc->SaveModified() || !CanCloseDoc() ))
  643. return NULL; // leave the original one
  644. CLockChildWindowUpdate lock (AfxGetMainWnd());
  645. CAMCDoc* pDocument = (CAMCDoc*)CreateNewDocument();
  646. if (pDocument == NULL)
  647. {
  648. TRACE0("CDocTemplate::CreateNewDocument returned NULL.\n");
  649. AfxMessageBox(AFX_IDP_FAILED_TO_CREATE_DOC); // do not change to MMCMessageBox
  650. return NULL;
  651. }
  652. HRESULT hr;
  653. if ((hr = pDocument->InitNodeManager()) != S_OK)
  654. {
  655. TRACE1("CAMCDoc::InitNodeManager failed, 0x%08x\n", hr);
  656. CAMCApp* pApp = AMCGetApp();
  657. MMCErrorBox((pApp && pApp->IsWin9xPlatform())
  658. ? IDS_NODEMGR_FAILED_9x
  659. : IDS_NODEMGR_FAILED);
  660. delete pDocument; // explicit delete on error
  661. return NULL;
  662. }
  663. ASSERT_VALID(pDocument);
  664. BOOL bAutoDelete = pDocument->m_bAutoDelete;
  665. pDocument->m_bAutoDelete = FALSE; // don't destroy if something goes wrong
  666. CFrameWnd* pFrame = CreateNewFrame(pDocument, NULL);
  667. pDocument->m_bAutoDelete = bAutoDelete;
  668. if (pFrame == NULL)
  669. {
  670. AfxMessageBox(AFX_IDP_FAILED_TO_CREATE_DOC); // do not change to MMCMessageBox
  671. delete pDocument; // explicit delete on error
  672. return NULL;
  673. }
  674. ASSERT_VALID(pFrame);
  675. if (lpszPathName == NULL)
  676. {
  677. // create a new document - with default document name
  678. SetDefaultTitle(pDocument);
  679. // avoid creating temporary compound file when starting up invisible
  680. if (!bMakeVisible)
  681. pDocument->m_bEmbedded = TRUE;
  682. if (!pDocument->OnNewDocument())
  683. {
  684. // user has be alerted to what failed in OnNewDocument
  685. TRACE0("CDocument::OnNewDocument returned FALSE.\n");
  686. AfxMessageBox (AFX_IDP_FAILED_TO_CREATE_DOC); // do not change to MMCMessageBox
  687. pFrame->DestroyWindow();
  688. return NULL;
  689. }
  690. // it worked, now bump untitled count
  691. m_nUntitledCount++;
  692. InitialUpdateFrame(pFrame, pDocument, bMakeVisible);
  693. }
  694. else
  695. {
  696. // open an existing document
  697. CWaitCursor wait;
  698. if (!pDocument->OnOpenDocument(lpszPathName))
  699. {
  700. // user has be alerted to what failed in OnOpenDocument
  701. TRACE0("CDocument::OnOpenDocument returned FALSE.\n");
  702. pFrame->DestroyWindow();
  703. return NULL;
  704. }
  705. #ifdef _MAC
  706. // if the document is dirty, we must have opened a stationery pad
  707. // - don't change the pathname because we want to treat the document
  708. // as untitled
  709. if (!pDocument->IsModified())
  710. #endif
  711. pDocument->SetPathName(lpszPathName);
  712. //REVIEW: dburg: InitialUpdateFrame(pFrame, pDocument, bMakeVisible);
  713. pFrame->DestroyWindow();
  714. pDocument->SetModifiedFlag (false);
  715. pDocument->SetFrameModifiedFlag (false);
  716. }
  717. // fire script event
  718. CAMCApp* pApp = AMCGetApp();
  719. sc = ScCheckPointers(pApp, E_UNEXPECTED);
  720. if (sc)
  721. return pDocument;
  722. sc = pApp->ScOnNewDocument(pDocument, (lpszPathName != NULL));
  723. if (sc)
  724. sc.TraceAndClear();
  725. return pDocument;
  726. }
  727. // this method is overrided to catch application quit event
  728. virtual void CloseAllDocuments( BOOL bEndSession )
  729. {
  730. DECLARE_SC(sc, TEXT("CAMCMultiDocTemplate::CloseAllDocuments"));
  731. // invoke base class to perform required tasks
  732. CMultiDocTemplate::CloseAllDocuments( bEndSession );
  733. // no other way we can get here but exit app
  734. // so that's a good time for script to know it
  735. CAMCApp* pApp = AMCGetApp();
  736. sc = ScCheckPointers(pApp, E_UNEXPECTED);
  737. if (sc)
  738. return;
  739. // forward to application to emit the script event
  740. sc = pApp->ScOnQuitApp();
  741. if (sc)
  742. sc.TraceAndClear();
  743. // cut off all strong references now.
  744. // Quit was executed - nothing else matters
  745. sc = GetComObjectEventSource().ScFireEvent( CComObjectObserver::ScOnDisconnectObjects );
  746. if (sc)
  747. sc.TraceAndClear();
  748. }
  749. };
  750. // Declare debug infolevel for this component
  751. DECLARE_INFOLEVEL(AMCConUI);
  752. //############################################################################
  753. //############################################################################
  754. //
  755. // Implementation of class CAMCApp
  756. //
  757. //############################################################################
  758. //############################################################################
  759. IMPLEMENT_DYNAMIC(CAMCApp, CWinApp)
  760. BEGIN_MESSAGE_MAP(CAMCApp, CWinApp)
  761. //{{AFX_MSG_MAP(CAMCApp)
  762. ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
  763. //}}AFX_MSG_MAP
  764. // Standard file based document commands
  765. ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)
  766. ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)
  767. // Standard print setup command
  768. ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup)
  769. ON_COMMAND(ID_FILE_NEW_USER_MODE, OnFileNewInUserMode) // CTRL+N in user mode - do nothing
  770. END_MESSAGE_MAP()
  771. /////////////////////////////////////////////////////////////////////////////
  772. // CAMCApp construction
  773. CAMCApp::CAMCApp() :
  774. m_bOleInitialized(FALSE),
  775. m_bDefaultDirSet(FALSE),
  776. m_eMode(eMode_Error),
  777. m_fAuthorModeForced(false),
  778. m_fInitializing(true),
  779. m_fDelayCloseUntilIdle(false),
  780. m_fCloseCameFromMainPump(false),
  781. m_nMessagePumpNestingLevel(0),
  782. m_fIsWin9xPlatform(false),
  783. m_dwHelpCookie(0),
  784. m_bHelpInitialized(false),
  785. m_fUnderUserControl(true),
  786. m_fRunningAsOLEServer(false)
  787. {
  788. }
  789. /////////////////////////////////////////////////////////////////////////////
  790. // The one and only CAMCApp object
  791. CAMCApp theApp;
  792. const CRect g_rectEmpty (0, 0, 0, 0);
  793. void DeleteDDEKeys()
  794. {
  795. HKEY key;
  796. if (ERROR_SUCCESS == RegOpenKeyEx (HKEY_CLASSES_ROOT,
  797. _T("MSCFile\\shell\\open"),
  798. 0, KEY_SET_VALUE, &key))
  799. {
  800. theApp.DelRegTree (key, _T("ddeexec"));
  801. RegCloseKey (key);
  802. }
  803. }
  804. /*+-------------------------------------------------------------------------*
  805. *
  806. * CAMCApp::GetMainFrame
  807. *
  808. * PURPOSE: Returns a pointer to the main frame.
  809. *
  810. * RETURNS:
  811. * CMainFrame *
  812. *
  813. *+-------------------------------------------------------------------------*/
  814. CMainFrame *
  815. CAMCApp::GetMainFrame()
  816. {
  817. return dynamic_cast<CMainFrame *>(m_pMainWnd);
  818. }
  819. /*+-------------------------------------------------------------------------*
  820. *
  821. * CAMCApp::ScGet_Application
  822. *
  823. * PURPOSE: Returns a pointer to an _Application object.
  824. *
  825. * PARAMETERS:
  826. * _Application ** pp_Application :
  827. *
  828. * RETURNS:
  829. * SC
  830. *
  831. *+-------------------------------------------------------------------------*/
  832. SC
  833. CAMCApp::ScGet_Application(_Application **pp_Application)
  834. {
  835. DECLARE_SC(sc, TEXT("CAMCApp::ScGet_Application"));
  836. // parameter check
  837. sc = ScCheckPointers(pp_Application);
  838. if (sc)
  839. return sc;
  840. // init out param
  841. *pp_Application = NULL;
  842. // see if we have a chached one
  843. if (m_sp_Application != NULL)
  844. {
  845. *pp_Application = m_sp_Application;
  846. (*pp_Application)->AddRef(); // addref for the client.
  847. return sc;
  848. }
  849. // create an _Application object. This is needed if MMC was instantiated
  850. // by a user, not COM.
  851. sc = CMMCApplication::CreateInstance(pp_Application);
  852. if(sc)
  853. return sc;
  854. // The constructor of the CMMCApplication calls ScRegister_Application
  855. // which sets the m_sp_Application pointer. Do not set this pointer here.
  856. sc = ScCheckPointers(*pp_Application, E_UNEXPECTED);
  857. if (sc)
  858. return sc;
  859. // done
  860. return sc;
  861. }
  862. /*+-------------------------------------------------------------------------*
  863. *
  864. * CAMCApp::ScRegister_Application
  865. *
  866. * PURPOSE: called by a CMMCApplication object to enable the CAMCApp to store
  867. * a pointer to it.
  868. *
  869. * PARAMETERS:
  870. * _Application * p_Application :
  871. *
  872. * RETURNS:
  873. * SC
  874. *
  875. *+-------------------------------------------------------------------------*/
  876. SC
  877. CAMCApp::ScRegister_Application(_Application *p_Application)
  878. {
  879. DECLARE_SC(sc, TEXT("CAMCApp::ScRegister_Application"));
  880. ASSERT(m_sp_Application == NULL); // only one _Application object should ever register.
  881. sc = ScCheckPointers(p_Application);
  882. if(sc)
  883. return sc;
  884. m_sp_Application = p_Application;
  885. return sc;
  886. }
  887. //+-------------------------------------------------------------------
  888. //
  889. // Member: RegisterShellFileTypes
  890. //
  891. // Synopsis: Register the file associations.
  892. //
  893. // Note: Also set all other relevant registry keys like
  894. // Open, Author, RunAs. Eventhough the setup has
  895. // done this it may have been deleted mistakenly.
  896. //
  897. // History:
  898. // [AnandhaG] - Added the registry repair.
  899. // Returns: None.
  900. //
  901. //--------------------------------------------------------------------
  902. void CAMCApp::RegisterShellFileTypes(BOOL bCompat)
  903. {
  904. CWinApp::RegisterShellFileTypes (bCompat);
  905. do
  906. {
  907. // Create the top level MSCFile key.
  908. CRegKey regKey;
  909. LONG lRet = regKey.Create(HKEY_CLASSES_ROOT, _T("MSCFile"), REG_NONE,
  910. REG_OPTION_NON_VOLATILE, KEY_WRITE);
  911. if (ERROR_SUCCESS != lRet)
  912. break;
  913. /*
  914. * for platforms that support it (i.e. not Win9x), set the MUI-friendly
  915. * value for the MSCFile document type
  916. */
  917. if (!IsWin9xPlatform())
  918. {
  919. CString strMUIValue;
  920. strMUIValue.Format (_T("@%%SystemRoot%%\\system32\\mmcbase.dll,-%d"), IDR_MUIFRIENDLYNAME);
  921. lRet = RegSetValueEx (regKey, _T("FriendlyTypeName"), NULL, REG_EXPAND_SZ,
  922. (CONST BYTE *)(LPCTSTR) strMUIValue,
  923. sizeof(TCHAR) * (strMUIValue.GetLength()+1) );
  924. if (ERROR_SUCCESS != lRet)
  925. break;
  926. }
  927. // Set the EditFlags value.
  928. lRet = regKey.SetValue(0x100000, _T("EditFlags"));
  929. if (ERROR_SUCCESS != lRet)
  930. break;
  931. // Create the Author verb.
  932. lRet = regKey.Create(HKEY_CLASSES_ROOT, _T("MSCFile\\shell\\Author"), REG_NONE,
  933. REG_OPTION_NON_VOLATILE, KEY_WRITE);
  934. if (ERROR_SUCCESS != lRet)
  935. break;
  936. // And set default value for author (this reflects in shell menu).
  937. CString strRegVal;
  938. LoadString(strRegVal, IDS_MENUAUTHOR);
  939. lRet = RegSetValueEx ((HKEY)regKey, (LPCTSTR)NULL, NULL, REG_SZ,
  940. (CONST BYTE *)(LPCTSTR)strRegVal, sizeof(TCHAR) * (strRegVal.GetLength()+1) );
  941. if (ERROR_SUCCESS != lRet)
  942. break;
  943. /*
  944. * for platforms that support it (i.e. not Win9x), set the MUI-friendly
  945. * value for the menu item
  946. */
  947. if (!IsWin9xPlatform())
  948. {
  949. CString strMUIValue;
  950. strMUIValue.Format (_T("@%%SystemRoot%%\\system32\\mmcbase.dll,-%d"), IDS_MENUAUTHOR);
  951. lRet = RegSetValueEx (regKey, _T("MUIVerb"), NULL, REG_EXPAND_SZ,
  952. (CONST BYTE *)(LPCTSTR) strMUIValue,
  953. sizeof(TCHAR) * (strMUIValue.GetLength()+1) );
  954. if (ERROR_SUCCESS != lRet)
  955. break;
  956. }
  957. // Create the Author command.
  958. lRet = regKey.Create(HKEY_CLASSES_ROOT, _T("MSCFile\\shell\\Author\\command"), REG_NONE,
  959. REG_OPTION_NON_VOLATILE, KEY_WRITE);
  960. if (ERROR_SUCCESS != lRet)
  961. break;
  962. //////////////////////////////////////////////////////////////
  963. // Win95 does not support REG_EXPAND_SZ for default values. //
  964. // So we set expand strings and set registry strings as //
  965. // REG_SZ for Win9x. //
  966. // The following declarations are for Win9x platform. //
  967. //////////////////////////////////////////////////////////////
  968. TCHAR szRegValue[2 * MAX_PATH];
  969. TCHAR szWinDir[MAX_PATH];
  970. if (0 == ExpandEnvironmentStrings(_T("%WinDir%"), szWinDir, MAX_PATH) )
  971. break;
  972. DWORD dwCount = 0;
  973. LPTSTR lpszRegValue = NULL;
  974. // Set the default value for Author command.
  975. if (IsWin9xPlatform() == false)
  976. {
  977. lpszRegValue = _T("%SystemRoot%\\system32\\mmc.exe /a \"%1\" %*");
  978. dwCount = sizeof(TCHAR) * (1 + _tcslen(lpszRegValue));
  979. lRet = RegSetValueEx ((HKEY)regKey, (LPCTSTR)NULL, NULL, REG_EXPAND_SZ,
  980. (CONST BYTE *)lpszRegValue, dwCount);
  981. }
  982. else // Win9x platform
  983. {
  984. lpszRegValue = _T("\\mmc.exe /a \"%1\" %2 %3 %4 %5 %6 %7 %8 %9");
  985. _tcscpy(szRegValue, szWinDir);
  986. _tcscat(szRegValue, lpszRegValue);
  987. dwCount = sizeof(TCHAR) * (1 + _tcslen(szRegValue));
  988. lRet = RegSetValueEx ((HKEY)regKey, (LPCTSTR)NULL, NULL, REG_SZ,
  989. (CONST BYTE *)szRegValue, dwCount);
  990. }
  991. if (ERROR_SUCCESS != lRet)
  992. break;
  993. // Create the Open verb.
  994. lRet = regKey.Create(HKEY_CLASSES_ROOT, _T("MSCFile\\shell\\Open"), REG_NONE,
  995. REG_OPTION_NON_VOLATILE, KEY_WRITE);
  996. if (ERROR_SUCCESS != lRet)
  997. break;
  998. // Set default value for Open.
  999. LoadString(strRegVal, IDS_MENUOPEN);
  1000. lRet = RegSetValueEx ((HKEY)regKey, (LPCTSTR)NULL, NULL, REG_SZ,
  1001. (CONST BYTE *)(LPCTSTR)strRegVal,sizeof(TCHAR) * (strRegVal.GetLength()+1) );
  1002. if (ERROR_SUCCESS != lRet)
  1003. break;
  1004. /*
  1005. * for platforms that support it (i.e. not Win9x), set the MUI-friendly
  1006. * value for the menu item
  1007. */
  1008. if (!IsWin9xPlatform())
  1009. {
  1010. CString strMUIValue;
  1011. strMUIValue.Format (_T("@%%SystemRoot%%\\system32\\mmcbase.dll,-%d"), IDS_MENUOPEN);
  1012. lRet = RegSetValueEx (regKey, _T("MUIVerb"), NULL, REG_EXPAND_SZ,
  1013. (CONST BYTE *)(LPCTSTR) strMUIValue,
  1014. sizeof(TCHAR) * (strMUIValue.GetLength()+1) );
  1015. if (ERROR_SUCCESS != lRet)
  1016. break;
  1017. }
  1018. // Create the Open command.
  1019. lRet = regKey.Create(HKEY_CLASSES_ROOT, _T("MSCFile\\shell\\Open\\command"), REG_NONE,
  1020. REG_OPTION_NON_VOLATILE, KEY_WRITE);
  1021. if (ERROR_SUCCESS != lRet)
  1022. break;
  1023. // Set the default value for Open command.
  1024. if (IsWin9xPlatform() == false)
  1025. {
  1026. lpszRegValue = _T("%SystemRoot%\\system32\\mmc.exe \"%1\" %*");
  1027. dwCount = sizeof(TCHAR) * (1 + _tcslen(lpszRegValue));
  1028. lRet = RegSetValueEx ((HKEY)regKey, (LPCTSTR)NULL, NULL, REG_EXPAND_SZ,
  1029. (CONST BYTE *)lpszRegValue, dwCount);
  1030. }
  1031. else // Win9x platform
  1032. {
  1033. lpszRegValue = _T("\\mmc.exe \"%1\" %2 %3 %4 %5 %6 %7 %8 %9");
  1034. _tcscpy(szRegValue, szWinDir);
  1035. _tcscat(szRegValue, lpszRegValue);
  1036. dwCount = sizeof(TCHAR) * (1 + _tcslen(szRegValue));
  1037. lRet = RegSetValueEx ((HKEY)regKey, (LPCTSTR)NULL, NULL, REG_SZ,
  1038. (CONST BYTE *)szRegValue, dwCount);
  1039. }
  1040. if (ERROR_SUCCESS != lRet)
  1041. break;
  1042. // Create the RunAs verb (only on NT).
  1043. if (IsWin9xPlatform() == false)
  1044. {
  1045. lRet = regKey.Create(HKEY_CLASSES_ROOT, _T("MSCFile\\shell\\RunAs"), REG_NONE,
  1046. REG_OPTION_NON_VOLATILE, KEY_WRITE);
  1047. if (ERROR_SUCCESS != lRet)
  1048. break;
  1049. // Set default value for RunAs verb.
  1050. LoadString(strRegVal, IDS_MENURUNAS);
  1051. lRet = RegSetValueEx ((HKEY)regKey, (LPCTSTR)NULL, NULL, REG_SZ,
  1052. (CONST BYTE *)(LPCTSTR)strRegVal,sizeof(TCHAR) * (strRegVal.GetLength()+1) );
  1053. if (ERROR_SUCCESS != lRet)
  1054. break;
  1055. /*
  1056. * for platforms that support it (i.e. not Win9x), set the MUI-friendly
  1057. * value for the menu item
  1058. */
  1059. if (!IsWin9xPlatform())
  1060. {
  1061. CString strMUIValue;
  1062. strMUIValue.Format (_T("@%%SystemRoot%%\\system32\\mmcbase.dll,-%d"), IDS_MENURUNAS);
  1063. lRet = RegSetValueEx (regKey, _T("MUIVerb"), NULL, REG_EXPAND_SZ,
  1064. (CONST BYTE *)(LPCTSTR) strMUIValue,
  1065. sizeof(TCHAR) * (strMUIValue.GetLength()+1) );
  1066. if (ERROR_SUCCESS != lRet)
  1067. break;
  1068. }
  1069. // Create the RunAs command.
  1070. lRet = regKey.Create(HKEY_CLASSES_ROOT, _T("MSCFile\\shell\\RunAs\\command"), REG_NONE,
  1071. REG_OPTION_NON_VOLATILE, KEY_WRITE);
  1072. if (ERROR_SUCCESS != lRet)
  1073. break;
  1074. // Set the default value for RunAs command. (Only on NT Unicode)
  1075. lpszRegValue = _T("%SystemRoot%\\system32\\mmc.exe \"%1\" %*");
  1076. dwCount = sizeof(TCHAR) * (1 + _tcslen(lpszRegValue));
  1077. lRet = RegSetValueEx ((HKEY)regKey, (LPCTSTR)NULL, NULL, REG_EXPAND_SZ,
  1078. (CONST BYTE *)lpszRegValue, dwCount);
  1079. }
  1080. if (ERROR_SUCCESS != lRet)
  1081. break;
  1082. } while ( FALSE );
  1083. return;
  1084. }
  1085. /////////////////////////////////////////////////////////////////////////////
  1086. // CAMCApp initialization
  1087. #ifdef UNICODE
  1088. SC ScLaunchMMC (eArchitecture eArch, int nCmdShow);
  1089. #endif
  1090. #ifdef MMC_WIN64
  1091. class CMMCCommandLineInfo;
  1092. SC ScDetermineArchitecture (const CMMCCommandLineInfo& rCmdInfo, eArchitecture& eArch);
  1093. #else
  1094. bool IsWin64();
  1095. #endif // MMC_WIN64
  1096. class CMMCCommandLineInfo : public CCommandLineInfo
  1097. {
  1098. public:
  1099. eArchitecture m_eArch;
  1100. bool m_fForceAuthorMode;
  1101. bool m_fRegisterServer;
  1102. CString m_strDumpFilename;
  1103. public:
  1104. CMMCCommandLineInfo() :
  1105. m_eArch (eArch_Any),
  1106. m_fForceAuthorMode(false),
  1107. m_fRegisterServer(false)
  1108. {}
  1109. virtual void ParseParam (LPCTSTR pszParam, BOOL bFlag, BOOL bLast)
  1110. {
  1111. bool fHandledHere = false;
  1112. if (bFlag)
  1113. {
  1114. /*
  1115. * ignore the following parameters:
  1116. * -dde (await DDE command), -s (splash screen, obsolete).
  1117. */
  1118. if ((lstrcmpi (pszParam, _T("s")) == 0) ||
  1119. (lstrcmpi (pszParam, _T("dde")) == 0))
  1120. {
  1121. fHandledHere = true;
  1122. }
  1123. // force author mode
  1124. else if (lstrcmpi (pszParam, _T("a")) == 0)
  1125. {
  1126. m_fForceAuthorMode = true;
  1127. fHandledHere = true;
  1128. }
  1129. // register the server only
  1130. else if (lstrcmpi (pszParam, _T("RegServer")) == 0)
  1131. {
  1132. m_fRegisterServer = true;
  1133. fHandledHere = true;
  1134. }
  1135. // force 64-bit MMC to run
  1136. else if (lstrcmp (pszParam, _T("64")) == 0)
  1137. {
  1138. m_eArch = eArch_64bit;
  1139. fHandledHere = true;
  1140. }
  1141. // force 32-bit MMC to run
  1142. else if (lstrcmp (pszParam, _T("32")) == 0)
  1143. {
  1144. m_eArch = eArch_32bit;
  1145. fHandledHere = true;
  1146. }
  1147. else
  1148. {
  1149. static const TCHAR szDumpParam[] = _T("dump:");
  1150. const int cchDumpParam = countof (szDumpParam);
  1151. TCHAR szParam[cchDumpParam];
  1152. lstrcpyn (szParam, pszParam, cchDumpParam);
  1153. szParam[cchDumpParam-1] = _T('\0');
  1154. // dump console file contents
  1155. if (lstrcmpi (szParam, szDumpParam) == 0)
  1156. {
  1157. m_strDumpFilename = pszParam + cchDumpParam - 1;
  1158. fHandledHere = true;
  1159. }
  1160. }
  1161. }
  1162. // if not handled, pass it on to base class
  1163. // if just handled last parameter, call base class ParseLast
  1164. // so it can do the final processing
  1165. if (!fHandledHere)
  1166. CCommandLineInfo::ParseParam (pszParam, bFlag, bLast);
  1167. else if (bLast)
  1168. CCommandLineInfo::ParseLast(bLast);
  1169. }
  1170. }; // class CMMCCommandLineInfo
  1171. /*+-------------------------------------------------------------------------*
  1172. * CWow64FilesystemRedirectionDisabler
  1173. *
  1174. * Disables Wow64 file system redirection for the file represented in the
  1175. * given CMMCCommandLineInfo. We do this so MMC32 can open consoles in
  1176. * %windir%\system32 without having the path redirected to %windir%\syswow64.
  1177. *--------------------------------------------------------------------------*/
  1178. class CWow64FilesystemRedirectionDisabler
  1179. {
  1180. public:
  1181. CWow64FilesystemRedirectionDisabler (LPCTSTR pszFilename)
  1182. {
  1183. #ifndef MMC_WIN64
  1184. m_fDisabled = ((pszFilename != NULL) && IsWin64());
  1185. if (m_fDisabled)
  1186. {
  1187. Trace (tag32BitTransfer, _T("Disabling Wow64 file system redirection for %s"), pszFilename);
  1188. Wow64DisableFilesystemRedirector (pszFilename);
  1189. }
  1190. #endif // !MMC_WIN64
  1191. }
  1192. ~CWow64FilesystemRedirectionDisabler ()
  1193. {
  1194. #ifndef MMC_WIN64
  1195. if (m_fDisabled)
  1196. {
  1197. Trace (tag32BitTransfer, _T("Enabling Wow64 file system redirection"));
  1198. Wow64EnableFilesystemRedirector();
  1199. }
  1200. #endif // !MMC_WIN64
  1201. }
  1202. private:
  1203. #ifndef MMC_WIN64
  1204. bool m_fDisabled;
  1205. #endif // !MMC_WIN64
  1206. };
  1207. /*+-------------------------------------------------------------------------*
  1208. *
  1209. * CAMCApp::ScProcessAuthorModeRestrictions
  1210. *
  1211. * PURPOSE: Determines whether author mode restrictions are being enforced
  1212. * by system policy, and if author mode is not allowed,
  1213. * displays an error box and exits.
  1214. *
  1215. * RETURNS:
  1216. * SC
  1217. *
  1218. *+-------------------------------------------------------------------------*/
  1219. SC
  1220. CAMCApp::ScProcessAuthorModeRestrictions()
  1221. {
  1222. DECLARE_SC(sc, TEXT("CAMCApp::ScProcessAuthorModeRestrictions"));
  1223. CRegKey regKey;
  1224. // The mode is initialized to "author", if it is not in
  1225. // initialized state just return.
  1226. if (eMode_Author != m_eMode)
  1227. return sc;
  1228. // The console file mode is already read.
  1229. // Check if user policy permits author mode.
  1230. long lResult = regKey.Open(HKEY_CURRENT_USER, POLICY_KEY, KEY_READ);
  1231. if (lResult != ERROR_SUCCESS)
  1232. return sc;
  1233. // get the value of RestrictAuthorMode.
  1234. DWORD dwRestrictAuthorMode = 0;
  1235. lResult = regKey.QueryValue(dwRestrictAuthorMode, g_szRestrictAuthorMode);
  1236. if (lResult != ERROR_SUCCESS)
  1237. return sc;
  1238. if (dwRestrictAuthorMode == 0) // Author mode is not restricted so return.
  1239. return sc;
  1240. /*
  1241. * If called from script (running as embedded server) see if policy
  1242. * restricts scripts from entering into author mode.
  1243. *
  1244. * If restricted then script will fail, thus restricting rogue scripts.
  1245. *
  1246. * Even if not restricted here cannot add snapins that are restricted.
  1247. */
  1248. if (IsMMCRunningAsOLEServer())
  1249. {
  1250. DWORD dwRestrictScriptsFromEnteringAuthorMode = 0;
  1251. lResult = regKey.QueryValue(dwRestrictScriptsFromEnteringAuthorMode, g_szRestrictScriptsFromEnteringAuthorMode);
  1252. if (lResult != ERROR_SUCCESS)
  1253. return sc;
  1254. if (dwRestrictScriptsFromEnteringAuthorMode == 0) // Scripts can enter author mode so return
  1255. return sc;
  1256. sc = ScFromMMC(IDS_AUTHORMODE_NOTALLOWED_FORSCRIPTS);
  1257. }
  1258. else
  1259. // If author mode is not allowed and
  1260. // the user tried to force author mode
  1261. // then display error message and exit.
  1262. sc = ScFromMMC(IDS_AUTHORMODE_NOTALLOWED);
  1263. return sc;
  1264. }
  1265. /*+-------------------------------------------------------------------------*
  1266. *
  1267. * CAMCApp::ScCheckMMCPrerequisites
  1268. *
  1269. * PURPOSE: Checks all prerequisites. These are: (add to the list as appropriate)
  1270. * 1) Internet Explorer 5.5 or greater must be installed
  1271. *
  1272. * RETURNS:
  1273. * SC
  1274. *
  1275. *+-------------------------------------------------------------------------*/
  1276. SC
  1277. CAMCApp::ScCheckMMCPrerequisites()
  1278. {
  1279. DECLARE_SC(sc, TEXT("CAMCApp::ScCheckMMCPrerequisites"));
  1280. // 1. Determine the installed version of Internet Explorer.
  1281. const int CBDATA = 100;
  1282. TCHAR szVersion[CBDATA];
  1283. BOOL bIE55Found = false;
  1284. HKEY hkey = NULL;
  1285. DWORD dwType =0;
  1286. DWORD cbData =CBDATA;
  1287. DWORD dwMajor =0;
  1288. DWORD dwMinor =0;
  1289. DWORD dwRevision =0;
  1290. DWORD dwBuild =0;
  1291. lstrcpy(szVersion, TEXT(""));
  1292. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\Microsoft\\Internet Explorer"), 0, KEY_READ, &hkey))
  1293. {
  1294. cbData = 100;
  1295. RegQueryValueEx(hkey, TEXT("Version"), 0, &dwType, (LPBYTE)szVersion, &cbData);
  1296. RegCloseKey(hkey);
  1297. if (lstrlen(szVersion) > 0)
  1298. {
  1299. _stscanf(szVersion, TEXT("%d.%d.%d.%d"), &dwMajor, &dwMinor, &dwRevision, &dwBuild);
  1300. //Make sure IE 5.5 or greater is installed. To do this:
  1301. // 1) Check if the major version is >= 6. If so we're done.
  1302. // 2) If the major version is 5, the minor version should be >= 50
  1303. if (dwMajor >= 6)
  1304. {
  1305. bIE55Found = true;
  1306. }
  1307. if (dwMajor == 5)
  1308. {
  1309. if(dwMinor >= 50)
  1310. bIE55Found = true;
  1311. }
  1312. }
  1313. }
  1314. if (!bIE55Found)
  1315. {
  1316. sc = ScFromMMC(MMC_E_INCORRECT_IE_VERSION); // NOTE: update the string when the version requirement changes
  1317. return sc;
  1318. }
  1319. return sc;
  1320. }
  1321. /*+-------------------------------------------------------------------------*
  1322. *
  1323. * CAMCApp::InitInstance
  1324. *
  1325. * PURPOSE: Initializes the document.
  1326. *
  1327. * NOTE: as an aside, if you need to break on, say, the 269th allocation,
  1328. * add the following code:
  1329. *
  1330. * #define ALLOCATION_NUM 269
  1331. * _CrtSetBreakAlloc(ALLOCATION_NUM);
  1332. * _crtBreakAlloc = ALLOCATION_NUM;
  1333. *
  1334. * RETURNS:
  1335. * BOOL
  1336. *
  1337. *+-------------------------------------------------------------------------*/
  1338. BOOL CAMCApp::InitInstance()
  1339. {
  1340. DECLARE_SC(sc, TEXT("CAMCApp::InitInstance"));
  1341. /*
  1342. * Initialize Fusion.
  1343. */
  1344. SHFusionInitializeFromModuleID (NULL, static_cast<int>(reinterpret_cast<ULONG_PTR>(SXS_MANIFEST_RESOURCE_ID)));
  1345. #ifdef DBG
  1346. if (tagForceMirror.FAny())
  1347. {
  1348. HINSTANCE hmodUser = GetModuleHandle (_T("user32.dll"));
  1349. if (hmodUser != NULL)
  1350. {
  1351. BOOL (WINAPI* pfnSetProcessDefaultLayout)(DWORD);
  1352. (FARPROC&)pfnSetProcessDefaultLayout = GetProcAddress (hmodUser, "SetProcessDefaultLayout");
  1353. if (pfnSetProcessDefaultLayout != NULL)
  1354. (*pfnSetProcessDefaultLayout)(LAYOUT_RTL);
  1355. }
  1356. }
  1357. #endif
  1358. BOOL bRet = TRUE;
  1359. // Initialize OLE libraries
  1360. if (InitializeOLE() == FALSE)
  1361. return FALSE;
  1362. // Initialize the ATL Module
  1363. _Module.Init(ObjectMap,m_hInstance);
  1364. #ifdef DBG
  1365. if(tagGDIBatching.FAny())
  1366. {
  1367. // disable GDI batching so we'll see drawing as it happens
  1368. GdiSetBatchLimit (1);
  1369. }
  1370. #endif
  1371. Unregister();
  1372. Trace(tagAMCAppInit, TEXT("CAMCApp::InitInstance"));
  1373. CMMCCommandLineInfo cmdInfo;
  1374. ParseCommandLine(cmdInfo);
  1375. /*
  1376. * if we got a file on the command line, expand environment
  1377. * variables in the filename so we can open files like
  1378. * "%SystemRoot%\system32\compmgmt.msc"
  1379. */
  1380. if (!cmdInfo.m_strFileName.IsEmpty())
  1381. {
  1382. CWow64FilesystemRedirectionDisabler disabler (cmdInfo.m_strFileName);
  1383. sc = ScExpandEnvironmentStrings (cmdInfo.m_strFileName);
  1384. if (sc)
  1385. {
  1386. MMCErrorBox (sc);
  1387. return (false);
  1388. }
  1389. }
  1390. // Don't use an .ini file for the MRU or Settings
  1391. // Note: This string does not need to be localizable.
  1392. // HKEY_CURRENT_USER\\Software\\Microsoft\\Microsoft Management Console
  1393. SetRegistryKey(_T("Microsoft"));
  1394. // Find out OS version.
  1395. OSVERSIONINFO versInfo;
  1396. versInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  1397. BOOL bStat = GetVersionEx(&versInfo);
  1398. ASSERT(bStat);
  1399. m_fIsWin9xPlatform = (versInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
  1400. // default to Author mode (loading a console may change this later)
  1401. InitializeMode (eMode_Author);
  1402. m_fAuthorModeForced = cmdInfo.m_fForceAuthorMode ||
  1403. cmdInfo.m_strFileName.IsEmpty();
  1404. /*
  1405. * dump the snap-ins (and do nothing else) if we got "-dump:<filename>"
  1406. */
  1407. if (!cmdInfo.m_strDumpFilename.IsEmpty())
  1408. {
  1409. DumpConsoleFile (cmdInfo.m_strFileName, cmdInfo.m_strDumpFilename);
  1410. return (false);
  1411. }
  1412. #ifdef MMC_WIN64
  1413. /*
  1414. * We're currently running the MMC64. See if we need to defer to MMC32.
  1415. * If we do, try to launch MMC32. If we were able to launch MMC32
  1416. * successfully, abort MMC64.
  1417. */
  1418. eArchitecture eArch = eArch_64bit;
  1419. sc = ScDetermineArchitecture (cmdInfo, eArch);
  1420. if (sc)
  1421. {
  1422. DisplayFileOpenError (sc, cmdInfo.m_strFileName);
  1423. return (false);
  1424. }
  1425. switch (eArch)
  1426. {
  1427. /*
  1428. * MMC64 is fine, do nothing
  1429. */
  1430. case eArch_64bit:
  1431. break;
  1432. /*
  1433. * User cancelled action, abort
  1434. */
  1435. case eArch_None:
  1436. return (false);
  1437. break;
  1438. /*
  1439. * We need MMC32, so try to launch it. If we were able to launch MMC32
  1440. * successfully, abort MMC64; if not, continue running MMC64.
  1441. */
  1442. case eArch_32bit:
  1443. if (!ScLaunchMMC(eArch_32bit, m_nCmdShow).IsError())
  1444. {
  1445. Trace (tag32BitTransfer, _T("32-bit MMC launched successfully"));
  1446. return (false);
  1447. }
  1448. Trace (tag32BitTransfer, _T("32-bit MMC failed to launch"));
  1449. MMCErrorBox (MMC_E_UnableToLaunchMMC32);
  1450. break;
  1451. default:
  1452. ASSERT (false && "Unexpected architecture returned from ScDetermineArchitecture");
  1453. break;
  1454. }
  1455. #elif defined(UNICODE)
  1456. /*
  1457. * We're currently running the MMC32. If it's running on IA64 and 32-bit
  1458. * wasn't specifically requested with a "-32" switch (this is what MMC64
  1459. * will do when it defers to MMC32), defer to MMC64 so it can do snap-in
  1460. * analysis and determine the appropriate "bitness" to run.
  1461. */
  1462. if ((cmdInfo.m_eArch != eArch_32bit) && IsWin64())
  1463. {
  1464. /*
  1465. * We need MMC64, so try to launch it. If we were able to launch MMC64
  1466. * successfully, abort MMC32; if not, continue running MMC32.
  1467. */
  1468. if (!ScLaunchMMC(eArch_64bit, m_nCmdShow).IsError())
  1469. {
  1470. Trace (tag32BitTransfer, _T("64-bit MMC launched successfully"));
  1471. return (false);
  1472. }
  1473. Trace (tag32BitTransfer, _T("64-bit MMC failed to launch"));
  1474. MMCErrorBox (MMC_E_UnableToLaunchMMC64);
  1475. }
  1476. #endif // MMC_WIN64
  1477. AfxEnableControlContainer();
  1478. // Standard initialization
  1479. #ifdef _AFXDLL
  1480. Enable3dControls(); // Call this when using MFC in a shared DLL
  1481. #else
  1482. Enable3dControlsStatic(); // Call this when linking to MFC statically
  1483. #endif
  1484. LoadStdProfileSettings(); // Load standard INI file options (including MRU)
  1485. // create our own CDocManager derivative before adding any templates
  1486. // (CWinApp::~CWinApp will delete it)
  1487. m_pDocManager = new CAMCDocManager;
  1488. // Register document templates
  1489. CMultiDocTemplate* pDocTemplate;
  1490. pDocTemplate = new CAMCMultiDocTemplate(
  1491. IDR_AMCTYPE,
  1492. RUNTIME_CLASS(CAMCDoc),
  1493. RUNTIME_CLASS(CChildFrame), // custom MDI child frame
  1494. RUNTIME_CLASS(CAMCView));
  1495. AddDocTemplate(pDocTemplate);
  1496. // Note: MDI applications register all server objects without regard
  1497. // to the /Embedding or /Automation on the command line.
  1498. if (cmdInfo.m_fRegisterServer)
  1499. {
  1500. sc = _Module.RegisterServer(TRUE);// ATL Classes
  1501. if (sc == TYPE_E_REGISTRYACCESS)
  1502. sc.TraceAndClear();
  1503. }
  1504. if (sc)
  1505. {
  1506. MMCErrorBox (sc);
  1507. return (false);
  1508. }
  1509. // create main MDI Frame window
  1510. CMainFrame *pMainFrame = new CMainFrame;
  1511. if (!pMainFrame->LoadFrame(IDR_MAINFRAME))
  1512. return FALSE;
  1513. m_pMainWnd = pMainFrame;
  1514. // set the HWND to use as the parent for modal error dialogs.
  1515. SC::SetHWnd(pMainFrame->GetSafeHwnd());
  1516. // save this main thread's ID to check if snapins call MMC
  1517. // interfaces from main thread.
  1518. SC::SetMainThreadID(::GetCurrentThreadId());
  1519. m_fRunningAsOLEServer = false;
  1520. // Check to see if launched as OLE server
  1521. if (RunEmbedded() || RunAutomated())
  1522. {
  1523. m_fRunningAsOLEServer = true;
  1524. // Application was run with /Embedding or /Automation. Don't show the
  1525. // main window in this case.
  1526. //return TRUE;
  1527. // Also set that script is controlling the application not the user
  1528. // The script can modify the UserControl property on the application.
  1529. SetUnderUserControl(false);
  1530. // When a server application is launched stand-alone, it is a good idea to register all objects
  1531. // ATL ones specifically register with REGCLS_MULTIPLEUSE
  1532. // we register class objects only when run as an OLE server. This way, cannot connect to
  1533. // an existing instance of MMC.
  1534. sc = _Module.RegisterClassObjects(CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE);
  1535. if(sc)
  1536. goto Error;
  1537. }
  1538. if (cmdInfo.m_fRegisterServer)
  1539. {
  1540. CString strTypeLib;
  1541. strTypeLib.Format(TEXT("\\%d"), IDR_WEBSINK_TYPELIB); // this should evaluate to something like "\\4"
  1542. sc = _Module.RegisterTypeLib((LPCTSTR)strTypeLib);
  1543. if (sc == TYPE_E_REGISTRYACCESS)
  1544. sc.TraceAndClear();
  1545. if(sc)
  1546. goto Error;
  1547. }
  1548. // Don't Enable drag/drop open
  1549. // m_pMainWnd->DragAcceptFiles();
  1550. // Enable DDE Execute open
  1551. if (cmdInfo.m_fRegisterServer)
  1552. RegisterShellFileTypes(FALSE);
  1553. EnableShellOpen();
  1554. if (cmdInfo.m_fRegisterServer)
  1555. DeleteDDEKeys();
  1556. /*
  1557. * At this point, all of our registration is complete. If we were invoked
  1558. * with -RegServer, we can bail now.
  1559. */
  1560. if (cmdInfo.m_fRegisterServer)
  1561. return (false);
  1562. { // limit scope of disabler
  1563. CWow64FilesystemRedirectionDisabler disabler (cmdInfo.m_strFileName);
  1564. // Dispatch commands specified on the command line.
  1565. // This loads a console file if necessary.
  1566. if (!ProcessShellCommand(cmdInfo))
  1567. return (false); // user is already informed about errors
  1568. }
  1569. // Now the console file is loaded. Check if Author mode
  1570. // is permitted.
  1571. sc = ScProcessAuthorModeRestrictions(); // check if there are any restrictions set by policy
  1572. if(sc)
  1573. goto Error;
  1574. // if proccessing the command line put MMC into author mode,
  1575. // it has to stick with it forever.
  1576. // see bug 102465 openning an author mode console file and then
  1577. // a user mode console switched MMC into user mode
  1578. if (eMode_Author == m_eMode)
  1579. m_fAuthorModeForced = true;
  1580. // create a document automatically only if we're not instantiated as an
  1581. // OLE server.
  1582. if(! IsMMCRunningAsOLEServer ())
  1583. {
  1584. // if we don't have a document now (maybe because
  1585. // the Node Manager wasn't registered), punt
  1586. CAMCDoc* pDoc = CAMCDoc::GetDocument ();
  1587. if (pDoc == NULL)
  1588. return (FALSE);
  1589. pDoc->SetFrameModifiedFlag (false);
  1590. pDoc->UpdateFrameCounts ();
  1591. CMainFrame *pMainFrame = GetMainFrame();
  1592. if (pMainFrame)
  1593. {
  1594. pMainFrame->ShowWindow(m_nCmdShow);
  1595. pMainFrame->UpdateWindow();
  1596. }
  1597. // showing will set the frame and "Modified" - reset it
  1598. pDoc->SetFrameModifiedFlag (false);
  1599. }
  1600. // register itself as dispatcher able to dispatch com events
  1601. sc = CConsoleEventDispatcherProvider::ScSetConsoleEventDispatcher( this );
  1602. if (sc)
  1603. goto Error;
  1604. m_fInitializing = false;
  1605. // check for all MMC prerequisites
  1606. sc = ScCheckMMCPrerequisites();
  1607. if (sc)
  1608. goto Error;
  1609. // Comment out below line when script engines hosted in mmc are enabled.
  1610. // sc = ScRunTestScript();
  1611. Cleanup:
  1612. return bRet;
  1613. Error:
  1614. MMCErrorBox(sc);
  1615. bRet = FALSE;
  1616. goto Cleanup;
  1617. }
  1618. //+-------------------------------------------------------------------
  1619. //
  1620. // Member: ScRunTestScript
  1621. //
  1622. // Synopsis: Test program to run a script. Once script input mechanisms
  1623. // are defined this can be removed.
  1624. //
  1625. // Arguments: None
  1626. //
  1627. // Returns: SC
  1628. //
  1629. //--------------------------------------------------------------------
  1630. SC CAMCApp::ScRunTestScript ()
  1631. {
  1632. DECLARE_SC(sc, _T("CAMCApp::ScRunTestScript"));
  1633. // The Running of scripts is enabled only in debug mode.
  1634. bool bEnableScriptEngines = false;
  1635. #ifdef DBG
  1636. if (tagEnableScriptEngines.FAny())
  1637. bEnableScriptEngines = true;
  1638. #endif
  1639. if (!bEnableScriptEngines)
  1640. return sc;
  1641. // Get the IDispatch from MMC object, the script engine needs
  1642. // the IUnknown to top level object & the ITypeInfo ptr.
  1643. CComPtr<_Application> spApplication;
  1644. sc = ScGet_Application(&spApplication);
  1645. if (sc)
  1646. return sc;
  1647. IDispatchPtr spDispatch = NULL;
  1648. sc = spApplication->QueryInterface(IID_IDispatch, (LPVOID*)&spDispatch);
  1649. if (sc)
  1650. return sc;
  1651. // The CScriptHostMgr should be instead created on the stack (as we have only
  1652. // one per app) and destroyed with app. This change can be made once we decide
  1653. // how & when the script host will be used to execute the scripts.
  1654. CScriptHostMgr* pMgr = new CScriptHostMgr(spDispatch);
  1655. if (NULL == pMgr)
  1656. return (sc = E_OUTOFMEMORY);
  1657. LPOLESTR pszScript = L"set WShShell=CreateObject(\"WScript.Shell\")\n\
  1658. WshShell.Popup(\"Anand\")\n\
  1659. Select Case WshShell.Popup(\"Anand\",5,\"Ganesan\", vbyesnocancel)\n\
  1660. End Select";
  1661. tstring strExtn = _T(".vbs");
  1662. sc = pMgr->ScExecuteScript(pszScript, strExtn);
  1663. tstring strFile = _T("E:\\newnt\\admin\\mmcdev\\test\\script\\MMCStartupScript.vbs");
  1664. sc = pMgr->ScExecuteScript(strFile);
  1665. delete pMgr;
  1666. return (sc);
  1667. }
  1668. // App command to run the dialog
  1669. void CAMCApp::OnAppAbout()
  1670. {
  1671. /*
  1672. * load the title of the about dialog
  1673. */
  1674. CString strTitle (MAKEINTRESOURCE (IDS_APP_NAME));
  1675. CString strVersion (MAKEINTRESOURCE (IDS_APP_VERSION));
  1676. strTitle += _T(" ");
  1677. strTitle += strVersion;
  1678. ShellAbout(*AfxGetMainWnd(), strTitle, NULL, LoadIcon(IDR_MAINFRAME));
  1679. }
  1680. /*+-------------------------------------------------------------------------*
  1681. *
  1682. * CAMCApp::OnFileNewInUserMode
  1683. *
  1684. * PURPOSE: Do nothing in user mode when CTRL+N is pressed.
  1685. * This handler prevents the hotkey from going to any WebBrowser controls
  1686. *
  1687. * RETURNS:
  1688. * void
  1689. *
  1690. *+-------------------------------------------------------------------------*/
  1691. void CAMCApp::OnFileNewInUserMode()
  1692. {
  1693. MessageBeep(-1);
  1694. }
  1695. //+-------------------------------------------------------------------
  1696. //
  1697. // Member: ScShowHtmlHelp
  1698. //
  1699. // Synopsis: Initialize and then call Help control to display help topic.
  1700. //
  1701. // Arguments: [pszFile] - File to display.
  1702. // [dwData] - Depends on uCommand for HH_DISPLAY_TOPIC it
  1703. // is help topic string.
  1704. //
  1705. // Note: The command is always HH_DISPLAY_TOPIC. HWND is NULL so that
  1706. // Help can get behind MMC window.
  1707. // See ScUnintializeHelpControl's Note for more info.
  1708. //
  1709. // Returns: SC
  1710. //
  1711. //--------------------------------------------------------------------
  1712. SC CAMCApp::ScShowHtmlHelp(LPCTSTR pszFile, DWORD_PTR dwData)
  1713. {
  1714. DECLARE_SC(sc, _T("CAMCApp::ScInitializeHelpControl"));
  1715. /*
  1716. * displaying HtmlHelp might take awhile, so show a wait cursor
  1717. */
  1718. CWaitCursor wait;
  1719. if (! m_bHelpInitialized)
  1720. HtmlHelp (NULL, NULL, HH_INITIALIZE, (DWORD_PTR)&m_dwHelpCookie);
  1721. // No documented return value for HH_INITIALIZE so always assume
  1722. // Initialize is successful.
  1723. m_bHelpInitialized = true;
  1724. HtmlHelp (NULL, pszFile, HH_DISPLAY_TOPIC, dwData);
  1725. return sc;
  1726. }
  1727. //+-------------------------------------------------------------------
  1728. //
  1729. // Member: ScUninitializeHelpControl
  1730. //
  1731. // Synopsis: UnInitialize the help if it was initialized by MMC.
  1732. //
  1733. // Note: The help-control calls OleInitialize & OleUninitialize
  1734. // in its DllMain. If a snapin creates any free threaded object
  1735. // on main thread (STA), the OLE creates an MTA.
  1736. // The last OleUninitialize does OLEProcessUninitialize in which
  1737. // then OLE waits for the above MTA to cleanup and return.
  1738. // By the time help-control does last OleUninitialize in its
  1739. // DllMain the MTA is already terminated so OLE waits for this
  1740. // MTA to signal which it never would.
  1741. // We call HtmlHelp(.. HH_UNINITIALIZE..) to force help control
  1742. // to uninit so that MMC does last OleUninit.
  1743. // (This will not solve the problem of snapins calling help directly).
  1744. //
  1745. // Arguments:
  1746. //
  1747. // Returns: SC, S_FALSE if already uninitialized else S_OK.
  1748. //
  1749. //--------------------------------------------------------------------
  1750. SC CAMCApp::ScUninitializeHelpControl()
  1751. {
  1752. DECLARE_SC(sc, _T("CAMCApp::ScUninitializeHelpControl"));
  1753. if (false == m_bHelpInitialized)
  1754. return (sc = S_FALSE);
  1755. HtmlHelp (NULL, NULL, HH_UNINITIALIZE, m_dwHelpCookie);
  1756. m_bHelpInitialized = false;
  1757. m_dwHelpCookie = 0;
  1758. return sc;
  1759. }
  1760. BOOL CAMCApp::InitializeOLE()
  1761. {
  1762. if (FAILED(::OleInitialize(NULL)))
  1763. return FALSE;
  1764. return (m_bOleInitialized = TRUE);
  1765. }
  1766. void CAMCApp::DeinitializeOLE()
  1767. {
  1768. // Uninit help, see ScUninitializeHelpControl note.
  1769. SC sc = ScUninitializeHelpControl();
  1770. if (sc)
  1771. {
  1772. TraceError(_T("Uninit Help control failed"), sc);
  1773. }
  1774. // Forced DllCanUnloadNow before mmc exits.
  1775. ::CoFreeUnusedLibraries();
  1776. if (m_bOleInitialized == TRUE)
  1777. {
  1778. ::OleUninitialize();
  1779. m_bOleInitialized = FALSE;
  1780. }
  1781. }
  1782. /////////////////////////////////////////////////////////////////////////////
  1783. // CAMCApp diagnostics
  1784. #ifdef _DEBUG
  1785. void CAMCApp::AssertValid() const
  1786. {
  1787. CWinApp::AssertValid();
  1788. }
  1789. #endif //_DEBUG
  1790. /////////////////////////////////////////////////////////////////////////////
  1791. // CAMCApp commands
  1792. int CAMCApp::ExitInstance()
  1793. {
  1794. DECLARE_SC(sc, TEXT("CAMCApp::ExitInstance"));
  1795. // if the main window is not destroyed yet - do that now.
  1796. // since we need to get rid of all the objects before denitializing OLE.
  1797. // It is not requred in most cases, since usually quit starts from closing the mainframe,
  1798. // but in cases like system shut down it will come here with a valid window
  1799. // See WindowsBug(ntbug9) #178858
  1800. if ( ::IsWindow( AfxGetMainWnd()->GetSafeHwnd() ) )
  1801. {
  1802. AfxGetMainWnd()->DestroyWindow();
  1803. }
  1804. // disconnect the pointers to event dispatcher
  1805. sc = CConsoleEventDispatcherProvider::ScSetConsoleEventDispatcher( NULL );
  1806. if (sc)
  1807. sc.TraceAndClear();
  1808. // release cached application object
  1809. m_sp_Application = NULL;
  1810. // MFC's class factories registration is automatically revoked by MFC itself
  1811. if (RunEmbedded() || RunAutomated())
  1812. _Module.RevokeClassObjects(); // Revoke class factories for ATL
  1813. _Module.Term(); // clanup ATL GLobal Module
  1814. // Ask node manager to cleanup what's got cached
  1815. CComPtr<IComCacheCleanup> spComCacheCleanup;
  1816. HRESULT hr = spComCacheCleanup.CoCreateInstance(CLSID_ComCacheCleanup, NULL, MMC_CLSCTX_INPROC);
  1817. if (hr == S_OK)
  1818. {
  1819. spComCacheCleanup->ReleaseCachedOleObjects();
  1820. spComCacheCleanup.Release();
  1821. }
  1822. // by now EVERY reference should be released
  1823. ASSERT(_Module.GetLockCount() == 0 && "Outstanding references still exist on exit");
  1824. DeinitializeOLE();
  1825. /*
  1826. * uninitialize Fusion
  1827. */
  1828. SHFusionUninitialize();
  1829. int iRet = CWinApp::ExitInstance();
  1830. DEBUG_VERIFY_INSTANCE_COUNT(CAMCTreeView);
  1831. DEBUG_VERIFY_INSTANCE_COUNT(CAMCListView);
  1832. DEBUG_VERIFY_INSTANCE_COUNT(CCCListViewCtrl);
  1833. return iRet;
  1834. }
  1835. BOOL CAMCApp::PreTranslateMessage(MSG* pMsg)
  1836. {
  1837. // Give HTML help a chance to crack the message. (Bug# 119355 & 206909).
  1838. if ( m_bHelpInitialized && HtmlHelp(NULL, NULL, HH_PRETRANSLATEMESSAGE, (DWORD_PTR)pMsg) )
  1839. return TRUE;
  1840. // let all of the hook windows have a crack at this message
  1841. WindowListIterator it = m_TranslateMessageHookWindows.begin();
  1842. while (it != m_TranslateMessageHookWindows.end())
  1843. {
  1844. HWND hwndHook = *it;
  1845. CWnd* pwndHook = CWnd::FromHandlePermanent (hwndHook);
  1846. // if this window is no longer valid, or it's not a permanent
  1847. // window, remove it from the list
  1848. if (!IsWindow (hwndHook) || (pwndHook == NULL))
  1849. it = m_TranslateMessageHookWindows.erase (it);
  1850. else
  1851. {
  1852. // otherwise if the hook window handled the message, bail
  1853. if (pwndHook->PreTranslateMessage (pMsg))
  1854. return (TRUE);
  1855. ++it;
  1856. }
  1857. }
  1858. // give the MMC defined main window accelerators a crack at the message
  1859. if (m_Accel.TranslateAccelerator (AfxGetMainWnd()->GetSafeHwnd(), pMsg))
  1860. return TRUE;
  1861. return CWinApp::PreTranslateMessage(pMsg);
  1862. }
  1863. /*+-------------------------------------------------------------------------*
  1864. * CAMCApp::SaveUserDirectory
  1865. *
  1866. *
  1867. *--------------------------------------------------------------------------*/
  1868. void CAMCApp::SaveUserDirectory(LPCTSTR pszUserDir)
  1869. {
  1870. // if we got an empty string, change the pointer to NULL so
  1871. // the entry will be removed from the registry
  1872. if ((pszUserDir != NULL) && (lstrlen(pszUserDir) == 0))
  1873. pszUserDir = NULL;
  1874. WriteProfileString (m_szSettingsSection, m_szUserDirectoryEntry,
  1875. pszUserDir);
  1876. }
  1877. /*+-------------------------------------------------------------------------*
  1878. * CAMCApp::GetUserDirectory
  1879. *
  1880. *
  1881. *--------------------------------------------------------------------------*/
  1882. CString CAMCApp::GetUserDirectory(void)
  1883. {
  1884. return (GetProfileString (m_szSettingsSection, m_szUserDirectoryEntry));
  1885. }
  1886. /*+-------------------------------------------------------------------------*
  1887. * CAMCApp::GetDefaultDirectory
  1888. *
  1889. *
  1890. *--------------------------------------------------------------------------*/
  1891. CString CAMCApp::GetDefaultDirectory(void)
  1892. {
  1893. static CString strDefaultDir;
  1894. if (strDefaultDir.IsEmpty())
  1895. {
  1896. LPITEMIDLIST pidl;
  1897. if (SUCCEEDED(SHGetSpecialFolderLocation(
  1898. AfxGetMainWnd()->GetSafeHwnd(),
  1899. CSIDL_ADMINTOOLS | CSIDL_FLAG_CREATE, &pidl)))
  1900. {
  1901. // Convert to path name
  1902. SHGetPathFromIDList (pidl, strDefaultDir.GetBuffer (MAX_PATH));
  1903. strDefaultDir.ReleaseBuffer ();
  1904. // Free IDList
  1905. LPMALLOC pMalloc;
  1906. if (SUCCEEDED(SHGetMalloc (&pMalloc)))
  1907. {
  1908. pMalloc->Free(pidl);
  1909. pMalloc->Release();
  1910. }
  1911. }
  1912. }
  1913. return (strDefaultDir);
  1914. }
  1915. /*+-------------------------------------------------------------------------*
  1916. * CAMCApp::SetDefaultDirectory
  1917. *
  1918. *
  1919. *--------------------------------------------------------------------------*/
  1920. void CAMCApp::SetDefaultDirectory(void)
  1921. {
  1922. // Only set default first time, so we don't override user selection
  1923. if (m_bDefaultDirSet)
  1924. return;
  1925. // Set the current directory to the default directory
  1926. CString strDirectory;
  1927. BOOL rc = FALSE;
  1928. strDirectory = GetDefaultDirectory ();
  1929. if (!strDirectory.IsEmpty())
  1930. rc = SetCurrentDirectory (strDirectory);
  1931. m_bDefaultDirSet = rc;
  1932. }
  1933. /*+-------------------------------------------------------------------------*
  1934. * CAMCApp::PumpMessage
  1935. *
  1936. *
  1937. *--------------------------------------------------------------------------*/
  1938. BOOL CAMCApp::PumpMessage()
  1939. {
  1940. m_nMessagePumpNestingLevel++;
  1941. MSG msg;
  1942. ::PeekMessage(&msg, NULL, NULL, NULL, PM_NOREMOVE);
  1943. if (msg.message == WM_CLOSE)
  1944. m_fCloseCameFromMainPump = true;
  1945. BOOL rc = CWinApp::PumpMessage();
  1946. if (m_fDelayCloseUntilIdle && (m_nMessagePumpNestingLevel == 1))
  1947. {
  1948. m_fCloseCameFromMainPump = true;
  1949. CMainFrame *pMainFrame = GetMainFrame();
  1950. if (pMainFrame)
  1951. pMainFrame->SendMessage (WM_CLOSE);
  1952. m_fDelayCloseUntilIdle = false;
  1953. }
  1954. m_fCloseCameFromMainPump = false;
  1955. m_nMessagePumpNestingLevel--;
  1956. ASSERT (m_nMessagePumpNestingLevel >= 0);
  1957. return (rc);
  1958. }
  1959. /*+-------------------------------------------------------------------------*
  1960. *
  1961. * CAMCApp::ScHelp
  1962. *
  1963. * PURPOSE: Displays help for the application.
  1964. *
  1965. * RETURNS:
  1966. * SC
  1967. *
  1968. *+-------------------------------------------------------------------------*/
  1969. SC
  1970. CAMCApp::ScHelp()
  1971. {
  1972. DECLARE_SC(sc, TEXT("CAMCApp::ScHelp"));
  1973. CMainFrame * pMainFrame = GetMainFrame();
  1974. if(!pMainFrame)
  1975. {
  1976. sc = E_UNEXPECTED;
  1977. return sc;
  1978. }
  1979. pMainFrame->OnHelpTopics();
  1980. return sc;
  1981. }
  1982. /*+-------------------------------------------------------------------------*
  1983. * CAMCApp::OnIdle
  1984. *
  1985. * WM_IDLE handler for CAMCApp.
  1986. *--------------------------------------------------------------------------*/
  1987. BOOL CAMCApp::OnIdle(LONG lCount)
  1988. {
  1989. SC sc;
  1990. CIdleTaskQueue * pQueue = GetIdleTaskQueue();
  1991. BOOL fMoreIdleWork = TRUE;
  1992. if(NULL == pQueue)
  1993. {
  1994. ASSERT(0 && "Should not come here.");
  1995. goto Error;
  1996. }
  1997. fMoreIdleWork = CWinApp::OnIdle(lCount);
  1998. if (!fMoreIdleWork)
  1999. {
  2000. CMainFrame *pMainFrame = GetMainFrame();
  2001. if (pMainFrame)
  2002. pMainFrame->OnIdle ();
  2003. }
  2004. /*
  2005. * if MFC doesn't have any more idle work to do,
  2006. * check our idle task queue (if we have one)
  2007. */
  2008. if (!fMoreIdleWork && (pQueue != NULL))
  2009. {
  2010. LONG_PTR cIdleTasks;
  2011. pQueue->ScGetTaskCount (&cIdleTasks);
  2012. if(sc)
  2013. goto Error;
  2014. /*
  2015. * do we have any idle tasks?
  2016. */
  2017. if (cIdleTasks > 0)
  2018. {
  2019. SC sc = pQueue->ScPerformNextTask();
  2020. if(sc)
  2021. goto Error;
  2022. /*
  2023. * this idle task may have added others; refresh the count
  2024. */
  2025. sc = pQueue->ScGetTaskCount(&cIdleTasks);
  2026. if(sc)
  2027. goto Error;
  2028. }
  2029. /*
  2030. * do we have any more idle work to do?
  2031. */
  2032. fMoreIdleWork = (cIdleTasks > 0);
  2033. }
  2034. if (!fMoreIdleWork)
  2035. {
  2036. // this code is to trigger MMC exit sequence when it
  2037. // is under the script control and the last reference is released.
  2038. // (we do not use MFC [which would simply delete the mainframe] to do that)
  2039. if ( !IsUnderUserControl() && CMMCStrongReferences::LastRefReleased() )
  2040. {
  2041. // we are in script control mode and all references are released
  2042. // a good time to say goodbye
  2043. CMainFrame *pMainFrame = GetMainFrame();
  2044. sc = ScCheckPointers(pMainFrame, E_UNEXPECTED);
  2045. if (sc)
  2046. goto Error;
  2047. // disabled main window will probably mean we are under modal dialog
  2048. // wait until it is dismissed ( and try again )
  2049. if (pMainFrame->IsWindowEnabled())
  2050. {
  2051. // here is the deal: if MMC is shown - we will initiate the exit sequence,
  2052. // but put into the user mode first, so if user chooses to cancel it - it will have
  2053. // the control over the application. He will also have to handle save request if
  2054. // something has changed in the console
  2055. if ( pMainFrame->IsWindowVisible() )
  2056. {
  2057. if ( !m_fUnderUserControl )
  2058. SetUnderUserControl();
  2059. pMainFrame->PostMessage(WM_CLOSE);
  2060. }
  2061. else
  2062. {
  2063. // if the application is hidden it should wait until user closes all open property sheets.
  2064. // since it will come back here, waiting means just doing nothing at this point.
  2065. if ( !FArePropertySheetsOpen(NULL, false /*bBringToFrontAndAskToClose*/ ) )
  2066. {
  2067. // if there are not sheets open - we must die silently
  2068. CAMCDoc* const pDoc = CAMCDoc::GetDocument();
  2069. if(pDoc == NULL)
  2070. {
  2071. sc = E_POINTER;
  2072. //fall thru; (need to close anyway)
  2073. }
  2074. else
  2075. {
  2076. // discard document without asking to save
  2077. pDoc->OnCloseDocument();
  2078. }
  2079. // say goodbye
  2080. pMainFrame->PostMessage(WM_CLOSE);
  2081. }
  2082. }
  2083. }
  2084. }
  2085. }
  2086. Cleanup:
  2087. return (fMoreIdleWork);
  2088. Error:
  2089. TraceError(TEXT("CAMCApp::OnIdle"), sc);
  2090. goto Cleanup;
  2091. }
  2092. //+-------------------------------------------------------------------
  2093. //
  2094. // Member: InitializeMode
  2095. //
  2096. // Synopsis: Set the mode and load the menus, accelerator tables.
  2097. //
  2098. // Arguments: [eMode] - New application mode.
  2099. //
  2100. // Returns: None.
  2101. //
  2102. //--------------------------------------------------------------------
  2103. void CAMCApp::InitializeMode (ProgramMode eMode)
  2104. {
  2105. SetMode(eMode);
  2106. UpdateFrameWindow(false);
  2107. }
  2108. //+-------------------------------------------------------------------
  2109. //
  2110. // Member: SetMode
  2111. //
  2112. // Synopsis: Set the mode.
  2113. //
  2114. // Note: Call UpdateFrameWindow some time soon to update
  2115. // menus/toolbars for this mode.
  2116. // Cannot do this in this method. This is called
  2117. // from CAMCDoc::LoadAppMode. The CAMCDoc::LoadFrame
  2118. // calls the UpdateFrameWindow.
  2119. //
  2120. // Arguments: [eMode] - New application mode.
  2121. //
  2122. // Returns: None.
  2123. //
  2124. //--------------------------------------------------------------------
  2125. void CAMCApp::SetMode (ProgramMode eMode)
  2126. {
  2127. ASSERT (IsValidProgramMode (eMode));
  2128. if (m_fAuthorModeForced)
  2129. {
  2130. ASSERT (m_eMode == eMode_Author);
  2131. ASSERT (GetMainFrame()->IsMenuVisible ());
  2132. }
  2133. else
  2134. m_eMode = eMode;
  2135. }
  2136. //+-------------------------------------------------------------------
  2137. //
  2138. // Member: UpdateFrameWindow
  2139. //
  2140. // Synopsis: Load the menu/accelerator tables and update
  2141. // them if loaded from console file.
  2142. //
  2143. // Note: Call UpdateFrameWindow some time soon after
  2144. // calling SetMode to update menus/toolbars for this mode.
  2145. // This is called from CAMCDoc::LoadFrame.
  2146. //
  2147. // Arguments: [bUpdate] - BOOL
  2148. // We need to update the toolbar/menus only
  2149. // if loaded from console file
  2150. //
  2151. // Returns: None.
  2152. //
  2153. //--------------------------------------------------------------------
  2154. void CAMCApp::UpdateFrameWindow(bool bUpdate)
  2155. {
  2156. static const struct ModeDisplayParams
  2157. {
  2158. int nResourceID;
  2159. bool fShowToolbar;
  2160. } aDisplayParams[eMode_Count] =
  2161. {
  2162. { IDR_AMCTYPE, true }, // eMode_Author
  2163. { IDR_AMCTYPE_USER, false }, // eMode_User
  2164. { IDR_AMCTYPE_MDI_USER, false }, // eMode_User_MDI
  2165. { IDR_AMCTYPE_SDI_USER, false }, // eMode_User_SDI
  2166. };
  2167. if (m_fAuthorModeForced)
  2168. {
  2169. ASSERT (m_eMode == eMode_Author);
  2170. ASSERT (GetMainFrame()->IsMenuVisible ());
  2171. return;
  2172. }
  2173. m_Menu.DestroyMenu ();
  2174. m_Accel.DestroyAcceleratorTable ();
  2175. VERIFY (m_Menu.LoadMenu (aDisplayParams[m_eMode].nResourceID));
  2176. m_Accel.LoadAccelerators (aDisplayParams[m_eMode].nResourceID);
  2177. if (bUpdate)
  2178. {
  2179. CMainFrame *pMainFrame = GetMainFrame();
  2180. ASSERT (pMainFrame != NULL);
  2181. ASSERT_VALID (pMainFrame);
  2182. CMDIChildWnd* pwndActive = pMainFrame ? pMainFrame->MDIGetActive () : NULL;
  2183. // bypass CMainFrame::OnUpdateFrameMenu so CMainFrame::NotifyMenuChanged
  2184. // doesn't get called twice and remove the new menu entirely
  2185. if (pwndActive != NULL)
  2186. pwndActive->OnUpdateFrameMenu (TRUE, pwndActive, m_Menu);
  2187. else if (pMainFrame)
  2188. pMainFrame->OnUpdateFrameMenu (m_Menu);
  2189. if (m_eMode == eMode_User_SDI)
  2190. {
  2191. if (pwndActive != NULL)
  2192. pwndActive->MDIMaximize ();
  2193. if (pMainFrame)
  2194. AppendToSystemMenu (pMainFrame, eMode_User_SDI);
  2195. }
  2196. if (pMainFrame)
  2197. pMainFrame->ShowMenu (true /*Always show menu*/);
  2198. }
  2199. }
  2200. /*+-------------------------------------------------------------------------*
  2201. * IsInContainer
  2202. *
  2203. *
  2204. *--------------------------------------------------------------------------*/
  2205. template<class InputIterator, class T>
  2206. bool Find (InputIterator itFirst, InputIterator itLast, const T& t)
  2207. {
  2208. return (std::find (itFirst, itLast, t) != itLast);
  2209. }
  2210. /*+-------------------------------------------------------------------------*
  2211. * CAMCApp::HookPreTranslateMessage
  2212. *
  2213. * Adds a window the the list of windows that get prioritized cracks at
  2214. * PreTranslateMessage. Hooks set later get priority over earlier hooks.
  2215. *--------------------------------------------------------------------------*/
  2216. void CAMCApp::HookPreTranslateMessage (CWnd* pwndHook)
  2217. {
  2218. HWND hwndHook = pwndHook->GetSafeHwnd();
  2219. ASSERT (IsWindow (hwndHook));
  2220. // this only makes sense for permanent windows
  2221. ASSERT (CWnd::FromHandlePermanent(hwndHook) == pwndHook);
  2222. /*
  2223. * Put the hook window at the front of the hook list. We're preserving
  2224. * the HWND instead of the CWnd* so we don't have unnecessary list<>
  2225. * code generated. We already use a list<HWND> for m_DelayedUpdateWindows,
  2226. * so using list<HWND> here doesn't cause any more code to be generated.
  2227. */
  2228. if (!Find (m_TranslateMessageHookWindows.begin(),
  2229. m_TranslateMessageHookWindows.end(),
  2230. hwndHook))
  2231. {
  2232. m_TranslateMessageHookWindows.push_front (hwndHook);
  2233. }
  2234. }
  2235. /*+-------------------------------------------------------------------------*
  2236. * CAMCApp::UnhookPreTranslateMessage
  2237. *
  2238. *
  2239. *--------------------------------------------------------------------------*/
  2240. void CAMCApp::UnhookPreTranslateMessage (CWnd* pwndUnhook)
  2241. {
  2242. HWND hwndUnhook = pwndUnhook->GetSafeHwnd();
  2243. ASSERT (IsWindow (hwndUnhook));
  2244. WindowListIterator itEnd = m_TranslateMessageHookWindows.end();
  2245. WindowListIterator itFound = std::find (m_TranslateMessageHookWindows.begin(),
  2246. itEnd, hwndUnhook);
  2247. if (itFound != itEnd)
  2248. m_TranslateMessageHookWindows.erase (itFound);
  2249. }
  2250. /*+-------------------------------------------------------------------------*
  2251. * CAMCApp::GetIdleTaskQueue
  2252. *
  2253. * Returns the IIdleTaskQueue interface for the application, creating it
  2254. * if necessary.
  2255. *--------------------------------------------------------------------------*/
  2256. CIdleTaskQueue * CAMCApp::GetIdleTaskQueue ()
  2257. {
  2258. return &m_IdleTaskQueue;
  2259. }
  2260. /*+-------------------------------------------------------------------------*
  2261. * ScExpandEnvironmentStrings
  2262. *
  2263. * Expands the any environment string (e.g. %SystemRoot%) in the input
  2264. * string, in place.
  2265. *--------------------------------------------------------------------------*/
  2266. SC ScExpandEnvironmentStrings (CString& str)
  2267. {
  2268. DECLARE_SC (sc, _T("ScExpandEnvironmentStrings"));
  2269. if (str.Find(_T('%')) != -1)
  2270. {
  2271. TCHAR szBuffer[MAX_PATH];
  2272. if (!ExpandEnvironmentStrings (str, szBuffer, countof(szBuffer)))
  2273. return (sc.FromLastError());
  2274. str = szBuffer;
  2275. }
  2276. return (sc);
  2277. }
  2278. /*+-------------------------------------------------------------------------*
  2279. * ScCreateDumpSnapins
  2280. *
  2281. * Creates a CLSID_MMCDocConfig object, opens it on the supplied filename,
  2282. * and returns a pointer to the IDumpSnapins interface on the object.
  2283. *--------------------------------------------------------------------------*/
  2284. SC ScCreateDumpSnapins (
  2285. CString& strConsoleFile, /* I/O:console file */
  2286. IDumpSnapins** ppDumpSnapins) /* O:IDumpSnapins interface */
  2287. {
  2288. DECLARE_SC (sc, _T("ScCreateDumpSnapins"));
  2289. /*
  2290. * validate input
  2291. */
  2292. sc = ScCheckPointers (ppDumpSnapins);
  2293. if (sc)
  2294. return (sc);
  2295. *ppDumpSnapins = NULL;
  2296. /*
  2297. * create a doc config object
  2298. */
  2299. IDocConfigPtr spDocConfig;
  2300. sc = spDocConfig.CreateInstance (CLSID_MMCDocConfig);
  2301. if (sc)
  2302. return (sc);
  2303. /*
  2304. * expand any embedded environment strings in the console filename
  2305. */
  2306. sc = ScExpandEnvironmentStrings (strConsoleFile);
  2307. if (sc)
  2308. return (sc);
  2309. /*
  2310. * open the console file
  2311. */
  2312. sc = spDocConfig->OpenFile (::ATL::CComBSTR (strConsoleFile));
  2313. if (sc)
  2314. return (sc);
  2315. /*
  2316. * get the IDumpSnapins interface
  2317. */
  2318. sc = spDocConfig.QueryInterface (IID_IDumpSnapins, *ppDumpSnapins);
  2319. if (sc)
  2320. return (sc);
  2321. return (sc);
  2322. }
  2323. /*+-------------------------------------------------------------------------*
  2324. * CAMCApp::DumpConsoleFile
  2325. *
  2326. *
  2327. *--------------------------------------------------------------------------*/
  2328. HRESULT CAMCApp::DumpConsoleFile (CString strConsoleFile, CString strDumpFile)
  2329. {
  2330. DECLARE_SC (sc, _T("CAMCApp::DumpConsoleFile"));
  2331. const CString* pstrFileWithError = &strConsoleFile;
  2332. /*
  2333. * get an IDumpSnapins interface on this console file
  2334. */
  2335. IDumpSnapinsPtr spDumpSnapins;
  2336. sc = ScCreateDumpSnapins (strConsoleFile, &spDumpSnapins);
  2337. if (sc)
  2338. goto Error;
  2339. sc = ScCheckPointers (spDumpSnapins, E_UNEXPECTED);
  2340. if (sc)
  2341. goto Error;
  2342. /*
  2343. * expand the dump filename if necessary
  2344. */
  2345. sc = ScExpandEnvironmentStrings (strDumpFile);
  2346. if (sc)
  2347. goto Error;
  2348. /*
  2349. * If there's no directory specifier on the dump file, put a "current
  2350. * directory" marker on it. We do this to prevent WritePrivateProfile*
  2351. * from putting the file in the Windows directory.
  2352. */
  2353. if (strDumpFile.FindOneOf(_T(":\\")) == -1)
  2354. strDumpFile = _T(".\\") + strDumpFile;
  2355. /*
  2356. * future file-related errors will pertain to the dump file
  2357. * (see Error handler)
  2358. */
  2359. pstrFileWithError = &strDumpFile;
  2360. /*
  2361. * wipe out the existing file, if any
  2362. */
  2363. if ((GetFileAttributes (strDumpFile) != 0xFFFFFFFF) && !DeleteFile (strDumpFile))
  2364. {
  2365. sc.FromLastError();
  2366. goto Error;
  2367. }
  2368. /*
  2369. * dump the contents of the console file
  2370. */
  2371. sc = spDumpSnapins->Dump (strDumpFile);
  2372. if (sc)
  2373. goto Error;
  2374. return (sc.ToHr());
  2375. Error:
  2376. MMCErrorBox (*pstrFileWithError, sc);
  2377. return (sc.ToHr());
  2378. }
  2379. /***************************************************************************\
  2380. *
  2381. * METHOD: CAMCApp::ScOnNewDocument
  2382. *
  2383. * PURPOSE: Emits script event for application object
  2384. *
  2385. * PARAMETERS:
  2386. * CAMCDoc *pDocument [in] document being created/opened
  2387. * BOOL bLoadedFromConsole [in] if document is loaded from file
  2388. *
  2389. * RETURNS:
  2390. * SC - result code
  2391. *
  2392. \***************************************************************************/
  2393. SC CAMCApp::ScOnNewDocument(CAMCDoc *pDocument, BOOL bLoadedFromConsole)
  2394. {
  2395. DECLARE_SC(sc, TEXT("CAMCApp::ScOnNewDocument"));
  2396. // check if there are "listeners"
  2397. sc = ScHasSinks(m_sp_Application, AppEvents);
  2398. if (sc)
  2399. return sc;
  2400. if (sc == SC(S_FALSE)) // no sinks;
  2401. return sc;
  2402. // construct document com object
  2403. DocumentPtr spComDoc;
  2404. sc = pDocument->ScGetMMCDocument(&spComDoc);
  2405. if (sc)
  2406. return sc;
  2407. // check pointer
  2408. sc = ScCheckPointers(spComDoc, E_POINTER);
  2409. if (sc)
  2410. return sc;
  2411. // fire the event
  2412. sc = ScFireComEvent(m_sp_Application, AppEvents , OnDocumentOpen (spComDoc , bLoadedFromConsole == FALSE));
  2413. if (sc)
  2414. sc.TraceAndClear(); // failure to issue the com event is not critical to this action
  2415. return sc;
  2416. }
  2417. /***************************************************************************\
  2418. *
  2419. * METHOD: CAMCApp::ScOnQuitApp
  2420. *
  2421. * PURPOSE: Emits script event for application object
  2422. *
  2423. * PARAMETERS:
  2424. *
  2425. * RETURNS:
  2426. * SC - result code
  2427. *
  2428. \***************************************************************************/
  2429. SC CAMCApp::ScOnQuitApp()
  2430. {
  2431. DECLARE_SC(sc, TEXT("CAMCApp::ScOnQuitApp"));
  2432. // fire the event
  2433. sc = ScFireComEvent(m_sp_Application, AppEvents , OnQuit (m_sp_Application));
  2434. if (sc)
  2435. sc.TraceAndClear(); // failure to issue the com event is not critical to this action
  2436. return sc;
  2437. }
  2438. /***************************************************************************\
  2439. *
  2440. * METHOD: CAMCApp::ScOnCloseView
  2441. *
  2442. * PURPOSE: Script event firing helper. Invoked when the view is closed
  2443. *
  2444. * PARAMETERS:
  2445. * CAMCView *pView [in] - view being closed
  2446. *
  2447. * RETURNS:
  2448. * SC - result code
  2449. *
  2450. \***************************************************************************/
  2451. SC CAMCApp::ScOnCloseView( CAMCView *pView )
  2452. {
  2453. DECLARE_SC(sc, TEXT("CAMCApp::ScOnCloseView"));
  2454. // parameter check
  2455. sc = ScCheckPointers(pView);
  2456. if (sc)
  2457. return sc;
  2458. // check if we have sinks connected
  2459. sc = ScHasSinks(m_sp_Application, AppEvents);
  2460. if (sc)
  2461. return sc;
  2462. if (sc == SC(S_FALSE)) // no sinks
  2463. return sc;
  2464. // construct view com object
  2465. ViewPtr spView;
  2466. sc = pView->ScGetMMCView(&spView);
  2467. if (sc)
  2468. return sc;
  2469. // fire the event
  2470. sc = ScFireComEvent(m_sp_Application, AppEvents , OnViewClose (spView));
  2471. if (sc)
  2472. sc.TraceAndClear(); // failure to issue the com event is not critical to this action
  2473. return sc;
  2474. }
  2475. /***************************************************************************\
  2476. *
  2477. * METHOD: CAMCApp::ScOnViewChange
  2478. *
  2479. * PURPOSE: Script event firing helper. Invoked when scope selection change
  2480. *
  2481. * PARAMETERS:
  2482. * CAMCView *pView [in] affected view
  2483. * HNODE hNode [in] new selected scope node
  2484. *
  2485. * RETURNS:
  2486. * SC - result code
  2487. *
  2488. \***************************************************************************/
  2489. SC CAMCApp::ScOnViewChange( CAMCView *pView, HNODE hNode )
  2490. {
  2491. DECLARE_SC(sc, TEXT("CAMCApp::ScOnViewChange"));
  2492. // parameter check
  2493. sc = ScCheckPointers(pView);
  2494. if (sc)
  2495. return sc;
  2496. // check if we have sinks connected
  2497. sc = ScHasSinks(m_sp_Application, AppEvents);
  2498. if (sc)
  2499. return sc;
  2500. if (sc == SC(S_FALSE)) // no sinks
  2501. return sc;
  2502. // construct view com object
  2503. ViewPtr spView;
  2504. sc = pView->ScGetMMCView(&spView);
  2505. if (sc)
  2506. return sc;
  2507. // construct Node com object
  2508. NodePtr spNode;
  2509. sc = pView->ScGetScopeNode( hNode, &spNode );
  2510. if (sc)
  2511. return sc;
  2512. // fire script event
  2513. sc = ScFireComEvent(m_sp_Application, AppEvents , OnViewChange(spView, spNode));
  2514. if (sc)
  2515. sc.TraceAndClear(); // failure to issue the com event is not critical to this action
  2516. return sc;
  2517. }
  2518. /***************************************************************************\
  2519. *
  2520. * METHOD: CAMCApp::ScOnResultSelectionChange
  2521. *
  2522. * PURPOSE: Script event firing helper. Invoked when result selection change
  2523. *
  2524. * PARAMETERS:
  2525. * CAMCView *pView [in] - affected view
  2526. *
  2527. * RETURNS:
  2528. * SC - result code
  2529. *
  2530. \***************************************************************************/
  2531. SC CAMCApp::ScOnResultSelectionChange( CAMCView *pView )
  2532. {
  2533. DECLARE_SC(sc, TEXT("CAMCApp::ScOnResultSelectionChange"));
  2534. // parameter check
  2535. sc = ScCheckPointers(pView);
  2536. if (sc)
  2537. return sc;
  2538. // check if we have sinks connected
  2539. sc = ScHasSinks(m_sp_Application, AppEvents);
  2540. if (sc)
  2541. return sc;
  2542. if (sc == SC(S_FALSE)) // no sinks
  2543. return sc;
  2544. // construct view com object
  2545. ViewPtr spView;
  2546. sc = pView->ScGetMMCView(&spView);
  2547. if (sc)
  2548. return sc;
  2549. // construct Node com object
  2550. NodesPtr spNodes;
  2551. sc = pView->Scget_Selection( &spNodes );
  2552. if (sc)
  2553. return sc;
  2554. // fire script event
  2555. sc = ScFireComEvent(m_sp_Application, AppEvents , OnSelectionChange(spView, spNodes));
  2556. if (sc)
  2557. sc.TraceAndClear(); // failure to issue the com event is not critical to this action
  2558. return sc;
  2559. }
  2560. /***************************************************************************\
  2561. *
  2562. * METHOD: CMMCApplication::ScOnContextMenuExecuted
  2563. *
  2564. * PURPOSE: called when the context menu is executed to fire the event to script
  2565. *
  2566. * PARAMETERS:
  2567. * PMENUITEM pMenuItem - menu item (note: it may be NULL if menu item is gone)
  2568. *
  2569. * RETURNS:
  2570. * SC - result code
  2571. *
  2572. \***************************************************************************/
  2573. SC CAMCApp::ScOnContextMenuExecuted( PMENUITEM pMenuItem )
  2574. {
  2575. DECLARE_SC(sc, TEXT("CAMCApp::ScOnContextMenuExecuted"));
  2576. // see if we have sinks connected
  2577. sc = ScHasSinks(m_sp_Application, AppEvents);
  2578. if (sc)
  2579. return sc;
  2580. if (sc == SC(S_FALSE)) // no sinks
  2581. return sc;
  2582. // fire the event
  2583. sc = ScFireComEvent(m_sp_Application, AppEvents, OnContextMenuExecuted( pMenuItem ) );
  2584. if (sc)
  2585. sc.TraceAndClear(); // failure to issue the com event is not critical to this action
  2586. return sc;
  2587. }
  2588. /*+-------------------------------------------------------------------------*
  2589. *
  2590. * CAMCApp::ScOnListViewItemUpdated
  2591. *
  2592. * PURPOSE:
  2593. *
  2594. * PARAMETERS:
  2595. * CAMCView * pView :
  2596. * int nIndex :
  2597. *
  2598. * RETURNS:
  2599. * SC
  2600. *
  2601. *+-------------------------------------------------------------------------*/
  2602. SC
  2603. CAMCApp::ScOnListViewItemUpdated(CAMCView *pView , int nIndex)
  2604. {
  2605. DECLARE_SC(sc, TEXT("CAMCApp::ScOnListViewItemUpdated"));
  2606. // parameter check
  2607. sc = ScCheckPointers(pView);
  2608. if (sc)
  2609. return sc;
  2610. // check if we have sinks connected
  2611. sc = ScHasSinks(m_sp_Application, AppEvents);
  2612. if (sc)
  2613. return sc;
  2614. if (sc == SC(S_FALSE)) // no sinks
  2615. return sc;
  2616. // construct view com object
  2617. ViewPtr spView;
  2618. sc = pView->ScGetMMCView(&spView);
  2619. if (sc)
  2620. return sc;
  2621. // fire script event
  2622. sc = ScFireComEvent(m_sp_Application, AppEvents , OnListUpdated(spView));
  2623. if (sc)
  2624. sc.TraceAndClear(); // failure to issue the com event is not critical to this action
  2625. return sc;
  2626. }
  2627. /***************************************************************************\
  2628. *
  2629. * METHOD: CAMCApp::ScOnSnapinAdded
  2630. *
  2631. * PURPOSE: Script event firing helper. Implements interface accessible from
  2632. * node manager
  2633. *
  2634. * PARAMETERS:
  2635. * PSNAPIN pSnapIn [in] - snapin added to the console
  2636. *
  2637. * RETURNS:
  2638. * SC - result code
  2639. *
  2640. \***************************************************************************/
  2641. SC CAMCApp::ScOnSnapinAdded(CAMCDoc *pAMCDoc, PSNAPIN pSnapIn)
  2642. {
  2643. DECLARE_SC(sc, TEXT("CAMCApp::ScOnSnapinAdded"));
  2644. // parameter check
  2645. sc = ScCheckPointers(pAMCDoc, pSnapIn);
  2646. if (sc)
  2647. return sc;
  2648. // see if we have sinks connected
  2649. sc = ScHasSinks(m_sp_Application, AppEvents);
  2650. if (sc)
  2651. return sc;
  2652. if (sc == SC(S_FALSE)) // no sinks
  2653. return sc;
  2654. DocumentPtr spDocument;
  2655. sc = pAMCDoc->ScGetMMCDocument(&spDocument);
  2656. if (sc)
  2657. return sc;
  2658. // check
  2659. sc = ScCheckPointers(spDocument, E_UNEXPECTED);
  2660. if (sc)
  2661. return sc;
  2662. // fire the event
  2663. sc = ScFireComEvent(m_sp_Application, AppEvents , OnSnapInAdded (spDocument, pSnapIn));
  2664. if (sc)
  2665. sc.TraceAndClear(); // failure to issue the com event is not critical to this action
  2666. return sc;
  2667. }
  2668. /***************************************************************************\
  2669. *
  2670. * METHOD: CAMCApp::ScOnSnapinRemoved
  2671. *
  2672. * PURPOSE: Script event firing helper. Implements interface accessible from
  2673. * node manager
  2674. *
  2675. * PARAMETERS:
  2676. * PSNAPIN pSnapIn [in] - snapin removed from console
  2677. *
  2678. * RETURNS:
  2679. * SC - result code
  2680. *
  2681. \***************************************************************************/
  2682. SC CAMCApp::ScOnSnapinRemoved(CAMCDoc *pAMCDoc, PSNAPIN pSnapIn)
  2683. {
  2684. DECLARE_SC(sc, TEXT("CAMCApp::ScOnSnapinRemoved"));
  2685. // parameter check
  2686. sc = ScCheckPointers(pAMCDoc, pSnapIn);
  2687. if (sc)
  2688. return sc;
  2689. // see if we have sinks connected
  2690. sc = ScHasSinks(m_sp_Application, AppEvents);
  2691. if (sc)
  2692. return sc;
  2693. if (sc == SC(S_FALSE)) // no sinks
  2694. return sc;
  2695. DocumentPtr spDocument;
  2696. sc = pAMCDoc->ScGetMMCDocument(&spDocument);
  2697. if (sc)
  2698. return sc;
  2699. // check
  2700. sc = ScCheckPointers(spDocument, E_UNEXPECTED);
  2701. if (sc)
  2702. return sc;
  2703. // fire the event
  2704. sc = ScFireComEvent(m_sp_Application, AppEvents , OnSnapInRemoved (spDocument, pSnapIn));
  2705. if (sc)
  2706. sc.TraceAndClear(); // failure to issue the com event is not critical to this action
  2707. return sc;
  2708. }
  2709. /***************************************************************************\
  2710. *
  2711. * METHOD: CAMCApp::ScOnNewView
  2712. *
  2713. * PURPOSE: Script event firing helper
  2714. *
  2715. * PARAMETERS:
  2716. * CAMCView *pView [in] - created view
  2717. *
  2718. * RETURNS:
  2719. * SC - result code
  2720. *
  2721. \***************************************************************************/
  2722. SC CAMCApp::ScOnNewView(CAMCView *pView)
  2723. {
  2724. DECLARE_SC(sc, TEXT("CAMCApp::ScOnNewView"));
  2725. // parameter check
  2726. sc = ScCheckPointers(pView);
  2727. if (sc)
  2728. return sc;
  2729. // see if we have sinks connected
  2730. sc = ScHasSinks(m_sp_Application, AppEvents);
  2731. if (sc)
  2732. return sc;
  2733. if (sc == SC(S_FALSE)) // no sinks
  2734. return sc;
  2735. // construct View com object
  2736. ViewPtr spView;
  2737. sc = pView->ScGetMMCView(&spView);
  2738. if (sc)
  2739. return sc;
  2740. // fire the event
  2741. sc = ScFireComEvent(m_sp_Application, AppEvents , OnNewView(spView));
  2742. if (sc)
  2743. sc.TraceAndClear(); // failure to issue the com event is not critical to this action
  2744. return sc;
  2745. }
  2746. /***************************************************************************\
  2747. *
  2748. * METHOD: CAMCApp::OnCloseDocument
  2749. *
  2750. * PURPOSE: Helper for invoking com event
  2751. *
  2752. * PARAMETERS:
  2753. * CAMCDoc *pAMCDoc [in] - document being closed
  2754. *
  2755. * RETURNS:
  2756. * SC - result code
  2757. *
  2758. \***************************************************************************/
  2759. SC CAMCApp::ScOnCloseDocument(CAMCDoc *pAMCDoc)
  2760. {
  2761. DECLARE_SC(sc, TEXT("CAMCApp::OnCloseDocument"));
  2762. // parameter check
  2763. sc = ScCheckPointers(pAMCDoc);
  2764. if (sc)
  2765. return sc;
  2766. // see if we have sinks connected
  2767. sc = ScHasSinks(m_sp_Application, AppEvents);
  2768. if (sc)
  2769. return sc;
  2770. if (sc == SC(S_FALSE)) // no sinks
  2771. return sc;
  2772. DocumentPtr spDocument;
  2773. sc = pAMCDoc->ScGetMMCDocument(&spDocument);
  2774. if (sc)
  2775. return sc;
  2776. // check
  2777. sc = ScCheckPointers(spDocument, E_UNEXPECTED);
  2778. if (sc)
  2779. return sc;
  2780. // fire the event
  2781. sc = ScFireComEvent(m_sp_Application, AppEvents , OnDocumentClose (spDocument));
  2782. if (sc)
  2783. sc.TraceAndClear(); // failure to issue the com event is not critical to this action
  2784. return sc;
  2785. }
  2786. /***************************************************************************\
  2787. *
  2788. * METHOD: CAMCApp::ScOnToolbarButtonClicked
  2789. *
  2790. * PURPOSE: Observed toolbar event - used to fire com event
  2791. *
  2792. * PARAMETERS:
  2793. * CAMCView *pAMCView - [in] view which toobar is executed
  2794. *
  2795. * RETURNS:
  2796. * SC - result code
  2797. *
  2798. \***************************************************************************/
  2799. SC CAMCApp::ScOnToolbarButtonClicked( )
  2800. {
  2801. DECLARE_SC(sc, TEXT("CAMCApp::ScOnToolbarButtonClicked"));
  2802. // see if we have sinks connected
  2803. sc = ScHasSinks(m_sp_Application, AppEvents);
  2804. if (sc)
  2805. return sc;
  2806. if (sc == SC(S_FALSE)) // no sinks
  2807. return sc;
  2808. // fire the event
  2809. sc = ScFireComEvent(m_sp_Application, AppEvents , OnToolbarButtonClicked ( ));
  2810. if (sc)
  2811. sc.TraceAndClear(); // ignore the error - should not affect main behavior
  2812. return sc;
  2813. }
  2814. /***************************************************************************\
  2815. *
  2816. * METHOD: CAMCApp::SetUnderUserControl
  2817. *
  2818. * PURPOSE: puts application into user control/script control mode
  2819. * implements Application.UserControl property
  2820. *
  2821. * PARAMETERS:
  2822. * bool bUserControl [in] true == set user control
  2823. *
  2824. * RETURNS:
  2825. * void
  2826. *
  2827. \***************************************************************************/
  2828. void CAMCApp::SetUnderUserControl(bool bUserControl /* = true */ )
  2829. {
  2830. m_fUnderUserControl = bUserControl;
  2831. AfxOleSetUserCtrl(bUserControl); // allow MFC to know that
  2832. if (bUserControl)
  2833. {
  2834. // make sure application is visible if it's under user control
  2835. CMainFrame *pMainFrame = GetMainFrame();
  2836. if(pMainFrame && !pMainFrame->IsWindowVisible())
  2837. {
  2838. pMainFrame->ShowWindow(SW_SHOW);
  2839. }
  2840. }
  2841. }
  2842. #ifdef MMC_WIN64
  2843. /*+-------------------------------------------------------------------------*
  2844. * CompareBasicSnapinInfo
  2845. *
  2846. * Implements a less-than comparison for CBasicSnapinInfo, based solely on
  2847. * the CLSID. Returns true if the CLSID for bsi1 is less than the CLSID
  2848. * for bsi2, false otherwise.
  2849. *--------------------------------------------------------------------------*/
  2850. bool CompareBasicSnapinInfo (const CBasicSnapinInfo& bsi1, const CBasicSnapinInfo& bsi2)
  2851. {
  2852. return (bsi1.m_clsid < bsi2.m_clsid);
  2853. }
  2854. /*+-------------------------------------------------------------------------*
  2855. * ScDetermineArchitecture
  2856. *
  2857. * Determines whether MMC64 (which is currently executing) should chain
  2858. * to MMC32. This will occur in one of three situations:
  2859. *
  2860. * 1. The "-32" command line parameter was specified.
  2861. *
  2862. * 2. A console file was specified on the command line, and it contains
  2863. * one or more snap-ins that were not registered in the 64-bit HKCR
  2864. * hive, but all snap-ins are registered in the 32-bit HKCR hive.
  2865. *
  2866. * 3. A console file was specified on the command line, and it contained
  2867. * one or more snap-ins that were not registered in the 64-bit HKCR
  2868. * hive, and one or more snap-ins that are not registered in the 32-bit
  2869. * HKCR hive. In this case we'll do one of three things:
  2870. *
  2871. * a. If the set of unavailable 64-bit snap-ins is a subset of the
  2872. * set of unavailable 32-bit snap-ins, the 64-bit console will be
  2873. * more functional than the 32-bit console, so we'll run MMC64.
  2874. *
  2875. * b. If the set of unavailable 32-bit snap-ins is a subset of the
  2876. * set of unavailable 64-bit snap-ins, the 32-bit console will be
  2877. * more functional than the 64-bit console, so we'll run MMC32.
  2878. *
  2879. * c. If neither a. or b. is true, we'll display UI asking which
  2880. * version of MMC to run.
  2881. *
  2882. * Returns:
  2883. * eArch == eArch_64bit - 64-bit MMC is needed (or an error occurred)
  2884. * eArch == eArch_32bit - 32-bit MMC is needed
  2885. * eArch == eArch_None - user cancelled the operation
  2886. *--------------------------------------------------------------------------*/
  2887. SC ScDetermineArchitecture (const CMMCCommandLineInfo& rCmdInfo, eArchitecture& eArch)
  2888. {
  2889. DECLARE_SC (sc, _T("ScDetermineArchitecture"));
  2890. /*
  2891. * default to 64-bit
  2892. */
  2893. eArch = eArch_64bit;
  2894. /*
  2895. * Case 0: Was "-64" specified on the command line? 64-bit needed
  2896. */
  2897. if (rCmdInfo.m_eArch == eArch_64bit)
  2898. {
  2899. Trace (tag32BitTransfer, _T("\"-64\" parameter specified, 64-bit MMC needed"));
  2900. return (sc);
  2901. }
  2902. /*
  2903. * Case 1: Was "-32" specified on the command line? 32-bit needed
  2904. */
  2905. if (rCmdInfo.m_eArch == eArch_32bit)
  2906. {
  2907. Trace (tag32BitTransfer, _T("\"-32\" parameter specified, 32-bit MMC needed"));
  2908. eArch = eArch_32bit;
  2909. return (sc);
  2910. }
  2911. /*
  2912. * No file on the command line? 64-bit needed
  2913. */
  2914. if (rCmdInfo.m_nShellCommand != CCommandLineInfo::FileOpen)
  2915. {
  2916. Trace (tag32BitTransfer, _T("No console file specified, 64-bit MMC needed"));
  2917. return (sc);
  2918. }
  2919. /*
  2920. * Cases 2 and 3: Analyze the specified console file
  2921. */
  2922. Trace (tag32BitTransfer, _T("Analyzing snap-ins in \"%s\""), (LPCTSTR) rCmdInfo.m_strFileName);
  2923. /*
  2924. * get an IDumpSnapins interface so we can analyze the console file
  2925. */
  2926. IDumpSnapinsPtr spDumpSnapins;
  2927. CString strConsoleFile = rCmdInfo.m_strFileName;
  2928. sc = ScCreateDumpSnapins (strConsoleFile, &spDumpSnapins);
  2929. if (sc)
  2930. return (sc);
  2931. sc = ScCheckPointers (spDumpSnapins, E_UNEXPECTED);
  2932. if (sc)
  2933. return (sc);
  2934. /*
  2935. * analyze the 64-bit snap-ins in this console
  2936. */
  2937. CAvailableSnapinInfo asi64(false);
  2938. sc = spDumpSnapins->CheckSnapinAvailability (asi64);
  2939. if (sc)
  2940. return (sc);
  2941. /*
  2942. * if no snap-ins are unavailable in 64-bit form, no need for MMC32
  2943. */
  2944. if (asi64.m_vAvailableSnapins.size() == asi64.m_cTotalSnapins)
  2945. {
  2946. Trace (tag32BitTransfer, _T("All snapins are available in 64-bit form, 64-bit MMC needed"));
  2947. return (sc);
  2948. }
  2949. /*
  2950. * analyze the 32-bit snap-ins in this console
  2951. */
  2952. CAvailableSnapinInfo asi32(true);
  2953. sc = spDumpSnapins->CheckSnapinAvailability (asi32);
  2954. if (sc)
  2955. return (sc);
  2956. /*
  2957. * Case 2: If no snap-ins are unavailable in 32-bit form, 32-bit needed
  2958. */
  2959. if (asi32.m_vAvailableSnapins.size() == asi32.m_cTotalSnapins)
  2960. {
  2961. Trace (tag32BitTransfer, _T("All snapins are available in 32-bit form, 32-bit MMC needed"));
  2962. eArch = eArch_32bit;
  2963. return (sc);
  2964. }
  2965. /*
  2966. * std::includes depends on its ranges being sorted, so make sure
  2967. * that's the case
  2968. */
  2969. std::sort (asi32.m_vAvailableSnapins.begin(), asi32.m_vAvailableSnapins.end(), CompareBasicSnapinInfo);
  2970. std::sort (asi64.m_vAvailableSnapins.begin(), asi64.m_vAvailableSnapins.end(), CompareBasicSnapinInfo);
  2971. /*
  2972. * Case 3a: If the set of available 64-bit snap-ins is a
  2973. * superset of the set of available 32-bit snap-ins, run MMC64
  2974. */
  2975. if (std::includes (asi64.m_vAvailableSnapins.begin(), asi64.m_vAvailableSnapins.end(),
  2976. asi32.m_vAvailableSnapins.begin(), asi32.m_vAvailableSnapins.end(),
  2977. CompareBasicSnapinInfo))
  2978. {
  2979. Trace (tag32BitTransfer, _T("The set of available 64-bit snapins is a superset of..."));
  2980. Trace (tag32BitTransfer, _T("...the set of available 32-bit snapins, 64-bit MMC needed"));
  2981. return (sc);
  2982. }
  2983. /*
  2984. * Case 3b: If the set of available 32-bit snap-ins is a
  2985. * superset of the set of available 64-bit snap-ins, run MMC32
  2986. */
  2987. if (std::includes (asi32.m_vAvailableSnapins.begin(), asi32.m_vAvailableSnapins.end(),
  2988. asi64.m_vAvailableSnapins.begin(), asi64.m_vAvailableSnapins.end(),
  2989. CompareBasicSnapinInfo))
  2990. {
  2991. Trace (tag32BitTransfer, _T("The set of available 32-bit snapins is a superset of..."));
  2992. Trace (tag32BitTransfer, _T("...the set of available 64-bit snapins, 32-bit MMC needed"));
  2993. eArch = eArch_32bit;
  2994. return (sc);
  2995. }
  2996. /*
  2997. * Case 3c: Ask the user which to run
  2998. */
  2999. CArchitecturePicker dlg (rCmdInfo.m_strFileName, asi64, asi32);
  3000. if (dlg.DoModal() == IDOK)
  3001. {
  3002. eArch = dlg.GetArchitecture();
  3003. Trace (tag32BitTransfer, _T("User chose %d-bit, %d-bit MMC needed"), (eArch == eArch_32bit) ? 32 : 64, (eArch == eArch_32bit) ? 32 : 64);
  3004. }
  3005. else
  3006. {
  3007. Trace (tag32BitTransfer, _T("User chose to exit, terminating"));
  3008. eArch = eArch_None;
  3009. }
  3010. return (sc);
  3011. }
  3012. #endif // MMC_WIN64
  3013. #ifdef UNICODE
  3014. /*+-------------------------------------------------------------------------*
  3015. * ScLaunchMMC
  3016. *
  3017. * Launches a specific architecture of MMC (i.e. MMC32 from MMC64 or vice
  3018. * versa) with the same command line used to launch this process.
  3019. *
  3020. * Returns S_OK if the given architecture of MMC was launched successfully,
  3021. * or an error code if an error occurred.
  3022. *--------------------------------------------------------------------------*/
  3023. SC ScLaunchMMC (
  3024. eArchitecture eArch, /* I:desired architecture */
  3025. int nCmdShow) /* I:show state */
  3026. {
  3027. DECLARE_SC (sc, _T("ScLaunchMMC"));
  3028. CString strArgs;
  3029. int nFolder;
  3030. switch (eArch)
  3031. {
  3032. case eArch_64bit:
  3033. nFolder = CSIDL_SYSTEM;
  3034. break;
  3035. case eArch_32bit:
  3036. /*
  3037. * make sure we give MMC32 a "-32" argument so it won't defer
  3038. * to MMC64 again (see CAMCApp::InitInstance)
  3039. */
  3040. strArgs = _T("-32 ");
  3041. nFolder = CSIDL_SYSTEMX86;
  3042. break;
  3043. default:
  3044. return (sc = E_INVALIDARG);
  3045. break;
  3046. }
  3047. /*
  3048. * Get the directory where MMC32 lives (%SystemRoot%\syswow64) and
  3049. * append the executable name
  3050. */
  3051. CString strProgram;
  3052. sc = SHGetFolderPath (NULL, nFolder, NULL, 0, strProgram.GetBuffer(MAX_PATH));
  3053. if (sc)
  3054. return (sc);
  3055. strProgram.ReleaseBuffer();
  3056. strProgram += _T("\\mmc.exe");
  3057. /*
  3058. * disable file system redirection so MMC32 will be able to launch MMC64
  3059. */
  3060. CWow64FilesystemRedirectionDisabler disabler (strProgram);
  3061. /*
  3062. * get the arguments for the original invocation of MMC, skipping
  3063. * argv[0] (the executable name) and any "-32" or "-64" parameters
  3064. */
  3065. int argc;
  3066. CAutoGlobalPtr<LPWSTR> argv (CommandLineToArgvW (GetCommandLine(), &argc));
  3067. if (argv == NULL)
  3068. return (sc.FromLastError());
  3069. for (int i = 1; i < argc; i++)
  3070. {
  3071. CString strArg = argv[i];
  3072. if ((strArg != _T("-32")) && (strArg != _T("/32")) &&
  3073. (strArg != _T("-64")) && (strArg != _T("/64")))
  3074. {
  3075. strArgs += _T("\"") + strArg + _T("\" ");
  3076. }
  3077. }
  3078. /*
  3079. * start the requested architecture of MMC
  3080. */
  3081. Trace (tag32BitTransfer, _T("Attempting to run: %s %s"), (LPCTSTR) strProgram, (LPCTSTR) strArgs);
  3082. SHELLEXECUTEINFO sei = {0};
  3083. sei.cbSize = sizeof (sei);
  3084. sei.fMask = SEE_MASK_FLAG_NO_UI;
  3085. sei.lpFile = strProgram;
  3086. sei.lpParameters = strArgs;
  3087. sei.nShow = nCmdShow;
  3088. if (!ShellExecuteEx (&sei))
  3089. return (sc.FromLastError());
  3090. return (sc);
  3091. }
  3092. #endif // UNICODE
  3093. #ifndef MMC_WIN64
  3094. /*+-------------------------------------------------------------------------*
  3095. * IsWin64
  3096. *
  3097. * Returns true if we're running on Win64, false otherwise.
  3098. *--------------------------------------------------------------------------*/
  3099. bool IsWin64()
  3100. {
  3101. #ifdef UNICODE
  3102. /*
  3103. * get a pointer to kernel32!GetSystemWow64Directory
  3104. */
  3105. HMODULE hmod = GetModuleHandle (_T("kernel32.dll"));
  3106. if (hmod == NULL)
  3107. return (false);
  3108. UINT (WINAPI* pfnGetSystemWow64Directory)(LPTSTR, UINT);
  3109. (FARPROC&)pfnGetSystemWow64Directory = GetProcAddress (hmod, "GetSystemWow64DirectoryW");
  3110. if (pfnGetSystemWow64Directory == NULL)
  3111. return (false);
  3112. /*
  3113. * if GetSystemWow64Directory fails and sets the last error to
  3114. * ERROR_CALL_NOT_IMPLEMENTED, we're on a 32-bit OS
  3115. */
  3116. TCHAR szWow64Dir[MAX_PATH];
  3117. if (((pfnGetSystemWow64Directory)(szWow64Dir, countof(szWow64Dir)) == 0) &&
  3118. (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED))
  3119. {
  3120. return (false);
  3121. }
  3122. /*
  3123. * if we get here, we're on Win64
  3124. */
  3125. return (true);
  3126. #else
  3127. /*
  3128. * non-Unicode platforms cannot be Win64
  3129. */
  3130. return (false);
  3131. #endif // UNICODE
  3132. }
  3133. #endif // !MMC_WIN64