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.

1566 lines
38 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 2000, 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::deleteResultItem(const SnapInDataItem& item) const
  441. {
  442. HRESULTITEM itemId;
  443. CheckError(resultData->FindItemByLParam((LPARAM)&item, &itemId));
  444. CheckError(resultData->DeleteItem(itemId, 0));
  445. }
  446. void SnapInView::updateResultItem(const SnapInDataItem& item) const
  447. {
  448. HRESULTITEM itemId;
  449. CheckError(resultData->FindItemByLParam((LPARAM)&item, &itemId));
  450. CheckError(resultData->UpdateItem(itemId));
  451. }
  452. bool SnapInView::isPropertySheetOpen(const SnapInDataItem& item) const
  453. {
  454. HRESULT hr = sheetProvider->FindPropertySheet(
  455. (MMC_COOKIE)&item,
  456. const_cast<SnapInView*>(this),
  457. const_cast<SnapInDataItem*>(&item)
  458. );
  459. CheckError(hr);
  460. return hr == S_OK;
  461. }
  462. IToolbar* SnapInView::attachToolbar(size_t index)
  463. {
  464. // Make sure we have a controlbar.
  465. if (!controlbar) { AfxThrowOleException(E_POINTER); }
  466. // Get the entry for this index.
  467. ToolbarEntry& entry = toolbars[index];
  468. // Create the toolbar if necessary.
  469. if (!entry.toolbar)
  470. {
  471. // Create the toolbar.
  472. CComPtr<IUnknown> unk;
  473. CheckError(controlbar->Create(TOOLBAR, this, &unk));
  474. CComPtr<IToolbar> newToolbar;
  475. CheckError(unk->QueryInterface(__uuidof(IToolbar), (PVOID*)&newToolbar));
  476. const SnapInToolbarDef& def = *(entry.def);
  477. // Add the bitmaps.
  478. CheckError(newToolbar->AddBitmap(
  479. def.nImages,
  480. def.hbmp,
  481. 16,
  482. 16,
  483. def.crMask
  484. ));
  485. // Add the buttons.
  486. CheckError(newToolbar->AddButtons( def.nButtons, def.lpButtons));
  487. // All went well, so save it away.
  488. entry.toolbar = newToolbar;
  489. }
  490. // Attach the toolbar to the controlbar ...
  491. CheckError(controlbar->Attach(TOOLBAR, entry.toolbar));
  492. return entry.toolbar;
  493. }
  494. void SnapInView::detachToolbar(size_t index) throw ()
  495. {
  496. if (toolbars[index].toolbar)
  497. {
  498. // We don't care if this fails, because there's nothing we can do about
  499. // it anyway.
  500. controlbar->Detach(toolbars[index].toolbar);
  501. }
  502. }
  503. void SnapInView::reSort() const
  504. {
  505. CheckError(resultData->Sort(sortColumn, sortOption, 0));
  506. }
  507. void SnapInView::formatMessageBox(
  508. UINT titleId,
  509. UINT formatId,
  510. BOOL ignoreInserts,
  511. UINT style,
  512. int* retval,
  513. ...
  514. )
  515. {
  516. ResourceString title(titleId);
  517. ResourceString format(formatId);
  518. HRESULT hr;
  519. if (ignoreInserts)
  520. {
  521. hr = console->MessageBox(
  522. format,
  523. title,
  524. style,
  525. retval
  526. );
  527. }
  528. else
  529. {
  530. va_list marker;
  531. va_start(marker, retval);
  532. PWSTR text;
  533. DWORD nchar = FormatMessageW(
  534. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  535. FORMAT_MESSAGE_FROM_STRING,
  536. format,
  537. 0,
  538. 0,
  539. (PWSTR)&text,
  540. 4096,
  541. &marker
  542. );
  543. va_end(marker);
  544. if (!nchar) { AfxThrowLastError(); }
  545. hr = console->MessageBox(
  546. text,
  547. title,
  548. style,
  549. retval
  550. );
  551. LocalFree(text);
  552. }
  553. CheckError(hr);
  554. }
  555. void SnapInView::setImageStrip(
  556. UINT smallStripId,
  557. UINT largeStripId,
  558. BOOL scopePane
  559. )
  560. {
  561. //////////
  562. // Load the bitmaps.
  563. //////////
  564. HBITMAP smallStrip, largeStrip;
  565. smallStrip = LoadBitmap(
  566. _Module.GetModuleInstance(),
  567. MAKEINTRESOURCE(smallStripId)
  568. );
  569. if (smallStrip)
  570. {
  571. largeStrip = LoadBitmap(
  572. _Module.GetModuleInstance(),
  573. MAKEINTRESOURCE(largeStripId)
  574. );
  575. }
  576. if (!smallStrip || !largeStrip)
  577. {
  578. AfxThrowLastError();
  579. }
  580. //////////
  581. // Set the image strip.
  582. //////////
  583. HRESULT hr;
  584. IImageList* imageList;
  585. if (scopePane)
  586. {
  587. hr = console->QueryScopeImageList(&imageList);
  588. }
  589. else
  590. {
  591. hr = console->QueryResultImageList(&imageList);
  592. }
  593. if (SUCCEEDED(hr))
  594. {
  595. hr = imageList->ImageListSetStrip(
  596. (LONG_PTR*)smallStrip,
  597. (LONG_PTR*)largeStrip,
  598. 0,
  599. RGB(255, 0, 255)
  600. );
  601. imageList->Release();
  602. }
  603. DeleteObject(smallStrip);
  604. DeleteObject(largeStrip);
  605. CheckError(hr);
  606. }
  607. STDMETHODIMP_(ULONG) SnapInView::AddRef()
  608. {
  609. return InternalAddRef();
  610. }
  611. STDMETHODIMP_(ULONG) SnapInView::Release()
  612. {
  613. ULONG l = InternalRelease();
  614. if (l == 0) { delete this; }
  615. return l;
  616. }
  617. STDMETHODIMP SnapInView::Initialize(LPCONSOLE lpConsole)
  618. {
  619. HRESULT hr;
  620. hr = lpConsole->QueryInterface(
  621. __uuidof(IConsole2),
  622. (PVOID*)&console
  623. );
  624. if (FAILED(hr)) { return hr; }
  625. hr = lpConsole->QueryInterface(
  626. __uuidof(IHeaderCtrl2),
  627. (PVOID*)&headerCtrl
  628. );
  629. if (FAILED(hr)) { return hr; }
  630. hr = lpConsole->QueryInterface(
  631. __uuidof(sheetProvider),
  632. (PVOID*)&sheetProvider
  633. );
  634. if (FAILED(hr)) { return hr; }
  635. hr = lpConsole->QueryInterface(
  636. __uuidof(IResultData),
  637. (PVOID*)&resultData
  638. );
  639. if (FAILED(hr)) { return hr; }
  640. return S_OK;
  641. }
  642. STDMETHODIMP SnapInView::Destroy(MMC_COOKIE cookie)
  643. {
  644. resultData.Release();
  645. sheetProvider.Release();
  646. headerCtrl.Release();
  647. console.Release();
  648. nameSpace.Release();
  649. return S_OK;
  650. }
  651. STDMETHODIMP SnapInView::GetResultViewType(
  652. MMC_COOKIE cookie,
  653. LPOLESTR* ppViewType,
  654. long* pViewOptions
  655. )
  656. {
  657. return ((SnapInDataItem*)cookie)->getResultViewType(
  658. ppViewType,
  659. pViewOptions
  660. );
  661. }
  662. STDMETHODIMP SnapInView::GetDisplayInfo(
  663. RESULTDATAITEM* pResultDataItem
  664. )
  665. {
  666. if (pResultDataItem->mask & RDI_STR)
  667. {
  668. SnapInDataItem* item = (SnapInDataItem*)(pResultDataItem->lParam);
  669. pResultDataItem->str =
  670. const_cast<PWSTR>(item->getDisplayName(pResultDataItem->nCol));
  671. }
  672. return S_OK;
  673. }
  674. STDMETHODIMP SnapInView::Initialize(LPUNKNOWN pUnknown)
  675. {
  676. HRESULT hr;
  677. CComPtr<IConsoleNameSpace2> initNameSpace;
  678. hr = pUnknown->QueryInterface(
  679. __uuidof(IConsoleNameSpace2),
  680. (PVOID*)&initNameSpace
  681. );
  682. if (FAILED(hr)) { return hr; }
  683. CComPtr<IConsole> initConsole;
  684. hr = pUnknown->QueryInterface(
  685. __uuidof(IConsole),
  686. (PVOID*)&initConsole
  687. );
  688. if (FAILED(hr)) { return hr; }
  689. hr = internalInitialize(initNameSpace, this);
  690. if (FAILED(hr)) { return hr; }
  691. return Initialize(initConsole);
  692. }
  693. STDMETHODIMP SnapInView::CreateComponent(LPCOMPONENT* ppComponent)
  694. {
  695. HRESULT hr;
  696. CComObject<SnapInView>* newComponent;
  697. hr = CComObject<SnapInView>::CreateInstance(&newComponent);
  698. if (FAILED(hr)) { return hr; }
  699. CComPtr<SnapInView> newView(newComponent);
  700. hr = newView.p->internalInitialize(nameSpace, this);
  701. if (FAILED(hr)) { return hr; }
  702. (*ppComponent = newView)->AddRef();
  703. return S_OK;
  704. }
  705. STDMETHODIMP SnapInView::Destroy()
  706. {
  707. return Destroy((MMC_COOKIE)0);
  708. }
  709. STDMETHODIMP SnapInView::GetDisplayInfo(SCOPEDATAITEM* pScopeDataItem)
  710. {
  711. if (pScopeDataItem->mask & SDI_STR)
  712. {
  713. SnapInDataItem* item = (SnapInDataItem*)(pScopeDataItem->lParam);
  714. pScopeDataItem->displayname = const_cast<PWSTR>(item->getDisplayName());
  715. }
  716. return S_OK;
  717. }
  718. STDMETHODIMP SnapInView::QueryDataObject(
  719. MMC_COOKIE cookie,
  720. DATA_OBJECT_TYPES type,
  721. LPDATAOBJECT* ppDataObject
  722. )
  723. {
  724. if (!IS_SPECIAL_COOKIE(cookie))
  725. {
  726. (*ppDataObject = (SnapInDataItem*)cookie)->AddRef();
  727. return S_OK;
  728. }
  729. else
  730. {
  731. return S_FALSE;
  732. }
  733. }
  734. STDMETHODIMP SnapInView::Notify(
  735. LPDATAOBJECT lpDataObject,
  736. MMC_NOTIFY_TYPE event,
  737. LPARAM arg,
  738. LPARAM param
  739. )
  740. {
  741. // Extract the SnapInDataItem.
  742. SnapInDataItem* item;
  743. if (IS_SPECIAL_DATAOBJECT(lpDataObject))
  744. {
  745. item = NULL;
  746. }
  747. else
  748. {
  749. item = SnapInDataItem::narrow(lpDataObject);
  750. }
  751. HRESULT hr = S_FALSE;
  752. try
  753. {
  754. if (item)
  755. {
  756. // If we have a SnapInDataItem, dispatch the notification ...
  757. switch (event)
  758. {
  759. case MMCN_BTN_CLICK:
  760. hr = item->onButtonClick(*this, (MMC_CONSOLE_VERB)param);
  761. break;
  762. case MMCN_CONTEXTHELP:
  763. hr = item->onContextHelp(*this);
  764. break;
  765. case MMCN_DELETE:
  766. hr = item->onDelete(*this);
  767. break;
  768. case MMCN_DBLCLICK:
  769. hr = item->onDoubleClick(*this);
  770. break;
  771. case MMCN_EXPAND:
  772. hr = item->onExpand(*this, (HSCOPEITEM)param, (BOOL)arg);
  773. break;
  774. case MMCN_REFRESH:
  775. hr = item->onRefresh(*this);
  776. break;
  777. case MMCN_RENAME:
  778. hr = item->onRename(*this, (LPOLESTR)param);
  779. break;
  780. case MMCN_SELECT:
  781. hr = item->onSelect(*this, LOWORD(arg), HIWORD(arg));
  782. break;
  783. case MMCN_SHOW:
  784. hr = item->onShow(*this, (HSCOPEITEM)param, (BOOL)arg);
  785. break;
  786. case MMCN_VIEW_CHANGE:
  787. hr = item->onViewChange(*this, arg, param);
  788. }
  789. }
  790. else
  791. {
  792. // ... otherwise, handle it ourselves.
  793. switch (event)
  794. {
  795. case MMCN_COLUMN_CLICK:
  796. sortColumn = (int)arg;
  797. sortOption = (int)param;
  798. break;
  799. case MMCN_PROPERTY_CHANGE:
  800. {
  801. hr = ((SnapInDataItem*)param)->onPropertyChange(*this, arg);
  802. break;
  803. }
  804. }
  805. }
  806. }
  807. CATCH_AND_SAVE(hr);
  808. return hr;
  809. }
  810. STDMETHODIMP SnapInView::CompareObjects(
  811. LPDATAOBJECT lpDataObjectA,
  812. LPDATAOBJECT lpDataObjectB
  813. )
  814. {
  815. return SnapInDataItem::narrow(lpDataObjectA) ==
  816. SnapInDataItem::narrow(lpDataObjectB) ? S_OK : S_FALSE;
  817. }
  818. STDMETHODIMP SnapInView::AddMenuItems(
  819. LPDATAOBJECT lpDataObject,
  820. LPCONTEXTMENUCALLBACK piCallback,
  821. long *pInsertionAllowed
  822. )
  823. {
  824. SnapInDataItem* item = SnapInDataItem::narrow(lpDataObject);
  825. if (!item) { return S_FALSE; }
  826. HRESULT hr;
  827. try
  828. {
  829. hr = item->addMenuItems(*this, piCallback, *pInsertionAllowed);
  830. }
  831. CATCH_AND_SAVE(hr);
  832. return hr;
  833. }
  834. STDMETHODIMP SnapInView::Command(
  835. long lCommandID,
  836. LPDATAOBJECT lpDataObject
  837. )
  838. {
  839. SnapInDataItem* item = SnapInDataItem::narrow(lpDataObject);
  840. if (!item) { return S_FALSE; }
  841. HRESULT hr;
  842. try
  843. {
  844. hr = item->onMenuCommand(*this, lCommandID);
  845. }
  846. CATCH_AND_SAVE(hr);
  847. return hr;
  848. }
  849. STDMETHODIMP SnapInView::ControlbarNotify(
  850. MMC_NOTIFY_TYPE event,
  851. LPARAM arg,
  852. LPARAM param
  853. )
  854. {
  855. // If we don't have a controlbar, there's nothing we can do.
  856. if (!controlbar) { return S_FALSE; }
  857. // Get the IDataObject.
  858. IDataObject* lpDataObject;
  859. switch (event)
  860. {
  861. case MMCN_BTN_CLICK:
  862. lpDataObject = (IDataObject*)arg;
  863. break;
  864. case MMCN_SELECT:
  865. lpDataObject = (IDataObject*)param;
  866. break;
  867. default:
  868. lpDataObject = NULL;
  869. }
  870. // Convert to a SnapInDataItem.
  871. if (IS_SPECIAL_DATAOBJECT(lpDataObject)) { return S_FALSE; }
  872. SnapInDataItem* item = SnapInDataItem::narrow(lpDataObject);
  873. if (!item) { return S_FALSE; }
  874. // Dispatch the notification.
  875. HRESULT hr = S_FALSE;
  876. try
  877. {
  878. switch (event)
  879. {
  880. case MMCN_BTN_CLICK:
  881. hr = item->onToolbarButtonClick(*this, param);
  882. break;
  883. case MMCN_SELECT:
  884. hr = item->onToolbarSelect(*this, LOWORD(arg), HIWORD(arg));
  885. break;
  886. }
  887. }
  888. CATCH_AND_SAVE(hr);
  889. return hr;
  890. }
  891. STDMETHODIMP SnapInView::SetControlbar(
  892. LPCONTROLBAR pControlbar
  893. )
  894. {
  895. releaseToolbars();
  896. controlbar = pControlbar;
  897. return S_OK;
  898. }
  899. STDMETHODIMP SnapInView::CreatePropertyPages(
  900. LPPROPERTYSHEETCALLBACK lpProvider,
  901. LONG_PTR handle,
  902. LPDATAOBJECT lpDataObject
  903. )
  904. {
  905. SnapInDataItem* item = SnapInDataItem::narrow(lpDataObject);
  906. if (!item) { return S_FALSE; }
  907. HRESULT hr;
  908. try
  909. {
  910. hr = item->createPropertyPages(*this, lpProvider, handle);
  911. }
  912. CATCH_AND_SAVE(hr);
  913. return hr;
  914. }
  915. STDMETHODIMP SnapInView::QueryPagesFor(
  916. LPDATAOBJECT lpDataObject
  917. )
  918. {
  919. SnapInDataItem* item = SnapInDataItem::narrow(lpDataObject);
  920. return item ? item->queryPagesFor() : S_FALSE;
  921. }
  922. STDMETHODIMP SnapInView::GetWatermarks(
  923. LPDATAOBJECT lpIDataObject,
  924. HBITMAP *lphWatermark,
  925. HBITMAP *lphHeader,
  926. HPALETTE *lphPalette,
  927. BOOL *bStretch
  928. )
  929. { return E_NOTIMPL; }
  930. HRESULT SnapInView::Compare(
  931. LPARAM lUserParam,
  932. MMC_COOKIE cookieA,
  933. MMC_COOKIE cookieB,
  934. int* pnResult
  935. )
  936. {
  937. *pnResult = ((SnapInDataItem*)cookieA)->compare(
  938. *(SnapInDataItem*)cookieB,
  939. *pnResult
  940. );
  941. return S_OK;
  942. }
  943. const SnapInToolbarDef* SnapInView::getToolbars() const throw ()
  944. {
  945. static SnapInToolbarDef none;
  946. return &none;
  947. }
  948. SnapInView::SnapInView() throw ()
  949. : master(NULL),
  950. toolbars(NULL),
  951. numToolbars(0),
  952. sortColumn(0),
  953. sortOption(RSI_NOSORTICON)
  954. { }
  955. SnapInView::~SnapInView() throw ()
  956. {
  957. releaseToolbars();
  958. delete[] toolbars;
  959. if (master && master != this) { master->Release(); }
  960. }
  961. HRESULT SnapInView::internalInitialize(
  962. IConsoleNameSpace2* consoleNameSpace,
  963. SnapInView* masterView
  964. ) throw ()
  965. {
  966. nameSpace = consoleNameSpace;
  967. master = masterView;
  968. if (master != this) { master->AddRef(); }
  969. const SnapInToolbarDef* defs = master->getToolbars();
  970. // How many new toolbars are there?
  971. size_t count = 0;
  972. while (defs[count].nImages) { ++count; }
  973. if (count)
  974. {
  975. // Allocate memory ...
  976. toolbars = new (std::nothrow) ToolbarEntry[count];
  977. if (!toolbars) { return E_OUTOFMEMORY; }
  978. // ... and save the definitions. We don't actually create the toolbars
  979. // now. We do this as we need them.
  980. for (size_t i = 0; i < count; ++i)
  981. {
  982. toolbars[i].def = defs + i;
  983. }
  984. }
  985. numToolbars = count;
  986. return S_OK;
  987. }
  988. void SnapInView::releaseToolbars() throw ()
  989. {
  990. if (controlbar)
  991. {
  992. for (size_t i = 0; i < numToolbars; ++i)
  993. {
  994. if (toolbars[i].toolbar)
  995. {
  996. controlbar->Detach(toolbars[i].toolbar);
  997. toolbars[i].toolbar.Release();
  998. }
  999. }
  1000. }
  1001. }
  1002. SnapInPropertyPage::SnapInPropertyPage(
  1003. UINT nIDTemplate,
  1004. UINT nIDHeaderTitle,
  1005. UINT nIDHeaderSubTitle,
  1006. bool EnableHelp
  1007. )
  1008. : CHelpPageEx(nIDTemplate, 0, nIDHeaderTitle, nIDHeaderSubTitle, EnableHelp),
  1009. notify(0),
  1010. param(0),
  1011. owner(false),
  1012. applied(false),
  1013. modified(FALSE)
  1014. {
  1015. if (!nIDHeaderTitle)
  1016. {
  1017. m_psp.dwFlags |= PSP_HIDEHEADER;
  1018. }
  1019. }
  1020. SnapInPropertyPage::SnapInPropertyPage(
  1021. LONG_PTR notifyHandle,
  1022. LPARAM notifyParam,
  1023. bool deleteHandle,
  1024. UINT nIDTemplate,
  1025. UINT nIDCaption,
  1026. bool EnableHelp
  1027. )
  1028. : CHelpPageEx(nIDTemplate, nIDCaption, EnableHelp),
  1029. notify(notifyHandle),
  1030. param(notifyParam),
  1031. owner(deleteHandle),
  1032. applied(false),
  1033. modified(FALSE)
  1034. {
  1035. }
  1036. SnapInPropertyPage::~SnapInPropertyPage() throw ()
  1037. {
  1038. if (owner && notify) { MMCFreeNotifyHandle(notify); }
  1039. }
  1040. void SnapInPropertyPage::addToMMCSheet(IPropertySheetCallback* cback)
  1041. {
  1042. // Swap our callback for the MFC supplied one.
  1043. mfcCallback = m_psp.pfnCallback;
  1044. m_psp.pfnCallback = propSheetPageProc;
  1045. m_psp.lParam = (LPARAM)this;
  1046. HRESULT hr = MMCPropPageCallback(&m_psp);
  1047. if (SUCCEEDED(hr))
  1048. {
  1049. HPROPSHEETPAGE page = CreatePropertySheetPage(&m_psp);
  1050. if (page)
  1051. {
  1052. hr = cback->AddPage(page);
  1053. if (FAILED(hr))
  1054. {
  1055. DestroyPropertySheetPage(page);
  1056. }
  1057. }
  1058. else
  1059. {
  1060. // GetLastError() doesn't work with CreatePropertySheetPage.
  1061. hr = E_UNEXPECTED;
  1062. }
  1063. }
  1064. if (FAILED(hr)) { delete this; }
  1065. CheckError(hr);
  1066. }
  1067. void SnapInPropertyPage::DoDataExchange(CDataExchange* pDX)
  1068. {
  1069. pDX->m_bSaveAndValidate ? getData() : setData();
  1070. }
  1071. BOOL SnapInPropertyPage::OnApply()
  1072. {
  1073. // If we've been modified, ...
  1074. if (modified)
  1075. {
  1076. try
  1077. {
  1078. // Save the changes.
  1079. saveChanges();
  1080. }
  1081. catch (CException* e)
  1082. {
  1083. // Bring up a message box.
  1084. reportException(e);
  1085. // We're in an indeterminate state, so we can't cancel.
  1086. CancelToClose();
  1087. // Block the apply.
  1088. return FALSE;
  1089. }
  1090. // Notify MMC if necessary.
  1091. if (notify) { MMCPropertyChangeNotify(notify, param); }
  1092. // Set our flags.
  1093. applied = true;
  1094. modified = FALSE;
  1095. }
  1096. return TRUE;
  1097. }
  1098. BOOL SnapInPropertyPage::OnWizardFinish()
  1099. {
  1100. try
  1101. {
  1102. saveChanges();
  1103. }
  1104. catch (CException* e)
  1105. {
  1106. // Bring up a message box.
  1107. reportException(e);
  1108. // Disable all the buttons. Something's wrong, so we'll only let the user
  1109. // cancel.
  1110. ::PostMessageW(
  1111. ::GetParent(m_hWnd),
  1112. PSM_SETWIZBUTTONS,
  1113. 0,
  1114. (LPARAM)(DWORD)PSWIZB_DISABLEDFINISH
  1115. );
  1116. return FALSE;
  1117. }
  1118. return TRUE;
  1119. }
  1120. void SnapInPropertyPage::OnReset()
  1121. {
  1122. // If we've been modified, ...
  1123. if (modified)
  1124. {
  1125. // ... discard the changes.
  1126. discardChanges();
  1127. modified = FALSE;
  1128. }
  1129. }
  1130. void SnapInPropertyPage::SetModified(BOOL bChanged)
  1131. {
  1132. modified = bChanged;
  1133. CHelpPageEx::SetModified(bChanged);
  1134. }
  1135. void SnapInPropertyPage::getData()
  1136. {
  1137. }
  1138. void SnapInPropertyPage::setData()
  1139. {
  1140. }
  1141. void SnapInPropertyPage::saveChanges()
  1142. {
  1143. }
  1144. void SnapInPropertyPage::discardChanges()
  1145. {
  1146. }
  1147. void SnapInPropertyPage::enableControl(int controlId, bool enable)
  1148. {
  1149. ::EnableWindow(::GetDlgItem(m_hWnd, controlId), (enable ? TRUE : FALSE));
  1150. }
  1151. void SnapInPropertyPage::fail(int controlId, UINT errorText, bool isEdit)
  1152. {
  1153. failNoThrow(controlId, errorText, isEdit);
  1154. AfxThrowUserException();
  1155. }
  1156. void SnapInPropertyPage::failNoThrow(int controlId, UINT errorText, bool isEdit)
  1157. {
  1158. // Give the offending control the focus.
  1159. HWND ctrl = ::GetDlgItem(m_hWnd, controlId);
  1160. ::SetFocus(ctrl);
  1161. if (isEdit) { ::SendMessage(ctrl, EM_SETSEL, 0, -1); }
  1162. // Bring up a message box.
  1163. reportError(errorText);
  1164. }
  1165. void SnapInPropertyPage::initControl(int controlId, CWnd& control)
  1166. {
  1167. if (control.m_hWnd == NULL)
  1168. {
  1169. if (!control.SubclassWindow(::GetDlgItem(m_hWnd, controlId)))
  1170. {
  1171. AfxThrowNotSupportedException();
  1172. }
  1173. }
  1174. }
  1175. void SnapInPropertyPage::onChange()
  1176. {
  1177. SetModified();
  1178. }
  1179. void SnapInPropertyPage::reportError(UINT errorText)
  1180. {
  1181. // Bring up a message box.
  1182. MessageBox(
  1183. ResourceString(errorText),
  1184. ResourceString(getErrorCaption()),
  1185. MB_ICONWARNING
  1186. );
  1187. }
  1188. void SnapInPropertyPage::reportException(CException* e)
  1189. {
  1190. // Get the error message.
  1191. WCHAR errorText[256];
  1192. e->GetErrorMessage(errorText, sizeof(errorText)/sizeof(errorText[0]));
  1193. e->Delete();
  1194. // Bring up a message box.
  1195. MessageBox(
  1196. errorText,
  1197. ResourceString(getErrorCaption()),
  1198. MB_ICONERROR
  1199. );
  1200. }
  1201. void SnapInPropertyPage::setLargeFont(int controlId)
  1202. {
  1203. static CFont largeFont;
  1204. CWnd* ctrl = GetDlgItem(controlId);
  1205. if (ctrl)
  1206. {
  1207. // If we don't have the large font yet, ...
  1208. if (!(HFONT)largeFont)
  1209. {
  1210. // ... create it.
  1211. largeFont.CreatePointFont(
  1212. 10 * _wtoi(ResourceString(IDS_LARGE_FONT_SIZE)),
  1213. ResourceString(IDS_LARGE_FONT_NAME)
  1214. );
  1215. }
  1216. ctrl->SetFont(&largeFont);
  1217. }
  1218. }
  1219. void SnapInPropertyPage::showControl(int controlId, bool show)
  1220. {
  1221. CWnd* ctrl = GetDlgItem(controlId);
  1222. if (ctrl)
  1223. {
  1224. show ? ctrl->ModifyStyle(0, WS_VISIBLE)
  1225. : ctrl->ModifyStyle(WS_VISIBLE, 0);
  1226. }
  1227. }
  1228. void SnapInPropertyPage::getValue(
  1229. int controlId,
  1230. LONG& value,
  1231. UINT errorText
  1232. )
  1233. {
  1234. WCHAR buffer[32];
  1235. int len = GetDlgItemText(controlId, buffer, 32);
  1236. // We'll fail anything that's longer than 30 characters. This is an
  1237. // arbitrary bound. We just need to make sure that buffer is long enough to
  1238. // hold any valid integer plus a little whitespace.
  1239. if (len == 0 || len > 30)
  1240. {
  1241. fail(controlId, errorText);
  1242. }
  1243. // Skip any leading whitespace.
  1244. PWSTR sz = buffer;
  1245. while (*sz == L' ' && *sz == L'\t') { ++sz; }
  1246. // Save the first non-whitespace character.
  1247. WCHAR first = *sz;
  1248. // Convert the integer.
  1249. value = wcstol(sz, &sz, 10);
  1250. // Skip any trailing whitespace.
  1251. while (*sz == L' ' && *sz == L'\t') { ++sz; }
  1252. // Make sure all went well.
  1253. if ((value == 0 && first != L'0') ||
  1254. *sz != L'\0' ||
  1255. value == LONG_MIN ||
  1256. value == LONG_MAX)
  1257. {
  1258. fail(controlId, errorText);
  1259. }
  1260. }
  1261. void SnapInPropertyPage::setValue(
  1262. int controlId,
  1263. LONG value
  1264. )
  1265. {
  1266. WCHAR buffer[12];
  1267. SetDlgItemText(controlId, _ltow(value, buffer, 10));
  1268. }
  1269. void SnapInPropertyPage::getValue(
  1270. int controlId,
  1271. bool& value
  1272. )
  1273. {
  1274. value = IsDlgButtonChecked(controlId) != 0;
  1275. }
  1276. void SnapInPropertyPage::setValue(
  1277. int controlId,
  1278. bool value
  1279. )
  1280. {
  1281. CheckDlgButton(controlId, (value ? BST_CHECKED : BST_UNCHECKED));
  1282. }
  1283. void SnapInPropertyPage::getValue(
  1284. int controlId,
  1285. CComBSTR& value,
  1286. bool trim
  1287. )
  1288. {
  1289. HWND hwnd = ::GetDlgItem(m_hWnd, controlId);
  1290. int len = ::GetWindowTextLength(hwnd);
  1291. SysFreeString(value.m_str);
  1292. value.m_str = SysAllocStringLen(NULL, len);
  1293. if (!value) { AfxThrowMemoryException(); }
  1294. ::GetWindowTextW(hwnd, value, len + 1);
  1295. if (trim) { SdoTrimBSTR(value); }
  1296. }
  1297. void SnapInPropertyPage::setValue(
  1298. int controlId,
  1299. PCWSTR value
  1300. )
  1301. {
  1302. SetDlgItemText(controlId, value);
  1303. }
  1304. void SnapInPropertyPage::getRadio(
  1305. int firstId,
  1306. int lastId,
  1307. LONG& value
  1308. )
  1309. {
  1310. value = GetCheckedRadioButton(firstId, lastId);
  1311. value = value ? value - firstId : -1;
  1312. }
  1313. void SnapInPropertyPage::setRadio(
  1314. int firstId,
  1315. int lastId,
  1316. LONG value
  1317. )
  1318. {
  1319. CheckRadioButton(firstId, lastId, firstId + value);
  1320. }
  1321. UINT CALLBACK SnapInPropertyPage::propSheetPageProc(
  1322. HWND hwnd,
  1323. UINT uMsg,
  1324. LPPROPSHEETPAGE ppsp
  1325. ) throw ()
  1326. {
  1327. SnapInPropertyPage* page = (SnapInPropertyPage*)(ppsp->lParam);
  1328. UINT retval = page->mfcCallback(hwnd, uMsg, ppsp);
  1329. if (uMsg == PSPCB_RELEASE) { delete page; }
  1330. return retval;
  1331. }