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.

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