Leaked source code of windows server 2003
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.

1386 lines
38 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. pemi->PiCommand()->AddRef();
  463. hr = pemi->PiCommand()->InvokeCommand(pemi->NExtCommandID(), Pdo()->GetUnknown());
  464. if (hr == NOERROR)
  465. {
  466. bHandled = TRUE;
  467. } //if:
  468. } // if: found an item for the command ID
  469. return bHandled;
  470. } //*** CExtensions::BExecuteContextMenuItem()
  471. /////////////////////////////////////////////////////////////////////////////
  472. //++
  473. //
  474. // CExtensions::BGetCommandString
  475. //
  476. // Routine Description:
  477. // Get a command string from a menu ID.
  478. //
  479. // Arguments:
  480. // nCommandID [IN] Command ID for the menu item.
  481. // rstrMessage [OUT] String in which to return the message.
  482. //
  483. // Return Value:
  484. // TRUE String is being returned.
  485. // FALSE No string is being returned.
  486. //
  487. // Exceptions Thrown:
  488. // Any exceptions thrown by CExtensionDll::BGetCommandString().
  489. //
  490. //--
  491. /////////////////////////////////////////////////////////////////////////////
  492. BOOL CExtensions::BGetCommandString(
  493. IN ULONG nCommandID,
  494. OUT CString & rstrMessage
  495. )
  496. {
  497. BOOL bHandled = FALSE;
  498. CExtMenuItem * pemi;
  499. // Find the item in our list.
  500. pemi = PemiFromCommandID(nCommandID);
  501. if (pemi != NULL)
  502. {
  503. rstrMessage = pemi->StrStatusBarText();
  504. bHandled = TRUE;
  505. } // if: found an item for the command ID
  506. return bHandled;
  507. } //*** CExtensions::BGetCommandString()
  508. /////////////////////////////////////////////////////////////////////////////
  509. //++
  510. //
  511. // CExtensions::OnUpdateCommand
  512. //
  513. // Routine Description:
  514. // Determines whether extension DLL menu items should be enabled or not.
  515. //
  516. // Arguments:
  517. // pCmdUI [IN OUT] Command routing object.
  518. //
  519. // Return Value:
  520. // None.
  521. //
  522. // Exceptions Thrown:
  523. // Any exceptions thrown by CExtensionDll::BOnUpdateCommand().
  524. //
  525. //--
  526. /////////////////////////////////////////////////////////////////////////////
  527. void CExtensions::OnUpdateCommand(CCmdUI * pCmdUI)
  528. {
  529. CExtMenuItem * pemi;
  530. ASSERT(Plextdll() != NULL);
  531. // Find the item in our list.
  532. Trace(g_tagExtDll, _T("OnUpdateCommand() - ID = %d"), pCmdUI->m_nID);
  533. pemi = PemiFromCommandID(pCmdUI->m_nID);
  534. if (pemi != NULL)
  535. {
  536. Trace(g_tagExtDll, _T("OnUpdateCommand() - Found a match with '%s' ExtID = %d"), pemi->StrName(), pemi->NExtCommandID());
  537. pCmdUI->Enable( TRUE );
  538. if ( pCmdUI->m_pMenu != NULL && (pemi->UFlags() != 0) )
  539. {
  540. (pCmdUI->m_pMenu)->EnableMenuItem( pCmdUI->m_nID, pemi->UFlags() );
  541. } // if:
  542. } // if: found an item for the command ID
  543. } //*** CExtensions::OnUpdateCommand()
  544. /////////////////////////////////////////////////////////////////////////////
  545. //++
  546. //
  547. // CExtensions::OnCmdMsg
  548. //
  549. // Routine Description:
  550. // Processes command messages. Attempts to pass them on to a selected
  551. // item first.
  552. //
  553. // Arguments:
  554. // nID [IN] Command ID.
  555. // nCode [IN] Notification code.
  556. // pExtra [IN OUT] Used according to the value of nCode.
  557. // pHandlerInfo [OUT] ???
  558. //
  559. // Return Value:
  560. // TRUE Message has been handled.
  561. // FALSE Message has NOT been handled.
  562. //
  563. //--
  564. /////////////////////////////////////////////////////////////////////////////
  565. BOOL CExtensions::OnCmdMsg(
  566. UINT nID,
  567. int nCode,
  568. void * pExtra,
  569. AFX_CMDHANDLERINFO * pHandlerInfo
  570. )
  571. {
  572. return BExecuteContextMenuItem(nID);
  573. } //*** CExtensions::OnCmdMsg()
  574. /////////////////////////////////////////////////////////////////////////////
  575. //++
  576. //
  577. // CExtensions::PemiFromCommandID
  578. //
  579. // Routine Description:
  580. // Find the menu item for the specified command ID.
  581. //
  582. // Arguments:
  583. // nCommandID [IN] Command ID for the menu item.
  584. //
  585. // Return Value:
  586. // pemi Menu item or NULL if not found.
  587. //
  588. // Exceptions Thrown:
  589. // None.
  590. //
  591. //--
  592. /////////////////////////////////////////////////////////////////////////////
  593. CExtMenuItem * CExtensions::PemiFromCommandID(IN ULONG nCommandID) const
  594. {
  595. POSITION pos;
  596. CExtMenuItem * pemi;
  597. CExtMenuItem * pemiReturn = NULL;
  598. if (PlMenuItems() != NULL)
  599. {
  600. pos = PlMenuItems()->GetHeadPosition();
  601. while (pos != NULL)
  602. {
  603. pemi = PlMenuItems()->GetNext(pos);
  604. ASSERT_VALID(pemi);
  605. if (pemi->NCommandID() == nCommandID)
  606. {
  607. pemiReturn = pemi;
  608. break;
  609. } // if: match was found
  610. } // while: more items in the list
  611. } // if: item list exists
  612. return pemiReturn;
  613. } //*** CExtensions::PemiFromCommandID()
  614. #ifdef _DEBUG
  615. /////////////////////////////////////////////////////////////////////////////
  616. //++
  617. //
  618. // CExtensions::PemiFromExtCommandID
  619. //
  620. // Routine Description:
  621. // Find the menu item for the specified extension command ID.
  622. //
  623. // Arguments:
  624. // nExtCommandID [IN] Extension command ID for the menu item.
  625. //
  626. // Return Value:
  627. // pemi Menu item or NULL if not found.
  628. //
  629. // Exceptions Thrown:
  630. // None.
  631. //
  632. //--
  633. /////////////////////////////////////////////////////////////////////////////
  634. CExtMenuItem * CExtensions::PemiFromExtCommandID(IN ULONG nExtCommandID) const
  635. {
  636. POSITION pos;
  637. CExtMenuItem * pemi;
  638. CExtMenuItem * pemiReturn = NULL;
  639. if (PlMenuItems() != NULL)
  640. {
  641. pos = PlMenuItems()->GetHeadPosition();
  642. while (pos != NULL)
  643. {
  644. pemi = PlMenuItems()->GetNext(pos);
  645. ASSERT_VALID(pemi);
  646. if (pemi->NExtCommandID() == nExtCommandID)
  647. {
  648. pemiReturn = pemi;
  649. break;
  650. } // if: match was found
  651. } // while: more items in the list
  652. } // if: item list exists
  653. return pemiReturn;
  654. } //*** CExtensions::PemiFromExtCommandID()
  655. #endif
  656. //*************************************************************************//
  657. /////////////////////////////////////////////////////////////////////////////
  658. // CComObject<CExtensionDll>
  659. /////////////////////////////////////////////////////////////////////////////
  660. IMPLEMENT_DYNAMIC(CExtensionDll, CObject);
  661. BEGIN_OBJECT_MAP(ObjectMap)
  662. OBJECT_ENTRY(CLSID_CoCluAdmin, CExtensionDll)
  663. END_OBJECT_MAP()
  664. /////////////////////////////////////////////////////////////////////////////
  665. //++
  666. //
  667. // CExtensionDll::CExtensionDll
  668. //
  669. // Routine Description:
  670. // Default constructor.
  671. //
  672. // Arguments:
  673. // None.
  674. //
  675. // Return Value:
  676. // None.
  677. //
  678. //--
  679. /////////////////////////////////////////////////////////////////////////////
  680. CExtensionDll::CExtensionDll(void)
  681. {
  682. m_piExtendPropSheet = NULL;
  683. m_piExtendWizard = NULL;
  684. m_piExtendContextMenu = NULL;
  685. m_piInvokeCommand = NULL;
  686. m_pext = NULL;
  687. m_pModuleState = AfxGetModuleState();
  688. ASSERT(m_pModuleState != NULL);
  689. } //*** CExtensionDll::CExtensionDll()
  690. /////////////////////////////////////////////////////////////////////////////
  691. //++
  692. //
  693. // CExtensionDll::~CExtensionDll
  694. //
  695. // Routine Description:
  696. // Destructor.
  697. //
  698. // Arguments:
  699. // None.
  700. //
  701. // Return Value:
  702. // None.
  703. //
  704. //--
  705. /////////////////////////////////////////////////////////////////////////////
  706. CExtensionDll::~CExtensionDll(void)
  707. {
  708. UnloadExtension();
  709. m_pModuleState = NULL;
  710. } //*** CExtensionDll::~CExtensionDll()
  711. /////////////////////////////////////////////////////////////////////////////
  712. //++
  713. //
  714. // CExtensionDll::Init
  715. //
  716. // Routine Description:
  717. // Initialize this class in preparation for accessing the extension.
  718. //
  719. // Arguments:
  720. // rstrCLSID [IN] CLSID of the extension in string form.
  721. //
  722. // Return Value:
  723. // None.
  724. //
  725. // Exceptions Thrown:
  726. // CNTException 0 (error converting CLSID from string)
  727. // Any exceptions thrown by CString::operater=().
  728. //
  729. //--
  730. /////////////////////////////////////////////////////////////////////////////
  731. void CExtensionDll::Init(
  732. IN const CString & rstrCLSID,
  733. IN OUT CExtensions * pext
  734. )
  735. {
  736. HRESULT hr;
  737. CWaitCursor wc;
  738. ASSERT_VALID(pext);
  739. Trace(g_tagExtDll, _T("Init() - CLSID = %s"), rstrCLSID);
  740. // Save parameters.
  741. ASSERT(StrCLSID().IsEmpty() || (StrCLSID() == rstrCLSID));
  742. m_strCLSID = rstrCLSID;
  743. m_pext = pext;
  744. // Convert the CLSID string to a CLSID.
  745. hr = ::CLSIDFromString((LPWSTR) (LPCTSTR) rstrCLSID, &m_clsid);
  746. if (hr != S_OK)
  747. ThrowStaticException(hr, IDS_CLSIDFROMSTRING_ERROR, rstrCLSID);
  748. } //*** CExtensionDll::Init()
  749. /////////////////////////////////////////////////////////////////////////////
  750. //++
  751. //
  752. // CExtensionDll::LoadInterface
  753. //
  754. // Routine Description:
  755. // Load an extension DLL.
  756. //
  757. // Arguments:
  758. // riid [IN] Interface ID.
  759. //
  760. // Return Value:
  761. // piUnk IUnknown interface pointer for interface.
  762. //
  763. // Exceptions Thrown:
  764. // CNTException IDS_EXT_CREATE_INSTANCE_ERROR
  765. //
  766. //--
  767. /////////////////////////////////////////////////////////////////////////////
  768. IUnknown * CExtensionDll::LoadInterface(IN const REFIID riid)
  769. {
  770. HRESULT hr;
  771. IUnknown * piUnk;
  772. CWaitCursor wc;
  773. // Load the inproc server and get the IShellExtInit interface pointer.
  774. Trace(g_tagExtDllRef, _T("LoadInterface() - Getting interface pointer"));
  775. hr = ::CoCreateInstance(
  776. Rclsid(),
  777. NULL,
  778. CLSCTX_INPROC_SERVER,
  779. riid,
  780. (LPVOID *) &piUnk
  781. );
  782. if ((hr != S_OK)
  783. && (hr != REGDB_E_CLASSNOTREG)
  784. && (hr != E_NOINTERFACE)
  785. )
  786. ThrowStaticException(hr, IDS_EXT_CREATE_INSTANCE_ERROR, StrCLSID());
  787. return piUnk;
  788. } //*** CExtensionDll::LoadInterface()
  789. /////////////////////////////////////////////////////////////////////////////
  790. //++
  791. //
  792. // CExtensionDll::UnloadExtension
  793. //
  794. // Routine Description:
  795. // Unload the extension DLL.
  796. //
  797. // Arguments:
  798. // None.
  799. //
  800. // Return Value:
  801. // None.
  802. //
  803. //--
  804. /////////////////////////////////////////////////////////////////////////////
  805. void CExtensionDll::UnloadExtension(void)
  806. {
  807. // Release the interface pointers in the opposite order in which they
  808. // were obtained.
  809. ReleaseInterface(&m_piExtendPropSheet);
  810. ReleaseInterface(&m_piExtendWizard);
  811. ReleaseInterface(&m_piExtendContextMenu);
  812. ReleaseInterface(&m_piInvokeCommand);
  813. m_strCLSID.Empty();
  814. } //*** CExtensionDll::UnloadExtension()
  815. /////////////////////////////////////////////////////////////////////////////
  816. //++
  817. //
  818. // CExtensionDll::CreatePropertySheetPages
  819. //
  820. // Routine Description:
  821. // Add pages to a property sheet.
  822. //
  823. // Arguments:
  824. // None.
  825. //
  826. // Return Value:
  827. // None.
  828. //
  829. // Exceptions Thrown:
  830. // CNTException IDS_EXT_ADD_PAGES_ERROR
  831. //
  832. //--
  833. /////////////////////////////////////////////////////////////////////////////
  834. void CExtensionDll::CreatePropertySheetPages(void)
  835. {
  836. HRESULT hr;
  837. ASSERT_VALID(Pext());
  838. ASSERT(m_piExtendPropSheet == NULL);
  839. // Load the interface.
  840. m_piExtendPropSheet = (interface IWEExtendPropertySheet *) LoadInterface(IID_IWEExtendPropertySheet);
  841. if (m_piExtendPropSheet == NULL)
  842. return;
  843. ASSERT(m_piExtendPropSheet != NULL);
  844. // Add pages from the extension.
  845. GetUnknown()->AddRef(); // Add a reference because extension is going to release.
  846. Pdo()->AddRef();
  847. try
  848. {
  849. hr = PiExtendPropSheet()->CreatePropertySheetPages(Pdo()->GetUnknown(), this);
  850. } // try
  851. catch ( ... )
  852. {
  853. hr = E_FAIL;
  854. } // catch
  855. if ((hr != NOERROR) && (hr != E_NOTIMPL))
  856. ThrowStaticException(hr, IDS_EXT_ADD_PAGES_ERROR, StrCLSID());
  857. } //*** CExtensionDll::CreatePropertySheetPages()
  858. /////////////////////////////////////////////////////////////////////////////
  859. //++
  860. //
  861. // CExtensionDll::CreateWizardPages
  862. //
  863. // Routine Description:
  864. // Add pages to a wizard.
  865. //
  866. // Arguments:
  867. // None.
  868. //
  869. // Return Value:
  870. // None.
  871. //
  872. // Exceptions Thrown:
  873. // CNTException IDS_EXT_ADD_PAGES_ERROR
  874. //
  875. //--
  876. /////////////////////////////////////////////////////////////////////////////
  877. void CExtensionDll::CreateWizardPages(void)
  878. {
  879. HRESULT hr;
  880. ASSERT_VALID(Pext());
  881. ASSERT(m_piExtendWizard == NULL);
  882. ASSERT_VALID(Psht());
  883. // Load the interface.
  884. m_piExtendWizard = (interface IWEExtendWizard *) LoadInterface(IID_IWEExtendWizard);
  885. if (m_piExtendWizard == NULL)
  886. return;
  887. ASSERT(m_piExtendWizard != NULL);
  888. // Add pages from the extension.
  889. GetUnknown()->AddRef(); // Add a reference because extension is going to release.
  890. Pdo()->AddRef();
  891. try
  892. {
  893. hr = PiExtendWizard()->CreateWizardPages(Pdo()->GetUnknown(), this);
  894. } // try
  895. catch ( ... )
  896. {
  897. hr = E_FAIL;
  898. } // catch
  899. if ((hr != NOERROR) && (hr != E_NOTIMPL))
  900. ThrowStaticException(hr, IDS_EXT_ADD_PAGES_ERROR, StrCLSID());
  901. } //*** CExtensionDll::CreateWizardPages()
  902. /////////////////////////////////////////////////////////////////////////////
  903. //++
  904. //
  905. // CExtensionDll::AddContextMenuItems
  906. //
  907. // Routine Description:
  908. // Ask the extension DLL to add items to the menu.
  909. //
  910. // Arguments:
  911. // None.
  912. //
  913. // Return Value:
  914. // None.
  915. //
  916. // Exceptions Thrown:
  917. // CNTException IDS_EXT_QUERY_CONTEXT_MENU_ERROR
  918. //
  919. //--
  920. /////////////////////////////////////////////////////////////////////////////
  921. void CExtensionDll::AddContextMenuItems(void)
  922. {
  923. HRESULT hr;
  924. ASSERT_VALID(Pext());
  925. ASSERT_VALID(Pmenu());
  926. ASSERT(m_piExtendContextMenu == NULL);
  927. // Load the interface.
  928. m_piExtendContextMenu = (interface IWEExtendContextMenu *) LoadInterface(IID_IWEExtendContextMenu);
  929. if (m_piExtendContextMenu == NULL)
  930. return;
  931. ASSERT(m_piExtendContextMenu != NULL);
  932. hr = PiExtendContextMenu()->QueryInterface(IID_IWEInvokeCommand, (LPVOID *) &m_piInvokeCommand);
  933. if (hr != NOERROR)
  934. {
  935. PiExtendContextMenu()->Release();
  936. m_piExtendContextMenu = NULL;
  937. ThrowStaticException(hr, IDS_EXT_QUERY_CONTEXT_MENU_ERROR, StrCLSID());
  938. } // if: error getting the InvokeCommand interface
  939. GetUnknown()->AddRef(); // Add a reference because extension is going to release.
  940. Pdo()->AddRef();
  941. Trace(g_tagExtDll, _T("CExtensionDll::AddContextMenuItem() - Adding context menu items from '%s'"), StrCLSID());
  942. try
  943. {
  944. hr = PiExtendContextMenu()->AddContextMenuItems(Pdo()->GetUnknown(), this);
  945. } // try
  946. catch ( ... )
  947. {
  948. hr = E_FAIL;
  949. } // catch
  950. if (hr != NOERROR)
  951. ThrowStaticException(hr, IDS_EXT_QUERY_CONTEXT_MENU_ERROR, StrCLSID());
  952. // Add a separator after the extension's items.
  953. Trace(g_tagExtDll, _T("CExtensionDll::AddContextMenuItem() - Adding separator"));
  954. try
  955. {
  956. hr = AddExtensionMenuItem(NULL, NULL, (ULONG) -1, 0, MF_SEPARATOR);
  957. } // try
  958. catch ( ... )
  959. {
  960. hr = E_FAIL;
  961. } // catch
  962. if (hr != NOERROR)
  963. ThrowStaticException(hr, IDS_EXT_QUERY_CONTEXT_MENU_ERROR, StrCLSID());
  964. } //*** CExtensionDll::AddContextMenuItems()
  965. /////////////////////////////////////////////////////////////////////////////
  966. //++
  967. //
  968. // CExtensionDll::InterfaceSupportsErrorInfo [ISupportsErrorInfo]
  969. //
  970. // Routine Description:
  971. // Determines whether the interface supports error info (???).
  972. //
  973. // Arguments:
  974. // riid [IN] Reference to the interface ID.
  975. //
  976. // Return Value:
  977. // S_OK Interface supports error info.
  978. // S_FALSE Interface does not support error info.
  979. //
  980. // Exceptions Thrown:
  981. // None.
  982. //
  983. //--
  984. /////////////////////////////////////////////////////////////////////////////
  985. STDMETHODIMP CExtensionDll::InterfaceSupportsErrorInfo(REFIID riid)
  986. {
  987. static const IID * rgiid[] =
  988. {
  989. &IID_IWCPropertySheetCallback,
  990. &IID_IWCWizardCallback,
  991. &IID_IWCContextMenuCallback,
  992. };
  993. int iiid;
  994. for (iiid = 0 ; iiid < sizeof(rgiid) / sizeof(rgiid[0]) ; iiid++)
  995. {
  996. if (InlineIsEqualGUID(*rgiid[iiid], riid))
  997. return S_OK;
  998. }
  999. return S_FALSE;
  1000. } //*** CExtensionDll::InterfaceSupportsErrorInfo()
  1001. /////////////////////////////////////////////////////////////////////////////
  1002. //++
  1003. //
  1004. // CExtensionDll::AddPropertySheetPage [IWCPropertySheetCallback]
  1005. //
  1006. // Routine Description:
  1007. // Add a page to the property sheet.
  1008. //
  1009. // Arguments:
  1010. // hpage [IN] Page to add.
  1011. //
  1012. // Return Value:
  1013. // NOERROR Page added successfully.
  1014. // E_INVALIDARG NULL hpage.
  1015. // Any hresult returned from CBasePropertySheet::HrAddPage().
  1016. //
  1017. // Exceptions Thrown:
  1018. // None.
  1019. //
  1020. //--
  1021. /////////////////////////////////////////////////////////////////////////////
  1022. STDMETHODIMP CExtensionDll::AddPropertySheetPage(
  1023. IN LONG * hpage
  1024. )
  1025. {
  1026. HRESULT hr = NOERROR;
  1027. AFX_MANAGE_STATE(m_pModuleState);
  1028. ASSERT(hpage != NULL);
  1029. ASSERT_VALID(Psht());
  1030. // Do this for the release build.
  1031. if ((hpage == NULL)
  1032. || (Psht() == NULL))
  1033. hr = E_INVALIDARG;
  1034. else
  1035. hr = Psht()->HrAddPage((HPROPSHEETPAGE) hpage);
  1036. return hr;
  1037. } //*** CExtensionDll::AddPropertySheetPage()
  1038. /////////////////////////////////////////////////////////////////////////////
  1039. //++
  1040. //
  1041. // CExtensionDll::AddWizardPage [IWCWizardCallback]
  1042. //
  1043. // Routine Description:
  1044. // Add a page to the wizard.
  1045. //
  1046. // Arguments:
  1047. // hpage [IN] Page to add.
  1048. //
  1049. // Return Value:
  1050. // NOERROR Page added successfully.
  1051. // E_INVALIDARG NULL hpage.
  1052. // Any hresult returned from CBaseSheet::HrAddPage().
  1053. //
  1054. // Exceptions Thrown:
  1055. // None.
  1056. //
  1057. //--
  1058. /////////////////////////////////////////////////////////////////////////////
  1059. STDMETHODIMP CExtensionDll::AddWizardPage(
  1060. IN LONG * hpage
  1061. )
  1062. {
  1063. HRESULT hr = NOERROR;
  1064. AFX_MANAGE_STATE(m_pModuleState);
  1065. ASSERT(hpage != NULL);
  1066. ASSERT_VALID(Psht());
  1067. // Do this for the release build.
  1068. if ((hpage == NULL) || (Psht() == NULL))
  1069. hr = E_INVALIDARG;
  1070. else
  1071. hr = Psht()->HrAddPage((HPROPSHEETPAGE) hpage);
  1072. return hr;
  1073. } //*** CExtensionDll::AddWizardPage()
  1074. /////////////////////////////////////////////////////////////////////////////
  1075. //++
  1076. //
  1077. // CExtensionDll::EnableNext [IWCWizardCallback]
  1078. //
  1079. // Routine Description:
  1080. // Enable or disable the NEXT button. If it is the last page, the
  1081. // FINISH button will be enabled or disabled.
  1082. //
  1083. // Arguments:
  1084. // hpage [IN] Page for which the button is being enabled or
  1085. // disabled.
  1086. // bEnable [IN] TRUE = Enable the button, FALSE = disable.
  1087. //
  1088. // Return Value:
  1089. // NOERROR Success.
  1090. // E_INVALIDARG Unknown hpage specified.
  1091. //
  1092. // Exceptions Thrown:
  1093. // None.
  1094. //
  1095. //--
  1096. /////////////////////////////////////////////////////////////////////////////
  1097. STDMETHODIMP CExtensionDll::EnableNext(
  1098. IN LONG * hpage,
  1099. IN BOOL bEnable
  1100. )
  1101. {
  1102. HRESULT hr = NOERROR;
  1103. CBaseWizard * pwiz;
  1104. DWORD dwWizButtons;
  1105. AFX_MANAGE_STATE(m_pModuleState);
  1106. ASSERT(hpage != NULL);
  1107. ASSERT_VALID(Psht());
  1108. ASSERT_KINDOF(CBaseWizard, Psht());
  1109. pwiz = (CBaseWizard *) Psht();
  1110. // If this is the last extension page, enable/disable the FINISH button.
  1111. {
  1112. POSITION pos;
  1113. BOOL bMatch = FALSE;
  1114. pos = pwiz->Lhpage().GetHeadPosition();
  1115. while (pos != NULL)
  1116. {
  1117. if (pwiz->Lhpage().GetNext(pos) == hpage)
  1118. {
  1119. bMatch = TRUE;
  1120. break;
  1121. } // if: found a match
  1122. } // while: more items in the list
  1123. if (!bMatch)
  1124. return E_INVALIDARG;
  1125. if (pos == NULL)
  1126. dwWizButtons = PSWIZB_BACK | (bEnable ? PSWIZB_FINISH : PSWIZB_DISABLEDFINISH);
  1127. else
  1128. dwWizButtons = PSWIZB_BACK | (bEnable ? PSWIZB_NEXT : 0);
  1129. } // If this is the last extension page, set the FINISH button
  1130. // Set wizard buttons.
  1131. pwiz->SetWizardButtons(dwWizButtons);
  1132. return hr;
  1133. } //*** CExtensionDll::EnableNext()
  1134. /////////////////////////////////////////////////////////////////////////////
  1135. //++
  1136. //
  1137. // CExtensionDll::AddExtensionMenuItem [IWCContextMenuCallback]
  1138. //
  1139. // Routine Description:
  1140. // Add a page to the wizard.
  1141. //
  1142. // Arguments:
  1143. // lpszName [IN] Name of item.
  1144. // lpszStatusBarText [IN] Text to appear on the status bar when the
  1145. // item is highlighted.
  1146. // nCommandID [IN] ID for the command when menu item is invoked.
  1147. // Must not be -1.
  1148. // nSubmenuCommandID [IN] ID for a submenu.
  1149. // uFlags [IN] Menu flags. The following are not supportd:
  1150. // MF_OWNERDRAW, MF_POPUP
  1151. //
  1152. // Return Value:
  1153. // NOERROR Item added successfully.
  1154. // E_INVALIDARG MF_OWNERDRAW or MF_POPUP were specified.
  1155. // E_OUTOFMEMORY Error allocating the item.
  1156. //
  1157. // Exceptions Thrown:
  1158. // None.
  1159. //
  1160. //--
  1161. /////////////////////////////////////////////////////////////////////////////
  1162. STDMETHODIMP CExtensionDll::AddExtensionMenuItem(
  1163. IN BSTR lpszName,
  1164. IN BSTR lpszStatusBarText,
  1165. IN ULONG nCommandID,
  1166. IN ULONG nSubmenuCommandID,
  1167. IN ULONG uFlags
  1168. )
  1169. {
  1170. HRESULT hr = NOERROR;
  1171. CExtMenuItem * pemi = NULL;
  1172. AFX_MANAGE_STATE( m_pModuleState );
  1173. UNREFERENCED_PARAMETER( nSubmenuCommandID );
  1174. ASSERT_VALID( Pext() );
  1175. ASSERT( ! ( uFlags & (MF_OWNERDRAW | MF_POPUP) ) );
  1176. ASSERT_VALID( Pmenu() );
  1177. // Do this for the release build.
  1178. if ( ( uFlags & (MF_OWNERDRAW | MF_POPUP) ) != 0 )
  1179. {
  1180. hr = E_INVALIDARG;
  1181. } // if: trying to add invalid type of menu item
  1182. else
  1183. {
  1184. ASSERT( Pext()->PemiFromExtCommandID( nCommandID ) == NULL );
  1185. try
  1186. {
  1187. Trace( g_tagExtDll, _T("CExtensionDll::AddExtensionMenuItem() - Adding menu item '%s', ExtID = %d"), lpszName, nCommandID );
  1188. // Allocate a new item.
  1189. pemi = new CExtMenuItem(
  1190. OLE2CT( lpszName ),
  1191. OLE2CT( lpszStatusBarText ),
  1192. nCommandID,
  1193. NNextCommandID(),
  1194. NNextMenuID(),
  1195. uFlags,
  1196. FALSE, /*bMakeDefault*/
  1197. PiInvokeCommand()
  1198. );
  1199. if ( pemi == NULL )
  1200. {
  1201. AfxThrowMemoryException();
  1202. } // if: error allocating memory
  1203. // Insert the item in the menu.
  1204. if ( ! Pmenu()->InsertMenu( NNextMenuID(), MF_BYPOSITION | uFlags, NNextCommandID(), pemi->StrName() ) )
  1205. {
  1206. ThrowStaticException( ::GetLastError(), IDS_INSERT_MENU_ERROR, pemi->StrName() );
  1207. } // if: error inserting the menu item
  1208. // Add the item to the tail of the list.
  1209. Pext()->PlMenuItems()->AddTail( pemi );
  1210. pemi = NULL;
  1211. // Update the counters.
  1212. Pext()->m_nNextCommandID++;
  1213. Pext()->m_nNextMenuID++;
  1214. } // try
  1215. catch ( CNTException * pnte )
  1216. {
  1217. hr = pnte->Sc();
  1218. pnte->ReportError();
  1219. pnte->Delete();
  1220. } // catch: CException
  1221. catch ( CException * pe )
  1222. {
  1223. hr = E_OUTOFMEMORY;
  1224. pe->ReportError();
  1225. pe->Delete();
  1226. } // catch: CException
  1227. } // else: we can add the item
  1228. delete pemi;
  1229. return hr;
  1230. } //*** CExtensionDll::AddExtensionMenuItem()