///////////////////////////////////////////////////////////////////////////// // // Copyright (c) 1996-2000 Microsoft Corporation // // Module Name: // ExtDll.cpp // // Abstract: // Implementation of the extension DLL classes. // // Author: // David Potter (davidp) May 31, 1996 // // Revision History: // // Notes: // ///////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include #include "CluAdmID.h" #include "ExtDll.h" #include "CluAdmin.h" #include "ExtMenu.h" #include "TraceTag.h" #include "ExcOper.h" #include "ClusItem.h" #include "BaseSht.h" #include "BasePSht.h" #include "BaseWiz.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // Global Variables ///////////////////////////////////////////////////////////////////////////// #ifdef _DEBUG CTraceTag g_tagExtDll(_T("UI"), _T("EXTENSION DLL"), 0); CTraceTag g_tagExtDllRef(_T("UI"), _T("EXTENSION DLL References"), 0); #endif ///////////////////////////////////////////////////////////////////////////// // CExtensions ///////////////////////////////////////////////////////////////////////////// IMPLEMENT_DYNAMIC(CExtensions, CObject); ///////////////////////////////////////////////////////////////////////////// //++ // // CExtensions::CExtensions // // Routine Description: // Default constructor. // // Arguments: // None. // // Return Value: // None. // //-- ///////////////////////////////////////////////////////////////////////////// CExtensions::CExtensions(void) { m_pci = NULL; m_hfont = NULL; m_hicon = NULL; m_pdoData = NULL; m_plextdll = NULL; m_psht = NULL; m_pmenu = NULL; m_plMenuItems = NULL; m_nFirstCommandID = (ULONG) -1; m_nNextCommandID = (ULONG) -1; m_nFirstMenuID = (ULONG) -1; m_nNextMenuID = (ULONG) -1; } //*** CExtensions::CExtensions() ///////////////////////////////////////////////////////////////////////////// //++ // // CExtensions::~CExtensions // // Routine Description: // Destructor. // // Arguments: // None. // // Return Value: // None. // //-- ///////////////////////////////////////////////////////////////////////////// CExtensions::~CExtensions(void) { UnloadExtensions(); } //*** CExtensions::~CExtensions() ///////////////////////////////////////////////////////////////////////////// //++ // // CExtensions::Init // // Routine Description: // Common initialize for all interfaces. // // Arguments: // rlstrExtensions [IN] List of extension CLSID strings. // pci [IN OUT] Cluster item to be administered. // hfont [IN] Font for dialog text. // hicon [IN] Icon for upper left corner. // // Return Value: // None. // // Exceptions Thrown: // Any exceptions thrown by new. // //-- ///////////////////////////////////////////////////////////////////////////// void CExtensions::Init( IN const CStringList & rlstrExtensions, IN OUT CClusterItem * pci, IN HFONT hfont, IN HICON hicon ) { CWaitCursor wc; ASSERT( rlstrExtensions.GetCount() > 0 ); UnloadExtensions(); // Save parameters. m_plstrExtensions = &rlstrExtensions; m_pci = pci; m_hfont = hfont; m_hicon = hicon; // Allocate a new Data Object. m_pdoData = new CComObject< CDataObject >; if ( m_pdoData == NULL ) { AfxThrowMemoryException(); } // if: error allocating memory m_pdoData->AddRef(); // Construct the Data Object. Pdo()->Init( pci, GetClusterAdminApp()->Lcid(), hfont, hicon ); // Allocate the extension list. m_plextdll = new CExtDllList; if ( m_plextdll == NULL ) { AfxThrowMemoryException(); } // if: error allocating memory ASSERT( Plextdll() != NULL ); // Loop through the extensions and load each one. { CComObject * pextdll = NULL; POSITION posName; Trace( g_tagExtDll, _T("CExtensions::Init() - %d extensions"), rlstrExtensions.GetCount() ); posName = rlstrExtensions.GetHeadPosition(); while ( posName != NULL ) { // Allocate an extension DLL object and add it to the list. pextdll = new CComObject< CExtensionDll >; if ( pextdll == NULL ) { AfxThrowMemoryException(); } // if: error allocating memory pextdll->AddRef(); Plextdll()->AddTail( pextdll ); try { pextdll->Init( rlstrExtensions.GetNext( posName ), this ); } // try catch ( CException * pe ) { POSITION pos; pe->ReportError(); pe->Delete(); pos = Plextdll()->Find(pextdll); ASSERT( pos != NULL ); Plextdll()->RemoveAt( pos ); delete pextdll; } // catch: anything } // while: more items in the list } // Loop through the extensions and load each one } //*** CExtensions::Init() ///////////////////////////////////////////////////////////////////////////// //++ // // CExtensions::UnloadExtensions // // Routine Description: // Unload the extension DLL. // // Arguments: // None. // // Return Value: // None. // //-- ///////////////////////////////////////////////////////////////////////////// void CExtensions::UnloadExtensions(void) { // Delete all the extension DLL objects. if (Plextdll() != NULL) { POSITION pos; CComObject * pextdll; pos = Plextdll()->GetHeadPosition(); while (pos != NULL) { pextdll = Plextdll()->GetNext(pos); pextdll->AddRef(); // See comment below. pextdll->UnloadExtension(); if (pextdll->m_dwRef != 2) { Trace(g_tagError, _T("CExtensions::UnloadExtensions() - Extension DLL has ref count = %d"), pextdll->m_dwRef); } // We added a reference above. Combined with the reference that // was added when the object was created, we typically will need // to release two references. However, due to bogus code // generated by earlier versions of the custom AppWizard where the // extension was releasing the interface but not zeroing out its // pointer in the error case, we may not need to release the // second reference. if (pextdll->Release() != 0) { pextdll->Release(); } // if: more references to release } // while: more items in the list delete m_plextdll; m_plextdll = NULL; } // if: there is a list of extensions if (m_pdoData != NULL) { if (m_pdoData->m_dwRef != 1) { Trace(g_tagError, _T("CExtensions::UnloadExtensions() - Data Object has ref count = %d"), m_pdoData->m_dwRef); } m_pdoData->Release(); m_pdoData = NULL; } // if: data object allocated m_pci = NULL; m_hfont = NULL; m_hicon = NULL; // Delete all menu items. if (PlMenuItems() != NULL) { POSITION pos; CExtMenuItem * pemi; pos = PlMenuItems()->GetHeadPosition(); while (pos != NULL) { pemi = PlMenuItems()->GetNext(pos); delete pemi; } // while: more items in the list delete m_plMenuItems; m_plMenuItems = NULL; } // if: there is a list of menu items } //*** CExtensions::UnloadExtensions() ///////////////////////////////////////////////////////////////////////////// //++ // // CExtensions::CreatePropertySheetPages // // Routine Description: // Add pages to a property sheet. // // Arguments: // psht [IN OUT] Property sheet to which pages are to be added. // rlstrExtensions [IN] List of extension CLSID strings. // pci [IN OUT] Cluster item to be administered. // hfont [IN] Font for dialog text. // hicon [IN] Icon for upper left corner. // // Return Value: // None. // // Exceptions Thrown: // Any exceptions thrown by CExtensionDll::AddPages(). // //-- ///////////////////////////////////////////////////////////////////////////// void CExtensions::CreatePropertySheetPages( IN OUT CBasePropertySheet * psht, IN const CStringList & rlstrExtensions, IN OUT CClusterItem * pci, IN HFONT hfont, IN HICON hicon ) { POSITION pos; CComObject * pextdll; ASSERT_VALID(psht); m_psht = psht; // Initialize for all extensions. Init(rlstrExtensions, pci, hfont, hicon); ASSERT(Plextdll() != NULL); pos = Plextdll()->GetHeadPosition(); while (pos != NULL) { pextdll = Plextdll()->GetNext(pos); ASSERT_VALID(pextdll); try { pextdll->CreatePropertySheetPages(); } // try catch (CException * pe) { pe->ReportError(); pe->Delete(); } // catch: CNTException } // while: more items in the list } //*** CExtensions::CreatePropertySheetPages() ///////////////////////////////////////////////////////////////////////////// //++ // // CExtensions::CreateWizardPages // // Routine Description: // Add pages to a wizard. // // Arguments: // psht [IN OUT] Property sheet to which pages are to be added. // rlstrExtensions [IN] List of extension CLSID strings. // pci [IN OUT] Cluster item to be administered. // hfont [IN] Font for dialog text. // hicon [IN] Icon for upper left corner. // // Return Value: // None. // // Exceptions Thrown: // Any exceptions thrown by CExtensionDll::AddPages(). // //-- ///////////////////////////////////////////////////////////////////////////// void CExtensions::CreateWizardPages( IN OUT CBaseWizard * psht, IN const CStringList & rlstrExtensions, IN OUT CClusterItem * pci, IN HFONT hfont, IN HICON hicon ) { POSITION pos; CComObject * pextdll; ASSERT_VALID(psht); m_psht = psht; // Initialize for all extensions. Init(rlstrExtensions, pci, hfont, hicon); ASSERT(Plextdll() != NULL); pos = Plextdll()->GetHeadPosition(); while (pos != NULL) { pextdll = Plextdll()->GetNext(pos); ASSERT_VALID(pextdll); try { pextdll->CreateWizardPages(); } // try catch (CException * pe) { pe->ReportError(); pe->Delete(); } // catch: CNTException } // while: more items in the list } //*** CExtensions::CreateWizardPages() ///////////////////////////////////////////////////////////////////////////// //++ // // CExtensions::AddContextMenuItems // // Routine Description: // Query the extension DLL for new menu items to be added to the context // menu. // // Arguments: // pmenu [IN OUT] Menu to which items are to be added. // rlstrExtensions [IN] List of extension CLSID strings. // pci [IN OUT] Cluster item to be administered. // // Return Value: // None. // // Exceptions Thrown: // Any exceptions thrown by CExtensionDll::AddContextMenuItems() or // CExtMenuItemList::new(). // //-- ///////////////////////////////////////////////////////////////////////////// void CExtensions::AddContextMenuItems( IN OUT CMenu * pmenu, IN const CStringList & rlstrExtensions, IN OUT CClusterItem * pci ) { POSITION pos; CComObject< CExtensionDll > * pextdll; ASSERT(m_pmenu == NULL); ASSERT_VALID(pmenu); // Initialize for all extensions. Init( rlstrExtensions, pci, NULL, NULL ); ASSERT( Plextdll() != NULL ); m_pmenu = pmenu; m_nFirstCommandID = CAEXT_MENU_FIRST_ID; m_nNextCommandID = m_nFirstCommandID; m_nFirstMenuID = 0; m_nNextMenuID = m_nFirstMenuID; // Create the list of menu items. ASSERT( m_plMenuItems == NULL ); m_plMenuItems = new CExtMenuItemList; if ( m_plMenuItems == NULL ) { AfxThrowMemoryException(); } // if: error allocating memory pos = Plextdll()->GetHeadPosition(); while ( pos != NULL ) { pextdll = Plextdll()->GetNext( pos ); ASSERT_VALID( pextdll ); try { pextdll->AddContextMenuItems(); } // try catch ( CException * pe ) { pe->ReportError(); pe->Delete(); } // catch: CNTException } // while: more items in the list } //*** CExtensions::AddContextMenuItems() ///////////////////////////////////////////////////////////////////////////// //++ // // CExtensions::BExecuteContextMenuItem // // Routine Description: // Execute a command associated with a menu item added to a context menu // by the extension DLL. // // Arguments: // nCommandID [IN] Command ID for the menu item chosen by the user. // // Return Value: // TRUE Context menu item was executed. // FALSE Context menu item was not executed. // // Exceptions Thrown: // Any exceptions thrown by CExceptionDll::BExecuteContextMenuItem(). // //-- ///////////////////////////////////////////////////////////////////////////// BOOL CExtensions::BExecuteContextMenuItem(IN ULONG nCommandID) { BOOL bHandled = FALSE; HRESULT hr; CExtMenuItem * pemi; // Find the item in our list. pemi = PemiFromCommandID(nCommandID); if (pemi != NULL) { Pdo()->AddRef(); pemi->PiCommand()->AddRef(); hr = pemi->PiCommand()->InvokeCommand(pemi->NExtCommandID(), Pdo()->GetUnknown()); if (hr == NOERROR) { bHandled = TRUE; } //if: } // if: found an item for the command ID return bHandled; } //*** CExtensions::BExecuteContextMenuItem() ///////////////////////////////////////////////////////////////////////////// //++ // // CExtensions::BGetCommandString // // Routine Description: // Get a command string from a menu ID. // // Arguments: // nCommandID [IN] Command ID for the menu item. // rstrMessage [OUT] String in which to return the message. // // Return Value: // TRUE String is being returned. // FALSE No string is being returned. // // Exceptions Thrown: // Any exceptions thrown by CExtensionDll::BGetCommandString(). // //-- ///////////////////////////////////////////////////////////////////////////// BOOL CExtensions::BGetCommandString( IN ULONG nCommandID, OUT CString & rstrMessage ) { BOOL bHandled = FALSE; CExtMenuItem * pemi; // Find the item in our list. pemi = PemiFromCommandID(nCommandID); if (pemi != NULL) { rstrMessage = pemi->StrStatusBarText(); bHandled = TRUE; } // if: found an item for the command ID return bHandled; } //*** CExtensions::BGetCommandString() ///////////////////////////////////////////////////////////////////////////// //++ // // CExtensions::OnUpdateCommand // // Routine Description: // Determines whether extension DLL menu items should be enabled or not. // // Arguments: // pCmdUI [IN OUT] Command routing object. // // Return Value: // None. // // Exceptions Thrown: // Any exceptions thrown by CExtensionDll::BOnUpdateCommand(). // //-- ///////////////////////////////////////////////////////////////////////////// void CExtensions::OnUpdateCommand(CCmdUI * pCmdUI) { CExtMenuItem * pemi; ASSERT(Plextdll() != NULL); // Find the item in our list. Trace(g_tagExtDll, _T("OnUpdateCommand() - ID = %d"), pCmdUI->m_nID); pemi = PemiFromCommandID(pCmdUI->m_nID); if (pemi != NULL) { Trace(g_tagExtDll, _T("OnUpdateCommand() - Found a match with '%s' ExtID = %d"), pemi->StrName(), pemi->NExtCommandID()); pCmdUI->Enable( TRUE ); if ( pCmdUI->m_pMenu != NULL && (pemi->UFlags() != 0) ) { (pCmdUI->m_pMenu)->EnableMenuItem( pCmdUI->m_nID, pemi->UFlags() ); } // if: } // if: found an item for the command ID } //*** CExtensions::OnUpdateCommand() ///////////////////////////////////////////////////////////////////////////// //++ // // CExtensions::OnCmdMsg // // Routine Description: // Processes command messages. Attempts to pass them on to a selected // item first. // // Arguments: // nID [IN] Command ID. // nCode [IN] Notification code. // pExtra [IN OUT] Used according to the value of nCode. // pHandlerInfo [OUT] ??? // // Return Value: // TRUE Message has been handled. // FALSE Message has NOT been handled. // //-- ///////////////////////////////////////////////////////////////////////////// BOOL CExtensions::OnCmdMsg( UINT nID, int nCode, void * pExtra, AFX_CMDHANDLERINFO * pHandlerInfo ) { return BExecuteContextMenuItem(nID); } //*** CExtensions::OnCmdMsg() ///////////////////////////////////////////////////////////////////////////// //++ // // CExtensions::PemiFromCommandID // // Routine Description: // Find the menu item for the specified command ID. // // Arguments: // nCommandID [IN] Command ID for the menu item. // // Return Value: // pemi Menu item or NULL if not found. // // Exceptions Thrown: // None. // //-- ///////////////////////////////////////////////////////////////////////////// CExtMenuItem * CExtensions::PemiFromCommandID(IN ULONG nCommandID) const { POSITION pos; CExtMenuItem * pemi; CExtMenuItem * pemiReturn = NULL; if (PlMenuItems() != NULL) { pos = PlMenuItems()->GetHeadPosition(); while (pos != NULL) { pemi = PlMenuItems()->GetNext(pos); ASSERT_VALID(pemi); if (pemi->NCommandID() == nCommandID) { pemiReturn = pemi; break; } // if: match was found } // while: more items in the list } // if: item list exists return pemiReturn; } //*** CExtensions::PemiFromCommandID() #ifdef _DEBUG ///////////////////////////////////////////////////////////////////////////// //++ // // CExtensions::PemiFromExtCommandID // // Routine Description: // Find the menu item for the specified extension command ID. // // Arguments: // nExtCommandID [IN] Extension command ID for the menu item. // // Return Value: // pemi Menu item or NULL if not found. // // Exceptions Thrown: // None. // //-- ///////////////////////////////////////////////////////////////////////////// CExtMenuItem * CExtensions::PemiFromExtCommandID(IN ULONG nExtCommandID) const { POSITION pos; CExtMenuItem * pemi; CExtMenuItem * pemiReturn = NULL; if (PlMenuItems() != NULL) { pos = PlMenuItems()->GetHeadPosition(); while (pos != NULL) { pemi = PlMenuItems()->GetNext(pos); ASSERT_VALID(pemi); if (pemi->NExtCommandID() == nExtCommandID) { pemiReturn = pemi; break; } // if: match was found } // while: more items in the list } // if: item list exists return pemiReturn; } //*** CExtensions::PemiFromExtCommandID() #endif //*************************************************************************// ///////////////////////////////////////////////////////////////////////////// // CComObject ///////////////////////////////////////////////////////////////////////////// IMPLEMENT_DYNAMIC(CExtensionDll, CObject); BEGIN_OBJECT_MAP(ObjectMap) OBJECT_ENTRY(CLSID_CoCluAdmin, CExtensionDll) END_OBJECT_MAP() ///////////////////////////////////////////////////////////////////////////// //++ // // CExtensionDll::CExtensionDll // // Routine Description: // Default constructor. // // Arguments: // None. // // Return Value: // None. // //-- ///////////////////////////////////////////////////////////////////////////// CExtensionDll::CExtensionDll(void) { m_piExtendPropSheet = NULL; m_piExtendWizard = NULL; m_piExtendContextMenu = NULL; m_piInvokeCommand = NULL; m_pext = NULL; m_pModuleState = AfxGetModuleState(); ASSERT(m_pModuleState != NULL); } //*** CExtensionDll::CExtensionDll() ///////////////////////////////////////////////////////////////////////////// //++ // // CExtensionDll::~CExtensionDll // // Routine Description: // Destructor. // // Arguments: // None. // // Return Value: // None. // //-- ///////////////////////////////////////////////////////////////////////////// CExtensionDll::~CExtensionDll(void) { UnloadExtension(); m_pModuleState = NULL; } //*** CExtensionDll::~CExtensionDll() ///////////////////////////////////////////////////////////////////////////// //++ // // CExtensionDll::Init // // Routine Description: // Initialize this class in preparation for accessing the extension. // // Arguments: // rstrCLSID [IN] CLSID of the extension in string form. // // Return Value: // None. // // Exceptions Thrown: // CNTException 0 (error converting CLSID from string) // Any exceptions thrown by CString::operater=(). // //-- ///////////////////////////////////////////////////////////////////////////// void CExtensionDll::Init( IN const CString & rstrCLSID, IN OUT CExtensions * pext ) { HRESULT hr; CWaitCursor wc; ASSERT_VALID(pext); Trace(g_tagExtDll, _T("Init() - CLSID = %s"), rstrCLSID); // Save parameters. ASSERT(StrCLSID().IsEmpty() || (StrCLSID() == rstrCLSID)); m_strCLSID = rstrCLSID; m_pext = pext; // Convert the CLSID string to a CLSID. hr = ::CLSIDFromString((LPWSTR) (LPCTSTR) rstrCLSID, &m_clsid); if (hr != S_OK) ThrowStaticException(hr, IDS_CLSIDFROMSTRING_ERROR, rstrCLSID); } //*** CExtensionDll::Init() ///////////////////////////////////////////////////////////////////////////// //++ // // CExtensionDll::LoadInterface // // Routine Description: // Load an extension DLL. // // Arguments: // riid [IN] Interface ID. // // Return Value: // piUnk IUnknown interface pointer for interface. // // Exceptions Thrown: // CNTException IDS_EXT_CREATE_INSTANCE_ERROR // //-- ///////////////////////////////////////////////////////////////////////////// IUnknown * CExtensionDll::LoadInterface(IN const REFIID riid) { HRESULT hr; IUnknown * piUnk; CWaitCursor wc; // Load the inproc server and get the IShellExtInit interface pointer. Trace(g_tagExtDllRef, _T("LoadInterface() - Getting interface pointer")); hr = ::CoCreateInstance( Rclsid(), NULL, CLSCTX_INPROC_SERVER, riid, (LPVOID *) &piUnk ); if ((hr != S_OK) && (hr != REGDB_E_CLASSNOTREG) && (hr != E_NOINTERFACE) ) ThrowStaticException(hr, IDS_EXT_CREATE_INSTANCE_ERROR, StrCLSID()); return piUnk; } //*** CExtensionDll::LoadInterface() ///////////////////////////////////////////////////////////////////////////// //++ // // CExtensionDll::UnloadExtension // // Routine Description: // Unload the extension DLL. // // Arguments: // None. // // Return Value: // None. // //-- ///////////////////////////////////////////////////////////////////////////// void CExtensionDll::UnloadExtension(void) { // Release the interface pointers in the opposite order in which they // were obtained. ReleaseInterface(&m_piExtendPropSheet); ReleaseInterface(&m_piExtendWizard); ReleaseInterface(&m_piExtendContextMenu); ReleaseInterface(&m_piInvokeCommand); m_strCLSID.Empty(); } //*** CExtensionDll::UnloadExtension() ///////////////////////////////////////////////////////////////////////////// //++ // // CExtensionDll::CreatePropertySheetPages // // Routine Description: // Add pages to a property sheet. // // Arguments: // None. // // Return Value: // None. // // Exceptions Thrown: // CNTException IDS_EXT_ADD_PAGES_ERROR // //-- ///////////////////////////////////////////////////////////////////////////// void CExtensionDll::CreatePropertySheetPages(void) { HRESULT hr; ASSERT_VALID(Pext()); ASSERT(m_piExtendPropSheet == NULL); // Load the interface. m_piExtendPropSheet = (interface IWEExtendPropertySheet *) LoadInterface(IID_IWEExtendPropertySheet); if (m_piExtendPropSheet == NULL) return; ASSERT(m_piExtendPropSheet != NULL); // Add pages from the extension. GetUnknown()->AddRef(); // Add a reference because extension is going to release. Pdo()->AddRef(); try { hr = PiExtendPropSheet()->CreatePropertySheetPages(Pdo()->GetUnknown(), this); } // try catch ( ... ) { hr = E_FAIL; } // catch if ((hr != NOERROR) && (hr != E_NOTIMPL)) ThrowStaticException(hr, IDS_EXT_ADD_PAGES_ERROR, StrCLSID()); } //*** CExtensionDll::CreatePropertySheetPages() ///////////////////////////////////////////////////////////////////////////// //++ // // CExtensionDll::CreateWizardPages // // Routine Description: // Add pages to a wizard. // // Arguments: // None. // // Return Value: // None. // // Exceptions Thrown: // CNTException IDS_EXT_ADD_PAGES_ERROR // //-- ///////////////////////////////////////////////////////////////////////////// void CExtensionDll::CreateWizardPages(void) { HRESULT hr; ASSERT_VALID(Pext()); ASSERT(m_piExtendWizard == NULL); ASSERT_VALID(Psht()); // Load the interface. m_piExtendWizard = (interface IWEExtendWizard *) LoadInterface(IID_IWEExtendWizard); if (m_piExtendWizard == NULL) return; ASSERT(m_piExtendWizard != NULL); // Add pages from the extension. GetUnknown()->AddRef(); // Add a reference because extension is going to release. Pdo()->AddRef(); try { hr = PiExtendWizard()->CreateWizardPages(Pdo()->GetUnknown(), this); } // try catch ( ... ) { hr = E_FAIL; } // catch if ((hr != NOERROR) && (hr != E_NOTIMPL)) ThrowStaticException(hr, IDS_EXT_ADD_PAGES_ERROR, StrCLSID()); } //*** CExtensionDll::CreateWizardPages() ///////////////////////////////////////////////////////////////////////////// //++ // // CExtensionDll::AddContextMenuItems // // Routine Description: // Ask the extension DLL to add items to the menu. // // Arguments: // None. // // Return Value: // None. // // Exceptions Thrown: // CNTException IDS_EXT_QUERY_CONTEXT_MENU_ERROR // //-- ///////////////////////////////////////////////////////////////////////////// void CExtensionDll::AddContextMenuItems(void) { HRESULT hr; ASSERT_VALID(Pext()); ASSERT_VALID(Pmenu()); ASSERT(m_piExtendContextMenu == NULL); // Load the interface. m_piExtendContextMenu = (interface IWEExtendContextMenu *) LoadInterface(IID_IWEExtendContextMenu); if (m_piExtendContextMenu == NULL) return; ASSERT(m_piExtendContextMenu != NULL); hr = PiExtendContextMenu()->QueryInterface(IID_IWEInvokeCommand, (LPVOID *) &m_piInvokeCommand); if (hr != NOERROR) { PiExtendContextMenu()->Release(); m_piExtendContextMenu = NULL; ThrowStaticException(hr, IDS_EXT_QUERY_CONTEXT_MENU_ERROR, StrCLSID()); } // if: error getting the InvokeCommand interface GetUnknown()->AddRef(); // Add a reference because extension is going to release. Pdo()->AddRef(); Trace(g_tagExtDll, _T("CExtensionDll::AddContextMenuItem() - Adding context menu items from '%s'"), StrCLSID()); try { hr = PiExtendContextMenu()->AddContextMenuItems(Pdo()->GetUnknown(), this); } // try catch ( ... ) { hr = E_FAIL; } // catch if (hr != NOERROR) ThrowStaticException(hr, IDS_EXT_QUERY_CONTEXT_MENU_ERROR, StrCLSID()); // Add a separator after the extension's items. Trace(g_tagExtDll, _T("CExtensionDll::AddContextMenuItem() - Adding separator")); try { hr = AddExtensionMenuItem(NULL, NULL, (ULONG) -1, 0, MF_SEPARATOR); } // try catch ( ... ) { hr = E_FAIL; } // catch if (hr != NOERROR) ThrowStaticException(hr, IDS_EXT_QUERY_CONTEXT_MENU_ERROR, StrCLSID()); } //*** CExtensionDll::AddContextMenuItems() ///////////////////////////////////////////////////////////////////////////// //++ // // CExtensionDll::InterfaceSupportsErrorInfo [ISupportsErrorInfo] // // Routine Description: // Determines whether the interface supports error info (???). // // Arguments: // riid [IN] Reference to the interface ID. // // Return Value: // S_OK Interface supports error info. // S_FALSE Interface does not support error info. // // Exceptions Thrown: // None. // //-- ///////////////////////////////////////////////////////////////////////////// STDMETHODIMP CExtensionDll::InterfaceSupportsErrorInfo(REFIID riid) { static const IID * rgiid[] = { &IID_IWCPropertySheetCallback, &IID_IWCWizardCallback, &IID_IWCContextMenuCallback, }; int iiid; for (iiid = 0 ; iiid < sizeof(rgiid) / sizeof(rgiid[0]) ; iiid++) { if (InlineIsEqualGUID(*rgiid[iiid], riid)) return S_OK; } return S_FALSE; } //*** CExtensionDll::InterfaceSupportsErrorInfo() ///////////////////////////////////////////////////////////////////////////// //++ // // CExtensionDll::AddPropertySheetPage [IWCPropertySheetCallback] // // Routine Description: // Add a page to the property sheet. // // Arguments: // hpage [IN] Page to add. // // Return Value: // NOERROR Page added successfully. // E_INVALIDARG NULL hpage. // Any hresult returned from CBasePropertySheet::HrAddPage(). // // Exceptions Thrown: // None. // //-- ///////////////////////////////////////////////////////////////////////////// STDMETHODIMP CExtensionDll::AddPropertySheetPage( IN LONG * hpage ) { HRESULT hr = NOERROR; AFX_MANAGE_STATE(m_pModuleState); ASSERT(hpage != NULL); ASSERT_VALID(Psht()); // Do this for the release build. if ((hpage == NULL) || (Psht() == NULL)) hr = E_INVALIDARG; else hr = Psht()->HrAddPage((HPROPSHEETPAGE) hpage); return hr; } //*** CExtensionDll::AddPropertySheetPage() ///////////////////////////////////////////////////////////////////////////// //++ // // CExtensionDll::AddWizardPage [IWCWizardCallback] // // Routine Description: // Add a page to the wizard. // // Arguments: // hpage [IN] Page to add. // // Return Value: // NOERROR Page added successfully. // E_INVALIDARG NULL hpage. // Any hresult returned from CBaseSheet::HrAddPage(). // // Exceptions Thrown: // None. // //-- ///////////////////////////////////////////////////////////////////////////// STDMETHODIMP CExtensionDll::AddWizardPage( IN LONG * hpage ) { HRESULT hr = NOERROR; AFX_MANAGE_STATE(m_pModuleState); ASSERT(hpage != NULL); ASSERT_VALID(Psht()); // Do this for the release build. if ((hpage == NULL) || (Psht() == NULL)) hr = E_INVALIDARG; else hr = Psht()->HrAddPage((HPROPSHEETPAGE) hpage); return hr; } //*** CExtensionDll::AddWizardPage() ///////////////////////////////////////////////////////////////////////////// //++ // // CExtensionDll::EnableNext [IWCWizardCallback] // // Routine Description: // Enable or disable the NEXT button. If it is the last page, the // FINISH button will be enabled or disabled. // // Arguments: // hpage [IN] Page for which the button is being enabled or // disabled. // bEnable [IN] TRUE = Enable the button, FALSE = disable. // // Return Value: // NOERROR Success. // E_INVALIDARG Unknown hpage specified. // // Exceptions Thrown: // None. // //-- ///////////////////////////////////////////////////////////////////////////// STDMETHODIMP CExtensionDll::EnableNext( IN LONG * hpage, IN BOOL bEnable ) { HRESULT hr = NOERROR; CBaseWizard * pwiz; DWORD dwWizButtons; AFX_MANAGE_STATE(m_pModuleState); ASSERT(hpage != NULL); ASSERT_VALID(Psht()); ASSERT_KINDOF(CBaseWizard, Psht()); pwiz = (CBaseWizard *) Psht(); // If this is the last extension page, enable/disable the FINISH button. { POSITION pos; BOOL bMatch = FALSE; pos = pwiz->Lhpage().GetHeadPosition(); while (pos != NULL) { if (pwiz->Lhpage().GetNext(pos) == hpage) { bMatch = TRUE; break; } // if: found a match } // while: more items in the list if (!bMatch) return E_INVALIDARG; if (pos == NULL) dwWizButtons = PSWIZB_BACK | (bEnable ? PSWIZB_FINISH : PSWIZB_DISABLEDFINISH); else dwWizButtons = PSWIZB_BACK | (bEnable ? PSWIZB_NEXT : 0); } // If this is the last extension page, set the FINISH button // Set wizard buttons. pwiz->SetWizardButtons(dwWizButtons); return hr; } //*** CExtensionDll::EnableNext() ///////////////////////////////////////////////////////////////////////////// //++ // // CExtensionDll::AddExtensionMenuItem [IWCContextMenuCallback] // // Routine Description: // Add a page to the wizard. // // Arguments: // lpszName [IN] Name of item. // lpszStatusBarText [IN] Text to appear on the status bar when the // item is highlighted. // nCommandID [IN] ID for the command when menu item is invoked. // Must not be -1. // nSubmenuCommandID [IN] ID for a submenu. // uFlags [IN] Menu flags. The following are not supportd: // MF_OWNERDRAW, MF_POPUP // // Return Value: // NOERROR Item added successfully. // E_INVALIDARG MF_OWNERDRAW or MF_POPUP were specified. // E_OUTOFMEMORY Error allocating the item. // // Exceptions Thrown: // None. // //-- ///////////////////////////////////////////////////////////////////////////// STDMETHODIMP CExtensionDll::AddExtensionMenuItem( IN BSTR lpszName, IN BSTR lpszStatusBarText, IN ULONG nCommandID, IN ULONG nSubmenuCommandID, IN ULONG uFlags ) { HRESULT hr = NOERROR; CExtMenuItem * pemi = NULL; AFX_MANAGE_STATE( m_pModuleState ); UNREFERENCED_PARAMETER( nSubmenuCommandID ); ASSERT_VALID( Pext() ); ASSERT( ! ( uFlags & (MF_OWNERDRAW | MF_POPUP) ) ); ASSERT_VALID( Pmenu() ); // Do this for the release build. if ( ( uFlags & (MF_OWNERDRAW | MF_POPUP) ) != 0 ) { hr = E_INVALIDARG; } // if: trying to add invalid type of menu item else { ASSERT( Pext()->PemiFromExtCommandID( nCommandID ) == NULL ); try { Trace( g_tagExtDll, _T("CExtensionDll::AddExtensionMenuItem() - Adding menu item '%s', ExtID = %d"), lpszName, nCommandID ); // Allocate a new item. pemi = new CExtMenuItem( OLE2CT( lpszName ), OLE2CT( lpszStatusBarText ), nCommandID, NNextCommandID(), NNextMenuID(), uFlags, FALSE, /*bMakeDefault*/ PiInvokeCommand() ); if ( pemi == NULL ) { AfxThrowMemoryException(); } // if: error allocating memory // Insert the item in the menu. if ( ! Pmenu()->InsertMenu( NNextMenuID(), MF_BYPOSITION | uFlags, NNextCommandID(), pemi->StrName() ) ) { ThrowStaticException( ::GetLastError(), IDS_INSERT_MENU_ERROR, pemi->StrName() ); } // if: error inserting the menu item // Add the item to the tail of the list. Pext()->PlMenuItems()->AddTail( pemi ); pemi = NULL; // Update the counters. Pext()->m_nNextCommandID++; Pext()->m_nNextMenuID++; } // try catch ( CNTException * pnte ) { hr = pnte->Sc(); pnte->ReportError(); pnte->Delete(); } // catch: CException catch ( CException * pe ) { hr = E_OUTOFMEMORY; pe->ReportError(); pe->Delete(); } // catch: CException } // else: we can add the item delete pemi; return hr; } //*** CExtensionDll::AddExtensionMenuItem()