|
|
//+-------------------------------------------------------------------------
//
// 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 <shlobj.h>
#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 <wow64t.h> // 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 <multimon.h>
#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 <atlimpl.cpp>
#include <atlwin.cpp>
// 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<CMMCApplication, &CLSID_Application>, // support for connection points (script events)
public IConnectionPointContainerImpl<CMMCApplication>, public IConnectionPointImpl<CMMCApplication, &DIID_AppEvents, CComDynamicUnkArray>, 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<HWND>::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<HWND> 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<CMainFrame *>(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<int>(reinterpret_cast<ULONG_PTR>(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:<filename>" */ 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<IComCacheCleanup> 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<class InputIterator, class T> 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<HWND> for m_DelayedUpdateWindows, * so using list<HWND> 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<LPWSTR> 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
|