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.

856 lines
23 KiB

  1. ////////////////////////////////////////////////////////////////////////////
  2. // File: TBExt.cpp (toolbar extension classes)
  3. // Author: Karim Farouki
  4. //
  5. // We define here three classes:
  6. // (1) CToolbarExt a base class that takes care of the
  7. // button work for our custom extensions
  8. // (2) CToolbarExtBand the object which deals with custom
  9. // buttons that plug into bands
  10. // (3) CToolbarExtExec the object which deals with custom
  11. // buttons (or tools menu items) that exec stuff.
  12. //
  13. // The latter two are derived from the former
  14. #include "priv.h"
  15. #include <mshtmcid.h>
  16. #include "tbext.h"
  17. //////////////////////////////
  18. // Class CToolbarExt
  19. //
  20. // This is the base class from which CToolbarExtBand and CToolbarExtExec
  21. // both inherit. It takes care of all the ToolbarButton specific stuff
  22. // like lazy loading the appropriate icons, and keeping track of the button
  23. // text.
  24. // Constructor / Destructor
  25. //
  26. CToolbarExt::CToolbarExt() : _cRef(1)
  27. {
  28. ASSERT(_hIcon == NULL);
  29. ASSERT(_hIconSm == NULL);
  30. ASSERT(_hHotIcon == NULL);
  31. ASSERT(_hHotIconSm == NULL);
  32. ASSERT(_bstrButtonText == NULL);
  33. ASSERT(_bstrToolTip == NULL);
  34. ASSERT(_hkeyThisExtension == NULL);
  35. ASSERT(_hkeyCurrentLang == NULL);
  36. ASSERT(_pisb == NULL);
  37. DllAddRef();
  38. }
  39. // Destructor
  40. //
  41. CToolbarExt::~CToolbarExt()
  42. {
  43. if (_pisb)
  44. _pisb->Release();
  45. if (_bstrButtonText)
  46. SysFreeString(_bstrButtonText);
  47. if (_bstrToolTip)
  48. SysFreeString(_bstrToolTip);
  49. if (_hIcon)
  50. DestroyIcon(_hIcon);
  51. if (_hIconSm)
  52. DestroyIcon(_hIconSm);
  53. if (_hHotIcon)
  54. DestroyIcon(_hHotIcon);
  55. if (_hHotIconSm)
  56. DestroyIcon(_hHotIconSm);
  57. if (_hkeyThisExtension)
  58. RegCloseKey(_hkeyThisExtension);
  59. if (_hkeyCurrentLang)
  60. RegCloseKey(_hkeyCurrentLang);
  61. DllRelease();
  62. }
  63. // IUnknown implementation
  64. //
  65. STDMETHODIMP CToolbarExt::QueryInterface(const IID& iid, void** ppv)
  66. {
  67. if (iid == IID_IUnknown)
  68. *ppv = static_cast<IBrowserExtension*>(this);
  69. else if (iid == IID_IBrowserExtension)
  70. *ppv = static_cast<IBrowserExtension*>(this);
  71. else if (iid == IID_IOleCommandTarget)
  72. *ppv = static_cast<IOleCommandTarget*>(this);
  73. else if (iid == IID_IObjectWithSite)
  74. *ppv = static_cast<IObjectWithSite*>(this);
  75. else
  76. {
  77. *ppv = NULL;
  78. return E_NOINTERFACE;
  79. }
  80. reinterpret_cast<IUnknown*>(*ppv)->AddRef();
  81. return S_OK;
  82. }
  83. STDMETHODIMP_(ULONG) CToolbarExt::AddRef()
  84. {
  85. return InterlockedIncrement(&_cRef);
  86. }
  87. STDMETHODIMP_(ULONG) CToolbarExt::Release()
  88. {
  89. if (InterlockedDecrement(&_cRef) == 0)
  90. {
  91. delete this;
  92. return 0;
  93. }
  94. return _cRef;
  95. }
  96. // IBrowserExtension::Init Implementation. We'll read the ButtonText here but wait on the icons until
  97. // a specific variant of the icon is requested.
  98. STDMETHODIMP CToolbarExt::Init(REFGUID rguid)
  99. {
  100. HRESULT hr = S_OK;
  101. LPOLESTR pszGUID;
  102. if (SUCCEEDED(StringFromCLSID(rguid, &pszGUID)))
  103. {
  104. //Open the extension reg key associated with this guid
  105. WCHAR szKey[MAX_PATH];
  106. StrCpyN(szKey, TEXT("Software\\Microsoft\\Internet Explorer\\Extensions\\"), ARRAYSIZE(szKey));
  107. StrCatBuff(szKey, pszGUID, ARRAYSIZE(szKey));
  108. // We will keep _hkeyThisExtension around... it will be closed in the destructor!
  109. if (RegOpenKeyEx(HKEY_CURRENT_USER, szKey, 0, KEY_READ, &_hkeyThisExtension) == ERROR_SUCCESS ||
  110. RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKey, 0, KEY_READ, &_hkeyThisExtension) == ERROR_SUCCESS)
  111. {
  112. // See if there is a subkey for the current language
  113. LANGID langid = MLGetUILanguage();
  114. WCHAR szBuff[MAX_PATH];
  115. wnsprintf(szBuff, ARRAYSIZE(szBuff), L"Lang%04x", langid);
  116. RegOpenKeyEx(_hkeyThisExtension, szBuff, 0, KEY_READ, &_hkeyCurrentLang);
  117. // Now get the button text
  118. _RegReadString(_hkeyThisExtension, TEXT("ButtonText"), &_bstrButtonText);
  119. }
  120. CoTaskMemFree(pszGUID);
  121. }
  122. if (!_bstrButtonText)
  123. hr = E_FAIL;
  124. return hr;
  125. }
  126. //
  127. // Gets the icon closest to the desired size from an .ico file or from the
  128. // resource in a .dll of .exe file
  129. //
  130. HICON CToolbarExt::_ExtractIcon
  131. (
  132. LPWSTR pszPath, // file to get icon from
  133. int resid, // resource id (0 if unused)
  134. int cx, // desired icon width
  135. int cy // desired icon height
  136. )
  137. {
  138. HICON hIcon = NULL;
  139. WCHAR szPath[MAX_PATH];
  140. SHExpandEnvironmentStrings(pszPath, szPath, ARRAYSIZE(szPath));
  141. // If no resource id, assume it's an ico file
  142. if (resid == 0)
  143. {
  144. hIcon = (HICON)LoadImage(0, szPath, IMAGE_ICON, cx, cy, LR_LOADFROMFILE);
  145. }
  146. // Otherwise, see if it's a resouce
  147. if (hIcon == NULL)
  148. {
  149. HINSTANCE hInst = LoadLibraryEx(szPath, NULL, LOAD_LIBRARY_AS_DATAFILE);
  150. if (hInst)
  151. {
  152. hIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(resid), IMAGE_ICON, cx, cy, LR_DEFAULTCOLOR);
  153. FreeLibrary(hInst);
  154. }
  155. }
  156. return hIcon;
  157. }
  158. //
  159. // Returns the desired icon in pvarProperty
  160. //
  161. HRESULT CToolbarExt::_GetIcon
  162. (
  163. LPCWSTR pszIcon, // Name of icon value in registry
  164. int nWidth, // icon width
  165. int nHeight, // icon height
  166. HICON& rhIcon, // location to cached icon
  167. VARIANTARG * pvarProperty // used for return icon
  168. )
  169. {
  170. HRESULT hr = S_OK;
  171. if (pvarProperty)
  172. {
  173. if (rhIcon == NULL)
  174. {
  175. BSTR bstrIconName;
  176. if (_RegReadString(_hkeyThisExtension, pszIcon, &bstrIconName, TRUE))
  177. {
  178. // Parse entry such as "file.ext,1" to get the icon index
  179. int nIconIndex = PathParseIconLocation(bstrIconName);
  180. // If the entry was ",#" then it's an index into our built-in button bitmap
  181. if (*bstrIconName == L'\0')
  182. {
  183. pvarProperty->vt = VT_I4;
  184. pvarProperty->lVal = nIconIndex;
  185. SysFreeString(bstrIconName);
  186. return hr;
  187. }
  188. else
  189. {
  190. rhIcon = _ExtractIcon(bstrIconName, nIconIndex, nWidth, nHeight);
  191. }
  192. SysFreeString(bstrIconName);
  193. }
  194. }
  195. if (rhIcon)
  196. {
  197. pvarProperty->vt = VT_BYREF;
  198. pvarProperty->byref = rhIcon;
  199. }
  200. else
  201. {
  202. VariantInit(pvarProperty);
  203. }
  204. }
  205. return hr;
  206. }
  207. //
  208. // Implementation of IBrowserExtension::GetProperty(). There are two important points here:
  209. // (1) We are lazy loading the appropriate icons. This way if the user never goes into small icon
  210. // mode we never create the images...
  211. // (2) If we are called with a NULL pvarProperty then we must still return S_OK if the iPropID
  212. // is for a property that we support and E_NOTIMPL if we do not. This is why the if (pvarProperty)
  213. // check is done for each case rather tan outside the case block. This behavior is important
  214. // for CBrowserExtension::Update() who passes in a NULL pvarProperty but still is trying to determine
  215. // what kind of extension this is!
  216. //
  217. STDMETHODIMP CToolbarExt::GetProperty(SHORT iPropID, VARIANTARG * pvarProperty)
  218. {
  219. HRESULT hr = S_OK;
  220. if (pvarProperty)
  221. VariantInit(pvarProperty); // in case of failure
  222. switch (iPropID)
  223. {
  224. case TBEX_BUTTONTEXT:
  225. if (pvarProperty)
  226. {
  227. pvarProperty->bstrVal = SysAllocString(_bstrButtonText);
  228. if (pvarProperty->bstrVal)
  229. {
  230. pvarProperty->vt = VT_BSTR;
  231. }
  232. else
  233. {
  234. hr = E_OUTOFMEMORY;
  235. }
  236. }
  237. break;
  238. case TBEX_GRAYICON:
  239. // For Whistler, we now use a 24 x 24 icons
  240. if (SHUseClassicToolbarGlyphs())
  241. {
  242. hr = _GetIcon(TEXT("Icon"), 20, 20, _hIcon, pvarProperty);
  243. }
  244. else
  245. {
  246. hr = _GetIcon(TEXT("Icon"), 24, 24, _hIcon, pvarProperty);
  247. }
  248. break;
  249. case TBEX_GRAYICONSM:
  250. hr = _GetIcon(TEXT("Icon"), 16, 16, _hIconSm, pvarProperty);
  251. break;
  252. case TBEX_HOTICON:
  253. // For Whistler, we now use a 24 x 24 icons
  254. if (SHUseClassicToolbarGlyphs())
  255. {
  256. hr = _GetIcon(TEXT("HotIcon"), 20, 20, _hHotIcon, pvarProperty);
  257. }
  258. else
  259. {
  260. hr = _GetIcon(TEXT("HotIcon"), 24, 24, _hHotIcon, pvarProperty);
  261. }
  262. break;
  263. case TBEX_HOTICONSM:
  264. hr = _GetIcon(TEXT("HotIcon"), 16, 16, _hHotIconSm, pvarProperty);
  265. break;
  266. case TBEX_DEFAULTVISIBLE:
  267. if (pvarProperty)
  268. {
  269. BOOL fVisible = _RegGetBoolValue(L"Default Visible", FALSE);
  270. pvarProperty->vt = VT_BOOL;
  271. pvarProperty->boolVal = fVisible ? VARIANT_TRUE : VARIANT_FALSE;
  272. }
  273. break;
  274. default:
  275. hr = E_NOTIMPL;
  276. }
  277. return hr;
  278. }
  279. //
  280. // IOleCommandTarget Implementation
  281. //
  282. STDMETHODIMP CToolbarExt::QueryStatus(const GUID* pguidCmdGroup, ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT* pCmdText)
  283. {
  284. HRESULT hr = OLECMDERR_E_UNKNOWNGROUP;
  285. if (pguidCmdGroup && IsEqualGUID(*pguidCmdGroup, CLSID_ToolbarExtButtons))
  286. {
  287. // Default to all commands enabled
  288. for (ULONG i = 0; i < cCmds; i++)
  289. {
  290. // if (prgCmds[i].cmdID == 1)
  291. // Execing this object is supported and can be done at this point
  292. rgCmds[i].cmdf = OLECMDF_ENABLED | OLECMDF_SUPPORTED;
  293. // else
  294. // prgCmds[i].cmdf = 0;
  295. }
  296. hr = S_OK;
  297. }
  298. // Return an empty pCmdText
  299. if (pCmdText != NULL)
  300. {
  301. pCmdText->cwActual = 0;
  302. }
  303. return hr;
  304. }
  305. //
  306. // IObjectWithSite Implementation
  307. //
  308. STDMETHODIMP CToolbarExt::SetSite(IUnknown* pUnkSite)
  309. {
  310. if (_pisb != NULL)
  311. {
  312. _pisb->Release();
  313. _pisb = NULL;
  314. }
  315. if (pUnkSite)
  316. pUnkSite->QueryInterface(IID_IShellBrowser, (void **)&_pisb);
  317. return S_OK;
  318. }
  319. STDMETHODIMP CToolbarExt::GetSite(REFIID riid, void ** ppvSite)
  320. {
  321. return E_NOTIMPL;
  322. }
  323. BOOL CToolbarExt::_RegGetBoolValue
  324. (
  325. LPCWSTR pszPropName,
  326. BOOL fDefault
  327. )
  328. {
  329. WCHAR szData[MAX_PATH];
  330. DWORD cbData = SIZEOF(szData);
  331. if ((_hkeyCurrentLang && RegQueryValueEx(_hkeyCurrentLang, pszPropName, NULL, NULL, (unsigned char *)szData, &cbData) == ERROR_SUCCESS) ||
  332. (_hkeyThisExtension && RegQueryValueEx(_hkeyThisExtension, pszPropName, NULL, NULL, (unsigned char *)szData, &cbData) == ERROR_SUCCESS))
  333. {
  334. if ((0 == StrCmpI(L"TRUE", szData)) ||
  335. (0 == StrCmpI(L"YES", szData)))
  336. {
  337. fDefault = TRUE; // We read TRUE from the registry.
  338. }
  339. else if ((0 == StrCmpI(L"FALSE", szData)) ||
  340. (0 == StrCmpI(L"NO", szData)))
  341. {
  342. fDefault = FALSE; // We read TRUE from the registry.
  343. }
  344. }
  345. return fDefault;
  346. }
  347. // Private Helper Functions
  348. //
  349. // shlwapi has some similar function; however, they all insist on reopening and closing the key in question
  350. // with each read. It is explicitly suggested that we use our own helper if we are caching the key...
  351. BOOL CToolbarExt::_RegReadString
  352. (
  353. HKEY hkeyThisExtension,
  354. LPCWSTR pszPropName,
  355. BSTR * pbstrProp,
  356. BOOL fExpand // = FALSE, Expand Environment strings
  357. )
  358. {
  359. WCHAR szData[MAX_PATH];
  360. *pbstrProp = NULL;
  361. BOOL fSuccess = FALSE;
  362. // First try the optional location for localized content
  363. if (_hkeyCurrentLang)
  364. {
  365. if (SUCCEEDED(SHLoadRegUIString(_hkeyCurrentLang, pszPropName, szData, ARRAYSIZE(szData))))
  366. {
  367. fSuccess = TRUE;
  368. }
  369. }
  370. // Next try default location
  371. if (!fSuccess && _hkeyThisExtension)
  372. {
  373. if (SUCCEEDED(SHLoadRegUIString(hkeyThisExtension, pszPropName, szData, ARRAYSIZE(szData))))
  374. {
  375. fSuccess = TRUE;
  376. }
  377. }
  378. if (fSuccess)
  379. {
  380. LPWSTR psz = szData;
  381. WCHAR szExpand[MAX_PATH];
  382. if (fExpand)
  383. {
  384. SHExpandEnvironmentStrings(szData, szExpand, ARRAYSIZE(szExpand));
  385. psz = szExpand;
  386. }
  387. *pbstrProp = SysAllocString(psz);
  388. }
  389. return (NULL != *pbstrProp);
  390. }
  391. ///////////////////////////////////////////////////////////
  392. // Class CToolbarExtBand
  393. //
  394. // This class adds to the base functionality of CToolbarExt
  395. // by storing the CLSID for a registered band, and displaying that
  396. // band upon execution of IOleCommandTarget::Exec
  397. //
  398. //
  399. STDAPI CToolbarExtBand_CreateInstance(
  400. IUnknown * punkOuter,
  401. IUnknown ** ppunk,
  402. LPCOBJECTINFO poi
  403. )
  404. {
  405. HRESULT hr = S_OK;
  406. *ppunk = NULL;
  407. CToolbarExtBand * lpTEB = new CToolbarExtBand();
  408. if (lpTEB == NULL)
  409. hr = E_OUTOFMEMORY;
  410. else
  411. *ppunk = SAFECAST(lpTEB, IBrowserExtension *);
  412. return hr;
  413. }
  414. // Constructor / Destructor
  415. //
  416. CToolbarExtBand::CToolbarExtBand()
  417. {
  418. ASSERT(_cRef == 1);
  419. ASSERT(_bBandState == FALSE);
  420. ASSERT(_bstrBandCLSID == NULL);
  421. }
  422. // Destructor
  423. //
  424. CToolbarExtBand::~CToolbarExtBand()
  425. {
  426. if (_bstrBandCLSID)
  427. SysFreeString(_bstrBandCLSID);
  428. }
  429. // IBrowserExtension::Init() We pass the majroity of the work on to the base class, then we load
  430. // the BandCLSID and cache it.
  431. STDMETHODIMP CToolbarExtBand::Init(REFGUID rguid)
  432. {
  433. HRESULT hr = CToolbarExt::Init(rguid);
  434. _RegReadString(_hkeyThisExtension, TEXT("BandCLSID"), &_bstrBandCLSID);
  435. if (!(_bstrButtonText && _bstrBandCLSID))
  436. hr = E_FAIL;
  437. return hr;
  438. }
  439. STDMETHODIMP CToolbarExtBand::QueryStatus
  440. (
  441. const GUID * pguidCmdGroup,
  442. ULONG cCmds,
  443. OLECMD prgCmds[],
  444. OLECMDTEXT * pCmdText
  445. )
  446. {
  447. HRESULT hr = OLECMDERR_E_UNKNOWNGROUP;
  448. if (pguidCmdGroup && IsEqualGUID(*pguidCmdGroup, CLSID_ToolbarExtButtons))
  449. {
  450. VARIANT varClsid;
  451. // Default to all commands enabled
  452. for (ULONG i = 0; i < cCmds; i++)
  453. {
  454. varClsid.vt = VT_BSTR;
  455. varClsid.bstrVal = _bstrBandCLSID;
  456. prgCmds[i].cmdf = OLECMDF_ENABLED | OLECMDF_SUPPORTED;
  457. hr = IUnknown_Exec(_pisb, &CGID_ShellDocView, SHDVID_ISBROWSERBARVISIBLE, 0, &varClsid, NULL);
  458. if (S_OK == hr)
  459. {
  460. prgCmds[i].cmdf |= OLECMDF_LATCHED;
  461. }
  462. }
  463. hr = S_OK;
  464. }
  465. return hr;
  466. }
  467. // Take the pIShellBrowser (obtained from IObjectWithSite::SetSite()) and disply the band
  468. STDMETHODIMP CToolbarExtBand::Exec(
  469. const GUID * pguidCmdGroup,
  470. DWORD nCmdID,
  471. DWORD nCmdexecopt,
  472. VARIANT * pvaIn,
  473. VARIANT * pvaOut
  474. )
  475. {
  476. HRESULT hr = E_FAIL;
  477. if (_pisb)
  478. {
  479. VARIANT varClsid;
  480. varClsid.vt = VT_BSTR;
  481. varClsid.bstrVal = _bstrBandCLSID;
  482. _bBandState = !_bBandState;
  483. IUnknown_Exec(_pisb, &CGID_ShellDocView, SHDVID_SHOWBROWSERBAR, _bBandState, &varClsid, NULL);
  484. hr = S_OK;
  485. }
  486. return hr;
  487. }
  488. ///////////////////////////////////////////////////////////////////////
  489. // Class CToolbarExtExec
  490. //
  491. // Expands on the base class by adding support for tools menu plug-ins.
  492. // An instance of this class can be a button OR a menu OR BOTH. It also
  493. // keeps track of a BSTR which it ShellExecutes in its IOleCommandTarget::Exec()
  494. //
  495. STDAPI CToolbarExtExec_CreateInstance(
  496. IUnknown * punkOuter,
  497. IUnknown ** ppunk,
  498. LPCOBJECTINFO poi
  499. )
  500. {
  501. HRESULT hr = S_OK;
  502. *ppunk = NULL;
  503. CToolbarExtExec * lpTEE = new CToolbarExtExec();
  504. if (lpTEE == NULL)
  505. hr = E_OUTOFMEMORY;
  506. else
  507. *ppunk = SAFECAST(lpTEE, IBrowserExtension *);
  508. return hr;
  509. }
  510. CToolbarExtExec::CToolbarExtExec()
  511. {
  512. ASSERT(_cRef == 1);
  513. ASSERT(_bstrToolTip == NULL);
  514. ASSERT(_bstrExec == NULL);
  515. ASSERT(_bstrScript == NULL);
  516. ASSERT(_bstrMenuText == NULL);
  517. ASSERT(_bstrMenuCustomize == NULL);
  518. ASSERT(_bstrMenuStatusBar == NULL);
  519. ASSERT(_punkExt == NULL);
  520. }
  521. CToolbarExtExec::~CToolbarExtExec()
  522. {
  523. if (_bstrToolTip)
  524. SysFreeString(_bstrToolTip);
  525. if (_bstrExec)
  526. SysFreeString(_bstrExec);
  527. if (_bstrScript)
  528. SysFreeString(_bstrScript);
  529. if (_bstrMenuText)
  530. SysFreeString(_bstrMenuText);
  531. if (_bstrMenuCustomize)
  532. SysFreeString(_bstrMenuCustomize);
  533. if (_bstrMenuStatusBar)
  534. SysFreeString(_bstrMenuStatusBar);
  535. if (_punkExt)
  536. _punkExt->Release();
  537. }
  538. // Pass on the work for the toolbar button intiaztion to the base class then determine the object
  539. // type and initialize the menu information if necessary...
  540. STDMETHODIMP CToolbarExtExec::Init(REFGUID rguid)
  541. {
  542. HRESULT hr = CToolbarExt::Init(rguid);
  543. // If the baseclass initialization went OK, then we have a working button
  544. if (hr == S_OK)
  545. _bButton = TRUE;
  546. // Get app and/or script to execute (optional)
  547. _RegReadString(_hkeyThisExtension, TEXT("Exec"), &_bstrExec, TRUE);
  548. _RegReadString(_hkeyThisExtension, TEXT("Script"), &_bstrScript, TRUE);
  549. // See if we have a menu item
  550. if (_RegReadString(_hkeyThisExtension, TEXT("MenuText"), &_bstrMenuText))
  551. {
  552. _RegReadString(_hkeyThisExtension, TEXT("MenuCustomize"), &_bstrMenuCustomize);
  553. _RegReadString(_hkeyThisExtension, TEXT("MenuStatusBar"), &_bstrMenuStatusBar);
  554. _bMenuItem = TRUE;
  555. }
  556. if (_bMenuItem || _bButton)
  557. {
  558. hr = S_OK;
  559. }
  560. return hr;
  561. }
  562. // It we're a button try passing the work on to the base class, if that doesn't cut it we'll
  563. // check the menu stuff...
  564. STDMETHODIMP CToolbarExtExec::GetProperty(SHORT iPropID, VARIANTARG * pvarProperty)
  565. {
  566. HRESULT hr = S_OK;
  567. BOOL fImple = FALSE;
  568. if (_bButton)
  569. {
  570. // If The generic button's getproperty returns S_OK then our job here is done
  571. if (CToolbarExt::GetProperty(iPropID, pvarProperty) == S_OK)
  572. fImple = TRUE;
  573. }
  574. if (_bMenuItem && !fImple)
  575. {
  576. fImple = TRUE;
  577. if (pvarProperty)
  578. VariantInit(pvarProperty);
  579. switch (iPropID)
  580. {
  581. case TMEX_CUSTOM_MENU:
  582. {
  583. if (pvarProperty)
  584. {
  585. pvarProperty->bstrVal = SysAllocString(_bstrMenuCustomize);
  586. if (pvarProperty->bstrVal)
  587. {
  588. pvarProperty->vt = VT_BSTR;
  589. }
  590. else
  591. {
  592. hr = E_OUTOFMEMORY;
  593. }
  594. }
  595. }
  596. break;
  597. case TMEX_MENUTEXT:
  598. if (pvarProperty)
  599. {
  600. pvarProperty->bstrVal = SysAllocString(_bstrMenuText);
  601. if (pvarProperty->bstrVal)
  602. {
  603. pvarProperty->vt = VT_BSTR;
  604. }
  605. else
  606. {
  607. hr = E_OUTOFMEMORY;
  608. }
  609. }
  610. break;
  611. case TMEX_STATUSBARTEXT:
  612. if (pvarProperty)
  613. {
  614. pvarProperty->bstrVal = SysAllocString(_bstrMenuStatusBar);
  615. if (pvarProperty->bstrVal)
  616. {
  617. pvarProperty->vt = VT_BSTR;
  618. }
  619. else
  620. {
  621. hr = E_OUTOFMEMORY;
  622. }
  623. }
  624. break;
  625. default:
  626. fImple = FALSE;
  627. }
  628. }
  629. if (!fImple)
  630. hr = E_NOTIMPL;
  631. return hr;
  632. }
  633. STDMETHODIMP CToolbarExtExec::SetSite(IUnknown* punkSite)
  634. {
  635. // Give the external object our site
  636. IUnknown_SetSite(_punkExt, punkSite);
  637. // Call base class
  638. return CToolbarExt::SetSite(punkSite);
  639. }
  640. STDMETHODIMP CToolbarExtExec::QueryStatus(const GUID * pguidCmdGroup, ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT * pCmdText)
  641. {
  642. HRESULT hr = S_OK;
  643. // Pass query to external object if it exists
  644. IOleCommandTarget* pCmd;
  645. if (_punkExt && SUCCEEDED(_punkExt->QueryInterface(IID_IOleCommandTarget, (LPVOID*)&pCmd)))
  646. {
  647. hr = pCmd->QueryStatus(pguidCmdGroup, cCmds, rgCmds, pCmdText);
  648. pCmd->Release();
  649. }
  650. else
  651. {
  652. // Let base class handle this
  653. hr = CToolbarExt::QueryStatus(pguidCmdGroup, cCmds, rgCmds, pCmdText);
  654. }
  655. return hr;
  656. }
  657. // Shell execute the _bstrExec
  658. STDMETHODIMP CToolbarExtExec::Exec(
  659. const GUID * pguidCmdGroup,
  660. DWORD nCmdId,
  661. DWORD nCmdexecopt,
  662. VARIANT * pvaIn,
  663. VARIANT * pvaOut
  664. )
  665. {
  666. HRESULT hr = S_OK;
  667. //
  668. // The first time this is called, we lazy instantiate an external object if
  669. // one is registered.. This object can JIT in components and provide a
  670. // command target.
  671. //
  672. if (!_bExecCalled)
  673. {
  674. // We only do this once
  675. _bExecCalled = TRUE;
  676. BSTR bstrExtCLSID;
  677. if (_RegReadString(_hkeyThisExtension, TEXT("clsidExtension"), &bstrExtCLSID))
  678. {
  679. // We have an extension clsid, so create the object. This gives the object an oportunity
  680. // to jit in code when its button or menu is invoked.
  681. CLSID clsidExt;
  682. if (CLSIDFromString(bstrExtCLSID, &clsidExt) == S_OK)
  683. {
  684. if (SUCCEEDED(CoCreateInstance(clsidExt, NULL, CLSCTX_INPROC_SERVER,
  685. IID_IUnknown, (void **)&_punkExt)))
  686. {
  687. // Give the object our site (optional)
  688. IUnknown_SetSite(_punkExt, _pisb);
  689. }
  690. }
  691. SysFreeString(bstrExtCLSID);
  692. }
  693. }
  694. // Pass command to external object if it exists
  695. IOleCommandTarget* pCmd;
  696. if (_punkExt && SUCCEEDED(_punkExt->QueryInterface(IID_IOleCommandTarget, (LPVOID*)&pCmd)))
  697. {
  698. hr = pCmd->Exec(pguidCmdGroup, nCmdId, nCmdexecopt, pvaIn, pvaOut);
  699. pCmd->Release();
  700. }
  701. // Run a script if one was specified
  702. if(_bstrScript && _pisb)
  703. {
  704. IOleCommandTarget *poct = NULL;
  705. VARIANT varArg;
  706. varArg.vt = VT_BSTR;
  707. varArg.bstrVal = _bstrScript;
  708. hr = _pisb->QueryInterface(IID_IOleCommandTarget, (LPVOID *)&poct);
  709. if (SUCCEEDED(hr))
  710. {
  711. // Tell MSHTML to execute the script
  712. hr = poct->Exec(&CGID_MSHTML, IDM_RUNURLSCRIPT, 0, &varArg, NULL);
  713. poct->Release();
  714. }
  715. }
  716. // Launch executable if one was specified
  717. if (_bstrExec)
  718. {
  719. SHELLEXECUTEINFO sei = { 0 };
  720. sei.cbSize = sizeof(sei);
  721. sei.lpFile = _bstrExec;
  722. sei.nShow = SW_SHOWNORMAL;
  723. // We are using ShellExecuteEx over ShellExecute because the Unicode version of ShellExecute
  724. // is bogus on 95/98
  725. if (ShellExecuteExW(&sei) == FALSE)
  726. hr = E_FAIL;
  727. }
  728. return hr;
  729. }