//+------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1999 // // File: amc.cpp // // Contents: The one and only app // // History: 01-Jan-96 TRomano Created // 16-Jul-96 WayneSc Add code to switch views // //-------------------------------------------------------------------------- #include "stdafx.h" #include "AMC.h" #include "MainFrm.h" #include "ChildFrm.h" #include "AMCDoc.h" #include "AMCView.h" #include "amcdocmg.h" #include "sysmenu.h" #include #include "strings.h" #include "macros.h" #include "scripthost.h" #include "HtmlHelp.h" #include "scriptevents.h" #include "mmcutil.h" #include "guidhelp.h" // for CLSID relational operators #include "archpicker.h" #include "classreg.h" #define DECLSPEC_UUID(x) __declspec(uuid(x)) #include "websnk.h" #include "websnk_i.c" // We aren't picking this up from winuser.h for some reason. #define ISOLATIONAWARE_NOSTATICIMPORT_MANIFEST_RESOURCE_ID MAKEINTRESOURCE(3) /* * define our own Win64 symbol to make it easy to include 64-bit only * code in the 32-bit build, so we can exercise some code on 32-bit Windows * where the debuggers are better */ #ifdef _WIN64 #define MMC_WIN64 #endif #ifndef MMC_WIN64 #include // for Wow64DisableFilesystemRedirector #endif /* * multimon.h is included by stdafx.h, without defining COMPILE_MULTIMON_STUBS * first. We need to include it again here after defining COMPILE_MULTIMON_STUBS * so we'll get the stub functions. */ #if (_WIN32_WINNT < 0x0500) #define COMPILE_MULTIMON_STUBS #include #endif #ifdef DBG CTraceTag tagEnableScriptEngines(_T("MMCScriptEngines"), _T("Enable")); CTraceTag tag32BitTransfer(_T("64/32-bit interop"), _T("64/32-bit interop")); #endif // Note: These strings do not need to be localizable. const TCHAR CAMCApp::m_szSettingsSection[] = _T("Settings"); const TCHAR CAMCApp::m_szUserDirectoryEntry[] = _T("Save Location"); bool CanCloseDoc(void); SC ScExpandEnvironmentStrings (CString& str); //############################################################################ //############################################################################ // // ATL Support // //############################################################################ //############################################################################ #include #include // The one and only instance of CAtlGlobalModule CAtlGlobalModule _Module; //############################################################################ //############################################################################ // // Trace Tags // //############################################################################ //############################################################################ #ifdef DBG // enable this tag if you suspect memory corruption // and you don't mind things slowing way down BEGIN_TRACETAG(CDebugCRTCheck) void OnEnable() { _CrtSetDbgFlag (_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_CHECK_ALWAYS_DF | _CRTDBG_DELAY_FREE_MEM_DF); } void OnDisable() { _CrtSetDbgFlag (_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) & ~(_CRTDBG_CHECK_ALWAYS_DF | _CRTDBG_DELAY_FREE_MEM_DF) ); } END_TRACETAG(CDebugCRTCheck, TEXT("Debug CRTs"), TEXT("Memory Check - SLOW!")) CTraceTag tagAMCAppInit(TEXT("CAMCView"), TEXT("InitInstance")); CTraceTag tagATLLock(TEXT("ATL"), TEXT("Lock/Unlock")); // used by atlconui.h CTraceTag tagGDIBatching(TEXT("CAMCView"), TEXT("Disable Graphics/GDI Batching")); CTraceTag tagForceMirror(TEXT("Mirroring"), TEXT("Force MMC windows to be mirrored on non-mirrored systems")); #endif //############################################################################ //############################################################################ // // Implementation of class CMMCApplication - the root level // automation class // //############################################################################ //############################################################################ class CMMCApplication : public CMMCIDispatchImpl<_Application, &CLSID_Application>, public CComCoClass, // support for connection points (script events) public IConnectionPointContainerImpl, public IConnectionPointImpl, public IProvideClassInfo2Impl<&CLSID_Application, &DIID_AppEvents, &LIBID_MMC20> { public: BEGIN_MMC_COM_MAP(CMMCApplication) COM_INTERFACE_ENTRY(IProvideClassInfo) COM_INTERFACE_ENTRY(IProvideClassInfo2) COM_INTERFACE_ENTRY(IConnectionPointContainer) END_MMC_COM_MAP() DECLARE_NOT_AGGREGATABLE(CMMCApplication) static HRESULT WINAPI UpdateRegistry(BOOL bRegister) { CObjectRegParams op ( CLSID_Application, _T("mmc.exe"), _T("MMC Application Class"), _T("MMC20.Application.1"), _T("MMC20.Application"), _T("LocalServer32") ); return (MMCUpdateRegistry (bRegister, &op, NULL)); } //hooks into ATL's construction HRESULT InternalFinalConstructRelease(); // not FinalConstruct() - this is to work around a bogus ATL assert. BEGIN_CONNECTION_POINT_MAP(CMMCApplication) CONNECTION_POINT_ENTRY(DIID_AppEvents) END_CONNECTION_POINT_MAP() // overriden to do more job than the base class does virtual ::SC ScOnDisconnectObjects(); private: //IMMCApplication public: void STDMETHODCALLTYPE Help(); void STDMETHODCALLTYPE Quit(); STDMETHOD(get_Document) (Document **ppDocument); STDMETHOD(Load) (BSTR bstrFilename); STDMETHOD(get_Frame) (Frame **ppFrame); STDMETHOD(get_Visible) (BOOL *pVisible); STDMETHOD(Show) (); STDMETHOD(Hide) (); STDMETHOD(get_UserControl) (PBOOL pUserControl); STDMETHOD(put_UserControl) (BOOL bUserControl); STDMETHOD(get_VersionMajor) (PLONG pVersionMajor); STDMETHOD(get_VersionMinor) (PLONG pVersionMinor); private: // Return the CAMCApp only if it is initialized. We do not want // object model methods to operate on app while initializing. CAMCApp *GetApp() { CAMCApp *pApp = AMCGetApp(); if ( (! pApp) || (pApp->IsInitializing()) ) return NULL; return pApp; } }; //############################################################################ //############################################################################ // // Event map for application events // //############################################################################ //############################################################################ DISPATCH_CALL_MAP_BEGIN(AppEvents) DISPATCH_CALL1( OnQuit, PAPPLICATION ) DISPATCH_CALL2( OnDocumentOpen, PDOCUMENT, BOOL) DISPATCH_CALL1( OnDocumentClose, PDOCUMENT ) DISPATCH_CALL2( OnSnapInAdded, PDOCUMENT, PSNAPIN ) DISPATCH_CALL2( OnSnapInRemoved, PDOCUMENT, PSNAPIN ) DISPATCH_CALL1( OnNewView, PVIEW ) DISPATCH_CALL1( OnViewClose, PVIEW ) DISPATCH_CALL2( OnViewChange, PVIEW, PNODE ); DISPATCH_CALL2( OnSelectionChange, PVIEW, PNODES ) DISPATCH_CALL1( OnContextMenuExecuted, PMENUITEM ); DISPATCH_CALL0( OnToolbarButtonClicked ) DISPATCH_CALL1( OnListUpdated, PVIEW ) DISPATCH_CALL_MAP_END() /*+-------------------------------------------------------------------------* * * CMMCApplication::InternalFinalConstructRelease * * PURPOSE: Hands the CAMCApp a pointer to the 'this' object. * *+-------------------------------------------------------------------------*/ HRESULT CMMCApplication::InternalFinalConstructRelease() { DECLARE_SC(sc, TEXT("CMMCApplication::InternalFinalConstructRelease")); // Dont use GetApp, we need to get CAMCApp even if it is not fully initialized. CAMCApp *pApp = AMCGetApp(); sc = ScCheckPointers(pApp); if(sc) return sc.ToHr(); // some wierd error. sc = pApp->ScRegister_Application(this); return sc.ToHr(); } /*+-------------------------------------------------------------------------* * * CMMCApplication::GetFrame * * PURPOSE: A static function that hooks into the COM interface entry list * and allows a tear-off object to be created that implements the * Frame interface. * * PARAMETERS: * void* pv : Defined by ATL to hold a pointer to the CMMCApplication object * because this is a static method. * REFIID riid : As per QI * LPVOID* ppv : As per QI * DWORD dw : ignored * * RETURNS: * HRESULT WINAPI * *+-------------------------------------------------------------------------*/ STDMETHODIMP CMMCApplication::get_Frame(Frame **ppFrame) { DECLARE_SC(sc, TEXT("CMMCApplication::get_Frame")); if(!ppFrame) { sc = E_POINTER; return sc.ToHr(); } // get the app CAMCApp *pApp = GetApp(); if(NULL == pApp) { sc = E_UNEXPECTED; return sc.ToHr(); } CMainFrame *pMainFrame = pApp->GetMainFrame(); if(!pMainFrame) { sc = E_UNEXPECTED; return sc.ToHr(); } sc = pMainFrame->ScGetFrame(ppFrame); return sc.ToHr(); } STDMETHODIMP CMMCApplication::get_Document(Document **ppDocument) { DECLARE_SC(sc, TEXT("CMMCApplication::get_Document")); CAMCDoc* const pDoc = CAMCDoc::GetDocument(); ASSERT(ppDocument != NULL); if(ppDocument == NULL || (pDoc == NULL)) { sc = E_POINTER; return sc.ToHr(); } sc = pDoc->ScGetMMCDocument(ppDocument); if(sc) return sc.ToHr(); return sc.ToHr(); } /***************************************************************************\ * * METHOD: CMMCApplication::Load * * PURPOSE: implements Application.Load for object model * * PARAMETERS: * BSTR bstrFilename - console file to load * * RETURNS: * SC - result code * \***************************************************************************/ STDMETHODIMP CMMCApplication::Load(BSTR bstrFilename) { DECLARE_SC(sc, TEXT("CMMCApplication::Load")); CAMCApp *pApp = GetApp(); sc = ScCheckPointers(pApp, E_UNEXPECTED); if (sc) return sc.ToHr(); USES_CONVERSION; pApp->OpenDocumentFile(OLE2CT(bstrFilename)); return sc.ToHr(); } void STDMETHODCALLTYPE CMMCApplication::Help() { DECLARE_SC(sc, TEXT("CMMCApplication::Help")); CAMCApp *pApp = GetApp(); if(NULL == pApp) { sc = E_UNEXPECTED; return; } sc = pApp->ScHelp(); if(sc) return; return; } void STDMETHODCALLTYPE CMMCApplication::Quit() { SC sc; CAMCApp *pApp = GetApp(); if(NULL == pApp) goto Error; // confiscate the control from user pApp->SetUnderUserControl(false); // get mainframe { CMainFrame * pMainFrame = pApp->GetMainFrame(); if(NULL == pMainFrame) goto Error; // close it gracefully. pMainFrame->PostMessage(WM_CLOSE); } Cleanup: return; Error: sc = E_UNEXPECTED; TraceError(TEXT("CMMCApplication::Quit"), sc); goto Cleanup; } /*+-------------------------------------------------------------------------* * * CMMCApplication::get_VersionMajor * * PURPOSE: Returns the major version number for the installed version of MMC. * * PARAMETERS: * PLONG pVersionMajor : * * RETURNS: * HRESULT * *+-------------------------------------------------------------------------*/ HRESULT CMMCApplication::get_VersionMajor(PLONG pVersionMajor) { DECLARE_SC(sc, TEXT("CMMCApplication::get_VersionMajor")); sc = ScCheckPointers(pVersionMajor); if(sc) return sc.ToHr(); *pVersionMajor = MMC_VERSION_MAJOR; return sc.ToHr(); } /*+-------------------------------------------------------------------------* * * CMMCApplication::get_VersionMinor * * PURPOSE: Returns the minor version number for the installed version of MMC. * * PARAMETERS: * PLONG pVersionMinor : * * RETURNS: * HRESULT * *+-------------------------------------------------------------------------*/ HRESULT CMMCApplication::get_VersionMinor(PLONG pVersionMinor) { DECLARE_SC(sc, TEXT("CMMCApplication::get_VersionMinor")); sc = ScCheckPointers(pVersionMinor); if(sc) return sc.ToHr(); *pVersionMinor = MMC_VERSION_MINOR; return sc.ToHr(); } //+------------------------------------------------------------------- // // Member: CMMCApplication::get_Visible // // Synopsis: Returns the visible property // // Arguments: [PBOOL] - out bool // // Returns: HRESULT // //-------------------------------------------------------------------- HRESULT CMMCApplication::get_Visible (PBOOL pbVisible) { DECLARE_SC(sc, _T("CMMCApplication::get_Visible")); sc = ScCheckPointers(pbVisible); if (sc) return sc.ToHr(); // get the app CAMCApp *pApp = GetApp(); sc = ScCheckPointers(pApp, E_UNEXPECTED); if (sc) return (sc.ToHr()); CMainFrame *pMainFrame = pApp->GetMainFrame(); sc = ScCheckPointers(pMainFrame, E_UNEXPECTED); if (sc) return (sc.ToHr()); *pbVisible = pMainFrame->IsWindowVisible(); return (sc.ToHr()); } //+------------------------------------------------------------------- // // Member: CMMCApplication::Show // // Synopsis: Shows the application // // Arguments: None // // Returns: HRESULT // //-------------------------------------------------------------------- HRESULT CMMCApplication::Show () { DECLARE_SC(sc, _T("CMMCApplication::Show")); // get the app CAMCApp *pApp = GetApp(); sc = ScCheckPointers(pApp, E_UNEXPECTED); if (sc) return (sc.ToHr()); CMainFrame *pMainFrame = pApp->GetMainFrame(); sc = ScCheckPointers(pMainFrame, E_UNEXPECTED); if (sc) return (sc.ToHr()); sc = pMainFrame->ShowWindow(SW_SHOW); return (sc.ToHr()); } //+------------------------------------------------------------------- // // Member: CMMCApplication::Hide // // Synopsis: Hides the application. // // Arguments: None // // Returns: HRESULT // // Note: If the user is under control (UserControl property is set) // then Hide fails. // //-------------------------------------------------------------------- HRESULT CMMCApplication::Hide () { DECLARE_SC(sc, _T("CMMCApplication::Hide")); // get the app CAMCApp *pApp = GetApp(); sc = ScCheckPointers(pApp, E_UNEXPECTED); if (sc) return (sc.ToHr()); // Cant hide if app is under user control. if (pApp->IsUnderUserControl()) { sc = E_FAIL; return sc.ToHr(); } CMainFrame *pMainFrame = pApp->GetMainFrame(); sc = ScCheckPointers(pMainFrame, E_UNEXPECTED); if (sc) return (sc.ToHr()); sc = pMainFrame->ShowWindow(SW_HIDE); return (sc.ToHr()); } //+------------------------------------------------------------------- // // Member: CMMCApplication::get_UserControl // // Synopsis: Returns the UserControl property // // Arguments: PBOOL - out param. // // Returns: HRESULT // //-------------------------------------------------------------------- HRESULT CMMCApplication::get_UserControl (PBOOL pbUserControl) { DECLARE_SC(sc, _T("CMMCApplication::get_UserControl")); sc = ScCheckPointers(pbUserControl); if (sc) return (sc.ToHr()); // get the app CAMCApp *pApp = GetApp(); sc = ScCheckPointers(pApp, E_UNEXPECTED); if (sc) return (sc.ToHr()); *pbUserControl = pApp->IsUnderUserControl(); return (sc.ToHr()); } //+------------------------------------------------------------------- // // Member: CMMCApplication::put_UserControl // // Synopsis: Sets the UserControl property // // Arguments: BOOL // // Returns: HRESULT // //-------------------------------------------------------------------- HRESULT CMMCApplication::put_UserControl (BOOL bUserControl) { DECLARE_SC(sc, _T("CMMCApplication::put_UserControl")); // get the app CAMCApp *pApp = GetApp(); sc = ScCheckPointers(pApp, E_UNEXPECTED); if (sc) return (sc.ToHr()); pApp->SetUnderUserControl(bUserControl); return (sc.ToHr()); } /***************************************************************************\ * * METHOD: CMMCApplication::ScOnDisconnectObjects * * PURPOSE: special disconnect implementation. For this object implementation * provided by the base class is not enough, since connection point * is an internal object which may also have strong references on it * * PARAMETERS: * * RETURNS: * SC - result code * \***************************************************************************/ SC CMMCApplication::ScOnDisconnectObjects() { DECLARE_SC(sc, TEXT("CMMCApplication::ScOnDisconnectObjects")); // get the connection point container IConnectionPointContainerPtr spContainer(GetUnknown()); sc = ScCheckPointers( spContainer, E_UNEXPECTED ); if (sc) return sc; // get the connection point IConnectionPointPtr spConnectionPoint; sc = spContainer->FindConnectionPoint( DIID_AppEvents, &spConnectionPoint ); if (sc) return sc; // cut connection point references sc = CoDisconnectObject( spConnectionPoint, 0/*dwReserved*/ ); if (sc) return sc; // let the base class do the rest sc = CMMCIDispatchImplClass::ScOnDisconnectObjects(); if (sc) return sc; return sc; } //############################################################################ //############################################################################ // // ATL GLobal Object Map // //############################################################################ //############################################################################ BEGIN_OBJECT_MAP(ObjectMap) OBJECT_ENTRY(CLSID_Application, CMMCApplication) END_OBJECT_MAP() /*+-------------------------------------------------------------------------* * CLockChildWindowUpdate * * Helper class whose constructor turns off redraw for all of the children * of the given window, and whose destructor turns redraw back on for all * of the windows for which it was turned off. * * This is used to prevent ugly transient drawing while opening console * files that take a long time to completely open (bug 150356). *--------------------------------------------------------------------------*/ class CLockChildWindowUpdate { public: CLockChildWindowUpdate (CWnd* pwndLock) : m_pwndLock(pwndLock) { if (m_pwndLock != NULL) { CWnd* pwndChild; /* * turn off redraw for each child, saving the HWND for later * so we can turn it back on (we save the HWND instead of the * CWnd* because MFC might have returned a temporary object). */ for (pwndChild = m_pwndLock->GetWindow (GW_CHILD); pwndChild != NULL; pwndChild = pwndChild->GetNextWindow()) { pwndChild->SetRedraw (false); m_vChildren.push_back (pwndChild->GetSafeHwnd()); } } } ~CLockChildWindowUpdate() { std::vector::iterator it; /* * for every window for which we turned off redraw, turn it back on */ for (it = m_vChildren.begin(); it != m_vChildren.end(); ++it) { HWND hWndChild = *it; if ( (hWndChild != NULL) && ::IsWindow(hWndChild) ) { CWnd *pwndChild = CWnd::FromHandle(hWndChild); pwndChild->SetRedraw (true); pwndChild->RedrawWindow (NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN); } } } private: CWnd* const m_pwndLock; std::vector m_vChildren; }; //############################################################################ //############################################################################ // // Implementation of class CAMCMultiDocTemplate // //############################################################################ //############################################################################ class CAMCMultiDocTemplate : public CMultiDocTemplate { public: CAMCMultiDocTemplate(UINT nIDResource, CRuntimeClass* pDocClass, CRuntimeClass* pFrameClass, CRuntimeClass* pViewClass) : CMultiDocTemplate(nIDResource, pDocClass, pFrameClass, pViewClass) { } CDocument* OpenDocumentFile(LPCTSTR lpszPathName, BOOL bMakeVisible) { DECLARE_SC(sc, TEXT("CAMCMultiDocTemplate::OpenDocumentFile")); CAMCDoc* const pDoc = CAMCDoc::GetDocument(); if (pDoc && (!pDoc->SaveModified() || !CanCloseDoc() )) return NULL; // leave the original one CLockChildWindowUpdate lock (AfxGetMainWnd()); CAMCDoc* pDocument = (CAMCDoc*)CreateNewDocument(); if (pDocument == NULL) { TRACE0("CDocTemplate::CreateNewDocument returned NULL.\n"); AfxMessageBox(AFX_IDP_FAILED_TO_CREATE_DOC); // do not change to MMCMessageBox return NULL; } HRESULT hr; if ((hr = pDocument->InitNodeManager()) != S_OK) { TRACE1("CAMCDoc::InitNodeManager failed, 0x%08x\n", hr); CAMCApp* pApp = AMCGetApp(); MMCErrorBox((pApp && pApp->IsWin9xPlatform()) ? IDS_NODEMGR_FAILED_9x : IDS_NODEMGR_FAILED); delete pDocument; // explicit delete on error return NULL; } ASSERT_VALID(pDocument); BOOL bAutoDelete = pDocument->m_bAutoDelete; pDocument->m_bAutoDelete = FALSE; // don't destroy if something goes wrong CFrameWnd* pFrame = CreateNewFrame(pDocument, NULL); pDocument->m_bAutoDelete = bAutoDelete; if (pFrame == NULL) { AfxMessageBox(AFX_IDP_FAILED_TO_CREATE_DOC); // do not change to MMCMessageBox delete pDocument; // explicit delete on error return NULL; } ASSERT_VALID(pFrame); if (lpszPathName == NULL) { // create a new document - with default document name SetDefaultTitle(pDocument); // avoid creating temporary compound file when starting up invisible if (!bMakeVisible) pDocument->m_bEmbedded = TRUE; if (!pDocument->OnNewDocument()) { // user has be alerted to what failed in OnNewDocument TRACE0("CDocument::OnNewDocument returned FALSE.\n"); AfxMessageBox (AFX_IDP_FAILED_TO_CREATE_DOC); // do not change to MMCMessageBox pFrame->DestroyWindow(); return NULL; } // it worked, now bump untitled count m_nUntitledCount++; InitialUpdateFrame(pFrame, pDocument, bMakeVisible); } else { // open an existing document CWaitCursor wait; if (!pDocument->OnOpenDocument(lpszPathName)) { // user has be alerted to what failed in OnOpenDocument TRACE0("CDocument::OnOpenDocument returned FALSE.\n"); pFrame->DestroyWindow(); return NULL; } #ifdef _MAC // if the document is dirty, we must have opened a stationery pad // - don't change the pathname because we want to treat the document // as untitled if (!pDocument->IsModified()) #endif pDocument->SetPathName(lpszPathName); //REVIEW: dburg: InitialUpdateFrame(pFrame, pDocument, bMakeVisible); pFrame->DestroyWindow(); pDocument->SetModifiedFlag (false); pDocument->SetFrameModifiedFlag (false); } // fire script event CAMCApp* pApp = AMCGetApp(); sc = ScCheckPointers(pApp, E_UNEXPECTED); if (sc) return pDocument; sc = pApp->ScOnNewDocument(pDocument, (lpszPathName != NULL)); if (sc) sc.TraceAndClear(); return pDocument; } // this method is overrided to catch application quit event virtual void CloseAllDocuments( BOOL bEndSession ) { DECLARE_SC(sc, TEXT("CAMCMultiDocTemplate::CloseAllDocuments")); // invoke base class to perform required tasks CMultiDocTemplate::CloseAllDocuments( bEndSession ); // no other way we can get here but exit app // so that's a good time for script to know it CAMCApp* pApp = AMCGetApp(); sc = ScCheckPointers(pApp, E_UNEXPECTED); if (sc) return; // forward to application to emit the script event sc = pApp->ScOnQuitApp(); if (sc) sc.TraceAndClear(); // cut off all strong references now. // Quit was executed - nothing else matters sc = GetComObjectEventSource().ScFireEvent( CComObjectObserver::ScOnDisconnectObjects ); if (sc) sc.TraceAndClear(); } }; // Declare debug infolevel for this component DECLARE_INFOLEVEL(AMCConUI); //############################################################################ //############################################################################ // // Implementation of class CAMCApp // //############################################################################ //############################################################################ IMPLEMENT_DYNAMIC(CAMCApp, CWinApp) BEGIN_MESSAGE_MAP(CAMCApp, CWinApp) //{{AFX_MSG_MAP(CAMCApp) ON_COMMAND(ID_APP_ABOUT, OnAppAbout) //}}AFX_MSG_MAP // Standard file based document commands ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew) ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen) // Standard print setup command ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup) ON_COMMAND(ID_FILE_NEW_USER_MODE, OnFileNewInUserMode) // CTRL+N in user mode - do nothing END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CAMCApp construction CAMCApp::CAMCApp() : m_bOleInitialized(FALSE), m_bDefaultDirSet(FALSE), m_eMode(eMode_Error), m_fAuthorModeForced(false), m_fInitializing(true), m_fDelayCloseUntilIdle(false), m_fCloseCameFromMainPump(false), m_nMessagePumpNestingLevel(0), m_fIsWin9xPlatform(false), m_dwHelpCookie(0), m_bHelpInitialized(false), m_fUnderUserControl(true), m_fRunningAsOLEServer(false) { } ///////////////////////////////////////////////////////////////////////////// // The one and only CAMCApp object CAMCApp theApp; const CRect g_rectEmpty (0, 0, 0, 0); void DeleteDDEKeys() { HKEY key; if (ERROR_SUCCESS == RegOpenKeyEx (HKEY_CLASSES_ROOT, _T("MSCFile\\shell\\open"), 0, KEY_SET_VALUE, &key)) { theApp.DelRegTree (key, _T("ddeexec")); RegCloseKey (key); } } /*+-------------------------------------------------------------------------* * * CAMCApp::GetMainFrame * * PURPOSE: Returns a pointer to the main frame. * * RETURNS: * CMainFrame * * *+-------------------------------------------------------------------------*/ CMainFrame * CAMCApp::GetMainFrame() { return dynamic_cast(m_pMainWnd); } /*+-------------------------------------------------------------------------* * * CAMCApp::ScGet_Application * * PURPOSE: Returns a pointer to an _Application object. * * PARAMETERS: * _Application ** pp_Application : * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCApp::ScGet_Application(_Application **pp_Application) { DECLARE_SC(sc, TEXT("CAMCApp::ScGet_Application")); // parameter check sc = ScCheckPointers(pp_Application); if (sc) return sc; // init out param *pp_Application = NULL; // see if we have a chached one if (m_sp_Application != NULL) { *pp_Application = m_sp_Application; (*pp_Application)->AddRef(); // addref for the client. return sc; } // create an _Application object. This is needed if MMC was instantiated // by a user, not COM. sc = CMMCApplication::CreateInstance(pp_Application); if(sc) return sc; // The constructor of the CMMCApplication calls ScRegister_Application // which sets the m_sp_Application pointer. Do not set this pointer here. sc = ScCheckPointers(*pp_Application, E_UNEXPECTED); if (sc) return sc; // done return sc; } /*+-------------------------------------------------------------------------* * * CAMCApp::ScRegister_Application * * PURPOSE: called by a CMMCApplication object to enable the CAMCApp to store * a pointer to it. * * PARAMETERS: * _Application * p_Application : * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCApp::ScRegister_Application(_Application *p_Application) { DECLARE_SC(sc, TEXT("CAMCApp::ScRegister_Application")); ASSERT(m_sp_Application == NULL); // only one _Application object should ever register. sc = ScCheckPointers(p_Application); if(sc) return sc; m_sp_Application = p_Application; return sc; } //+------------------------------------------------------------------- // // Member: RegisterShellFileTypes // // Synopsis: Register the file associations. // // Note: Also set all other relevant registry keys like // Open, Author, RunAs. Eventhough the setup has // done this it may have been deleted mistakenly. // // History: // [AnandhaG] - Added the registry repair. // Returns: None. // //-------------------------------------------------------------------- void CAMCApp::RegisterShellFileTypes(BOOL bCompat) { CWinApp::RegisterShellFileTypes (bCompat); do { // Create the top level MSCFile key. CRegKey regKey; LONG lRet = regKey.Create(HKEY_CLASSES_ROOT, _T("MSCFile"), REG_NONE, REG_OPTION_NON_VOLATILE, KEY_WRITE); if (ERROR_SUCCESS != lRet) break; /* * for platforms that support it (i.e. not Win9x), set the MUI-friendly * value for the MSCFile document type */ if (!IsWin9xPlatform()) { CString strMUIValue; strMUIValue.Format (_T("@%%SystemRoot%%\\system32\\mmcbase.dll,-%d"), IDR_MUIFRIENDLYNAME); lRet = RegSetValueEx (regKey, _T("FriendlyTypeName"), NULL, REG_EXPAND_SZ, (CONST BYTE *)(LPCTSTR) strMUIValue, sizeof(TCHAR) * (strMUIValue.GetLength()+1) ); if (ERROR_SUCCESS != lRet) break; } // Set the EditFlags value. lRet = regKey.SetValue(0x100000, _T("EditFlags")); if (ERROR_SUCCESS != lRet) break; // Create the Author verb. lRet = regKey.Create(HKEY_CLASSES_ROOT, _T("MSCFile\\shell\\Author"), REG_NONE, REG_OPTION_NON_VOLATILE, KEY_WRITE); if (ERROR_SUCCESS != lRet) break; // And set default value for author (this reflects in shell menu). CString strRegVal; LoadString(strRegVal, IDS_MENUAUTHOR); lRet = RegSetValueEx ((HKEY)regKey, (LPCTSTR)NULL, NULL, REG_SZ, (CONST BYTE *)(LPCTSTR)strRegVal, sizeof(TCHAR) * (strRegVal.GetLength()+1) ); if (ERROR_SUCCESS != lRet) break; /* * for platforms that support it (i.e. not Win9x), set the MUI-friendly * value for the menu item */ if (!IsWin9xPlatform()) { CString strMUIValue; strMUIValue.Format (_T("@%%SystemRoot%%\\system32\\mmcbase.dll,-%d"), IDS_MENUAUTHOR); lRet = RegSetValueEx (regKey, _T("MUIVerb"), NULL, REG_EXPAND_SZ, (CONST BYTE *)(LPCTSTR) strMUIValue, sizeof(TCHAR) * (strMUIValue.GetLength()+1) ); if (ERROR_SUCCESS != lRet) break; } // Create the Author command. lRet = regKey.Create(HKEY_CLASSES_ROOT, _T("MSCFile\\shell\\Author\\command"), REG_NONE, REG_OPTION_NON_VOLATILE, KEY_WRITE); if (ERROR_SUCCESS != lRet) break; ////////////////////////////////////////////////////////////// // Win95 does not support REG_EXPAND_SZ for default values. // // So we set expand strings and set registry strings as // // REG_SZ for Win9x. // // The following declarations are for Win9x platform. // ////////////////////////////////////////////////////////////// TCHAR szRegValue[2 * MAX_PATH]; TCHAR szWinDir[MAX_PATH]; if (0 == ExpandEnvironmentStrings(_T("%WinDir%"), szWinDir, MAX_PATH) ) break; DWORD dwCount = 0; LPTSTR lpszRegValue = NULL; // Set the default value for Author command. if (IsWin9xPlatform() == false) { lpszRegValue = _T("%SystemRoot%\\system32\\mmc.exe /a \"%1\" %*"); dwCount = sizeof(TCHAR) * (1 + _tcslen(lpszRegValue)); lRet = RegSetValueEx ((HKEY)regKey, (LPCTSTR)NULL, NULL, REG_EXPAND_SZ, (CONST BYTE *)lpszRegValue, dwCount); } else // Win9x platform { lpszRegValue = _T("\\mmc.exe /a \"%1\" %2 %3 %4 %5 %6 %7 %8 %9"); _tcscpy(szRegValue, szWinDir); _tcscat(szRegValue, lpszRegValue); dwCount = sizeof(TCHAR) * (1 + _tcslen(szRegValue)); lRet = RegSetValueEx ((HKEY)regKey, (LPCTSTR)NULL, NULL, REG_SZ, (CONST BYTE *)szRegValue, dwCount); } if (ERROR_SUCCESS != lRet) break; // Create the Open verb. lRet = regKey.Create(HKEY_CLASSES_ROOT, _T("MSCFile\\shell\\Open"), REG_NONE, REG_OPTION_NON_VOLATILE, KEY_WRITE); if (ERROR_SUCCESS != lRet) break; // Set default value for Open. LoadString(strRegVal, IDS_MENUOPEN); lRet = RegSetValueEx ((HKEY)regKey, (LPCTSTR)NULL, NULL, REG_SZ, (CONST BYTE *)(LPCTSTR)strRegVal,sizeof(TCHAR) * (strRegVal.GetLength()+1) ); if (ERROR_SUCCESS != lRet) break; /* * for platforms that support it (i.e. not Win9x), set the MUI-friendly * value for the menu item */ if (!IsWin9xPlatform()) { CString strMUIValue; strMUIValue.Format (_T("@%%SystemRoot%%\\system32\\mmcbase.dll,-%d"), IDS_MENUOPEN); lRet = RegSetValueEx (regKey, _T("MUIVerb"), NULL, REG_EXPAND_SZ, (CONST BYTE *)(LPCTSTR) strMUIValue, sizeof(TCHAR) * (strMUIValue.GetLength()+1) ); if (ERROR_SUCCESS != lRet) break; } // Create the Open command. lRet = regKey.Create(HKEY_CLASSES_ROOT, _T("MSCFile\\shell\\Open\\command"), REG_NONE, REG_OPTION_NON_VOLATILE, KEY_WRITE); if (ERROR_SUCCESS != lRet) break; // Set the default value for Open command. if (IsWin9xPlatform() == false) { lpszRegValue = _T("%SystemRoot%\\system32\\mmc.exe \"%1\" %*"); dwCount = sizeof(TCHAR) * (1 + _tcslen(lpszRegValue)); lRet = RegSetValueEx ((HKEY)regKey, (LPCTSTR)NULL, NULL, REG_EXPAND_SZ, (CONST BYTE *)lpszRegValue, dwCount); } else // Win9x platform { lpszRegValue = _T("\\mmc.exe \"%1\" %2 %3 %4 %5 %6 %7 %8 %9"); _tcscpy(szRegValue, szWinDir); _tcscat(szRegValue, lpszRegValue); dwCount = sizeof(TCHAR) * (1 + _tcslen(szRegValue)); lRet = RegSetValueEx ((HKEY)regKey, (LPCTSTR)NULL, NULL, REG_SZ, (CONST BYTE *)szRegValue, dwCount); } if (ERROR_SUCCESS != lRet) break; // Create the RunAs verb (only on NT). if (IsWin9xPlatform() == false) { lRet = regKey.Create(HKEY_CLASSES_ROOT, _T("MSCFile\\shell\\RunAs"), REG_NONE, REG_OPTION_NON_VOLATILE, KEY_WRITE); if (ERROR_SUCCESS != lRet) break; // Set default value for RunAs verb. LoadString(strRegVal, IDS_MENURUNAS); lRet = RegSetValueEx ((HKEY)regKey, (LPCTSTR)NULL, NULL, REG_SZ, (CONST BYTE *)(LPCTSTR)strRegVal,sizeof(TCHAR) * (strRegVal.GetLength()+1) ); if (ERROR_SUCCESS != lRet) break; /* * for platforms that support it (i.e. not Win9x), set the MUI-friendly * value for the menu item */ if (!IsWin9xPlatform()) { CString strMUIValue; strMUIValue.Format (_T("@%%SystemRoot%%\\system32\\mmcbase.dll,-%d"), IDS_MENURUNAS); lRet = RegSetValueEx (regKey, _T("MUIVerb"), NULL, REG_EXPAND_SZ, (CONST BYTE *)(LPCTSTR) strMUIValue, sizeof(TCHAR) * (strMUIValue.GetLength()+1) ); if (ERROR_SUCCESS != lRet) break; } // Create the RunAs command. lRet = regKey.Create(HKEY_CLASSES_ROOT, _T("MSCFile\\shell\\RunAs\\command"), REG_NONE, REG_OPTION_NON_VOLATILE, KEY_WRITE); if (ERROR_SUCCESS != lRet) break; // Set the default value for RunAs command. (Only on NT Unicode) lpszRegValue = _T("%SystemRoot%\\system32\\mmc.exe \"%1\" %*"); dwCount = sizeof(TCHAR) * (1 + _tcslen(lpszRegValue)); lRet = RegSetValueEx ((HKEY)regKey, (LPCTSTR)NULL, NULL, REG_EXPAND_SZ, (CONST BYTE *)lpszRegValue, dwCount); } if (ERROR_SUCCESS != lRet) break; } while ( FALSE ); return; } ///////////////////////////////////////////////////////////////////////////// // CAMCApp initialization #ifdef UNICODE SC ScLaunchMMC (eArchitecture eArch, int nCmdShow); #endif #ifdef MMC_WIN64 class CMMCCommandLineInfo; SC ScDetermineArchitecture (const CMMCCommandLineInfo& rCmdInfo, eArchitecture& eArch); #else bool IsWin64(); #endif // MMC_WIN64 class CMMCCommandLineInfo : public CCommandLineInfo { public: eArchitecture m_eArch; bool m_fForceAuthorMode; bool m_fRegisterServer; CString m_strDumpFilename; public: CMMCCommandLineInfo() : m_eArch (eArch_Any), m_fForceAuthorMode(false), m_fRegisterServer(false) {} virtual void ParseParam (LPCTSTR pszParam, BOOL bFlag, BOOL bLast) { bool fHandledHere = false; if (bFlag) { /* * ignore the following parameters: * -dde (await DDE command), -s (splash screen, obsolete). */ if ((lstrcmpi (pszParam, _T("s")) == 0) || (lstrcmpi (pszParam, _T("dde")) == 0)) { fHandledHere = true; } // force author mode else if (lstrcmpi (pszParam, _T("a")) == 0) { m_fForceAuthorMode = true; fHandledHere = true; } // register the server only else if (lstrcmpi (pszParam, _T("RegServer")) == 0) { m_fRegisterServer = true; fHandledHere = true; } // force 64-bit MMC to run else if (lstrcmp (pszParam, _T("64")) == 0) { m_eArch = eArch_64bit; fHandledHere = true; } // force 32-bit MMC to run else if (lstrcmp (pszParam, _T("32")) == 0) { m_eArch = eArch_32bit; fHandledHere = true; } else { static const TCHAR szDumpParam[] = _T("dump:"); const int cchDumpParam = countof (szDumpParam); TCHAR szParam[cchDumpParam]; lstrcpyn (szParam, pszParam, cchDumpParam); szParam[cchDumpParam-1] = _T('\0'); // dump console file contents if (lstrcmpi (szParam, szDumpParam) == 0) { m_strDumpFilename = pszParam + cchDumpParam - 1; fHandledHere = true; } } } // if not handled, pass it on to base class // if just handled last parameter, call base class ParseLast // so it can do the final processing if (!fHandledHere) CCommandLineInfo::ParseParam (pszParam, bFlag, bLast); else if (bLast) CCommandLineInfo::ParseLast(bLast); } }; // class CMMCCommandLineInfo /*+-------------------------------------------------------------------------* * CWow64FilesystemRedirectionDisabler * * Disables Wow64 file system redirection for the file represented in the * given CMMCCommandLineInfo. We do this so MMC32 can open consoles in * %windir%\system32 without having the path redirected to %windir%\syswow64. *--------------------------------------------------------------------------*/ class CWow64FilesystemRedirectionDisabler { public: CWow64FilesystemRedirectionDisabler (LPCTSTR pszFilename) { #ifndef MMC_WIN64 m_fDisabled = ((pszFilename != NULL) && IsWin64()); if (m_fDisabled) { Trace (tag32BitTransfer, _T("Disabling Wow64 file system redirection for %s"), pszFilename); Wow64DisableFilesystemRedirector (pszFilename); } #endif // !MMC_WIN64 } ~CWow64FilesystemRedirectionDisabler () { #ifndef MMC_WIN64 if (m_fDisabled) { Trace (tag32BitTransfer, _T("Enabling Wow64 file system redirection")); Wow64EnableFilesystemRedirector(); } #endif // !MMC_WIN64 } private: #ifndef MMC_WIN64 bool m_fDisabled; #endif // !MMC_WIN64 }; /*+-------------------------------------------------------------------------* * * CAMCApp::ScProcessAuthorModeRestrictions * * PURPOSE: Determines whether author mode restrictions are being enforced * by system policy, and if author mode is not allowed, * displays an error box and exits. * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCApp::ScProcessAuthorModeRestrictions() { DECLARE_SC(sc, TEXT("CAMCApp::ScProcessAuthorModeRestrictions")); CRegKey regKey; // The mode is initialized to "author", if it is not in // initialized state just return. if (eMode_Author != m_eMode) return sc; // The console file mode is already read. // Check if user policy permits author mode. long lResult = regKey.Open(HKEY_CURRENT_USER, POLICY_KEY, KEY_READ); if (lResult != ERROR_SUCCESS) return sc; // get the value of RestrictAuthorMode. DWORD dwRestrictAuthorMode = 0; lResult = regKey.QueryValue(dwRestrictAuthorMode, g_szRestrictAuthorMode); if (lResult != ERROR_SUCCESS) return sc; if (dwRestrictAuthorMode == 0) // Author mode is not restricted so return. return sc; /* * If called from script (running as embedded server) see if policy * restricts scripts from entering into author mode. * * If restricted then script will fail, thus restricting rogue scripts. * * Even if not restricted here cannot add snapins that are restricted. */ if (IsMMCRunningAsOLEServer()) { DWORD dwRestrictScriptsFromEnteringAuthorMode = 0; lResult = regKey.QueryValue(dwRestrictScriptsFromEnteringAuthorMode, g_szRestrictScriptsFromEnteringAuthorMode); if (lResult != ERROR_SUCCESS) return sc; if (dwRestrictScriptsFromEnteringAuthorMode == 0) // Scripts can enter author mode so return return sc; sc = ScFromMMC(IDS_AUTHORMODE_NOTALLOWED_FORSCRIPTS); } else // If author mode is not allowed and // the user tried to force author mode // then display error message and exit. sc = ScFromMMC(IDS_AUTHORMODE_NOTALLOWED); return sc; } /*+-------------------------------------------------------------------------* * * CAMCApp::ScCheckMMCPrerequisites * * PURPOSE: Checks all prerequisites. These are: (add to the list as appropriate) * 1) Internet Explorer 5.5 or greater must be installed * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCApp::ScCheckMMCPrerequisites() { DECLARE_SC(sc, TEXT("CAMCApp::ScCheckMMCPrerequisites")); // 1. Determine the installed version of Internet Explorer. const int CBDATA = 100; TCHAR szVersion[CBDATA]; BOOL bIE55Found = false; HKEY hkey = NULL; DWORD dwType =0; DWORD cbData =CBDATA; DWORD dwMajor =0; DWORD dwMinor =0; DWORD dwRevision =0; DWORD dwBuild =0; lstrcpy(szVersion, TEXT("")); if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\Microsoft\\Internet Explorer"), 0, KEY_READ, &hkey)) { cbData = 100; RegQueryValueEx(hkey, TEXT("Version"), 0, &dwType, (LPBYTE)szVersion, &cbData); RegCloseKey(hkey); if (lstrlen(szVersion) > 0) { _stscanf(szVersion, TEXT("%d.%d.%d.%d"), &dwMajor, &dwMinor, &dwRevision, &dwBuild); //Make sure IE 5.5 or greater is installed. To do this: // 1) Check if the major version is >= 6. If so we're done. // 2) If the major version is 5, the minor version should be >= 50 if (dwMajor >= 6) { bIE55Found = true; } if (dwMajor == 5) { if(dwMinor >= 50) bIE55Found = true; } } } if (!bIE55Found) { sc = ScFromMMC(MMC_E_INCORRECT_IE_VERSION); // NOTE: update the string when the version requirement changes return sc; } return sc; } /*+-------------------------------------------------------------------------* * * CAMCApp::InitInstance * * PURPOSE: Initializes the document. * * NOTE: as an aside, if you need to break on, say, the 269th allocation, * add the following code: * * #define ALLOCATION_NUM 269 * _CrtSetBreakAlloc(ALLOCATION_NUM); * _crtBreakAlloc = ALLOCATION_NUM; * * RETURNS: * BOOL * *+-------------------------------------------------------------------------*/ BOOL CAMCApp::InitInstance() { DECLARE_SC(sc, TEXT("CAMCApp::InitInstance")); /* * Initialize Fusion. */ SHFusionInitializeFromModuleID (NULL, static_cast(reinterpret_cast(SXS_MANIFEST_RESOURCE_ID))); #ifdef DBG if (tagForceMirror.FAny()) { HINSTANCE hmodUser = GetModuleHandle (_T("user32.dll")); if (hmodUser != NULL) { BOOL (WINAPI* pfnSetProcessDefaultLayout)(DWORD); (FARPROC&)pfnSetProcessDefaultLayout = GetProcAddress (hmodUser, "SetProcessDefaultLayout"); if (pfnSetProcessDefaultLayout != NULL) (*pfnSetProcessDefaultLayout)(LAYOUT_RTL); } } #endif BOOL bRet = TRUE; // Initialize OLE libraries if (InitializeOLE() == FALSE) return FALSE; // Initialize the ATL Module _Module.Init(ObjectMap,m_hInstance); #ifdef DBG if(tagGDIBatching.FAny()) { // disable GDI batching so we'll see drawing as it happens GdiSetBatchLimit (1); } #endif Unregister(); Trace(tagAMCAppInit, TEXT("CAMCApp::InitInstance")); CMMCCommandLineInfo cmdInfo; ParseCommandLine(cmdInfo); /* * if we got a file on the command line, expand environment * variables in the filename so we can open files like * "%SystemRoot%\system32\compmgmt.msc" */ if (!cmdInfo.m_strFileName.IsEmpty()) { CWow64FilesystemRedirectionDisabler disabler (cmdInfo.m_strFileName); sc = ScExpandEnvironmentStrings (cmdInfo.m_strFileName); if (sc) { MMCErrorBox (sc); return (false); } } // Don't use an .ini file for the MRU or Settings // Note: This string does not need to be localizable. // HKEY_CURRENT_USER\\Software\\Microsoft\\Microsoft Management Console SetRegistryKey(_T("Microsoft")); // Find out OS version. OSVERSIONINFO versInfo; versInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); BOOL bStat = GetVersionEx(&versInfo); ASSERT(bStat); m_fIsWin9xPlatform = (versInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS); // default to Author mode (loading a console may change this later) InitializeMode (eMode_Author); m_fAuthorModeForced = cmdInfo.m_fForceAuthorMode || cmdInfo.m_strFileName.IsEmpty(); /* * dump the snap-ins (and do nothing else) if we got "-dump:" */ if (!cmdInfo.m_strDumpFilename.IsEmpty()) { DumpConsoleFile (cmdInfo.m_strFileName, cmdInfo.m_strDumpFilename); return (false); } #ifdef MMC_WIN64 /* * We're currently running the MMC64. See if we need to defer to MMC32. * If we do, try to launch MMC32. If we were able to launch MMC32 * successfully, abort MMC64. */ eArchitecture eArch = eArch_64bit; sc = ScDetermineArchitecture (cmdInfo, eArch); if (sc) { DisplayFileOpenError (sc, cmdInfo.m_strFileName); return (false); } switch (eArch) { /* * MMC64 is fine, do nothing */ case eArch_64bit: break; /* * User cancelled action, abort */ case eArch_None: return (false); break; /* * We need MMC32, so try to launch it. If we were able to launch MMC32 * successfully, abort MMC64; if not, continue running MMC64. */ case eArch_32bit: if (!ScLaunchMMC(eArch_32bit, m_nCmdShow).IsError()) { Trace (tag32BitTransfer, _T("32-bit MMC launched successfully")); return (false); } Trace (tag32BitTransfer, _T("32-bit MMC failed to launch")); MMCErrorBox (MMC_E_UnableToLaunchMMC32); break; default: ASSERT (false && "Unexpected architecture returned from ScDetermineArchitecture"); break; } #elif defined(UNICODE) /* * We're currently running the MMC32. If it's running on IA64 and 32-bit * wasn't specifically requested with a "-32" switch (this is what MMC64 * will do when it defers to MMC32), defer to MMC64 so it can do snap-in * analysis and determine the appropriate "bitness" to run. */ if ((cmdInfo.m_eArch != eArch_32bit) && IsWin64()) { /* * We need MMC64, so try to launch it. If we were able to launch MMC64 * successfully, abort MMC32; if not, continue running MMC32. */ if (!ScLaunchMMC(eArch_64bit, m_nCmdShow).IsError()) { Trace (tag32BitTransfer, _T("64-bit MMC launched successfully")); return (false); } Trace (tag32BitTransfer, _T("64-bit MMC failed to launch")); MMCErrorBox (MMC_E_UnableToLaunchMMC64); } #endif // MMC_WIN64 AfxEnableControlContainer(); // Standard initialization #ifdef _AFXDLL Enable3dControls(); // Call this when using MFC in a shared DLL #else Enable3dControlsStatic(); // Call this when linking to MFC statically #endif LoadStdProfileSettings(); // Load standard INI file options (including MRU) // create our own CDocManager derivative before adding any templates // (CWinApp::~CWinApp will delete it) m_pDocManager = new CAMCDocManager; // Register document templates CMultiDocTemplate* pDocTemplate; pDocTemplate = new CAMCMultiDocTemplate( IDR_AMCTYPE, RUNTIME_CLASS(CAMCDoc), RUNTIME_CLASS(CChildFrame), // custom MDI child frame RUNTIME_CLASS(CAMCView)); AddDocTemplate(pDocTemplate); // Note: MDI applications register all server objects without regard // to the /Embedding or /Automation on the command line. if (cmdInfo.m_fRegisterServer) { sc = _Module.RegisterServer(TRUE);// ATL Classes if (sc == TYPE_E_REGISTRYACCESS) sc.TraceAndClear(); } if (sc) { MMCErrorBox (sc); return (false); } // create main MDI Frame window CMainFrame *pMainFrame = new CMainFrame; if (!pMainFrame->LoadFrame(IDR_MAINFRAME)) return FALSE; m_pMainWnd = pMainFrame; // set the HWND to use as the parent for modal error dialogs. SC::SetHWnd(pMainFrame->GetSafeHwnd()); // save this main thread's ID to check if snapins call MMC // interfaces from main thread. SC::SetMainThreadID(::GetCurrentThreadId()); m_fRunningAsOLEServer = false; // Check to see if launched as OLE server if (RunEmbedded() || RunAutomated()) { m_fRunningAsOLEServer = true; // Application was run with /Embedding or /Automation. Don't show the // main window in this case. //return TRUE; // Also set that script is controlling the application not the user // The script can modify the UserControl property on the application. SetUnderUserControl(false); // When a server application is launched stand-alone, it is a good idea to register all objects // ATL ones specifically register with REGCLS_MULTIPLEUSE // we register class objects only when run as an OLE server. This way, cannot connect to // an existing instance of MMC. sc = _Module.RegisterClassObjects(CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE); if(sc) goto Error; } if (cmdInfo.m_fRegisterServer) { CString strTypeLib; strTypeLib.Format(TEXT("\\%d"), IDR_WEBSINK_TYPELIB); // this should evaluate to something like "\\4" sc = _Module.RegisterTypeLib((LPCTSTR)strTypeLib); if (sc == TYPE_E_REGISTRYACCESS) sc.TraceAndClear(); if(sc) goto Error; } // Don't Enable drag/drop open // m_pMainWnd->DragAcceptFiles(); // Enable DDE Execute open if (cmdInfo.m_fRegisterServer) RegisterShellFileTypes(FALSE); EnableShellOpen(); if (cmdInfo.m_fRegisterServer) DeleteDDEKeys(); /* * At this point, all of our registration is complete. If we were invoked * with -RegServer, we can bail now. */ if (cmdInfo.m_fRegisterServer) return (false); { // limit scope of disabler CWow64FilesystemRedirectionDisabler disabler (cmdInfo.m_strFileName); // Dispatch commands specified on the command line. // This loads a console file if necessary. if (!ProcessShellCommand(cmdInfo)) return (false); // user is already informed about errors } // Now the console file is loaded. Check if Author mode // is permitted. sc = ScProcessAuthorModeRestrictions(); // check if there are any restrictions set by policy if(sc) goto Error; // if proccessing the command line put MMC into author mode, // it has to stick with it forever. // see bug 102465 openning an author mode console file and then // a user mode console switched MMC into user mode if (eMode_Author == m_eMode) m_fAuthorModeForced = true; // create a document automatically only if we're not instantiated as an // OLE server. if(! IsMMCRunningAsOLEServer ()) { // if we don't have a document now (maybe because // the Node Manager wasn't registered), punt CAMCDoc* pDoc = CAMCDoc::GetDocument (); if (pDoc == NULL) return (FALSE); pDoc->SetFrameModifiedFlag (false); pDoc->UpdateFrameCounts (); CMainFrame *pMainFrame = GetMainFrame(); if (pMainFrame) { pMainFrame->ShowWindow(m_nCmdShow); pMainFrame->UpdateWindow(); } // showing will set the frame and "Modified" - reset it pDoc->SetFrameModifiedFlag (false); } // register itself as dispatcher able to dispatch com events sc = CConsoleEventDispatcherProvider::ScSetConsoleEventDispatcher( this ); if (sc) goto Error; m_fInitializing = false; // check for all MMC prerequisites sc = ScCheckMMCPrerequisites(); if (sc) goto Error; // Comment out below line when script engines hosted in mmc are enabled. // sc = ScRunTestScript(); Cleanup: return bRet; Error: MMCErrorBox(sc); bRet = FALSE; goto Cleanup; } //+------------------------------------------------------------------- // // Member: ScRunTestScript // // Synopsis: Test program to run a script. Once script input mechanisms // are defined this can be removed. // // Arguments: None // // Returns: SC // //-------------------------------------------------------------------- SC CAMCApp::ScRunTestScript () { DECLARE_SC(sc, _T("CAMCApp::ScRunTestScript")); // The Running of scripts is enabled only in debug mode. bool bEnableScriptEngines = false; #ifdef DBG if (tagEnableScriptEngines.FAny()) bEnableScriptEngines = true; #endif if (!bEnableScriptEngines) return sc; // Get the IDispatch from MMC object, the script engine needs // the IUnknown to top level object & the ITypeInfo ptr. CComPtr<_Application> spApplication; sc = ScGet_Application(&spApplication); if (sc) return sc; IDispatchPtr spDispatch = NULL; sc = spApplication->QueryInterface(IID_IDispatch, (LPVOID*)&spDispatch); if (sc) return sc; // The CScriptHostMgr should be instead created on the stack (as we have only // one per app) and destroyed with app. This change can be made once we decide // how & when the script host will be used to execute the scripts. CScriptHostMgr* pMgr = new CScriptHostMgr(spDispatch); if (NULL == pMgr) return (sc = E_OUTOFMEMORY); LPOLESTR pszScript = L"set WShShell=CreateObject(\"WScript.Shell\")\n\ WshShell.Popup(\"Anand\")\n\ Select Case WshShell.Popup(\"Anand\",5,\"Ganesan\", vbyesnocancel)\n\ End Select"; tstring strExtn = _T(".vbs"); sc = pMgr->ScExecuteScript(pszScript, strExtn); tstring strFile = _T("E:\\newnt\\admin\\mmcdev\\test\\script\\MMCStartupScript.vbs"); sc = pMgr->ScExecuteScript(strFile); delete pMgr; return (sc); } // App command to run the dialog void CAMCApp::OnAppAbout() { /* * load the title of the about dialog */ CString strTitle (MAKEINTRESOURCE (IDS_APP_NAME)); CString strVersion (MAKEINTRESOURCE (IDS_APP_VERSION)); strTitle += _T(" "); strTitle += strVersion; ShellAbout(*AfxGetMainWnd(), strTitle, NULL, LoadIcon(IDR_MAINFRAME)); } /*+-------------------------------------------------------------------------* * * CAMCApp::OnFileNewInUserMode * * PURPOSE: Do nothing in user mode when CTRL+N is pressed. * This handler prevents the hotkey from going to any WebBrowser controls * * RETURNS: * void * *+-------------------------------------------------------------------------*/ void CAMCApp::OnFileNewInUserMode() { MessageBeep(-1); } //+------------------------------------------------------------------- // // Member: ScShowHtmlHelp // // Synopsis: Initialize and then call Help control to display help topic. // // Arguments: [pszFile] - File to display. // [dwData] - Depends on uCommand for HH_DISPLAY_TOPIC it // is help topic string. // // Note: The command is always HH_DISPLAY_TOPIC. HWND is NULL so that // Help can get behind MMC window. // See ScUnintializeHelpControl's Note for more info. // // Returns: SC // //-------------------------------------------------------------------- SC CAMCApp::ScShowHtmlHelp(LPCTSTR pszFile, DWORD_PTR dwData) { DECLARE_SC(sc, _T("CAMCApp::ScInitializeHelpControl")); /* * displaying HtmlHelp might take awhile, so show a wait cursor */ CWaitCursor wait; if (! m_bHelpInitialized) HtmlHelp (NULL, NULL, HH_INITIALIZE, (DWORD_PTR)&m_dwHelpCookie); // No documented return value for HH_INITIALIZE so always assume // Initialize is successful. m_bHelpInitialized = true; HtmlHelp (NULL, pszFile, HH_DISPLAY_TOPIC, dwData); return sc; } //+------------------------------------------------------------------- // // Member: ScUninitializeHelpControl // // Synopsis: UnInitialize the help if it was initialized by MMC. // // Note: The help-control calls OleInitialize & OleUninitialize // in its DllMain. If a snapin creates any free threaded object // on main thread (STA), the OLE creates an MTA. // The last OleUninitialize does OLEProcessUninitialize in which // then OLE waits for the above MTA to cleanup and return. // By the time help-control does last OleUninitialize in its // DllMain the MTA is already terminated so OLE waits for this // MTA to signal which it never would. // We call HtmlHelp(.. HH_UNINITIALIZE..) to force help control // to uninit so that MMC does last OleUninit. // (This will not solve the problem of snapins calling help directly). // // Arguments: // // Returns: SC, S_FALSE if already uninitialized else S_OK. // //-------------------------------------------------------------------- SC CAMCApp::ScUninitializeHelpControl() { DECLARE_SC(sc, _T("CAMCApp::ScUninitializeHelpControl")); if (false == m_bHelpInitialized) return (sc = S_FALSE); HtmlHelp (NULL, NULL, HH_UNINITIALIZE, m_dwHelpCookie); m_bHelpInitialized = false; m_dwHelpCookie = 0; return sc; } BOOL CAMCApp::InitializeOLE() { if (FAILED(::OleInitialize(NULL))) return FALSE; return (m_bOleInitialized = TRUE); } void CAMCApp::DeinitializeOLE() { // Uninit help, see ScUninitializeHelpControl note. SC sc = ScUninitializeHelpControl(); if (sc) { TraceError(_T("Uninit Help control failed"), sc); } // Forced DllCanUnloadNow before mmc exits. ::CoFreeUnusedLibraries(); if (m_bOleInitialized == TRUE) { ::OleUninitialize(); m_bOleInitialized = FALSE; } } ///////////////////////////////////////////////////////////////////////////// // CAMCApp diagnostics #ifdef _DEBUG void CAMCApp::AssertValid() const { CWinApp::AssertValid(); } #endif //_DEBUG ///////////////////////////////////////////////////////////////////////////// // CAMCApp commands int CAMCApp::ExitInstance() { DECLARE_SC(sc, TEXT("CAMCApp::ExitInstance")); // if the main window is not destroyed yet - do that now. // since we need to get rid of all the objects before denitializing OLE. // It is not requred in most cases, since usually quit starts from closing the mainframe, // but in cases like system shut down it will come here with a valid window // See WindowsBug(ntbug9) #178858 if ( ::IsWindow( AfxGetMainWnd()->GetSafeHwnd() ) ) { AfxGetMainWnd()->DestroyWindow(); } // disconnect the pointers to event dispatcher sc = CConsoleEventDispatcherProvider::ScSetConsoleEventDispatcher( NULL ); if (sc) sc.TraceAndClear(); // release cached application object m_sp_Application = NULL; // MFC's class factories registration is automatically revoked by MFC itself if (RunEmbedded() || RunAutomated()) _Module.RevokeClassObjects(); // Revoke class factories for ATL _Module.Term(); // clanup ATL GLobal Module // Ask node manager to cleanup what's got cached CComPtr spComCacheCleanup; HRESULT hr = spComCacheCleanup.CoCreateInstance(CLSID_ComCacheCleanup, NULL, MMC_CLSCTX_INPROC); if (hr == S_OK) { spComCacheCleanup->ReleaseCachedOleObjects(); spComCacheCleanup.Release(); } // by now EVERY reference should be released ASSERT(_Module.GetLockCount() == 0 && "Outstanding references still exist on exit"); DeinitializeOLE(); /* * uninitialize Fusion */ SHFusionUninitialize(); int iRet = CWinApp::ExitInstance(); DEBUG_VERIFY_INSTANCE_COUNT(CAMCTreeView); DEBUG_VERIFY_INSTANCE_COUNT(CAMCListView); DEBUG_VERIFY_INSTANCE_COUNT(CCCListViewCtrl); return iRet; } BOOL CAMCApp::PreTranslateMessage(MSG* pMsg) { // Give HTML help a chance to crack the message. (Bug# 119355 & 206909). if ( m_bHelpInitialized && HtmlHelp(NULL, NULL, HH_PRETRANSLATEMESSAGE, (DWORD_PTR)pMsg) ) return TRUE; // let all of the hook windows have a crack at this message WindowListIterator it = m_TranslateMessageHookWindows.begin(); while (it != m_TranslateMessageHookWindows.end()) { HWND hwndHook = *it; CWnd* pwndHook = CWnd::FromHandlePermanent (hwndHook); // if this window is no longer valid, or it's not a permanent // window, remove it from the list if (!IsWindow (hwndHook) || (pwndHook == NULL)) it = m_TranslateMessageHookWindows.erase (it); else { // otherwise if the hook window handled the message, bail if (pwndHook->PreTranslateMessage (pMsg)) return (TRUE); ++it; } } // give the MMC defined main window accelerators a crack at the message if (m_Accel.TranslateAccelerator (AfxGetMainWnd()->GetSafeHwnd(), pMsg)) return TRUE; return CWinApp::PreTranslateMessage(pMsg); } /*+-------------------------------------------------------------------------* * CAMCApp::SaveUserDirectory * * *--------------------------------------------------------------------------*/ void CAMCApp::SaveUserDirectory(LPCTSTR pszUserDir) { // if we got an empty string, change the pointer to NULL so // the entry will be removed from the registry if ((pszUserDir != NULL) && (lstrlen(pszUserDir) == 0)) pszUserDir = NULL; WriteProfileString (m_szSettingsSection, m_szUserDirectoryEntry, pszUserDir); } /*+-------------------------------------------------------------------------* * CAMCApp::GetUserDirectory * * *--------------------------------------------------------------------------*/ CString CAMCApp::GetUserDirectory(void) { return (GetProfileString (m_szSettingsSection, m_szUserDirectoryEntry)); } /*+-------------------------------------------------------------------------* * CAMCApp::GetDefaultDirectory * * *--------------------------------------------------------------------------*/ CString CAMCApp::GetDefaultDirectory(void) { static CString strDefaultDir; if (strDefaultDir.IsEmpty()) { LPITEMIDLIST pidl; if (SUCCEEDED(SHGetSpecialFolderLocation( AfxGetMainWnd()->GetSafeHwnd(), CSIDL_ADMINTOOLS | CSIDL_FLAG_CREATE, &pidl))) { // Convert to path name SHGetPathFromIDList (pidl, strDefaultDir.GetBuffer (MAX_PATH)); strDefaultDir.ReleaseBuffer (); // Free IDList LPMALLOC pMalloc; if (SUCCEEDED(SHGetMalloc (&pMalloc))) { pMalloc->Free(pidl); pMalloc->Release(); } } } return (strDefaultDir); } /*+-------------------------------------------------------------------------* * CAMCApp::SetDefaultDirectory * * *--------------------------------------------------------------------------*/ void CAMCApp::SetDefaultDirectory(void) { // Only set default first time, so we don't override user selection if (m_bDefaultDirSet) return; // Set the current directory to the default directory CString strDirectory; BOOL rc = FALSE; strDirectory = GetDefaultDirectory (); if (!strDirectory.IsEmpty()) rc = SetCurrentDirectory (strDirectory); m_bDefaultDirSet = rc; } /*+-------------------------------------------------------------------------* * CAMCApp::PumpMessage * * *--------------------------------------------------------------------------*/ BOOL CAMCApp::PumpMessage() { m_nMessagePumpNestingLevel++; MSG msg; ::PeekMessage(&msg, NULL, NULL, NULL, PM_NOREMOVE); if (msg.message == WM_CLOSE) m_fCloseCameFromMainPump = true; BOOL rc = CWinApp::PumpMessage(); if (m_fDelayCloseUntilIdle && (m_nMessagePumpNestingLevel == 1)) { m_fCloseCameFromMainPump = true; CMainFrame *pMainFrame = GetMainFrame(); if (pMainFrame) pMainFrame->SendMessage (WM_CLOSE); m_fDelayCloseUntilIdle = false; } m_fCloseCameFromMainPump = false; m_nMessagePumpNestingLevel--; ASSERT (m_nMessagePumpNestingLevel >= 0); return (rc); } /*+-------------------------------------------------------------------------* * * CAMCApp::ScHelp * * PURPOSE: Displays help for the application. * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCApp::ScHelp() { DECLARE_SC(sc, TEXT("CAMCApp::ScHelp")); CMainFrame * pMainFrame = GetMainFrame(); if(!pMainFrame) { sc = E_UNEXPECTED; return sc; } pMainFrame->OnHelpTopics(); return sc; } /*+-------------------------------------------------------------------------* * CAMCApp::OnIdle * * WM_IDLE handler for CAMCApp. *--------------------------------------------------------------------------*/ BOOL CAMCApp::OnIdle(LONG lCount) { SC sc; CIdleTaskQueue * pQueue = GetIdleTaskQueue(); BOOL fMoreIdleWork = TRUE; if(NULL == pQueue) { ASSERT(0 && "Should not come here."); goto Error; } fMoreIdleWork = CWinApp::OnIdle(lCount); if (!fMoreIdleWork) { CMainFrame *pMainFrame = GetMainFrame(); if (pMainFrame) pMainFrame->OnIdle (); } /* * if MFC doesn't have any more idle work to do, * check our idle task queue (if we have one) */ if (!fMoreIdleWork && (pQueue != NULL)) { LONG_PTR cIdleTasks; pQueue->ScGetTaskCount (&cIdleTasks); if(sc) goto Error; /* * do we have any idle tasks? */ if (cIdleTasks > 0) { SC sc = pQueue->ScPerformNextTask(); if(sc) goto Error; /* * this idle task may have added others; refresh the count */ sc = pQueue->ScGetTaskCount(&cIdleTasks); if(sc) goto Error; } /* * do we have any more idle work to do? */ fMoreIdleWork = (cIdleTasks > 0); } if (!fMoreIdleWork) { // this code is to trigger MMC exit sequence when it // is under the script control and the last reference is released. // (we do not use MFC [which would simply delete the mainframe] to do that) if ( !IsUnderUserControl() && CMMCStrongReferences::LastRefReleased() ) { // we are in script control mode and all references are released // a good time to say goodbye CMainFrame *pMainFrame = GetMainFrame(); sc = ScCheckPointers(pMainFrame, E_UNEXPECTED); if (sc) goto Error; // disabled main window will probably mean we are under modal dialog // wait until it is dismissed ( and try again ) if (pMainFrame->IsWindowEnabled()) { // here is the deal: if MMC is shown - we will initiate the exit sequence, // but put into the user mode first, so if user chooses to cancel it - it will have // the control over the application. He will also have to handle save request if // something has changed in the console if ( pMainFrame->IsWindowVisible() ) { if ( !m_fUnderUserControl ) SetUnderUserControl(); pMainFrame->PostMessage(WM_CLOSE); } else { // if the application is hidden it should wait until user closes all open property sheets. // since it will come back here, waiting means just doing nothing at this point. if ( !FArePropertySheetsOpen(NULL, false /*bBringToFrontAndAskToClose*/ ) ) { // if there are not sheets open - we must die silently CAMCDoc* const pDoc = CAMCDoc::GetDocument(); if(pDoc == NULL) { sc = E_POINTER; //fall thru; (need to close anyway) } else { // discard document without asking to save pDoc->OnCloseDocument(); } // say goodbye pMainFrame->PostMessage(WM_CLOSE); } } } } } Cleanup: return (fMoreIdleWork); Error: TraceError(TEXT("CAMCApp::OnIdle"), sc); goto Cleanup; } //+------------------------------------------------------------------- // // Member: InitializeMode // // Synopsis: Set the mode and load the menus, accelerator tables. // // Arguments: [eMode] - New application mode. // // Returns: None. // //-------------------------------------------------------------------- void CAMCApp::InitializeMode (ProgramMode eMode) { SetMode(eMode); UpdateFrameWindow(false); } //+------------------------------------------------------------------- // // Member: SetMode // // Synopsis: Set the mode. // // Note: Call UpdateFrameWindow some time soon to update // menus/toolbars for this mode. // Cannot do this in this method. This is called // from CAMCDoc::LoadAppMode. The CAMCDoc::LoadFrame // calls the UpdateFrameWindow. // // Arguments: [eMode] - New application mode. // // Returns: None. // //-------------------------------------------------------------------- void CAMCApp::SetMode (ProgramMode eMode) { ASSERT (IsValidProgramMode (eMode)); if (m_fAuthorModeForced) { ASSERT (m_eMode == eMode_Author); ASSERT (GetMainFrame()->IsMenuVisible ()); } else m_eMode = eMode; } //+------------------------------------------------------------------- // // Member: UpdateFrameWindow // // Synopsis: Load the menu/accelerator tables and update // them if loaded from console file. // // Note: Call UpdateFrameWindow some time soon after // calling SetMode to update menus/toolbars for this mode. // This is called from CAMCDoc::LoadFrame. // // Arguments: [bUpdate] - BOOL // We need to update the toolbar/menus only // if loaded from console file // // Returns: None. // //-------------------------------------------------------------------- void CAMCApp::UpdateFrameWindow(bool bUpdate) { static const struct ModeDisplayParams { int nResourceID; bool fShowToolbar; } aDisplayParams[eMode_Count] = { { IDR_AMCTYPE, true }, // eMode_Author { IDR_AMCTYPE_USER, false }, // eMode_User { IDR_AMCTYPE_MDI_USER, false }, // eMode_User_MDI { IDR_AMCTYPE_SDI_USER, false }, // eMode_User_SDI }; if (m_fAuthorModeForced) { ASSERT (m_eMode == eMode_Author); ASSERT (GetMainFrame()->IsMenuVisible ()); return; } m_Menu.DestroyMenu (); m_Accel.DestroyAcceleratorTable (); VERIFY (m_Menu.LoadMenu (aDisplayParams[m_eMode].nResourceID)); m_Accel.LoadAccelerators (aDisplayParams[m_eMode].nResourceID); if (bUpdate) { CMainFrame *pMainFrame = GetMainFrame(); ASSERT (pMainFrame != NULL); ASSERT_VALID (pMainFrame); CMDIChildWnd* pwndActive = pMainFrame ? pMainFrame->MDIGetActive () : NULL; // bypass CMainFrame::OnUpdateFrameMenu so CMainFrame::NotifyMenuChanged // doesn't get called twice and remove the new menu entirely if (pwndActive != NULL) pwndActive->OnUpdateFrameMenu (TRUE, pwndActive, m_Menu); else if (pMainFrame) pMainFrame->OnUpdateFrameMenu (m_Menu); if (m_eMode == eMode_User_SDI) { if (pwndActive != NULL) pwndActive->MDIMaximize (); if (pMainFrame) AppendToSystemMenu (pMainFrame, eMode_User_SDI); } if (pMainFrame) pMainFrame->ShowMenu (true /*Always show menu*/); } } /*+-------------------------------------------------------------------------* * IsInContainer * * *--------------------------------------------------------------------------*/ template bool Find (InputIterator itFirst, InputIterator itLast, const T& t) { return (std::find (itFirst, itLast, t) != itLast); } /*+-------------------------------------------------------------------------* * CAMCApp::HookPreTranslateMessage * * Adds a window the the list of windows that get prioritized cracks at * PreTranslateMessage. Hooks set later get priority over earlier hooks. *--------------------------------------------------------------------------*/ void CAMCApp::HookPreTranslateMessage (CWnd* pwndHook) { HWND hwndHook = pwndHook->GetSafeHwnd(); ASSERT (IsWindow (hwndHook)); // this only makes sense for permanent windows ASSERT (CWnd::FromHandlePermanent(hwndHook) == pwndHook); /* * Put the hook window at the front of the hook list. We're preserving * the HWND instead of the CWnd* so we don't have unnecessary list<> * code generated. We already use a list for m_DelayedUpdateWindows, * so using list here doesn't cause any more code to be generated. */ if (!Find (m_TranslateMessageHookWindows.begin(), m_TranslateMessageHookWindows.end(), hwndHook)) { m_TranslateMessageHookWindows.push_front (hwndHook); } } /*+-------------------------------------------------------------------------* * CAMCApp::UnhookPreTranslateMessage * * *--------------------------------------------------------------------------*/ void CAMCApp::UnhookPreTranslateMessage (CWnd* pwndUnhook) { HWND hwndUnhook = pwndUnhook->GetSafeHwnd(); ASSERT (IsWindow (hwndUnhook)); WindowListIterator itEnd = m_TranslateMessageHookWindows.end(); WindowListIterator itFound = std::find (m_TranslateMessageHookWindows.begin(), itEnd, hwndUnhook); if (itFound != itEnd) m_TranslateMessageHookWindows.erase (itFound); } /*+-------------------------------------------------------------------------* * CAMCApp::GetIdleTaskQueue * * Returns the IIdleTaskQueue interface for the application, creating it * if necessary. *--------------------------------------------------------------------------*/ CIdleTaskQueue * CAMCApp::GetIdleTaskQueue () { return &m_IdleTaskQueue; } /*+-------------------------------------------------------------------------* * ScExpandEnvironmentStrings * * Expands the any environment string (e.g. %SystemRoot%) in the input * string, in place. *--------------------------------------------------------------------------*/ SC ScExpandEnvironmentStrings (CString& str) { DECLARE_SC (sc, _T("ScExpandEnvironmentStrings")); if (str.Find(_T('%')) != -1) { TCHAR szBuffer[MAX_PATH]; if (!ExpandEnvironmentStrings (str, szBuffer, countof(szBuffer))) return (sc.FromLastError()); str = szBuffer; } return (sc); } /*+-------------------------------------------------------------------------* * ScCreateDumpSnapins * * Creates a CLSID_MMCDocConfig object, opens it on the supplied filename, * and returns a pointer to the IDumpSnapins interface on the object. *--------------------------------------------------------------------------*/ SC ScCreateDumpSnapins ( CString& strConsoleFile, /* I/O:console file */ IDumpSnapins** ppDumpSnapins) /* O:IDumpSnapins interface */ { DECLARE_SC (sc, _T("ScCreateDumpSnapins")); /* * validate input */ sc = ScCheckPointers (ppDumpSnapins); if (sc) return (sc); *ppDumpSnapins = NULL; /* * create a doc config object */ IDocConfigPtr spDocConfig; sc = spDocConfig.CreateInstance (CLSID_MMCDocConfig); if (sc) return (sc); /* * expand any embedded environment strings in the console filename */ sc = ScExpandEnvironmentStrings (strConsoleFile); if (sc) return (sc); /* * open the console file */ sc = spDocConfig->OpenFile (::ATL::CComBSTR (strConsoleFile)); if (sc) return (sc); /* * get the IDumpSnapins interface */ sc = spDocConfig.QueryInterface (IID_IDumpSnapins, *ppDumpSnapins); if (sc) return (sc); return (sc); } /*+-------------------------------------------------------------------------* * CAMCApp::DumpConsoleFile * * *--------------------------------------------------------------------------*/ HRESULT CAMCApp::DumpConsoleFile (CString strConsoleFile, CString strDumpFile) { DECLARE_SC (sc, _T("CAMCApp::DumpConsoleFile")); const CString* pstrFileWithError = &strConsoleFile; /* * get an IDumpSnapins interface on this console file */ IDumpSnapinsPtr spDumpSnapins; sc = ScCreateDumpSnapins (strConsoleFile, &spDumpSnapins); if (sc) goto Error; sc = ScCheckPointers (spDumpSnapins, E_UNEXPECTED); if (sc) goto Error; /* * expand the dump filename if necessary */ sc = ScExpandEnvironmentStrings (strDumpFile); if (sc) goto Error; /* * If there's no directory specifier on the dump file, put a "current * directory" marker on it. We do this to prevent WritePrivateProfile* * from putting the file in the Windows directory. */ if (strDumpFile.FindOneOf(_T(":\\")) == -1) strDumpFile = _T(".\\") + strDumpFile; /* * future file-related errors will pertain to the dump file * (see Error handler) */ pstrFileWithError = &strDumpFile; /* * wipe out the existing file, if any */ if ((GetFileAttributes (strDumpFile) != 0xFFFFFFFF) && !DeleteFile (strDumpFile)) { sc.FromLastError(); goto Error; } /* * dump the contents of the console file */ sc = spDumpSnapins->Dump (strDumpFile); if (sc) goto Error; return (sc.ToHr()); Error: MMCErrorBox (*pstrFileWithError, sc); return (sc.ToHr()); } /***************************************************************************\ * * METHOD: CAMCApp::ScOnNewDocument * * PURPOSE: Emits script event for application object * * PARAMETERS: * CAMCDoc *pDocument [in] document being created/opened * BOOL bLoadedFromConsole [in] if document is loaded from file * * RETURNS: * SC - result code * \***************************************************************************/ SC CAMCApp::ScOnNewDocument(CAMCDoc *pDocument, BOOL bLoadedFromConsole) { DECLARE_SC(sc, TEXT("CAMCApp::ScOnNewDocument")); // check if there are "listeners" sc = ScHasSinks(m_sp_Application, AppEvents); if (sc) return sc; if (sc == SC(S_FALSE)) // no sinks; return sc; // construct document com object DocumentPtr spComDoc; sc = pDocument->ScGetMMCDocument(&spComDoc); if (sc) return sc; // check pointer sc = ScCheckPointers(spComDoc, E_POINTER); if (sc) return sc; // fire the event sc = ScFireComEvent(m_sp_Application, AppEvents , OnDocumentOpen (spComDoc , bLoadedFromConsole == FALSE)); if (sc) sc.TraceAndClear(); // failure to issue the com event is not critical to this action return sc; } /***************************************************************************\ * * METHOD: CAMCApp::ScOnQuitApp * * PURPOSE: Emits script event for application object * * PARAMETERS: * * RETURNS: * SC - result code * \***************************************************************************/ SC CAMCApp::ScOnQuitApp() { DECLARE_SC(sc, TEXT("CAMCApp::ScOnQuitApp")); // fire the event sc = ScFireComEvent(m_sp_Application, AppEvents , OnQuit (m_sp_Application)); if (sc) sc.TraceAndClear(); // failure to issue the com event is not critical to this action return sc; } /***************************************************************************\ * * METHOD: CAMCApp::ScOnCloseView * * PURPOSE: Script event firing helper. Invoked when the view is closed * * PARAMETERS: * CAMCView *pView [in] - view being closed * * RETURNS: * SC - result code * \***************************************************************************/ SC CAMCApp::ScOnCloseView( CAMCView *pView ) { DECLARE_SC(sc, TEXT("CAMCApp::ScOnCloseView")); // parameter check sc = ScCheckPointers(pView); if (sc) return sc; // check if we have sinks connected sc = ScHasSinks(m_sp_Application, AppEvents); if (sc) return sc; if (sc == SC(S_FALSE)) // no sinks return sc; // construct view com object ViewPtr spView; sc = pView->ScGetMMCView(&spView); if (sc) return sc; // fire the event sc = ScFireComEvent(m_sp_Application, AppEvents , OnViewClose (spView)); if (sc) sc.TraceAndClear(); // failure to issue the com event is not critical to this action return sc; } /***************************************************************************\ * * METHOD: CAMCApp::ScOnViewChange * * PURPOSE: Script event firing helper. Invoked when scope selection change * * PARAMETERS: * CAMCView *pView [in] affected view * HNODE hNode [in] new selected scope node * * RETURNS: * SC - result code * \***************************************************************************/ SC CAMCApp::ScOnViewChange( CAMCView *pView, HNODE hNode ) { DECLARE_SC(sc, TEXT("CAMCApp::ScOnViewChange")); // parameter check sc = ScCheckPointers(pView); if (sc) return sc; // check if we have sinks connected sc = ScHasSinks(m_sp_Application, AppEvents); if (sc) return sc; if (sc == SC(S_FALSE)) // no sinks return sc; // construct view com object ViewPtr spView; sc = pView->ScGetMMCView(&spView); if (sc) return sc; // construct Node com object NodePtr spNode; sc = pView->ScGetScopeNode( hNode, &spNode ); if (sc) return sc; // fire script event sc = ScFireComEvent(m_sp_Application, AppEvents , OnViewChange(spView, spNode)); if (sc) sc.TraceAndClear(); // failure to issue the com event is not critical to this action return sc; } /***************************************************************************\ * * METHOD: CAMCApp::ScOnResultSelectionChange * * PURPOSE: Script event firing helper. Invoked when result selection change * * PARAMETERS: * CAMCView *pView [in] - affected view * * RETURNS: * SC - result code * \***************************************************************************/ SC CAMCApp::ScOnResultSelectionChange( CAMCView *pView ) { DECLARE_SC(sc, TEXT("CAMCApp::ScOnResultSelectionChange")); // parameter check sc = ScCheckPointers(pView); if (sc) return sc; // check if we have sinks connected sc = ScHasSinks(m_sp_Application, AppEvents); if (sc) return sc; if (sc == SC(S_FALSE)) // no sinks return sc; // construct view com object ViewPtr spView; sc = pView->ScGetMMCView(&spView); if (sc) return sc; // construct Node com object NodesPtr spNodes; sc = pView->Scget_Selection( &spNodes ); if (sc) return sc; // fire script event sc = ScFireComEvent(m_sp_Application, AppEvents , OnSelectionChange(spView, spNodes)); if (sc) sc.TraceAndClear(); // failure to issue the com event is not critical to this action return sc; } /***************************************************************************\ * * METHOD: CMMCApplication::ScOnContextMenuExecuted * * PURPOSE: called when the context menu is executed to fire the event to script * * PARAMETERS: * PMENUITEM pMenuItem - menu item (note: it may be NULL if menu item is gone) * * RETURNS: * SC - result code * \***************************************************************************/ SC CAMCApp::ScOnContextMenuExecuted( PMENUITEM pMenuItem ) { DECLARE_SC(sc, TEXT("CAMCApp::ScOnContextMenuExecuted")); // see if we have sinks connected sc = ScHasSinks(m_sp_Application, AppEvents); if (sc) return sc; if (sc == SC(S_FALSE)) // no sinks return sc; // fire the event sc = ScFireComEvent(m_sp_Application, AppEvents, OnContextMenuExecuted( pMenuItem ) ); if (sc) sc.TraceAndClear(); // failure to issue the com event is not critical to this action return sc; } /*+-------------------------------------------------------------------------* * * CAMCApp::ScOnListViewItemUpdated * * PURPOSE: * * PARAMETERS: * CAMCView * pView : * int nIndex : * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CAMCApp::ScOnListViewItemUpdated(CAMCView *pView , int nIndex) { DECLARE_SC(sc, TEXT("CAMCApp::ScOnListViewItemUpdated")); // parameter check sc = ScCheckPointers(pView); if (sc) return sc; // check if we have sinks connected sc = ScHasSinks(m_sp_Application, AppEvents); if (sc) return sc; if (sc == SC(S_FALSE)) // no sinks return sc; // construct view com object ViewPtr spView; sc = pView->ScGetMMCView(&spView); if (sc) return sc; // fire script event sc = ScFireComEvent(m_sp_Application, AppEvents , OnListUpdated(spView)); if (sc) sc.TraceAndClear(); // failure to issue the com event is not critical to this action return sc; } /***************************************************************************\ * * METHOD: CAMCApp::ScOnSnapinAdded * * PURPOSE: Script event firing helper. Implements interface accessible from * node manager * * PARAMETERS: * PSNAPIN pSnapIn [in] - snapin added to the console * * RETURNS: * SC - result code * \***************************************************************************/ SC CAMCApp::ScOnSnapinAdded(CAMCDoc *pAMCDoc, PSNAPIN pSnapIn) { DECLARE_SC(sc, TEXT("CAMCApp::ScOnSnapinAdded")); // parameter check sc = ScCheckPointers(pAMCDoc, pSnapIn); if (sc) return sc; // see if we have sinks connected sc = ScHasSinks(m_sp_Application, AppEvents); if (sc) return sc; if (sc == SC(S_FALSE)) // no sinks return sc; DocumentPtr spDocument; sc = pAMCDoc->ScGetMMCDocument(&spDocument); if (sc) return sc; // check sc = ScCheckPointers(spDocument, E_UNEXPECTED); if (sc) return sc; // fire the event sc = ScFireComEvent(m_sp_Application, AppEvents , OnSnapInAdded (spDocument, pSnapIn)); if (sc) sc.TraceAndClear(); // failure to issue the com event is not critical to this action return sc; } /***************************************************************************\ * * METHOD: CAMCApp::ScOnSnapinRemoved * * PURPOSE: Script event firing helper. Implements interface accessible from * node manager * * PARAMETERS: * PSNAPIN pSnapIn [in] - snapin removed from console * * RETURNS: * SC - result code * \***************************************************************************/ SC CAMCApp::ScOnSnapinRemoved(CAMCDoc *pAMCDoc, PSNAPIN pSnapIn) { DECLARE_SC(sc, TEXT("CAMCApp::ScOnSnapinRemoved")); // parameter check sc = ScCheckPointers(pAMCDoc, pSnapIn); if (sc) return sc; // see if we have sinks connected sc = ScHasSinks(m_sp_Application, AppEvents); if (sc) return sc; if (sc == SC(S_FALSE)) // no sinks return sc; DocumentPtr spDocument; sc = pAMCDoc->ScGetMMCDocument(&spDocument); if (sc) return sc; // check sc = ScCheckPointers(spDocument, E_UNEXPECTED); if (sc) return sc; // fire the event sc = ScFireComEvent(m_sp_Application, AppEvents , OnSnapInRemoved (spDocument, pSnapIn)); if (sc) sc.TraceAndClear(); // failure to issue the com event is not critical to this action return sc; } /***************************************************************************\ * * METHOD: CAMCApp::ScOnNewView * * PURPOSE: Script event firing helper * * PARAMETERS: * CAMCView *pView [in] - created view * * RETURNS: * SC - result code * \***************************************************************************/ SC CAMCApp::ScOnNewView(CAMCView *pView) { DECLARE_SC(sc, TEXT("CAMCApp::ScOnNewView")); // parameter check sc = ScCheckPointers(pView); if (sc) return sc; // see if we have sinks connected sc = ScHasSinks(m_sp_Application, AppEvents); if (sc) return sc; if (sc == SC(S_FALSE)) // no sinks return sc; // construct View com object ViewPtr spView; sc = pView->ScGetMMCView(&spView); if (sc) return sc; // fire the event sc = ScFireComEvent(m_sp_Application, AppEvents , OnNewView(spView)); if (sc) sc.TraceAndClear(); // failure to issue the com event is not critical to this action return sc; } /***************************************************************************\ * * METHOD: CAMCApp::OnCloseDocument * * PURPOSE: Helper for invoking com event * * PARAMETERS: * CAMCDoc *pAMCDoc [in] - document being closed * * RETURNS: * SC - result code * \***************************************************************************/ SC CAMCApp::ScOnCloseDocument(CAMCDoc *pAMCDoc) { DECLARE_SC(sc, TEXT("CAMCApp::OnCloseDocument")); // parameter check sc = ScCheckPointers(pAMCDoc); if (sc) return sc; // see if we have sinks connected sc = ScHasSinks(m_sp_Application, AppEvents); if (sc) return sc; if (sc == SC(S_FALSE)) // no sinks return sc; DocumentPtr spDocument; sc = pAMCDoc->ScGetMMCDocument(&spDocument); if (sc) return sc; // check sc = ScCheckPointers(spDocument, E_UNEXPECTED); if (sc) return sc; // fire the event sc = ScFireComEvent(m_sp_Application, AppEvents , OnDocumentClose (spDocument)); if (sc) sc.TraceAndClear(); // failure to issue the com event is not critical to this action return sc; } /***************************************************************************\ * * METHOD: CAMCApp::ScOnToolbarButtonClicked * * PURPOSE: Observed toolbar event - used to fire com event * * PARAMETERS: * CAMCView *pAMCView - [in] view which toobar is executed * * RETURNS: * SC - result code * \***************************************************************************/ SC CAMCApp::ScOnToolbarButtonClicked( ) { DECLARE_SC(sc, TEXT("CAMCApp::ScOnToolbarButtonClicked")); // see if we have sinks connected sc = ScHasSinks(m_sp_Application, AppEvents); if (sc) return sc; if (sc == SC(S_FALSE)) // no sinks return sc; // fire the event sc = ScFireComEvent(m_sp_Application, AppEvents , OnToolbarButtonClicked ( )); if (sc) sc.TraceAndClear(); // ignore the error - should not affect main behavior return sc; } /***************************************************************************\ * * METHOD: CAMCApp::SetUnderUserControl * * PURPOSE: puts application into user control/script control mode * implements Application.UserControl property * * PARAMETERS: * bool bUserControl [in] true == set user control * * RETURNS: * void * \***************************************************************************/ void CAMCApp::SetUnderUserControl(bool bUserControl /* = true */ ) { m_fUnderUserControl = bUserControl; AfxOleSetUserCtrl(bUserControl); // allow MFC to know that if (bUserControl) { // make sure application is visible if it's under user control CMainFrame *pMainFrame = GetMainFrame(); if(pMainFrame && !pMainFrame->IsWindowVisible()) { pMainFrame->ShowWindow(SW_SHOW); } } } #ifdef MMC_WIN64 /*+-------------------------------------------------------------------------* * CompareBasicSnapinInfo * * Implements a less-than comparison for CBasicSnapinInfo, based solely on * the CLSID. Returns true if the CLSID for bsi1 is less than the CLSID * for bsi2, false otherwise. *--------------------------------------------------------------------------*/ bool CompareBasicSnapinInfo (const CBasicSnapinInfo& bsi1, const CBasicSnapinInfo& bsi2) { return (bsi1.m_clsid < bsi2.m_clsid); } /*+-------------------------------------------------------------------------* * ScDetermineArchitecture * * Determines whether MMC64 (which is currently executing) should chain * to MMC32. This will occur in one of three situations: * * 1. The "-32" command line parameter was specified. * * 2. A console file was specified on the command line, and it contains * one or more snap-ins that were not registered in the 64-bit HKCR * hive, but all snap-ins are registered in the 32-bit HKCR hive. * * 3. A console file was specified on the command line, and it contained * one or more snap-ins that were not registered in the 64-bit HKCR * hive, and one or more snap-ins that are not registered in the 32-bit * HKCR hive. In this case we'll do one of three things: * * a. If the set of unavailable 64-bit snap-ins is a subset of the * set of unavailable 32-bit snap-ins, the 64-bit console will be * more functional than the 32-bit console, so we'll run MMC64. * * b. If the set of unavailable 32-bit snap-ins is a subset of the * set of unavailable 64-bit snap-ins, the 32-bit console will be * more functional than the 64-bit console, so we'll run MMC32. * * c. If neither a. or b. is true, we'll display UI asking which * version of MMC to run. * * Returns: * eArch == eArch_64bit - 64-bit MMC is needed (or an error occurred) * eArch == eArch_32bit - 32-bit MMC is needed * eArch == eArch_None - user cancelled the operation *--------------------------------------------------------------------------*/ SC ScDetermineArchitecture (const CMMCCommandLineInfo& rCmdInfo, eArchitecture& eArch) { DECLARE_SC (sc, _T("ScDetermineArchitecture")); /* * default to 64-bit */ eArch = eArch_64bit; /* * Case 0: Was "-64" specified on the command line? 64-bit needed */ if (rCmdInfo.m_eArch == eArch_64bit) { Trace (tag32BitTransfer, _T("\"-64\" parameter specified, 64-bit MMC needed")); return (sc); } /* * Case 1: Was "-32" specified on the command line? 32-bit needed */ if (rCmdInfo.m_eArch == eArch_32bit) { Trace (tag32BitTransfer, _T("\"-32\" parameter specified, 32-bit MMC needed")); eArch = eArch_32bit; return (sc); } /* * No file on the command line? 64-bit needed */ if (rCmdInfo.m_nShellCommand != CCommandLineInfo::FileOpen) { Trace (tag32BitTransfer, _T("No console file specified, 64-bit MMC needed")); return (sc); } /* * Cases 2 and 3: Analyze the specified console file */ Trace (tag32BitTransfer, _T("Analyzing snap-ins in \"%s\""), (LPCTSTR) rCmdInfo.m_strFileName); /* * get an IDumpSnapins interface so we can analyze the console file */ IDumpSnapinsPtr spDumpSnapins; CString strConsoleFile = rCmdInfo.m_strFileName; sc = ScCreateDumpSnapins (strConsoleFile, &spDumpSnapins); if (sc) return (sc); sc = ScCheckPointers (spDumpSnapins, E_UNEXPECTED); if (sc) return (sc); /* * analyze the 64-bit snap-ins in this console */ CAvailableSnapinInfo asi64(false); sc = spDumpSnapins->CheckSnapinAvailability (asi64); if (sc) return (sc); /* * if no snap-ins are unavailable in 64-bit form, no need for MMC32 */ if (asi64.m_vAvailableSnapins.size() == asi64.m_cTotalSnapins) { Trace (tag32BitTransfer, _T("All snapins are available in 64-bit form, 64-bit MMC needed")); return (sc); } /* * analyze the 32-bit snap-ins in this console */ CAvailableSnapinInfo asi32(true); sc = spDumpSnapins->CheckSnapinAvailability (asi32); if (sc) return (sc); /* * Case 2: If no snap-ins are unavailable in 32-bit form, 32-bit needed */ if (asi32.m_vAvailableSnapins.size() == asi32.m_cTotalSnapins) { Trace (tag32BitTransfer, _T("All snapins are available in 32-bit form, 32-bit MMC needed")); eArch = eArch_32bit; return (sc); } /* * std::includes depends on its ranges being sorted, so make sure * that's the case */ std::sort (asi32.m_vAvailableSnapins.begin(), asi32.m_vAvailableSnapins.end(), CompareBasicSnapinInfo); std::sort (asi64.m_vAvailableSnapins.begin(), asi64.m_vAvailableSnapins.end(), CompareBasicSnapinInfo); /* * Case 3a: If the set of available 64-bit snap-ins is a * superset of the set of available 32-bit snap-ins, run MMC64 */ if (std::includes (asi64.m_vAvailableSnapins.begin(), asi64.m_vAvailableSnapins.end(), asi32.m_vAvailableSnapins.begin(), asi32.m_vAvailableSnapins.end(), CompareBasicSnapinInfo)) { Trace (tag32BitTransfer, _T("The set of available 64-bit snapins is a superset of...")); Trace (tag32BitTransfer, _T("...the set of available 32-bit snapins, 64-bit MMC needed")); return (sc); } /* * Case 3b: If the set of available 32-bit snap-ins is a * superset of the set of available 64-bit snap-ins, run MMC32 */ if (std::includes (asi32.m_vAvailableSnapins.begin(), asi32.m_vAvailableSnapins.end(), asi64.m_vAvailableSnapins.begin(), asi64.m_vAvailableSnapins.end(), CompareBasicSnapinInfo)) { Trace (tag32BitTransfer, _T("The set of available 32-bit snapins is a superset of...")); Trace (tag32BitTransfer, _T("...the set of available 64-bit snapins, 32-bit MMC needed")); eArch = eArch_32bit; return (sc); } /* * Case 3c: Ask the user which to run */ CArchitecturePicker dlg (rCmdInfo.m_strFileName, asi64, asi32); if (dlg.DoModal() == IDOK) { eArch = dlg.GetArchitecture(); Trace (tag32BitTransfer, _T("User chose %d-bit, %d-bit MMC needed"), (eArch == eArch_32bit) ? 32 : 64, (eArch == eArch_32bit) ? 32 : 64); } else { Trace (tag32BitTransfer, _T("User chose to exit, terminating")); eArch = eArch_None; } return (sc); } #endif // MMC_WIN64 #ifdef UNICODE /*+-------------------------------------------------------------------------* * ScLaunchMMC * * Launches a specific architecture of MMC (i.e. MMC32 from MMC64 or vice * versa) with the same command line used to launch this process. * * Returns S_OK if the given architecture of MMC was launched successfully, * or an error code if an error occurred. *--------------------------------------------------------------------------*/ SC ScLaunchMMC ( eArchitecture eArch, /* I:desired architecture */ int nCmdShow) /* I:show state */ { DECLARE_SC (sc, _T("ScLaunchMMC")); CString strArgs; int nFolder; switch (eArch) { case eArch_64bit: nFolder = CSIDL_SYSTEM; break; case eArch_32bit: /* * make sure we give MMC32 a "-32" argument so it won't defer * to MMC64 again (see CAMCApp::InitInstance) */ strArgs = _T("-32 "); nFolder = CSIDL_SYSTEMX86; break; default: return (sc = E_INVALIDARG); break; } /* * Get the directory where MMC32 lives (%SystemRoot%\syswow64) and * append the executable name */ CString strProgram; sc = SHGetFolderPath (NULL, nFolder, NULL, 0, strProgram.GetBuffer(MAX_PATH)); if (sc) return (sc); strProgram.ReleaseBuffer(); strProgram += _T("\\mmc.exe"); /* * disable file system redirection so MMC32 will be able to launch MMC64 */ CWow64FilesystemRedirectionDisabler disabler (strProgram); /* * get the arguments for the original invocation of MMC, skipping * argv[0] (the executable name) and any "-32" or "-64" parameters */ int argc; CAutoGlobalPtr argv (CommandLineToArgvW (GetCommandLine(), &argc)); if (argv == NULL) return (sc.FromLastError()); for (int i = 1; i < argc; i++) { CString strArg = argv[i]; if ((strArg != _T("-32")) && (strArg != _T("/32")) && (strArg != _T("-64")) && (strArg != _T("/64"))) { strArgs += _T("\"") + strArg + _T("\" "); } } /* * start the requested architecture of MMC */ Trace (tag32BitTransfer, _T("Attempting to run: %s %s"), (LPCTSTR) strProgram, (LPCTSTR) strArgs); SHELLEXECUTEINFO sei = {0}; sei.cbSize = sizeof (sei); sei.fMask = SEE_MASK_FLAG_NO_UI; sei.lpFile = strProgram; sei.lpParameters = strArgs; sei.nShow = nCmdShow; if (!ShellExecuteEx (&sei)) return (sc.FromLastError()); return (sc); } #endif // UNICODE #ifndef MMC_WIN64 /*+-------------------------------------------------------------------------* * IsWin64 * * Returns true if we're running on Win64, false otherwise. *--------------------------------------------------------------------------*/ bool IsWin64() { #ifdef UNICODE /* * get a pointer to kernel32!GetSystemWow64Directory */ HMODULE hmod = GetModuleHandle (_T("kernel32.dll")); if (hmod == NULL) return (false); UINT (WINAPI* pfnGetSystemWow64Directory)(LPTSTR, UINT); (FARPROC&)pfnGetSystemWow64Directory = GetProcAddress (hmod, "GetSystemWow64DirectoryW"); if (pfnGetSystemWow64Directory == NULL) return (false); /* * if GetSystemWow64Directory fails and sets the last error to * ERROR_CALL_NOT_IMPLEMENTED, we're on a 32-bit OS */ TCHAR szWow64Dir[MAX_PATH]; if (((pfnGetSystemWow64Directory)(szWow64Dir, countof(szWow64Dir)) == 0) && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)) { return (false); } /* * if we get here, we're on Win64 */ return (true); #else /* * non-Unicode platforms cannot be Win64 */ return (false); #endif // UNICODE } #endif // !MMC_WIN64