Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1531 lines
45 KiB

  1. /*
  2. NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE
  3. This file is #include'd in browseui\ and shdocvw\ util.cpp. these are too small
  4. to add an extra dependency, so they're just shared. ideally, these should move
  5. to shlwapi or comctl32 or some lib or ...
  6. NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE
  7. */
  8. #include "ccstock2.h"
  9. #include "mluisupp.h"
  10. #include "richedit.h" //for charformat2
  11. STDAPI_(BOOL) IsBrowseNewProcess()
  12. {
  13. return SHRegGetBoolUSValue(REGSTR_PATH_EXPLORER TEXT("\\BrowseNewProcess"), TEXT("BrowseNewProcess"), FALSE, FALSE);
  14. }
  15. // Should we run browser in a new process?
  16. STDAPI_(BOOL) IsBrowseNewProcessAndExplorer()
  17. {
  18. if (GetModuleHandle(TEXT("EXPLORER.EXE")))
  19. return IsBrowseNewProcess();
  20. return FALSE; // Not in shell process so ignore browse new process flag
  21. }
  22. HRESULT _NavigateFrame(IUnknown *punkFrame, LPCTSTR pszPath, BOOL fIsInternetShortcut)
  23. {
  24. HRESULT hr = E_OUTOFMEMORY;
  25. BSTR bstr = SysAllocStringT(pszPath);
  26. if (bstr)
  27. {
  28. if (fIsInternetShortcut)
  29. {
  30. IOleCommandTarget *pcmdt;
  31. hr = IUnknown_QueryService(punkFrame, SID_SHlinkFrame, IID_PPV_ARG(IOleCommandTarget, &pcmdt));
  32. if (SUCCEEDED(hr))
  33. {
  34. VARIANT varShortCutPath = {0};
  35. VARIANT varFlag = {0};
  36. varFlag.vt = VT_BOOL;
  37. varFlag.boolVal = VARIANT_TRUE;
  38. varShortCutPath.vt = VT_BSTR;
  39. varShortCutPath.bstrVal = bstr;
  40. hr = pcmdt->Exec(&CGID_Explorer, SBCMDID_IESHORTCUT, 0, &varShortCutPath, &varFlag);
  41. pcmdt->Release();
  42. }
  43. }
  44. else
  45. {
  46. IWebBrowser2 *pwb;
  47. hr = IUnknown_QueryService(punkFrame, SID_SHlinkFrame, IID_PPV_ARG(IWebBrowser2, &pwb));
  48. if (SUCCEEDED(hr))
  49. {
  50. hr = pwb->Navigate(bstr, PVAREMPTY, PVAREMPTY, PVAREMPTY, PVAREMPTY);
  51. hr = pwb->put_Visible(VARIANT_TRUE);
  52. pwb->Release();
  53. }
  54. }
  55. SysFreeString(bstr);
  56. }
  57. return hr;
  58. }
  59. //
  60. // Take a path or an URL and create a shorcut to navigare to it
  61. //
  62. STDAPI IENavigateIEProcess(LPCTSTR pszPath, BOOL fIsInternetShortcut)
  63. {
  64. IUnknown *punk;
  65. HRESULT hr = CoCreateInstance(CLSID_InternetExplorer, NULL, CLSCTX_LOCAL_SERVER, IID_PPV_ARG(IUnknown, &punk));
  66. if (SUCCEEDED(hr))
  67. {
  68. hr = _NavigateFrame(punk, pszPath, fIsInternetShortcut);
  69. punk->Release();
  70. }
  71. return hr;
  72. }
  73. // If this is an internet shortcut (.url file), we want it to
  74. // navigate using using the file name so the frame frame
  75. // can read data beyond out of that file. this includes frame set
  76. // navigation and data that script on the page may have stored.
  77. /*
  78. Purpose : This function takes a path to a file. if that file is a .URL we try
  79. to navigate with that file name. this is because .URL files have extra data stored
  80. in them that we want to let script on the page get to. the exec we send here
  81. lets the frame know the .URL file that this came from
  82. Parameters : file name of .URL file (maybe) : In param
  83. pUnk : Pointer to Object from which you can get the IOleCommandTarget
  84. returns:
  85. TRUE handled
  86. FALSE not handled, file might not be a .URL
  87. */
  88. STDAPI NavFrameWithFile(LPCTSTR pszPath, IUnknown *punk)
  89. {
  90. HRESULT hr = E_FAIL;
  91. LPTSTR pszExt = PathFindExtension(pszPath);
  92. // HACK: we hard code .URL. this should be a property of the file type
  93. if (0 == StrCmpI(pszExt, TEXT(".url")))
  94. {
  95. #ifdef BROWSENEWPROCESS_STRICT // "Nav in new process" has become "Launch in new process", so this is no longer needed
  96. if (IsBrowseNewProcessAndExplorer())
  97. hr = IENavigateIEProcess(pszPath, TRUE);
  98. else
  99. #endif
  100. hr = _NavigateFrame(punk, pszPath, TRUE);
  101. }
  102. return hr;
  103. }
  104. // get the win32 file system name (path) for the item
  105. // and optional attributes
  106. //
  107. // pdwAttrib may be NULL
  108. // in/out:
  109. // pdwAttrib may be NULL, attributes to query on the item
  110. STDAPI GetPathForItem(IShellFolder *psf, LPCITEMIDLIST pidl, LPTSTR pszPath, DWORD *pdwAttrib)
  111. {
  112. HRESULT hres = E_FAIL;
  113. DWORD dwAttrib;
  114. if (pdwAttrib == NULL)
  115. {
  116. pdwAttrib = &dwAttrib;
  117. dwAttrib = SFGAO_FILESYSTEM;
  118. }
  119. else
  120. *pdwAttrib |= SFGAO_FILESYSTEM;
  121. if (SUCCEEDED(psf->GetAttributesOf(1, &pidl, pdwAttrib)) &&
  122. (*pdwAttrib & SFGAO_FILESYSTEM))
  123. {
  124. STRRET str;
  125. hres = psf->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &str);
  126. if (SUCCEEDED(hres))
  127. StrRetToBuf(&str, pidl, pszPath, MAX_PATH);
  128. }
  129. return hres;
  130. }
  131. STDAPI EditBox_TranslateAcceleratorST(LPMSG lpmsg)
  132. {
  133. switch (lpmsg->message) {
  134. case WM_KEYUP: // eat these (if we process corresponding WM_KEYDOWN)
  135. case WM_KEYDOWN: // process these
  136. if (lpmsg->wParam != VK_TAB)
  137. {
  138. // all keydown messages except for the tab key should go straight to
  139. // the edit control -- unless the Ctrl key is down, in which case there
  140. // are 9 messages that should go straight to the edit control
  141. #ifdef DEBUG
  142. if (lpmsg->wParam == VK_CONTROL)
  143. return S_FALSE;
  144. #endif
  145. if (GetKeyState(VK_CONTROL) & 0x80000000)
  146. {
  147. switch (lpmsg->wParam)
  148. {
  149. case VK_RIGHT:
  150. case VK_LEFT:
  151. case VK_UP:
  152. case VK_DOWN:
  153. case VK_HOME:
  154. case VK_END:
  155. case VK_F4:
  156. case VK_INSERT:
  157. case VK_DELETE:
  158. case 'C':
  159. case 'X':
  160. case 'V':
  161. case 'A':
  162. case 'Z':
  163. // these Ctrl+key messages are used by the edit control
  164. // send 'em straight there
  165. break;
  166. default:
  167. return(S_FALSE);
  168. }
  169. }
  170. else
  171. {
  172. switch(lpmsg->wParam)
  173. {
  174. case VK_F5: // for refresh
  175. case VK_F6: // for cycle focus
  176. return(S_FALSE);
  177. }
  178. }
  179. // Note that we return S_OK.
  180. goto TranslateDispatch;
  181. }
  182. break;
  183. case WM_CHAR:
  184. TranslateDispatch:
  185. TranslateMessage(lpmsg);
  186. DispatchMessage(lpmsg);
  187. return(S_OK);
  188. }
  189. return S_FALSE;
  190. }
  191. // NOTE: dupe with shell32 util.cpp function
  192. // like OLE GetClassFile(), but it only works on ProgID\CLSID type registration
  193. // not real doc files or pattern matched files
  194. //
  195. STDAPI _CLSIDFromExtension(LPCTSTR pszExt, CLSID *pclsid)
  196. {
  197. TCHAR szProgID[80];
  198. DWORD cb = SIZEOF(szProgID);
  199. if (SHGetValue(HKEY_CLASSES_ROOT, pszExt, NULL, NULL, szProgID, &cb) == ERROR_SUCCESS)
  200. {
  201. TCHAR szCLSID[80];
  202. StrCatBuff(szProgID, TEXT("\\CLSID"), ARRAYSIZE(szProgID));
  203. cb = SIZEOF(szCLSID);
  204. if (SHGetValue(HKEY_CLASSES_ROOT, szProgID, NULL, NULL, szCLSID, &cb) == ERROR_SUCCESS)
  205. {
  206. return GUIDFromString(szCLSID, pclsid) ? S_OK : E_FAIL;
  207. }
  208. }
  209. return E_FAIL;
  210. }
  211. #if 0 // not used yet
  212. // IShellLink is #defined to IShellLinkA or IShellLinkW depending on compile flags,
  213. // bug Win95 did not support IShellLinkW. So call this function instead and you
  214. // get the correct results regardless of what platform you are running on.
  215. // REVIEW: In fact, we probably want these for ALL IShellLink functions...
  216. //
  217. LWSTDAPI IShellLink_GetPathA(IUnknown *punk, LPSTR pszBuf, UINT cchBuf, DWORD dwFlags)
  218. {
  219. HRESULT hres = E_INVALIDARG;
  220. RIPMSG(cchBuf && pszBuf && IS_VALID_WRITE_BUFFER(pszBuf, char, cchBuf), "IShellLink_GetPathA: callre passed bad pszBuf/cchBuf");
  221. DEBUGWhackPathBufferA(pszBuf, cchBuf);
  222. if (cchBuf && pszBuf)
  223. {
  224. // In case of gross failure, NULL output buffer
  225. *pszBuf = 0;
  226. IShellLinkA * pslA;
  227. hres = punk->QueryInterface(IID_IShellLinkA, (void**)&pslA);
  228. if (SUCCEEDED(hres))
  229. {
  230. hres = pslA->GetPath(pszBuf, cchBuf, NULL, dwFlags);
  231. pslA->Release();
  232. }
  233. else if (FAILED(hres))
  234. {
  235. #ifdef UNICODE
  236. IShellLinkW *pslW;
  237. hres = punk->QueryInterface(IID_IShellLinkW, (void**)&pslW);
  238. if (SUCCEEDED(hres))
  239. {
  240. WCHAR wszPath[MAX_BUF];
  241. LPWSTR pwszBuf = wszPath;
  242. UINT cch = ARRAYSIZE(wszPath);
  243. // Our stack buffer is too small, allocate one of the output buffer size
  244. if (cchBuf > cch)
  245. {
  246. LPWSTR pwsz = LocalAlloc(LPTR, cchBuf * sizeof(WCHAR));
  247. if (pwsz)
  248. {
  249. pwszBuf = pwsz;
  250. cch = cchBuf;
  251. }
  252. }
  253. hres = pslW->GetPath(pwszBuf, cch, NULL, dwFlags);
  254. if (SUCCEEDED(hres))
  255. {
  256. SHUnicodeToAnsi(pwszBuf, pszBuf, cchBuf);
  257. }
  258. pslW->Release();
  259. }
  260. #endif
  261. }
  262. }
  263. return hres;
  264. }
  265. LWSTDAPI IShellLink_GetPathW(IUnknown *punk, LPWSTR pwszBuf, UINT cchBuf, DWORD dwFlags)
  266. {
  267. HRESULT hres = E_INVALIDARG;
  268. RIPMSG(cchBuf && pwszBuf && IS_VALID_WRITE_BUFFER(pwszBuf, WCHAR, cchBuf), "IShellLink_GetPathW: caller passed bad pwszBuf/cchBuf");
  269. DEBUGWhackPathBufferW(pwszBuf, cchBuf);
  270. if (cchBuf && pwszBuf)
  271. {
  272. // In case of gross failure, NULL output buffer
  273. *pwszBuf = 0;
  274. #ifdef UNICODE
  275. IShellLinkW * pslW;
  276. hres = punk->QueryInterface(IID_IShellLinkW, (void**)&pslW);
  277. if (SUCCEEDED(hres))
  278. {
  279. hres = pslW->GetPath(pszBuf, cchBuf, NULL, dwFlags);
  280. pslW->Release();
  281. }
  282. else if (FAILED(hres))
  283. #endif
  284. {
  285. IShellLinkA *pslA;
  286. hres = punk->QueryInterface(IID_IShellLinkA, (void**)&pslA);
  287. if (SUCCEEDED(hres))
  288. {
  289. char szPath[MAX_BUF];
  290. LPSTR pszBuf = szPath;
  291. UINT cch = ARRAYSIZE(szPath);
  292. // Our stack buffer is too small, allocate one of the output buffer size
  293. if (cchBuf > cch)
  294. {
  295. LPSTR psz = LocalAlloc(LPTR, cchBuf * sizeof(char));
  296. if (psz)
  297. {
  298. pszBuf = psz;
  299. cch = cchBuf;
  300. }
  301. }
  302. hres = pslA->GetPath(pszBuf, cch, NULL, dwFlags);
  303. if (SUCCEEDED(hres))
  304. {
  305. SHAnsiToUnicode(pszBuf, pwszBuf, cchBuf);
  306. }
  307. pslA->Release();
  308. }
  309. }
  310. }
  311. return hres;
  312. }
  313. #endif // 0
  314. HRESULT IShellLinkAorW_GetPath(IShellLinkA *pslA, LPTSTR pszBuf, UINT cchBuf, DWORD dwFlags)
  315. {
  316. HRESULT hres = E_FAIL;
  317. // If we store the string unicode, we could be losing file information by asking
  318. // through A version. Be unicode friendly and use the W version if it exists
  319. //
  320. #ifdef UNICODE
  321. IShellLinkW *pslW;
  322. hres = pslA->QueryInterface(IID_PPV_ARG(IShellLinkW, &pslW));
  323. if (SUCCEEDED(hres))
  324. {
  325. hres = pslW->GetPath(pszBuf, cchBuf, NULL, dwFlags);
  326. pslW->Release();
  327. }
  328. #endif
  329. if (FAILED(hres))
  330. {
  331. char szBuf[MAX_URL_STRING]; // BOGUS, but this is a common size used, perhaps we should LocalAlloc...
  332. cchBuf = ARRAYSIZE(szBuf);
  333. hres = pslA->GetPath(szBuf, cchBuf, NULL, dwFlags);
  334. SHAnsiToTChar(szBuf, pszBuf, cchBuf);
  335. }
  336. return hres;
  337. }
  338. STDAPI GetLinkTargetIDList(LPCTSTR pszPath, LPTSTR pszTarget, DWORD cchTarget, LPITEMIDLIST *ppidl)
  339. {
  340. IShellLinkA *psl;
  341. CLSID clsid;
  342. HRESULT hres;
  343. *ppidl = NULL; // assume failure
  344. // WARNING: we really should call GetClassFile() but this could
  345. // slow this down a lot... so chicken out and just look in the registry
  346. if (FAILED(_CLSIDFromExtension(PathFindExtension(pszPath), &clsid)))
  347. clsid = CLSID_ShellLink; // assume it's a shell link
  348. hres = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellLinkA, &psl));
  349. if (SUCCEEDED(hres))
  350. {
  351. IPersistFile *ppf;
  352. hres = psl->QueryInterface(IID_PPV_ARG(IPersistFile, &ppf));
  353. if (SUCCEEDED(hres))
  354. {
  355. WCHAR wszPath[MAX_PATH];
  356. SHTCharToUnicode(pszPath, wszPath, ARRAYSIZE(wszPath));
  357. hres = ppf->Load(wszPath, 0);
  358. if (SUCCEEDED(hres))
  359. {
  360. psl->GetIDList(ppidl);
  361. if (*ppidl == NULL)
  362. hres = E_FAIL; // NULL pidl is valid, but
  363. // lets not return that to clients
  364. if (pszTarget)
  365. {
  366. IShellLinkAorW_GetPath(psl, pszTarget, cchTarget, 0);
  367. }
  368. }
  369. ppf->Release();
  370. }
  371. psl->Release();
  372. }
  373. // pszPath might == pszTarget so don't null out on entry always
  374. if (FAILED(hres) && pszTarget)
  375. *pszTarget = 0;
  376. return hres;
  377. }
  378. STDAPI_(void) PathToDisplayNameW(LPCTSTR pszPath, LPTSTR pszDisplayName, UINT cchDisplayName)
  379. {
  380. SHFILEINFO sfi;
  381. if (SHGetFileInfo(pszPath, 0, &sfi, SIZEOF(sfi), SHGFI_DISPLAYNAME))
  382. {
  383. StrCpyN(pszDisplayName, sfi.szDisplayName, cchDisplayName);
  384. }
  385. else
  386. {
  387. StrCpyN(pszDisplayName, PathFindFileName(pszPath), cchDisplayName);
  388. PathRemoveExtension(pszDisplayName);
  389. }
  390. }
  391. STDAPI_(void) PathToDisplayNameA(LPSTR pszPathA, LPSTR pszDisplayNameA, int cchDisplayName)
  392. {
  393. SHFILEINFOA sfi;
  394. if (SHGetFileInfoA(pszPathA, 0, &sfi, SIZEOF(sfi), SHGFI_DISPLAYNAME))
  395. {
  396. StrCpyNA(pszDisplayNameA, sfi.szDisplayName, cchDisplayName);
  397. }
  398. else
  399. {
  400. pszPathA = PathFindFileNameA(pszPathA);
  401. StrCpyNA(pszDisplayNameA, pszPathA, cchDisplayName);
  402. PathRemoveExtensionA(pszDisplayNameA);
  403. }
  404. }
  405. void* DataObj_GetDataOfType(IDataObject* pdtobj, UINT cfType, STGMEDIUM *pstg)
  406. {
  407. void * pret = NULL;
  408. FORMATETC fmte = {(CLIPFORMAT)cfType, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  409. if (pdtobj->GetData(&fmte, pstg) == S_OK)
  410. {
  411. pret = GlobalLock(pstg->hGlobal);
  412. if (!pret)
  413. ReleaseStgMedium(pstg);
  414. }
  415. return pret;
  416. }
  417. void ReleaseStgMediumHGLOBAL(STGMEDIUM *pstg)
  418. {
  419. ASSERT(pstg->tymed == TYMED_HGLOBAL);
  420. GlobalUnlock(pstg->hGlobal);
  421. ReleaseStgMedium(pstg);
  422. }
  423. // this looks for the file descriptor format to get the display name of a data object
  424. STDAPI DataObj_GetNameFromFileDescriptor(IDataObject *pdtobj, LPWSTR pszDisplayName, UINT cch)
  425. {
  426. HRESULT hres = E_FAIL;
  427. STGMEDIUM mediumFGD;
  428. InitClipboardFormats();
  429. FILEGROUPDESCRIPTORW * pfgd = (FILEGROUPDESCRIPTORW *)DataObj_GetDataOfType(pdtobj, g_cfFileDescW, &mediumFGD);
  430. if (pfgd)
  431. {
  432. if (pfgd->cItems > 0)
  433. {
  434. LPFILEDESCRIPTORW pfd = &(pfgd->fgd[0]);
  435. SHUnicodeToTChar(pfd->cFileName, pszDisplayName, cch);
  436. hres = S_OK;
  437. }
  438. ReleaseStgMediumHGLOBAL(&mediumFGD);
  439. }
  440. else
  441. {
  442. FILEGROUPDESCRIPTORA * pfgd = (FILEGROUPDESCRIPTORA *)DataObj_GetDataOfType(pdtobj, g_cfFileDescA, &mediumFGD);
  443. if (pfgd)
  444. {
  445. if (pfgd->cItems > 0)
  446. {
  447. LPFILEDESCRIPTORA pfd = &(pfgd->fgd[0]);
  448. SHAnsiToTChar(pfd->cFileName, pszDisplayName, cch);
  449. hres = S_OK;
  450. }
  451. ReleaseStgMediumHGLOBAL(&mediumFGD);
  452. }
  453. }
  454. return hres;
  455. }
  456. STDAPI SHPidlFromDataObject2(IDataObject *pdtobj, LPITEMIDLIST * ppidl)
  457. {
  458. HRESULT hres = E_FAIL;
  459. STGMEDIUM medium;
  460. InitClipboardFormats();
  461. void *pdata = DataObj_GetDataOfType(pdtobj, g_cfHIDA, &medium);
  462. if (pdata)
  463. {
  464. *ppidl = IDA_ILClone((LPIDA)pdata, 0);
  465. if (*ppidl)
  466. hres = S_OK;
  467. else
  468. hres = E_OUTOFMEMORY;
  469. ReleaseStgMediumHGLOBAL(&medium);
  470. }
  471. return hres;
  472. }
  473. STDAPI SHPidlFromDataObject(IDataObject *pdtobj, LPITEMIDLIST *ppidl,
  474. LPWSTR pszDisplayNameW, DWORD cchDisplayName)
  475. {
  476. FORMATETC fmte = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  477. STGMEDIUM medium;
  478. *ppidl = NULL;
  479. HRESULT hres = pdtobj->GetData(&fmte, &medium);
  480. if (hres == S_OK)
  481. {
  482. // This string is also used to store an URL in case it's an URL file
  483. TCHAR szPath[MAX_URL_STRING];
  484. hres = E_FAIL;
  485. if (DragQueryFile((HDROP)medium.hGlobal, 0, szPath, ARRAYSIZE(szPath)))
  486. {
  487. SHFILEINFO sfi;
  488. SHGetFileInfo(szPath, 0, &sfi, SIZEOF(sfi), SHGFI_ATTRIBUTES | SHGFI_DISPLAYNAME);
  489. if (pszDisplayNameW)
  490. SHTCharToUnicode(sfi.szDisplayName, pszDisplayNameW, MAX_PATH);
  491. if (sfi.dwAttributes & SFGAO_LINK)
  492. hres = GetLinkTargetIDList(szPath, szPath, ARRAYSIZE(szPath), ppidl);
  493. if (FAILED(hres))
  494. hres = IECreateFromPath(szPath, ppidl);
  495. }
  496. ReleaseStgMedium(&medium);
  497. }
  498. else
  499. {
  500. hres = SHPidlFromDataObject2(pdtobj, ppidl);
  501. if (FAILED(hres))
  502. {
  503. void *pdata = DataObj_GetDataOfType(pdtobj, g_cfURL, &medium);
  504. if (pdata)
  505. {
  506. LPSTR pszPath = (LPSTR)pdata;
  507. if (pszDisplayNameW)
  508. {
  509. if (FAILED(DataObj_GetNameFromFileDescriptor(pdtobj, pszDisplayNameW, cchDisplayName)))
  510. {
  511. CHAR szDisplayNameA[MAX_URL_STRING];
  512. ASSERT(cchDisplayName < MAX_URL_STRING);
  513. SHUnicodeToAnsi(pszDisplayNameW, szDisplayNameA, cchDisplayName);
  514. PathToDisplayNameA(pszPath, szDisplayNameA, cchDisplayName);
  515. }
  516. }
  517. hres = IECreateFromPathA(pszPath, ppidl);
  518. ReleaseStgMediumHGLOBAL(&medium);
  519. }
  520. }
  521. }
  522. return hres;
  523. }
  524. // BharatS - Perhaps all the stuff below here should be moved to shlwapi after beta 2 ?
  525. typedef struct _broadcastmsgparams
  526. {
  527. BOOL fSendMessage; // If true - we call SendMessageTimeout
  528. UINT uTimeout; // Only Matters if fSendMessage is set
  529. UINT uMsg;
  530. WPARAM wParam;
  531. LPARAM lParam;
  532. } BROADCAST_MSG_PARAMS;
  533. BOOL CALLBACK EnumShellIEWindowsProc(
  534. HWND hwnd, // handle to parent window
  535. LPARAM lParam // application-defined value - this has the info needed for posting/sending the message
  536. )
  537. {
  538. BROADCAST_MSG_PARAMS *pParams = (BROADCAST_MSG_PARAMS *)lParam;
  539. BOOL fRet = TRUE;
  540. if(IsExplorerWindow(hwnd) || IsFolderWindow(hwnd))
  541. {
  542. if(pParams->fSendMessage)
  543. {
  544. UINT uTimeout = (pParams->uTimeout < 4000) ? pParams->uTimeout : 4000;
  545. LRESULT lResult;
  546. DWORD_PTR dwpResult;
  547. if (g_fRunningOnNT)
  548. {
  549. lResult = SendMessageTimeout(hwnd, pParams->uMsg, pParams->wParam, pParams->lParam, SMTO_ABORTIFHUNG | SMTO_NORMAL, uTimeout, &dwpResult);
  550. }
  551. else
  552. {
  553. lResult = SendMessageTimeoutA(hwnd, pParams->uMsg, pParams->wParam, pParams->lParam, SMTO_ABORTIFHUNG | SMTO_NORMAL, uTimeout, &dwpResult);
  554. }
  555. fRet = BOOLIFY(lResult);
  556. }
  557. else
  558. {
  559. fRet = PostMessage(hwnd, pParams->uMsg, pParams->wParam, pParams->lParam);
  560. }
  561. }
  562. return fRet;
  563. }
  564. // PostShellIEBroadcastMessage is commented out since it is not used currentl
  565. /*
  566. STDAPI_(LRESULT) PostShellIEBroadcastMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
  567. {
  568. BROADCAST_MSG_PARAMS MsgParam;
  569. MsgParam.uMsg = uMsg;
  570. MsgParam.wParam = wParam;
  571. MsgParam.lParam = lParam;
  572. MsgParam.fSendMessage = FALSE;
  573. return EnumWindows(EnumShellIEWindowsProc, (LPARAM)&MsgParam);
  574. }
  575. */
  576. //
  577. // We can be hung if we use sendMessage, and you can not use pointers with asynchronous
  578. // calls such as PostMessage or SendNotifyMessage. So we resort to using a timeout.
  579. // This function should be used to broadcast notification messages, such as WM_SETTINGCHANGE,
  580. // that pass pointers. (stevepro)
  581. //
  582. STDAPI_(LRESULT) SendShellIEBroadcastMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, UINT uTimeout)
  583. {
  584. // Note that each this timeout is applied to each window that we broadcast to
  585. BROADCAST_MSG_PARAMS MsgParam;
  586. MsgParam.uMsg = uMsg;
  587. MsgParam.wParam = wParam;
  588. #ifdef UNICODE
  589. CHAR szSection[MAX_PATH];
  590. if (!g_fRunningOnNT && (uMsg == WM_WININICHANGE) && (0 != lParam))
  591. {
  592. SHUnicodeToAnsi((LPCWSTR)lParam, szSection, ARRAYSIZE(szSection));
  593. lParam = (LPARAM)szSection;
  594. }
  595. #endif
  596. MsgParam.lParam = lParam;
  597. MsgParam.fSendMessage = TRUE;
  598. MsgParam.uTimeout = uTimeout;
  599. return EnumWindows(EnumShellIEWindowsProc, (LPARAM)&MsgParam);
  600. }
  601. // Return the parent psf and relative pidl given a pidl.
  602. STDAPI IEBindToParentFolder(LPCITEMIDLIST pidl, IShellFolder** ppsfParent, LPCITEMIDLIST *ppidlChild)
  603. {
  604. HRESULT hres;
  605. //
  606. // if this is a rooted pidl and it is just the root
  607. // then we can bind to the target pidl of the root instead
  608. //
  609. if (ILIsRooted(pidl) && ILIsEmpty(_ILNext(pidl)))
  610. pidl = ILRootedFindIDList(pidl);
  611. LPITEMIDLIST pidlParent = ILCloneParent(pidl);
  612. if (pidlParent)
  613. {
  614. hres = IEBindToObject(pidlParent, ppsfParent);
  615. ILFree(pidlParent);
  616. }
  617. else
  618. hres = E_OUTOFMEMORY;
  619. if (ppidlChild)
  620. *ppidlChild = ILFindLastID(pidl);
  621. return hres;
  622. }
  623. STDAPI GetDataObjectForPidl(LPCITEMIDLIST pidl, IDataObject ** ppdtobj)
  624. {
  625. HRESULT hres = E_FAIL;
  626. if (pidl)
  627. {
  628. IShellFolder *psfParent;
  629. LPCITEMIDLIST pidlChild;
  630. hres = IEBindToParentFolder(pidl, &psfParent, &pidlChild);
  631. if (SUCCEEDED(hres))
  632. {
  633. hres = psfParent->GetUIObjectOf(NULL, 1, &pidlChild, IID_PPV_ARG_NULL(IDataObject, ppdtobj));
  634. psfParent->Release();
  635. }
  636. }
  637. return hres;
  638. }
  639. // Is this pidl a Folder/Directory in the File System?
  640. STDAPI_(BOOL) ILIsFileSysFolder(LPCITEMIDLIST pidl)
  641. {
  642. if (!pidl)
  643. return FALSE;
  644. DWORD dwAttributes = SFGAO_FOLDER | SFGAO_FILESYSTEM;
  645. HRESULT hr = IEGetAttributesOf(pidl, &dwAttributes);
  646. return SUCCEEDED(hr) && ((dwAttributes & (SFGAO_FOLDER | SFGAO_FILESYSTEM)) == (SFGAO_FOLDER | SFGAO_FILESYSTEM));
  647. }
  648. // HACKHACK HACKHACK
  649. // the following functions are to work around the menu
  650. // munging that happens in the shlwapi wrappers... when we're
  651. // manipulating menus which are tracked by the system, the
  652. // menu munging code in our shlwapi wrappers (necessary
  653. // for xcp plugUI) trashes them since the system doesn't
  654. // understand munged menus... hence the work arounds below.
  655. // note that many of these functions are copies of the shlwapi
  656. // *WrapW functions (minus the munging).
  657. #undef LoadMenuW
  658. // from winuser.h
  659. EXTERN_C WINUSERAPI HMENU WINAPI LoadMenuW(HINSTANCE hInstance, LPCWSTR lpMenuName);
  660. STDAPI_(HMENU)
  661. LoadMenu_PrivateNoMungeW(HINSTANCE hInstance, LPCWSTR lpMenuName)
  662. {
  663. ASSERT(HIWORD64(lpMenuName) == 0);
  664. if (g_fRunningOnNT)
  665. {
  666. return LoadMenuW(hInstance, lpMenuName);
  667. }
  668. return LoadMenuA(hInstance, (LPCSTR) lpMenuName);
  669. }
  670. #define CP_ATOM 0xFFFFFFFF /* not a string at all */
  671. #undef InsertMenuW
  672. // from winuser.h
  673. EXTERN_C WINUSERAPI BOOL WINAPI InsertMenuW(IN HMENU hMenu, IN UINT uPosition, IN UINT uFlags, IN UINT_PTR uIDNewItem, IN LPCWSTR lpNewItem);
  674. STDAPI_(BOOL) InsertMenu_PrivateNoMungeW(HMENU hMenu,
  675. UINT uPosition,
  676. UINT uFlags,
  677. UINT_PTR uIDNewItem,
  678. LPCWSTR lpNewItem)
  679. {
  680. if (g_fRunningOnNT)
  681. {
  682. return InsertMenuW(hMenu, uPosition, uFlags, uIDNewItem, lpNewItem);
  683. }
  684. char szMenuItem[CCH_MENUMAX];
  685. SHUnicodeToAnsiCP((uFlags & MFT_NONSTRING) ? CP_ATOM : CP_ACP,
  686. lpNewItem,
  687. szMenuItem,
  688. ARRAYSIZE(szMenuItem));
  689. return InsertMenuA(hMenu, uPosition, uFlags, uIDNewItem, szMenuItem);
  690. }
  691. #ifndef NO_MLUI_IN_SHELL32
  692. STDAPI_(HMENU) LoadMenuPopup_PrivateNoMungeW(UINT id)
  693. {
  694. HINSTANCE hinst = MLLoadShellLangResources();
  695. HMENU hMenuSub = NULL;
  696. HMENU hMenu = LoadMenu_PrivateNoMungeW(hinst, MAKEINTRESOURCEW(id));
  697. if (hMenu)
  698. {
  699. hMenuSub = GetSubMenu(hMenu, 0);
  700. if (hMenuSub)
  701. {
  702. RemoveMenu(hMenu, 0, MF_BYPOSITION);
  703. }
  704. // note this calls the shlwapi wrapper (that handles
  705. // destroying munged menus) but it looks like
  706. // it's safe to do so.
  707. DestroyMenu(hMenu);
  708. }
  709. MLFreeLibrary(hinst);
  710. return hMenuSub;
  711. }
  712. #endif // NO_MLUI_IN_SHELL32
  713. // determine if a path is just a filespec (contains no path parts)
  714. //
  715. // REVIEW: we may want to count the # of elements, and make sure
  716. // there are no illegal chars, but that is probably another routing
  717. // PathIsValid()
  718. //
  719. // in:
  720. // lpszPath path to look at
  721. // returns:
  722. // TRUE no ":" or "\" chars in this path
  723. // FALSE there are path chars in there
  724. //
  725. //
  726. BOOL PathIsFilePathA(LPCSTR lpszPath)
  727. {
  728. #ifdef UNIX
  729. if (lpszPath[0] == '/')
  730. #else
  731. if ((lpszPath[0] == '\\') || (lpszPath[1] == ':'))
  732. #endif
  733. return TRUE;
  734. return IsFileUrl(lpszPath);
  735. }
  736. //
  737. // PrepareURLForDisplay
  738. //
  739. // Decodes without stripping file:// prefix
  740. //
  741. STDAPI_(BOOL) PrepareURLForDisplayA(LPCSTR psz, LPSTR pszOut, LPDWORD pcchOut)
  742. {
  743. if (PathIsFilePathA(psz))
  744. {
  745. if (IsFileUrl(psz))
  746. return SUCCEEDED(PathCreateFromUrlA(psz, pszOut, pcchOut, 0));
  747. StrCpyNA(pszOut, psz, *pcchOut);
  748. *pcchOut = lstrlenA(pszOut);
  749. return TRUE;
  750. }
  751. return SUCCEEDED(UrlUnescapeA((LPSTR)psz, pszOut, pcchOut, 0));
  752. }
  753. #undef InsertMenuW
  754. #undef LoadMenuW
  755. // from w95wraps.h
  756. #define InsertMenuW InsertMenuWrapW
  757. #define LoadMenuW LoadMenuWrapW
  758. STDAPI SHTitleFromPidl(LPCITEMIDLIST pidl, LPTSTR psz, DWORD cch, BOOL fFullPath)
  759. {
  760. // Tries to get a system-displayable string from a pidl.
  761. // (On Win9x and NT4, User32 doesn't support font-linking,
  762. // so we can't display non-system language strings as window
  763. // titles or menu items. In those cases, we call this function
  764. // to grab the path/URL instead, which will likely be system-
  765. // displayable).
  766. UINT uType;
  767. *psz = NULL;
  768. TCHAR szName[MAX_URL_STRING];
  769. if (fFullPath)
  770. uType = SHGDN_FORPARSING;
  771. else
  772. uType = SHGDN_NORMAL;
  773. uType |= SHGDN_FORADDRESSBAR;
  774. DWORD dwAttrib = SFGAO_LINK;
  775. HRESULT hr = IEGetNameAndFlags(pidl, uType, szName, SIZECHARS(szName), &dwAttrib);
  776. if (SUCCEEDED(hr))
  777. {
  778. if ((uType & SHGDN_FORPARSING) && (dwAttrib & SFGAO_LINK))
  779. {
  780. // folder shortcut special case
  781. IShellLinkA *psl; // Use A version for W95.
  782. if (SUCCEEDED(SHGetUIObjectFromFullPIDL(pidl, NULL, IID_PPV_ARG(IShellLinkA, &psl))))
  783. {
  784. LPITEMIDLIST pidlTarget;
  785. if (SUCCEEDED(psl->GetIDList(&pidlTarget)) && pidlTarget)
  786. {
  787. hr = IEGetNameAndFlags(pidlTarget, uType, szName, SIZECHARS(szName), NULL);
  788. ILFree(pidlTarget);
  789. }
  790. }
  791. }
  792. }
  793. else
  794. {
  795. // didn't work, try the reverse
  796. uType ^= SHGDN_FORPARSING; // flip the for parsing bit
  797. hr = IEGetNameAndFlags(pidl, uType, szName, SIZECHARS(szName), NULL);
  798. // some old namespaces get confused by all our funny bits...
  799. if (FAILED(hr))
  800. {
  801. hr = IEGetNameAndFlags(pidl, SHGDN_NORMAL, szName, SIZECHARS(szName), NULL);
  802. }
  803. }
  804. if (SUCCEEDED(hr))
  805. {
  806. SHRemoveURLTurd(szName);
  807. SHCleanupUrlForDisplay(szName);
  808. // HTTP URLs are not escaped because they come from the
  809. // user or web page which is required to create correctly
  810. // escaped URLs. FTP creates then via results from the
  811. // FTP session, so their pieces (username, password, path)
  812. // need to be escaped when put in URL form. However,
  813. // we are going to put that URL into the Caption Bar, and
  814. // and we want to unescape it because it's assumed to be
  815. // a DBCS name. All of this is done because unescaped URLs
  816. // are pretty. (NT #1272882)
  817. if (URL_SCHEME_FTP == GetUrlScheme(szName))
  818. {
  819. CHAR szUrlTemp[MAX_BROWSER_WINDOW_TITLE];
  820. CHAR szUnEscaped[MAX_BROWSER_WINDOW_TITLE];
  821. DWORD cchSizeTemp = ARRAYSIZE(szUnEscaped);
  822. // This thunking stuff is necessary. Unescaping won't
  823. // gell into DBCS chars unless it's in ansi.
  824. SHTCharToAnsi(szName, szUrlTemp, ARRAYSIZE(szUrlTemp));
  825. PrepareURLForDisplayA(szUrlTemp, szUnEscaped, &cchSizeTemp);
  826. SHAnsiToTChar(szUnEscaped, psz, cch);
  827. }
  828. else
  829. {
  830. StrCpyN(psz, szName, cch);
  831. }
  832. }
  833. return hr;
  834. }
  835. BOOL IsSpecialUrl(LPCWSTR pchURL)
  836. {
  837. UINT uProt = GetUrlSchemeW(pchURL);
  838. return (URL_SCHEME_JAVASCRIPT == uProt ||
  839. URL_SCHEME_VBSCRIPT == uProt ||
  840. URL_SCHEME_ABOUT == uProt);
  841. }
  842. //encode any incoming %1 so that people can't spoof our domain security code
  843. HRESULT WrapSpecialUrl(BSTR * pbstrUrl)
  844. {
  845. HRESULT hr = S_OK;
  846. TCHAR *pchSafeUrl = NULL;
  847. TCHAR *pch;
  848. TCHAR achUrl[4096];
  849. DWORD dwSize;
  850. BSTR bstrURL = *pbstrUrl;
  851. int cSize;
  852. if (IsSpecialUrl(bstrURL))
  853. {
  854. //
  855. // If this is javascript:, vbscript: or about:, append the
  856. // url of this document so that on the other side we can
  857. // decide whether or not to allow script execution.
  858. //
  859. // QFE 2735 (Georgi XDomain): [alanau]
  860. //
  861. // If the special URL contains an %00 sequence, then it will be converted to a Null char when
  862. // encoded. This will effectively truncate the Security ID. For now, simply disallow this
  863. // sequence, and display a "Permission Denied" script error.
  864. //
  865. if (StrStrW(bstrURL, L"%00"))
  866. {
  867. hr = E_ACCESSDENIED;
  868. goto Cleanup;
  869. }
  870. // Copy the URL so we can munge it.
  871. //
  872. cSize = SysStringLen(bstrURL) + 1;
  873. pchSafeUrl = new TCHAR[cSize];
  874. if (!pchSafeUrl)
  875. {
  876. hr = E_OUTOFMEMORY;
  877. goto Cleanup;
  878. }
  879. StrCpyN(pchSafeUrl, bstrURL, cSize);
  880. // someone could put in a string like this:
  881. // %2501 OR %252501 OR %25252501
  882. // which, depending on the number of decoding steps, will bypass security
  883. // so, just keep decoding while there are %s and the string is getting shorter
  884. int nPreviousLen = 0;
  885. while ( (nPreviousLen != lstrlen(pchSafeUrl)) && (StrChrW(pchSafeUrl, L'%')))
  886. {
  887. nPreviousLen = lstrlen(pchSafeUrl);
  888. int nNumPercents;
  889. int nNumPrevPercents = 0;
  890. // Reduce the URL
  891. //
  892. for (;;)
  893. {
  894. // Count the % signs.
  895. //
  896. nNumPercents = 0;
  897. pch = pchSafeUrl;
  898. while (pch = StrChrW(pch, L'%'))
  899. {
  900. pch++;
  901. nNumPercents++;
  902. }
  903. // If the number of % signs has changed, we've reduced the URL one iteration.
  904. //
  905. if (nNumPercents != nNumPrevPercents)
  906. {
  907. // Encode the URL
  908. hr = THR(CoInternetParseUrl(pchSafeUrl,
  909. PARSE_ENCODE,
  910. 0,
  911. achUrl,
  912. ARRAYSIZE(achUrl),
  913. &dwSize,
  914. 0));
  915. StrCpyN(pchSafeUrl, achUrl, cSize);
  916. nNumPrevPercents = nNumPercents;
  917. }
  918. else
  919. {
  920. // The URL is fully reduced. Break out of loop.
  921. //
  922. break;
  923. }
  924. }
  925. }
  926. // Now scan for '\1' characters.
  927. //
  928. if (StrChrW(pchSafeUrl, L'\1'))
  929. {
  930. // If there are '\1' characters, we can't guarantee the safety. Put up "Permission Denied".
  931. //
  932. hr = E_ACCESSDENIED;
  933. goto Cleanup;
  934. }
  935. SysFreeString(*pbstrUrl);
  936. *pbstrUrl = SysAllocString(pchSafeUrl);
  937. if (!*pbstrUrl)
  938. {
  939. hr = E_OUTOFMEMORY;
  940. goto Cleanup;
  941. }
  942. }
  943. Cleanup:
  944. delete [] pchSafeUrl;
  945. return hr;
  946. }
  947. HRESULT WrapSpecialUrlFlat(LPWSTR pszUrl, DWORD cchUrl)
  948. {
  949. HRESULT hr = S_OK;
  950. if (IsSpecialUrl(pszUrl))
  951. {
  952. //
  953. // If this is javascript:, vbscript: or about:, append the
  954. // url of this document so that on the other side we can
  955. // decide whether or not to allow script execution.
  956. //
  957. // QFE 2735 (Georgi XDomain): [alanau]
  958. //
  959. // If the special URL contains an %00 sequence, then it will be converted to a Null char when
  960. // encoded. This will effectively truncate the Security ID. For now, simply disallow this
  961. // sequence, and display a "Permission Denied" script error.
  962. //
  963. if (StrStrW(pszUrl, L"%00"))
  964. {
  965. hr = E_ACCESSDENIED;
  966. }
  967. else
  968. {
  969. // munge the url in place
  970. //
  971. // someone could put in a string like this:
  972. // %2501 OR %252501 OR %25252501
  973. // which, depending on the number of decoding steps, will bypass security
  974. // so, just keep decoding while there are %s and the string is getting shorter
  975. int nPreviousLen = 0;
  976. while ( (nPreviousLen != lstrlen(pszUrl)) && (StrChrW(pszUrl, L'%')))
  977. {
  978. nPreviousLen = lstrlen(pszUrl);
  979. int nNumPercents;
  980. int nNumPrevPercents = 0;
  981. // Reduce the URL
  982. //
  983. for (;;)
  984. {
  985. // Count the % signs.
  986. //
  987. nNumPercents = 0;
  988. WCHAR *pch = pszUrl;
  989. while (pch = StrChrW(pch, L'%'))
  990. {
  991. pch++;
  992. nNumPercents++;
  993. }
  994. // If the number of % signs has changed, we've reduced the URL one iteration.
  995. //
  996. if (nNumPercents != nNumPrevPercents)
  997. {
  998. WCHAR szBuf[MAX_URL_STRING];
  999. DWORD dwSize;
  1000. // Encode the URL
  1001. hr = THR(CoInternetParseUrl(pszUrl,
  1002. PARSE_ENCODE,
  1003. 0,
  1004. szBuf,
  1005. ARRAYSIZE(szBuf),
  1006. &dwSize,
  1007. 0));
  1008. StrCpyN(pszUrl, szBuf, cchUrl);
  1009. nNumPrevPercents = nNumPercents;
  1010. }
  1011. else
  1012. {
  1013. // The URL is fully reduced. Break out of loop.
  1014. //
  1015. break;
  1016. }
  1017. }
  1018. }
  1019. // Now scan for '\1' characters.
  1020. //
  1021. if (StrChrW(pszUrl, L'\1'))
  1022. {
  1023. // If there are '\1' characters, we can't guarantee the safety. Put up "Permission Denied".
  1024. //
  1025. hr = E_ACCESSDENIED;
  1026. }
  1027. }
  1028. }
  1029. return hr;
  1030. }
  1031. STDAPI GetBrowserFrameOptions(IUnknown *punkFolder, IN BROWSERFRAMEOPTIONS dwMask, OUT BROWSERFRAMEOPTIONS * pdwOptions)
  1032. {
  1033. HRESULT hr = E_INVALIDARG;
  1034. *pdwOptions = BFO_NONE;
  1035. if (punkFolder)
  1036. {
  1037. IBrowserFrameOptions *pbfo;
  1038. hr = punkFolder->QueryInterface(IID_PPV_ARG(IBrowserFrameOptions, &pbfo));
  1039. if (SUCCEEDED(hr))
  1040. {
  1041. hr = pbfo->GetFrameOptions(dwMask, pdwOptions);
  1042. pbfo->Release();
  1043. }
  1044. }
  1045. return hr;
  1046. }
  1047. STDAPI GetBrowserFrameOptionsPidl(IN LPCITEMIDLIST pidl, IN BROWSERFRAMEOPTIONS dwMask, OUT BROWSERFRAMEOPTIONS * pdwOptions)
  1048. {
  1049. HRESULT hr = E_INVALIDARG;
  1050. *pdwOptions = BFO_NONE;
  1051. if (pidl)
  1052. {
  1053. IBrowserFrameOptions *pbfo;
  1054. hr = IEBindToObjectEx(pidl, NULL, IID_PPV_ARG(IBrowserFrameOptions, &pbfo));
  1055. if (SUCCEEDED(hr) && pbfo)
  1056. {
  1057. hr = pbfo->GetFrameOptions(dwMask, pdwOptions);
  1058. pbfo->Release();
  1059. }
  1060. }
  1061. return hr;
  1062. }
  1063. // Return TRUE only if all the bits in dwMask are set.
  1064. STDAPI_(BOOL) IsBrowserFrameOptionsSet(IN IShellFolder * psf, IN BROWSERFRAMEOPTIONS dwMask)
  1065. {
  1066. BOOL fSet = FALSE;
  1067. BROWSERFRAMEOPTIONS dwOptions = 0;
  1068. if (SUCCEEDED(GetBrowserFrameOptions(psf, dwMask, &dwOptions)) &&
  1069. (dwOptions == dwMask))
  1070. {
  1071. fSet = TRUE;
  1072. }
  1073. return fSet;
  1074. }
  1075. // Return TRUE only if all the bits in dwMask are set.
  1076. STDAPI_(BOOL) IsBrowserFrameOptionsPidlSet(IN LPCITEMIDLIST pidl, IN BROWSERFRAMEOPTIONS dwMask)
  1077. {
  1078. BOOL fSet = FALSE;
  1079. BROWSERFRAMEOPTIONS dwOptions = 0;
  1080. if (SUCCEEDED(GetBrowserFrameOptionsPidl(pidl, dwMask, &dwOptions)) &&
  1081. (dwOptions == dwMask))
  1082. {
  1083. fSet = TRUE;
  1084. }
  1085. return fSet;
  1086. }
  1087. STDAPI_(BOOL) IsFTPFolder(IShellFolder * psf)
  1088. {
  1089. BOOL fIsFTPFolder = FALSE;
  1090. CLSID clsid;
  1091. if (psf && SUCCEEDED(IUnknown_GetClassID(psf, &clsid)))
  1092. {
  1093. // Is this an FTP Folder?
  1094. if (IsEqualIID(clsid, CLSID_FtpFolder))
  1095. fIsFTPFolder = TRUE;
  1096. else
  1097. {
  1098. // Not directly, but let's see if it is an Folder Shortcut to
  1099. // an FTP Folder
  1100. if (IsEqualIID(clsid, CLSID_FolderShortcut))
  1101. {
  1102. IShellLinkA * psl;
  1103. HRESULT hr = psf->QueryInterface(IID_PPV_ARG(IShellLinkA, &psl));
  1104. if (SUCCEEDED(hr))
  1105. {
  1106. LPITEMIDLIST pidl;
  1107. hr = psl->GetIDList(&pidl);
  1108. if (SUCCEEDED(hr))
  1109. {
  1110. IShellFolder * psfTarget;
  1111. hr = IEBindToObject(pidl, &psfTarget);
  1112. if (SUCCEEDED(hr))
  1113. {
  1114. if (SUCCEEDED(IUnknown_GetClassID(psfTarget, &clsid)) &&
  1115. IsEqualIID(clsid, CLSID_FtpFolder))
  1116. {
  1117. fIsFTPFolder = TRUE;
  1118. }
  1119. psfTarget->Release();
  1120. }
  1121. ILFree(pidl);
  1122. }
  1123. psl->Release();
  1124. }
  1125. }
  1126. }
  1127. }
  1128. return fIsFTPFolder;
  1129. }
  1130. //+---------------------------------------------------------------------------
  1131. //
  1132. // Function: DrawFocusRectangle
  1133. //
  1134. // Synopsis: draws the focus rectangle for the edit control
  1135. //
  1136. //----------------------------------------------------------------------------
  1137. void DrawFocusRectangle (HWND hwnd, HDC hdc)
  1138. {
  1139. RECT rect;
  1140. BOOL fReleaseDC = FALSE;
  1141. if ( hdc == NULL )
  1142. {
  1143. hdc = GetDC(hwnd);
  1144. if ( hdc == NULL )
  1145. {
  1146. return;
  1147. }
  1148. fReleaseDC = TRUE;
  1149. }
  1150. GetClientRect(hwnd, &rect);
  1151. DrawFocusRect(hdc, &rect);
  1152. if ( fReleaseDC == TRUE )
  1153. {
  1154. ReleaseDC(hwnd, hdc);
  1155. }
  1156. }
  1157. typedef struct {
  1158. LPSTR psz;
  1159. LPCWSTR pwsz;
  1160. LONG byteoffset;
  1161. BOOL fStreamIn;
  1162. } STREAMIN_HELPER_STRUCT;
  1163. DWORD CALLBACK SetRicheditTextWCallback(
  1164. DWORD_PTR dwCookie, // application-defined value
  1165. LPBYTE pbBuff, // pointer to a buffer
  1166. LONG cb, // number of bytes to read or write
  1167. LONG *pcb // pointer to number of bytes transferred
  1168. )
  1169. {
  1170. STREAMIN_HELPER_STRUCT *pHelpStruct = (STREAMIN_HELPER_STRUCT *) dwCookie;
  1171. LONG lRemain = ((wcslen(pHelpStruct->pwsz) * sizeof(WCHAR)) - pHelpStruct->byteoffset);
  1172. if (pHelpStruct->fStreamIn)
  1173. {
  1174. //
  1175. // The whole string can be copied first time
  1176. //
  1177. if ((cb >= (LONG) (wcslen(pHelpStruct->pwsz) * sizeof(WCHAR))) && (pHelpStruct->byteoffset == 0))
  1178. {
  1179. memcpy(pbBuff, pHelpStruct->pwsz, wcslen(pHelpStruct->pwsz) * sizeof(WCHAR));
  1180. *pcb = wcslen(pHelpStruct->pwsz) * sizeof(WCHAR);
  1181. pHelpStruct->byteoffset = *pcb;
  1182. }
  1183. //
  1184. // The whole string has been copied, so terminate the streamin callbacks
  1185. // by setting the num bytes copied to 0
  1186. //
  1187. else if (((LONG)(wcslen(pHelpStruct->pwsz) * sizeof(WCHAR))) <= pHelpStruct->byteoffset)
  1188. {
  1189. *pcb = 0;
  1190. }
  1191. //
  1192. // The rest of the string will fit in this buffer
  1193. //
  1194. else if (cb >= (LONG) ((wcslen(pHelpStruct->pwsz) * sizeof(WCHAR)) - pHelpStruct->byteoffset))
  1195. {
  1196. memcpy(
  1197. pbBuff,
  1198. ((BYTE *)pHelpStruct->pwsz) + pHelpStruct->byteoffset,
  1199. ((wcslen(pHelpStruct->pwsz) * sizeof(WCHAR)) - pHelpStruct->byteoffset));
  1200. *pcb = ((wcslen(pHelpStruct->pwsz) * sizeof(WCHAR)) - pHelpStruct->byteoffset);
  1201. pHelpStruct->byteoffset += ((wcslen(pHelpStruct->pwsz) * sizeof(WCHAR)) - pHelpStruct->byteoffset);
  1202. }
  1203. //
  1204. // copy as much as possible
  1205. //
  1206. else
  1207. {
  1208. memcpy(
  1209. pbBuff,
  1210. ((BYTE *)pHelpStruct->pwsz) + pHelpStruct->byteoffset,
  1211. cb);
  1212. *pcb = cb;
  1213. pHelpStruct->byteoffset += cb;
  1214. }
  1215. }
  1216. else
  1217. {
  1218. //
  1219. // This is the EM_STREAMOUT which is only used during the testing of
  1220. // the richedit2.0 functionality. (we know our buffer is 32 bytes)
  1221. //
  1222. if (cb <= 32)
  1223. {
  1224. memcpy(pHelpStruct->psz, pbBuff, cb);
  1225. }
  1226. *pcb = cb;
  1227. }
  1228. return 0;
  1229. }
  1230. void SetRicheditIMFOption(HWND hWndRichEdit)
  1231. {
  1232. DWORD dwOptions;
  1233. dwOptions = (DWORD)SendMessageW(hWndRichEdit, EM_GETLANGOPTIONS, 0, 0);
  1234. dwOptions |= IMF_UIFONTS;
  1235. SendMessageW(hWndRichEdit, EM_SETLANGOPTIONS, 0, dwOptions);
  1236. }
  1237. DWORD SetRicheditTextW(HWND hwndDlg, UINT id, LPCWSTR pwsz)
  1238. {
  1239. EDITSTREAM editStream;
  1240. STREAMIN_HELPER_STRUCT helpStruct;
  1241. SetRicheditIMFOption(GetDlgItem(hwndDlg, id));
  1242. //
  1243. // setup the edit stream struct since it is the same no matter what
  1244. //
  1245. editStream.dwCookie = (DWORD_PTR) &helpStruct;
  1246. editStream.dwError = 0;
  1247. editStream.pfnCallback = SetRicheditTextWCallback;
  1248. helpStruct.pwsz = pwsz;
  1249. helpStruct.byteoffset = 0;
  1250. helpStruct.fStreamIn = TRUE;
  1251. SendDlgItemMessageW(hwndDlg, id, EM_STREAMIN, SF_TEXT | SF_UNICODE, (LPARAM) &editStream);
  1252. return editStream.dwError;
  1253. }
  1254. //+---------------------------------------------------------------------------
  1255. //
  1256. // Function: RenderStringToEditControlW
  1257. //
  1258. // Synopsis: renders a string to the control given and if requested, gives
  1259. // it a link look and feel, subclassed to the wndproc given
  1260. //
  1261. // Arguments: [hwndDlg] -- dialog window handle
  1262. // [pwsz] -- string
  1263. // [wndproc] -- wndproc
  1264. // [uID] -- ID of control
  1265. //
  1266. //
  1267. // Notes:
  1268. //
  1269. //----------------------------------------------------------------------------
  1270. void RenderStringToEditControlW (
  1271. HWND hwndDlg,
  1272. LPCWSTR pwsz,
  1273. WNDPROC wndproc,
  1274. UINT uID)
  1275. {
  1276. HWND hControl;
  1277. //
  1278. // Get the control and set the text on it, make sure the background is right
  1279. //
  1280. hControl = GetDlgItem(hwndDlg, uID);
  1281. SetRicheditIMFOption(GetDlgItem(hwndDlg, uID));
  1282. SetRicheditTextW(hwndDlg, uID, L"");
  1283. SetRicheditTextW(hwndDlg, uID, pwsz);
  1284. SendMessage(
  1285. hControl,
  1286. EM_SETBKGNDCOLOR,
  1287. 0,
  1288. (LPARAM)GetSysColor(COLOR_3DFACE)
  1289. );
  1290. //
  1291. // Update for the link look
  1292. //
  1293. CHARFORMAT cf;
  1294. memset(&cf, 0, sizeof(CHARFORMAT));
  1295. cf.cbSize = sizeof(CHARFORMAT);
  1296. cf.dwMask = CFM_COLOR | CFM_UNDERLINE | CFM_LINK;
  1297. cf.crTextColor = RGB(0, 0, 255);
  1298. cf.dwEffects |= CFE_UNDERLINE | CFE_LINK;
  1299. SendMessage(hControl, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
  1300. //subclass the window proc so we can handle the link specially
  1301. LONG_PTR PrevWndProc = GetWindowLongPtr(hControl, GWLP_WNDPROC);
  1302. SetWindowLongPtr(hControl, GWLP_USERDATA, (LONG_PTR)PrevWndProc);
  1303. SetWindowLongPtr(hControl, GWLP_WNDPROC, (LONG_PTR)wndproc);
  1304. }