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.

1731 lines
55 KiB

  1. /*
  2. * isurl.cpp - IUniformResourceLocator implementation for Intshcut class.
  3. */
  4. #include "priv.h"
  5. #include "ishcut.h"
  6. #include "urlprop.h"
  7. #include "shlwapi.h"
  8. #include "infotip.h"
  9. #include "resource.h"
  10. #include <intshctp.h>
  11. #include <mluisupp.h>
  12. #define DM_PLUGGABLE DM_TRACE
  13. #define DM_SHELLEXECOBJECT 0x80000000
  14. extern HRESULT CreateTargetFrame(LPCOLESTR pszTargetName, LPUNKNOWN /*IN,OUT*/ *ppunk);
  15. BOOL
  16. GetClassDefaultVerb(
  17. LPCTSTR pcszClass,
  18. LPTSTR pszDefaultVerbBuf,
  19. UINT cchBufLen)
  20. {
  21. // No; get the default verb
  22. TCHAR szKey[MAX_PATH];
  23. StrCpyN(szKey, pcszClass, SIZECHARS(szKey));
  24. StrCatBuff(szKey, TEXT("\\"), SIZECHARS(szKey));
  25. StrCatBuff(szKey, TEXT("shell"), SIZECHARS(szKey));
  26. DWORD cbSize = CbFromCch(cchBufLen);
  27. if (NO_ERROR != SHGetValue(HKEY_CLASSES_ROOT, szKey, NULL, NULL, pszDefaultVerbBuf, &cbSize)
  28. || !*pszDefaultVerbBuf)
  29. {
  30. // Default to "open" if the registry doesn't specify one
  31. StrCpyN(pszDefaultVerbBuf, TEXT("open"), cchBufLen);
  32. }
  33. return TRUE;
  34. }
  35. #ifdef DEBUG
  36. BOOL
  37. IsValidPCURLINVOKECOMMANDINFO(
  38. PCURLINVOKECOMMANDINFO pcurlici)
  39. {
  40. return(IS_VALID_READ_PTR(pcurlici, CURLINVOKECOMMANDINFO) &&
  41. EVAL(pcurlici->dwcbSize >= SIZEOF(*pcurlici)) &&
  42. FLAGS_ARE_VALID(pcurlici->dwFlags, ALL_IURL_INVOKECOMMAND_FLAGS) &&
  43. (IsFlagClear(pcurlici->dwFlags, IURL_INVOKECOMMAND_FL_ALLOW_UI) ||
  44. NULL == pcurlici->hwndParent ||
  45. IS_VALID_HANDLE(pcurlici->hwndParent, WND)) &&
  46. (IsFlagSet(pcurlici->dwFlags, IURL_INVOKECOMMAND_FL_USE_DEFAULT_VERB) ||
  47. IS_VALID_STRING_PTR(pcurlici->pcszVerb, -1)));
  48. }
  49. #endif
  50. /********************************** Methods **********************************/
  51. typedef struct
  52. {
  53. UINT idsVerb;
  54. UINT idsMenuHelp;
  55. LPCTSTR pszVerb;
  56. } ISCM;
  57. const static ISCM g_rgiscm[] =
  58. {
  59. { IDS_MENUOPEN, IDS_MH_OPEN, TEXT("open") }, // IDCMD_ISCM_OPEN
  60. { IDS_SYNCHRONIZE, IDS_MH_SYNCHRONIZE, TEXT("update now")}, // IDCMD_ISCM_SYNC
  61. { IDS_MAKE_OFFLINE, IDS_MH_MAKE_OFFLINE, TEXT("subscribe")}, // IDCMD_ISCM_SUB
  62. };
  63. // WARNING - these must match their index into g_rgiscm
  64. #define IDCMD_ISCM_OPEN 0
  65. #define IDCMD_ISCM_SYNC 1
  66. #define IDCMD_ISCM_SUB 2
  67. BOOL _IsSubscribed(LPCWSTR pszUrl, BOOL *pfSubscribable)
  68. {
  69. BOOL fRet = FALSE;
  70. ISubscriptionMgr * pMgr;
  71. *pfSubscribable = FALSE;
  72. if (SUCCEEDED(CoCreateInstance(CLSID_SubscriptionMgr, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(ISubscriptionMgr, &pMgr))))
  73. {
  74. pMgr->IsSubscribed(pszUrl, &fRet);
  75. pMgr->Release();
  76. }
  77. if (!fRet)
  78. {
  79. //test if we CAN subscribe to this thing
  80. if (!SHRestricted2W(REST_NoAddingSubscriptions, pszUrl, 0) &&
  81. IsFeaturePotentiallyAvailable(CLSID_SubscriptionMgr))
  82. {
  83. *pfSubscribable = IsSubscribableW(pszUrl);
  84. }
  85. }
  86. else
  87. *pfSubscribable = TRUE;
  88. return fRet;
  89. }
  90. void _InsertISCM(UINT indexISCM, HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT uFlags)
  91. {
  92. TCHAR szMenu[CCH_MENUMAX];
  93. uFlags |= MF_BYPOSITION | MF_STRING;
  94. MLLoadShellLangString(g_rgiscm[indexISCM].idsVerb, szMenu, SIZECHARS(szMenu));
  95. InsertMenu_PrivateNoMungeW(hmenu, indexMenu, uFlags, idCmdFirst + indexISCM, szMenu);
  96. }
  97. // IContextMenu::QueryContextMenu handler for Intshcut
  98. // The context menu handler adds the open verb for .url
  99. // files. This is because we remove the shell\open\command
  100. // key in Nashville for this file type.
  101. STDMETHODIMP Intshcut::QueryContextMenu(
  102. IN HMENU hmenu,
  103. IN UINT indexMenu,
  104. IN UINT idCmdFirst,
  105. IN UINT idCmdLast,
  106. IN UINT uFlags)
  107. {
  108. //
  109. // LEGACY - .URL files have to maintain an open verb in the registry - ZekeL - 14-APR-99
  110. // we would like to just use the "open" verb here in the context menu extension,
  111. // but we need to not duplicate the open verb that is added by DefCM
  112. // on NT5+ shell32 we disable that verb so we can add it here.
  113. // on earlier shell32 we want to add "open" any time we arent
  114. // initialized by DefCM. if we think that DefCM added us,
  115. // then we go ahead and allow the DefCM's open from the registry.
  116. //
  117. if (!m_fProbablyDefCM || GetUIVersion() >= 5)
  118. {
  119. _InsertISCM(IDCMD_ISCM_OPEN, hmenu, indexMenu, idCmdFirst, 0);
  120. if (-1 == GetMenuDefaultItem(hmenu, MF_BYCOMMAND, 0))
  121. SetMenuDefaultItem(hmenu, indexMenu, MF_BYPOSITION);
  122. indexMenu++;
  123. }
  124. #ifndef UNIX
  125. /* v-sriran: 12/8/97
  126. * disabling the context menu item for subscribe, separators etc.
  127. * because we are not supporting subscriptions right now
  128. */
  129. // skip this if we only want default or if there is no room for more.
  130. if (!(uFlags & CMF_DEFAULTONLY) && (idCmdLast - idCmdFirst >= ARRAYSIZE(g_rgiscm)))
  131. {
  132. WCHAR *pwszURL;
  133. if (SUCCEEDED(GetURLW(&pwszURL)))
  134. {
  135. BOOL bSubscribable = FALSE; //can be subscribed to
  136. BOOL bSub = _IsSubscribed(pwszURL, &bSubscribable);
  137. m_bCheckForDelete = bSub && m_pszFile;
  138. if (bSubscribable || bSub)
  139. {
  140. // add a separator for our subscription stuff
  141. InsertMenu(hmenu, indexMenu++, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
  142. UINT uMenuFlags = 0;
  143. if (bSub)
  144. {
  145. uMenuFlags |= MF_CHECKED;
  146. if (SHRestricted2W(REST_NoRemovingSubscriptions, pwszURL, 0))
  147. {
  148. uMenuFlags |= MF_GRAYED;
  149. }
  150. }
  151. _InsertISCM(IDCMD_ISCM_SUB, hmenu, indexMenu++, idCmdFirst, uMenuFlags);
  152. if (bSub)
  153. {
  154. uMenuFlags = 0;
  155. if (SHRestricted2W(REST_NoManualUpdates, NULL, 0))
  156. {
  157. uMenuFlags |= MF_GRAYED;
  158. }
  159. _InsertISCM(IDCMD_ISCM_SYNC, hmenu, indexMenu++, idCmdFirst, uMenuFlags);
  160. }
  161. }
  162. SHFree(pwszURL);
  163. }
  164. }
  165. #endif /* UNIX */
  166. return ResultFromShort(ARRAYSIZE(g_rgiscm));
  167. }
  168. STDMETHODIMP Intshcut::InvokeCommand(IN LPCMINVOKECOMMANDINFO pici)
  169. {
  170. HRESULT hres = E_INVALIDARG;
  171. ASSERT(pici);
  172. if (pici && SIZEOF(*pici) <= pici->cbSize)
  173. {
  174. UINT idCmd;
  175. if (0 == HIWORD(pici->lpVerb)) // Is the ID cmd given?
  176. {
  177. idCmd = LOWORD(pici->lpVerb); // Yes
  178. // Old versions of ShellExec() didnt get the right default command - Zekel - 15-MAR-99
  179. // since our QCM implementation doesnt add anything to the menu
  180. // if we fix the QCM to work correctly, then this problem will go away.
  181. // it sent 0xfffe instead. so just adjust here.
  182. if (idCmd == 0xfffe && GetUIVersion() <= 4)
  183. idCmd = IDCMD_ISCM_OPEN;
  184. }
  185. else
  186. {
  187. // No; a language-independent verb was supplied
  188. int i;
  189. LPCTSTR pszVerb;
  190. LPCMINVOKECOMMANDINFOEX piciex = (LPCMINVOKECOMMANDINFOEX)pici;
  191. ASSERT(SIZEOF(*piciex) <= piciex->cbSize);
  192. WCHAR szVerb[40];
  193. if (piciex->lpVerbW)
  194. {
  195. pszVerb = piciex->lpVerbW;
  196. }
  197. else
  198. {
  199. if (piciex->lpVerb)
  200. {
  201. ASSERT(lstrlenA(piciex->lpVerb) < ARRAYSIZE(szVerb));
  202. SHAnsiToUnicode(piciex->lpVerb, szVerb, ARRAYSIZE(szVerb));
  203. }
  204. else
  205. {
  206. szVerb[0] = L'\0';
  207. }
  208. pszVerb = szVerb;
  209. }
  210. idCmd = (UINT)-1;
  211. for (i = 0; i < ARRAYSIZE(g_rgiscm); i++)
  212. {
  213. if (0 == StrCmpI(g_rgiscm[i].pszVerb, pszVerb))
  214. {
  215. idCmd = i;
  216. break;
  217. }
  218. }
  219. }
  220. switch (idCmd)
  221. {
  222. case IDCMD_ISCM_OPEN:
  223. {
  224. URLINVOKECOMMANDINFO urlici;
  225. urlici.dwcbSize = SIZEOF(urlici);
  226. urlici.hwndParent = pici->hwnd;
  227. urlici.pcszVerb = NULL;
  228. urlici.dwFlags = IURL_INVOKECOMMAND_FL_USE_DEFAULT_VERB;
  229. if (IsFlagClear(pici->fMask, CMIC_MASK_FLAG_NO_UI))
  230. {
  231. SetFlag(urlici.dwFlags, IURL_INVOKECOMMAND_FL_ALLOW_UI);
  232. }
  233. if (IsFlagSet(pici->fMask, SEE_MASK_FLAG_DDEWAIT))
  234. {
  235. SetFlag(urlici.dwFlags, IURL_INVOKECOMMAND_FL_DDEWAIT);
  236. }
  237. hres = InvokeCommand(&urlici);
  238. m_bCheckForDelete = FALSE;
  239. }
  240. break;
  241. case IDCMD_ISCM_SUB:
  242. case IDCMD_ISCM_SYNC:
  243. {
  244. hres = S_OK;
  245. WCHAR *pwszURL;
  246. if (SUCCEEDED(GetURLW(&pwszURL)))
  247. {
  248. ISubscriptionMgr * pMgr;
  249. if (SUCCEEDED(JITCoCreateInstance(CLSID_SubscriptionMgr,
  250. NULL,
  251. CLSCTX_INPROC_SERVER,
  252. IID_PPV_ARG(ISubscriptionMgr, &pMgr),
  253. pici->hwnd,
  254. FIEF_FLAG_FORCE_JITUI)))
  255. {
  256. if (idCmd == IDCMD_ISCM_SUB)
  257. {
  258. BOOL bSubscribed;
  259. pMgr->IsSubscribed(pwszURL, &bSubscribed);
  260. if (!bSubscribed)
  261. {
  262. SHFILEINFO sfi = {0};
  263. WCHAR wszName[MAX_PATH];
  264. wszName[0] = 0;
  265. if (SHGetFileInfo(m_pszFile, 0, &sfi, sizeof(sfi), SHGFI_DISPLAYNAME))
  266. {
  267. SHTCharToUnicode(sfi.szDisplayName, wszName, ARRAYSIZE(wszName));
  268. }
  269. if (!wszName[0])
  270. StrCpyNW(wszName, pwszURL, ARRAYSIZE(wszName));
  271. //all subscriptions to local .urls are treated as subscribing something
  272. //that's already in Favorites, so user isn't forced to add it to their
  273. //favorites as they subscribe.
  274. if (SUCCEEDED(pMgr->CreateSubscription(pici->hwnd, pwszURL, wszName,
  275. CREATESUBS_FROMFAVORITES,
  276. SUBSTYPE_URL,
  277. NULL)))
  278. {
  279. pMgr->UpdateSubscription(pwszURL);
  280. }
  281. }
  282. else
  283. {
  284. pMgr->DeleteSubscription(pwszURL, pici->hwnd);
  285. }
  286. }
  287. else if (idCmd == IDCMD_ISCM_SYNC)
  288. {
  289. pMgr->UpdateSubscription(pwszURL);
  290. }
  291. pMgr->Release();
  292. }
  293. SHFree(pwszURL);
  294. m_bCheckForDelete = FALSE;
  295. }
  296. break;
  297. }
  298. default:
  299. hres = E_INVALIDARG;
  300. break;
  301. }
  302. }
  303. return hres;
  304. }
  305. /*----------------------------------------------------------
  306. Purpose: IContextMenu::GetCommandString handler for Intshcut
  307. */
  308. STDMETHODIMP Intshcut::GetCommandString(
  309. IN UINT_PTR idCmd,
  310. IN UINT uType,
  311. IN OUT UINT* puReserved,
  312. IN OUT LPSTR pszName,
  313. IN UINT cchMax)
  314. {
  315. HRESULT hres;
  316. TCHAR szMenu[CCH_MENUMAX];
  317. ASSERT(NULL == puReserved);
  318. ASSERT(IS_VALID_WRITE_BUFFER(pszName, char, cchMax));
  319. switch (uType)
  320. {
  321. case GCS_HELPTEXTA:
  322. case GCS_HELPTEXTW:
  323. if (idCmd < ARRAYSIZE(g_rgiscm))
  324. {
  325. MLLoadString(g_rgiscm[idCmd].idsMenuHelp, szMenu, SIZECHARS(szMenu));
  326. if (GCS_HELPTEXTA == uType)
  327. {
  328. UnicodeToAnsi(szMenu, pszName, cchMax);
  329. }
  330. else
  331. {
  332. StrCpyN((LPWSTR)pszName, szMenu, cchMax);
  333. }
  334. hres = NOERROR;
  335. }
  336. else
  337. {
  338. ASSERT(0);
  339. hres = E_INVALIDARG;
  340. }
  341. break;
  342. case GCS_VALIDATEA:
  343. case GCS_VALIDATEW:
  344. hres = idCmd < ARRAYSIZE(g_rgiscm) ? S_OK : S_FALSE;
  345. break;
  346. case GCS_VERBA:
  347. case GCS_VERBW:
  348. if (idCmd < ARRAYSIZE(g_rgiscm))
  349. {
  350. LPCTSTR pszVerb = g_rgiscm[idCmd].pszVerb;
  351. if (GCS_VERBA == uType)
  352. {
  353. UnicodeToAnsi(pszVerb, pszName, cchMax);
  354. }
  355. else
  356. {
  357. StrCpyN((LPWSTR)pszName, pszVerb, cchMax);
  358. }
  359. hres = NOERROR;
  360. }
  361. else
  362. {
  363. ASSERT(0);
  364. hres = E_INVALIDARG;
  365. }
  366. break;
  367. default:
  368. hres = E_NOTIMPL;
  369. break;
  370. }
  371. return hres;
  372. }
  373. // IContextMenu2::HandleMenuMsg handler for Intshcut
  374. STDMETHODIMP Intshcut::HandleMenuMsg(IN UINT uMsg, IN WPARAM wParam, IN LPARAM lParam)
  375. {
  376. return S_OK;
  377. }
  378. // Returns the protocol scheme value (URL_SCHEME_*).
  379. STDMETHODIMP_(DWORD)
  380. Intshcut::GetScheme(void)
  381. {
  382. DWORD dwScheme = URL_SCHEME_UNKNOWN;
  383. if (SUCCEEDED(InitProp()))
  384. {
  385. m_pprop->GetProp(PID_IS_SCHEME, &dwScheme);
  386. }
  387. return dwScheme;
  388. }
  389. // IUniformResourceLocator::SetURL handler for Intshcut
  390. //
  391. // Note:
  392. // 1. SetURL clears the IDList, so that when we launch this shortcut,
  393. // we will use the URL.
  394. STDMETHODIMP
  395. Intshcut::SetURL(
  396. IN LPCTSTR pszURL, OPTIONAL
  397. IN DWORD dwFlags)
  398. {
  399. HRESULT hres = E_FAIL;
  400. ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut));
  401. ASSERT(! pszURL ||
  402. IS_VALID_STRING_PTR(pszURL, -1));
  403. ASSERT(FLAGS_ARE_VALID(dwFlags, ALL_IURL_SETURL_FLAGS));
  404. hres = InitProp();
  405. if (SUCCEEDED(hres))
  406. {
  407. hres = m_pprop->SetURLProp(pszURL, dwFlags);
  408. if (SUCCEEDED(hres))
  409. {
  410. // if the path was set successfully, clear the pidl.
  411. m_pprop->SetIDListProp(NULL);
  412. }
  413. }
  414. return hres;
  415. }
  416. /*----------------------------------------------------------
  417. Purpose: IUniformResourceLocatorA::SetURL handler for Intshcut
  418. Ansi version
  419. */
  420. STDMETHODIMP
  421. Intshcut::SetURL(
  422. IN LPCSTR pcszURL, OPTIONAL
  423. IN DWORD dwInFlags)
  424. {
  425. if ( !pcszURL )
  426. {
  427. return SetURL((LPCTSTR)NULL, dwInFlags);
  428. }
  429. else
  430. {
  431. WCHAR wszURL[MAX_URL_STRING];
  432. ASSERT(IS_VALID_STRING_PTRA(pcszURL, -1));
  433. AnsiToUnicode(pcszURL, wszURL, SIZECHARS(wszURL));
  434. return SetURL(wszURL, dwInFlags);
  435. }
  436. }
  437. STDMETHODIMP Intshcut::GetURLW(WCHAR **ppwsz)
  438. {
  439. LPTSTR pszURL;
  440. HRESULT hres = GetURL(&pszURL);
  441. if (S_OK == hres)
  442. {
  443. hres = SHStrDup(pszURL, ppwsz);
  444. SHFree(pszURL);
  445. }
  446. else
  447. hres = E_FAIL; // map S_FALSE to FAILED()
  448. return hres;
  449. }
  450. // IUniformResourceLocator::GetURL handler for Intshcut
  451. STDMETHODIMP Intshcut::GetURL(LPTSTR * ppszURL)
  452. {
  453. HRESULT hres;
  454. TCHAR szURL[MAX_URL_STRING];
  455. ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut));
  456. ASSERT(IS_VALID_WRITE_PTR(ppszURL, PTSTR));
  457. *ppszURL = NULL;
  458. hres = InitProp();
  459. if (SUCCEEDED(hres))
  460. {
  461. hres = m_pprop->GetProp(PID_IS_URL, szURL, SIZECHARS(szURL));
  462. if (S_OK == hres)
  463. {
  464. // (+ 1) for null terminator.
  465. int cch = lstrlen(szURL) + 1;
  466. *ppszURL = (PTSTR)SHAlloc(CbFromCch(cch));
  467. if (*ppszURL)
  468. StrCpyN(*ppszURL, szURL, cch);
  469. else
  470. hres = E_OUTOFMEMORY;
  471. }
  472. }
  473. ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut));
  474. ASSERT((hres == S_OK &&
  475. IS_VALID_STRING_PTR(*ppszURL, -1)) ||
  476. ((hres == S_FALSE ||
  477. hres == E_OUTOFMEMORY) &&
  478. ! *ppszURL));
  479. return hres;
  480. }
  481. /*----------------------------------------------------------
  482. Purpose: IUniformResourceLocatorA::GetURL handler for Intshcut
  483. Ansi version
  484. */
  485. STDMETHODIMP Intshcut::GetURL(LPSTR * ppszURL)
  486. {
  487. HRESULT hres;
  488. TCHAR szURL[MAX_URL_STRING];
  489. ASSERT(IS_VALID_WRITE_PTR(ppszURL, PSTR));
  490. *ppszURL = NULL;
  491. hres = InitProp();
  492. if (SUCCEEDED(hres))
  493. {
  494. hres = m_pprop->GetProp(PID_IS_URL, szURL, SIZECHARS(szURL));
  495. if (S_OK == hres)
  496. {
  497. DWORD cch = WideCharToMultiByte(CP_ACP, 0, szURL, -1, NULL, 0, NULL, NULL);
  498. *ppszURL = (LPSTR)SHAlloc(CbFromCchA(cch + 1));
  499. if (*ppszURL)
  500. UnicodeToAnsi(szURL, *ppszURL, cch);
  501. else
  502. hres = E_OUTOFMEMORY;
  503. }
  504. }
  505. return hres;
  506. }
  507. HRESULT HandlePluggableProtocol(LPCTSTR pszURL, LPCTSTR pszProtocol)
  508. {
  509. HRESULT hres = E_UNEXPECTED;
  510. HKEY hkey;
  511. TraceMsg(DM_PLUGGABLE, "HandlePluggableProtocol called");
  512. if (RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT("PROTOCOLS\\Handler"), 0, KEY_READ, &hkey) == ERROR_SUCCESS) {
  513. HKEY hkeyProtocol;
  514. if (RegOpenKeyEx(hkey, pszProtocol, 0, KEY_READ, &hkeyProtocol) == ERROR_SUCCESS) {
  515. TraceMsg(DM_PLUGGABLE, "HandlePluggableProtocol found %s", pszProtocol);
  516. IUnknown* punk = NULL; // CreateTargetFrame's ppunk is [IN][OUT]
  517. hres = CreateTargetFrame(NULL, &punk);
  518. if (SUCCEEDED(hres)) {
  519. IWebBrowser2* pauto;
  520. hres = punk->QueryInterface(IID_IWebBrowser2, (LPVOID*)&pauto);
  521. if (SUCCEEDED(hres))
  522. {
  523. TraceMsg(DM_PLUGGABLE, "HandlePluggableProtocol calling navigate with %s", pszURL);
  524. LBSTR::CString strUrl;
  525. LPTSTR pstrUrl = strUrl.GetBuffer( MAX_URL_STRING );
  526. if ( strUrl.GetAllocLength() < MAX_URL_STRING )
  527. {
  528. TraceMsg( TF_WARNING, "HandlePluggableProtocol() - strUrl Allocation Failed!" );
  529. strUrl.Empty();
  530. }
  531. else
  532. {
  533. SHTCharToUnicode( pszURL, pstrUrl, MAX_URL_STRING );
  534. // Let CString class own the buffer again.
  535. strUrl.ReleaseBuffer();
  536. }
  537. pauto->Navigate( strUrl, PVAREMPTY, PVAREMPTY, PVAREMPTY, PVAREMPTY );
  538. pauto->put_Visible(TRUE);
  539. pauto->Release();
  540. }
  541. punk->Release();
  542. }
  543. RegCloseKey(hkeyProtocol);
  544. } else {
  545. TraceMsg(DM_WARNING, "HandlePluggableProtocol can't find %s", pszProtocol);
  546. }
  547. RegCloseKey(hkey);
  548. } else {
  549. ASSERT(0);
  550. }
  551. return hres;
  552. }
  553. HRESULT _IEExecFile_TryRunningWindow(VARIANT *pvarIn, DWORD cid)
  554. {
  555. HRESULT hr = E_FAIL;
  556. ASSERT(pvarIn);
  557. IShellWindows *psw = WinList_GetShellWindows(TRUE);
  558. if (psw)
  559. {
  560. IUnknown *punk;
  561. if (SUCCEEDED(psw->_NewEnum(&punk)))
  562. {
  563. VARIANT var = {0};
  564. IEnumVARIANT *penum;
  565. //
  566. // its too bad _NewEnum doesnt return an penum....
  567. // this should never fail.
  568. //
  569. punk->QueryInterface(IID_PPV_ARG(IEnumVARIANT, &penum));
  570. ASSERT(penum);
  571. //
  572. // this can be super spendy since every one of these
  573. // items is marshalled.
  574. //
  575. // should we clone the stream here??
  576. //
  577. while (FAILED(hr) && S_OK == penum->Next(1, &var, NULL))
  578. {
  579. ASSERT(var.vt == VT_DISPATCH);
  580. ASSERT(var.pdispVal);
  581. IOleCommandTarget *poct;
  582. if (SUCCEEDED(var.pdispVal->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &poct))))
  583. {
  584. CoAllowSetForegroundWindow(poct, NULL);
  585. hr = poct->Exec(&CGID_Explorer, cid, 0, pvarIn, NULL);
  586. poct->Release();
  587. }
  588. // this should release the pdisp
  589. VariantClear(&var);
  590. }
  591. punk->Release();
  592. penum->Release();
  593. }
  594. psw->Release();
  595. }
  596. TraceMsgW(DM_SHELLEXECOBJECT, "IEExecFile_Running returns 0x%X", hr);
  597. return hr;
  598. }
  599. BOOL IsIESchemeHandler(LPTSTR pszVerb, LPTSTR pszScheme)
  600. {
  601. // if we fail to get any value at all, the we must assume that it
  602. // is some protocol like about: or res: that is not in the registry
  603. // so we default to success.
  604. BOOL fRet = FALSE;
  605. TCHAR szExe[MAX_PATH];
  606. if (SUCCEEDED(AssocQueryString(0, ASSOCSTR_EXECUTABLE, pszScheme, pszVerb, szExe, (LPDWORD)MAKEINTRESOURCE(SIZECHARS(szExe)))))
  607. {
  608. // if we find something and it aint us, then fail.
  609. if ((StrStrI(szExe, TEXT("iexplore.exe")) || StrStrI(szExe, TEXT("explorer.exe"))))
  610. {
  611. fRet = TRUE;
  612. TraceMsg(DM_SHELLEXECOBJECT, "IsIEScheme() found %s", szExe);
  613. }
  614. }
  615. else
  616. {
  617. // these are unregistered schemes, we are the only ones that
  618. // should ever even use the unregistered schemes like
  619. // res: or shell: so return TRUE here too.
  620. fRet = *pszScheme && *pszScheme != TEXT('.');
  621. }
  622. TraceMsg(DM_SHELLEXECOBJECT, "IsIEScheme() returns %d for %s", fRet, pszScheme);
  623. return fRet;
  624. }
  625. HRESULT IEExecFile(LPTSTR pszVerb, LPTSTR pszScheme, DWORD cid, LPTSTR pszPath)
  626. {
  627. HRESULT hr = E_FAIL;
  628. ASSERT(pszVerb);
  629. ASSERT(pszScheme);
  630. ASSERT(pszPath);
  631. if (IsIESchemeHandler(pszVerb, pszScheme))
  632. {
  633. VARIANT varIn = {0};
  634. varIn.vt = VT_BSTR;
  635. SHSTRW str;
  636. str.SetStr(pszPath);
  637. varIn.bstrVal = SysAllocString(str.GetStr());
  638. if (varIn.bstrVal)
  639. {
  640. if (!SHRegGetBoolUSValue(REGSTR_PATH_MAIN, TEXT("AllowWindowReuse"), FALSE, TRUE)
  641. || FAILED(hr = _IEExecFile_TryRunningWindow(&varIn, cid)))
  642. {
  643. IOleCommandTarget *poct;
  644. if (SUCCEEDED(CoCreateInstance(CLSID_InternetExplorer, NULL, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
  645. IID_PPV_ARG(IOleCommandTarget, &poct))))
  646. {
  647. hr = poct->Exec(&CGID_Explorer, cid, 0, &varIn, NULL);
  648. poct->Release();
  649. }
  650. }
  651. SysFreeString(varIn.bstrVal);
  652. }
  653. }
  654. TraceMsg(DM_SHELLEXECOBJECT, "IEExecFile returns 0x%X for %s", hr, pszPath);
  655. return hr;
  656. }
  657. /*----------------------------------------------------------
  658. Purpose: IUniformResourceLocator::InvokeCommand for Intshcut
  659. Note:
  660. 1. If the internet shortcut comes with a pidl, use it to ShellExec,
  661. otherwise use the URL.
  662. */
  663. STDMETHODIMP Intshcut::InvokeCommand(PURLINVOKECOMMANDINFO purlici)
  664. {
  665. HRESULT hr = E_INVALIDARG;
  666. ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut));
  667. ASSERT(IS_VALID_STRUCT_PTR(purlici, CURLINVOKECOMMANDINFO));
  668. if (purlici && EVAL(SIZEOF(*purlici) == purlici->dwcbSize))
  669. {
  670. //
  671. // App compat. Don't use stack space for the URL. We use up 16-bit app
  672. // stack space when we they shell exec urls.
  673. //
  674. LPWSTR pszURL = (LPWSTR)LocalAlloc(LPTR, MAX_URL_STRING * sizeof(WCHAR));
  675. if (pszURL)
  676. {
  677. hr = InitProp();
  678. if (SUCCEEDED(hr))
  679. {
  680. //
  681. // App Compat: Don't use up stack space.
  682. //
  683. LPWSTR pszT = (LPWSTR)LocalAlloc(LPTR, MAX_PATH * sizeof(WCHAR));
  684. if (pszT)
  685. {
  686. SHELLEXECUTEINFO sei = {0};
  687. LPITEMIDLIST pidl = NULL;
  688. LPTSTR pszProtocol = NULL;
  689. PARSEDURL pu;
  690. pu.nScheme = 0; // init to avoid bogus C4701 warning
  691. sei.fMask = SEE_MASK_NO_HOOKS;
  692. // check if we have a pidl for the target.
  693. hr = GetIDListInternal(&pidl);
  694. if ((hr == S_OK) && pidl)
  695. {
  696. // yse, use the pidl to ShellExec.
  697. sei.fMask |= SEE_MASK_INVOKEIDLIST;
  698. sei.lpIDList = pidl;
  699. }
  700. else
  701. {
  702. // no, get the URL and invoke class handler.
  703. if (SUCCEEDED(hr))
  704. {
  705. hr = m_pprop->GetProp(PID_IS_URL, pszURL, MAX_URL_STRING);
  706. }
  707. if (S_OK == hr)
  708. {
  709. hr = CopyURLProtocol(pszURL, &pszProtocol, &pu);
  710. if (hr == S_OK)
  711. {
  712. hr = IsProtocolRegistered(pszProtocol);
  713. if (FAILED(hr)) {
  714. if (SUCCEEDED(HandlePluggableProtocol(pszURL, pszProtocol))) {
  715. hr = S_OK;
  716. goto done;
  717. }
  718. }
  719. if (SUCCEEDED(hr))
  720. {
  721. hr = ResultFromWin32(RegOpenKeyExW(HKEY_CLASSES_ROOT, pszProtocol, 0, KEY_READ, &sei.hkeyClass));
  722. sei.fMask |= SEE_MASK_CLASSKEY;
  723. }
  724. }
  725. }
  726. }
  727. // the prop code returns S_FALSE when it fails to get anything
  728. if (S_FALSE == hr)
  729. hr = URL_E_INVALID_SYNTAX;
  730. if (SUCCEEDED(hr))
  731. {
  732. //
  733. // App Compat: Don't use up stack space.
  734. //
  735. LPWSTR pszVerb = (LPWSTR)LocalAlloc(LPTR, MAX_PATH * sizeof(WCHAR));
  736. if (pszVerb)
  737. {
  738. int nShowCmd;
  739. // Execute URL via registered protocol handler.
  740. if (IsFlagClear(purlici->dwFlags,
  741. IURL_INVOKECOMMAND_FL_ALLOW_UI))
  742. SetFlag(sei.fMask, SEE_MASK_FLAG_NO_UI);
  743. if (purlici->dwFlags & IURL_INVOKECOMMAND_FL_DDEWAIT)
  744. SetFlag(sei.fMask, SEE_MASK_FLAG_DDEWAIT);
  745. if (IsFlagClear(purlici->dwFlags,
  746. IURL_INVOKECOMMAND_FL_USE_DEFAULT_VERB))
  747. {
  748. sei.lpVerb = purlici->pcszVerb;
  749. }
  750. else
  751. {
  752. if (pszProtocol &&
  753. GetClassDefaultVerb(pszProtocol, pszVerb,
  754. MAX_PATH))
  755. sei.lpVerb = pszVerb;
  756. else
  757. ASSERT(! sei.lpVerb);
  758. }
  759. ASSERT(m_pprop);
  760. if (SUCCEEDED(hr))
  761. {
  762. m_pprop->GetProp(PID_IS_WORKINGDIR, pszT, MAX_PATH);
  763. m_pprop->GetProp(PID_IS_SHOWCMD, &nShowCmd); // inits to zero if not found
  764. // if we have a file try using a direct connection
  765. // to the shell to give the whole shortcut
  766. if (m_pszFile && ((IsIEDefaultBrowser()) || (_IsInFavoritesFolder())))
  767. {
  768. LPTSTR pszType = pszProtocol;
  769. if (pu.nScheme == URL_SCHEME_FILE)
  770. pszType = PathFindExtension(pszURL);
  771. hr = IEExecFile(pszVerb, pszType, SBCMDID_IESHORTCUT, m_pszFile);
  772. }
  773. else
  774. hr = E_FAIL;
  775. // if we failed to pass it to IE, then we should just default
  776. // to the old behavior
  777. if (FAILED(hr))
  778. {
  779. sei.cbSize = SIZEOF(sei);
  780. sei.hwnd = purlici->hwndParent;
  781. sei.lpFile = pszURL;
  782. sei.lpDirectory = pszT;
  783. sei.nShow = nShowCmd ? nShowCmd : SW_NORMAL;
  784. // We have to special case "file:" URLs,
  785. // because Nashville's Explorer typically handles
  786. // file: URLs via DDE, which fails for executables
  787. // (eg, "file://c:\windows\notepad.exe") and
  788. // non-hostable docs (like text files).
  789. //
  790. // So in this case, we remove the protocol class
  791. // and execute the suffix.
  792. // App Compat: Don't use up stack space.
  793. DWORD cchPath = MAX_PATH;
  794. LPWSTR pszPath = (LPWSTR)LocalAlloc(LPTR, cchPath * sizeof(WCHAR));
  795. if (pszPath)
  796. {
  797. if (IsFlagSet(sei.fMask, SEE_MASK_CLASSKEY) &&
  798. (URL_SCHEME_FILE == pu.nScheme) &&
  799. SUCCEEDED(PathCreateFromUrl(pszURL, pszPath, &cchPath, 0)))
  800. {
  801. sei.hkeyClass = NULL;
  802. ClearFlag(sei.fMask, SEE_MASK_CLASSKEY);
  803. sei.lpFile = pszPath;
  804. }
  805. if (m_pszFile && IsOS(OS_WHISTLERORGREATER))
  806. {
  807. // this is the security context
  808. // so that shellexec() can do zone checks
  809. sei.lpClass = m_pszFile;
  810. sei.fMask |= SEE_MASK_HASTITLE | SEE_MASK_HASLINKNAME;
  811. }
  812. TraceMsg(TF_INTSHCUT, "Intshcut::InvokeCommand(): Invoking %s verb on URL %s.",
  813. sei.lpVerb ? sei.lpVerb : TEXT("open"),
  814. sei.lpFile);
  815. hr = ShellExecuteEx(&sei) ? S_OK : IS_E_EXEC_FAILED;
  816. LocalFree(pszPath);
  817. pszPath = NULL;
  818. }
  819. else
  820. {
  821. hr = E_OUTOFMEMORY;
  822. }
  823. }
  824. }
  825. if (hr != S_OK)
  826. TraceMsg(TF_WARNING, "Intshcut::InvokeCommand(): ShellExecuteEx() via registered protcol handler failed for %s.",
  827. pszURL);
  828. LocalFree(pszVerb);
  829. pszVerb = NULL;
  830. }
  831. else
  832. {
  833. hr = E_OUTOFMEMORY;
  834. }
  835. }
  836. done:
  837. if (pszProtocol)
  838. {
  839. LocalFree(pszProtocol);
  840. pszProtocol = NULL;
  841. }
  842. if (pidl)
  843. ILFree(pidl);
  844. if (sei.hkeyClass)
  845. RegCloseKey(sei.hkeyClass);
  846. if (FAILED(hr) && (purlici->dwFlags & IURL_INVOKECOMMAND_FL_ALLOW_UI))
  847. {
  848. switch (hr)
  849. {
  850. case IS_E_EXEC_FAILED:
  851. break;
  852. case URL_E_INVALID_SYNTAX:
  853. MLShellMessageBox(
  854. purlici->hwndParent,
  855. MAKEINTRESOURCE(IDS_IS_EXEC_INVALID_SYNTAX),
  856. MAKEINTRESOURCE(IDS_SHORTCUT_ERROR_TITLE),
  857. (MB_OK | MB_ICONEXCLAMATION),
  858. pszURL);
  859. break;
  860. case URL_E_UNREGISTERED_PROTOCOL:
  861. {
  862. LPTSTR pszProtocol;
  863. if (CopyURLProtocol(pszURL, &pszProtocol, NULL) == S_OK)
  864. {
  865. MLShellMessageBox(
  866. purlici->hwndParent,
  867. MAKEINTRESOURCE(IDS_IS_EXEC_UNREGISTERED_PROTOCOL),
  868. MAKEINTRESOURCE(IDS_SHORTCUT_ERROR_TITLE),
  869. (MB_OK | MB_ICONEXCLAMATION),
  870. pszProtocol);
  871. LocalFree(pszProtocol);
  872. pszProtocol = NULL;
  873. }
  874. break;
  875. }
  876. case E_OUTOFMEMORY:
  877. MLShellMessageBox(
  878. purlici->hwndParent,
  879. MAKEINTRESOURCE(IDS_IS_EXEC_OUT_OF_MEMORY),
  880. MAKEINTRESOURCE(IDS_SHORTCUT_ERROR_TITLE),
  881. (MB_OK | MB_ICONEXCLAMATION));
  882. break;
  883. default:
  884. ASSERT(hr == E_ABORT);
  885. break;
  886. }
  887. }
  888. LocalFree(pszT);
  889. pszT = NULL;
  890. }
  891. else
  892. {
  893. hr = E_OUTOFMEMORY;
  894. }
  895. }
  896. LocalFree(pszURL);
  897. pszURL = NULL;
  898. }
  899. else
  900. {
  901. hr = E_OUTOFMEMORY;
  902. }
  903. }
  904. ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut));
  905. ASSERT(hr == S_OK ||
  906. hr == E_ABORT ||
  907. hr == E_OUTOFMEMORY ||
  908. hr == URL_E_INVALID_SYNTAX ||
  909. hr == URL_E_UNREGISTERED_PROTOCOL ||
  910. hr == IS_E_EXEC_FAILED ||
  911. hr == E_INVALIDARG);
  912. return(hr);
  913. }
  914. /*----------------------------------------------------------
  915. Purpose: IUniformResourceLocatorA::InvokeCommand for Intshcut
  916. Ansi version
  917. */
  918. STDMETHODIMP
  919. Intshcut::InvokeCommand(
  920. IN PURLINVOKECOMMANDINFOA purlici)
  921. {
  922. HRESULT hres = E_INVALIDARG;
  923. ASSERT(purlici);
  924. ASSERT(SIZEOF(*purlici) == purlici->dwcbSize);
  925. if (SIZEOF(*purlici) == purlici->dwcbSize)
  926. {
  927. URLINVOKECOMMANDINFOW ici;
  928. ici.dwcbSize = SIZEOF(ici);
  929. ici.dwFlags = purlici->dwFlags;
  930. ici.hwndParent = purlici->hwndParent;
  931. ici.pcszVerb = NULL;
  932. if (purlici->pcszVerb)
  933. {
  934. //
  935. // App compat hack.
  936. //
  937. // Note: use local alloc here instead of the stack since 16-bit code
  938. // can shell exec urls and we don't want to use up their stack.
  939. //
  940. int cch = lstrlenA(purlici->pcszVerb) + 1;
  941. ici.pcszVerb = (LPWSTR)LocalAlloc(LPTR, cch * sizeof(WCHAR));
  942. if (ici.pcszVerb)
  943. {
  944. AnsiToUnicode(purlici->pcszVerb, (LPWSTR)ici.pcszVerb, cch);
  945. }
  946. }
  947. hres = InvokeCommand(&ici);
  948. if (ici.pcszVerb)
  949. {
  950. LocalFree((void*)ici.pcszVerb);
  951. ici.pcszVerb = NULL;
  952. }
  953. }
  954. return hres;
  955. }
  956. STDMETHODIMP Intshcut::Create(REFFMTID fmtid, const CLSID *pclsid,
  957. DWORD grfFlags, DWORD grfMode, IPropertyStorage **pppropstg)
  958. {
  959. *pppropstg = NULL;
  960. return E_NOTIMPL;
  961. }
  962. STDMETHODIMP Intshcut::Open(REFFMTID fmtid, DWORD grfMode, IPropertyStorage **pppropstg)
  963. {
  964. HRESULT hres = E_FAIL; // assume failure
  965. *pppropstg = NULL;
  966. if (IsEqualGUID(fmtid, FMTID_Intshcut))
  967. {
  968. // Create a URLProp object for this format ID
  969. hres = CIntshcutProp_CreateInstance(NULL, IID_PPV_ARG(IPropertyStorage, pppropstg));
  970. if (SUCCEEDED(hres))
  971. {
  972. // Initialize this object
  973. IntshcutProp * pisprop = (IntshcutProp *)*pppropstg;
  974. hres = pisprop->InitFromFile(m_pszFile);
  975. }
  976. }
  977. else if (IsEqualGUID(fmtid, FMTID_InternetSite))
  978. {
  979. // Create a URLProp object for this format ID
  980. hres = CIntsiteProp_CreateInstance(NULL, IID_PPV_ARG(IPropertyStorage, pppropstg));
  981. if (SUCCEEDED(hres))
  982. {
  983. hres = InitProp();
  984. if (SUCCEEDED(hres))
  985. {
  986. TCHAR szURL[MAX_URL_STRING];
  987. hres = m_pprop->GetProp(PID_IS_URL, szURL, SIZECHARS(szURL));
  988. if (SUCCEEDED(hres))
  989. {
  990. IntsiteProp * pisprop = (IntsiteProp *)*pppropstg;
  991. hres = pisprop->InitFromDB(szURL, this, FALSE);
  992. }
  993. }
  994. if (FAILED(hres))
  995. {
  996. (*pppropstg)->Release();
  997. *pppropstg = NULL;
  998. }
  999. }
  1000. }
  1001. return hres;
  1002. }
  1003. STDMETHODIMP Intshcut::Delete(REFFMTID fmtid)
  1004. {
  1005. return STG_E_ACCESSDENIED;
  1006. }
  1007. STDMETHODIMP Intshcut::Enum(OUT IEnumSTATPROPSETSTG ** ppenum)
  1008. {
  1009. *ppenum = NULL;
  1010. return E_NOTIMPL;
  1011. }
  1012. STDAPI GetStringPropURL(IPropertyStorage *ppropstg, PROPID propid, LPTSTR pszBuf, DWORD cchBuf)
  1013. {
  1014. HRESULT hres = GetStringProp(ppropstg, propid, pszBuf, cchBuf);
  1015. if (SUCCEEDED(hres))
  1016. {
  1017. // get rid of the query string for display
  1018. if (UrlIs(pszBuf, URLIS_HASQUERY))
  1019. UrlCombine(pszBuf, TEXT("?..."), pszBuf, &cchBuf, 0);
  1020. }
  1021. return hres;
  1022. }
  1023. BOOL Intshcut::_TryLink(REFIID riid, void **ppvOut)
  1024. {
  1025. HRESULT hr = InitProp();
  1026. if (SUCCEEDED(hr) && URL_SCHEME_FILE == GetScheme())
  1027. {
  1028. // This shortcut is not in the favorites folder as far as we know
  1029. TCHAR szURL[INTERNET_MAX_URL_LENGTH];
  1030. DWORD cch = SIZECHARS(szURL);
  1031. *szURL = 0;
  1032. m_pprop->GetProp(PID_IS_URL, szURL, SIZECHARS(szURL));
  1033. if (*szURL && SUCCEEDED(PathCreateFromUrl(szURL, szURL, &cch, 0)))
  1034. {
  1035. if (!_punkLink)
  1036. {
  1037. hr = _CreateShellLink(szURL, &_punkLink);
  1038. }
  1039. if (_punkLink)
  1040. {
  1041. if (SUCCEEDED(_punkLink->QueryInterface(riid, ppvOut)))
  1042. return TRUE;
  1043. }
  1044. }
  1045. if (FAILED(hr))
  1046. ATOMICRELEASE(_punkLink);
  1047. }
  1048. return FALSE;
  1049. }
  1050. STDMETHODIMP Intshcut::GetInfoTip(DWORD dwFlags, WCHAR **ppwszTip)
  1051. {
  1052. HRESULT hr = E_FAIL;
  1053. IQueryInfo *pqi;
  1054. if (_TryLink(IID_PPV_ARG(IQueryInfo, &pqi)))
  1055. {
  1056. hr = pqi->GetInfoTip(dwFlags, ppwszTip);
  1057. pqi->Release();
  1058. }
  1059. if (FAILED(hr))
  1060. {
  1061. static const ITEM_PROP c_rgTitleAndURL[] = {
  1062. { &FMTID_InternetSite, PID_INTSITE_TITLE, GetStringProp, IDS_FAV_STRING },
  1063. { &FMTID_Intshcut, PID_IS_URL, GetStringPropURL, IDS_FAV_STRING },
  1064. { NULL, 0, 0, 0 },
  1065. };
  1066. hr = GetInfoTipFromStorage(SAFECAST(this, IPropertySetStorage *), c_rgTitleAndURL, ppwszTip);
  1067. }
  1068. return hr;
  1069. }
  1070. STDMETHODIMP Intshcut::GetInfoFlags(DWORD *pdwFlags)
  1071. {
  1072. *pdwFlags = 0;
  1073. #if 0
  1074. // This Function is commented out since it has not been tested.
  1075. // It can be uncommented if we provide support for providing offline cursor
  1076. // for shortucts. I think this needs updates to listview in comctl -- BharatS
  1077. LPSTR pszURL;
  1078. if (S_OK == GetURL(&pszURL))
  1079. {
  1080. BOOL fCached = UrlIsCached(pszUrl);
  1081. if (!fCached)
  1082. {
  1083. CHAR szCanonicalizedUrlA[MAX_URL_STRING];
  1084. DWORD dwLen = ARRAYSIZE(szCanonicalizedUrlA);
  1085. InternetCanonicalizeUrlA(pszURL, szCanonicalizedUrlA, &dwLen, 0);
  1086. fCached = UrlIsMappedOrInCache(szCanonicalizedUrlA);
  1087. }
  1088. if (fCached)
  1089. *pdwFlags |= QIF_CACHED;
  1090. SHFree(pszURL);
  1091. }
  1092. return S_OK;
  1093. #else
  1094. return E_NOTIMPL;
  1095. #endif
  1096. }
  1097. /*----------------------------------------------------------
  1098. IQueryCodePage:
  1099. */
  1100. STDMETHODIMP Intshcut::GetCodePage(UINT * puiCodePage)
  1101. {
  1102. HRESULT hres = E_FAIL;
  1103. *puiCodePage = 0; // NULL out the code page.
  1104. if (IsFlagSet(m_dwFlags, ISF_CODEPAGE))
  1105. {
  1106. *puiCodePage = m_uiCodePage;
  1107. hres = S_OK;
  1108. }
  1109. return hres;
  1110. }
  1111. STDMETHODIMP Intshcut::SetCodePage(UINT uiCodePage)
  1112. {
  1113. SetFlag(m_dwFlags, ISF_CODEPAGE);
  1114. m_uiCodePage = uiCodePage;
  1115. return S_OK;
  1116. }
  1117. /***************************** Exported Functions ****************************/
  1118. // This function was ported from URL.DLL. Normally, since our
  1119. // internet shortcut object has a context menu handler, we don't
  1120. // call this function.
  1121. //
  1122. // Only one thing needs this entry point: Exchange. Sigh.
  1123. //
  1124. // Instead of simply calling ShellExecuteEx to handle opening file
  1125. // attachments, they grovel thru the registry themselves. Of course,
  1126. // their code is incomplete and thinks a file-association needs to
  1127. // have an explicit \shell\open\command that works before it executes
  1128. // it. Hmm, it brings to mind a phrase, like:
  1129. //
  1130. //
  1131. //
  1132. // So, we export this API so they will work. But really the invoke
  1133. // occurs in the context menu handler for normal cases.
  1134. //
  1135. STDAPI_(void) OpenURL(HWND hwndParent, HINSTANCE hinst, LPSTR pszCmdLine, int nShowCmd)
  1136. {
  1137. HRESULT hr;
  1138. HRESULT hrCoInit;
  1139. Intshcut * pIntshcut = new Intshcut; // This must be a 0 INITed memory allocation
  1140. WCHAR wszPath[MAX_PATH];
  1141. if (!pIntshcut)
  1142. return;
  1143. hrCoInit = SHCoInitialize(); // gets called from rundll32 in browser only mode - hence we need to
  1144. // make sure that OLE has been init'ed
  1145. ASSERT(IS_VALID_HANDLE(hwndParent, WND));
  1146. ASSERT(IS_VALID_HANDLE(hinst, INSTANCE));
  1147. ASSERT(IS_VALID_STRING_PTRA(pszCmdLine, -1));
  1148. ASSERT(IsValidShowCmd(nShowCmd));
  1149. // Assume the entire command line is an Internet Shortcut file path.
  1150. TrimWhiteSpaceA(pszCmdLine);
  1151. TraceMsgA(TF_INTSHCUT, "OpenURL(): Trying to open Internet Shortcut %s.",
  1152. pszCmdLine);
  1153. #ifndef UNIX
  1154. AnsiToUnicode(pszCmdLine, wszPath, SIZECHARS(wszPath));
  1155. hr = pIntshcut->LoadFromFile(wszPath);
  1156. #else /* UNIX */
  1157. #ifndef ANSI_SHELL32_ON_UNIX
  1158. // IEUNIX : Our Shell32 calls this function with unicode command line
  1159. hr = pIntshcut->LoadFromFile((LPWSTR)pszCmdLine);
  1160. #else
  1161. hr = pIntshcut->LoadFromFile(pszCmdLine);
  1162. #endif
  1163. #endif /* !UNIX */
  1164. if (hr == S_OK)
  1165. {
  1166. URLINVOKECOMMANDINFO urlici;
  1167. urlici.dwcbSize = SIZEOF(urlici);
  1168. urlici.hwndParent = hwndParent;
  1169. urlici.pcszVerb = NULL;
  1170. urlici.dwFlags = (IURL_INVOKECOMMAND_FL_ALLOW_UI |
  1171. IURL_INVOKECOMMAND_FL_USE_DEFAULT_VERB);
  1172. hr = pIntshcut->InvokeCommand(&urlici);
  1173. }
  1174. if (hr != S_OK)
  1175. {
  1176. MLShellMessageBox(
  1177. hwndParent,
  1178. MAKEINTRESOURCE(IDS_IS_LOADFROMFILE_FAILED),
  1179. MAKEINTRESOURCE(IDS_SHORTCUT_ERROR_TITLE),
  1180. (MB_OK | MB_ICONEXCLAMATION),
  1181. wszPath);
  1182. }
  1183. pIntshcut->Release();
  1184. SHCoUninitialize(hrCoInit);
  1185. }
  1186. // INamedPropertyBag Methods
  1187. //
  1188. // Reads & writes properties from a section in the shortcut ini file
  1189. const TCHAR c_szSizeSuffix[] = TEXT("__Size");
  1190. STDMETHODIMP Intshcut::WritePropertyNPB(
  1191. LPCOLESTR pszSectionNameW,
  1192. /* [in] */ LPCOLESTR pszPropNameW,
  1193. /* [out][in] */ PROPVARIANT *pVar)
  1194. {
  1195. const TCHAR *pszSectionName;
  1196. const TCHAR *pszPropName;
  1197. HRESULT hr;
  1198. if((NULL == pszSectionNameW) || (NULL == pszPropNameW) || (NULL == pVar))
  1199. {
  1200. return E_FAIL;
  1201. }
  1202. if(S_OK != _CreateTemporaryBackingFile())
  1203. {
  1204. ASSERT(NULL == m_pszTempFileName);
  1205. return E_FAIL;
  1206. }
  1207. ASSERT(m_pszTempFileName);
  1208. pszSectionName = pszSectionNameW;
  1209. pszPropName = pszPropNameW;
  1210. // Write the appropriate value in depending on the type
  1211. switch(pVar->vt)
  1212. {
  1213. // NOTE: (andrewgu) these types we also can round-trip using the same code pass as for
  1214. // unsigned types, except bharats in a codereview recommended we comment these out because
  1215. // they'll look goofy in the *.ini file (you wrote -5 but see 4294967290 junk instead).
  1216. // VT_UINT is not listed as "may appear in an OLE property set" in <wtypes.h>.
  1217. /* case VT_I1:
  1218. case VT_I2:
  1219. case VT_I4:
  1220. case VT_INT:
  1221. case VT_UINT: */
  1222. case VT_UI1:
  1223. case VT_UI2:
  1224. case VT_UI4:
  1225. hr = WriteUnsignedToFile(m_pszTempFileName, pszSectionName, pszPropName, pVar->ulVal);
  1226. break;
  1227. case VT_BSTR:
  1228. hr = WriteGenericString(m_pszTempFileName, pszSectionName, pszPropName, pVar->bstrVal);
  1229. break;
  1230. case VT_BLOB:
  1231. {
  1232. TCHAR *pszSizePropName = NULL;
  1233. int cchPropName = lstrlen(pszPropName) + ARRAYSIZE(c_szSizeSuffix) + 1;
  1234. DWORD dwAllocSize = cchPropName * sizeof(TCHAR);
  1235. pszSizePropName = (TCHAR *)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, dwAllocSize);
  1236. if(pszSizePropName)
  1237. {
  1238. DWORD dwBufferSize;
  1239. StrCpyN(pszSizePropName, pszPropName, cchPropName);
  1240. StrCatBuff(pszSizePropName, c_szSizeSuffix, cchPropName);
  1241. // OK Now - we have the name for the size
  1242. // we write it out
  1243. dwBufferSize = pVar->blob.cbSize;
  1244. hr = WriteBinaryToFile(m_pszTempFileName, pszSectionName, pszSizePropName,
  1245. (LPVOID)(&dwBufferSize), sizeof(DWORD));
  1246. if(S_OK == hr)
  1247. {
  1248. // Write out the buffer
  1249. hr = WriteBinaryToFile(m_pszTempFileName, pszSectionName, pszPropName,
  1250. (LPVOID)(pVar->blob.pBlobData), dwBufferSize);
  1251. }
  1252. LocalFree((LPVOID)pszSizePropName);
  1253. pszSizePropName = NULL;
  1254. }
  1255. else
  1256. {
  1257. hr = E_OUTOFMEMORY;
  1258. }
  1259. break;
  1260. }
  1261. default:
  1262. hr = WriteBinaryToFile(m_pszTempFileName, pszSectionName, pszPropName, (LPVOID)pVar, sizeof(PROPVARIANT));
  1263. break;
  1264. }
  1265. return hr;
  1266. }
  1267. STDMETHODIMP Intshcut::ReadPropertyNPB(
  1268. /* [in] */ LPCOLESTR pszSectionNameW,
  1269. /* [in] */ LPCOLESTR pszPropNameW,
  1270. /* [out][in] */ PROPVARIANT *pVar)
  1271. {
  1272. const TCHAR *pszSectionName;
  1273. const TCHAR *pszPropName;
  1274. TCHAR *pszFileToReadFrom;
  1275. HRESULT hr;
  1276. if((NULL == pszSectionNameW) || (NULL == pszPropNameW) || (NULL == pVar))
  1277. {
  1278. if (NULL != pVar)
  1279. pVar->vt = VT_ERROR;
  1280. return E_FAIL;
  1281. }
  1282. if(m_pszTempFileName)
  1283. {
  1284. pszFileToReadFrom = m_pszTempFileName;
  1285. }
  1286. else if(m_pszFile)
  1287. {
  1288. pszFileToReadFrom = m_pszFile;
  1289. }
  1290. else
  1291. {
  1292. pVar->vt = VT_EMPTY;
  1293. return S_FALSE;
  1294. }
  1295. pszSectionName = pszSectionNameW;
  1296. pszPropName = pszPropNameW;
  1297. switch(pVar->vt)
  1298. {
  1299. // NOTE: (andrewgu) these types we also can round-trip using the same code pass as for
  1300. // unsigned types, except bharats in a codereview recommended we comment these out because
  1301. // they'll look goofy in the *.ini file (you wrote -5 but see 4294967290 junk instead).
  1302. // VT_UINT is not listed as "may appear in an OLE property set" in <wtypes.h>.
  1303. /* case VT_I1:
  1304. case VT_I2:
  1305. case VT_I4:
  1306. case VT_INT:
  1307. case VT_UINT: */
  1308. case VT_UI1:
  1309. case VT_UI2:
  1310. case VT_UI4:
  1311. pVar->ulVal = 0;
  1312. hr = ReadUnsignedFromFile(pszFileToReadFrom, pszSectionName, pszPropName, &(pVar->ulVal));
  1313. break;
  1314. case VT_BSTR:
  1315. // It is a string
  1316. pVar->vt = VT_BSTR;
  1317. pVar->bstrVal = NULL;
  1318. hr = ReadBStrFromFile(pszFileToReadFrom, pszSectionName, pszPropName, &(pVar->bstrVal));
  1319. break;
  1320. case VT_BLOB:
  1321. {
  1322. TCHAR *pszSizePropName = NULL;
  1323. int cchPropName = lstrlen(pszPropName) + ARRAYSIZE(c_szSizeSuffix) + 1;
  1324. DWORD dwAllocSize = cchPropName * sizeof(TCHAR);
  1325. pszSizePropName = (TCHAR *)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, dwAllocSize);
  1326. if(pszSizePropName)
  1327. {
  1328. DWORD dwBufferSize;
  1329. StrCpyN(pszSizePropName, pszPropName, cchPropName);
  1330. StrCatBuff(pszSizePropName, c_szSizeSuffix, cchPropName);
  1331. // Read the Size first
  1332. hr = ReadBinaryFromFile(pszFileToReadFrom, pszSectionName, pszSizePropName,
  1333. &dwBufferSize, sizeof(DWORD));
  1334. if(S_OK == hr)
  1335. {
  1336. pVar->blob.pBlobData = (unsigned char *)CoTaskMemAlloc(dwBufferSize);
  1337. if(pVar->blob.pBlobData)
  1338. {
  1339. hr = ReadBinaryFromFile(pszFileToReadFrom, pszSectionName, pszPropName,
  1340. pVar->blob.pBlobData, dwBufferSize);
  1341. if(S_OK == hr)
  1342. {
  1343. pVar->blob.cbSize = dwBufferSize;
  1344. }
  1345. else
  1346. {
  1347. CoTaskMemFree(pVar->blob.pBlobData);
  1348. }
  1349. }
  1350. }
  1351. LocalFree(pszSizePropName);
  1352. pszSizePropName = NULL;
  1353. }
  1354. else
  1355. {
  1356. hr = E_OUTOFMEMORY;
  1357. }
  1358. break;
  1359. }
  1360. default:
  1361. {
  1362. // all else
  1363. PROPVARIANT tmpPropvar = {0};
  1364. hr = ReadBinaryFromFile(pszFileToReadFrom, pszSectionName, pszPropName, &tmpPropvar, sizeof(PROPVARIANT));
  1365. if((S_OK == hr) && (tmpPropvar.vt == pVar->vt))
  1366. {
  1367. memcpy(pVar, &tmpPropvar, sizeof(PROPVARIANT));
  1368. }
  1369. else
  1370. {
  1371. pVar->vt = VT_ERROR;
  1372. }
  1373. break;
  1374. }
  1375. }
  1376. if(hr != S_OK)
  1377. {
  1378. memset(pVar, 0, sizeof(PROPVARIANT));
  1379. pVar->vt = VT_EMPTY;
  1380. }
  1381. return hr;
  1382. }
  1383. STDMETHODIMP Intshcut::RemovePropertyNPB (
  1384. /* [in] */ LPCOLESTR pszSectionNameW,
  1385. /* [in] */ LPCOLESTR pszPropNameW)
  1386. {
  1387. const TCHAR *pszSectionName;
  1388. const TCHAR *pszPropName;
  1389. HRESULT hr;
  1390. TCHAR *pszFileToDeleteFrom;
  1391. // Return if there is no file name
  1392. if((NULL == pszSectionNameW) || (NULL == pszPropNameW))
  1393. {
  1394. return E_FAIL;
  1395. }
  1396. if(m_pszTempFileName)
  1397. {
  1398. pszFileToDeleteFrom = m_pszTempFileName;
  1399. }
  1400. else if(m_pszFile)
  1401. {
  1402. pszFileToDeleteFrom = m_pszFile;
  1403. }
  1404. else
  1405. {
  1406. return E_FAIL;
  1407. }
  1408. // Just delete the key corresponding to this property name
  1409. pszSectionName = pszSectionNameW;
  1410. pszPropName = pszPropNameW;
  1411. hr = SHDeleteIniString(pszSectionName, pszPropName, pszFileToDeleteFrom)? S_OK : E_FAIL;
  1412. return hr;
  1413. }