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

1374 lines
37 KiB

  1. /////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1996-2000 Microsoft Corporation
  4. //
  5. // Module Name:
  6. // ExtDll.cpp
  7. //
  8. // Abstract:
  9. // Implementation of the extension DLL classes.
  10. //
  11. // Author:
  12. // David Potter (davidp) May 31, 1996
  13. //
  14. // Revision History:
  15. //
  16. // Notes:
  17. //
  18. /////////////////////////////////////////////////////////////////////////////
  19. #include "stdafx.h"
  20. #include <CluAdmEx.h>
  21. #include "CluAdmID.h"
  22. #include "ExtDll.h"
  23. #include "CluAdmin.h"
  24. #include "ExtMenu.h"
  25. #include "TraceTag.h"
  26. #include "ExcOper.h"
  27. #include "ClusItem.h"
  28. #include "BaseSht.h"
  29. #include "BasePSht.h"
  30. #include "BaseWiz.h"
  31. #ifdef _DEBUG
  32. #define new DEBUG_NEW
  33. #undef THIS_FILE
  34. static char THIS_FILE[] = __FILE__;
  35. #endif
  36. /////////////////////////////////////////////////////////////////////////////
  37. // Global Variables
  38. /////////////////////////////////////////////////////////////////////////////
  39. #ifdef _DEBUG
  40. CTraceTag g_tagExtDll(_T("UI"), _T("EXTENSION DLL"), 0);
  41. CTraceTag g_tagExtDllRef(_T("UI"), _T("EXTENSION DLL References"), 0);
  42. #endif
  43. /////////////////////////////////////////////////////////////////////////////
  44. // CExtensions
  45. /////////////////////////////////////////////////////////////////////////////
  46. IMPLEMENT_DYNAMIC(CExtensions, CObject);
  47. /////////////////////////////////////////////////////////////////////////////
  48. //++
  49. //
  50. // CExtensions::CExtensions
  51. //
  52. // Routine Description:
  53. // Default constructor.
  54. //
  55. // Arguments:
  56. // None.
  57. //
  58. // Return Value:
  59. // None.
  60. //
  61. //--
  62. /////////////////////////////////////////////////////////////////////////////
  63. CExtensions::CExtensions(void)
  64. {
  65. m_pci = NULL;
  66. m_hfont = NULL;
  67. m_hicon = NULL;
  68. m_pdoData = NULL;
  69. m_plextdll = NULL;
  70. m_psht = NULL;
  71. m_pmenu = NULL;
  72. m_plMenuItems = NULL;
  73. m_nFirstCommandID = (ULONG) -1;
  74. m_nNextCommandID = (ULONG) -1;
  75. m_nFirstMenuID = (ULONG) -1;
  76. m_nNextMenuID = (ULONG) -1;
  77. } //*** CExtensions::CExtensions()
  78. /////////////////////////////////////////////////////////////////////////////
  79. //++
  80. //
  81. // CExtensions::~CExtensions
  82. //
  83. // Routine Description:
  84. // Destructor.
  85. //
  86. // Arguments:
  87. // None.
  88. //
  89. // Return Value:
  90. // None.
  91. //
  92. //--
  93. /////////////////////////////////////////////////////////////////////////////
  94. CExtensions::~CExtensions(void)
  95. {
  96. UnloadExtensions();
  97. } //*** CExtensions::~CExtensions()
  98. /////////////////////////////////////////////////////////////////////////////
  99. //++
  100. //
  101. // CExtensions::Init
  102. //
  103. // Routine Description:
  104. // Common initialize for all interfaces.
  105. //
  106. // Arguments:
  107. // rlstrExtensions [IN] List of extension CLSID strings.
  108. // pci [IN OUT] Cluster item to be administered.
  109. // hfont [IN] Font for dialog text.
  110. // hicon [IN] Icon for upper left corner.
  111. //
  112. // Return Value:
  113. // None.
  114. //
  115. // Exceptions Thrown:
  116. // Any exceptions thrown by new.
  117. //
  118. //--
  119. /////////////////////////////////////////////////////////////////////////////
  120. void CExtensions::Init(
  121. IN const CStringList & rlstrExtensions,
  122. IN OUT CClusterItem * pci,
  123. IN HFONT hfont,
  124. IN HICON hicon
  125. )
  126. {
  127. CWaitCursor wc;
  128. ASSERT( rlstrExtensions.GetCount() > 0 );
  129. UnloadExtensions();
  130. // Save parameters.
  131. m_plstrExtensions = &rlstrExtensions;
  132. m_pci = pci;
  133. m_hfont = hfont;
  134. m_hicon = hicon;
  135. // Allocate a new Data Object.
  136. m_pdoData = new CComObject< CDataObject >;
  137. if ( m_pdoData == NULL )
  138. {
  139. AfxThrowMemoryException();
  140. } // if: error allocating memory
  141. m_pdoData->AddRef();
  142. // Construct the Data Object.
  143. Pdo()->Init( pci, GetClusterAdminApp()->Lcid(), hfont, hicon );
  144. // Allocate the extension list.
  145. m_plextdll = new CExtDllList;
  146. if ( m_plextdll == NULL )
  147. {
  148. AfxThrowMemoryException();
  149. } // if: error allocating memory
  150. ASSERT( Plextdll() != NULL );
  151. // Loop through the extensions and load each one.
  152. {
  153. CComObject<CExtensionDll> * pextdll = NULL;
  154. POSITION posName;
  155. Trace( g_tagExtDll, _T("CExtensions::Init() - %d extensions"), rlstrExtensions.GetCount() );
  156. posName = rlstrExtensions.GetHeadPosition();
  157. while ( posName != NULL )
  158. {
  159. // Allocate an extension DLL object and add it to the list.
  160. pextdll = new CComObject< CExtensionDll >;
  161. if ( pextdll == NULL )
  162. {
  163. AfxThrowMemoryException();
  164. } // if: error allocating memory
  165. pextdll->AddRef();
  166. Plextdll()->AddTail( pextdll );
  167. try
  168. {
  169. pextdll->Init( rlstrExtensions.GetNext( posName ), this );
  170. } // try
  171. catch ( CException * pe )
  172. {
  173. POSITION pos;
  174. pe->ReportError();
  175. pe->Delete();
  176. pos = Plextdll()->Find(pextdll);
  177. ASSERT( pos != NULL );
  178. Plextdll()->RemoveAt( pos );
  179. delete pextdll;
  180. } // catch: anything
  181. } // while: more items in the list
  182. } // Loop through the extensions and load each one
  183. } //*** CExtensions::Init()
  184. /////////////////////////////////////////////////////////////////////////////
  185. //++
  186. //
  187. // CExtensions::UnloadExtensions
  188. //
  189. // Routine Description:
  190. // Unload the extension DLL.
  191. //
  192. // Arguments:
  193. // None.
  194. //
  195. // Return Value:
  196. // None.
  197. //
  198. //--
  199. /////////////////////////////////////////////////////////////////////////////
  200. void CExtensions::UnloadExtensions(void)
  201. {
  202. // Delete all the extension DLL objects.
  203. if (Plextdll() != NULL)
  204. {
  205. POSITION pos;
  206. CComObject<CExtensionDll> * pextdll;
  207. pos = Plextdll()->GetHeadPosition();
  208. while (pos != NULL)
  209. {
  210. pextdll = Plextdll()->GetNext(pos);
  211. pextdll->AddRef(); // See comment below.
  212. pextdll->UnloadExtension();
  213. if (pextdll->m_dwRef != 2)
  214. {
  215. Trace(g_tagError, _T("CExtensions::UnloadExtensions() - Extension DLL has ref count = %d"), pextdll->m_dwRef);
  216. }
  217. // We added a reference above. Combined with the reference that
  218. // was added when the object was created, we typically will need
  219. // to release two references. However, due to bogus code
  220. // generated by earlier versions of the custom AppWizard where the
  221. // extension was releasing the interface but not zeroing out its
  222. // pointer in the error case, we may not need to release the
  223. // second reference.
  224. if (pextdll->Release() != 0)
  225. {
  226. pextdll->Release();
  227. } // if: more references to release
  228. } // while: more items in the list
  229. delete m_plextdll;
  230. m_plextdll = NULL;
  231. } // if: there is a list of extensions
  232. if (m_pdoData != NULL)
  233. {
  234. if (m_pdoData->m_dwRef != 1)
  235. {
  236. Trace(g_tagError, _T("CExtensions::UnloadExtensions() - Data Object has ref count = %d"), m_pdoData->m_dwRef);
  237. }
  238. m_pdoData->Release();
  239. m_pdoData = NULL;
  240. } // if: data object allocated
  241. m_pci = NULL;
  242. m_hfont = NULL;
  243. m_hicon = NULL;
  244. // Delete all menu items.
  245. if (PlMenuItems() != NULL)
  246. {
  247. POSITION pos;
  248. CExtMenuItem * pemi;
  249. pos = PlMenuItems()->GetHeadPosition();
  250. while (pos != NULL)
  251. {
  252. pemi = PlMenuItems()->GetNext(pos);
  253. delete pemi;
  254. } // while: more items in the list
  255. delete m_plMenuItems;
  256. m_plMenuItems = NULL;
  257. } // if: there is a list of menu items
  258. } //*** CExtensions::UnloadExtensions()
  259. /////////////////////////////////////////////////////////////////////////////
  260. //++
  261. //
  262. // CExtensions::CreatePropertySheetPages
  263. //
  264. // Routine Description:
  265. // Add pages to a property sheet.
  266. //
  267. // Arguments:
  268. // psht [IN OUT] Property sheet to which pages are to be added.
  269. // rlstrExtensions [IN] List of extension CLSID strings.
  270. // pci [IN OUT] Cluster item to be administered.
  271. // hfont [IN] Font for dialog text.
  272. // hicon [IN] Icon for upper left corner.
  273. //
  274. // Return Value:
  275. // None.
  276. //
  277. // Exceptions Thrown:
  278. // Any exceptions thrown by CExtensionDll::AddPages().
  279. //
  280. //--
  281. /////////////////////////////////////////////////////////////////////////////
  282. void CExtensions::CreatePropertySheetPages(
  283. IN OUT CBasePropertySheet * psht,
  284. IN const CStringList & rlstrExtensions,
  285. IN OUT CClusterItem * pci,
  286. IN HFONT hfont,
  287. IN HICON hicon
  288. )
  289. {
  290. POSITION pos;
  291. CComObject<CExtensionDll> * pextdll;
  292. ASSERT_VALID(psht);
  293. m_psht = psht;
  294. // Initialize for all extensions.
  295. Init(rlstrExtensions, pci, hfont, hicon);
  296. ASSERT(Plextdll() != NULL);
  297. pos = Plextdll()->GetHeadPosition();
  298. while (pos != NULL)
  299. {
  300. pextdll = Plextdll()->GetNext(pos);
  301. ASSERT_VALID(pextdll);
  302. try
  303. {
  304. pextdll->CreatePropertySheetPages();
  305. } // try
  306. catch (CException * pe)
  307. {
  308. pe->ReportError();
  309. pe->Delete();
  310. } // catch: CNTException
  311. } // while: more items in the list
  312. } //*** CExtensions::CreatePropertySheetPages()
  313. /////////////////////////////////////////////////////////////////////////////
  314. //++
  315. //
  316. // CExtensions::CreateWizardPages
  317. //
  318. // Routine Description:
  319. // Add pages to a wizard.
  320. //
  321. // Arguments:
  322. // psht [IN OUT] Property sheet to which pages are to be added.
  323. // rlstrExtensions [IN] List of extension CLSID strings.
  324. // pci [IN OUT] Cluster item to be administered.
  325. // hfont [IN] Font for dialog text.
  326. // hicon [IN] Icon for upper left corner.
  327. //
  328. // Return Value:
  329. // None.
  330. //
  331. // Exceptions Thrown:
  332. // Any exceptions thrown by CExtensionDll::AddPages().
  333. //
  334. //--
  335. /////////////////////////////////////////////////////////////////////////////
  336. void CExtensions::CreateWizardPages(
  337. IN OUT CBaseWizard * psht,
  338. IN const CStringList & rlstrExtensions,
  339. IN OUT CClusterItem * pci,
  340. IN HFONT hfont,
  341. IN HICON hicon
  342. )
  343. {
  344. POSITION pos;
  345. CComObject<CExtensionDll> * pextdll;
  346. ASSERT_VALID(psht);
  347. m_psht = psht;
  348. // Initialize for all extensions.
  349. Init(rlstrExtensions, pci, hfont, hicon);
  350. ASSERT(Plextdll() != NULL);
  351. pos = Plextdll()->GetHeadPosition();
  352. while (pos != NULL)
  353. {
  354. pextdll = Plextdll()->GetNext(pos);
  355. ASSERT_VALID(pextdll);
  356. try
  357. {
  358. pextdll->CreateWizardPages();
  359. } // try
  360. catch (CException * pe)
  361. {
  362. pe->ReportError();
  363. pe->Delete();
  364. } // catch: CNTException
  365. } // while: more items in the list
  366. } //*** CExtensions::CreateWizardPages()
  367. /////////////////////////////////////////////////////////////////////////////
  368. //++
  369. //
  370. // CExtensions::AddContextMenuItems
  371. //
  372. // Routine Description:
  373. // Query the extension DLL for new menu items to be added to the context
  374. // menu.
  375. //
  376. // Arguments:
  377. // pmenu [IN OUT] Menu to which items are to be added.
  378. // rlstrExtensions [IN] List of extension CLSID strings.
  379. // pci [IN OUT] Cluster item to be administered.
  380. //
  381. // Return Value:
  382. // None.
  383. //
  384. // Exceptions Thrown:
  385. // Any exceptions thrown by CExtensionDll::AddContextMenuItems() or
  386. // CExtMenuItemList::new().
  387. //
  388. //--
  389. /////////////////////////////////////////////////////////////////////////////
  390. void CExtensions::AddContextMenuItems(
  391. IN OUT CMenu * pmenu,
  392. IN const CStringList & rlstrExtensions,
  393. IN OUT CClusterItem * pci
  394. )
  395. {
  396. POSITION pos;
  397. CComObject< CExtensionDll > * pextdll;
  398. ASSERT(m_pmenu == NULL);
  399. ASSERT_VALID(pmenu);
  400. // Initialize for all extensions.
  401. Init( rlstrExtensions, pci, NULL, NULL );
  402. ASSERT( Plextdll() != NULL );
  403. m_pmenu = pmenu;
  404. m_nFirstCommandID = CAEXT_MENU_FIRST_ID;
  405. m_nNextCommandID = m_nFirstCommandID;
  406. m_nFirstMenuID = 0;
  407. m_nNextMenuID = m_nFirstMenuID;
  408. // Create the list of menu items.
  409. ASSERT( m_plMenuItems == NULL );
  410. m_plMenuItems = new CExtMenuItemList;
  411. if ( m_plMenuItems == NULL )
  412. {
  413. AfxThrowMemoryException();
  414. } // if: error allocating memory
  415. pos = Plextdll()->GetHeadPosition();
  416. while ( pos != NULL )
  417. {
  418. pextdll = Plextdll()->GetNext( pos );
  419. ASSERT_VALID( pextdll );
  420. try
  421. {
  422. pextdll->AddContextMenuItems();
  423. } // try
  424. catch ( CException * pe )
  425. {
  426. pe->ReportError();
  427. pe->Delete();
  428. } // catch: CNTException
  429. } // while: more items in the list
  430. } //*** CExtensions::AddContextMenuItems()
  431. /////////////////////////////////////////////////////////////////////////////
  432. //++
  433. //
  434. // CExtensions::BExecuteContextMenuItem
  435. //
  436. // Routine Description:
  437. // Execute a command associated with a menu item added to a context menu
  438. // by the extension DLL.
  439. //
  440. // Arguments:
  441. // nCommandID [IN] Command ID for the menu item chosen by the user.
  442. //
  443. // Return Value:
  444. // TRUE Context menu item was executed.
  445. // FALSE Context menu item was not executed.
  446. //
  447. // Exceptions Thrown:
  448. // Any exceptions thrown by CExceptionDll::BExecuteContextMenuItem().
  449. //
  450. //--
  451. /////////////////////////////////////////////////////////////////////////////
  452. BOOL CExtensions::BExecuteContextMenuItem(IN ULONG nCommandID)
  453. {
  454. BOOL bHandled = FALSE;
  455. HRESULT hr;
  456. CExtMenuItem * pemi;
  457. // Find the item in our list.
  458. pemi = PemiFromCommandID(nCommandID);
  459. if (pemi != NULL)
  460. {
  461. Pdo()->AddRef();
  462. hr = pemi->PiCommand()->InvokeCommand(pemi->NExtCommandID(), Pdo()->GetUnknown());
  463. if (hr == NOERROR)
  464. bHandled = TRUE;
  465. } // if: found an item for the command ID
  466. return bHandled;
  467. } //*** CExtensions::BExecuteContextMenuItem()
  468. /////////////////////////////////////////////////////////////////////////////
  469. //++
  470. //
  471. // CExtensions::BGetCommandString
  472. //
  473. // Routine Description:
  474. // Get a command string from a menu ID.
  475. //
  476. // Arguments:
  477. // nCommandID [IN] Command ID for the menu item.
  478. // rstrMessage [OUT] String in which to return the message.
  479. //
  480. // Return Value:
  481. // TRUE String is being returned.
  482. // FALSE No string is being returned.
  483. //
  484. // Exceptions Thrown:
  485. // Any exceptions thrown by CExtensionDll::BGetCommandString().
  486. //
  487. //--
  488. /////////////////////////////////////////////////////////////////////////////
  489. BOOL CExtensions::BGetCommandString(
  490. IN ULONG nCommandID,
  491. OUT CString & rstrMessage
  492. )
  493. {
  494. BOOL bHandled = FALSE;
  495. CExtMenuItem * pemi;
  496. // Find the item in our list.
  497. pemi = PemiFromCommandID(nCommandID);
  498. if (pemi != NULL)
  499. {
  500. rstrMessage = pemi->StrStatusBarText();
  501. bHandled = TRUE;
  502. } // if: found an item for the command ID
  503. return bHandled;
  504. } //*** CExtensions::BGetCommandString()
  505. /////////////////////////////////////////////////////////////////////////////
  506. //++
  507. //
  508. // CExtensions::OnUpdateCommand
  509. //
  510. // Routine Description:
  511. // Determines whether extension DLL menu items should be enabled or not.
  512. //
  513. // Arguments:
  514. // pCmdUI [IN OUT] Command routing object.
  515. //
  516. // Return Value:
  517. // None.
  518. //
  519. // Exceptions Thrown:
  520. // Any exceptions thrown by CExtensionDll::BOnUpdateCommand().
  521. //
  522. //--
  523. /////////////////////////////////////////////////////////////////////////////
  524. void CExtensions::OnUpdateCommand(CCmdUI * pCmdUI)
  525. {
  526. CExtMenuItem * pemi;
  527. ASSERT(Plextdll() != NULL);
  528. // Find the item in our list.
  529. Trace(g_tagExtDll, _T("OnUpdateCommand() - ID = %d"), pCmdUI->m_nID);
  530. pemi = PemiFromCommandID(pCmdUI->m_nID);
  531. if (pemi != NULL)
  532. {
  533. Trace(g_tagExtDll, _T("OnUpdateCommand() - Found a match with '%s' ExtID = %d"), pemi->StrName(), pemi->NExtCommandID());
  534. pCmdUI->Enable();
  535. } // if: found an item for the command ID
  536. } //*** CExtensions::OnUpdateCommand()
  537. /////////////////////////////////////////////////////////////////////////////
  538. //++
  539. //
  540. // CExtensions::OnCmdMsg
  541. //
  542. // Routine Description:
  543. // Processes command messages. Attempts to pass them on to a selected
  544. // item first.
  545. //
  546. // Arguments:
  547. // nID [IN] Command ID.
  548. // nCode [IN] Notification code.
  549. // pExtra [IN OUT] Used according to the value of nCode.
  550. // pHandlerInfo [OUT] ???
  551. //
  552. // Return Value:
  553. // TRUE Message has been handled.
  554. // FALSE Message has NOT been handled.
  555. //
  556. //--
  557. /////////////////////////////////////////////////////////////////////////////
  558. BOOL CExtensions::OnCmdMsg(
  559. UINT nID,
  560. int nCode,
  561. void * pExtra,
  562. AFX_CMDHANDLERINFO * pHandlerInfo
  563. )
  564. {
  565. return BExecuteContextMenuItem(nID);
  566. } //*** CExtensions::OnCmdMsg()
  567. /////////////////////////////////////////////////////////////////////////////
  568. //++
  569. //
  570. // CExtensions::PemiFromCommandID
  571. //
  572. // Routine Description:
  573. // Find the menu item for the specified command ID.
  574. //
  575. // Arguments:
  576. // nCommandID [IN] Command ID for the menu item.
  577. //
  578. // Return Value:
  579. // pemi Menu item or NULL if not found.
  580. //
  581. // Exceptions Thrown:
  582. // None.
  583. //
  584. //--
  585. /////////////////////////////////////////////////////////////////////////////
  586. CExtMenuItem * CExtensions::PemiFromCommandID(IN ULONG nCommandID) const
  587. {
  588. POSITION pos;
  589. CExtMenuItem * pemi;
  590. CExtMenuItem * pemiReturn = NULL;
  591. if (PlMenuItems() != NULL)
  592. {
  593. pos = PlMenuItems()->GetHeadPosition();
  594. while (pos != NULL)
  595. {
  596. pemi = PlMenuItems()->GetNext(pos);
  597. ASSERT_VALID(pemi);
  598. if (pemi->NCommandID() == nCommandID)
  599. {
  600. pemiReturn = pemi;
  601. break;
  602. } // if: match was found
  603. } // while: more items in the list
  604. } // if: item list exists
  605. return pemiReturn;
  606. } //*** CExtensions::PemiFromCommandID()
  607. #ifdef _DEBUG
  608. /////////////////////////////////////////////////////////////////////////////
  609. //++
  610. //
  611. // CExtensions::PemiFromExtCommandID
  612. //
  613. // Routine Description:
  614. // Find the menu item for the specified extension command ID.
  615. //
  616. // Arguments:
  617. // nExtCommandID [IN] Extension command ID for the menu item.
  618. //
  619. // Return Value:
  620. // pemi Menu item or NULL if not found.
  621. //
  622. // Exceptions Thrown:
  623. // None.
  624. //
  625. //--
  626. /////////////////////////////////////////////////////////////////////////////
  627. CExtMenuItem * CExtensions::PemiFromExtCommandID(IN ULONG nExtCommandID) const
  628. {
  629. POSITION pos;
  630. CExtMenuItem * pemi;
  631. CExtMenuItem * pemiReturn = NULL;
  632. if (PlMenuItems() != NULL)
  633. {
  634. pos = PlMenuItems()->GetHeadPosition();
  635. while (pos != NULL)
  636. {
  637. pemi = PlMenuItems()->GetNext(pos);
  638. ASSERT_VALID(pemi);
  639. if (pemi->NExtCommandID() == nExtCommandID)
  640. {
  641. pemiReturn = pemi;
  642. break;
  643. } // if: match was found
  644. } // while: more items in the list
  645. } // if: item list exists
  646. return pemiReturn;
  647. } //*** CExtensions::PemiFromExtCommandID()
  648. #endif
  649. //*************************************************************************//
  650. /////////////////////////////////////////////////////////////////////////////
  651. // CComObject<CExtensionDll>
  652. /////////////////////////////////////////////////////////////////////////////
  653. IMPLEMENT_DYNAMIC(CExtensionDll, CObject);
  654. BEGIN_OBJECT_MAP(ObjectMap)
  655. OBJECT_ENTRY(CLSID_CoCluAdmin, CExtensionDll)
  656. END_OBJECT_MAP()
  657. /////////////////////////////////////////////////////////////////////////////
  658. //++
  659. //
  660. // CExtensionDll::CExtensionDll
  661. //
  662. // Routine Description:
  663. // Default constructor.
  664. //
  665. // Arguments:
  666. // None.
  667. //
  668. // Return Value:
  669. // None.
  670. //
  671. //--
  672. /////////////////////////////////////////////////////////////////////////////
  673. CExtensionDll::CExtensionDll(void)
  674. {
  675. m_piExtendPropSheet = NULL;
  676. m_piExtendWizard = NULL;
  677. m_piExtendContextMenu = NULL;
  678. m_piInvokeCommand = NULL;
  679. m_pext = NULL;
  680. m_pModuleState = AfxGetModuleState();
  681. ASSERT(m_pModuleState != NULL);
  682. } //*** CExtensionDll::CExtensionDll()
  683. /////////////////////////////////////////////////////////////////////////////
  684. //++
  685. //
  686. // CExtensionDll::~CExtensionDll
  687. //
  688. // Routine Description:
  689. // Destructor.
  690. //
  691. // Arguments:
  692. // None.
  693. //
  694. // Return Value:
  695. // None.
  696. //
  697. //--
  698. /////////////////////////////////////////////////////////////////////////////
  699. CExtensionDll::~CExtensionDll(void)
  700. {
  701. UnloadExtension();
  702. m_pModuleState = NULL;
  703. } //*** CExtensionDll::~CExtensionDll()
  704. /////////////////////////////////////////////////////////////////////////////
  705. //++
  706. //
  707. // CExtensionDll::Init
  708. //
  709. // Routine Description:
  710. // Initialize this class in preparation for accessing the extension.
  711. //
  712. // Arguments:
  713. // rstrCLSID [IN] CLSID of the extension in string form.
  714. //
  715. // Return Value:
  716. // None.
  717. //
  718. // Exceptions Thrown:
  719. // CNTException 0 (error converting CLSID from string)
  720. // Any exceptions thrown by CString::operater=().
  721. //
  722. //--
  723. /////////////////////////////////////////////////////////////////////////////
  724. void CExtensionDll::Init(
  725. IN const CString & rstrCLSID,
  726. IN OUT CExtensions * pext
  727. )
  728. {
  729. HRESULT hr;
  730. CWaitCursor wc;
  731. ASSERT_VALID(pext);
  732. Trace(g_tagExtDll, _T("Init() - CLSID = %s"), rstrCLSID);
  733. // Save parameters.
  734. ASSERT(StrCLSID().IsEmpty() || (StrCLSID() == rstrCLSID));
  735. m_strCLSID = rstrCLSID;
  736. m_pext = pext;
  737. // Convert the CLSID string to a CLSID.
  738. hr = ::CLSIDFromString((LPWSTR) (LPCTSTR) rstrCLSID, &m_clsid);
  739. if (hr != S_OK)
  740. ThrowStaticException(hr, IDS_CLSIDFROMSTRING_ERROR, rstrCLSID);
  741. } //*** CExtensionDll::Init()
  742. /////////////////////////////////////////////////////////////////////////////
  743. //++
  744. //
  745. // CExtensionDll::LoadInterface
  746. //
  747. // Routine Description:
  748. // Load an extension DLL.
  749. //
  750. // Arguments:
  751. // riid [IN] Interface ID.
  752. //
  753. // Return Value:
  754. // piUnk IUnknown interface pointer for interface.
  755. //
  756. // Exceptions Thrown:
  757. // CNTException IDS_EXT_CREATE_INSTANCE_ERROR
  758. //
  759. //--
  760. /////////////////////////////////////////////////////////////////////////////
  761. IUnknown * CExtensionDll::LoadInterface(IN const REFIID riid)
  762. {
  763. HRESULT hr;
  764. IUnknown * piUnk;
  765. CWaitCursor wc;
  766. // Load the inproc server and get the IShellExtInit interface pointer.
  767. Trace(g_tagExtDllRef, _T("LoadInterface() - Getting interface pointer"));
  768. hr = ::CoCreateInstance(
  769. Rclsid(),
  770. NULL,
  771. CLSCTX_INPROC_SERVER,
  772. riid,
  773. (LPVOID *) &piUnk
  774. );
  775. if ((hr != S_OK)
  776. && (hr != REGDB_E_CLASSNOTREG)
  777. && (hr != E_NOINTERFACE)
  778. )
  779. ThrowStaticException(hr, IDS_EXT_CREATE_INSTANCE_ERROR, StrCLSID());
  780. return piUnk;
  781. } //*** CExtensionDll::LoadInterface()
  782. /////////////////////////////////////////////////////////////////////////////
  783. //++
  784. //
  785. // CExtensionDll::UnloadExtension
  786. //
  787. // Routine Description:
  788. // Unload the extension DLL.
  789. //
  790. // Arguments:
  791. // None.
  792. //
  793. // Return Value:
  794. // None.
  795. //
  796. //--
  797. /////////////////////////////////////////////////////////////////////////////
  798. void CExtensionDll::UnloadExtension(void)
  799. {
  800. // Release the interface pointers in the opposite order in which they
  801. // were obtained.
  802. ReleaseInterface(&m_piExtendPropSheet);
  803. ReleaseInterface(&m_piExtendWizard);
  804. ReleaseInterface(&m_piExtendContextMenu);
  805. ReleaseInterface(&m_piInvokeCommand);
  806. m_strCLSID.Empty();
  807. } //*** CExtensionDll::UnloadExtension()
  808. /////////////////////////////////////////////////////////////////////////////
  809. //++
  810. //
  811. // CExtensionDll::CreatePropertySheetPages
  812. //
  813. // Routine Description:
  814. // Add pages to a property sheet.
  815. //
  816. // Arguments:
  817. // None.
  818. //
  819. // Return Value:
  820. // None.
  821. //
  822. // Exceptions Thrown:
  823. // CNTException IDS_EXT_ADD_PAGES_ERROR
  824. //
  825. //--
  826. /////////////////////////////////////////////////////////////////////////////
  827. void CExtensionDll::CreatePropertySheetPages(void)
  828. {
  829. HRESULT hr;
  830. ASSERT_VALID(Pext());
  831. ASSERT(m_piExtendPropSheet == NULL);
  832. // Load the interface.
  833. m_piExtendPropSheet = (interface IWEExtendPropertySheet *) LoadInterface(IID_IWEExtendPropertySheet);
  834. if (m_piExtendPropSheet == NULL)
  835. return;
  836. ASSERT(m_piExtendPropSheet != NULL);
  837. // Add pages from the extension.
  838. GetUnknown()->AddRef(); // Add a reference because extension is going to release.
  839. Pdo()->AddRef();
  840. try
  841. {
  842. hr = PiExtendPropSheet()->CreatePropertySheetPages(Pdo()->GetUnknown(), this);
  843. } // try
  844. catch ( ... )
  845. {
  846. hr = E_FAIL;
  847. } // catch
  848. if ((hr != NOERROR) && (hr != E_NOTIMPL))
  849. ThrowStaticException(hr, IDS_EXT_ADD_PAGES_ERROR, StrCLSID());
  850. } //*** CExtensionDll::CreatePropertySheetPages()
  851. /////////////////////////////////////////////////////////////////////////////
  852. //++
  853. //
  854. // CExtensionDll::CreateWizardPages
  855. //
  856. // Routine Description:
  857. // Add pages to a wizard.
  858. //
  859. // Arguments:
  860. // None.
  861. //
  862. // Return Value:
  863. // None.
  864. //
  865. // Exceptions Thrown:
  866. // CNTException IDS_EXT_ADD_PAGES_ERROR
  867. //
  868. //--
  869. /////////////////////////////////////////////////////////////////////////////
  870. void CExtensionDll::CreateWizardPages(void)
  871. {
  872. HRESULT hr;
  873. ASSERT_VALID(Pext());
  874. ASSERT(m_piExtendWizard == NULL);
  875. ASSERT_VALID(Psht());
  876. // Load the interface.
  877. m_piExtendWizard = (interface IWEExtendWizard *) LoadInterface(IID_IWEExtendWizard);
  878. if (m_piExtendWizard == NULL)
  879. return;
  880. ASSERT(m_piExtendWizard != NULL);
  881. // Add pages from the extension.
  882. GetUnknown()->AddRef(); // Add a reference because extension is going to release.
  883. Pdo()->AddRef();
  884. try
  885. {
  886. hr = PiExtendWizard()->CreateWizardPages(Pdo()->GetUnknown(), this);
  887. } // try
  888. catch ( ... )
  889. {
  890. hr = E_FAIL;
  891. } // catch
  892. if ((hr != NOERROR) && (hr != E_NOTIMPL))
  893. ThrowStaticException(hr, IDS_EXT_ADD_PAGES_ERROR, StrCLSID());
  894. } //*** CExtensionDll::CreateWizardPages()
  895. /////////////////////////////////////////////////////////////////////////////
  896. //++
  897. //
  898. // CExtensionDll::AddContextMenuItems
  899. //
  900. // Routine Description:
  901. // Ask the extension DLL to add items to the menu.
  902. //
  903. // Arguments:
  904. // None.
  905. //
  906. // Return Value:
  907. // None.
  908. //
  909. // Exceptions Thrown:
  910. // CNTException IDS_EXT_QUERY_CONTEXT_MENU_ERROR
  911. //
  912. //--
  913. /////////////////////////////////////////////////////////////////////////////
  914. void CExtensionDll::AddContextMenuItems(void)
  915. {
  916. HRESULT hr;
  917. ASSERT_VALID(Pext());
  918. ASSERT_VALID(Pmenu());
  919. ASSERT(m_piExtendContextMenu == NULL);
  920. // Load the interface.
  921. m_piExtendContextMenu = (interface IWEExtendContextMenu *) LoadInterface(IID_IWEExtendContextMenu);
  922. if (m_piExtendContextMenu == NULL)
  923. return;
  924. ASSERT(m_piExtendContextMenu != NULL);
  925. hr = PiExtendContextMenu()->QueryInterface(IID_IWEInvokeCommand, (LPVOID *) &m_piInvokeCommand);
  926. if (hr != NOERROR)
  927. {
  928. PiExtendContextMenu()->Release();
  929. m_piExtendContextMenu = NULL;
  930. ThrowStaticException(hr, IDS_EXT_QUERY_CONTEXT_MENU_ERROR, StrCLSID());
  931. } // if: error getting the InvokeCommand interface
  932. GetUnknown()->AddRef(); // Add a reference because extension is going to release.
  933. Pdo()->AddRef();
  934. Trace(g_tagExtDll, _T("CExtensionDll::AddContextMenuItem() - Adding context menu items from '%s'"), StrCLSID());
  935. try
  936. {
  937. hr = PiExtendContextMenu()->AddContextMenuItems(Pdo()->GetUnknown(), this);
  938. } // try
  939. catch ( ... )
  940. {
  941. hr = E_FAIL;
  942. } // catch
  943. if (hr != NOERROR)
  944. ThrowStaticException(hr, IDS_EXT_QUERY_CONTEXT_MENU_ERROR, StrCLSID());
  945. // Add a separator after the extension's items.
  946. Trace(g_tagExtDll, _T("CExtensionDll::AddContextMenuItem() - Adding separator"));
  947. try
  948. {
  949. hr = AddExtensionMenuItem(NULL, NULL, (ULONG) -1, 0, MF_SEPARATOR);
  950. } // try
  951. catch ( ... )
  952. {
  953. hr = E_FAIL;
  954. } // catch
  955. if (hr != NOERROR)
  956. ThrowStaticException(hr, IDS_EXT_QUERY_CONTEXT_MENU_ERROR, StrCLSID());
  957. } //*** CExtensionDll::AddContextMenuItems()
  958. /////////////////////////////////////////////////////////////////////////////
  959. //++
  960. //
  961. // CExtensionDll::InterfaceSupportsErrorInfo [ISupportsErrorInfo]
  962. //
  963. // Routine Description:
  964. // Determines whether the interface supports error info (???).
  965. //
  966. // Arguments:
  967. // riid [IN] Reference to the interface ID.
  968. //
  969. // Return Value:
  970. // S_OK Interface supports error info.
  971. // S_FALSE Interface does not support error info.
  972. //
  973. // Exceptions Thrown:
  974. // None.
  975. //
  976. //--
  977. /////////////////////////////////////////////////////////////////////////////
  978. STDMETHODIMP CExtensionDll::InterfaceSupportsErrorInfo(REFIID riid)
  979. {
  980. static const IID * rgiid[] =
  981. {
  982. &IID_IWCPropertySheetCallback,
  983. &IID_IWCWizardCallback,
  984. &IID_IWCContextMenuCallback,
  985. };
  986. int iiid;
  987. for (iiid = 0 ; iiid < sizeof(rgiid) / sizeof(rgiid[0]) ; iiid++)
  988. {
  989. if (InlineIsEqualGUID(*rgiid[iiid], riid))
  990. return S_OK;
  991. }
  992. return S_FALSE;
  993. } //*** CExtensionDll::InterfaceSupportsErrorInfo()
  994. /////////////////////////////////////////////////////////////////////////////
  995. //++
  996. //
  997. // CExtensionDll::AddPropertySheetPage [IWCPropertySheetCallback]
  998. //
  999. // Routine Description:
  1000. // Add a page to the property sheet.
  1001. //
  1002. // Arguments:
  1003. // hpage [IN] Page to add.
  1004. //
  1005. // Return Value:
  1006. // NOERROR Page added successfully.
  1007. // E_INVALIDARG NULL hpage.
  1008. // Any hresult returned from CBasePropertySheet::HrAddPage().
  1009. //
  1010. // Exceptions Thrown:
  1011. // None.
  1012. //
  1013. //--
  1014. /////////////////////////////////////////////////////////////////////////////
  1015. STDMETHODIMP CExtensionDll::AddPropertySheetPage(
  1016. IN LONG * hpage
  1017. )
  1018. {
  1019. HRESULT hr = NOERROR;
  1020. AFX_MANAGE_STATE(m_pModuleState);
  1021. ASSERT(hpage != NULL);
  1022. ASSERT_VALID(Psht());
  1023. // Do this for the release build.
  1024. if ((hpage == NULL)
  1025. || (Psht() == NULL))
  1026. hr = E_INVALIDARG;
  1027. else
  1028. hr = Psht()->HrAddPage((HPROPSHEETPAGE) hpage);
  1029. return hr;
  1030. } //*** CExtensionDll::AddPropertySheetPage()
  1031. /////////////////////////////////////////////////////////////////////////////
  1032. //++
  1033. //
  1034. // CExtensionDll::AddWizardPage [IWCWizardCallback]
  1035. //
  1036. // Routine Description:
  1037. // Add a page to the wizard.
  1038. //
  1039. // Arguments:
  1040. // hpage [IN] Page to add.
  1041. //
  1042. // Return Value:
  1043. // NOERROR Page added successfully.
  1044. // E_INVALIDARG NULL hpage.
  1045. // Any hresult returned from CBaseSheet::HrAddPage().
  1046. //
  1047. // Exceptions Thrown:
  1048. // None.
  1049. //
  1050. //--
  1051. /////////////////////////////////////////////////////////////////////////////
  1052. STDMETHODIMP CExtensionDll::AddWizardPage(
  1053. IN LONG * hpage
  1054. )
  1055. {
  1056. HRESULT hr = NOERROR;
  1057. AFX_MANAGE_STATE(m_pModuleState);
  1058. ASSERT(hpage != NULL);
  1059. ASSERT_VALID(Psht());
  1060. // Do this for the release build.
  1061. if ((hpage == NULL) || (Psht() == NULL))
  1062. hr = E_INVALIDARG;
  1063. else
  1064. hr = Psht()->HrAddPage((HPROPSHEETPAGE) hpage);
  1065. return hr;
  1066. } //*** CExtensionDll::AddWizardPage()
  1067. /////////////////////////////////////////////////////////////////////////////
  1068. //++
  1069. //
  1070. // CExtensionDll::EnableNext [IWCWizardCallback]
  1071. //
  1072. // Routine Description:
  1073. // Enable or disable the NEXT button. If it is the last page, the
  1074. // FINISH button will be enabled or disabled.
  1075. //
  1076. // Arguments:
  1077. // hpage [IN] Page for which the button is being enabled or
  1078. // disabled.
  1079. // bEnable [IN] TRUE = Enable the button, FALSE = disable.
  1080. //
  1081. // Return Value:
  1082. // NOERROR Success.
  1083. // E_INVALIDARG Unknown hpage specified.
  1084. //
  1085. // Exceptions Thrown:
  1086. // None.
  1087. //
  1088. //--
  1089. /////////////////////////////////////////////////////////////////////////////
  1090. STDMETHODIMP CExtensionDll::EnableNext(
  1091. IN LONG * hpage,
  1092. IN BOOL bEnable
  1093. )
  1094. {
  1095. HRESULT hr = NOERROR;
  1096. CBaseWizard * pwiz;
  1097. DWORD dwWizButtons;
  1098. AFX_MANAGE_STATE(m_pModuleState);
  1099. ASSERT(hpage != NULL);
  1100. ASSERT_VALID(Psht());
  1101. ASSERT_KINDOF(CBaseWizard, Psht());
  1102. pwiz = (CBaseWizard *) Psht();
  1103. // If this is the last extension page, enable/disable the FINISH button.
  1104. {
  1105. POSITION pos;
  1106. BOOL bMatch = FALSE;
  1107. pos = pwiz->Lhpage().GetHeadPosition();
  1108. while (pos != NULL)
  1109. {
  1110. if (pwiz->Lhpage().GetNext(pos) == hpage)
  1111. {
  1112. bMatch = TRUE;
  1113. break;
  1114. } // if: found a match
  1115. } // while: more items in the list
  1116. if (!bMatch)
  1117. return E_INVALIDARG;
  1118. if (pos == NULL)
  1119. dwWizButtons = PSWIZB_BACK | (bEnable ? PSWIZB_FINISH : PSWIZB_DISABLEDFINISH);
  1120. else
  1121. dwWizButtons = PSWIZB_BACK | (bEnable ? PSWIZB_NEXT : 0);
  1122. } // If this is the last extension page, set the FINISH button
  1123. // Set wizard buttons.
  1124. pwiz->SetWizardButtons(dwWizButtons);
  1125. return hr;
  1126. } //*** CExtensionDll::EnableNext()
  1127. /////////////////////////////////////////////////////////////////////////////
  1128. //++
  1129. //
  1130. // CExtensionDll::AddExtensionMenuItem [IWCContextMenuCallback]
  1131. //
  1132. // Routine Description:
  1133. // Add a page to the wizard.
  1134. //
  1135. // Arguments:
  1136. // lpszName [IN] Name of item.
  1137. // lpszStatusBarText [IN] Text to appear on the status bar when the
  1138. // item is highlighted.
  1139. // nCommandID [IN] ID for the command when menu item is invoked.
  1140. // Must not be -1.
  1141. // nSubmenuCommandID [IN] ID for a submenu.
  1142. // uFlags [IN] Menu flags. The following are not supportd:
  1143. // MF_OWNERDRAW, MF_POPUP
  1144. //
  1145. // Return Value:
  1146. // NOERROR Item added successfully.
  1147. // E_INVALIDARG MF_OWNERDRAW or MF_POPUP were specified.
  1148. // E_OUTOFMEMORY Error allocating the item.
  1149. //
  1150. // Exceptions Thrown:
  1151. // None.
  1152. //
  1153. //--
  1154. /////////////////////////////////////////////////////////////////////////////
  1155. STDMETHODIMP CExtensionDll::AddExtensionMenuItem(
  1156. IN BSTR lpszName,
  1157. IN BSTR lpszStatusBarText,
  1158. IN ULONG nCommandID,
  1159. IN ULONG nSubmenuCommandID,
  1160. IN ULONG uFlags
  1161. )
  1162. {
  1163. HRESULT hr = NOERROR;
  1164. CExtMenuItem * pemi = NULL;
  1165. AFX_MANAGE_STATE( m_pModuleState );
  1166. ASSERT_VALID( Pext() );
  1167. ASSERT( ! ( uFlags & (MF_OWNERDRAW | MF_POPUP) ) );
  1168. ASSERT_VALID( Pmenu() );
  1169. // Do this for the release build.
  1170. if ( ( uFlags & (MF_OWNERDRAW | MF_POPUP) ) != 0 )
  1171. {
  1172. hr = E_INVALIDARG;
  1173. } // if: trying to add invalid type of menu item
  1174. else
  1175. {
  1176. ASSERT( Pext()->PemiFromExtCommandID( nCommandID ) == NULL );
  1177. try
  1178. {
  1179. Trace( g_tagExtDll, _T("CExtensionDll::AddExtensionMenuItem() - Adding menu item '%s', ExtID = %d"), lpszName, nCommandID );
  1180. // Allocate a new item.
  1181. pemi = new CExtMenuItem(
  1182. OLE2CT( lpszName ),
  1183. OLE2CT( lpszStatusBarText ),
  1184. nCommandID,
  1185. NNextCommandID(),
  1186. NNextMenuID(),
  1187. uFlags,
  1188. FALSE, /*bMakeDefault*/
  1189. PiInvokeCommand()
  1190. );
  1191. if ( pemi == NULL )
  1192. {
  1193. AfxThrowMemoryException();
  1194. } // if: error allocating memory
  1195. // Insert the item in the menu.
  1196. if ( ! Pmenu()->InsertMenu( NNextMenuID(), MF_BYPOSITION | uFlags, NNextCommandID(), pemi->StrName() ) )
  1197. {
  1198. ThrowStaticException( ::GetLastError(), IDS_INSERT_MENU_ERROR, pemi->StrName() );
  1199. } // if: error inserting the menu item
  1200. // Add the item to the tail of the list.
  1201. Pext()->PlMenuItems()->AddTail( pemi );
  1202. pemi = NULL;
  1203. // Update the counters.
  1204. Pext()->m_nNextCommandID++;
  1205. Pext()->m_nNextMenuID++;
  1206. } // try
  1207. catch ( CNTException * pnte )
  1208. {
  1209. hr = pnte->Sc();
  1210. pnte->ReportError();
  1211. pnte->Delete();
  1212. } // catch: CException
  1213. catch ( CException * pe )
  1214. {
  1215. hr = E_OUTOFMEMORY;
  1216. pe->ReportError();
  1217. pe->Delete();
  1218. } // catch: CException
  1219. } // else: we can add the item
  1220. delete pemi;
  1221. return hr;
  1222. } //*** CExtensionDll::AddExtensionMenuItem()