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.

2025 lines
56 KiB

  1. #include "stock.h"
  2. #pragma hdrstop
  3. #include <idhidden.h>
  4. #include <regitemp.h>
  5. #include <shstr.h>
  6. #include <shlobjp.h>
  7. #include <lmcons.h>
  8. #include <validc.h>
  9. #include "ccstock2.h"
  10. #include "wininet.h"
  11. #include "w95wraps.h"
  12. #include <strsafe.h>
  13. //------------------------------------------------------------------------
  14. // Random helpful functions
  15. //------------------------------------------------------------------------
  16. //
  17. STDAPI_(LPCTSTR) SkipServerSlashes(LPCTSTR pszName)
  18. {
  19. for (pszName; *pszName && *pszName == TEXT('\\'); pszName++);
  20. return pszName;
  21. }
  22. // pbIsNamed is true if the i-th item in hm is a named separator
  23. STDAPI_(BOOL) _SHIsMenuSeparator2(HMENU hm, int i, BOOL *pbIsNamed)
  24. {
  25. MENUITEMINFO mii;
  26. BOOL bLocal;
  27. if (!pbIsNamed)
  28. pbIsNamed = &bLocal;
  29. *pbIsNamed = FALSE;
  30. mii.cbSize = sizeof(mii);
  31. mii.fMask = MIIM_TYPE | MIIM_ID;
  32. mii.cch = 0; // WARNING: We MUST initialize it to 0!!!
  33. if (GetMenuItemInfo(hm, i, TRUE, &mii) && (mii.fType & MFT_SEPARATOR))
  34. {
  35. // NOTE that there is a bug in either 95 or NT user!!!
  36. // 95 returns 16 bit ID's and NT 32 bit therefore there is a
  37. // the following may fail, on win9x, to evaluate to false
  38. // without casting
  39. *pbIsNamed = ((WORD)mii.wID != (WORD)-1);
  40. return TRUE;
  41. }
  42. return FALSE;
  43. }
  44. STDAPI_(BOOL) _SHIsMenuSeparator(HMENU hm, int i)
  45. {
  46. return _SHIsMenuSeparator2(hm, i, NULL);
  47. }
  48. //
  49. // _SHPrettyMenu -- make this menu look darn purty
  50. //
  51. // Prune the separators in this hmenu to ensure there isn't one in the first or last
  52. // position and there aren't any runs of >1 separator.
  53. //
  54. // Named separators take precedence over regular separators.
  55. //
  56. STDAPI_(void) _SHPrettyMenu(HMENU hm)
  57. {
  58. BOOL bSeparated = TRUE;
  59. BOOL bWasNamed = TRUE;
  60. for (int i = GetMenuItemCount(hm) - 1; i > 0; --i)
  61. {
  62. BOOL bIsNamed;
  63. if (_SHIsMenuSeparator2(hm, i, &bIsNamed))
  64. {
  65. if (bSeparated)
  66. {
  67. // if we have two separators in a row, only one of which is named
  68. // remove the non named one!
  69. if (bIsNamed && !bWasNamed)
  70. {
  71. DeleteMenu(hm, i+1, MF_BYPOSITION);
  72. bWasNamed = bIsNamed;
  73. }
  74. else
  75. {
  76. DeleteMenu(hm, i, MF_BYPOSITION);
  77. }
  78. }
  79. else
  80. {
  81. bWasNamed = bIsNamed;
  82. bSeparated = TRUE;
  83. }
  84. }
  85. else
  86. {
  87. bSeparated = FALSE;
  88. }
  89. }
  90. // The above loop does not handle the case of many separators at
  91. // the beginning of the menu
  92. while (_SHIsMenuSeparator2(hm, 0, NULL))
  93. {
  94. DeleteMenu(hm, 0, MF_BYPOSITION);
  95. }
  96. }
  97. STDAPI_(DWORD) SHIsButtonObscured(HWND hwnd, PRECT prc, INT_PTR i)
  98. {
  99. ASSERT(IsWindow(hwnd));
  100. ASSERT(i < SendMessage(hwnd, TB_BUTTONCOUNT, 0, 0));
  101. DWORD dwEdge = 0;
  102. RECT rc, rcInt;
  103. SendMessage(hwnd, TB_GETITEMRECT, i, (LPARAM)&rc);
  104. if (!IntersectRect(&rcInt, prc, &rc))
  105. {
  106. dwEdge = EDGE_LEFT | EDGE_RIGHT | EDGE_TOP | EDGE_BOTTOM;
  107. }
  108. else
  109. {
  110. if (rc.top != rcInt.top)
  111. dwEdge |= EDGE_TOP;
  112. if (rc.bottom != rcInt.bottom)
  113. dwEdge |= EDGE_BOTTOM;
  114. if (rc.left != rcInt.left)
  115. dwEdge |= EDGE_LEFT;
  116. if (rc.right != rcInt.right)
  117. dwEdge |= EDGE_RIGHT;
  118. }
  119. return dwEdge;
  120. }
  121. STDAPI_(BYTE) SHBtnStateFromRestriction(DWORD dwRest, BYTE fsState)
  122. {
  123. if (dwRest == RESTOPT_BTN_STATE_VISIBLE)
  124. return (fsState & ~TBSTATE_HIDDEN);
  125. else if (dwRest == RESTOPT_BTN_STATE_HIDDEN)
  126. return (fsState | TBSTATE_HIDDEN);
  127. else {
  128. #ifdef DEBUG
  129. if (dwRest != RESTOPT_BTN_STATE_DEFAULT)
  130. TraceMsg(TF_ERROR, "bad toolbar button state policy %x", dwRest);
  131. #endif
  132. return fsState;
  133. }
  134. }
  135. //
  136. // SHIsDisplayable
  137. //
  138. // Figure out if this unicode string can be displayed by the system
  139. // (i.e., won't be turned into a string of question marks).
  140. //
  141. STDAPI_(BOOL) SHIsDisplayable(LPCWSTR pwszName, BOOL fRunOnFE, BOOL fRunOnNT5)
  142. {
  143. BOOL fNotDisplayable = FALSE;
  144. if (pwszName)
  145. {
  146. if (!fRunOnNT5)
  147. {
  148. // if WCtoMB has to use default characters in mapping pwszName to multibyte,
  149. // it sets fNotDisplayable == TRUE, in which case we have to use something
  150. // else for the title string.
  151. WideCharToMultiByte(CP_ACP, 0, pwszName, -1, NULL, 0, NULL, &fNotDisplayable);
  152. if (fNotDisplayable)
  153. {
  154. if (fRunOnFE)
  155. {
  156. WCHAR wzName[INTERNET_MAX_URL_LENGTH];
  157. BOOL fReplaceNbsp = FALSE;
  158. StrCpyNW(wzName, pwszName, ARRAYSIZE(wzName));
  159. for (int i = 0; i < ARRAYSIZE(wzName); i++)
  160. {
  161. if (0x00A0 == wzName[i]) // if &nbsp
  162. {
  163. wzName[i] = 0x0020; // replace to space
  164. fReplaceNbsp = TRUE;
  165. }
  166. else if (0 == wzName[i])
  167. break;
  168. }
  169. if (fReplaceNbsp)
  170. {
  171. pwszName = wzName;
  172. WideCharToMultiByte(CP_ACP, 0, pwszName, -1, NULL, 0, NULL, &fNotDisplayable);
  173. }
  174. }
  175. }
  176. }
  177. }
  178. return !fNotDisplayable;
  179. }
  180. // Trident will take URLs that don't indicate their source of
  181. // origin (about:, javascript:, & vbscript:) and will append
  182. // an URL turd and then the source URL. The turd will indicate
  183. // where the source URL begins and that source URL is needed
  184. // when the action needs to be Zone Checked.
  185. //
  186. // This function will remove that URL turd and everything behind
  187. // it so the URL is presentable for the user.
  188. #define URL_TURD ((TCHAR)0x01)
  189. STDAPI_(void) SHRemoveURLTurd(LPTSTR pszUrl)
  190. {
  191. if (!pszUrl)
  192. return;
  193. while (0 != pszUrl[0])
  194. {
  195. if (URL_TURD == pszUrl[0])
  196. {
  197. pszUrl[0] = 0;
  198. break;
  199. }
  200. pszUrl = CharNext(pszUrl);
  201. }
  202. }
  203. STDAPI_(BOOL) SetWindowZorder(HWND hwnd, HWND hwndInsertAfter)
  204. {
  205. return SetWindowPos(hwnd, hwndInsertAfter, 0, 0, 0, 0,
  206. SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
  207. }
  208. BOOL CALLBACK _FixZorderEnumProc(HWND hwnd, LPARAM lParam)
  209. {
  210. HWND hwndTest = (HWND)lParam;
  211. HWND hwndOwner = hwnd;
  212. while (hwndOwner = GetWindow(hwndOwner, GW_OWNER))
  213. {
  214. if (hwndOwner == hwndTest)
  215. {
  216. TraceMsg(TF_WARNING, "_FixZorderEnumProc: Found topmost window %x owned by non-topmost window %x, fixing...", hwnd, hwndTest);
  217. SetWindowZorder(hwnd, HWND_NOTOPMOST);
  218. #ifdef DEBUG
  219. if (GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST)
  220. TraceMsg(TF_ERROR, "_FixZorderEnumProc: window %x is still topmost", hwnd);
  221. #endif
  222. break;
  223. }
  224. }
  225. return TRUE;
  226. }
  227. STDAPI_(BOOL) SHForceWindowZorder(HWND hwnd, HWND hwndInsertAfter)
  228. {
  229. BOOL fRet = SetWindowZorder(hwnd, hwndInsertAfter);
  230. if (fRet && hwndInsertAfter == HWND_TOPMOST)
  231. {
  232. if (!(GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST))
  233. {
  234. //
  235. // user didn't actually move the hwnd to topmost
  236. //
  237. // According to GerardoB, this can happen if the window has
  238. // an owned window that somehow has become topmost while the
  239. // owner remains non-topmost, i.e., the two have become
  240. // separated in the z-order. In this state, when the owner
  241. // window tries to make itself topmost, the call will
  242. // silently fail.
  243. //
  244. // TERRIBLE HORRIBLE NO GOOD VERY BAD HACK
  245. //
  246. // Hacky fix is to enumerate the toplevel windows, check to see
  247. // if any are topmost and owned by hwnd, and if so, make them
  248. // non-topmost. Then, retry the SetWindowPos call.
  249. //
  250. TraceMsg(TF_WARNING, "SHForceWindowZorder: SetWindowPos(%x, HWND_TOPMOST) failed", hwnd);
  251. // Fix up the z-order
  252. EnumWindows(_FixZorderEnumProc, (LPARAM)hwnd);
  253. // Retry the set. (This should make all owned windows topmost as well.)
  254. SetWindowZorder(hwnd, HWND_TOPMOST);
  255. #ifdef DEBUG
  256. if (!(GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST))
  257. TraceMsg(TF_ERROR, "SHForceWindowZorder: window %x is still not topmost", hwnd);
  258. #endif
  259. }
  260. }
  261. return fRet;
  262. }
  263. STDAPI_(LPITEMIDLIST) ILCloneParent(LPCITEMIDLIST pidl)
  264. {
  265. LPITEMIDLIST pidlParent = ILClone(pidl);
  266. if (pidlParent)
  267. ILRemoveLastID(pidlParent);
  268. return pidlParent;
  269. }
  270. // in:
  271. // psf OPTIONAL, if NULL assume psfDesktop
  272. // pidl to bind to from psfParent
  273. //
  274. STDAPI SHBindToObject(IShellFolder *psf, REFIID riid, LPCITEMIDLIST pidl, void **ppv)
  275. {
  276. // NOTE: callers should use SHBindToObjectEx!!!
  277. return SHBindToObjectEx(psf, pidl, NULL, riid, ppv);
  278. }
  279. // in:
  280. // psf OPTIONAL, if NULL assume psfDesktop
  281. // pidl to bind to from psfParent
  282. // pbc bind context
  283. STDAPI SHBindToObjectEx(IShellFolder *psf, LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
  284. {
  285. HRESULT hr;
  286. IShellFolder *psfRelease = NULL;
  287. if (!psf)
  288. {
  289. SHGetDesktopFolder(&psf);
  290. psfRelease = psf;
  291. }
  292. if (psf)
  293. {
  294. if (!pidl || ILIsEmpty(pidl))
  295. {
  296. hr = psf->QueryInterface(riid, ppv);
  297. }
  298. else
  299. {
  300. hr = psf->BindToObject(pidl, pbc, riid, ppv);
  301. }
  302. }
  303. else
  304. {
  305. *ppv = NULL;
  306. hr = E_FAIL;
  307. }
  308. if (psfRelease)
  309. {
  310. psfRelease->Release();
  311. }
  312. if (SUCCEEDED(hr) && (*ppv == NULL))
  313. {
  314. // Some shell extensions (eg WS_FTP) will return success and a null out pointer
  315. TraceMsg(TF_WARNING, "SHBindToObjectEx: BindToObject succeeded but returned null ppv!!");
  316. hr = E_FAIL;
  317. }
  318. return hr;
  319. }
  320. // psfRoot is the base of the bind. If NULL, then we use the shell desktop.
  321. // If you want to bind relative to the explorer root (e.g., CabView, MSN),
  322. // then use SHBindToIDListParent.
  323. STDAPI SHBindToFolderIDListParent(IShellFolder *psfRoot, LPCITEMIDLIST pidl, REFIID riid, void **ppv, LPCITEMIDLIST *ppidlLast)
  324. {
  325. HRESULT hr;
  326. // Old shell32 code in some cases simply whacked the pidl,
  327. // but this is unsafe. Do what shdocvw does and clone/remove:
  328. //
  329. LPITEMIDLIST pidlParent = ILCloneParent(pidl);
  330. if (pidlParent)
  331. {
  332. hr = SHBindToObjectEx(psfRoot, pidlParent, NULL, riid, ppv);
  333. ILFree(pidlParent);
  334. }
  335. else
  336. hr = E_OUTOFMEMORY;
  337. if (ppidlLast)
  338. *ppidlLast = ILFindLastID(pidl);
  339. return hr;
  340. }
  341. //
  342. // Warning! brutil.cpp overrides this function
  343. //
  344. STDAPI SHBindToIDListParent(LPCITEMIDLIST pidl, REFIID riid, void **ppv, LPCITEMIDLIST *ppidlLast)
  345. {
  346. return SHBindToFolderIDListParent(NULL, pidl, riid, ppv, ppidlLast);
  347. }
  348. // should be IUnknown_GetIDList()
  349. STDAPI SHGetIDListFromUnk(IUnknown *punk, LPITEMIDLIST *ppidl)
  350. {
  351. *ppidl = NULL;
  352. HRESULT hr = E_NOINTERFACE;
  353. if (punk)
  354. {
  355. IPersistFolder2 *ppf;
  356. IPersistIDList *pperid;
  357. if (SUCCEEDED(punk->QueryInterface(IID_PPV_ARG(IPersistIDList, &pperid))))
  358. {
  359. hr = pperid->GetIDList(ppidl);
  360. pperid->Release();
  361. }
  362. else if (SUCCEEDED(punk->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf))))
  363. {
  364. hr = ppf->GetCurFolder(ppidl);
  365. ppf->Release();
  366. }
  367. }
  368. return hr;
  369. }
  370. //
  371. // generically useful to hide.
  372. //
  373. #pragma pack(1)
  374. typedef struct _HIDDENCLSID
  375. {
  376. HIDDENITEMID hid;
  377. CLSID clsid;
  378. } HIDDENCLSID;
  379. #pragma pack()
  380. typedef UNALIGNED HIDDENCLSID *PHIDDENCLSID;
  381. typedef const UNALIGNED HIDDENCLSID *PCHIDDENCLSID;
  382. STDAPI_(LPITEMIDLIST) ILAppendHiddenClsid(LPITEMIDLIST pidl, IDLHID id, CLSID *pclsid)
  383. {
  384. HIDDENCLSID hc = {{sizeof(hc), 0, id}};
  385. hc.clsid = *pclsid;
  386. // WARNING - cannot use hid.wVersion for compat reasons - ZekeL - 23-OCT-2000
  387. // on win2k and winMe we appended clsid's with wVersion
  388. // as stack garbage. this means we cannot use it for anything
  389. return ILAppendHiddenID(pidl, &hc.hid);
  390. }
  391. STDAPI_(BOOL) ILGetHiddenClsid(LPCITEMIDLIST pidl, IDLHID id, CLSID *pclsid)
  392. {
  393. PCHIDDENCLSID phc = (PCHIDDENCLSID) ILFindHiddenID(pidl, id);
  394. // WARNING - cannot use hid.wVersion for compat reasons - ZekeL - 23-OCT-2000
  395. // on win2k and winMe we appended clsid's with wVersion
  396. // as stack garbage. this means we cannot use it for anything
  397. if (phc)
  398. {
  399. *pclsid = phc->clsid;
  400. return TRUE;
  401. }
  402. return FALSE;
  403. }
  404. #pragma pack(1)
  405. typedef struct _HIDDENSTRINGA
  406. {
  407. HIDDENITEMID hid;
  408. WORD type;
  409. CHAR sz[1]; // variable length string
  410. } HIDDENSTRINGA;
  411. #pragma pack()
  412. typedef UNALIGNED HIDDENSTRINGA *PHIDDENSTRINGA;
  413. typedef const UNALIGNED HIDDENSTRINGA *PCHIDDENSTRINGA;
  414. #pragma pack(1)
  415. typedef struct _HIDDENSTRINGW
  416. {
  417. HIDDENITEMID hid;
  418. WORD type;
  419. WCHAR sz[1]; // canonical name to be passed to ISTRING
  420. } HIDDENSTRINGW;
  421. #pragma pack()
  422. typedef UNALIGNED HIDDENSTRINGW *PHIDDENSTRINGW;
  423. typedef const UNALIGNED HIDDENSTRINGW *PCHIDDENSTRINGW;
  424. #define HIDSTRTYPE_ANSI 0x0001
  425. #define HIDSTRTYPE_WIDE 0x0002
  426. #define HIDSTR_MAX 0xF000 // max ushort - sizeof(HIDDENSTRINGW) - other goo for original pidl
  427. STDAPI_(LPITEMIDLIST) ILAppendHiddenStringW(LPITEMIDLIST pidl, IDLHID id, LPCWSTR psz)
  428. {
  429. // terminator is included in the ID definition
  430. size_t cbString;
  431. HRESULT hr = StringCbLengthW(psz, HIDSTR_MAX, &cbString);
  432. if (FAILED(hr))
  433. {
  434. return NULL;
  435. }
  436. USHORT cb = (USHORT)(sizeof(HIDDENSTRINGW) + cbString);
  437. //
  438. // Use HIDDENSTRINGW* here instead of PHIDDENSTRINGW which is defined
  439. // as UNALIGNED.
  440. //
  441. HIDDENSTRINGW *phs = (HIDDENSTRINGW *) LocalAlloc(LPTR, cb);
  442. if (phs)
  443. {
  444. phs->hid.cb = cb;
  445. phs->hid.id = id;
  446. phs->type = HIDSTRTYPE_WIDE;
  447. //
  448. // Terminator is included in the ID definition but...
  449. // we need to now account for that extra character
  450. // when we copy the hidden string.
  451. //
  452. StringCbCopyW(phs->sz, cbString + sizeof(*psz), psz);
  453. pidl = ILAppendHiddenID(pidl, &phs->hid);
  454. LocalFree(phs);
  455. return pidl;
  456. }
  457. return NULL;
  458. }
  459. STDAPI_(LPITEMIDLIST) ILAppendHiddenStringA(LPITEMIDLIST pidl, IDLHID id, LPCSTR psz)
  460. {
  461. // terminator is included in the ID definition
  462. size_t cbString;
  463. HRESULT hr = StringCbLengthA(psz, HIDSTR_MAX, &cbString);
  464. if (FAILED(hr))
  465. {
  466. return NULL;
  467. }
  468. USHORT cb = (USHORT)(sizeof(HIDDENSTRINGA) + cbString);
  469. //
  470. // Use HIDDENSTRINGA* here instead of PHIDDENSTRINGW which is defined
  471. // as UNALIGNED.
  472. //
  473. HIDDENSTRINGA *phs = (HIDDENSTRINGA *) LocalAlloc(LPTR, cb);
  474. if (phs)
  475. {
  476. phs->hid.cb = cb;
  477. phs->hid.id = id;
  478. phs->type = HIDSTRTYPE_ANSI;
  479. //
  480. // Terminator is included in the ID definition but...
  481. // we need to now account for that extra character
  482. // when we copy the hidden string.
  483. //
  484. StringCbCopyA(phs->sz, cbString + sizeof(*psz), psz);
  485. pidl = ILAppendHiddenID(pidl, &phs->hid);
  486. LocalFree(phs);
  487. return pidl;
  488. }
  489. return NULL;
  490. }
  491. STDAPI_(void *) _MemDupe(const UNALIGNED void *pv, DWORD cb)
  492. {
  493. void *pvRet = LocalAlloc(LPTR, cb);
  494. if (pvRet)
  495. {
  496. CopyMemory(pvRet, pv, cb);
  497. }
  498. return pvRet;
  499. }
  500. STDAPI_(BOOL) ILGetHiddenStringW(LPCITEMIDLIST pidl, IDLHID id, LPWSTR psz, DWORD cch)
  501. {
  502. PCHIDDENSTRINGW phs = (PCHIDDENSTRINGW) ILFindHiddenID(pidl, id);
  503. RIP(psz);
  504. if (phs)
  505. {
  506. if (phs->type == HIDSTRTYPE_WIDE)
  507. {
  508. ualstrcpynW(psz, phs->sz, cch);
  509. return TRUE;
  510. }
  511. else
  512. {
  513. ASSERT(phs->type == HIDSTRTYPE_ANSI);
  514. SHAnsiToUnicode((LPSTR)phs->sz, psz, cch);
  515. return TRUE;
  516. }
  517. }
  518. return FALSE;
  519. }
  520. STDAPI_(BOOL) ILGetHiddenStringA(LPCITEMIDLIST pidl, IDLHID id, LPSTR psz, DWORD cch)
  521. {
  522. PCHIDDENSTRINGW phs = (PCHIDDENSTRINGW) ILFindHiddenID(pidl, id);
  523. RIP(psz);
  524. if (phs)
  525. {
  526. if (phs->type == HIDSTRTYPE_ANSI)
  527. {
  528. ualstrcpynA(psz, (LPSTR)phs->sz, cch);
  529. return TRUE;
  530. }
  531. else
  532. {
  533. ASSERT(phs->type == HIDSTRTYPE_WIDE);
  534. // we need to handle the unalignment here...
  535. LPWSTR pszT = (LPWSTR) _MemDupe(phs->sz, CbFromCch(ualstrlenW(phs->sz) +1));
  536. if (pszT)
  537. {
  538. SHUnicodeToAnsi(pszT, psz, cch);
  539. LocalFree(pszT);
  540. return TRUE;
  541. }
  542. }
  543. }
  544. return FALSE;
  545. }
  546. STDAPI_(int) ILCompareHiddenString(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2, IDLHID id)
  547. {
  548. // if there are fragments in here, then they might
  549. // differentiate the two pidls
  550. PCHIDDENSTRINGW ps1 = (PCHIDDENSTRINGW)ILFindHiddenID(pidl1, id);
  551. PCHIDDENSTRINGW ps2 = (PCHIDDENSTRINGW)ILFindHiddenID(pidl2, id);
  552. if (ps1 && ps2)
  553. {
  554. if (ps1->type == ps2->type)
  555. {
  556. if (ps1->type == HIDSTRTYPE_WIDE)
  557. return ualstrcmpW(ps1->sz, ps2->sz);
  558. ASSERT(ps1->type == HIDSTRTYPE_ANSI);
  559. return lstrcmpA((LPCSTR)ps1->sz, (LPCSTR)ps2->sz);
  560. }
  561. else
  562. {
  563. SHSTRW str;
  564. if (ps1->type == HIDSTRTYPE_ANSI)
  565. {
  566. str.SetStr((LPCSTR)ps1->sz);
  567. return ualstrcmpW(str, ps2->sz);
  568. }
  569. else
  570. {
  571. ASSERT(ps2->type == HIDSTRTYPE_ANSI);
  572. str.SetStr((LPCSTR)ps2->sz);
  573. return ualstrcmpW(ps1->sz, str);
  574. }
  575. }
  576. }
  577. if (ps1)
  578. return 1;
  579. if (ps2)
  580. return -1;
  581. return 0;
  582. }
  583. STDAPI_(OBJCOMPATFLAGS) SHGetObjectCompatFlagsFromIDList(LPCITEMIDLIST pidl)
  584. {
  585. OBJCOMPATFLAGS ocf = 0;
  586. CLSID clsid;
  587. // APPCOMPAT: FileNet IDMDS (Panagon)'s shell folder extension returns
  588. // E_NOTIMPL for IPersistFolder::GetClassID, so to detect the application,
  589. // we have to crack the pidl. (B#359464: tracysh)
  590. if (!ILIsEmpty(pidl)
  591. && pidl->mkid.cb >= sizeof(IDREGITEM)
  592. && pidl->mkid.abID[0] == SHID_ROOT_REGITEM)
  593. {
  594. clsid = ((LPCIDLREGITEM)pidl)->idri.clsid;
  595. ocf = SHGetObjectCompatFlags(NULL, &clsid);
  596. }
  597. return ocf;
  598. }
  599. STDAPI_(LPITEMIDLIST) _ILCreate(UINT cbSize)
  600. {
  601. LPITEMIDLIST pidl = (LPITEMIDLIST)SHAlloc(cbSize);
  602. if (pidl)
  603. memset(pidl, 0, cbSize); // zero-init for external task allocator
  604. return pidl;
  605. }
  606. //
  607. // ILClone using Task allocator
  608. //
  609. STDAPI SHILClone(LPCITEMIDLIST pidl, LPITEMIDLIST * ppidlOut)
  610. {
  611. *ppidlOut = ILClone(pidl);
  612. return *ppidlOut ? S_OK : E_OUTOFMEMORY;
  613. }
  614. //
  615. // ILCombine using Task allocator
  616. //
  617. STDAPI SHILCombine(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2, LPITEMIDLIST * ppidlOut)
  618. {
  619. *ppidlOut = ILCombine(pidl1, pidl2);
  620. return *ppidlOut ? S_OK : E_OUTOFMEMORY;
  621. }
  622. //
  623. // rooted helpers
  624. //
  625. LPCIDREGITEM _IsRooted(LPCITEMIDLIST pidl)
  626. {
  627. LPCIDREGITEM pidlr = (LPCIDREGITEM)pidl;
  628. if (!ILIsEmpty(pidl)
  629. && pidlr->cb > sizeof(IDREGITEM)
  630. && pidlr->bFlags == SHID_ROOTEDREGITEM)
  631. return pidlr;
  632. return NULL;
  633. }
  634. STDAPI_(BOOL) ILIsRooted(LPCITEMIDLIST pidl)
  635. {
  636. return (NULL != _IsRooted(pidl));
  637. }
  638. #define _ROOTEDPIDL(pidlr) (LPITEMIDLIST)(((LPBYTE)pidlr)+sizeof(IDREGITEM))
  639. STDAPI_(LPCITEMIDLIST) ILRootedFindIDList(LPCITEMIDLIST pidl)
  640. {
  641. LPCIDREGITEM pidlr = _IsRooted(pidl);
  642. if (pidlr && pidlr->cb > sizeof(IDREGITEM))
  643. {
  644. // then we have a rooted IDList in there
  645. return _ROOTEDPIDL(pidlr);
  646. }
  647. return NULL;
  648. }
  649. STDAPI_(BOOL) ILRootedGetClsid(LPCITEMIDLIST pidl, CLSID *pclsid)
  650. {
  651. LPCIDREGITEM pidlr = _IsRooted(pidl);
  652. *pclsid = pidlr ? pidlr->clsid : CLSID_NULL;
  653. return (NULL != pidlr);
  654. }
  655. STDAPI_(LPITEMIDLIST) ILRootedCreateIDList(CLSID *pclsid, LPCITEMIDLIST pidl)
  656. {
  657. UINT cbPidl = ILGetSize(pidl);
  658. UINT cbTotal = sizeof(IDREGITEM) + cbPidl;
  659. LPIDREGITEM pidlr = (LPIDREGITEM) SHAlloc(cbTotal + sizeof(WORD));
  660. if (pidlr)
  661. {
  662. pidlr->cb = (WORD)cbTotal;
  663. pidlr->bFlags = SHID_ROOTEDREGITEM;
  664. pidlr->bOrder = 0; // Nobody uses this (yet)
  665. if (pclsid)
  666. pidlr->clsid = *pclsid;
  667. else
  668. pidlr->clsid = CLSID_ShellDesktop;
  669. MoveMemory(_ROOTEDPIDL(pidlr), pidl, cbPidl);
  670. // terminate
  671. _ILNext((LPITEMIDLIST)pidlr)->mkid.cb = 0;
  672. }
  673. return (LPITEMIDLIST) pidlr;
  674. }
  675. int CompareGUID(REFGUID guid1, REFGUID guid2)
  676. {
  677. TCHAR sz1[GUIDSTR_MAX];
  678. TCHAR sz2[GUIDSTR_MAX];
  679. SHStringFromGUIDW(guid1, sz1, SIZECHARS(sz1));
  680. SHStringFromGUIDW(guid2, sz2, SIZECHARS(sz2));
  681. return lstrcmp(sz1, sz2);
  682. }
  683. STDAPI_(int) ILRootedCompare(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  684. {
  685. int iRet;
  686. LPCIDREGITEM pidlr1 = _IsRooted(pidl1);
  687. LPCIDREGITEM pidlr2 = _IsRooted(pidl2);
  688. if (pidlr1 && pidlr2)
  689. {
  690. CLSID clsid1 = pidlr1->clsid;
  691. CLSID clsid2 = pidlr2->clsid;
  692. iRet = CompareGUID(clsid1, clsid2);
  693. if (0 == iRet)
  694. {
  695. if (!ILIsEqual(_ROOTEDPIDL(pidl1), _ROOTEDPIDL(pidl2)))
  696. {
  697. IShellFolder *psfDesktop;
  698. if (SUCCEEDED(SHGetDesktopFolder(&psfDesktop)))
  699. {
  700. HRESULT hr = psfDesktop->CompareIDs(0, _ROOTEDPIDL(pidl1), _ROOTEDPIDL(pidl2));
  701. psfDesktop->Release();
  702. iRet = ShortFromResult(hr);
  703. }
  704. }
  705. }
  706. }
  707. else if (pidlr1)
  708. {
  709. iRet = -1;
  710. }
  711. else if (pidlr2)
  712. {
  713. iRet = 1;
  714. }
  715. else
  716. {
  717. // if neither are rootes, then they share the desktop
  718. // as the same root...
  719. iRet = 0;
  720. }
  721. return iRet;
  722. }
  723. LPITEMIDLIST ILRootedTranslate(LPCITEMIDLIST pidlRooted, LPCITEMIDLIST pidlTrans)
  724. {
  725. LPCITEMIDLIST pidlChild = ILFindChild(ILRootedFindIDList(pidlRooted), pidlTrans);
  726. if (pidlChild)
  727. {
  728. LPITEMIDLIST pidlRoot = ILCloneFirst(pidlRooted);
  729. if (pidlRoot)
  730. {
  731. LPITEMIDLIST pidlRet = ILCombine(pidlRoot, pidlChild);
  732. ILFree(pidlRoot);
  733. return pidlRet;
  734. }
  735. }
  736. return NULL;
  737. }
  738. const ITEMIDLIST s_idlNULL = { 0 } ;
  739. HRESULT ILRootedBindToRoot(LPCITEMIDLIST pidl, REFIID riid, void **ppv)
  740. {
  741. HRESULT hr;
  742. CLSID clsid;
  743. ASSERT(ILIsRooted(pidl));
  744. ILRootedGetClsid(pidl, &clsid);
  745. pidl = ILRootedFindIDList(pidl);
  746. if (!pidl)
  747. pidl = &s_idlNULL;
  748. if (IsEqualGUID(clsid, CLSID_ShellDesktop))
  749. {
  750. hr = SHBindToObjectEx(NULL, pidl, NULL, riid, ppv);
  751. }
  752. else
  753. {
  754. IPersistFolder* ppf;
  755. hr = SHCoCreateInstance(NULL, &clsid, NULL, IID_PPV_ARG(IPersistFolder, &ppf));
  756. if (SUCCEEDED(hr))
  757. {
  758. hr = ppf->Initialize(pidl);
  759. if (SUCCEEDED(hr))
  760. {
  761. hr = ppf->QueryInterface(riid, ppv);
  762. }
  763. ppf->Release();
  764. }
  765. }
  766. return hr;
  767. }
  768. HRESULT ILRootedBindToObject(LPCITEMIDLIST pidl, REFIID riid, void **ppv)
  769. {
  770. IShellFolder *psf;
  771. HRESULT hr = ILRootedBindToRoot(pidl, IID_PPV_ARG(IShellFolder, &psf));
  772. if (SUCCEEDED(hr))
  773. {
  774. pidl = _ILNext(pidl);
  775. if (ILIsEmpty(pidl))
  776. hr = psf->QueryInterface(riid, ppv);
  777. else
  778. hr = psf->BindToObject(pidl, NULL, riid, ppv);
  779. }
  780. return hr;
  781. }
  782. HRESULT ILRootedBindToParentFolder(LPCITEMIDLIST pidl, REFIID riid, void **ppv, LPCITEMIDLIST *ppidlChild)
  783. {
  784. //
  785. // there are three different cases to handle
  786. //
  787. // 1. Rooted pidl Alone
  788. // [ rooted id [ target pidl ] ]
  789. // return the parent folder of the target pidl
  790. // and return its last id in ppidlChild
  791. //
  792. // 2. Rooted pidl with One Child
  793. // [ rooted id [ target pidl ] ][ child id ]
  794. // return the rooted id as the parent folder
  795. // and the child id in ppidlChild
  796. //
  797. // 3. rooted pidl with many children
  798. // [ rooted id [ target pidl ] ][ parent id ][ child id ]
  799. // return rooted id bound to parent id as the folder
  800. // and the child id in ppidlchild
  801. //
  802. HRESULT hr;
  803. ASSERT(ILIsRooted(pidl));
  804. //
  805. // if this is a rooted pidl and it is just the root
  806. // then we can bind to the target pidl of the root instead
  807. //
  808. if (ILIsEmpty(_ILNext(pidl)))
  809. {
  810. hr = SHBindToIDListParent(ILRootedFindIDList(pidl), riid, ppv, ppidlChild);
  811. }
  812. else
  813. {
  814. LPITEMIDLIST pidlParent = ILCloneParent(pidl);
  815. if (pidlParent)
  816. {
  817. hr = ILRootedBindToObject(pidlParent, riid, ppv);
  818. ILFree(pidlParent);
  819. }
  820. else
  821. hr = E_OUTOFMEMORY;
  822. if (ppidlChild)
  823. *ppidlChild = ILFindLastID(pidl);
  824. }
  825. return hr;
  826. }
  827. #define HIDA_GetPIDLItem(pida, i) (LPCITEMIDLIST)(((LPBYTE)pida)+(pida)->aoffset[i+1])
  828. #define HIDA_GetPIDLFolder(pida) (LPCITEMIDLIST)(((LPBYTE)pida)+(pida)->aoffset[0])
  829. STDAPI_(LPITEMIDLIST) IDA_ILClone(LPIDA pida, UINT i)
  830. {
  831. if (i < pida->cidl)
  832. return ILCombine(HIDA_GetPIDLFolder(pida), HIDA_GetPIDLItem(pida, i));
  833. return NULL;
  834. }
  835. STDAPI_(void) EnableOKButtonFromString(HWND hDlg, LPTSTR pszText)
  836. {
  837. BOOL bNonEmpty;
  838. PathRemoveBlanks(pszText); // REVIEW, should we not remove from the end of
  839. bNonEmpty = lstrlen(pszText); // Not a BOOL, but okay
  840. EnableWindow(GetDlgItem(hDlg, IDOK), bNonEmpty);
  841. if (bNonEmpty)
  842. {
  843. SendMessage(hDlg, DM_SETDEFID, IDOK, 0L);
  844. }
  845. }
  846. STDAPI_(void) EnableOKButtonFromID(HWND hDlg, int id)
  847. {
  848. TCHAR szText[MAX_PATH];
  849. if (!GetDlgItemText(hDlg, id, szText, ARRAYSIZE(szText)))
  850. {
  851. szText[0] = 0;
  852. }
  853. EnableOKButtonFromString(hDlg, szText);
  854. }
  855. //
  856. // C-callable versions of the ATL string conversion functions.
  857. //
  858. STDAPI_(LPWSTR) SHA2WHelper(LPWSTR lpw, LPCSTR lpa, int nChars)
  859. {
  860. ASSERT(lpa != NULL);
  861. ASSERT(lpw != NULL);
  862. // verify that no illegal character present
  863. // since lpw was allocated based on the size of lpa
  864. // don't worry about the number of chars
  865. lpw[0] = '\0';
  866. MultiByteToWideChar(CP_ACP, 0, lpa, -1, lpw, nChars);
  867. return lpw;
  868. }
  869. STDAPI_(LPSTR) SHW2AHelper(LPSTR lpa, LPCWSTR lpw, int nChars)
  870. {
  871. ASSERT(lpw != NULL);
  872. ASSERT(lpa != NULL);
  873. // verify that no illegal character present
  874. // since lpa was allocated based on the size of lpw
  875. // don't worry about the number of chars
  876. lpa[0] = '\0';
  877. WideCharToMultiByte(CP_ACP, 0, lpw, -1, lpa, nChars, NULL, NULL);
  878. return lpa;
  879. }
  880. //
  881. // Helper functions for SHChangeMenuAsIDList
  882. //
  883. // See comment in declaration of SHChangeMenuAsIDList for caveats about
  884. // the pSender member.
  885. //
  886. // This is tricky because IE 5.0 shipped with a Win64-unfriendly version
  887. // of this notification, so we have to sniff the structure and see if
  888. // this is an IE 5.0 style notification or a new Win64 style notification.
  889. // If an IE 5.0 style notification, then it was not sent by us because
  890. // we send the new Win64-style notification.
  891. //
  892. STDAPI_(BOOL) SHChangeMenuWasSentByMe(void * self, LPCITEMIDLIST pidlNotify)
  893. {
  894. SHChangeMenuAsIDList UNALIGNED * pcmidl = (SHChangeMenuAsIDList UNALIGNED *)pidlNotify;
  895. return pcmidl->cb >= FIELD_OFFSET(SHChangeMenuAsIDList, cbZero) &&
  896. pcmidl->pSender == (INT64)self &&
  897. pcmidl->dwProcessID == GetCurrentProcessId();
  898. }
  899. //
  900. //
  901. // Send out an extended event changenotify, using a SHChangeMenuAsIDList
  902. // as the pidl1 so recipients can identify whether they were the
  903. // sender or not.
  904. //
  905. // It's okay to pass self==NULL here. It means you don't care about
  906. // detecting whether it was sent by you or not.
  907. //
  908. STDAPI_(void) SHSendChangeMenuNotify(void * self, DWORD shcnee, DWORD shcnf, LPCITEMIDLIST pidl2)
  909. {
  910. SHChangeMenuAsIDList cmidl;
  911. cmidl.cb = FIELD_OFFSET(SHChangeMenuAsIDList, cbZero);
  912. cmidl.dwItem1 = shcnee;
  913. cmidl.pSender = (INT64)self;
  914. cmidl.dwProcessID = self ? GetCurrentProcessId() : 0;
  915. cmidl.cbZero = 0;
  916. // Nobody had better have specified a type; the type must be
  917. // SHCNF_IDLIST.
  918. ASSERT((shcnf & SHCNF_TYPE) == 0);
  919. SHChangeNotify(SHCNE_EXTENDED_EVENT, shcnf | SHCNF_IDLIST, (LPCITEMIDLIST)&cmidl, pidl2);
  920. }
  921. // Return FALSE if out of memory
  922. STDAPI_(BOOL) Pidl_Set(LPITEMIDLIST* ppidl, LPCITEMIDLIST pidl)
  923. {
  924. BOOL bRet = TRUE;
  925. LPITEMIDLIST pidlNew;
  926. ASSERT(IS_VALID_WRITE_PTR(ppidl, LPITEMIDLIST));
  927. ASSERT(NULL == *ppidl || IS_VALID_PIDL(*ppidl));
  928. ASSERT(NULL == pidl || IS_VALID_PIDL(pidl));
  929. if (pidl)
  930. {
  931. pidlNew = ILClone(pidl);
  932. if (!pidlNew)
  933. {
  934. bRet = FALSE; // failed to clone the pidl (out of memory)
  935. }
  936. }
  937. else
  938. {
  939. pidlNew = NULL;
  940. }
  941. LPITEMIDLIST pidlToFree = (LPITEMIDLIST)InterlockedExchangePointer((void **)ppidl, (void *)pidlNew);
  942. if (pidlToFree)
  943. {
  944. ILFree(pidlToFree);
  945. }
  946. return bRet;
  947. }
  948. // this needs to be the last thing in the file that uses ILClone, because everywhere
  949. // else, ILClone becomes SafeILClone
  950. #undef ILClone
  951. STDAPI_(LPITEMIDLIST) SafeILClone(LPCITEMIDLIST pidl)
  952. {
  953. // the shell32 implementation of ILClone is different for win95 an ie4.
  954. // it doesnt check for NULL in the old version, but it does in the new...
  955. // so we need to always check
  956. return pidl ? ILClone(pidl) : NULL;
  957. }
  958. //
  959. // retrieves the UIObject interface for the specified full pidl.
  960. //
  961. STDAPI SHGetUIObjectFromFullPIDL(LPCITEMIDLIST pidl, HWND hwnd, REFIID riid, void **ppv)
  962. {
  963. *ppv = NULL;
  964. LPCITEMIDLIST pidlChild;
  965. IShellFolder* psf;
  966. HRESULT hr = SHBindToIDListParent(pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlChild);
  967. if (SUCCEEDED(hr))
  968. {
  969. hr = psf->GetUIObjectOf(hwnd, 1, &pidlChild, riid, NULL, ppv);
  970. psf->Release();
  971. }
  972. return hr;
  973. }
  974. STDAPI LoadFromFileW(REFCLSID clsid, LPCWSTR pszFile, REFIID riid, void **ppv)
  975. {
  976. *ppv = NULL;
  977. IPersistFile *ppf;
  978. HRESULT hr = SHCoCreateInstance(NULL, &clsid, NULL, IID_PPV_ARG(IPersistFile, &ppf));
  979. if (SUCCEEDED(hr))
  980. {
  981. hr = ppf->Load(pszFile, STGM_READ);
  982. if (SUCCEEDED(hr))
  983. hr = ppf->QueryInterface(riid, ppv);
  984. ppf->Release();
  985. }
  986. return hr;
  987. }
  988. STDAPI LoadFromIDList(REFCLSID clsid, LPCITEMIDLIST pidl, REFIID riid, void **ppv)
  989. {
  990. *ppv = NULL;
  991. IPersistFolder *ppf;
  992. HRESULT hr = SHCoCreateInstanceAC(clsid, NULL, CLSCTX_INPROC, IID_PPV_ARG(IPersistFolder, &ppf));
  993. if (SUCCEEDED(hr))
  994. {
  995. hr = ppf->Initialize(pidl);
  996. if (SUCCEEDED(hr))
  997. {
  998. hr = ppf->QueryInterface(riid, ppv);
  999. }
  1000. ppf->Release();
  1001. }
  1002. return hr;
  1003. }
  1004. //
  1005. // This is a helper function for finding a specific verb's index in a context menu
  1006. //
  1007. STDAPI_(UINT) GetMenuIndexForCanonicalVerb(HMENU hMenu, IContextMenu *pcm, UINT idCmdFirst, LPCWSTR pwszVerb)
  1008. {
  1009. int cMenuItems = GetMenuItemCount(hMenu);
  1010. for (int iItem = 0; iItem < cMenuItems; iItem++)
  1011. {
  1012. MENUITEMINFO mii = {0};
  1013. mii.cbSize = sizeof(mii);
  1014. mii.fMask = MIIM_TYPE | MIIM_ID;
  1015. // IS_INTRESOURCE guards against mii.wID == -1 **and** against
  1016. // buggy shell extensions which set their menu item IDs out of range.
  1017. if (GetMenuItemInfo(hMenu, iItem, MF_BYPOSITION, &mii) &&
  1018. !(mii.fType & MFT_SEPARATOR) && IS_INTRESOURCE(mii.wID) &&
  1019. (mii.wID >= idCmdFirst))
  1020. {
  1021. union {
  1022. WCHAR szItemNameW[80];
  1023. char szItemNameA[80];
  1024. };
  1025. CHAR aszVerb[80];
  1026. // try both GCS_VERBA and GCS_VERBW in case it only supports one of them
  1027. SHUnicodeToAnsi(pwszVerb, aszVerb, ARRAYSIZE(aszVerb));
  1028. if (SUCCEEDED(pcm->GetCommandString(mii.wID - idCmdFirst, GCS_VERBA, NULL, szItemNameA, ARRAYSIZE(szItemNameA))))
  1029. {
  1030. if (StrCmpICA(szItemNameA, aszVerb) == 0)
  1031. {
  1032. break; // found it
  1033. }
  1034. }
  1035. else
  1036. {
  1037. if (SUCCEEDED(pcm->GetCommandString(mii.wID - idCmdFirst, GCS_VERBW, NULL, (LPSTR)szItemNameW, ARRAYSIZE(szItemNameW))) &&
  1038. (StrCmpICW(szItemNameW, pwszVerb) == 0))
  1039. {
  1040. break; // found it
  1041. }
  1042. }
  1043. }
  1044. }
  1045. if (iItem == cMenuItems)
  1046. {
  1047. iItem = -1; // went through all the menuitems and didn't find it
  1048. }
  1049. return iItem;
  1050. }
  1051. // deal with GCS_VERBW/GCS_VERBA maddness
  1052. STDAPI ContextMenu_GetCommandStringVerb(IContextMenu *pcm, UINT idCmd, LPWSTR pszVerb, int cchVerb)
  1053. {
  1054. // Ulead SmartSaver Pro has a 60 character verb, and
  1055. // over writes out stack, ignoring the cch param and we fault.
  1056. // so make sure this buffer is at least 60 chars
  1057. TCHAR wszVerb[64];
  1058. wszVerb[0] = 0;
  1059. HRESULT hr = pcm->GetCommandString(idCmd, GCS_VERBW, NULL, (LPSTR)wszVerb, ARRAYSIZE(wszVerb));
  1060. if (FAILED(hr))
  1061. {
  1062. // be extra paranoid about requesting the ansi version -- we've
  1063. // found IContextMenu implementations that return a UNICODE buffer
  1064. // even though we ask for an ANSI string on NT systems -- hopefully
  1065. // they will have answered the above request already, but just in
  1066. // case let's not let them overrun our stack!
  1067. char szVerbAnsi[128];
  1068. hr = pcm->GetCommandString(idCmd, GCS_VERBA, NULL, szVerbAnsi, ARRAYSIZE(szVerbAnsi) / 2);
  1069. if (SUCCEEDED(hr))
  1070. {
  1071. SHAnsiToUnicode(szVerbAnsi, wszVerb, ARRAYSIZE(wszVerb));
  1072. }
  1073. }
  1074. StrCpyNW(pszVerb, wszVerb, cchVerb);
  1075. return hr;
  1076. }
  1077. //
  1078. // Purpose: Deletes the menu item specified by name
  1079. //
  1080. // Parameters: pcm - Context menu interface
  1081. // hpopup - Context menu handle
  1082. // idFirst - Beginning of id range
  1083. // pszCommand - Command to look for
  1084. //
  1085. STDAPI ContextMenu_DeleteCommandByName(IContextMenu *pcm, HMENU hpopup, UINT idFirst, LPCWSTR pszCommand)
  1086. {
  1087. UINT ipos = GetMenuIndexForCanonicalVerb(hpopup, pcm, idFirst, pszCommand);
  1088. if (ipos != -1)
  1089. {
  1090. DeleteMenu(hpopup, ipos, MF_BYPOSITION);
  1091. return S_OK;
  1092. }
  1093. else
  1094. {
  1095. return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
  1096. }
  1097. }
  1098. //
  1099. // Helpers to banish STRRET's into the realm of darkness
  1100. //
  1101. STDAPI DisplayNameOf(IShellFolder *psf, LPCITEMIDLIST pidl, DWORD flags, LPTSTR psz, UINT cch)
  1102. {
  1103. *psz = 0;
  1104. STRRET sr;
  1105. HRESULT hr = psf->GetDisplayNameOf(pidl, flags, &sr);
  1106. if (SUCCEEDED(hr))
  1107. hr = StrRetToBuf(&sr, pidl, psz, cch);
  1108. return hr;
  1109. }
  1110. STDAPI DisplayNameOfAsOLESTR(IShellFolder *psf, LPCITEMIDLIST pidl, DWORD flags, LPWSTR *ppsz)
  1111. {
  1112. *ppsz = NULL;
  1113. STRRET sr;
  1114. HRESULT hr = psf->GetDisplayNameOf(pidl, flags, &sr);
  1115. if (SUCCEEDED(hr))
  1116. hr = StrRetToStrW(&sr, pidl, ppsz);
  1117. return hr;
  1118. }
  1119. // get the target pidl for a folder pidl. this deals with the case where a folder
  1120. // is an alias to a real folder, Folder Shortcuts, etc.
  1121. STDAPI SHGetTargetFolderIDList(LPCITEMIDLIST pidlFolder, LPITEMIDLIST *ppidl)
  1122. {
  1123. *ppidl = NULL;
  1124. // likely should ASSERT() that pidlFolder has SFGAO_FOLDER
  1125. IShellLink *psl;
  1126. HRESULT hr = SHGetUIObjectFromFullPIDL(pidlFolder, NULL, IID_PPV_ARG(IShellLink, &psl));
  1127. if (SUCCEEDED(hr))
  1128. {
  1129. hr = psl->GetIDList(ppidl);
  1130. psl->Release();
  1131. }
  1132. // No its not a folder shortcut. Get the pidl normally.
  1133. if (FAILED(hr))
  1134. hr = SHILClone(pidlFolder, ppidl);
  1135. return hr;
  1136. }
  1137. // get the target folder for a folder pidl. this deals with the case where a folder
  1138. // is an alias to a real folder, Folder Shortcuts, MyDocs, etc.
  1139. STDAPI SHGetTargetFolderPathW(LPCITEMIDLIST pidlFolder, LPWSTR pszPath, UINT cchPath)
  1140. {
  1141. *pszPath = 0;
  1142. LPITEMIDLIST pidlTarget;
  1143. if (SUCCEEDED(SHGetTargetFolderIDList(pidlFolder, &pidlTarget)))
  1144. {
  1145. SHGetPathFromIDListW(pidlTarget, pszPath); // make sure it is a path
  1146. ILFree(pidlTarget);
  1147. }
  1148. return *pszPath ? S_OK : E_FAIL;
  1149. }
  1150. STDAPI SHGetTargetFolderPathA(LPCITEMIDLIST pidlFolder, LPSTR pszPath, UINT cchPath)
  1151. {
  1152. *pszPath = 0;
  1153. WCHAR szPath[MAX_PATH];
  1154. HRESULT hr = SHGetTargetFolderPathW(pidlFolder, szPath, ARRAYSIZE(szPath));
  1155. if (SUCCEEDED(hr))
  1156. SHAnsiToUnicode(pszPath, szPath, cchPath);
  1157. return hr;
  1158. }
  1159. STDAPI SHBuildDisplayMachineName(LPCWSTR pszMachineName, LPCWSTR pszComment, LPWSTR pszDisplayName, DWORD cchDisplayName)
  1160. {
  1161. HRESULT hr = E_FAIL;
  1162. if (pszComment && pszComment[0])
  1163. {
  1164. // encorporate the comment into the display name
  1165. LPCWSTR pszNoSlashes = SkipServerSlashes(pszMachineName);
  1166. int i = wnsprintfW(pszDisplayName, cchDisplayName, L"%s (%s)", pszComment, pszNoSlashes);
  1167. hr = (i < 0) ? E_FAIL : S_OK;
  1168. }
  1169. else
  1170. {
  1171. // Return failure here so netfldr can do smarter things to build a display name
  1172. hr = E_FAIL;
  1173. }
  1174. return hr;
  1175. }
  1176. // create objects from registered under a key value, uses the per user per machine
  1177. // reg services to do this.
  1178. STDAPI CreateFromRegKey(LPCWSTR pszKey, LPCWSTR pszValue, REFIID riid, void **ppv)
  1179. {
  1180. HRESULT hr = E_FAIL;
  1181. WCHAR szCLSID[MAX_PATH];
  1182. DWORD cbSize = sizeof(szCLSID);
  1183. if (SHRegGetUSValueW(pszKey, pszValue, NULL, szCLSID, &cbSize, FALSE, NULL, 0) == ERROR_SUCCESS)
  1184. {
  1185. CLSID clsid;
  1186. if (GUIDFromString(szCLSID, &clsid))
  1187. {
  1188. hr = SHCoCreateInstanceAC(clsid, NULL, CLSCTX_INPROC_SERVER, riid, ppv);
  1189. }
  1190. }
  1191. return hr;
  1192. }
  1193. //
  1194. // SHProcessMessagesUntilEvent:
  1195. //
  1196. // this executes message loop until an event or a timeout occurs
  1197. //
  1198. STDAPI_(DWORD) SHProcessMessagesUntilEventEx(HWND hwnd, HANDLE hEvent, DWORD dwTimeout, DWORD dwWakeMask)
  1199. {
  1200. DWORD dwEndTime = GetTickCount() + dwTimeout;
  1201. LONG lWait = (LONG)dwTimeout;
  1202. DWORD dwReturn;
  1203. if (!hEvent && (dwTimeout == INFINITE))
  1204. {
  1205. ASSERTMSG(FALSE, "SHProcessMessagesUntilEvent: caller passed a NULL hEvent and an INFINITE timeout!!");
  1206. return -1;
  1207. }
  1208. for (;;)
  1209. {
  1210. DWORD dwCount = hEvent ? 1 : 0;
  1211. dwReturn = MsgWaitForMultipleObjects(dwCount, &hEvent, FALSE, lWait, dwWakeMask);
  1212. // were we signalled or did we time out?
  1213. if (dwReturn != (WAIT_OBJECT_0 + dwCount))
  1214. {
  1215. break;
  1216. }
  1217. // we woke up because of messages.
  1218. MSG msg;
  1219. while (PeekMessage(&msg, hwnd, 0, 0, PM_REMOVE))
  1220. {
  1221. ASSERT(msg.message != WM_QUIT);
  1222. TranslateMessage(&msg);
  1223. if (msg.message == WM_SETCURSOR)
  1224. {
  1225. SetCursor(LoadCursor(NULL, IDC_WAIT));
  1226. }
  1227. else
  1228. {
  1229. DispatchMessage(&msg);
  1230. }
  1231. }
  1232. // calculate new timeout value
  1233. if (dwTimeout != INFINITE)
  1234. {
  1235. lWait = (LONG)dwEndTime - GetTickCount();
  1236. }
  1237. }
  1238. return dwReturn;
  1239. }
  1240. // deals with goofyness of IShellFolder::GetAttributesOf() including
  1241. // in/out param issue
  1242. // failures
  1243. // goofy cast for 1 item case
  1244. // masks off results to only return what you asked for
  1245. STDAPI_(DWORD) SHGetAttributes(IShellFolder *psf, LPCITEMIDLIST pidl, DWORD dwAttribs)
  1246. {
  1247. // like SHBindToObject, if psf is NULL, use absolute pidl
  1248. LPCITEMIDLIST pidlChild;
  1249. if (!psf)
  1250. {
  1251. SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlChild);
  1252. }
  1253. else
  1254. {
  1255. psf->AddRef();
  1256. pidlChild = pidl;
  1257. }
  1258. DWORD dw = 0;
  1259. if (psf)
  1260. {
  1261. dw = dwAttribs;
  1262. dw = SUCCEEDED(psf->GetAttributesOf(1, (LPCITEMIDLIST *)&pidlChild, &dw)) ? (dwAttribs & dw) : 0;
  1263. if ((dw & SFGAO_FOLDER) && (dw & SFGAO_CANMONIKER) && !(dw & SFGAO_STORAGEANCESTOR) && (dwAttribs & SFGAO_STORAGEANCESTOR))
  1264. {
  1265. if (OBJCOMPATF_NEEDSSTORAGEANCESTOR & SHGetObjectCompatFlags(psf, NULL))
  1266. {
  1267. // switch SFGAO_CANMONIKER -> SFGAO_STORAGEANCESTOR
  1268. dw |= SFGAO_STORAGEANCESTOR;
  1269. dw &= ~SFGAO_CANMONIKER;
  1270. }
  1271. }
  1272. }
  1273. if (psf)
  1274. {
  1275. psf->Release();
  1276. }
  1277. return dw;
  1278. }
  1279. //===========================================================================
  1280. // IDLARRAY stuff
  1281. //===========================================================================
  1282. STDAPI_(HIDA) HIDA_Create(LPCITEMIDLIST pidlFolder, UINT cidl, LPCITEMIDLIST * apidl)
  1283. {
  1284. UINT offset = sizeof(CIDA) + sizeof(UINT) * cidl;
  1285. UINT cbTotal = offset + ILGetSize(pidlFolder);
  1286. for (UINT i = 0; i<cidl ; i++)
  1287. {
  1288. cbTotal += ILGetSize(apidl[i]);
  1289. }
  1290. HIDA hida = GlobalAlloc(GPTR, cbTotal); // This MUST be GlobalAlloc!!!
  1291. if (hida)
  1292. {
  1293. LPIDA pida = (LPIDA)hida; // no need to lock
  1294. LPCITEMIDLIST pidlNext;
  1295. pida->cidl = cidl;
  1296. for (i = 0, pidlNext = pidlFolder; ; pidlNext = apidl[i++])
  1297. {
  1298. UINT cbSize = ILGetSize(pidlNext);
  1299. pida->aoffset[i] = offset;
  1300. CopyMemory(((LPBYTE)pida) + offset, pidlNext, cbSize);
  1301. offset += cbSize;
  1302. ASSERT(ILGetSize(HIDA_GetPIDLItem(pida,i-1)) == cbSize);
  1303. if (i == cidl)
  1304. break;
  1305. }
  1306. ASSERT(offset == cbTotal);
  1307. }
  1308. return hida;
  1309. }
  1310. STDAPI_(UINT) HIDA_GetCount(HIDA hida)
  1311. {
  1312. UINT count = 0;
  1313. LPIDA pida = (LPIDA)GlobalLock(hida);
  1314. if (pida)
  1315. {
  1316. count = pida->cidl;
  1317. GlobalUnlock(hida);
  1318. }
  1319. return count;
  1320. }
  1321. STDAPI_(UINT) HIDA_GetIDList(HIDA hida, UINT i, LPITEMIDLIST pidlOut, UINT cbMax)
  1322. {
  1323. LPIDA pida = (LPIDA)GlobalLock(hida);
  1324. if (pida)
  1325. {
  1326. LPCITEMIDLIST pidlFolder = HIDA_GetPIDLFolder(pida);
  1327. LPCITEMIDLIST pidlItem = HIDA_GetPIDLItem(pida, i);
  1328. UINT cbFolder = ILGetSize(pidlFolder) - sizeof(USHORT);
  1329. UINT cbItem = ILGetSize(pidlItem);
  1330. if (cbMax < cbFolder+cbItem)
  1331. {
  1332. if (pidlOut)
  1333. pidlOut->mkid.cb = 0;
  1334. }
  1335. else
  1336. {
  1337. MoveMemory(pidlOut, pidlFolder, cbFolder);
  1338. MoveMemory(((LPBYTE)pidlOut) + cbFolder, pidlItem, cbItem);
  1339. }
  1340. GlobalUnlock(hida);
  1341. return cbFolder + cbItem;
  1342. }
  1343. return 0;
  1344. }
  1345. STDAPI_(BOOL) PathIsImage(LPCTSTR pszFile)
  1346. {
  1347. BOOL fPicture = FALSE;
  1348. LPTSTR pszExt = PathFindExtension(pszFile);
  1349. if (pszExt)
  1350. {
  1351. // there's no ASSOCSTR_PERCEIVED so pick it up from the registry.
  1352. TCHAR szPerceivedType[MAX_PATH];
  1353. DWORD cb = ARRAYSIZE(szPerceivedType) * sizeof(TCHAR);
  1354. if (ERROR_SUCCESS == SHGetValue(HKEY_CLASSES_ROOT, pszExt, TEXT("PerceivedType"), NULL, szPerceivedType, &cb))
  1355. {
  1356. fPicture = (StrCmpI(szPerceivedType, TEXT("image")) == 0);
  1357. }
  1358. }
  1359. return fPicture;
  1360. }
  1361. // helper function to create a stream or storage in a storage.
  1362. HRESULT CreateStreamOrStorage(IStorage * pStorageParent, LPCTSTR pszName, REFIID riid, void **ppv)
  1363. {
  1364. DWORD grfModeCreated = STGM_READWRITE;
  1365. HRESULT hr = E_INVALIDARG;
  1366. if (IsEqualGUID(riid, IID_IStorage))
  1367. {
  1368. IStorage * pStorageCreated;
  1369. hr = pStorageParent->CreateStorage(pszName, grfModeCreated, 0, 0, &pStorageCreated);
  1370. if (SUCCEEDED(hr))
  1371. {
  1372. hr = pStorageParent->Commit(STGC_DEFAULT);
  1373. *ppv = pStorageCreated;
  1374. }
  1375. }
  1376. else if (IsEqualGUID(riid, IID_IStream))
  1377. {
  1378. IStream * pStreamCreated;
  1379. hr = pStorageParent->CreateStream(pszName, grfModeCreated, 0, 0, &pStreamCreated);
  1380. if (SUCCEEDED(hr))
  1381. {
  1382. hr = pStorageParent->Commit(STGC_DEFAULT);
  1383. *ppv = pStreamCreated;
  1384. }
  1385. }
  1386. return hr;
  1387. }
  1388. // same as PathMakeUniqueNameEx but it works on storages.
  1389. // Note: LFN only!
  1390. STDAPI StgMakeUniqueNameWithCount(IStorage *pStorageParent, LPCWSTR pszTemplate,
  1391. int iMinLong, REFIID riid, void **ppv)
  1392. {
  1393. HRESULT hr = E_INVALIDARG;
  1394. RIPMSG(pszTemplate && IS_VALID_STRING_PTR(pszTemplate, -1) && lstrlen(pszTemplate)<(MAX_PATH-6), "StgMakeUniqueNameWithCount: invalid pszTemplate");
  1395. if (pszTemplate && lstrlen(pszTemplate)<(MAX_PATH-6)) // -6 for " (999)"
  1396. {
  1397. WCHAR szBuffer[MAX_PATH];
  1398. WCHAR szFormat[MAX_PATH];
  1399. int cchStem;
  1400. // Set up:
  1401. // cchStem : length of pszTemplate we're going to use w/o wsprintf
  1402. // szFormat : format string to wsprintf the number with, catenates on to pszTemplate[0..cchStem]
  1403. // Has template already been uniquified?
  1404. //
  1405. LPWSTR pszRest = StrChr(pszTemplate, L'(');
  1406. while (pszRest)
  1407. {
  1408. // First validate that this is the right one
  1409. LPWSTR pszEndUniq = CharNext(pszRest);
  1410. while (*pszEndUniq && *pszEndUniq >= L'0' && *pszEndUniq <= L'9')
  1411. {
  1412. pszEndUniq++;
  1413. }
  1414. if (*pszEndUniq == L')')
  1415. break; // We have the right one!
  1416. pszRest = StrChr(CharNext(pszRest), L'(');
  1417. }
  1418. if (!pszRest)
  1419. {
  1420. // if no (, then tack it on at the end. (but before the extension)
  1421. // eg. New Link yields New Link (1)
  1422. pszRest = PathFindExtension(pszTemplate);
  1423. cchStem = (int)(pszRest - pszTemplate);
  1424. wnsprintf(szFormat, ARRAYSIZE(szFormat), L" (%%d)%s", pszRest ? pszRest : L"");
  1425. }
  1426. else
  1427. {
  1428. // Template has been uniquified, remove uniquing digits
  1429. // eg. New Link (1) yields New Link (2)
  1430. //
  1431. pszRest++; // step over the (
  1432. cchStem = (int) (pszRest - pszTemplate);
  1433. while (*pszRest && *pszRest >= L'0' && *pszRest <= L'9')
  1434. {
  1435. pszRest++;
  1436. }
  1437. // we are guaranteed enough room because we don't include
  1438. // the stuff before the # in this format
  1439. wnsprintf(szFormat, ARRAYSIZE(szFormat), L"%%d%s", pszRest);
  1440. }
  1441. if (cchStem < ARRAYSIZE(szBuffer))
  1442. {
  1443. // copy the fixed portion into the buffer
  1444. //
  1445. StrCpyN(szBuffer, pszTemplate, cchStem+1);
  1446. // Iterate on the uniquifying szFormat portion until we find a unique name:
  1447. //
  1448. LPTSTR pszDigit = szBuffer + cchStem;
  1449. hr = STG_E_FILEALREADYEXISTS;
  1450. for (int i = iMinLong; (i < 1000) && (STG_E_FILEALREADYEXISTS == hr); i++)
  1451. {
  1452. wnsprintf(pszDigit, ARRAYSIZE(szBuffer) - cchStem, szFormat, i);
  1453. // okay, we have the unique name, so create it in the storage.
  1454. hr = CreateStreamOrStorage(pStorageParent, szBuffer, riid, ppv);
  1455. }
  1456. }
  1457. else
  1458. {
  1459. hr = E_INVALIDARG;
  1460. }
  1461. }
  1462. return hr;
  1463. }
  1464. STDAPI StgMakeUniqueName(IStorage *pStorageParent, LPCTSTR pszFileSpec, REFIID riid, void **ppv)
  1465. {
  1466. HRESULT hr = S_OK;
  1467. TCHAR szTemp[MAX_PATH];
  1468. LPTSTR psz;
  1469. LPTSTR pszNew;
  1470. // try it without the ( if there's a space after it
  1471. psz = StrChr(pszFileSpec, L'(');
  1472. while (psz)
  1473. {
  1474. if (*(CharNext(psz)) == L')')
  1475. break;
  1476. psz = StrChr(CharNext(psz), L'(');
  1477. }
  1478. if (psz)
  1479. {
  1480. // We have the (). See if we have either x () y or x ().y in which case
  1481. // we probably want to get rid of one of the blanks...
  1482. int ichSkip = 2;
  1483. LPTSTR pszT = CharPrev(pszFileSpec, psz);
  1484. if (*pszT == L' ')
  1485. {
  1486. ichSkip = 3;
  1487. psz = pszT;
  1488. }
  1489. StrCpyN(szTemp, pszFileSpec, ARRAYSIZE(szTemp));
  1490. SIZE_T cch = psz - pszFileSpec;
  1491. pszNew = szTemp + cch;
  1492. if (cch < ARRAYSIZE(szTemp))
  1493. {
  1494. StrCpyN(pszNew, psz + ichSkip, ARRAYSIZE(szTemp) - (int)cch);
  1495. }
  1496. else
  1497. {
  1498. hr = E_FAIL;
  1499. }
  1500. }
  1501. else
  1502. {
  1503. // 1taro registers its document with '/'.
  1504. if (psz=StrChr(pszFileSpec, '/'))
  1505. {
  1506. LPTSTR pszT = CharNext(psz);
  1507. pszNew = szTemp;
  1508. StrCpyN(szTemp, pszFileSpec, ARRAYSIZE(szTemp));
  1509. SIZE_T cch = psz - pszFileSpec;
  1510. pszNew = szTemp + cch;
  1511. if (cch < ARRAYSIZE(szTemp))
  1512. {
  1513. StrCpyN(pszNew, pszT, ARRAYSIZE(szTemp) - (int)cch);
  1514. }
  1515. else
  1516. {
  1517. hr = E_FAIL;
  1518. }
  1519. }
  1520. else
  1521. {
  1522. if (lstrlen(pszFileSpec) < ARRAYSIZE(szTemp))
  1523. {
  1524. StrCpyN(szTemp, pszFileSpec, ARRAYSIZE(szTemp));
  1525. }
  1526. else
  1527. {
  1528. hr = E_FAIL;
  1529. }
  1530. }
  1531. }
  1532. if (SUCCEEDED(hr))
  1533. {
  1534. hr = CreateStreamOrStorage(pStorageParent, szTemp, riid, ppv);
  1535. }
  1536. if (FAILED(hr))
  1537. {
  1538. hr = StgMakeUniqueNameWithCount(pStorageParent, pszFileSpec, 2, riid, ppv);
  1539. }
  1540. return hr;
  1541. }
  1542. STDAPI SHInvokeCommandOnPidl(HWND hwnd, IUnknown* punk, LPCITEMIDLIST pidl, UINT uFlags, LPCSTR lpVerb)
  1543. {
  1544. IShellFolder* psf;
  1545. LPCITEMIDLIST pidlChild;
  1546. HRESULT hr = SHBindToFolderIDListParent(NULL, pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlChild);
  1547. if (SUCCEEDED(hr))
  1548. {
  1549. hr = SHInvokeCommandOnPidlArray(hwnd, punk, psf, &pidlChild, 1, uFlags, lpVerb);
  1550. psf->Release();
  1551. }
  1552. return hr;
  1553. }
  1554. STDAPI SHInvokeCommandOnPidlArray(HWND hwnd, IUnknown* punk, IShellFolder* psf, LPCITEMIDLIST *ppidlItem, UINT cItems, UINT uFlags, LPCSTR lpVerb)
  1555. {
  1556. IContextMenu *pcm;
  1557. HRESULT hr = psf->GetUIObjectOf(hwnd, cItems, ppidlItem, IID_X_PPV_ARG(IContextMenu, 0, &pcm));
  1558. if (SUCCEEDED(hr) && pcm)
  1559. {
  1560. hr = SHInvokeCommandOnContextMenu(hwnd, punk, pcm, uFlags, lpVerb);
  1561. pcm->Release();
  1562. }
  1563. return hr;
  1564. }
  1565. STDAPI SHInvokeCommandOnDataObject(HWND hwnd, IUnknown* punk, IDataObject* pdtobj, UINT uFlags, LPCSTR pszVerb)
  1566. {
  1567. HRESULT hr = E_FAIL;
  1568. STGMEDIUM medium;
  1569. LPIDA pida = DataObj_GetHIDA(pdtobj, &medium);
  1570. if (pida)
  1571. {
  1572. IShellFolder *psf;
  1573. LPCITEMIDLIST pidlParent = IDA_GetIDListPtr(pida, (UINT)-1);
  1574. if (SUCCEEDED(SHBindToObject(NULL, IID_X_PPV_ARG(IShellFolder, pidlParent, &psf))))
  1575. {
  1576. LPCITEMIDLIST *ppidl = (LPCITEMIDLIST *)LocalAlloc(LPTR, pida->cidl * sizeof(LPCITEMIDLIST));
  1577. if (ppidl)
  1578. {
  1579. for (UINT i = 0; i < pida->cidl; i++)
  1580. {
  1581. ppidl[i] = IDA_GetIDListPtr(pida, i);
  1582. }
  1583. hr = SHInvokeCommandOnPidlArray(hwnd, punk, psf, ppidl, pida->cidl, uFlags, pszVerb);
  1584. LocalFree(ppidl);
  1585. }
  1586. psf->Release();
  1587. }
  1588. HIDA_ReleaseStgMedium(pida, &medium);
  1589. }
  1590. return hr;
  1591. }
  1592. STDAPI_(LPCITEMIDLIST) IDA_GetIDListPtr(LPIDA pida, UINT i)
  1593. {
  1594. LPCITEMIDLIST pidl = NULL;
  1595. if (pida && ((i == (UINT)-1) || i < pida->cidl))
  1596. {
  1597. pidl = HIDA_GetPIDLItem(pida, i);
  1598. }
  1599. return pidl;
  1600. }
  1601. STDAPI IUnknown_DragEnter(IUnknown* punk, IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  1602. {
  1603. HRESULT hr = E_FAIL;
  1604. if (punk)
  1605. {
  1606. IDropTarget* pdt;
  1607. hr = punk->QueryInterface(IID_PPV_ARG(IDropTarget, &pdt));
  1608. if (SUCCEEDED(hr))
  1609. {
  1610. hr = pdt->DragEnter(pdtobj, grfKeyState, pt, pdwEffect);
  1611. pdt->Release();
  1612. }
  1613. }
  1614. if (FAILED(hr))
  1615. *pdwEffect = DROPEFFECT_NONE;
  1616. return hr;
  1617. }
  1618. STDAPI IUnknown_DragOver(IUnknown* punk, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  1619. {
  1620. HRESULT hr = E_FAIL;
  1621. if (punk)
  1622. {
  1623. IDropTarget* pdt;
  1624. hr = punk->QueryInterface(IID_PPV_ARG(IDropTarget, &pdt));
  1625. if (SUCCEEDED(hr))
  1626. {
  1627. hr = pdt->DragOver(grfKeyState, pt, pdwEffect);
  1628. pdt->Release();
  1629. }
  1630. }
  1631. if (FAILED(hr))
  1632. *pdwEffect = DROPEFFECT_NONE;
  1633. return hr;
  1634. }
  1635. STDAPI IUnknown_DragLeave(IUnknown* punk)
  1636. {
  1637. HRESULT hr = E_FAIL;
  1638. if (punk)
  1639. {
  1640. IDropTarget* pdt;
  1641. hr = punk->QueryInterface(IID_PPV_ARG(IDropTarget, &pdt));
  1642. if (SUCCEEDED(hr))
  1643. {
  1644. hr = pdt->DragLeave();
  1645. pdt->Release();
  1646. }
  1647. }
  1648. return hr;
  1649. }
  1650. STDAPI IUnknown_Drop(IUnknown* punk, IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  1651. {
  1652. HRESULT hr = E_FAIL;
  1653. if (punk)
  1654. {
  1655. IDropTarget* pdt;
  1656. hr = punk->QueryInterface(IID_PPV_ARG(IDropTarget, &pdt));
  1657. if (SUCCEEDED(hr))
  1658. {
  1659. hr = pdt->Drop(pdtobj, grfKeyState, pt, pdwEffect);
  1660. pdt->Release();
  1661. }
  1662. }
  1663. if (FAILED(hr))
  1664. *pdwEffect = DROPEFFECT_NONE;
  1665. return hr;
  1666. }
  1667. STDAPI_(BOOL) ShouldNavigateInIE(LPCWSTR pszUrl)
  1668. {
  1669. // Default to navigating in IE. The idea here is that this
  1670. // changes the existing behavior the least.
  1671. BOOL fResult = TRUE;
  1672. // first, crack the URL
  1673. WCHAR szScheme[INTERNET_MAX_SCHEME_LENGTH];
  1674. DWORD cchScheme = ARRAYSIZE(szScheme);
  1675. if (SUCCEEDED(UrlGetPartW(pszUrl, szScheme, &cchScheme, URL_PART_SCHEME, 0)))
  1676. {
  1677. // if it is an http:, https:, file:, or ftp: URL then look up the association
  1678. // all other pluggable protocols go to IE
  1679. if ((0 == StrCmpIW(szScheme, L"http")) ||
  1680. (0 == StrCmpIW(szScheme, L"ftp")) ||
  1681. (0 == StrCmpIW(szScheme, L"file")) ||
  1682. (0 == StrCmpIW(szScheme, L"https")))
  1683. {
  1684. WCHAR szExecutable[MAX_PATH * 2];
  1685. DWORD cchExecutable = ARRAYSIZE(szExecutable);
  1686. WCHAR szFile[MAX_PATH];
  1687. LPCWSTR pszQuery = szScheme;
  1688. if (0 == StrCmpIW(szScheme, L"file"))
  1689. {
  1690. DWORD cchFile = ARRAYSIZE(szFile);
  1691. if (SUCCEEDED(PathCreateFromUrl(pszUrl, szFile, &cchFile, 0)))
  1692. {
  1693. pszQuery = PathFindExtension(szFile);
  1694. }
  1695. }
  1696. if (SUCCEEDED(AssocQueryStringW(ASSOCF_VERIFY, ASSOCSTR_EXECUTABLE, pszQuery, NULL, szExecutable, &cchExecutable)))
  1697. {
  1698. if (!StrStrIW(szExecutable, L"iexplore"))
  1699. {
  1700. // IE isn't the default for the verb so we'll ShellExecute it.
  1701. fResult = FALSE;
  1702. }
  1703. }
  1704. }
  1705. }
  1706. return fResult;
  1707. }
  1708. STDAPI_(BOOL) IsDesktopFrame(IUnknown *punk)
  1709. {
  1710. IUnknown *punkDesktop;
  1711. HRESULT hr = IUnknown_QueryService(punk, SID_SShellDesktop, SID_SShellDesktop, (void **)&punkDesktop);
  1712. BOOL fResult;
  1713. if (SUCCEEDED(hr))
  1714. {
  1715. punkDesktop->Release();
  1716. fResult = TRUE;
  1717. }
  1718. else
  1719. {
  1720. fResult = FALSE;
  1721. }
  1722. return fResult;
  1723. }