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.

1578 lines
40 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) Microsoft Corp. All rights reserved.
  4. //
  5. // FILE
  6. //
  7. // snapwork.cpp
  8. //
  9. // SYNOPSIS
  10. //
  11. // Defines classes for implementing an MMC Snap-In.
  12. //
  13. // MODIFICATION HISTORY
  14. //
  15. // 02/19/2000 Original version.
  16. //
  17. ///////////////////////////////////////////////////////////////////////////////
  18. #include <proxypch.h>
  19. #include <snapwork.h>
  20. namespace SnapIn
  21. {
  22. void AfxThrowLastError()
  23. {
  24. DWORD error = GetLastError();
  25. AfxThrowOleException(HRESULT_FROM_WIN32(error));
  26. }
  27. //////////
  28. // Clipboard formats we support.
  29. //////////
  30. const CLIPFORMAT CCF_ID_NODETYPE = (CLIPFORMAT)
  31. RegisterClipboardFormatW(CCF_NODETYPE);
  32. const CLIPFORMAT CCF_ID_SZNODETYPE = (CLIPFORMAT)
  33. RegisterClipboardFormatW(CCF_SZNODETYPE);
  34. const CLIPFORMAT CCF_ID_DISPLAY_NAME = (CLIPFORMAT)
  35. RegisterClipboardFormatW(CCF_DISPLAY_NAME);
  36. const CLIPFORMAT CCF_ID_SNAPIN_CLASSID = (CLIPFORMAT)
  37. RegisterClipboardFormatW(CCF_SNAPIN_CLASSID);
  38. //////////
  39. // Helper function that returns the length of a string in bytes.
  40. //////////
  41. inline ULONG wcsbytelen(PCWSTR sz) throw ()
  42. {
  43. return (wcslen(sz) + 1) * sizeof(WCHAR);
  44. }
  45. //////////
  46. // Helper functions that writes data to an HGLOBAL
  47. //////////
  48. HRESULT WriteDataToHGlobal(
  49. HGLOBAL& dst,
  50. const VOID* data,
  51. ULONG dataLen
  52. ) throw ()
  53. {
  54. if (GlobalSize(dst) < dataLen)
  55. {
  56. HGLOBAL newGlobal = GlobalReAlloc(dst, dataLen, 0);
  57. if (!newGlobal) { return E_OUTOFMEMORY; }
  58. dst = newGlobal;
  59. }
  60. memcpy(dst, data, dataLen);
  61. return S_OK;
  62. }
  63. //////////
  64. // Helper function that loads a string resource.
  65. //////////
  66. ULONG LoadString(
  67. HMODULE module,
  68. UINT id,
  69. PCWSTR* string
  70. ) throw ()
  71. {
  72. HRSRC resInfo = FindResourceW(
  73. module,
  74. MAKEINTRESOURCEW((id >> 4) + 1),
  75. RT_STRING
  76. );
  77. if (resInfo)
  78. {
  79. HGLOBAL resData = LoadResource(
  80. module,
  81. resInfo
  82. );
  83. if (resData)
  84. {
  85. PCWSTR sz = (PCWSTR)LockResource(resData);
  86. if (sz)
  87. {
  88. // Skip forward to our string.
  89. for (id &= 0xf; id > 0; --id)
  90. {
  91. sz += *sz + 1;
  92. }
  93. *string = sz + 1;
  94. return *sz;
  95. }
  96. }
  97. }
  98. *string = NULL;
  99. return 0;
  100. }
  101. }
  102. // Static member of ResourceString
  103. WCHAR ResourceString::empty;
  104. ResourceString::ResourceString(UINT id) throw ()
  105. {
  106. PCWSTR string;
  107. ULONG length = LoadString(
  108. _Module.GetResourceInstance(),
  109. id,
  110. &string
  111. );
  112. sz = new (std::nothrow) WCHAR[length + 1];
  113. if (sz)
  114. {
  115. memcpy(sz, string, length * sizeof(WCHAR));
  116. sz[length] = L'\0';
  117. }
  118. else
  119. {
  120. sz = &empty;
  121. }
  122. }
  123. ///////////////////////////////////////////////////////////////////////////////
  124. //
  125. // Methods for manipulating a generic IDataObject (i.e., not necessarily one of
  126. // ours).
  127. //
  128. ///////////////////////////////////////////////////////////////////////////////
  129. VOID
  130. WINAPI
  131. ExtractData(
  132. IDataObject* dataObject,
  133. CLIPFORMAT format,
  134. PVOID data,
  135. DWORD dataLen
  136. )
  137. {
  138. HGLOBAL global;
  139. ExtractData(
  140. dataObject,
  141. format,
  142. dataLen,
  143. &global
  144. );
  145. memcpy(data, global, dataLen);
  146. GlobalFree(global);
  147. }
  148. VOID
  149. WINAPI
  150. ExtractData(
  151. IDataObject* dataObject,
  152. CLIPFORMAT format,
  153. DWORD maxDataLen,
  154. HGLOBAL* data
  155. )
  156. {
  157. if (!dataObject) { AfxThrowOleException(E_POINTER); }
  158. FORMATETC formatetc =
  159. {
  160. format,
  161. NULL,
  162. DVASPECT_CONTENT,
  163. -1,
  164. TYMED_HGLOBAL
  165. };
  166. STGMEDIUM stgmedium = { TYMED_HGLOBAL, NULL };
  167. stgmedium.hGlobal = GlobalAlloc(GPTR, maxDataLen);
  168. if (!stgmedium.hGlobal) { AfxThrowOleException(E_OUTOFMEMORY); }
  169. HRESULT hr = dataObject->GetDataHere(&formatetc, &stgmedium);
  170. if (SUCCEEDED(hr))
  171. {
  172. *data = stgmedium.hGlobal;
  173. }
  174. else
  175. {
  176. GlobalFree(stgmedium.hGlobal);
  177. AfxThrowOleException(hr);
  178. }
  179. }
  180. VOID
  181. WINAPI
  182. ExtractNodeType(
  183. IDataObject* dataObject,
  184. GUID* nodeType
  185. )
  186. {
  187. ExtractData(
  188. dataObject,
  189. CCF_ID_NODETYPE,
  190. nodeType,
  191. sizeof(GUID)
  192. );
  193. }
  194. // Convert an IDataObject to its corresponding SnapInDataItem.
  195. SnapInDataItem* SnapInDataItem::narrow(IDataObject* dataObject) throw ()
  196. {
  197. if (!dataObject) { return NULL; }
  198. SnapInDataItem* object;
  199. HRESULT hr = dataObject->QueryInterface(
  200. __uuidof(SnapInDataItem),
  201. (PVOID*)&object
  202. );
  203. if (FAILED(hr)) { return NULL; }
  204. object->Release();
  205. return object;
  206. }
  207. // Default implementations of various functions used by GetDataHere. This way
  208. // derived classes don't have to implement these if they're sure MMC will never
  209. // ask for them.
  210. const GUID* SnapInDataItem::getNodeType() const throw ()
  211. { return &GUID_NULL; }
  212. const GUID* SnapInDataItem::getSnapInCLSID() const throw ()
  213. { return &GUID_NULL; }
  214. PCWSTR SnapInDataItem::getSZNodeType() const throw ()
  215. { return L"{00000000-0000-0000-0000-000000000000}"; }
  216. // By default we compare column items as case sensitive strings.
  217. int SnapInDataItem::compare(
  218. SnapInDataItem& item,
  219. int column
  220. ) throw ()
  221. {
  222. return wcscmp(getDisplayName(column), item.getDisplayName(column));
  223. }
  224. //////////
  225. // Do nothing implementations of all the notifications, etc.
  226. //////////
  227. HRESULT SnapInDataItem::addMenuItems(
  228. SnapInView& view,
  229. LPCONTEXTMENUCALLBACK callback,
  230. long insertionAllowed
  231. )
  232. { return S_FALSE; }
  233. HRESULT SnapInDataItem::createPropertyPages(
  234. SnapInView& view,
  235. LPPROPERTYSHEETCALLBACK provider,
  236. LONG_PTR handle
  237. )
  238. { return S_FALSE; }
  239. HRESULT SnapInDataItem::queryPagesFor() throw ()
  240. { return S_FALSE; }
  241. HRESULT SnapInDataItem::getResultViewType(
  242. LPOLESTR* ppViewType,
  243. long* pViewOptions
  244. ) throw ()
  245. { return S_FALSE; }
  246. HRESULT SnapInDataItem::onButtonClick(
  247. SnapInView& view,
  248. MMC_CONSOLE_VERB verb
  249. )
  250. { return S_FALSE; }
  251. HRESULT SnapInDataItem::onContextHelp(
  252. SnapInView& view
  253. )
  254. { return S_FALSE; }
  255. HRESULT SnapInDataItem::onDelete(
  256. SnapInView& view
  257. )
  258. { return S_FALSE; }
  259. HRESULT SnapInDataItem::onDoubleClick(
  260. SnapInView& view
  261. )
  262. { return S_FALSE; }
  263. HRESULT SnapInDataItem::onExpand(
  264. SnapInView& view,
  265. HSCOPEITEM itemId,
  266. BOOL expanded
  267. )
  268. { return S_FALSE; }
  269. HRESULT SnapInDataItem::onMenuCommand(
  270. SnapInView& view,
  271. long commandId
  272. )
  273. { return S_FALSE; }
  274. HRESULT SnapInDataItem::onPropertyChange(
  275. SnapInView& view,
  276. BOOL scopeItem
  277. )
  278. { return S_FALSE; }
  279. HRESULT SnapInDataItem::onRefresh(SnapInView& view)
  280. { return S_FALSE; }
  281. HRESULT SnapInDataItem::onRename(
  282. SnapInView& view,
  283. LPCOLESTR newName
  284. )
  285. { return S_FALSE; }
  286. HRESULT SnapInDataItem::onSelect(
  287. SnapInView& view,
  288. BOOL scopeItem,
  289. BOOL selected
  290. )
  291. { return S_FALSE; }
  292. HRESULT SnapInDataItem::onShow(
  293. SnapInView& view,
  294. HSCOPEITEM itemId,
  295. BOOL selected
  296. )
  297. { return S_FALSE; }
  298. HRESULT SnapInDataItem::onToolbarButtonClick(
  299. SnapInView& view,
  300. int buttonId
  301. )
  302. { return S_FALSE; }
  303. HRESULT SnapInDataItem::onToolbarSelect(
  304. SnapInView& view,
  305. BOOL scopeItem,
  306. BOOL selected
  307. )
  308. { return S_FALSE; }
  309. HRESULT SnapInDataItem::onViewChange(
  310. SnapInView& view,
  311. LPARAM data,
  312. LPARAM hint
  313. )
  314. { return S_FALSE; }
  315. //////////
  316. // IUnknown
  317. //////////
  318. STDMETHODIMP_(ULONG) SnapInDataItem::AddRef()
  319. {
  320. return InterlockedIncrement(&refCount);
  321. }
  322. STDMETHODIMP_(ULONG) SnapInDataItem::Release()
  323. {
  324. LONG l = InterlockedDecrement(&refCount);
  325. if (l == 0) { delete this; }
  326. return l;
  327. }
  328. STDMETHODIMP SnapInDataItem::QueryInterface(REFIID iid, void ** ppvObject)
  329. {
  330. if (ppvObject == NULL)
  331. {
  332. return E_POINTER;
  333. }
  334. else if (iid == __uuidof(SnapInDataItem) ||
  335. iid == __uuidof(IUnknown) ||
  336. iid == __uuidof(IDataObject))
  337. {
  338. *ppvObject = this;
  339. }
  340. else
  341. {
  342. *ppvObject = NULL;
  343. return E_NOINTERFACE;
  344. }
  345. AddRef();
  346. return S_OK;
  347. }
  348. //////////
  349. // IDataObject
  350. //////////
  351. STDMETHODIMP SnapInDataItem::GetData(
  352. FORMATETC *pformatetcIn,
  353. STGMEDIUM *pmedium
  354. )
  355. { return E_NOTIMPL; }
  356. STDMETHODIMP SnapInDataItem::GetDataHere(
  357. FORMATETC *pformatetc,
  358. STGMEDIUM *pmedium
  359. )
  360. {
  361. if (pmedium == NULL) { return E_POINTER; }
  362. if (pmedium->tymed != TYMED_HGLOBAL) { return DV_E_TYMED; }
  363. ULONG dataLen;
  364. const VOID* data;
  365. if (pformatetc->cfFormat == CCF_ID_NODETYPE)
  366. {
  367. dataLen = sizeof(GUID);
  368. data = getNodeType();
  369. }
  370. else if (pformatetc->cfFormat == CCF_ID_DISPLAY_NAME)
  371. {
  372. dataLen = wcsbytelen(getDisplayName());
  373. data = getDisplayName();
  374. }
  375. else if (pformatetc->cfFormat == CCF_ID_SZNODETYPE)
  376. {
  377. dataLen = wcsbytelen(getSZNodeType());
  378. data = getSZNodeType();
  379. }
  380. else if (pformatetc->cfFormat == CCF_ID_SNAPIN_CLASSID)
  381. {
  382. dataLen = sizeof(GUID);
  383. data = getSnapInCLSID();
  384. }
  385. else
  386. {
  387. return DV_E_CLIPFORMAT;
  388. }
  389. return WriteDataToHGlobal(pmedium->hGlobal, data, dataLen);
  390. }
  391. STDMETHODIMP SnapInDataItem::QueryGetData(
  392. FORMATETC *pformatetc
  393. )
  394. { return E_NOTIMPL; }
  395. STDMETHODIMP SnapInDataItem::GetCanonicalFormatEtc(
  396. FORMATETC *pformatectIn,
  397. FORMATETC *pformatetcOut
  398. )
  399. { return E_NOTIMPL; }
  400. STDMETHODIMP SnapInDataItem::SetData(
  401. FORMATETC *pformatetc,
  402. STGMEDIUM *pmedium,
  403. BOOL fRelease
  404. )
  405. { return E_NOTIMPL; }
  406. STDMETHODIMP SnapInDataItem::EnumFormatEtc(
  407. DWORD dwDirection,
  408. IEnumFORMATETC **ppenumFormatEtc
  409. )
  410. { return E_NOTIMPL; }
  411. STDMETHODIMP SnapInDataItem::DAdvise(
  412. FORMATETC *pformatetc,
  413. DWORD advf,
  414. IAdviseSink *pAdvSink,
  415. DWORD *pdwConnection
  416. )
  417. { return E_NOTIMPL; }
  418. STDMETHODIMP SnapInDataItem::DUnadvise(
  419. DWORD dwConnection
  420. )
  421. { return E_NOTIMPL; }
  422. STDMETHODIMP SnapInDataItem::EnumDAdvise(
  423. IEnumSTATDATA **ppenumAdvise
  424. )
  425. { return E_NOTIMPL; }
  426. SnapInDataItem::~SnapInDataItem() throw ()
  427. { }
  428. PCWSTR SnapInPreNamedItem::getDisplayName(int column) const throw ()
  429. { return name; }
  430. HRESULT SnapInView::displayHelp(PCWSTR contextHelpPath)
  431. {
  432. CComPtr<IDisplayHelp> displayHelp;
  433. HRESULT hr = console->QueryInterface(
  434. __uuidof(IDisplayHelp),
  435. (PVOID*)&displayHelp
  436. );
  437. if (FAILED(hr)) { return hr; }
  438. return displayHelp->ShowTopic(const_cast<LPWSTR>(contextHelpPath));
  439. }
  440. void SnapInView::updateAllViews(
  441. SnapInDataItem& item,
  442. LPARAM data,
  443. INT_PTR hint
  444. ) const
  445. {
  446. CheckError(master->getConsole()->UpdateAllViews(&item, data, hint));
  447. }
  448. void SnapInView::deleteResultItem(const SnapInDataItem& item) const
  449. {
  450. HRESULTITEM itemId;
  451. CheckError(resultData->FindItemByLParam((LPARAM)&item, &itemId));
  452. CheckError(resultData->DeleteItem(itemId, 0));
  453. }
  454. void SnapInView::updateResultItem(const SnapInDataItem& item) const
  455. {
  456. if (resultData != NULL)
  457. {
  458. HRESULTITEM itemId;
  459. CheckError(resultData->FindItemByLParam((LPARAM)&item, &itemId));
  460. CheckError(resultData->UpdateItem(itemId));
  461. }
  462. }
  463. bool SnapInView::isPropertySheetOpen(const SnapInDataItem& item) const
  464. {
  465. HRESULT hr = sheetProvider->FindPropertySheet(
  466. (MMC_COOKIE)&item,
  467. const_cast<SnapInView*>(this),
  468. const_cast<SnapInDataItem*>(&item)
  469. );
  470. CheckError(hr);
  471. return hr == S_OK;
  472. }
  473. IToolbar* SnapInView::attachToolbar(size_t index)
  474. {
  475. // Make sure we have a controlbar.
  476. if (!controlbar) { AfxThrowOleException(E_POINTER); }
  477. // Get the entry for this index.
  478. ToolbarEntry& entry = toolbars[index];
  479. // Create the toolbar if necessary.
  480. if (!entry.toolbar)
  481. {
  482. // Create the toolbar.
  483. CComPtr<IUnknown> unk;
  484. CheckError(controlbar->Create(TOOLBAR, this, &unk));
  485. CComPtr<IToolbar> newToolbar;
  486. CheckError(unk->QueryInterface(__uuidof(IToolbar), (PVOID*)&newToolbar));
  487. const SnapInToolbarDef& def = *(entry.def);
  488. // Add the bitmaps.
  489. CheckError(newToolbar->AddBitmap(
  490. def.nImages,
  491. def.hbmp,
  492. 16,
  493. 16,
  494. def.crMask
  495. ));
  496. // Add the buttons.
  497. CheckError(newToolbar->AddButtons( def.nButtons, def.lpButtons));
  498. // All went well, so save it away.
  499. entry.toolbar = newToolbar;
  500. }
  501. // Attach the toolbar to the controlbar ...
  502. CheckError(controlbar->Attach(TOOLBAR, entry.toolbar));
  503. return entry.toolbar;
  504. }
  505. void SnapInView::detachToolbar(size_t index) throw ()
  506. {
  507. if (toolbars[index].toolbar)
  508. {
  509. // We don't care if this fails, because there's nothing we can do about
  510. // it anyway.
  511. controlbar->Detach(toolbars[index].toolbar);
  512. }
  513. }
  514. void SnapInView::reSort() const
  515. {
  516. CheckError(resultData->Sort(sortColumn, sortOption, 0));
  517. }
  518. void SnapInView::formatMessageBox(
  519. UINT titleId,
  520. UINT formatId,
  521. BOOL ignoreInserts,
  522. UINT style,
  523. int* retval,
  524. ...
  525. )
  526. {
  527. ResourceString title(titleId);
  528. ResourceString format(formatId);
  529. HRESULT hr;
  530. if (ignoreInserts)
  531. {
  532. hr = console->MessageBox(
  533. format,
  534. title,
  535. style,
  536. retval
  537. );
  538. }
  539. else
  540. {
  541. va_list marker;
  542. va_start(marker, retval);
  543. PWSTR text;
  544. DWORD nchar = FormatMessageW(
  545. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  546. FORMAT_MESSAGE_FROM_STRING,
  547. format,
  548. 0,
  549. 0,
  550. (PWSTR)&text,
  551. 4096,
  552. &marker
  553. );
  554. va_end(marker);
  555. if (!nchar) { AfxThrowLastError(); }
  556. hr = console->MessageBox(
  557. text,
  558. title,
  559. style,
  560. retval
  561. );
  562. LocalFree(text);
  563. }
  564. CheckError(hr);
  565. }
  566. void SnapInView::setImageStrip(
  567. UINT smallStripId,
  568. UINT largeStripId,
  569. BOOL scopePane
  570. )
  571. {
  572. //////////
  573. // Load the bitmaps.
  574. //////////
  575. HBITMAP smallStrip, largeStrip;
  576. smallStrip = LoadBitmap(
  577. _Module.GetModuleInstance(),
  578. MAKEINTRESOURCE(smallStripId)
  579. );
  580. if (smallStrip)
  581. {
  582. largeStrip = LoadBitmap(
  583. _Module.GetModuleInstance(),
  584. MAKEINTRESOURCE(largeStripId)
  585. );
  586. }
  587. if (!smallStrip || !largeStrip)
  588. {
  589. AfxThrowLastError();
  590. }
  591. //////////
  592. // Set the image strip.
  593. //////////
  594. HRESULT hr;
  595. IImageList* imageList;
  596. if (scopePane)
  597. {
  598. hr = console->QueryScopeImageList(&imageList);
  599. }
  600. else
  601. {
  602. hr = console->QueryResultImageList(&imageList);
  603. }
  604. if (SUCCEEDED(hr))
  605. {
  606. hr = imageList->ImageListSetStrip(
  607. (LONG_PTR*)smallStrip,
  608. (LONG_PTR*)largeStrip,
  609. 0,
  610. RGB(255, 0, 255)
  611. );
  612. imageList->Release();
  613. }
  614. DeleteObject(smallStrip);
  615. DeleteObject(largeStrip);
  616. CheckError(hr);
  617. }
  618. STDMETHODIMP_(ULONG) SnapInView::AddRef()
  619. {
  620. return InternalAddRef();
  621. }
  622. STDMETHODIMP_(ULONG) SnapInView::Release()
  623. {
  624. ULONG l = InternalRelease();
  625. if (l == 0) { delete this; }
  626. return l;
  627. }
  628. STDMETHODIMP SnapInView::Initialize(LPCONSOLE lpConsole)
  629. {
  630. HRESULT hr;
  631. hr = lpConsole->QueryInterface(
  632. __uuidof(IConsole2),
  633. (PVOID*)&console
  634. );
  635. if (FAILED(hr)) { return hr; }
  636. hr = lpConsole->QueryInterface(
  637. __uuidof(IHeaderCtrl2),
  638. (PVOID*)&headerCtrl
  639. );
  640. if (FAILED(hr)) { return hr; }
  641. hr = lpConsole->QueryInterface(
  642. __uuidof(sheetProvider),
  643. (PVOID*)&sheetProvider
  644. );
  645. if (FAILED(hr)) { return hr; }
  646. hr = lpConsole->QueryInterface(
  647. __uuidof(IResultData),
  648. (PVOID*)&resultData
  649. );
  650. if (FAILED(hr)) { return hr; }
  651. return S_OK;
  652. }
  653. STDMETHODIMP SnapInView::Destroy(MMC_COOKIE cookie)
  654. {
  655. resultData.Release();
  656. sheetProvider.Release();
  657. headerCtrl.Release();
  658. console.Release();
  659. nameSpace.Release();
  660. return S_OK;
  661. }
  662. STDMETHODIMP SnapInView::GetResultViewType(
  663. MMC_COOKIE cookie,
  664. LPOLESTR* ppViewType,
  665. long* pViewOptions
  666. )
  667. {
  668. return ((SnapInDataItem*)cookie)->getResultViewType(
  669. ppViewType,
  670. pViewOptions
  671. );
  672. }
  673. STDMETHODIMP SnapInView::GetDisplayInfo(
  674. RESULTDATAITEM* pResultDataItem
  675. )
  676. {
  677. if (pResultDataItem->mask & RDI_STR)
  678. {
  679. SnapInDataItem* item = (SnapInDataItem*)(pResultDataItem->lParam);
  680. pResultDataItem->str =
  681. const_cast<PWSTR>(item->getDisplayName(pResultDataItem->nCol));
  682. }
  683. return S_OK;
  684. }
  685. STDMETHODIMP SnapInView::Initialize(LPUNKNOWN pUnknown)
  686. {
  687. HRESULT hr;
  688. CComPtr<IConsoleNameSpace2> initNameSpace;
  689. hr = pUnknown->QueryInterface(
  690. __uuidof(IConsoleNameSpace2),
  691. (PVOID*)&initNameSpace
  692. );
  693. if (FAILED(hr)) { return hr; }
  694. CComPtr<IConsole> initConsole;
  695. hr = pUnknown->QueryInterface(
  696. __uuidof(IConsole),
  697. (PVOID*)&initConsole
  698. );
  699. if (FAILED(hr)) { return hr; }
  700. hr = internalInitialize(initNameSpace, this);
  701. if (FAILED(hr)) { return hr; }
  702. return Initialize(initConsole);
  703. }
  704. STDMETHODIMP SnapInView::CreateComponent(LPCOMPONENT* ppComponent)
  705. {
  706. HRESULT hr;
  707. CComObject<SnapInView>* newComponent;
  708. hr = CComObject<SnapInView>::CreateInstance(&newComponent);
  709. if (FAILED(hr)) { return hr; }
  710. CComPtr<SnapInView> newView(newComponent);
  711. hr = newView.p->internalInitialize(nameSpace, this);
  712. if (FAILED(hr)) { return hr; }
  713. (*ppComponent = newView)->AddRef();
  714. return S_OK;
  715. }
  716. STDMETHODIMP SnapInView::Destroy()
  717. {
  718. return Destroy((MMC_COOKIE)0);
  719. }
  720. STDMETHODIMP SnapInView::GetDisplayInfo(SCOPEDATAITEM* pScopeDataItem)
  721. {
  722. if (pScopeDataItem->mask & SDI_STR)
  723. {
  724. SnapInDataItem* item = (SnapInDataItem*)(pScopeDataItem->lParam);
  725. pScopeDataItem->displayname = const_cast<PWSTR>(item->getDisplayName());
  726. }
  727. return S_OK;
  728. }
  729. STDMETHODIMP SnapInView::QueryDataObject(
  730. MMC_COOKIE cookie,
  731. DATA_OBJECT_TYPES type,
  732. LPDATAOBJECT* ppDataObject
  733. )
  734. {
  735. if (!IS_SPECIAL_COOKIE(cookie))
  736. {
  737. (*ppDataObject = (SnapInDataItem*)cookie)->AddRef();
  738. return S_OK;
  739. }
  740. else
  741. {
  742. return S_FALSE;
  743. }
  744. }
  745. STDMETHODIMP SnapInView::Notify(
  746. LPDATAOBJECT lpDataObject,
  747. MMC_NOTIFY_TYPE event,
  748. LPARAM arg,
  749. LPARAM param
  750. )
  751. {
  752. // Extract the SnapInDataItem.
  753. SnapInDataItem* item;
  754. if (IS_SPECIAL_DATAOBJECT(lpDataObject))
  755. {
  756. item = NULL;
  757. }
  758. else
  759. {
  760. item = SnapInDataItem::narrow(lpDataObject);
  761. }
  762. HRESULT hr = S_FALSE;
  763. try
  764. {
  765. if (item)
  766. {
  767. // If we have a SnapInDataItem, dispatch the notification ...
  768. switch (event)
  769. {
  770. case MMCN_BTN_CLICK:
  771. hr = item->onButtonClick(*this, (MMC_CONSOLE_VERB)param);
  772. break;
  773. case MMCN_CONTEXTHELP:
  774. hr = item->onContextHelp(*this);
  775. break;
  776. case MMCN_DELETE:
  777. hr = item->onDelete(*this);
  778. break;
  779. case MMCN_DBLCLICK:
  780. hr = item->onDoubleClick(*this);
  781. break;
  782. case MMCN_EXPAND:
  783. hr = item->onExpand(*this, (HSCOPEITEM)param, (BOOL)arg);
  784. break;
  785. case MMCN_REFRESH:
  786. hr = item->onRefresh(*this);
  787. break;
  788. case MMCN_RENAME:
  789. hr = item->onRename(*this, (LPOLESTR)param);
  790. break;
  791. case MMCN_SELECT:
  792. hr = item->onSelect(*this, LOWORD(arg), HIWORD(arg));
  793. break;
  794. case MMCN_SHOW:
  795. hr = item->onShow(*this, (HSCOPEITEM)param, (BOOL)arg);
  796. break;
  797. case MMCN_VIEW_CHANGE:
  798. hr = item->onViewChange(*this, arg, param);
  799. break;
  800. }
  801. }
  802. else
  803. {
  804. // ... otherwise, handle it ourselves.
  805. switch (event)
  806. {
  807. case MMCN_COLUMN_CLICK:
  808. sortColumn = (int)arg;
  809. sortOption = (int)param;
  810. break;
  811. case MMCN_PROPERTY_CHANGE:
  812. {
  813. hr = ((SnapInDataItem*)param)->onPropertyChange(*this, arg);
  814. break;
  815. }
  816. }
  817. }
  818. }
  819. CATCH_AND_SAVE(hr);
  820. return hr;
  821. }
  822. STDMETHODIMP SnapInView::CompareObjects(
  823. LPDATAOBJECT lpDataObjectA,
  824. LPDATAOBJECT lpDataObjectB
  825. )
  826. {
  827. return SnapInDataItem::narrow(lpDataObjectA) ==
  828. SnapInDataItem::narrow(lpDataObjectB) ? S_OK : S_FALSE;
  829. }
  830. STDMETHODIMP SnapInView::AddMenuItems(
  831. LPDATAOBJECT lpDataObject,
  832. LPCONTEXTMENUCALLBACK piCallback,
  833. long *pInsertionAllowed
  834. )
  835. {
  836. SnapInDataItem* item = SnapInDataItem::narrow(lpDataObject);
  837. if (!item) { return S_FALSE; }
  838. HRESULT hr;
  839. try
  840. {
  841. hr = item->addMenuItems(*this, piCallback, *pInsertionAllowed);
  842. }
  843. CATCH_AND_SAVE(hr);
  844. return hr;
  845. }
  846. STDMETHODIMP SnapInView::Command(
  847. long lCommandID,
  848. LPDATAOBJECT lpDataObject
  849. )
  850. {
  851. SnapInDataItem* item = SnapInDataItem::narrow(lpDataObject);
  852. if (!item) { return S_FALSE; }
  853. HRESULT hr;
  854. try
  855. {
  856. hr = item->onMenuCommand(*this, lCommandID);
  857. }
  858. CATCH_AND_SAVE(hr);
  859. return hr;
  860. }
  861. STDMETHODIMP SnapInView::ControlbarNotify(
  862. MMC_NOTIFY_TYPE event,
  863. LPARAM arg,
  864. LPARAM param
  865. )
  866. {
  867. // If we don't have a controlbar, there's nothing we can do.
  868. if (!controlbar) { return S_FALSE; }
  869. // Get the IDataObject.
  870. IDataObject* lpDataObject;
  871. switch (event)
  872. {
  873. case MMCN_BTN_CLICK:
  874. lpDataObject = (IDataObject*)arg;
  875. break;
  876. case MMCN_SELECT:
  877. lpDataObject = (IDataObject*)param;
  878. break;
  879. default:
  880. lpDataObject = NULL;
  881. }
  882. // Convert to a SnapInDataItem.
  883. if (IS_SPECIAL_DATAOBJECT(lpDataObject)) { return S_FALSE; }
  884. SnapInDataItem* item = SnapInDataItem::narrow(lpDataObject);
  885. if (!item) { return S_FALSE; }
  886. // Dispatch the notification.
  887. HRESULT hr = S_FALSE;
  888. try
  889. {
  890. switch (event)
  891. {
  892. case MMCN_BTN_CLICK:
  893. hr = item->onToolbarButtonClick(*this, param);
  894. break;
  895. case MMCN_SELECT:
  896. hr = item->onToolbarSelect(*this, LOWORD(arg), HIWORD(arg));
  897. break;
  898. }
  899. }
  900. CATCH_AND_SAVE(hr);
  901. return hr;
  902. }
  903. STDMETHODIMP SnapInView::SetControlbar(
  904. LPCONTROLBAR pControlbar
  905. )
  906. {
  907. releaseToolbars();
  908. controlbar = pControlbar;
  909. return S_OK;
  910. }
  911. STDMETHODIMP SnapInView::CreatePropertyPages(
  912. LPPROPERTYSHEETCALLBACK lpProvider,
  913. LONG_PTR handle,
  914. LPDATAOBJECT lpDataObject
  915. )
  916. {
  917. SnapInDataItem* item = SnapInDataItem::narrow(lpDataObject);
  918. if (!item) { return S_FALSE; }
  919. HRESULT hr;
  920. try
  921. {
  922. hr = item->createPropertyPages(*this, lpProvider, handle);
  923. }
  924. CATCH_AND_SAVE(hr);
  925. return hr;
  926. }
  927. STDMETHODIMP SnapInView::QueryPagesFor(
  928. LPDATAOBJECT lpDataObject
  929. )
  930. {
  931. SnapInDataItem* item = SnapInDataItem::narrow(lpDataObject);
  932. return item ? item->queryPagesFor() : S_FALSE;
  933. }
  934. STDMETHODIMP SnapInView::GetWatermarks(
  935. LPDATAOBJECT lpIDataObject,
  936. HBITMAP *lphWatermark,
  937. HBITMAP *lphHeader,
  938. HPALETTE *lphPalette,
  939. BOOL *bStretch
  940. )
  941. { return E_NOTIMPL; }
  942. HRESULT SnapInView::Compare(
  943. LPARAM lUserParam,
  944. MMC_COOKIE cookieA,
  945. MMC_COOKIE cookieB,
  946. int* pnResult
  947. )
  948. {
  949. *pnResult = ((SnapInDataItem*)cookieA)->compare(
  950. *(SnapInDataItem*)cookieB,
  951. *pnResult
  952. );
  953. return S_OK;
  954. }
  955. const SnapInToolbarDef* SnapInView::getToolbars() const throw ()
  956. {
  957. static SnapInToolbarDef none;
  958. return &none;
  959. }
  960. SnapInView::SnapInView() throw ()
  961. : master(NULL),
  962. toolbars(NULL),
  963. numToolbars(0),
  964. sortColumn(0),
  965. sortOption(RSI_NOSORTICON)
  966. { }
  967. SnapInView::~SnapInView() throw ()
  968. {
  969. releaseToolbars();
  970. delete[] toolbars;
  971. if (master && master != this) { master->Release(); }
  972. }
  973. HRESULT SnapInView::internalInitialize(
  974. IConsoleNameSpace2* consoleNameSpace,
  975. SnapInView* masterView
  976. ) throw ()
  977. {
  978. nameSpace = consoleNameSpace;
  979. master = masterView;
  980. if (master != this) { master->AddRef(); }
  981. const SnapInToolbarDef* defs = master->getToolbars();
  982. // How many new toolbars are there?
  983. size_t count = 0;
  984. while (defs[count].nImages) { ++count; }
  985. if (count)
  986. {
  987. // Allocate memory ...
  988. toolbars = new (std::nothrow) ToolbarEntry[count];
  989. if (!toolbars) { return E_OUTOFMEMORY; }
  990. // ... and save the definitions. We don't actually create the toolbars
  991. // now. We do this as we need them.
  992. for (size_t i = 0; i < count; ++i)
  993. {
  994. toolbars[i].def = defs + i;
  995. }
  996. }
  997. numToolbars = count;
  998. return S_OK;
  999. }
  1000. void SnapInView::releaseToolbars() throw ()
  1001. {
  1002. if (controlbar)
  1003. {
  1004. for (size_t i = 0; i < numToolbars; ++i)
  1005. {
  1006. if (toolbars[i].toolbar)
  1007. {
  1008. controlbar->Detach(toolbars[i].toolbar);
  1009. toolbars[i].toolbar.Release();
  1010. }
  1011. }
  1012. }
  1013. }
  1014. SnapInPropertyPage::SnapInPropertyPage(
  1015. UINT nIDTemplate,
  1016. UINT nIDHeaderTitle,
  1017. UINT nIDHeaderSubTitle,
  1018. bool EnableHelp
  1019. )
  1020. : CHelpPageEx(nIDTemplate, 0, nIDHeaderTitle, nIDHeaderSubTitle, EnableHelp),
  1021. notify(0),
  1022. param(0),
  1023. owner(false),
  1024. applied(false),
  1025. modified(FALSE)
  1026. {
  1027. if (!nIDHeaderTitle)
  1028. {
  1029. m_psp.dwFlags |= PSP_HIDEHEADER;
  1030. }
  1031. }
  1032. SnapInPropertyPage::SnapInPropertyPage(
  1033. LONG_PTR notifyHandle,
  1034. LPARAM notifyParam,
  1035. bool deleteHandle,
  1036. UINT nIDTemplate,
  1037. UINT nIDCaption,
  1038. bool EnableHelp
  1039. )
  1040. : CHelpPageEx(nIDTemplate, nIDCaption, EnableHelp),
  1041. notify(notifyHandle),
  1042. param(notifyParam),
  1043. owner(deleteHandle),
  1044. applied(false),
  1045. modified(FALSE)
  1046. {
  1047. }
  1048. SnapInPropertyPage::~SnapInPropertyPage() throw ()
  1049. {
  1050. if (owner && notify) { MMCFreeNotifyHandle(notify); }
  1051. }
  1052. void SnapInPropertyPage::addToMMCSheet(IPropertySheetCallback* cback)
  1053. {
  1054. // Swap our callback for the MFC supplied one.
  1055. mfcCallback = m_psp.pfnCallback;
  1056. m_psp.pfnCallback = propSheetPageProc;
  1057. m_psp.lParam = (LPARAM)this;
  1058. HRESULT hr = MMCPropPageCallback(&m_psp);
  1059. if (SUCCEEDED(hr))
  1060. {
  1061. HPROPSHEETPAGE page = CreatePropertySheetPage(&m_psp);
  1062. if (page)
  1063. {
  1064. hr = cback->AddPage(page);
  1065. if (FAILED(hr))
  1066. {
  1067. DestroyPropertySheetPage(page);
  1068. }
  1069. }
  1070. else
  1071. {
  1072. // GetLastError() doesn't work with CreatePropertySheetPage.
  1073. hr = E_UNEXPECTED;
  1074. }
  1075. }
  1076. if (FAILED(hr)) { delete this; }
  1077. CheckError(hr);
  1078. }
  1079. void SnapInPropertyPage::DoDataExchange(CDataExchange* pDX)
  1080. {
  1081. pDX->m_bSaveAndValidate ? getData() : setData();
  1082. }
  1083. BOOL SnapInPropertyPage::OnApply()
  1084. {
  1085. // If we've been modified, ...
  1086. if (modified)
  1087. {
  1088. try
  1089. {
  1090. // Save the changes.
  1091. saveChanges();
  1092. }
  1093. catch (CException* e)
  1094. {
  1095. // Bring up a message box.
  1096. reportException(e);
  1097. // We're in an indeterminate state, so we can't cancel.
  1098. CancelToClose();
  1099. // Block the apply.
  1100. return FALSE;
  1101. }
  1102. // Notify MMC if necessary.
  1103. if (notify) { MMCPropertyChangeNotify(notify, param); }
  1104. // Set our flags.
  1105. applied = true;
  1106. modified = FALSE;
  1107. }
  1108. return TRUE;
  1109. }
  1110. BOOL SnapInPropertyPage::OnWizardFinish()
  1111. {
  1112. try
  1113. {
  1114. saveChanges();
  1115. }
  1116. catch (CException* e)
  1117. {
  1118. // Bring up a message box.
  1119. reportException(e);
  1120. // Disable all the buttons. Something's wrong, so we'll only let the user
  1121. // cancel.
  1122. ::PostMessageW(
  1123. ::GetParent(m_hWnd),
  1124. PSM_SETWIZBUTTONS,
  1125. 0,
  1126. (LPARAM)(DWORD)PSWIZB_DISABLEDFINISH
  1127. );
  1128. return FALSE;
  1129. }
  1130. return TRUE;
  1131. }
  1132. void SnapInPropertyPage::OnReset()
  1133. {
  1134. // If we've been modified, ...
  1135. if (modified)
  1136. {
  1137. // ... discard the changes.
  1138. discardChanges();
  1139. modified = FALSE;
  1140. }
  1141. }
  1142. void SnapInPropertyPage::SetModified(BOOL bChanged)
  1143. {
  1144. modified = bChanged;
  1145. CHelpPageEx::SetModified(bChanged);
  1146. }
  1147. void SnapInPropertyPage::getData()
  1148. {
  1149. }
  1150. void SnapInPropertyPage::setData()
  1151. {
  1152. }
  1153. void SnapInPropertyPage::saveChanges()
  1154. {
  1155. }
  1156. void SnapInPropertyPage::discardChanges()
  1157. {
  1158. }
  1159. void SnapInPropertyPage::enableControl(int controlId, bool enable)
  1160. {
  1161. ::EnableWindow(::GetDlgItem(m_hWnd, controlId), (enable ? TRUE : FALSE));
  1162. }
  1163. void SnapInPropertyPage::fail(int controlId, UINT errorText, bool isEdit)
  1164. {
  1165. failNoThrow(controlId, errorText, isEdit);
  1166. AfxThrowUserException();
  1167. }
  1168. void SnapInPropertyPage::failNoThrow(int controlId, UINT errorText, bool isEdit)
  1169. {
  1170. // Give the offending control the focus.
  1171. HWND ctrl = ::GetDlgItem(m_hWnd, controlId);
  1172. ::SetFocus(ctrl);
  1173. if (isEdit) { ::SendMessage(ctrl, EM_SETSEL, 0, -1); }
  1174. // Bring up a message box.
  1175. reportError(errorText);
  1176. }
  1177. void SnapInPropertyPage::initControl(int controlId, CWnd& control)
  1178. {
  1179. if (control.m_hWnd == NULL)
  1180. {
  1181. if (!control.SubclassWindow(::GetDlgItem(m_hWnd, controlId)))
  1182. {
  1183. AfxThrowNotSupportedException();
  1184. }
  1185. }
  1186. }
  1187. void SnapInPropertyPage::onChange()
  1188. {
  1189. SetModified();
  1190. }
  1191. void SnapInPropertyPage::reportError(UINT errorText)
  1192. {
  1193. // Bring up a message box.
  1194. MessageBox(
  1195. ResourceString(errorText),
  1196. ResourceString(getErrorCaption()),
  1197. MB_ICONWARNING
  1198. );
  1199. }
  1200. void SnapInPropertyPage::reportException(CException* e)
  1201. {
  1202. // Get the error message.
  1203. WCHAR errorText[256];
  1204. e->GetErrorMessage(errorText, sizeof(errorText)/sizeof(errorText[0]));
  1205. e->Delete();
  1206. // Bring up a message box.
  1207. MessageBox(
  1208. errorText,
  1209. ResourceString(getErrorCaption()),
  1210. MB_ICONERROR
  1211. );
  1212. }
  1213. void SnapInPropertyPage::setLargeFont(int controlId)
  1214. {
  1215. static CFont largeFont;
  1216. CWnd* ctrl = GetDlgItem(controlId);
  1217. if (ctrl)
  1218. {
  1219. // If we don't have the large font yet, ...
  1220. if (!(HFONT)largeFont)
  1221. {
  1222. // ... create it.
  1223. largeFont.CreatePointFont(
  1224. 10 * _wtoi(ResourceString(IDS_LARGE_FONT_SIZE)),
  1225. ResourceString(IDS_LARGE_FONT_NAME)
  1226. );
  1227. }
  1228. ctrl->SetFont(&largeFont);
  1229. }
  1230. }
  1231. void SnapInPropertyPage::showControl(int controlId, bool show)
  1232. {
  1233. CWnd* ctrl = GetDlgItem(controlId);
  1234. if (ctrl)
  1235. {
  1236. show ? ctrl->ModifyStyle(0, WS_VISIBLE)
  1237. : ctrl->ModifyStyle(WS_VISIBLE, 0);
  1238. }
  1239. }
  1240. void SnapInPropertyPage::getValue(
  1241. int controlId,
  1242. LONG& value,
  1243. UINT errorText
  1244. )
  1245. {
  1246. WCHAR buffer[32];
  1247. int len = GetDlgItemText(controlId, buffer, 32);
  1248. // We'll fail anything that's longer than 30 characters. This is an
  1249. // arbitrary bound. We just need to make sure that buffer is long enough to
  1250. // hold any valid integer plus a little whitespace.
  1251. if (len == 0 || len > 30)
  1252. {
  1253. fail(controlId, errorText);
  1254. }
  1255. // Skip any leading whitespace.
  1256. PWSTR sz = buffer;
  1257. while (*sz == L' ' || *sz == L'\t') { ++sz; }
  1258. // Save the first non-whitespace character.
  1259. WCHAR first = *sz;
  1260. // Convert the integer.
  1261. value = wcstol(sz, &sz, 10);
  1262. // Skip any trailing whitespace.
  1263. while (*sz == L' ' || *sz == L'\t') { ++sz; }
  1264. // Make sure all went well.
  1265. if ((value == 0 && first != L'0') ||
  1266. *sz != L'\0' ||
  1267. value == LONG_MIN ||
  1268. value == LONG_MAX)
  1269. {
  1270. fail(controlId, errorText);
  1271. }
  1272. }
  1273. void SnapInPropertyPage::setValue(
  1274. int controlId,
  1275. LONG value
  1276. )
  1277. {
  1278. WCHAR buffer[12];
  1279. SetDlgItemText(controlId, _ltow(value, buffer, 10));
  1280. }
  1281. void SnapInPropertyPage::getValue(
  1282. int controlId,
  1283. bool& value
  1284. )
  1285. {
  1286. value = IsDlgButtonChecked(controlId) != 0;
  1287. }
  1288. void SnapInPropertyPage::setValue(
  1289. int controlId,
  1290. bool value
  1291. )
  1292. {
  1293. CheckDlgButton(controlId, (value ? BST_CHECKED : BST_UNCHECKED));
  1294. }
  1295. void SnapInPropertyPage::getValue(
  1296. int controlId,
  1297. CComBSTR& value,
  1298. bool trim
  1299. )
  1300. {
  1301. HWND hwnd = ::GetDlgItem(m_hWnd, controlId);
  1302. int len = ::GetWindowTextLength(hwnd);
  1303. SysFreeString(value.m_str);
  1304. value.m_str = SysAllocStringLen(NULL, len);
  1305. if (!value) { AfxThrowMemoryException(); }
  1306. ::GetWindowTextW(hwnd, value, len + 1);
  1307. if (trim) { SdoTrimBSTR(value); }
  1308. }
  1309. void SnapInPropertyPage::setValue(
  1310. int controlId,
  1311. PCWSTR value
  1312. )
  1313. {
  1314. SetDlgItemText(controlId, value);
  1315. }
  1316. void SnapInPropertyPage::getRadio(
  1317. int firstId,
  1318. int lastId,
  1319. LONG& value
  1320. )
  1321. {
  1322. value = GetCheckedRadioButton(firstId, lastId);
  1323. value = value ? value - firstId : -1;
  1324. }
  1325. void SnapInPropertyPage::setRadio(
  1326. int firstId,
  1327. int lastId,
  1328. LONG value
  1329. )
  1330. {
  1331. CheckRadioButton(firstId, lastId, firstId + value);
  1332. }
  1333. UINT CALLBACK SnapInPropertyPage::propSheetPageProc(
  1334. HWND hwnd,
  1335. UINT uMsg,
  1336. LPPROPSHEETPAGE ppsp
  1337. ) throw ()
  1338. {
  1339. SnapInPropertyPage* page = (SnapInPropertyPage*)(ppsp->lParam);
  1340. UINT retval = page->mfcCallback(hwnd, uMsg, ppsp);
  1341. if (uMsg == PSPCB_RELEASE) { delete page; }
  1342. return retval;
  1343. }