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.

4178 lines
121 KiB

  1. #include "priv.h"
  2. #include "sccls.h"
  3. #include "mlang.h" // fo char conversion
  4. #include "bandprxy.h"
  5. #include "resource.h"
  6. #include <shdocvw.h>
  7. #include <icwcfg.h>
  8. #include <advpub.h> // for IE activesetup GUID
  9. #include <shellapi.h>
  10. #include "apithk.h" //for WM_KEYBOARDCUES msg
  11. #include <platform.h>
  12. #include <mobsync.h>
  13. #include <mobsyncp.h>
  14. #include "..\shell32\shitemid.h" // for SHID_XX
  15. #ifdef UNIX
  16. #include "unixstuff.h"
  17. #endif /* UNIX */
  18. #define MLUI_INIT
  19. #include "mluisupp.h"
  20. //small (previously duplicated) functions shared between shdcovw and browseui
  21. #include "..\inc\brutil.cpp"
  22. // #define MLUI_SUPPORT 1
  23. LCID g_lcidLocale = MAKELCID(LANG_USER_DEFAULT, SORT_DEFAULT);
  24. #define DM_NAV TF_SHDNAVIGATE
  25. #define DM_ZONE TF_SHDNAVIGATE
  26. #define DM_IEDDE DM_TRACE
  27. #define DM_CANCELMODE 0
  28. #define DM_UIWINDOW 0
  29. #define DM_ENABLEMODELESS 0
  30. #define DM_EXPLORERMENU 0
  31. #define DM_BACKFORWARD 0
  32. #define DM_PROTOCOL 0
  33. #define DM_ITBAR 0
  34. #define DM_STARTUP 0
  35. #define DM_AUTOLIFE 0
  36. #define DM_PALETTE 0
  37. const VARIANT c_vaEmpty = {0};
  38. const LARGE_INTEGER c_li0 = { 0, 0 };
  39. #undef VariantCopy
  40. WINOLEAUTAPI VariantCopyLazy(VARIANTARG * pvargDest, VARIANTARG * pvargSrc)
  41. {
  42. VariantClearLazy(pvargDest);
  43. switch(pvargSrc->vt)
  44. {
  45. case VT_I4:
  46. case VT_UI4:
  47. case VT_BOOL:
  48. // we can add more
  49. *pvargDest = *pvargSrc;
  50. return S_OK;
  51. case VT_UNKNOWN:
  52. if (pvargDest)
  53. {
  54. *pvargDest = *pvargSrc;
  55. pvargDest->punkVal->AddRef();
  56. return S_OK;
  57. }
  58. ASSERT(0);
  59. return E_INVALIDARG;
  60. }
  61. return VariantCopy(pvargDest, pvargSrc);
  62. }
  63. //
  64. // WARNING: This function must be placed at the end because we #undef
  65. // VariantClear
  66. //
  67. #undef VariantClear
  68. HRESULT VariantClearLazy(VARIANTARG *pvarg)
  69. {
  70. switch(pvarg->vt)
  71. {
  72. case VT_I4:
  73. case VT_UI4:
  74. case VT_EMPTY:
  75. case VT_BOOL:
  76. // No operation
  77. break;
  78. default:
  79. return VariantClear(pvarg);
  80. }
  81. return S_OK;
  82. }
  83. HRESULT QueryService_SID_IBandProxy(IUnknown * punkParent, REFIID riid, IBandProxy ** ppbp, void **ppvObj)
  84. {
  85. HRESULT hr = E_FAIL;
  86. if (ppbp)
  87. {
  88. if (NULL == (*ppbp))
  89. hr = IUnknown_QueryService(punkParent, SID_IBandProxy, IID_PPV_ARG(IBandProxy, ppbp));
  90. if (*ppbp && ppvObj)
  91. hr = (*ppbp)->QueryInterface(riid, ppvObj); // They already have the object.
  92. }
  93. return hr;
  94. }
  95. HRESULT CreateIBandProxyAndSetSite(IUnknown * punkParent, REFIID riid, IBandProxy ** ppbp, void **ppvObj)
  96. {
  97. ASSERT(ppbp);
  98. HRESULT hr = CoCreateInstance(CLSID_BandProxy, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IBandProxy, ppbp));
  99. if (SUCCEEDED(hr))
  100. {
  101. // Set the site
  102. ASSERT(*ppbp);
  103. (*ppbp)->SetSite(punkParent);
  104. if (ppvObj)
  105. hr = (*ppbp)->QueryInterface(riid, ppvObj);
  106. }
  107. else
  108. {
  109. if (ppvObj)
  110. *ppvObj = NULL;
  111. }
  112. return hr;
  113. }
  114. HRESULT IUnknown_FileSysChange(IUnknown* punk, DWORD dwEvent, LPCITEMIDLIST* ppidl)
  115. {
  116. HRESULT hres = E_FAIL;
  117. if (punk)
  118. {
  119. IAddressBand * pab;
  120. hres = punk->QueryInterface(IID_PPV_ARG(IAddressBand, &pab));
  121. if (SUCCEEDED(hres))
  122. {
  123. hres = pab->FileSysChange(dwEvent, ppidl);
  124. pab->Release();
  125. }
  126. }
  127. return hres;
  128. }
  129. UINT g_cfURL = 0;
  130. UINT g_cfHIDA = 0;
  131. UINT g_cfFileDescA = 0;
  132. UINT g_cfFileDescW = 0;
  133. UINT g_cfFileContents = 0;
  134. UINT g_cfPreferedEffect = 0;
  135. void InitClipboardFormats()
  136. {
  137. if (g_cfURL == 0)
  138. {
  139. g_cfURL = RegisterClipboardFormat(CFSTR_SHELLURL);
  140. g_cfHIDA = RegisterClipboardFormat(CFSTR_SHELLIDLIST);
  141. g_cfFileDescA = RegisterClipboardFormat(CFSTR_FILEDESCRIPTORA);
  142. g_cfFileDescW = RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW);
  143. g_cfFileContents = RegisterClipboardFormat(CFSTR_FILECONTENTS);
  144. g_cfPreferedEffect = RegisterClipboardFormat(CFSTR_PREFERREDDROPEFFECT);
  145. }
  146. }
  147. DEFFOLDERSETTINGS g_dfs = INIT_DEFFOLDERSETTINGS;
  148. void _InitDefaultFolderSettings()
  149. {
  150. if (GetSystemMetrics(SM_CLEANBOOT))
  151. return;
  152. g_dfs.vid = g_bRunOnNT5 ? VID_LargeIcons : DFS_VID_Default;
  153. DEFFOLDERSETTINGS dfs = g_dfs;
  154. DWORD dwType, cbData = sizeof(dfs);
  155. if (SUCCEEDED(SKGetValue(SHELLKEY_HKCU_EXPLORER, REGVALUE_STREAMS, TEXT("Settings"), &dwType, &dfs, &cbData))
  156. && dwType == REG_BINARY)
  157. {
  158. if (cbData < sizeof(DEFFOLDERSETTINGS_W2K) || dfs.dwStructVersion < DFS_NASH_VER)
  159. {
  160. dfs.vid = g_bRunOnNT5 ? VID_LargeIcons : DFS_VID_Default;
  161. dfs.dwStructVersion = DFS_NASH_VER;
  162. dfs.bUseVID = TRUE;
  163. }
  164. if (cbData < sizeof(DEFFOLDERSETTINGS) || dfs.dwStructVersion < DFS_WHISTLER_VER)
  165. {
  166. dfs.dwViewPriority = VIEW_PRIORITY_CACHEMISS;
  167. dfs.dwStructVersion = DFS_WHISTLER_VER;
  168. }
  169. g_dfs = dfs;
  170. }
  171. }
  172. CABINETSTATE g_CabState = { 0 };
  173. extern HANDLE g_hCabStateChange;
  174. LONG g_lCabStateCount = -1; // never a valid count
  175. void GetCabState(CABINETSTATE *pcs)
  176. {
  177. if (g_hCabStateChange == NULL)
  178. g_hCabStateChange = SHGlobalCounterCreate(GUID_FolderSettingsChange);
  179. LONG lCabStateCur = SHGlobalCounterGetValue(g_hCabStateChange);
  180. if (g_lCabStateCount != lCabStateCur)
  181. {
  182. g_lCabStateCount = lCabStateCur;
  183. if (!ReadCabinetState(&g_CabState, sizeof(g_CabState)))
  184. {
  185. WriteCabinetState(&g_CabState);
  186. }
  187. }
  188. *pcs = g_CabState;
  189. }
  190. typedef struct tagINIPAIR
  191. {
  192. DWORD dwFlags;
  193. LPCTSTR pszSection;
  194. }
  195. INIPAIR, *PINIPAIR;
  196. const INIPAIR c_aIniPairs[] =
  197. {
  198. EICH_KINET, TEXT("Software\\Microsoft\\Internet Explorer"),
  199. EICH_KINETMAIN, TEXT("Software\\Microsoft\\Internet Explorer\\Main"),
  200. EICH_KWIN, TEXT("Software\\Microsoft\\Windows\\CurrentVersion"),
  201. EICH_KWINEXPLORER, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"),
  202. EICH_KWINEXPLSMICO, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\SmallIcons"),
  203. EICH_KWINPOLICY, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies"),
  204. EICH_SSAVETASKBAR, TEXT("SaveTaskbar"),
  205. EICH_SWINDOWMETRICS, TEXT("WindowMetrics"),
  206. EICH_SSHELLMENU, TEXT("ShellMenu"),
  207. EICH_SPOLICY, TEXT("Policy"),
  208. EICH_SWINDOWS, TEXT("Windows"),
  209. };
  210. DWORD SHIsExplorerIniChange(WPARAM wParam, LPARAM lParam)
  211. {
  212. DWORD dwFlags = 0;
  213. if (lParam == 0)
  214. {
  215. if (wParam == 0)
  216. {
  217. dwFlags = EICH_UNKNOWN;
  218. }
  219. }
  220. else
  221. {
  222. //
  223. // In the wacky world of browseui, UNICODE-ANSI doesn't vary from
  224. // window to window. Instead, on NT browseui registers all windows
  225. // UNICODE, while on 9x user browseui registers all windows ANSI.
  226. //
  227. LPCTSTR pszSection;
  228. TCHAR szTemp[MAX_PATH]; // not a filename, but a section/registry key name
  229. if (g_fRunningOnNT)
  230. {
  231. #ifdef UNICODE
  232. pszSection = (LPCTSTR)lParam;
  233. #else
  234. UINT cch = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)lParam, -1, szTemp, ARRAYSIZE(szTemp), NULL, NULL);
  235. if (cch == 0)
  236. {
  237. szTemp[0] = TEXT('\0'); // it won't compare
  238. }
  239. #endif
  240. }
  241. else
  242. {
  243. #ifdef UNICODE
  244. UINT cch = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)lParam, -1, szTemp, ARRAYSIZE(szTemp));
  245. if (cch == 0)
  246. {
  247. szTemp[0] = TEXT('\0'); // it won't compare
  248. }
  249. #else
  250. pszSection = (LPCTSTR)lParam;
  251. #endif
  252. }
  253. for (int i = 0; !dwFlags && i < ARRAYSIZE(c_aIniPairs); i++)
  254. {
  255. if (StrCmpI(pszSection, c_aIniPairs[i].pszSection) == 0)
  256. {
  257. dwFlags = c_aIniPairs[i].dwFlags;
  258. }
  259. }
  260. }
  261. return dwFlags;
  262. }
  263. void _InitAppGlobals()
  264. {
  265. static BOOL fInitialized = FALSE;
  266. if (!fInitialized)
  267. {
  268. _InitComCtl32();
  269. _InitDefaultFolderSettings();
  270. // dont put anything else here. instead init on demand
  271. fInitialized = TRUE; // allow a race on the above calls
  272. }
  273. }
  274. BOOL _InitComCtl32()
  275. {
  276. static BOOL fInitialized = FALSE;
  277. if (!fInitialized)
  278. {
  279. INITCOMMONCONTROLSEX icc;
  280. icc.dwSize = sizeof(INITCOMMONCONTROLSEX);
  281. icc.dwICC = ICC_USEREX_CLASSES | ICC_COOL_CLASSES | ICC_INTERNET_CLASSES | ICC_PAGESCROLLER_CLASS
  282. | ICC_NATIVEFNTCTL_CLASS;
  283. fInitialized = InitCommonControlsEx(&icc);
  284. }
  285. return fInitialized;
  286. }
  287. DWORD GetPreferedDropEffect(IDataObject *pdtobj)
  288. {
  289. InitClipboardFormats();
  290. DWORD dwEffect = 0;
  291. STGMEDIUM medium;
  292. DWORD *pdw = (DWORD *)DataObj_GetDataOfType(pdtobj, g_cfPreferedEffect, &medium);
  293. if (pdw)
  294. {
  295. dwEffect = *pdw;
  296. ReleaseStgMediumHGLOBAL(pdw,&medium);
  297. }
  298. return dwEffect;
  299. }
  300. HRESULT _SetPreferedDropEffect(IDataObject *pdtobj, DWORD dwEffect)
  301. {
  302. InitClipboardFormats();
  303. HRESULT hres = E_OUTOFMEMORY;
  304. DWORD *pdw = (DWORD *)GlobalAlloc(GPTR, sizeof(*pdw));
  305. if (pdw)
  306. {
  307. STGMEDIUM medium;
  308. FORMATETC fmte = {g_cfPreferedEffect, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  309. *pdw = dwEffect;
  310. medium.tymed = TYMED_HGLOBAL;
  311. medium.hGlobal = pdw;
  312. medium.pUnkForRelease = NULL;
  313. hres = pdtobj->SetData(&fmte, &medium, TRUE);
  314. if (FAILED(hres))
  315. GlobalFree((HGLOBAL)pdw);
  316. }
  317. return hres;
  318. }
  319. //*** Reg_GetStrs -- get values from registry, assign to struct
  320. void Reg_GetStrs(HKEY hkey, const struct regstrs *tab, LPTSTR szBuf, int cchBuf, void *pv)
  321. {
  322. for (; tab->name != NULL; tab++)
  323. {
  324. ULONG cbTmp = cchBuf;
  325. // NOTE: IE4 did *NOT* support SHLoadRegUIString, so don't call Reg_GetStrs
  326. // on roamable data. (Or at least don't register plugui strings there.)
  327. if (ERROR_SUCCESS == SHLoadRegUIString(hkey, tab->name, szBuf, cbTmp))
  328. {
  329. // pv->field = StrDup(szBuf)
  330. *(LPTSTR *)((char *)pv + tab->off) = StrDup(szBuf);
  331. }
  332. }
  333. return;
  334. }
  335. BOOL g_fNewNotify = FALSE; // Are we using classic mode (W95 or new mode?
  336. PFNSHCHANGENOTIFYREGISTER g_pfnSHChangeNotifyRegister = NULL;
  337. PFNSHCHANGENOTIFYDEREGISTER g_pfnSHChangeNotifyDeregister = NULL;
  338. #define GET_PRIVATE_PROC_ADDRESS(_hinst, _fname, _ord) GetProcAddress(_hinst, _ord)
  339. BOOL _DelayLoadRegisterNotify(void)
  340. {
  341. // See if we need to still figure out which version of SHChange Notify to call?
  342. if (g_pfnSHChangeNotifyDeregister == NULL)
  343. {
  344. // This should never fail, since we are load-time-linked to SHELL32
  345. HMODULE hmodShell32 = GetModuleHandleA("SHELL32.DLL");
  346. if (hmodShell32)
  347. {
  348. g_pfnSHChangeNotifyRegister = (PFNSHCHANGENOTIFYREGISTER)GET_PRIVATE_PROC_ADDRESS(hmodShell32, "NTSHChangeNotifyRegister",MAKEINTRESOURCEA(640));
  349. if (g_pfnSHChangeNotifyRegister && (WhichPlatform() == PLATFORM_INTEGRATED))
  350. {
  351. g_pfnSHChangeNotifyDeregister = (PFNSHCHANGENOTIFYDEREGISTER)GET_PRIVATE_PROC_ADDRESS(hmodShell32,"NTSHChangeNotifyDeregister", MAKEINTRESOURCEA(641));
  352. g_fNewNotify = TRUE;
  353. }
  354. else
  355. {
  356. g_pfnSHChangeNotifyRegister = (PFNSHCHANGENOTIFYREGISTER)GET_PRIVATE_PROC_ADDRESS(hmodShell32, "SHChangeNotifyRegister", MAKEINTRESOURCEA(2));
  357. g_pfnSHChangeNotifyDeregister = (PFNSHCHANGENOTIFYDEREGISTER)GET_PRIVATE_PROC_ADDRESS(hmodShell32, "SHChangeNotifyDeregister",MAKEINTRESOURCEA(4));
  358. }
  359. }
  360. }
  361. return (NULL == g_pfnSHChangeNotifyDeregister) ? FALSE : TRUE;
  362. }
  363. ULONG RegisterNotify(HWND hwnd, UINT nMsg, LPCITEMIDLIST pidl, DWORD dwEvents, UINT uFlags, BOOL fRecursive)
  364. {
  365. if (_DelayLoadRegisterNotify())
  366. {
  367. SHChangeNotifyEntry fsne;
  368. if (g_fNewNotify)
  369. uFlags |= SHCNRF_NewDelivery;
  370. fsne.fRecursive = fRecursive;
  371. fsne.pidl = pidl;
  372. return g_pfnSHChangeNotifyRegister(hwnd, uFlags, dwEvents, nMsg, 1, &fsne);
  373. }
  374. return 0;
  375. }
  376. int PropBag_ReadInt4(IPropertyBag* pPropBag, LPWSTR pszKey, int iDefault)
  377. {
  378. SHPropertyBag_ReadInt(pPropBag, pszKey, &iDefault);
  379. return iDefault;
  380. }
  381. STDAPI_(BOOL) _EnsureLoaded(HINSTANCE *phinst, LPCSTR pszDLL)
  382. {
  383. if (*phinst == NULL)
  384. {
  385. #ifdef DEBUG
  386. if (g_dwDumpFlags & DF_DELAYLOADDLL)
  387. {
  388. TraceMsg(TF_ALWAYS, "DLLLOAD: Loading %s for the first time", pszDLL);
  389. }
  390. if (g_dwBreakFlags & 0x00000080)
  391. {
  392. DebugBreak();
  393. }
  394. #endif
  395. *phinst = LoadLibraryA(pszDLL);
  396. if (*phinst == NULL)
  397. {
  398. return FALSE;
  399. }
  400. }
  401. return TRUE;
  402. }
  403. // global g_hinst values
  404. HINSTANCE g_hinstSHDOCVW = NULL;
  405. HINSTANCE g_hinstShell32 = NULL;
  406. HINSTANCE HinstShdocvw()
  407. {
  408. _EnsureLoaded(&g_hinstSHDOCVW, "shdocvw.dll");
  409. return g_hinstSHDOCVW;
  410. }
  411. HINSTANCE HinstShell32()
  412. {
  413. _EnsureLoaded(&g_hinstShell32, "shell32.dll");
  414. return g_hinstShell32;
  415. }
  416. STDAPI_(BOOL) CallCoInternetQueryInfo(LPCTSTR pszURL, QUERYOPTION QueryOption)
  417. {
  418. DWORD fRetVal;
  419. DWORD dwSize;
  420. WCHAR wszURL[MAX_URL_STRING];
  421. SHTCharToUnicode(pszURL, wszURL, ARRAYSIZE(wszURL));
  422. return SUCCEEDED(CoInternetQueryInfo(
  423. wszURL, QueryOption,
  424. 0, &fRetVal, sizeof(fRetVal), &dwSize, 0)) && fRetVal;
  425. }
  426. HRESULT IURLQualifyW(IN LPCWSTR pcwzURL, DWORD dwFlags, OUT LPWSTR pwzTranslatedURL, LPBOOL pbWasSearchURL, LPBOOL pbWasCorrected)
  427. {
  428. return IURLQualify(pcwzURL, dwFlags, pwzTranslatedURL, pbWasSearchURL, pbWasCorrected);
  429. }
  430. BSTR LoadBSTR(HINSTANCE hinst, UINT uID)
  431. {
  432. WCHAR wszBuf[128];
  433. if (LoadStringW(hinst, uID, wszBuf, ARRAYSIZE(wszBuf)))
  434. {
  435. return SysAllocString(wszBuf);
  436. }
  437. return NULL;
  438. }
  439. HRESULT _SetStdLocation(LPTSTR szPath, UINT id)
  440. {
  441. HRESULT hres = E_FAIL;
  442. WCHAR szDefaultPath[MAX_URL_STRING];
  443. ASSERT(id == DVIDM_GOHOME);
  444. if (SUCCEEDED(URLSubLoadString(MLGetHinst(), IDS_DEF_HOME, szDefaultPath, SIZECHARS(szDefaultPath), URLSUB_ALL)))
  445. {
  446. if (!StrCmp(szDefaultPath, szPath))
  447. return S_OK; // We don't need to write out the name string.
  448. }
  449. DWORD cbSize = (lstrlen(szPath) + 1) * sizeof(TCHAR);
  450. if (ERROR_SUCCESS == SHSetValue(HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Internet Explorer\\Main"), (id==DVIDM_GOHOME) ? TEXT("Start Page") : TEXT("Search Page"),
  451. REG_SZ, (LPBYTE)szPath, cbSize))
  452. {
  453. hres = S_OK;
  454. }
  455. return hres;
  456. }
  457. //*** IsVK_TABCycler -- is key a TAB-equivalent
  458. // ENTRY/EXIT
  459. // dir 0 if not a TAB, non-0 if a TAB
  460. // NOTES
  461. // NYI: -1 for shift+tab, 1 for tab
  462. //
  463. int IsVK_TABCycler(MSG *pMsg)
  464. {
  465. int nDir = 0;
  466. if (!pMsg)
  467. return nDir;
  468. if (pMsg->message != WM_KEYDOWN)
  469. return nDir;
  470. if (! (pMsg->wParam == VK_TAB || pMsg->wParam == VK_F6))
  471. return nDir;
  472. nDir = (GetKeyState(VK_SHIFT) < 0) ? -1 : 1;
  473. #ifdef KEYBOARDCUES
  474. HWND hwndParent = GetParent(pMsg->hwnd);
  475. if (hwndParent)
  476. SendMessage(hwndParent, WM_CHANGEUISTATE, MAKEWPARAM(UIS_CLEAR, UISF_HIDEFOCUS), 0);
  477. #endif
  478. return nDir ;
  479. }
  480. BOOL IsVK_CtlTABCycler(MSG *pMsg)
  481. {
  482. if (IsVK_TABCycler(pMsg))
  483. {
  484. if (GetKeyState(VK_CONTROL) < 0 || (pMsg->wParam == VK_F6))
  485. return TRUE;
  486. }
  487. return FALSE;
  488. }
  489. const ITEMIDLIST s_idlNULL = { 0 } ;
  490. // Copied from shell32 (was _ILCreate), which does not export this.
  491. // The fsmenu code needs this function.
  492. STDAPI_(LPITEMIDLIST) IEILCreate(UINT cbSize)
  493. {
  494. LPITEMIDLIST pidl = (LPITEMIDLIST)SHAlloc(cbSize);
  495. if (pidl)
  496. memset(pidl, 0, cbSize); // needed for external task allicator
  497. return pidl;
  498. }
  499. void SaveDefaultFolderSettings(UINT flags)
  500. {
  501. ASSERT(!(flags & ~GFSS_VALID));
  502. if (flags & GFSS_SETASDEFAULT)
  503. g_dfs.dwDefRevCount++;
  504. SKSetValue(SHELLKEY_HKCU_EXPLORER, REGVALUE_STREAMS, TEXT("Settings"), REG_BINARY, &g_dfs, sizeof(g_dfs));
  505. }
  506. BOOL ViewIDFromViewMode(UINT uViewMode, SHELLVIEWID *pvid)
  507. {
  508. switch (uViewMode)
  509. {
  510. case FVM_ICON:
  511. *pvid = VID_LargeIcons;
  512. break;
  513. case FVM_SMALLICON:
  514. *pvid = VID_SmallIcons;
  515. break;
  516. case FVM_LIST:
  517. *pvid = VID_List;
  518. break;
  519. case FVM_DETAILS:
  520. *pvid = VID_Details;
  521. break;
  522. case FVM_THUMBNAIL:
  523. *pvid = VID_Thumbnails;
  524. break;
  525. case FVM_TILE:
  526. *pvid = VID_Tile;
  527. break;
  528. default:
  529. *pvid = VID_LargeIcons;
  530. return(FALSE);
  531. }
  532. return(TRUE);
  533. }
  534. // This is a hack for IE6 23652 Beta 2. Remove in Whistler RC 1.
  535. BOOL CheckForOutlookExpress()
  536. {
  537. HKEY hKeyMail = NULL;
  538. HKEY hKeyOE = NULL;
  539. DWORD dwErr = 0;
  540. TCHAR szBuf[MAX_PATH];
  541. BOOL bRet = FALSE;
  542. // Open the key for default internet mail client
  543. // HKLM\Software\Clients\Mail
  544. dwErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\Clients\\Mail"), 0, KEY_QUERY_VALUE, &hKeyMail);
  545. if(dwErr != ERROR_SUCCESS)
  546. {
  547. // DebugTrace( TEXT("RegopenKey %s Failed -> %u\n"), szDefMailKey, dwErr);
  548. goto out;
  549. }
  550. dwErr = SHRegGetString(hKeyMail, NULL, NULL, szBuf, ARRAYSIZE(szBuf));
  551. if(dwErr != ERROR_SUCCESS)
  552. {
  553. goto out;
  554. }
  555. if(!lstrcmpi(szBuf, TEXT("Outlook Express")))
  556. {
  557. // Yes its outlook express ..
  558. bRet = TRUE;
  559. }
  560. out:
  561. if(hKeyOE)
  562. RegCloseKey(hKeyOE);
  563. if(hKeyMail)
  564. RegCloseKey(hKeyMail);
  565. return bRet;
  566. }
  567. HRESULT DropOnMailRecipient(IDataObject *pdtobj, DWORD grfKeyState)
  568. {
  569. IDropTarget *pdrop;
  570. HRESULT hres = CoCreateInstance(CLSID_MailRecipient,
  571. NULL, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
  572. IID_PPV_ARG(IDropTarget, &pdrop));
  573. ULONG_PTR uCookie = 0;
  574. if (CheckForOutlookExpress())
  575. {
  576. SHActivateContext(&uCookie);
  577. }
  578. if (SUCCEEDED(hres))
  579. {
  580. hres = SHSimulateDrop(pdrop, pdtobj, grfKeyState, NULL, NULL);
  581. pdrop->Release();
  582. }
  583. if (uCookie)
  584. {
  585. SHDeactivateContext(uCookie);
  586. }
  587. return hres;
  588. }
  589. //
  590. // This function cannot return Non -NULL pointers if
  591. // it returns a FAILED(hr)
  592. //
  593. HRESULT CreateShortcutSetSiteAndGetDataObjectIfPIDLIsNetUrl(
  594. LPCITEMIDLIST pidl,
  595. IUnknown *pUnkSite,
  596. IUniformResourceLocator **ppUrlOut,
  597. IDataObject **ppdtobj
  598. )
  599. {
  600. HRESULT hr;
  601. TCHAR szUrl[MAX_URL_STRING];
  602. ASSERT(ppUrlOut);
  603. ASSERT(ppdtobj);
  604. *ppUrlOut = NULL;
  605. *ppdtobj = NULL;
  606. szUrl[0] = TEXT('\0');
  607. hr = IEGetNameAndFlags(pidl, SHGDN_FORPARSING, szUrl, SIZECHARS(szUrl), NULL);
  608. if ((S_OK == hr) && (*szUrl))
  609. {
  610. BOOL fIsHTML = FALSE;
  611. BOOL fHitsNet = UrlHitsNetW(szUrl);
  612. if (!fHitsNet)
  613. {
  614. if (URL_SCHEME_FILE == GetUrlScheme(szUrl))
  615. {
  616. TCHAR *szExt = PathFindExtension(szUrl);
  617. if (szExt)
  618. {
  619. fIsHTML = ((0 == StrCmpNI(szExt, TEXT(".htm"),4)) ||
  620. (0 == StrCmpNI(szExt, TEXT(".html"),5)));
  621. }
  622. }
  623. }
  624. if (fHitsNet || fIsHTML)
  625. {
  626. // Create a shortcut object and
  627. HRESULT hr = CoCreateInstance(CLSID_InternetShortcut, NULL, CLSCTX_INPROC_SERVER,
  628. IID_PPV_ARG(IUniformResourceLocator, ppUrlOut));
  629. if (SUCCEEDED(hr))
  630. {
  631. hr = (*ppUrlOut)->SetURL(szUrl, 0);
  632. if (S_OK == hr)
  633. {
  634. // Get the IDataObject and send that back for the Drag Drop
  635. hr = (*ppUrlOut)->QueryInterface(IID_PPV_ARG(IDataObject, ppdtobj));
  636. if (SUCCEEDED(hr))
  637. {
  638. IUnknown_SetSite(*ppUrlOut, pUnkSite); // Only set the site if we're sure of
  639. // returning SUCCESS
  640. }
  641. }
  642. }
  643. }
  644. else
  645. {
  646. hr = E_FAIL;
  647. }
  648. }
  649. if (FAILED(hr))
  650. {
  651. SAFERELEASE(*ppUrlOut);
  652. SAFERELEASE(*ppdtobj);
  653. }
  654. return hr;
  655. }
  656. HRESULT SendDocToMailRecipient(LPCITEMIDLIST pidl, UINT uiCodePage, DWORD grfKeyState, IUnknown *pUnkSite)
  657. {
  658. IDataObject *pdtobj = NULL;
  659. IUniformResourceLocator *purl = NULL;
  660. HRESULT hr = CreateShortcutSetSiteAndGetDataObjectIfPIDLIsNetUrl(pidl, pUnkSite, &purl, &pdtobj);
  661. if (FAILED(hr))
  662. {
  663. ASSERT(NULL == pdtobj);
  664. ASSERT(NULL == purl);
  665. hr = GetDataObjectForPidl(pidl, &pdtobj);
  666. }
  667. if (SUCCEEDED(hr))
  668. {
  669. IQueryCodePage * pQcp;
  670. if (SUCCEEDED(pdtobj->QueryInterface(IID_PPV_ARG(IQueryCodePage, &pQcp))))
  671. {
  672. pQcp->SetCodePage(uiCodePage);
  673. pQcp->Release();
  674. }
  675. hr = DropOnMailRecipient(pdtobj, grfKeyState);
  676. pdtobj->Release();
  677. }
  678. if (purl)
  679. {
  680. IUnknown_SetSite(purl, NULL);
  681. purl->Release();
  682. }
  683. return hr;
  684. }
  685. #ifdef DEBUG
  686. /****************************************************\
  687. FUNCTION: Dbg_PidlStr
  688. DESCRIPTION:
  689. Create a display name for the pidl passed in
  690. and store the display name in pszBuffer.
  691. \****************************************************/
  692. LPTSTR Dbg_PidlStr(LPCITEMIDLIST pidl, LPTSTR pszBuffer, DWORD cchBufferSize)
  693. {
  694. if (pidl)
  695. {
  696. if (ILIsRooted(pidl))
  697. {
  698. StringCchCopy(pszBuffer, cchBufferSize, TEXT("<ROOTED>")); // ok to truncate for debug display only
  699. }
  700. else
  701. {
  702. IEGetNameAndFlags(pidl, SHGDN_FORPARSING, pszBuffer, cchBufferSize, NULL);
  703. }
  704. }
  705. else
  706. {
  707. StringCchCopy(pszBuffer, cchBufferSize, TEXT("<NULL>")); // ok to truncate for debug display only
  708. }
  709. return pszBuffer;
  710. }
  711. #endif // DEBUG
  712. #ifdef DEBUG
  713. #define MAX_DEPTH 8
  714. void Dbg_RecursiveDumpMenu(HMENU hmenu, int iDepth)
  715. {
  716. if (!hmenu || iDepth > MAX_DEPTH)
  717. return;
  718. TCHAR szTabs[MAX_DEPTH + 1];
  719. for (int i = 0; i < iDepth; i++)
  720. {
  721. szTabs[i] = '\t';
  722. }
  723. szTabs[iDepth] = '\0';
  724. int cItems = GetMenuItemCount(hmenu);
  725. for (i = 0; i < cItems; i++)
  726. {
  727. MENUITEMINFO mii;
  728. mii.cbSize = sizeof(MENUITEMINFO);
  729. mii.fMask = MIIM_ID | MIIM_SUBMENU | MIIM_TYPE;
  730. TCHAR szTmp[64];
  731. mii.dwTypeData = szTmp;
  732. mii.cch = ARRAYSIZE(szTmp);
  733. if (GetMenuItemInfoWrap(hmenu, i, TRUE, &mii))
  734. {
  735. LPTSTR pszType;
  736. if (mii.fType == MFT_STRING && mii.dwTypeData)
  737. pszType = mii.dwTypeData;
  738. else
  739. pszType = TEXT("");
  740. TraceMsg(TF_ALWAYS, "%swID %x\tfType %x\t%s", szTabs, mii.wID, mii.fType, pszType);
  741. if (mii.hSubMenu)
  742. {
  743. Dbg_RecursiveDumpMenu(mii.hSubMenu, iDepth + 1);
  744. }
  745. }
  746. }
  747. }
  748. // FUNCTION: Dbg_DumpMenu
  749. //
  750. // walk hmenu & dump every item
  751. void Dbg_DumpMenu(LPCTSTR psz, HMENU hmenu)
  752. {
  753. if (IsFlagSet(g_dwDumpFlags, DF_DEBUGMENU))
  754. {
  755. TraceMsg(TF_ALWAYS, "Dumping hmenu %x (%s)", hmenu, psz);
  756. Dbg_RecursiveDumpMenu(hmenu, 0);
  757. TraceMsg(TF_ALWAYS, "End hmenu dump");
  758. }
  759. }
  760. #endif
  761. // evil evil evil. for browse only mode support. not the right way to do things
  762. STDAPI LookForDesktopIniText(IShellFolder *psf, LPCITEMIDLIST pidl, LPCTSTR pszKey, LPTSTR pszBuffer, DWORD cbSize);
  763. #define CLSID_SIZE 40
  764. HRESULT LoadHandler(const CLSID * pCLSID, LPCWSTR pszBuffer, REFIID riid, void **ppvObj)
  765. {
  766. ASSERT(pszBuffer);
  767. CLSID clsid;
  768. if (!pCLSID)
  769. {
  770. // find the extension first ....
  771. // REARCHITECT - Shouldn't this be PathFindExtension?
  772. // Otherwise we will get confused by "foo.bar\baz"
  773. LPCWSTR pszDot = StrRChrW(pszBuffer, NULL, WCHAR('.'));
  774. if (!pszDot)
  775. {
  776. return E_NOINTERFACE;
  777. }
  778. HKEY hKey;
  779. LONG lRes = RegOpenKeyEx(HKEY_CLASSES_ROOT, pszDot, 0, KEY_QUERY_VALUE, &hKey);
  780. if (lRes != ERROR_SUCCESS)
  781. {
  782. return E_NOINTERFACE;
  783. }
  784. TCHAR szSubKey[CLSID_SIZE + 10];
  785. TCHAR szCLSID[CLSID_SIZE];
  786. DWORD dwType = REG_SZ;
  787. lRes = ERROR_FILE_NOT_FOUND;
  788. HRESULT hr = StringCchCopy(szSubKey, ARRAYSIZE(szSubKey), TEXT("shellex\\"));
  789. if (SUCCEEDED(hr))
  790. {
  791. int cch = SHStringFromGUID(riid, szSubKey + 8, ARRAYSIZE(szSubKey) - 8);
  792. if (cch != 0)
  793. {
  794. DWORD cbSize = sizeof(szCLSID);
  795. // should we test for a value as well as a key ?
  796. lRes = SHGetValue(hKey, szSubKey, TEXT(""), &dwType, szCLSID, &cbSize);
  797. }
  798. }
  799. RegCloseKey(hKey);
  800. if (lRes != ERROR_SUCCESS || dwType != REG_SZ)
  801. {
  802. return E_NOINTERFACE;
  803. }
  804. if (!GUIDFromString(szCLSID, &clsid))
  805. {
  806. return E_NOINTERFACE;
  807. }
  808. pCLSID = &clsid;
  809. }
  810. ASSERT(pCLSID);
  811. IPersistFile *pFile;
  812. HRESULT hr = CoCreateInstance(*pCLSID, NULL, CLSCTX_INPROC_SERVER,
  813. IID_PPV_ARG(IPersistFile, &pFile));
  814. if (FAILED(hr))
  815. {
  816. return E_NOINTERFACE;
  817. }
  818. *ppvObj = NULL;
  819. hr = pFile->Load(pszBuffer, TRUE);
  820. if (SUCCEEDED(hr))
  821. {
  822. hr = pFile->QueryInterface(riid, ppvObj);
  823. }
  824. ATOMICRELEASE(pFile);
  825. return hr;
  826. }
  827. // routine used to make us think it really came from the right place....
  828. HRESULT FakeGetUIObjectOf(IShellFolder *psf, LPCITEMIDLIST pidl, UINT * prgfFlags, REFIID riid, void **ppvObj)
  829. {
  830. HRESULT hr = E_NOINTERFACE;
  831. if (WhichPlatform() == PLATFORM_INTEGRATED)
  832. {
  833. // we are on Nashville try the new mechanism first...
  834. hr = psf->GetUIObjectOf(NULL, 1, & pidl, riid, NULL, ppvObj);
  835. if (SUCCEEDED(hr))
  836. {
  837. return hr;
  838. }
  839. }
  840. // failure cases...
  841. if (riid == IID_IExtractImage || riid == IID_IExtractLogo || riid == IID_IQueryInfo)
  842. {
  843. // make sure this hacked up code is only executed for browser only release....
  844. // otherwise people will not register their stuff right and what a mess that will be.....
  845. if (WhichPlatform() == PLATFORM_INTEGRATED)
  846. {
  847. return hr;
  848. }
  849. // try the IconExtractor first ....
  850. IExtractIconA *pIcon;
  851. hr = psf->GetUIObjectOf(NULL, 1, &pidl, IID_X_PPV_ARG(IExtractIconA, NULL, &pIcon));
  852. if (SUCCEEDED(hr))
  853. {
  854. if (riid != IID_IQueryInfo)
  855. {
  856. hr = pIcon->QueryInterface(IID_IExtractLogo, ppvObj);
  857. ATOMICRELEASE(pIcon);
  858. if (SUCCEEDED(hr))
  859. return NOERROR;
  860. }
  861. else
  862. {
  863. hr = pIcon->QueryInterface(IID_IQueryInfo, ppvObj);
  864. ATOMICRELEASE(pIcon);
  865. //if someone is asking for an IQueryInfo, don't try giving them an IExtractImage
  866. return hr;
  867. }
  868. }
  869. // browser mode only hack so we can detect if we are asking for the normal logo or the wide one...
  870. LPCTSTR pszTag = TEXT("Logo");
  871. if (prgfFlags != NULL && *prgfFlags)
  872. {
  873. pszTag = TEXT("WideLogo");
  874. }
  875. TCHAR szBuffer[MAX_PATH];
  876. hr = LookForDesktopIniText(psf, pidl, pszTag, szBuffer, ARRAYSIZE(szBuffer));
  877. if (SUCCEEDED(hr))
  878. {
  879. // use IID_IExtractImage, this is the same interface as IExtractLogo, just IExtractLogo
  880. // allows us to restrict the things that show up in Logo View...
  881. hr = LoadHandler(NULL, szBuffer, IID_IExtractImage, ppvObj);
  882. }
  883. }
  884. return hr;
  885. }
  886. BOOL GetInfoTipEx(IShellFolder* psf, DWORD dwFlags, LPCITEMIDLIST pidl, LPTSTR pszText, int cchTextMax)
  887. {
  888. BOOL fRet = FALSE;
  889. *pszText = 0; // empty for failure
  890. if (pidl)
  891. {
  892. IQueryInfo *pqi;
  893. if (SUCCEEDED(psf->GetUIObjectOf(NULL, 1, &pidl, IID_X_PPV_ARG(IQueryInfo, NULL, &pqi))))
  894. {
  895. WCHAR *pwszTip;
  896. pqi->GetInfoTip(dwFlags, &pwszTip);
  897. if (pwszTip)
  898. {
  899. fRet = TRUE;
  900. SHUnicodeToTChar(pwszTip, pszText, cchTextMax);
  901. SHFree(pwszTip);
  902. }
  903. pqi->Release();
  904. }
  905. else if (SUCCEEDED(FakeGetUIObjectOf(psf, pidl, 0, IID_PPV_ARG(IQueryInfo, &pqi))))
  906. {
  907. WCHAR *pwszTip;
  908. pqi->GetInfoTip(0, &pwszTip);
  909. if (pwszTip)
  910. {
  911. fRet = TRUE;
  912. SHUnicodeToTChar(pwszTip, pszText, cchTextMax);
  913. SHFree(pwszTip);
  914. }
  915. pqi->Release();
  916. }
  917. }
  918. return fRet;
  919. }
  920. BOOL GetInfoTip(IShellFolder* psf, LPCITEMIDLIST pidl, LPTSTR pszText, int cchTextMax)
  921. {
  922. return GetInfoTipEx(psf, 0, pidl, pszText, cchTextMax);
  923. }
  924. #define MAX_CLASS 80 // From ..\shell32\fstreex.c
  925. BOOL IsBrowsableShellExt(LPCITEMIDLIST pidl)
  926. {
  927. DWORD cb;
  928. LPCTSTR pszExt;
  929. TCHAR szFile[MAX_PATH];
  930. TCHAR szProgID[MAX_CLASS];
  931. TCHAR szCLSID[GUIDSTR_MAX], szCATID[GUIDSTR_MAX];
  932. TCHAR szKey[GUIDSTR_MAX * 4];
  933. HKEY hkeyProgID = NULL;
  934. BOOL fRet = FALSE;
  935. for (;;)
  936. {
  937. // Make sure we have a file extension
  938. if (
  939. !SHGetPathFromIDList(pidl, szFile)
  940. ||
  941. ((pszExt = PathFindExtension(szFile)) == NULL)
  942. ||
  943. (pszExt[0] != TEXT('.'))
  944. )
  945. {
  946. break;
  947. }
  948. // Get the ProgID.
  949. cb = sizeof(szProgID);
  950. if (
  951. (SHGetValue(HKEY_CLASSES_ROOT, pszExt, NULL, NULL, szProgID, &cb) != ERROR_SUCCESS)
  952. ||
  953. (RegOpenKeyEx(HKEY_CLASSES_ROOT, szProgID, 0, KEY_QUERY_VALUE, &hkeyProgID) != ERROR_SUCCESS)
  954. )
  955. {
  956. break;
  957. }
  958. // From the ProgID, get the CLSID.
  959. cb = sizeof(szCLSID);
  960. if (SHGetValue(hkeyProgID, TEXT("CLSID"), NULL, NULL, szCLSID, &cb) != ERROR_SUCCESS)
  961. break;
  962. // Construct the registry key that detects if
  963. // a CLSID is a member of a CATID.
  964. SHStringFromGUID(CATID_BrowsableShellExt, szCATID, ARRAYSIZE(szCATID));
  965. HRESULT hr = StringCchPrintf(szKey, ARRAYSIZE(szKey),
  966. TEXT("CLSID\\%s\\Implemented Categories\\%s"),
  967. szCLSID, szCATID);
  968. if (FAILED(hr))
  969. break;
  970. // See if it's there.
  971. cb = 0;
  972. if (SHGetValue(HKEY_CLASSES_ROOT, szKey, NULL, NULL, NULL, &cb) != ERROR_SUCCESS)
  973. break;
  974. fRet = TRUE;
  975. break;
  976. }
  977. if (hkeyProgID != NULL)
  978. RegCloseKey(hkeyProgID);
  979. return fRet;
  980. }
  981. void OpenFolderPidl(LPCITEMIDLIST pidl)
  982. {
  983. SHELLEXECUTEINFO shei = { 0 };
  984. shei.cbSize = sizeof(shei);
  985. shei.fMask = SEE_MASK_INVOKEIDLIST;
  986. shei.nShow = SW_SHOWNORMAL;
  987. shei.lpIDList = (LPITEMIDLIST)pidl;
  988. ShellExecuteEx(&shei);
  989. }
  990. void OpenFolderPath(LPCTSTR pszPath)
  991. {
  992. LPITEMIDLIST pidl = ILCreateFromPath(pszPath);
  993. if (pidl)
  994. {
  995. OpenFolderPidl(pidl);
  996. ILFree(pidl);
  997. }
  998. }
  999. // NOTE: this is only called from browseui, why is it in the lib directory?
  1000. STDAPI UpdateSubscriptions()
  1001. {
  1002. #ifndef DISABLE_SUBSCRIPTIONS
  1003. HRESULT hr;
  1004. if (!SHRestricted2W(REST_NoManualUpdates, NULL, 0))
  1005. {
  1006. ISyncMgrSynchronizeInvoke *pSyncMgrInvoke;
  1007. hr = CoCreateInstance(CLSID_SyncMgr, NULL, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
  1008. IID_PPV_ARG(ISyncMgrSynchronizeInvoke, &pSyncMgrInvoke));
  1009. if (SUCCEEDED(hr))
  1010. {
  1011. hr = pSyncMgrInvoke->UpdateAll();
  1012. pSyncMgrInvoke->Release();
  1013. }
  1014. }
  1015. else
  1016. {
  1017. SHRestrictedMessageBox(NULL);
  1018. hr = S_FALSE;
  1019. }
  1020. return hr;
  1021. #else /* !DISABLE_SUBSCRIPTIONS */
  1022. return E_FAIL;
  1023. #endif /* !DISABLE_SUBSCRIPTIONS */
  1024. }
  1025. STDAPI_(int) _SHHandleUpdateImage(LPCITEMIDLIST pidlExtra)
  1026. {
  1027. SHChangeUpdateImageIDList * pUs = (SHChangeUpdateImageIDList*) pidlExtra;
  1028. if (!pUs)
  1029. {
  1030. return -1;
  1031. }
  1032. // if in the same process, or an old style notification
  1033. if (pUs->dwProcessID == GetCurrentProcessId())
  1034. {
  1035. return (int) pUs->iCurIndex;
  1036. }
  1037. else
  1038. {
  1039. WCHAR szBuffer[MAX_PATH];
  1040. int iIconIndex = pUs->iIconIndex;
  1041. UINT uFlags = pUs->uFlags;
  1042. HRESULT hr = StringCchCopy(szBuffer, ARRAYSIZE(szBuffer), pUs->szName);
  1043. if (SUCCEEDED(hr))
  1044. {
  1045. // we are in a different process, look up the hash in our index to get the right one...
  1046. return Shell_GetCachedImageIndex(szBuffer, iIconIndex, uFlags);
  1047. }
  1048. else
  1049. {
  1050. return -1;
  1051. }
  1052. }
  1053. }
  1054. // As perf, share IShellLink implementations between bands and ask
  1055. // the bandsite for an implementation. Don't rely on the bandsite
  1056. // because you never know who will host us in the future. (And bandsite
  1057. // can change to not have us hosted at save/load time. Ex: it doesn't
  1058. // set our site before loading us from the stream, which sounds buggy.)
  1059. //
  1060. HRESULT SavePidlAsLink(IUnknown* punkSite, IStream *pstm, LPCITEMIDLIST pidl)
  1061. {
  1062. HRESULT hr = E_FAIL;
  1063. IShellLinkA* psl;
  1064. if (punkSite)
  1065. hr = IUnknown_QueryService(punkSite, IID_IBandSite, IID_PPV_ARG(IShellLinkA, &psl));
  1066. if (FAILED(hr))
  1067. hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellLinkA, &psl));
  1068. if (SUCCEEDED(hr))
  1069. {
  1070. IPersistStream *pps;
  1071. hr = psl->QueryInterface(IID_PPV_ARG(IPersistStream, &pps));
  1072. if (EVAL(SUCCEEDED(hr)))
  1073. {
  1074. ASSERT(pidl);
  1075. psl->SetIDList(pidl);
  1076. hr = pps->Save(pstm, FALSE);
  1077. // Win95 and NT4 shell32 have a bug in the CShellLink implementation
  1078. // THEY DON'T NULL TERMINATE THEIR "EXTRA DATA SECTION". This causes
  1079. // the object to trash the rest of the stream when it reads back in.
  1080. // Fix this by writing the NULL out in the Browser Only case.
  1081. if (SUCCEEDED(hr) && (PLATFORM_BROWSERONLY == WhichPlatform()))
  1082. {
  1083. DWORD dw = 0;
  1084. pstm->Write(&dw, sizeof(dw), NULL);
  1085. }
  1086. pps->Release();
  1087. }
  1088. psl->Release();
  1089. }
  1090. return hr;
  1091. }
  1092. HRESULT LoadPidlAsLink(IUnknown* punkSite, IStream *pstm, LPITEMIDLIST *ppidl)
  1093. {
  1094. IShellLinkA* psl;
  1095. HRESULT hr = IUnknown_QueryService(punkSite, IID_IBandSite, IID_PPV_ARG(IShellLinkA, &psl));
  1096. if (FAILED(hr))
  1097. hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellLinkA, &psl));
  1098. if (SUCCEEDED(hr))
  1099. {
  1100. IPersistStream *pps;
  1101. hr = psl->QueryInterface(IID_PPV_ARG(IPersistStream, &pps));
  1102. if (EVAL(SUCCEEDED(hr)))
  1103. {
  1104. hr = pps->Load(pstm);
  1105. if (EVAL(SUCCEEDED(hr)))
  1106. {
  1107. hr = psl->GetIDList(ppidl);
  1108. // Don't make me resolve the link because it's soo slow because
  1109. // it often loads 80k of networking dlls.
  1110. if (!EVAL(SUCCEEDED(hr)))
  1111. {
  1112. hr = psl->Resolve(NULL, SLR_NOUPDATE | SLR_NO_UI);
  1113. if (EVAL(SUCCEEDED(hr)))
  1114. hr = psl->GetIDList(ppidl);
  1115. }
  1116. hr = *ppidl ? S_OK : E_FAIL;
  1117. }
  1118. pps->Release();
  1119. }
  1120. psl->Release();
  1121. }
  1122. return hr;
  1123. }
  1124. // AdjustECPosition
  1125. //
  1126. // purpose: because FE NT always uses WCHAR position for ComboBoxEx32
  1127. // even though we're ANSI module for EM_GETSEL/EM_SETSEL,
  1128. // we need to adjust between WCHAR and TCHAR position.
  1129. // iType: ADJUST_TO_WCHAR_POS or ADJUST_TO_TCHAR_POS
  1130. //
  1131. int AdjustECPosition(char *psz, int iPos, int iType)
  1132. {
  1133. char *pstr = psz;
  1134. int iNewPos = iPos;
  1135. if (psz && g_fRunOnFE && g_fRunningOnNT)
  1136. {
  1137. if (ADJUST_TO_WCHAR_POS == iType)
  1138. {
  1139. iNewPos = 0;
  1140. while (*pstr && (pstr - psz != iPos))
  1141. {
  1142. pstr = CharNextA(pstr);
  1143. iNewPos++;
  1144. }
  1145. }
  1146. else if (ADJUST_TO_TCHAR_POS == iType)
  1147. {
  1148. while (*pstr && iPos--)
  1149. pstr = CharNextA(pstr);
  1150. iNewPos = (int)(pstr - psz);
  1151. }
  1152. }
  1153. return iNewPos;
  1154. }
  1155. int CALLBACK _CompareIDs(LPARAM p1, LPARAM p2, LPARAM psf)
  1156. {
  1157. HRESULT hr = ((IShellFolder*)psf)->CompareIDs(0, (LPITEMIDLIST)p1, (LPITEMIDLIST)p2);
  1158. //ASSERT(SUCCEEDED(hr))
  1159. return (short)HRESULT_CODE(hr);
  1160. }
  1161. HDPA GetSortedIDList(LPITEMIDLIST pidl)
  1162. {
  1163. HDPA hdpa = DPA_Create(4);
  1164. if (hdpa)
  1165. {
  1166. IShellFolder* psf;
  1167. if (SUCCEEDED(IEBindToObject(pidl, &psf)))
  1168. {
  1169. LPENUMIDLIST penum;
  1170. SHELLSTATE ss = {0};
  1171. SHGetSetSettings(&ss, SSF_SHOWALLOBJECTS, FALSE);
  1172. if (S_OK == IShellFolder_EnumObjects(psf, NULL,
  1173. ss.fShowAllObjects ? SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN : SHCONTF_FOLDERS,
  1174. &penum))
  1175. {
  1176. LPITEMIDLIST pidl;
  1177. ULONG celt;
  1178. while (penum->Next(1, &pidl, &celt) == S_OK && celt == 1)
  1179. {
  1180. if (DPA_AppendPtr(hdpa, pidl) == -1)
  1181. {
  1182. SHFree(pidl);
  1183. }
  1184. }
  1185. penum->Release();
  1186. }
  1187. DPA_Sort(hdpa, (PFNDPACOMPARE)_CompareIDs, (LPARAM)psf);
  1188. psf->Release();
  1189. }
  1190. }
  1191. return hdpa;
  1192. }
  1193. int DPA_SHFreeCallback(void * p, void * d)
  1194. {
  1195. SHFree((LPITEMIDLIST)p);
  1196. return 1;
  1197. }
  1198. void FreeSortedIDList(HDPA hdpa)
  1199. {
  1200. DPA_DestroyCallback(hdpa, (PFNDPAENUMCALLBACK)DPA_SHFreeCallback, 0);
  1201. hdpa = NULL;
  1202. }
  1203. /****************************************************\
  1204. FUNCTION: StrCmpIWithRoot
  1205. PARAMETERS:
  1206. szDispNameIn - Str to see if it is the same as the
  1207. Display Name of the Root ISF.
  1208. fTotalStrCmp - If TRUE, pszDispNameIn has to completely equal the
  1209. Root's Display Name to succeed. If FALSE, only the first part
  1210. of pszDispNameIn needs to compare to the Root's Display Name
  1211. for this function to return successful.
  1212. ppszCachedRoot (In/Out Optional) - If this function will be called more than
  1213. once, this function will cache the string and make it run
  1214. quicker. The first time this function is called, (*ppszCachedRoot)
  1215. needs to be NULL. This function will allocate and the caller
  1216. needs to call LocalFree() when it's no longer needed.
  1217. DESCRIPTION:
  1218. This function will get the Display Name of the Root ISF (Desktop) and
  1219. see if the first cchDispNameComp chars of szDispNameIn
  1220. match that display name. S_OK will be returned if TRUE, and
  1221. S_FALSE if not.
  1222. \****************************************************/
  1223. HRESULT StrCmpIWithRoot(LPCTSTR pszDispNameIn, BOOL fTotalStrCmp, LPTSTR * ppszCachedRoot)
  1224. {
  1225. HRESULT hr;
  1226. TCHAR szDispNameTemp[MAX_PATH];
  1227. LPTSTR pszDispName = szDispNameTemp;
  1228. ASSERT(IS_VALID_STRING_PTR(pszDispNameIn, -1));
  1229. ASSERT(NULL == ppszCachedRoot || IS_VALID_WRITE_PTR(ppszCachedRoot, LPTSTR));
  1230. // Did the caller supply the display name of the namespace root?
  1231. if ((!ppszCachedRoot) ||
  1232. (ppszCachedRoot && !*ppszCachedRoot))
  1233. {
  1234. MLLoadString(IDS_DESKTOP, szDispNameTemp, SIZECHARS(szDispNameTemp));
  1235. // Cache this guy?
  1236. if (ppszCachedRoot)
  1237. {
  1238. // Yes
  1239. *ppszCachedRoot = StrDup(szDispNameTemp);
  1240. if (!*ppszCachedRoot)
  1241. return E_OUTOFMEMORY;
  1242. }
  1243. }
  1244. if (ppszCachedRoot && *ppszCachedRoot)
  1245. pszDispName = *ppszCachedRoot;
  1246. // Do we want to compare the entire string or just the first part of it?
  1247. if (fTotalStrCmp)
  1248. hr = (0 == lstrcmpi(pszDispName, pszDispNameIn)) ? S_OK : S_FALSE; // Entire String
  1249. else if (ppszCachedRoot)
  1250. {
  1251. // Compare the first part of the string
  1252. DWORD cchDispNameComp = lstrlen(*ppszCachedRoot);
  1253. hr = (0 == StrCmpNI(pszDispName, pszDispNameIn, cchDispNameComp)) ? S_OK : S_FALSE;
  1254. }
  1255. else
  1256. {
  1257. hr = S_FALSE;
  1258. }
  1259. return hr;
  1260. }
  1261. /****************************************************\
  1262. FUNCTION: GetMRUEntry
  1263. PARAMETERS:
  1264. hKey - Pointer to Registry Key to retrieve MRU entries from.
  1265. dwMRUIndex - 0 based MRU Index to retrieve.
  1266. pszMRUEntry - Location to store MRU Entry string.
  1267. cchMRUEntry - Size of Buffer in characters.
  1268. DESCRIPTION:
  1269. This function will retrieve the MRU Entry specified
  1270. by dwMRUIndex.
  1271. \****************************************************/
  1272. HRESULT GetMRUEntry(HKEY hKey, DWORD dwMRUIndex, LPTSTR pszMRUEntry, DWORD cchMRUEntry, LPITEMIDLIST * ppidl)
  1273. {
  1274. HRESULT hr = S_OK;
  1275. TCHAR szValueName[15]; // big enough for "url99999"
  1276. ASSERT(hKey);
  1277. ASSERT(pszMRUEntry);
  1278. ASSERT(cchMRUEntry);
  1279. // make a value name a la "url1" (1-based for historical reasons)
  1280. hr = StringCchPrintf(szValueName, ARRAYSIZE(szValueName), SZ_REGVAL_MRUENTRY, dwMRUIndex+1);
  1281. if (SUCCEEDED(hr))
  1282. {
  1283. cchMRUEntry *= sizeof(TCHAR);
  1284. if (ERROR_SUCCESS != SHQueryValueEx(hKey, szValueName, NULL, NULL, (LPBYTE) pszMRUEntry, &cchMRUEntry))
  1285. {
  1286. pszMRUEntry[0] = TEXT('\0');
  1287. hr = E_FAIL;
  1288. }
  1289. }
  1290. return hr;
  1291. }
  1292. /*----------------------------------------------------------
  1293. Purpose: Gets a registry value that is User Specifc.
  1294. This will open HKEY_CURRENT_USER if it exists,
  1295. otherwise it will open HKEY_LOCAL_MACHINE.
  1296. Returns: DWORD containing success or error code.
  1297. Cond: --
  1298. */
  1299. LONG OpenRegUSKey(LPCTSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult)
  1300. {
  1301. DWORD dwRet = RegOpenKeyEx(HKEY_CURRENT_USER, lpSubKey, ulOptions, samDesired, phkResult);
  1302. if (ERROR_SUCCESS != dwRet)
  1303. dwRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, lpSubKey, ulOptions, samDesired, phkResult);
  1304. return dwRet;
  1305. }
  1306. typedef struct tagSTREAMHEADER
  1307. {
  1308. DWORD dwHeaderSize;
  1309. DWORD dwDataSize;
  1310. DWORD dwSignature;
  1311. DWORD dwVersion;
  1312. } STREAMHEADER;
  1313. /****************************************************\
  1314. FUNCTION: LoadStreamHeader
  1315. PARAMETERS:
  1316. dwSignature - The signature that the caller supports
  1317. dwStartVersion - The lowest version the caller chooses to support.
  1318. dwEndVersion - The highest version the caller chooses to support.
  1319. pdwSize (OUT) - The size that the caller should read.
  1320. pdwVersionOut (OUT) - The version found.
  1321. return - if S_OK, then the caller needs to read pdwSize bytes
  1322. of data.
  1323. if S_FALSE, then the caller should use default settings
  1324. and return S_OK.
  1325. DESCRIPTION:
  1326. This function see if the caller owns this
  1327. data in the stream. If the caller does own the
  1328. stream segment, the size and version will be returned.
  1329. If the caller doesn't own the stream segment then S_FALSE is
  1330. returned to indicate that the caller should use default
  1331. data. If the caller doesn't claim to support the version
  1332. found (because of the dwStartVersion-dwEndVersion range),
  1333. then S_FALSE is returned to indicate to use default values
  1334. and this function skips over that segment in the stream
  1335. so the next segment can be parsed.
  1336. \****************************************************/
  1337. HRESULT LoadStreamHeader(IStream *pstm,
  1338. DWORD dwSignature, // What version?
  1339. DWORD dwStartVersion, // What is the earlies version supported?
  1340. DWORD dwEndVersion, // What is the oldest version supported?
  1341. DWORD * pdwSize, // What is the size to read?
  1342. DWORD * pdwVersionOut) // What version was found in the stream?
  1343. {
  1344. HRESULT hr;
  1345. STREAMHEADER shHeader;
  1346. BOOL fNotOurs = FALSE;
  1347. BOOL fSkipData = FALSE;
  1348. hr = pstm->Read(&shHeader, sizeof(shHeader), NULL);
  1349. ASSERT(pdwSize && pdwVersionOut);
  1350. *pdwSize = 0;
  1351. *pdwVersionOut = 0;
  1352. if (SUCCEEDED(hr))
  1353. {
  1354. if (shHeader.dwHeaderSize != sizeof(shHeader))
  1355. fNotOurs = TRUE;
  1356. else if (shHeader.dwSignature != dwSignature)
  1357. fNotOurs = TRUE;
  1358. else if (shHeader.dwVersion < dwStartVersion)
  1359. fSkipData = TRUE;
  1360. else if (shHeader.dwVersion > dwEndVersion)
  1361. fSkipData = TRUE;
  1362. if (fNotOurs)
  1363. {
  1364. // It's not, so reset it so the next guy will be able to read correctly.
  1365. LARGE_INTEGER li;
  1366. li.LowPart = (DWORD)-(LONG)sizeof(shHeader);
  1367. li.HighPart = 0;
  1368. hr = pstm->Seek(li, STREAM_SEEK_CUR, NULL);
  1369. hr = S_FALSE; // Means caller should use default data.
  1370. }
  1371. // Do we want to skip the Data for this part of the stream?
  1372. if (fSkipData)
  1373. {
  1374. ASSERT(STREAMSIZE_UNKNOWN != shHeader.dwDataSize); // SERIOUS, we cannot skip over data because we don't know size.
  1375. if (STREAMSIZE_UNKNOWN != shHeader.dwDataSize)
  1376. {
  1377. // Yes. The caller cannot read in this data because the caller doesn't support
  1378. // this version of the data. Therefore, we skip past the data and return S_FALSE
  1379. // to indicate to the caller that default settings should be used.
  1380. LARGE_INTEGER li;
  1381. li.LowPart = shHeader.dwDataSize;
  1382. li.HighPart = 0;
  1383. hr = pstm->Seek(li, STREAM_SEEK_CUR, NULL);
  1384. hr = S_FALSE; // Means caller should use default data.
  1385. }
  1386. }
  1387. if (!fNotOurs && !fSkipData)
  1388. {
  1389. *pdwSize = shHeader.dwDataSize;
  1390. *pdwVersionOut = shHeader.dwVersion;
  1391. }
  1392. }
  1393. return hr;
  1394. }
  1395. /****************************************************\
  1396. FUNCTION: SaveStreamHeader
  1397. DESCRIPTION:
  1398. This function will save a StreamHeader to
  1399. the stream that will allow the caller to verify
  1400. if he/she owns the data the next time it's read in.
  1401. It will also support the ability to ignore old
  1402. or future versions of data.
  1403. \****************************************************/
  1404. HRESULT SaveStreamHeader(IStream *pstm, DWORD dwSignature, DWORD dwVersion, DWORD dwSize)
  1405. {
  1406. HRESULT hr;
  1407. STREAMHEADER shHeader;
  1408. shHeader.dwHeaderSize = sizeof(STREAMHEADER);
  1409. shHeader.dwDataSize = dwSize;
  1410. shHeader.dwSignature = dwSignature;
  1411. shHeader.dwVersion = dwVersion;
  1412. hr = pstm->Write(&shHeader, sizeof(shHeader), NULL);
  1413. return hr;
  1414. }
  1415. //----------------------------------------------------------------------
  1416. //
  1417. // CMenuList
  1418. //
  1419. //----------------------------------------------------------------------
  1420. typedef struct
  1421. {
  1422. HMENU hmenu;
  1423. BITBOOL bObject:1; // TRUE: menu belongs to object
  1424. } MLITEM; // CMenuList item
  1425. CMenuList::CMenuList(void)
  1426. {
  1427. ASSERT(NULL == _hdsa);
  1428. }
  1429. CMenuList::~CMenuList(void)
  1430. {
  1431. if (_hdsa)
  1432. {
  1433. DSA_Destroy(_hdsa);
  1434. _hdsa = NULL;
  1435. }
  1436. }
  1437. /*----------------------------------------------------------
  1438. Purpose: Set the menu list (comparable to HOLEMENU) so we can
  1439. dispatch commands to the frame or the object correctly.
  1440. We do this since menu bands bypass OLE's FrameFilterWndProc.
  1441. We build the menu list by comparing the given hmenuShared
  1442. with hmenuFrame. Anything in hmenuShared that is not
  1443. in hmenuFrame belongs to the object.
  1444. */
  1445. void CMenuList::Set(HMENU hmenuShared, HMENU hmenuFrame)
  1446. {
  1447. ASSERT(NULL == hmenuShared || IS_VALID_HANDLE(hmenuShared, MENU));
  1448. ASSERT(NULL == hmenuFrame || IS_VALID_HANDLE(hmenuFrame, MENU));
  1449. if (_hdsa)
  1450. {
  1451. ASSERT(IS_VALID_HANDLE(_hdsa, DSA));
  1452. DSA_DeleteAllItems(_hdsa);
  1453. }
  1454. else
  1455. _hdsa = DSA_Create(sizeof(MLITEM), 10);
  1456. if (_hdsa && hmenuShared && hmenuFrame)
  1457. {
  1458. int i;
  1459. int iFrame = 0;
  1460. int cmenu = GetMenuItemCount(hmenuShared);
  1461. int cmenuFrame = GetMenuItemCount(hmenuFrame);
  1462. BOOL bMatched;
  1463. int iSaveFrame;
  1464. int iHaveFrame = -1;
  1465. TCHAR sz[64];
  1466. TCHAR szFrame[64];
  1467. MENUITEMINFO miiFrame;
  1468. MENUITEMINFO mii;
  1469. MLITEM mlitem;
  1470. miiFrame.cbSize = sizeof(miiFrame);
  1471. miiFrame.hSubMenu = NULL;
  1472. mii.cbSize = sizeof(mii);
  1473. for (i = 0; i < cmenu; i++)
  1474. {
  1475. mii.cch = SIZECHARS(sz);
  1476. mii.fMask = MIIM_SUBMENU | MIIM_TYPE;
  1477. mii.dwTypeData = sz;
  1478. EVAL(GetMenuItemInfoWrap(hmenuShared, i, TRUE, &mii));
  1479. ASSERT(IS_VALID_HANDLE(mii.hSubMenu, MENU));
  1480. mlitem.hmenu = mii.hSubMenu;
  1481. iSaveFrame = iFrame;
  1482. bMatched = FALSE;
  1483. // DocObject might have dropped some of our menus, like edit and view
  1484. // Need to be able to skip over dropped frame menus
  1485. while (1)
  1486. {
  1487. if (iHaveFrame != iFrame)
  1488. {
  1489. iHaveFrame = iFrame;
  1490. if (iFrame < cmenuFrame)
  1491. {
  1492. miiFrame.cch = SIZECHARS(szFrame);
  1493. miiFrame.fMask = MIIM_SUBMENU | MIIM_TYPE;
  1494. miiFrame.dwTypeData = szFrame;
  1495. EVAL(GetMenuItemInfoWrap(hmenuFrame, iFrame, TRUE, &miiFrame));
  1496. }
  1497. else
  1498. {
  1499. // Make it so it won't compare
  1500. miiFrame.hSubMenu = NULL;
  1501. *szFrame = 0;
  1502. }
  1503. }
  1504. ASSERT(iFrame >= cmenuFrame || IS_VALID_HANDLE(miiFrame.hSubMenu, MENU));
  1505. // The browser may have a menu that was not merged into
  1506. // the shared menu because the object put one in with
  1507. // the same name. Have we hit this case? Check by comparing
  1508. // sz and szFrame
  1509. if (mii.hSubMenu == miiFrame.hSubMenu || 0 == StrCmp(sz, szFrame))
  1510. {
  1511. bMatched = TRUE;
  1512. break;
  1513. }
  1514. else
  1515. {
  1516. if (iFrame >= cmenuFrame)
  1517. {
  1518. break;
  1519. }
  1520. iFrame++;
  1521. }
  1522. }
  1523. // Is this one of our menus?
  1524. mlitem.bObject = (mii.hSubMenu == miiFrame.hSubMenu) ? FALSE:TRUE;
  1525. if (bMatched)
  1526. {
  1527. iFrame++;
  1528. }
  1529. else
  1530. {
  1531. iFrame = iSaveFrame;
  1532. }
  1533. DSA_SetItem(_hdsa, i, &mlitem);
  1534. }
  1535. }
  1536. }
  1537. /*----------------------------------------------------------
  1538. Purpose: Adds the given hmenu to the list.
  1539. */
  1540. void CMenuList::AddMenu(HMENU hmenu)
  1541. {
  1542. ASSERT(NULL == hmenu || IS_VALID_HANDLE(hmenu, MENU));
  1543. if (_hdsa && hmenu)
  1544. {
  1545. MLITEM mlitem;
  1546. mlitem.hmenu = hmenu;
  1547. mlitem.bObject = TRUE;
  1548. DSA_AppendItem(_hdsa, &mlitem);
  1549. }
  1550. }
  1551. /*----------------------------------------------------------
  1552. Purpose: Removes the given hmenu from the list.
  1553. */
  1554. void CMenuList::RemoveMenu(HMENU hmenu)
  1555. {
  1556. ASSERT(NULL == hmenu || IS_VALID_HANDLE(hmenu, MENU));
  1557. if (_hdsa && hmenu)
  1558. {
  1559. int i = DSA_GetItemCount(_hdsa) - 1;
  1560. for (; i >= 0; i--)
  1561. {
  1562. MLITEM * pmlitem = (MLITEM *)DSA_GetItemPtr(_hdsa, i);
  1563. ASSERT(pmlitem);
  1564. if (hmenu == pmlitem->hmenu)
  1565. {
  1566. DSA_DeleteItem(_hdsa, i);
  1567. break;
  1568. }
  1569. }
  1570. }
  1571. }
  1572. /*----------------------------------------------------------
  1573. Purpose: Returns TRUE if the given hmenu belongs to the object.
  1574. */
  1575. BOOL CMenuList::IsObjectMenu(HMENU hmenu)
  1576. {
  1577. BOOL bRet = FALSE;
  1578. ASSERT(NULL == hmenu || IS_VALID_HANDLE(hmenu, MENU));
  1579. if (_hdsa && hmenu)
  1580. {
  1581. int i;
  1582. for (i = 0; i < DSA_GetItemCount(_hdsa); i++)
  1583. {
  1584. MLITEM * pmlitem = (MLITEM *)DSA_GetItemPtr(_hdsa, i);
  1585. ASSERT(pmlitem);
  1586. if (hmenu == pmlitem->hmenu)
  1587. {
  1588. bRet = pmlitem->bObject;
  1589. break;
  1590. }
  1591. }
  1592. }
  1593. return bRet;
  1594. }
  1595. #ifdef DEBUG
  1596. void CMenuList::Dump(LPCTSTR pszMsg)
  1597. {
  1598. if (IsFlagSet(g_dwDumpFlags, DF_DEBUGMENU))
  1599. {
  1600. TraceMsg(TF_ALWAYS, "CMenuList: Dumping menus for %#08x %s", this, pszMsg);
  1601. if (_hdsa)
  1602. {
  1603. int i;
  1604. for (i = 0; i < DSA_GetItemCount(_hdsa); i++)
  1605. {
  1606. MLITEM * pmlitem = (MLITEM *)DSA_GetItemPtr(_hdsa, i);
  1607. ASSERT(pmlitem);
  1608. TraceMsg(TF_ALWAYS, " [%d] = %x", i, pmlitem->hmenu);
  1609. }
  1610. }
  1611. }
  1612. }
  1613. #endif
  1614. #define REGVAL_FIRST_HOME_PAGE TEXT("First Home Page")
  1615. #define REGVAL_UPDATE_CHECK_PAGE TEXT("Update_Check_Page")
  1616. #define REGVAL_UPDATE_CHECK_INTERVAL TEXT("Update_Check_Interval")
  1617. #define REGVAL_LASTCHECKEDHI TEXT("LastCheckedHi")
  1618. #define REGSTR_PATH_INFODEL_REST TEXT("Software\\Policies\\Microsoft\\Internet Explorer\\Infodelivery\\Restrictions")
  1619. #define REGVAL_IEUPDATECHECK_REST TEXT("NoUpdateCheck")
  1620. #define DEFAULT_IEUPDATECHECK_PAGE TEXT("http://www.microsoft.com/isapi/redir.dll?Prd=ie&Pver=5.0&Ar=ie5update&O1=b1")
  1621. BOOL
  1622. IsUpdateCheckRestricted()
  1623. {
  1624. HKEY hkeyRest = 0;
  1625. BOOL bUpdateCheckRest = FALSE;
  1626. DWORD dwValue = 0;
  1627. DWORD dwLen = sizeof(DWORD);
  1628. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_INFODEL_REST, 0, KEY_QUERY_VALUE, &hkeyRest) == ERROR_SUCCESS)
  1629. {
  1630. if (ERROR_SUCCESS == SHRegGetDWORD(hkeyRest, NULL, REGVAL_IEUPDATECHECK_REST, &dwValue)
  1631. && dwValue)
  1632. {
  1633. bUpdateCheckRest = TRUE;
  1634. }
  1635. RegCloseKey(hkeyRest);
  1636. }
  1637. if (!bUpdateCheckRest)
  1638. {
  1639. // Check to see if the user has turned it off under advanced options
  1640. dwValue = 0;
  1641. dwLen = sizeof(DWORD);
  1642. if (SHRegGetUSValue(REGSTR_PATH_MAIN, REGVAL_IEUPDATECHECK_REST, NULL, (LPBYTE)&dwValue, &dwLen, 0,NULL,0) == ERROR_SUCCESS && dwValue)
  1643. bUpdateCheckRest = TRUE;
  1644. }
  1645. return bUpdateCheckRest;
  1646. }
  1647. HRESULT
  1648. CheckIEMinimalUpdate()
  1649. {
  1650. HRESULT hr = S_OK;
  1651. HKEY hkeyIE = 0;
  1652. TCHAR szUpdateUrl[MAX_URL_STRING];
  1653. DWORD dwSize;
  1654. DWORD dwType;
  1655. FILETIME ftlast, ftnow;
  1656. DWORD dwMagicDays = 0;
  1657. DWORD dwMagicPerDay = 201;
  1658. if (IsUpdateCheckRestricted())
  1659. {
  1660. hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
  1661. goto Exit;
  1662. }
  1663. if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_MAIN, 0, KEY_QUERY_VALUE, &hkeyIE))
  1664. {
  1665. hr = HRESULT_FROM_WIN32(GetLastError());
  1666. goto Exit;
  1667. }
  1668. if (ERROR_SUCCESS != SHRegGetDWORD(hkeyIE, NULL, REGVAL_UPDATE_CHECK_INTERVAL, &dwMagicDays)
  1669. || dwMagicDays == 0)
  1670. {
  1671. dwMagicDays = 30; // hardcode default to check every 30 days.
  1672. }
  1673. if (ERROR_SUCCESS != SHRegGetString(hkeyIE, NULL, REGVAL_UPDATE_CHECK_PAGE, szUpdateUrl, ARRAYSIZE(szUpdateUrl)))
  1674. {
  1675. hr = StringCchCopy(szUpdateUrl, ARRAYSIZE(szUpdateUrl), DEFAULT_IEUPDATECHECK_PAGE);
  1676. if (FAILED(hr))
  1677. {
  1678. szUpdateUrl[0] = TEXT('\0');
  1679. }
  1680. }
  1681. RegCloseKey(hkeyIE);
  1682. if (RegOpenKeyEx(HKEY_CURRENT_USER, REGSTR_PATH_MAIN, 0, KEY_QUERY_VALUE | KEY_SET_VALUE, &hkeyIE) == ERROR_SUCCESS)
  1683. {
  1684. dwType = REG_SZ;
  1685. dwSize = MAX_URL_STRING;
  1686. if (RegQueryValueEx(hkeyIE, REGVAL_FIRST_HOME_PAGE, NULL, &dwType,
  1687. NULL, &dwSize) == ERROR_SUCCESS)
  1688. {
  1689. // if already exists then skip this write
  1690. hr = S_FALSE;
  1691. goto Exit;
  1692. }
  1693. GetSystemTimeAsFileTime(&ftnow);
  1694. ftnow.dwLowDateTime = 0;
  1695. ZeroMemory(&ftlast, sizeof(ftlast));
  1696. if (ERROR_SUCCESS == SHRegGetDWORD(hkeyIE, NULL, REGVAL_LASTCHECKEDHI, &ftlast.dwHighDateTime))
  1697. {
  1698. ftlast.dwHighDateTime += (dwMagicPerDay * dwMagicDays);
  1699. }
  1700. if (CompareFileTime(&ftlast, &ftnow) > 0)
  1701. {
  1702. hr = S_FALSE;
  1703. }
  1704. else if (szUpdateUrl[0] == TEXT('\0'))
  1705. {
  1706. hr = E_FAIL;
  1707. }
  1708. else
  1709. {
  1710. RegSetValueEx(hkeyIE,REGVAL_FIRST_HOME_PAGE, NULL,
  1711. REG_SZ,(LPBYTE)szUpdateUrl, (lstrlen(szUpdateUrl)+1)*sizeof(TCHAR));
  1712. RegSetValueEx(hkeyIE, REGVAL_LASTCHECKEDHI, NULL, REG_DWORD,
  1713. (unsigned char *)&ftnow.dwHighDateTime, sizeof(DWORD));
  1714. }
  1715. RegCloseKey(hkeyIE);
  1716. }
  1717. Exit:
  1718. return hr;
  1719. }
  1720. static BOOL s_fSUCheckComplete = FALSE;
  1721. // returns:
  1722. // TRUE The user clicked Update Now and we ShellExe'ed
  1723. // the update URL.
  1724. // FALSE We did not launch a browser to the update page.
  1725. // NOTE: the "run-once-ness" of this is controlled by the ICW check
  1726. // variable g_fICWCheckComplete.
  1727. BOOL CheckSoftwareUpdateUI(HWND hwndOwner, IShellBrowser *pisb)
  1728. {
  1729. BOOL fLaunchUpdate = FALSE;
  1730. #ifndef UNIX
  1731. HRESULT hr = S_OK;
  1732. int nRes;
  1733. SOFTDISTINFO sdi = { 0 };
  1734. sdi.cbSize = sizeof(SOFTDISTINFO);
  1735. if (s_fSUCheckComplete)
  1736. return FALSE;
  1737. else
  1738. s_fSUCheckComplete = TRUE;
  1739. // We're putting up a message box, so make the msg pump modal
  1740. pisb->EnableModelessSB(FALSE);
  1741. nRes = SoftwareUpdateMessageBox(hwndOwner, awchMSIE4GUID, 0, &sdi);
  1742. pisb->EnableModelessSB(TRUE);
  1743. if (nRes != IDABORT)
  1744. {
  1745. if (nRes == IDYES)
  1746. {
  1747. // Okay, we tried to do this a couple of different ways.
  1748. // Originally, this was done with ShellExecEx. This failed
  1749. // because the http hook wasn't 100% reliable on Win95.
  1750. // The next stab was to:
  1751. //LPITEMIDLIST pidl;
  1752. // The user wants to navigate to the install page.
  1753. //hr = pibs->IEParseDisplayName(CP_ACP, sdi.szHREF, &pidl);
  1754. //if (SUCCEEDED(hr))
  1755. //{
  1756. // OpenFolderPidl(pidl);
  1757. // ILFree(pidl);
  1758. //}
  1759. hr = NavToUrlUsingIEW(sdi.szHREF, TRUE);
  1760. } // if user wants update
  1761. if (sdi.szTitle != NULL)
  1762. CoTaskMemFree(sdi.szTitle);
  1763. if (sdi.szAbstract != NULL)
  1764. CoTaskMemFree(sdi.szAbstract);
  1765. if (sdi.szHREF != NULL)
  1766. CoTaskMemFree(sdi.szHREF);
  1767. fLaunchUpdate = nRes == IDYES && SUCCEEDED(hr);
  1768. }
  1769. if (!fLaunchUpdate)
  1770. {
  1771. // for minimal install of IE every N days or so we want to
  1772. // hijack the home page to check if an update is available
  1773. // for us.
  1774. CheckIEMinimalUpdate();
  1775. }
  1776. #endif
  1777. return fLaunchUpdate;
  1778. }
  1779. BOOL g_fICWCheckComplete = FALSE;
  1780. // returns:
  1781. // TRUE Internet Connection Wizard (ICW) was run, and we should exit
  1782. // the browser since we likely need to restart the system
  1783. // FALSE did not run the ICW, continue on as normal
  1784. BOOL CheckRunICW(LPCTSTR pszURL)
  1785. {
  1786. if (g_fICWCheckComplete)
  1787. return FALSE;
  1788. DWORD dwICWCompleted = 0;
  1789. BOOL fRet = FALSE;
  1790. // Check if ICW has already been run
  1791. DWORD dwSize = sizeof(dwICWCompleted);
  1792. SHGetValue(HKEY_CURRENT_USER, TEXT(ICW_REGPATHSETTINGS), TEXT(ICW_REGKEYCOMPLETED), NULL, &dwICWCompleted, &dwSize);
  1793. if (!dwICWCompleted)
  1794. {
  1795. HINSTANCE hInetCfgDll = LoadLibrary(TEXT("inetcfg.dll"));
  1796. // set this to TRUE here so that if there's an error in loading the dll, or getting the proc address,
  1797. // we don't keep trying to do that.
  1798. g_fICWCheckComplete = TRUE;
  1799. if (hInetCfgDll)
  1800. {
  1801. PFNCHECKCONNECTIONWIZARD fp = (PFNCHECKCONNECTIONWIZARD)GetProcAddress(hInetCfgDll, "CheckConnectionWizard");
  1802. if (fp)
  1803. {
  1804. DWORD dwRet;
  1805. DWORD dwFlags = ICW_LAUNCHFULL | ICW_LAUNCHMANUAL | ICW_FULL_SMARTSTART;
  1806. if (pszURL)
  1807. {
  1808. PFNSETSHELLNEXT fpSetShellNext = (PFNSETSHELLNEXT)GetProcAddress(hInetCfgDll, "SetShellNext");
  1809. if (fpSetShellNext)
  1810. {
  1811. CHAR szAnsiUrl[MAX_URL_STRING];
  1812. SHTCharToAnsi(pszURL, szAnsiUrl, ARRAYSIZE(szAnsiUrl));
  1813. dwFlags |= ICW_USE_SHELLNEXT;
  1814. fpSetShellNext(szAnsiUrl);
  1815. }
  1816. }
  1817. // if we get this far, set the fICWCheckComplete back to FALSE (had to be false since we didn't early out)
  1818. // and let the ICW set the reg key. this is so that if the user decides to cancel and come back later,
  1819. // we respect that.
  1820. g_fICWCheckComplete = FALSE;
  1821. // Launch ICW full or manual path, whichever is available
  1822. // NOTE: the ICW code makes sure only a single instance is up
  1823. fp(dwFlags, &dwRet);
  1824. // If it was launched successfully, we need to exit
  1825. // since ICW may restart the machine if it needs to
  1826. // install system files.
  1827. if (dwRet & (ICW_LAUNCHEDFULL | ICW_LAUNCHEDMANUAL))
  1828. {
  1829. fRet = TRUE;
  1830. }
  1831. }
  1832. FreeLibrary(hInetCfgDll);
  1833. }
  1834. }
  1835. else
  1836. {
  1837. g_fICWCheckComplete = TRUE;
  1838. }
  1839. return fRet;
  1840. }
  1841. int GetColorComponent(LPSTR *ppsz)
  1842. {
  1843. int iColor = 0;
  1844. if (*ppsz)
  1845. {
  1846. LPSTR pBuf = *ppsz;
  1847. iColor = StrToIntA(pBuf);
  1848. // find the next comma
  1849. while(pBuf && *pBuf && *pBuf!=L',')
  1850. pBuf++;
  1851. // if valid and not NULL...
  1852. if (pBuf && *pBuf)
  1853. pBuf++; // increment
  1854. *ppsz = pBuf;
  1855. }
  1856. return iColor;
  1857. }
  1858. // Read the registry for a string (REG_SZ) of comma separated RGB values
  1859. COLORREF RegGetColorRefString(HKEY hkey, LPTSTR RegValue, COLORREF Value)
  1860. {
  1861. CHAR SmallBuf[80];
  1862. CHAR szRegKey[MAXIMUM_SUB_KEY_LENGTH];
  1863. LPSTR pszBuf;
  1864. DWORD cb;
  1865. int iRed, iGreen, iBlue;
  1866. SHTCharToAnsi(RegValue, szRegKey, ARRAYSIZE(szRegKey));
  1867. cb = sizeof(SmallBuf);
  1868. if (SHQueryValueExA(hkey, szRegKey, NULL, NULL, (LPBYTE)&SmallBuf, &cb)
  1869. == ERROR_SUCCESS)
  1870. {
  1871. pszBuf = SmallBuf;
  1872. iRed = GetColorComponent(&pszBuf);
  1873. iGreen = GetColorComponent(&pszBuf);
  1874. iBlue = GetColorComponent(&pszBuf);
  1875. // make sure all values are valid
  1876. iRed %= 256;
  1877. iGreen %= 256;
  1878. iBlue %= 256;
  1879. Value = RGB(iRed, iGreen, iBlue);
  1880. }
  1881. return Value;
  1882. }
  1883. LRESULT SetHyperlinkCursor(IShellFolder* pShellFolder, LPCITEMIDLIST pidl)
  1884. {
  1885. HCURSOR hCursor;
  1886. BOOL fCursorSet = FALSE;
  1887. if (!pidl)
  1888. return 0;
  1889. if (SHIsGlobalOffline())
  1890. {
  1891. IQueryInfo *pqi;
  1892. if (SUCCEEDED(pShellFolder->GetUIObjectOf(NULL, 1, &pidl, IID_X_PPV_ARG(IQueryInfo, NULL, &pqi))))
  1893. {
  1894. DWORD dwFlags = 0;
  1895. if (SUCCEEDED(pqi->GetInfoFlags(&dwFlags)))
  1896. {
  1897. if (0 == (dwFlags & QIF_CACHED))
  1898. {
  1899. // Load Offline cursor since not cached
  1900. hCursor = (HCURSOR)LoadCursor(HINST_THISDLL, MAKEINTRESOURCE(IDC_OFFLINE_HAND));
  1901. if (hCursor)
  1902. {
  1903. SetCursor(hCursor);
  1904. fCursorSet = TRUE;
  1905. }
  1906. }
  1907. }
  1908. pqi->Release();
  1909. }
  1910. }
  1911. if (!fCursorSet)
  1912. {
  1913. // For whatever reason, offline cursor was not set
  1914. hCursor = LoadHandCursor(0);
  1915. if (hCursor)
  1916. SetCursor(hCursor);
  1917. }
  1918. return 1;
  1919. }
  1920. BOOL IsSubscribableA(LPCSTR pszUrl)
  1921. {
  1922. // REARCHITECT: this should be method on the subscription mgr interface - zekel
  1923. DWORD dwScheme = GetUrlSchemeA(pszUrl);
  1924. return (dwScheme == URL_SCHEME_HTTP) || (dwScheme == URL_SCHEME_HTTPS);
  1925. }
  1926. BOOL IsSubscribableW(LPCWSTR pwzUrl)
  1927. {
  1928. // REARCHITECT: this should be method on the subscription mgr interface - zekel
  1929. DWORD dwScheme = GetUrlSchemeW(pwzUrl);
  1930. return (dwScheme == URL_SCHEME_HTTP) || (dwScheme == URL_SCHEME_HTTPS);
  1931. }
  1932. HWND GetTrayWindow()
  1933. {
  1934. #ifndef UNIX
  1935. static HWND s_hwndTray = NULL;
  1936. if (!IsWindow(s_hwndTray))
  1937. {
  1938. s_hwndTray = FindWindow(TEXT(WNDCLASS_TRAYNOTIFY), NULL);
  1939. }
  1940. return s_hwndTray;
  1941. #else
  1942. return NULL;
  1943. #endif
  1944. }
  1945. void FireEventSzA(LPCSTR szEvent)
  1946. {
  1947. HANDLE hEvent = OpenEventA(EVENT_MODIFY_STATE, FALSE, szEvent);
  1948. if (hEvent)
  1949. {
  1950. SetEvent(hEvent);
  1951. CloseHandle(hEvent);
  1952. }
  1953. }
  1954. void FireEventSzW(LPCWSTR pszEvent)
  1955. {
  1956. USES_CONVERSION;
  1957. FireEventSzA(W2A(pszEvent));
  1958. }
  1959. BOOL IsNamedWindow(HWND hwnd, LPCTSTR pszClass)
  1960. {
  1961. #ifndef UNIX
  1962. TCHAR szClass[32];
  1963. #else // UNIX use this function for trident dialog window
  1964. TCHAR szClass[64];
  1965. #endif
  1966. GetClassName(hwnd, szClass, ARRAYSIZE(szClass));
  1967. return lstrcmp(szClass, pszClass) == 0;
  1968. }
  1969. BOOL IsExplorerWindow(HWND hwnd)
  1970. {
  1971. return IsNamedWindow(hwnd, c_szExploreClass);
  1972. }
  1973. BOOL IsFolderWindow(HWND hwnd)
  1974. {
  1975. TCHAR szClass[32];
  1976. GetClassName(hwnd, szClass, ARRAYSIZE(szClass));
  1977. return (lstrcmp(szClass, c_szCabinetClass) == 0) || (lstrcmp(szClass, c_szIExploreClass) == 0);
  1978. }
  1979. // returns TRUE if the unknown is on a window that was opened as IE
  1980. // returns FALSE if the window was opened on the shell namespace, even if it's now showing a web page
  1981. // returns FALSE in other cases e.g. on the taskbar
  1982. STDAPI_(BOOL) WasOpenedAsBrowser(IUnknown *punkSite)
  1983. {
  1984. // this is a more reliable way of distinguishing windows opened for a URL. Checking
  1985. // the hwnd's classname does not work -- clicking on a hyperlink from Outlook 98 opens
  1986. // a browser window with a shell window's classname.
  1987. return (S_OK == IUnknown_QueryServiceExec(punkSite, SID_STopLevelBrowser, &CGID_Explorer, SBCMDID_STARTEDFORINTERNET, 0, NULL, NULL));
  1988. }
  1989. #define DXTRACK 1
  1990. void FrameTrack(HDC hdc, LPRECT prc, UINT uFlags)
  1991. {
  1992. COLORREF clrSave, clr;
  1993. RECT rc;
  1994. // upperleft
  1995. switch (uFlags)
  1996. {
  1997. case TRACKHOT:
  1998. clr = GetSysColor(COLOR_BTNHILIGHT);
  1999. break;
  2000. case TRACKNOCHILD:
  2001. case TRACKEXPAND:
  2002. clr = GetSysColor(COLOR_BTNSHADOW);
  2003. break;
  2004. default:
  2005. ASSERT(FALSE);
  2006. break;
  2007. }
  2008. clrSave = SetBkColor(hdc, clr);
  2009. rc = *prc;
  2010. rc.bottom = rc.top + DXTRACK;
  2011. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
  2012. rc.bottom = prc->bottom;
  2013. rc.right = rc.left + DXTRACK;
  2014. rc.top = prc->top + DXTRACK;
  2015. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
  2016. // lowerright
  2017. switch (uFlags)
  2018. {
  2019. case TRACKHOT:
  2020. clr = GetSysColor(COLOR_BTNSHADOW);
  2021. break;
  2022. case TRACKNOCHILD:
  2023. case TRACKEXPAND:
  2024. clr = GetSysColor(COLOR_BTNHILIGHT);
  2025. break;
  2026. default:
  2027. ASSERT(FALSE);
  2028. break;
  2029. }
  2030. SetBkColor(hdc, clr);
  2031. if (uFlags & (TRACKHOT | TRACKNOCHILD))
  2032. {
  2033. rc.right = prc->right;
  2034. rc.top = rc.bottom - DXTRACK;
  2035. rc.left = prc->left;
  2036. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
  2037. }
  2038. rc.right = prc->right;
  2039. rc.left = prc->right - DXTRACK;
  2040. rc.top = prc->top;
  2041. rc.bottom = prc->bottom;
  2042. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
  2043. SetBkColor(hdc, clrSave);
  2044. return;
  2045. }
  2046. #ifdef DEBUG // {
  2047. //*** SearchDW -- scan for DWORD in buffer
  2048. // ENTRY/EXIT
  2049. // pdwBuf buffer
  2050. // cbBuf size of buffer in *bytes* (*not* DWORDs)
  2051. // dwVal DWORD we're looking for
  2052. // dOff (return) byte offset in buffer; o.w. -1 if not found
  2053. //
  2054. int SearchDWP(DWORD_PTR *pdwBuf, int cbBuf, DWORD_PTR dwVal)
  2055. {
  2056. int dOff;
  2057. for (dOff = 0; dOff < cbBuf; dOff += sizeof(DWORD_PTR), pdwBuf++)
  2058. {
  2059. if (*pdwBuf == dwVal)
  2060. return dOff;
  2061. }
  2062. return -1;
  2063. }
  2064. #endif // }
  2065. int CAssociationList::FindEntry(DWORD dwKey)
  2066. {
  2067. if (_hdsa)
  2068. {
  2069. for (int i = 0; i < DSA_GetItemCount(_hdsa); i++)
  2070. {
  2071. ASSOCDATA* pad;
  2072. pad = (ASSOCDATA*)DSA_GetItemPtr(_hdsa, i);
  2073. if (pad->dwKey == dwKey)
  2074. return i;
  2075. }
  2076. }
  2077. return -1;
  2078. }
  2079. HRESULT CAssociationList::Find(DWORD dwKey, void ** ppData)
  2080. {
  2081. HRESULT hr = E_FAIL;
  2082. ENTERCRITICAL;
  2083. int i = FindEntry(dwKey);
  2084. if (i != -1)
  2085. {
  2086. ASSOCDATA* pad = (ASSOCDATA*)DSA_GetItemPtr(_hdsa, i);
  2087. ASSERT(dwKey == pad->dwKey);
  2088. *ppData = pad->lpData;
  2089. hr = S_OK;
  2090. }
  2091. LEAVECRITICAL;
  2092. return hr;
  2093. }
  2094. void CAssociationList::Delete(DWORD dwKey)
  2095. {
  2096. ENTERCRITICAL;
  2097. int i = FindEntry(dwKey);
  2098. if (i != -1)
  2099. {
  2100. DSA_DeleteItem(_hdsa, i);
  2101. }
  2102. LEAVECRITICAL;
  2103. }
  2104. BOOL CAssociationList::Add(DWORD dwKey, void *lpData)
  2105. {
  2106. ENTERCRITICAL;
  2107. if (!_hdsa)
  2108. {
  2109. _hdsa = DSA_Create(sizeof(ASSOCDATA), 4);
  2110. }
  2111. LEAVECRITICAL;
  2112. BOOL fRet = FALSE;
  2113. if (_hdsa)
  2114. {
  2115. ASSOCDATA ad;
  2116. ad.dwKey = dwKey;
  2117. ad.lpData = lpData;
  2118. ENTERCRITICAL;
  2119. fRet = DSA_AppendItem(_hdsa, &ad) != -1;
  2120. LEAVECRITICAL;
  2121. }
  2122. return fRet;
  2123. }
  2124. int g_cxSmIcon = 0;
  2125. int g_cySmIcon = 0;
  2126. HIMAGELIST g_himlSysSmall = NULL;
  2127. void _InitSmallImageList()
  2128. {
  2129. if (!g_himlSysSmall)
  2130. {
  2131. Shell_GetImageLists(NULL, &g_himlSysSmall);
  2132. ImageList_GetIconSize(g_himlSysSmall, &g_cxSmIcon, &g_cySmIcon);
  2133. }
  2134. }
  2135. #define CXIMAGEGAP 6
  2136. STDAPI_(void) DrawMenuItem(DRAWITEMSTRUCT* lpdi, LPCTSTR lpszMenuText, UINT iIcon)
  2137. {
  2138. _InitSmallImageList();
  2139. if ((lpdi->itemAction & ODA_SELECT) || (lpdi->itemAction & ODA_DRAWENTIRE))
  2140. {
  2141. int x, y;
  2142. SIZE sz;
  2143. RECT rc;
  2144. // Draw the image (if there is one).
  2145. GetTextExtentPoint32(lpdi->hDC, lpszMenuText, lstrlen(lpszMenuText), &sz);
  2146. if (lpdi->itemState & ODS_SELECTED)
  2147. {
  2148. SetBkColor(lpdi->hDC, GetSysColor(COLOR_HIGHLIGHT));
  2149. SetTextColor(lpdi->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
  2150. FillRect(lpdi->hDC,&lpdi->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT));
  2151. }
  2152. else
  2153. {
  2154. SetTextColor(lpdi->hDC, GetSysColor(COLOR_MENUTEXT));
  2155. FillRect(lpdi->hDC,&lpdi->rcItem,GetSysColorBrush(COLOR_MENU));
  2156. }
  2157. rc = lpdi->rcItem;
  2158. rc.left += +2 * CXIMAGEGAP + g_cxSmIcon;
  2159. DrawText(lpdi->hDC, lpszMenuText, lstrlen(lpszMenuText), &rc, DT_SINGLELINE | DT_VCENTER | DT_EXPANDTABS);
  2160. if (iIcon != -1)
  2161. {
  2162. x = lpdi->rcItem.left + CXIMAGEGAP;
  2163. y = (lpdi->rcItem.bottom + lpdi->rcItem.top - g_cySmIcon) / 2;
  2164. ImageList_Draw(g_himlSysSmall, iIcon, lpdi->hDC, x, y, ILD_TRANSPARENT);
  2165. }
  2166. else
  2167. {
  2168. x = lpdi->rcItem.left + CXIMAGEGAP;
  2169. y = (lpdi->rcItem.bottom + lpdi->rcItem.top - g_cySmIcon) / 2;
  2170. }
  2171. }
  2172. }
  2173. STDAPI_(LRESULT) MeasureMenuItem(MEASUREITEMSTRUCT *lpmi, LPCTSTR lpszMenuText)
  2174. {
  2175. LRESULT lres = FALSE;
  2176. if (0 == g_cxSmIcon)
  2177. {
  2178. _InitSmallImageList();
  2179. }
  2180. // Get the rough height of an item so we can work out when to break the
  2181. // menu. User should really do this for us but that would be useful.
  2182. HDC hdc = GetDC(NULL);
  2183. if (hdc)
  2184. {
  2185. // REVIEW cache out the menu font?
  2186. NONCLIENTMETRICSA ncm;
  2187. ncm.cbSize = sizeof(ncm);
  2188. if (SystemParametersInfoA(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, FALSE))
  2189. {
  2190. HFONT hfont = CreateFontIndirectA(&ncm.lfMenuFont);
  2191. if (hfont)
  2192. {
  2193. SIZE sz;
  2194. HFONT hfontOld = (HFONT)SelectObject(hdc, hfont);
  2195. GetTextExtentPoint32(hdc, lpszMenuText, lstrlen(lpszMenuText), &sz);
  2196. lpmi->itemHeight = max (g_cySmIcon+CXIMAGEGAP/2, ncm.iMenuHeight);
  2197. lpmi->itemWidth = g_cxSmIcon + 2*CXIMAGEGAP + sz.cx;
  2198. SelectObject(hdc, hfontOld);
  2199. DeleteObject(hfont);
  2200. lres = TRUE;
  2201. }
  2202. }
  2203. ReleaseDC(NULL, hdc);
  2204. }
  2205. return lres;
  2206. }
  2207. //+-------------------------------------------------------------------------
  2208. // This function scans the document for the given HTML tag and returns the
  2209. // result in a collection.
  2210. //--------------------------------------------------------------------------
  2211. HRESULT GetDocumentTags
  2212. (
  2213. IHTMLDocument2 * pHTMLDocument, // doc to search
  2214. LPOLESTR pszTagName, // tag name to search for
  2215. IHTMLElementCollection ** ppTagsCollection // returned collection
  2216. )
  2217. {
  2218. HRESULT hr;
  2219. *ppTagsCollection = NULL;
  2220. //
  2221. // First get all document elements
  2222. //
  2223. IHTMLElementCollection * pAllCollection;
  2224. if (SUCCEEDED(hr = pHTMLDocument->get_all(&pAllCollection)))
  2225. {
  2226. //
  2227. // Now get all the elements with tags == pszTagName
  2228. //
  2229. VARIANT v;
  2230. v.vt = VT_BSTR;
  2231. v.bstrVal = ::SysAllocString(pszTagName);
  2232. if (v.bstrVal)
  2233. {
  2234. IDispatch * pDispTagsCollection;
  2235. if (SUCCEEDED(hr = pAllCollection->tags(v, &pDispTagsCollection)))
  2236. {
  2237. hr = pDispTagsCollection->QueryInterface(IID_PPV_ARG(IHTMLElementCollection, ppTagsCollection));
  2238. pDispTagsCollection->Release();
  2239. }
  2240. pAllCollection->Release();
  2241. VariantClear(&v);
  2242. }
  2243. }
  2244. return hr;
  2245. }
  2246. // This function uses the memory allocator from comctrl (which differs between NT and W95)
  2247. BOOL WINAPI Str_SetPtrPrivateW(WCHAR FAR * UNALIGNED * ppwzCurrent, LPCWSTR pwzNew)
  2248. {
  2249. LPWSTR pwzNewCopy = NULL;
  2250. if (pwzNew)
  2251. {
  2252. pwzNewCopy = StrDup(pwzNew);
  2253. if (!pwzNewCopy)
  2254. return FALSE;
  2255. }
  2256. LPWSTR pwzOld = (LPWSTR)InterlockedExchangePointer((void * *)ppwzCurrent, (void *)pwzNewCopy);
  2257. if (pwzOld)
  2258. LocalFree(pwzOld);
  2259. return TRUE;
  2260. }
  2261. // This function is compatible with API's that use LocalAlloc for string memory
  2262. BOOL WINAPI SetStr(WCHAR FAR * UNALIGNED * ppwzCurrent, LPCWSTR pwzNew)
  2263. {
  2264. int cchLength;
  2265. LPWSTR pwzOld;
  2266. LPWSTR pwzNewCopy = NULL;
  2267. if (pwzNew)
  2268. {
  2269. cchLength = lstrlenW(pwzNew);
  2270. // alloc a new buffer w/ room for the null terminator
  2271. pwzNewCopy = (LPWSTR)LocalAlloc(LPTR, (cchLength + 1) * sizeof(WCHAR));
  2272. if (!pwzNewCopy)
  2273. return FALSE;
  2274. HRESULT hr = StringCchCopy(pwzNewCopy, cchLength + 1, pwzNew);
  2275. if (FAILED(hr))
  2276. {
  2277. LocalFree(pwzNewCopy);
  2278. return FALSE;
  2279. }
  2280. }
  2281. pwzOld = (LPWSTR)InterlockedExchangePointer((void * *)ppwzCurrent, (void *)pwzNewCopy);
  2282. if (pwzOld)
  2283. LocalFree(pwzOld);
  2284. return TRUE;
  2285. }
  2286. //---------------------------------------------------------------------------
  2287. // If the string contains &ch or begins with ch then return TRUE.
  2288. BOOL _MenuCharMatch(LPCTSTR lpsz, TCHAR ch, BOOL fIgnoreAmpersand)
  2289. {
  2290. LPTSTR pchAS = StrChr(lpsz, TEXT('&')); // Find the first ampersand.
  2291. if (pchAS && !fIgnoreAmpersand)
  2292. {
  2293. // Yep, is the next char the one we want.
  2294. if (CharUpperChar(*CharNext(pchAS)) == CharUpperChar(ch))
  2295. {
  2296. // Yep.
  2297. return TRUE;
  2298. }
  2299. }
  2300. else if (CharUpperChar(*lpsz) == CharUpperChar(ch))
  2301. {
  2302. return TRUE;
  2303. }
  2304. return FALSE;
  2305. }
  2306. // Review chrisny: this can be moved into an object easily to handle generic droptarget, dropcursor
  2307. // , autoscrool, etc. . .
  2308. void _DragEnter(HWND hwndTarget, const POINTL ptStart, IDataObject *pdtObject)
  2309. {
  2310. RECT rc;
  2311. POINT pt;
  2312. GetWindowRect(hwndTarget, &rc);
  2313. //
  2314. // If hwndTarget is RTL mirrored, then measure the
  2315. // the client point from the visual right edge
  2316. // (near edge in RTL mirrored windows). [samera]
  2317. //
  2318. if (IS_WINDOW_RTL_MIRRORED(hwndTarget))
  2319. pt.x = rc.right - ptStart.x;
  2320. else
  2321. pt.x = ptStart.x - rc.left;
  2322. pt.y = ptStart.y - rc.top;
  2323. DAD_DragEnterEx2(hwndTarget, pt, pdtObject);
  2324. return;
  2325. }
  2326. void _DragMove(HWND hwndTarget, const POINTL ptStart)
  2327. {
  2328. RECT rc;
  2329. POINT pt;
  2330. GetWindowRect(hwndTarget, &rc);
  2331. //
  2332. // If hwndTarget is RTL mirrored, then measure the
  2333. // the client point from the visual right edge
  2334. // (near edge in RTL mirrored windows). [samera]
  2335. //
  2336. if (IS_WINDOW_RTL_MIRRORED(hwndTarget))
  2337. pt.x = rc.right - ptStart.x;
  2338. else
  2339. pt.x = ptStart.x - rc.left;
  2340. pt.y = ptStart.y - rc.top;
  2341. DAD_DragMove(pt);
  2342. return;
  2343. }
  2344. HRESULT CheckDesktopIni(LPCTSTR pszPath, LPCTSTR pszKey, LPTSTR pszBuffer, DWORD cchSize)
  2345. {
  2346. // NOTE:
  2347. // NOTE: DO NOT COPY THIS CODE. We only do this here for channels because we expect
  2348. // NOTE: the 99% case to be that it succeeds. If you need to find out if it is a
  2349. // NOTE: system folder, then you need to hack the pidl to get the system bit
  2350. // NOTE:
  2351. DWORD dwAttrs = GetFileAttributes(pszPath);
  2352. if (dwAttrs == (DWORD) -1 || !(dwAttrs & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY)))
  2353. return E_NOINTERFACE;
  2354. TCHAR szDIPath[MAX_PATH];
  2355. if (!PathCombine(szDIPath, pszPath, TEXT("desktop.ini")))
  2356. {
  2357. return E_FAIL;
  2358. }
  2359. if (pszKey == NULL)
  2360. {
  2361. if (GetFileAttributes(szDIPath) == (DWORD) -1)
  2362. {
  2363. return E_FAIL;
  2364. }
  2365. }
  2366. else
  2367. {
  2368. GetPrivateProfileString(TEXT(".ShellClassInfo"), pszKey, TEXT(""), pszBuffer, cchSize, szDIPath);
  2369. if (*pszBuffer == 0)
  2370. return E_NOINTERFACE;
  2371. // if its not a URL, then
  2372. if (!PathIsURL(pszBuffer))
  2373. {
  2374. if (!PathCombine(pszBuffer, pszPath, pszBuffer))
  2375. {
  2376. return E_FAIL;
  2377. }
  2378. }
  2379. }
  2380. return NOERROR;
  2381. }
  2382. STDAPI LookForDesktopIniText(IShellFolder *psf, LPCITEMIDLIST pidl, LPCTSTR pszKey, LPTSTR pszBuffer, DWORD cchSize)
  2383. {
  2384. TCHAR szPath[MAX_PATH];
  2385. DWORD ulFlags = SFGAO_FOLDER | SFGAO_FILESYSTEM;
  2386. HRESULT hr = GetPathForItem(psf, pidl, szPath, &ulFlags);
  2387. if (SUCCEEDED(hr) && (ulFlags & SFGAO_FOLDER))
  2388. {
  2389. hr = CheckDesktopIni(szPath, pszKey, pszBuffer, cchSize);
  2390. }
  2391. return hr;
  2392. }
  2393. // this is for channel category folders
  2394. HRESULT FakeGetNavigateTarget(IShellFolder *psf, LPCITEMIDLIST pidl, LPITEMIDLIST *ppidl)
  2395. {
  2396. HRESULT hres = E_FAIL;
  2397. WIN32_FIND_DATAA wfd;
  2398. // before looking for a desktop.ini (which hits the disk), cheaply
  2399. // see if it's a system folder.
  2400. //
  2401. // SHGetDataFromIDListA returns E_INVALIDARG on IE4.0 shell32 and
  2402. // IE4.01 shell32. It is fixed in IE4.01qfe shell32 and IE4.01sp1
  2403. // shell32. It also appears to work on NT4 and W95 shell32. If
  2404. // SHGetDataFromIDListA returns E_INVALIDARG we drop through and
  2405. // do the slow LookForDesktopIniText call.
  2406. //
  2407. HRESULT hresTemp = SHGetDataFromIDListA(psf, pidl, SHGDFIL_FINDDATA, &wfd, sizeof(wfd));
  2408. // on win95 non integrated, only the A version is implemented
  2409. if ((E_INVALIDARG == hresTemp) ||
  2410. (SUCCEEDED(hresTemp) &&
  2411. (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
  2412. (wfd.dwFileAttributes & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY))))
  2413. {
  2414. // final failure case, check to see if it is a system folder with a desktop.ini file. This is gross and slow,
  2415. // but this is only called when the user has navigated so we can be a little slower. Please do NOT COPY this
  2416. // code or DavidDS will get really really upset and perf will be bad.
  2417. TCHAR szBuffer[MAX_URL_STRING];
  2418. // this will check for SFGAO_FOLDER & SFGAO_FILESYSTEM first...
  2419. hres = LookForDesktopIniText(psf, pidl, TEXT("URL"), szBuffer, ARRAYSIZE(szBuffer));
  2420. if (SUCCEEDED(hres))
  2421. {
  2422. DWORD dwChar = ARRAYSIZE(szBuffer);
  2423. // this call uses a temp, so we can reuse the buffer...
  2424. hres = UrlCreateFromPath(szBuffer, szBuffer, &dwChar, 0);
  2425. if (SUCCEEDED(hres))
  2426. hres = IECreateFromPath(szBuffer, ppidl);
  2427. }
  2428. }
  2429. else
  2430. {
  2431. hres = E_FAIL;
  2432. }
  2433. return hres;
  2434. }
  2435. // Can we browse or navigate to this pidl? If not, need
  2436. BOOL ILIsBrowsable(LPCITEMIDLIST pidl, BOOL *pfIsFolder)
  2437. {
  2438. if (!pidl)
  2439. return FALSE;
  2440. DWORD dwAttributes = SFGAO_FOLDER | SFGAO_BROWSABLE;
  2441. HRESULT hr = IEGetAttributesOf(pidl, &dwAttributes);
  2442. if (pfIsFolder && SUCCEEDED(hr))
  2443. *pfIsFolder = dwAttributes & SFGAO_FOLDER;
  2444. return SUCCEEDED(hr) && (dwAttributes & (SFGAO_FOLDER | SFGAO_BROWSABLE));
  2445. }
  2446. // gets a target pidl given a name space item. typically this is a .lnk or .url file
  2447. //
  2448. // in:
  2449. // psf shell folder for item
  2450. // pidl item relative to psf, single level
  2451. //
  2452. // in/out
  2453. // pdwAttribs [optional] attributes mask to filter on (returned).
  2454. // must be initalized
  2455. //
  2456. //
  2457. // returns
  2458. // *ppidl the target pidl
  2459. // *pdwAttribs [optional] attributes of the source object
  2460. STDAPI SHGetNavigateTarget(IShellFolder *psf, LPCITEMIDLIST pidl,
  2461. LPITEMIDLIST *ppidl, DWORD *pdwAttribs)
  2462. {
  2463. ASSERT(IS_VALID_CODE_PTR(psf, IShellFolder));
  2464. ASSERT(IS_VALID_PIDL(pidl));
  2465. ASSERT(NULL == pdwAttribs || IS_VALID_WRITE_PTR(pdwAttribs, DWORD));
  2466. ASSERT(ILFindLastID(pidl) == pidl); // must be single level PIDL
  2467. *ppidl = NULL; // assume failure
  2468. DWORD dwAttribs = SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_LINK | SFGAO_BROWSABLE;
  2469. if (pdwAttribs)
  2470. dwAttribs |= *pdwAttribs;
  2471. HRESULT hres = psf->GetAttributesOf(1, &pidl, &dwAttribs);
  2472. if (SUCCEEDED(hres))
  2473. {
  2474. // first try the most efficient way
  2475. IShellLinkA *psl; // "A" so this works on Win95
  2476. hres = psf->GetUIObjectOf(NULL, 1, &pidl, IID_X_PPV_ARG(IShellLinkA, NULL, &psl));
  2477. if (SUCCEEDED(hres))
  2478. {
  2479. hres = psl->GetIDList(ppidl);
  2480. psl->Release();
  2481. }
  2482. // this is for .lnk and .url files that don't register properly
  2483. if (FAILED(hres) && (dwAttribs & (SFGAO_FILESYSTEM | SFGAO_LINK)) == (SFGAO_FILESYSTEM | SFGAO_LINK))
  2484. {
  2485. TCHAR szPath[MAX_PATH];
  2486. hres = GetPathForItem(psf, pidl, szPath, NULL);
  2487. if (SUCCEEDED(hres))
  2488. hres = GetLinkTargetIDList(szPath, NULL, 0, ppidl);
  2489. }
  2490. // .doc or .html. return the pidl for this.
  2491. // (fully qualify against the folder pidl)
  2492. if (FAILED(hres) && (dwAttribs & SFGAO_BROWSABLE))
  2493. {
  2494. LPITEMIDLIST pidlFolder;
  2495. hres = SHGetIDListFromUnk(psf, &pidlFolder);
  2496. if (SUCCEEDED(hres))
  2497. {
  2498. *ppidl = ILCombine(pidlFolder, pidl); // navigate to this thing...
  2499. hres = *ppidl ? S_OK : E_OUTOFMEMORY;
  2500. ILFree(pidlFolder);
  2501. }
  2502. }
  2503. // channel name space items on non integrated
  2504. if (FAILED(hres) && WhichPlatform() != PLATFORM_INTEGRATED)
  2505. {
  2506. IExtractIconA *pxicon; // Use IID_IExtractIconA so we work on W95.
  2507. hres = psf->GetUIObjectOf(NULL, 1, &pidl, IID_X_PPV_ARG(IExtractIconA, NULL, &pxicon));
  2508. if (SUCCEEDED(hres))
  2509. {
  2510. hres = pxicon->QueryInterface(IID_PPV_ARG(IShellLinkA, &psl));
  2511. if (SUCCEEDED(hres))
  2512. {
  2513. hres = psl->GetIDList(ppidl);
  2514. psl->Release();
  2515. }
  2516. pxicon->Release();
  2517. }
  2518. }
  2519. // Callers of SHGetNavigateTarget assume that the returned pidl
  2520. // is navigatable (SFGAO_FOLDER or SFGAO_BROWSER), which isn't
  2521. // the case for a link (it could be a link to an exe).
  2522. //
  2523. if (SUCCEEDED(hres) && !ILIsBrowsable(*ppidl, NULL))
  2524. {
  2525. ILFree(*ppidl);
  2526. *ppidl = NULL;
  2527. hres = E_FAIL;
  2528. }
  2529. if (SUCCEEDED(hres) && pdwAttribs)
  2530. *pdwAttribs = dwAttribs;
  2531. }
  2532. return hres;
  2533. }
  2534. BOOL CreateShortcutAndDoDragDropIfPIDLIsNetUrl(IOleCommandTarget *pcmdt, LPITEMIDLIST pidl, HWND hwnd)
  2535. {
  2536. IUniformResourceLocator *purl;
  2537. IDataObject *pdtobj;
  2538. HRESULT hr = CreateShortcutSetSiteAndGetDataObjectIfPIDLIsNetUrl(pidl, pcmdt, &purl, &pdtobj);
  2539. if (SUCCEEDED(hr))
  2540. {
  2541. ASSERT(pdtobj);
  2542. ASSERT(purl);
  2543. // REARCHITECT: we should be binding to the parent and getting the attributes
  2544. // to determine the allowed effects - like we do in DragDrop()
  2545. DWORD dwEffect = (DROPEFFECT_COPY | DROPEFFECT_LINK);
  2546. ::_SetPreferedDropEffect(pdtobj, DROPEFFECT_LINK);
  2547. // Win95 Browser Only - the shell32 in this process doesn't know
  2548. // ole is loaded, even though it is.
  2549. SHLoadOLE(SHELLNOTIFY_OLELOADED);
  2550. hr = SHDoDragDrop(hwnd, pdtobj, NULL, dwEffect, &dwEffect);
  2551. // the returned value is not S_OK even tho' the drag drop succeeded
  2552. // however it is a success return
  2553. if (SUCCEEDED(hr))
  2554. {
  2555. // Since drag drop succeeded
  2556. // Bring down the icon for this shortcut
  2557. IUnknown_Exec(purl, &CGID_ShortCut, ISHCUTCMDID_DOWNLOADICON, 0, NULL, NULL);
  2558. }
  2559. pdtobj->Release();
  2560. IUnknown_SetSite(purl, NULL);
  2561. purl->Release();
  2562. }
  2563. return SUCCEEDED(hr);
  2564. }
  2565. BOOL DoDragDropWithInternetShortcut(IOleCommandTarget *pcmdt, LPITEMIDLIST pidl, HWND hwnd)
  2566. {
  2567. BOOL fDragDropDone = CreateShortcutAndDoDragDropIfPIDLIsNetUrl(pcmdt, pidl, hwnd);
  2568. if (FALSE == fDragDropDone)
  2569. {
  2570. // simply use PIDL and get none of the persistence effect
  2571. fDragDropDone = SUCCEEDED(DragDrop(hwnd, NULL, pidl, DROPEFFECT_LINK, NULL));
  2572. }
  2573. return fDragDropDone;
  2574. }
  2575. STDAPI_(HWND) GetTopLevelAncestor(HWND hWnd)
  2576. {
  2577. HWND hwndTemp;
  2578. while ((hwndTemp=GetParent(hWnd)) != NULL)
  2579. {
  2580. hWnd = hwndTemp;
  2581. }
  2582. return(hWnd);
  2583. }
  2584. #if 0
  2585. BOOL IsIERepairOn()
  2586. {
  2587. static DWORD dwChecked = -1;
  2588. if (dwChecked == -1)
  2589. {
  2590. DWORD dwSize, dwType;
  2591. // First check the OS setting. On NT5 and Win98-OSR, Repair is Off.
  2592. // OS turned Off Repair ==> "DisableRepair" RegValue is set to 1.
  2593. dwChecked = 1; // The default Repair is ON
  2594. dwSize = sizeof(dwChecked);
  2595. if (SHRegGetUSValue(SZ_REGKEY_ACTIVE_SETUP, SZ_REGVALUE_DISABLE_REPAIR, &dwType, (void *) &dwChecked, &dwSize, TRUE, (void *)NULL, 0) == ERROR_SUCCESS)
  2596. {
  2597. // OS Reg setting of 0 ==> Repair is ON
  2598. // OS Reg setting of 1 ==> Repair is OFF
  2599. dwChecked = (dwChecked == 0) ? 1 : 0;
  2600. }
  2601. else
  2602. {
  2603. dwChecked = 1; // if we fail to read Reg, go back to default.
  2604. }
  2605. // Check for Admin policy only if OS setting leaves Repair On.
  2606. if (dwChecked == 1)
  2607. {
  2608. dwSize = sizeof(dwChecked);
  2609. if (SHRegGetUSValue(SZ_REGKEY_IE_POLICIES, SZ_REGVALUE_IEREPAIR, &dwType, (void *) &dwChecked, &dwSize, TRUE, (void *)NULL, 0) != ERROR_SUCCESS)
  2610. {
  2611. dwChecked = 1; // if we fail to read Reg, go back to default.
  2612. }
  2613. }
  2614. }
  2615. return (dwChecked == 1);
  2616. }
  2617. #endif
  2618. BOOL IsResetWebSettingsEnabled(void)
  2619. {
  2620. static BOOL fUseCache = FALSE; // have we already looked up the answer in the registry?
  2621. static BOOL fEnabled; // is the feature enabled or disabled?
  2622. if (!fUseCache)
  2623. {
  2624. DWORD dwData;
  2625. DWORD dwSize = sizeof(dwData);
  2626. DWORD dwType;
  2627. //
  2628. // Next time, we'll use the cached value instead of
  2629. // looking in the registry
  2630. //
  2631. fUseCache = TRUE;
  2632. //
  2633. // Look up the appropriate ieak value in the registry
  2634. //
  2635. if (ERROR_SUCCESS == SHRegGetUSValue(
  2636. SZ_REGKEY_INETCPL_POLICIES,
  2637. SZ_REGVALUE_RESETWEBSETTINGS,
  2638. &dwType,
  2639. (void *)&dwData,
  2640. &dwSize,
  2641. FALSE,
  2642. NULL,
  2643. 0))
  2644. {
  2645. //
  2646. // If the value was found in the registry, then
  2647. // set fEnabled accordingly
  2648. //
  2649. fEnabled = !dwData;
  2650. }
  2651. else
  2652. {
  2653. //
  2654. // If the value is missing from the registry, then
  2655. // assume the feature is enabled
  2656. //
  2657. fEnabled = TRUE;
  2658. }
  2659. }
  2660. return fEnabled;
  2661. }
  2662. STDAPI_(BOOL) InitOCHostClass(const SHDRC * pshdrc)
  2663. {
  2664. // It would be nice to remove this, but since it was exported, we keep it here for compat
  2665. RIPMSG(FALSE, "This export is dead, caller needs to call SHDOCVW!DllRegisterWindowClasses directly");
  2666. return DllRegisterWindowClasses(pshdrc);
  2667. }
  2668. STDAPI SHNavigateToFavorite(IShellFolder* psf, LPCITEMIDLIST pidl, IUnknown* punkSite, DWORD dwFlags)
  2669. {
  2670. HRESULT hres = S_FALSE;
  2671. TCHAR szPath[MAX_PATH];
  2672. // Can we navigate to this favorite?
  2673. BOOL fNavigateDone = SUCCEEDED(GetPathForItem(psf, pidl, szPath, NULL)) &&
  2674. SUCCEEDED(NavFrameWithFile(szPath, punkSite));
  2675. if (fNavigateDone)
  2676. return S_OK;
  2677. LPITEMIDLIST pidlGoto;
  2678. ASSERT(!(dwFlags & (SBSP_NEWBROWSER | SBSP_SAMEBROWSER)));
  2679. if (SUCCEEDED(SHGetNavigateTarget(psf, pidl, &pidlGoto, NULL)))
  2680. {
  2681. IShellBrowser* psb;
  2682. if (SUCCEEDED(IUnknown_QueryService(punkSite, SID_STopLevelBrowser,
  2683. IID_PPV_ARG(IShellBrowser, &psb))))
  2684. {
  2685. hres = psb->BrowseObject(pidlGoto, dwFlags | SBSP_SAMEBROWSER);
  2686. psb->Release();
  2687. }
  2688. ILFree(pidlGoto);
  2689. }
  2690. return hres;
  2691. }
  2692. STDAPI SHGetTopBrowserWindow(IUnknown* punk, HWND* phwnd)
  2693. {
  2694. IOleWindow* pOleWindow;
  2695. HRESULT hr = IUnknown_QueryService(punk, SID_STopLevelBrowser, IID_PPV_ARG(IOleWindow, &pOleWindow));
  2696. if (SUCCEEDED(hr))
  2697. {
  2698. hr = pOleWindow->GetWindow(phwnd);
  2699. pOleWindow->Release();
  2700. }
  2701. return hr;
  2702. }
  2703. BOOL ILIsFolder(LPCITEMIDLIST pidl)
  2704. {
  2705. BOOL fIsFolder = FALSE;
  2706. DWORD dwAttributes = SFGAO_FOLDER;
  2707. HRESULT hr = IEGetAttributesOf(pidl, &dwAttributes);
  2708. if (SFGAO_FOLDER == dwAttributes)
  2709. fIsFolder = TRUE;
  2710. return fIsFolder;
  2711. }
  2712. STDAPI_(LPITEMIDLIST) IEGetInternetRootID(void)
  2713. {
  2714. LPITEMIDLIST pidl;
  2715. //
  2716. // HACKHACK - we want the pidl to the Internet SF
  2717. // so we make a dummy URL and parse it. then
  2718. // we know its parent will be the Internet SF.
  2719. //
  2720. if (SUCCEEDED(IECreateFromPath(TEXT("dummy://url"), &pidl)))
  2721. {
  2722. ASSERT(!ILIsEmpty(_ILNext(pidl)));
  2723. ASSERT(IsURLChild(pidl, FALSE));
  2724. // we only want the parent Internt SF
  2725. _ILNext(pidl)->mkid.cb = 0;
  2726. return pidl;
  2727. }
  2728. return NULL;
  2729. }
  2730. STDAPI_(void) UpdateButtonArray(TBBUTTON *ptbDst, const TBBUTTON *ptbSrc, int ctb, LONG_PTR lStrOffset)
  2731. {
  2732. memcpy(ptbDst, ptbSrc, ctb*sizeof(TBBUTTON));
  2733. if (lStrOffset == -1)
  2734. {
  2735. // handle failure case
  2736. for (int i = 0; i < ctb; i++)
  2737. ptbDst[i].iString = 0;
  2738. }
  2739. else
  2740. {
  2741. for (int i = 0; i < ctb; i++)
  2742. ptbDst[i].iString += lStrOffset;
  2743. }
  2744. }
  2745. //----------------------------------------------------------------------------
  2746. // <Swipped from the NT5 version of Shell32>
  2747. //
  2748. STDAPI PathToAppPathKey(LPCTSTR pszPath, LPTSTR pszKey, int cchKey)
  2749. {
  2750. HRESULT hr;
  2751. // Use the szTemp variable of pseem to build key to the programs specific
  2752. // key in the registry as well as other things...
  2753. hr = StringCchCopy(pszKey, cchKey, REGSTR_PATH_APPPATHS);
  2754. if (SUCCEEDED(hr))
  2755. {
  2756. hr = StringCchCat(pszKey, cchKey, TEXT("\\"));
  2757. if (SUCCEEDED(hr))
  2758. {
  2759. hr = StringCchCat(pszKey, cchKey, PathFindFileName(pszPath));
  2760. if (SUCCEEDED(hr))
  2761. {
  2762. // Currently we will only look up .EXE if an extension is not
  2763. // specified
  2764. if (*PathFindExtension(pszKey) == 0)
  2765. {
  2766. hr = StringCchCat(pszKey, cchKey, TEXT(".exe"));
  2767. }
  2768. }
  2769. }
  2770. }
  2771. return hr;
  2772. }
  2773. //----------------------------------------------------------------------------
  2774. // <Swipped from the NT5 version of Shell32>
  2775. //
  2776. // this function checks for the existance of a value called "useURL" under the
  2777. // App Paths key in the registry associated with the app that is passed in.
  2778. STDAPI_(BOOL) DoesAppWantUrl(LPCTSTR pszCmdLine)
  2779. {
  2780. TCHAR szRegKeyName[MAX_PATH];
  2781. HKEY hKeyAppPaths;
  2782. BOOL bRet = FALSE;
  2783. // bug 61538 - The edit button never passes in args or quotes and the
  2784. // code below was screwing up if there were spaces in the path.
  2785. //
  2786. // need to copy the string since PathRemoveArgs whacks in a \0
  2787. // TCHAR szTemp[MAX_PATH];
  2788. // lstrcpyn(szTemp, pszCmdLine, ARRAYSIZE(szTemp));
  2789. // PathRemoveArgs(szTemp);
  2790. // PathUnquoteSpaces(szTemp);
  2791. HRESULT hr;
  2792. hr = PathToAppPathKey(pszCmdLine, szRegKeyName, ARRAYSIZE(szRegKeyName));
  2793. if (SUCCEEDED(hr))
  2794. {
  2795. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szRegKeyName, 0L, KEY_QUERY_VALUE, &hKeyAppPaths) == ERROR_SUCCESS)
  2796. {
  2797. bRet = RegQueryValueEx(hKeyAppPaths, TEXT("UseURL"), NULL, NULL, NULL, NULL) == ERROR_SUCCESS;
  2798. RegCloseKey(hKeyAppPaths);
  2799. }
  2800. }
  2801. return bRet;
  2802. }
  2803. // thread reference count object, this uses SHSetThreadRef()to let other code
  2804. // in this process hold a reference to this main thread, and thus the main thread in this process
  2805. class CRefThread : public IUnknown
  2806. {
  2807. public:
  2808. // IUnknown
  2809. virtual STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj);
  2810. virtual STDMETHODIMP_(ULONG) AddRef(void);
  2811. virtual STDMETHODIMP_(ULONG) Release(void);
  2812. CRefThread(LONG *pcRef);
  2813. private:
  2814. ~CRefThread();
  2815. LONG *_pcRef;
  2816. UINT _idThread;
  2817. };
  2818. CRefThread::CRefThread(LONG *pcRef)
  2819. {
  2820. _idThread = GetCurrentThreadId();
  2821. _pcRef = pcRef;
  2822. *_pcRef = 1;
  2823. }
  2824. //
  2825. // Note that this code tightens but does not close a race window.
  2826. // Although we nuke the process reference, the class factory for
  2827. // the web browser has yet to be deregistered, so if somebody decides
  2828. // to create one, our class factory will wake up and create a
  2829. // shell folder, which will flake out because it can't get a
  2830. // process reference.
  2831. //
  2832. CRefThread::~CRefThread()
  2833. {
  2834. // Avoid re-entrancy during destruction
  2835. *_pcRef = 1000;
  2836. // If we are the process reference, then revoke the process reference
  2837. // since we're going away.
  2838. IUnknown *punk;
  2839. SHGetInstanceExplorer(&punk);
  2840. if (punk == this)
  2841. SHSetInstanceExplorer(NULL);
  2842. ATOMICRELEASE(punk);
  2843. // Nobody should've rescued our reference
  2844. ASSERT(*_pcRef == 1000);
  2845. *_pcRef = 0;
  2846. // get the other thread out of WaitMessage() or GetMessage()
  2847. PostThreadMessage(_idThread, WM_NULL, 0, 0);
  2848. }
  2849. HRESULT CRefThread::QueryInterface(REFIID riid, void **ppvObj)
  2850. {
  2851. static const QITAB qit[] = { { 0 }, };
  2852. return QISearch(this, qit, riid, ppvObj);
  2853. }
  2854. ULONG CRefThread::AddRef()
  2855. {
  2856. return InterlockedIncrement(_pcRef);
  2857. }
  2858. ULONG CRefThread::Release()
  2859. {
  2860. ASSERT( 0 != *_pcRef );
  2861. ULONG cRef = InterlockedDecrement(_pcRef);
  2862. if ( 0 == cRef )
  2863. {
  2864. delete this;
  2865. }
  2866. return cRef;
  2867. }
  2868. STDAPI SHCreateThreadRef(LONG *pcRef, IUnknown **ppunk)
  2869. {
  2870. *ppunk = new CRefThread(pcRef);
  2871. if (*ppunk)
  2872. return S_OK;
  2873. *pcRef = 0;
  2874. *ppunk = NULL;
  2875. return E_OUTOFMEMORY;
  2876. }
  2877. //
  2878. // Returns the cache file associated with a URL. For file: urls, the associated
  2879. // disk file is returned. Not that we don't use URLDownloadToCacheFile because
  2880. // it causes another I-M-S GET to to be sent to the server
  2881. //
  2882. HRESULT URLToCacheFile
  2883. (
  2884. LPCWSTR pszUrl,
  2885. LPWSTR pszFile,
  2886. int cchFile
  2887. )
  2888. {
  2889. HRESULT hr;
  2890. DWORD dwScheme = GetUrlScheme(pszUrl);
  2891. if (URL_SCHEME_FILE == dwScheme)
  2892. {
  2893. ULONG cch = cchFile;
  2894. hr = PathCreateFromUrl(pszUrl, pszFile, &cch, 0);
  2895. }
  2896. else
  2897. {
  2898. // bug 73386 - GetUrlCacheEntryInfoExW fails to find entries if there is an anchor
  2899. // so we have to whack it off.
  2900. //
  2901. // We should really fix GetUrlCacheEntryInfoExW instead, but apparently
  2902. // this is risky for 5.x
  2903. //
  2904. hr = S_OK;
  2905. WCHAR szUrlBuf[MAX_URL_STRING];
  2906. if (URL_SCHEME_HTTP == dwScheme || URL_SCHEME_HTTPS == dwScheme)
  2907. {
  2908. LPWSTR pszAnchor = StrChr(pszUrl, L'#');
  2909. if (pszAnchor)
  2910. {
  2911. hr = StringCchCopyN(szUrlBuf, ARRAYSIZE(szUrlBuf), pszUrl, pszAnchor - pszUrl);
  2912. pszUrl = szUrlBuf;
  2913. }
  2914. }
  2915. if (SUCCEEDED(hr))
  2916. {
  2917. char szBuf[1024];
  2918. LPINTERNET_CACHE_ENTRY_INFOW pCE = (LPINTERNET_CACHE_ENTRY_INFOW)szBuf;
  2919. DWORD dwEntrySize = sizeof(szBuf);
  2920. BOOL fGotCacheInfo = GetUrlCacheEntryInfoExW(pszUrl, pCE, &dwEntrySize, NULL, NULL, NULL, 0);
  2921. if (!fGotCacheInfo)
  2922. {
  2923. if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  2924. {
  2925. // We guessed too small for the buffer so allocate the correct size & retry
  2926. pCE = (LPINTERNET_CACHE_ENTRY_INFOW)LocalAlloc(LPTR, dwEntrySize);
  2927. if (pCE)
  2928. {
  2929. fGotCacheInfo = GetUrlCacheEntryInfoEx(pszUrl, pCE, &dwEntrySize, NULL, NULL, NULL, 0);
  2930. }
  2931. }
  2932. else
  2933. {
  2934. // Retry using UTF8 encoding
  2935. //
  2936. // This fix belongs in GetUrlCacheEntryInfoEx (StevePro 01/19/99)
  2937. //
  2938. char szUrl[MAX_URL_STRING];
  2939. if (SHUnicodeToAnsiCP(CP_UTF8, pszUrl, szUrl, ARRAYSIZE(szUrl)))
  2940. {
  2941. szUrl[ARRAYSIZE(szUrl)-1] = '\0'; // paranoia
  2942. // UrlEscapeA Internally converts to unicode which messes up utf8. So we
  2943. // copy the string to a WCHAR buffer without coverting and call the unicode version.
  2944. // Yuk!
  2945. WCHAR wzUrl[ARRAYSIZE(szUrl)];
  2946. char* psz = szUrl;
  2947. WCHAR* pwz = wzUrl;
  2948. while (*psz!= NULL)
  2949. {
  2950. *pwz++ = ((WCHAR)*psz++) & 0xff;
  2951. }
  2952. *pwz = L'\0';
  2953. ULONG cch = ARRAYSIZE(wzUrl);
  2954. UrlEscapeW(wzUrl, wzUrl, &cch, /*URL_ESCAPE_PERCENT*/0);
  2955. psz = szUrl;
  2956. pwz = wzUrl;
  2957. while (*pwz!= NULL)
  2958. {
  2959. *psz++ = (char)LOWORD(*pwz++);
  2960. }
  2961. *psz = '\0';
  2962. LPINTERNET_CACHE_ENTRY_INFOA pCEA = (LPINTERNET_CACHE_ENTRY_INFOA)szBuf;
  2963. dwEntrySize = sizeof(szBuf);
  2964. BOOL fUtf8Worked = GetUrlCacheEntryInfoExA(szUrl, pCEA, &dwEntrySize, NULL, NULL, NULL, 0);
  2965. if (!fUtf8Worked)
  2966. {
  2967. if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  2968. {
  2969. // We guessed too small for the buffer so allocate the correct size & retry
  2970. pCEA = (LPINTERNET_CACHE_ENTRY_INFOA)LocalAlloc(LPTR, dwEntrySize);
  2971. if (pCEA)
  2972. {
  2973. fUtf8Worked = GetUrlCacheEntryInfoExA(szUrl, pCEA, &dwEntrySize, NULL, NULL, NULL, 0);
  2974. }
  2975. }
  2976. }
  2977. if (fUtf8Worked)
  2978. {
  2979. if (SHAnsiToUnicode(pCEA->lpszLocalFileName, pszFile, cchFile) >= cchFile)
  2980. {
  2981. hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  2982. }
  2983. else
  2984. {
  2985. hr = S_OK;
  2986. }
  2987. }
  2988. if ((char *)pCEA != szBuf)
  2989. {
  2990. LocalFree((HLOCAL)pCEA);
  2991. }
  2992. }
  2993. }
  2994. }
  2995. if (fGotCacheInfo)
  2996. {
  2997. hr = StringCchCopy(pszFile, cchFile, pCE->lpszLocalFileName);
  2998. }
  2999. // Free our GetUrlCacheEntryInfo buffer if we allocated one
  3000. if ((char *)pCE != szBuf)
  3001. {
  3002. LocalFree((HLOCAL)pCE);
  3003. }
  3004. }
  3005. }
  3006. return hr;
  3007. }
  3008. #ifdef DEBUG
  3009. void DebugDumpPidl(DWORD dwDumpFlag, LPTSTR pszOutputString, LPCITEMIDLIST pidl)
  3010. {
  3011. if (g_dwDumpFlags & dwDumpFlag)
  3012. {
  3013. TCHAR szPath[MAX_PATH];
  3014. LPTSTR lpsz;
  3015. if (pidl)
  3016. {
  3017. lpsz = szPath;
  3018. SHGetPathFromIDList(pidl, szPath);
  3019. }
  3020. else
  3021. {
  3022. lpsz = TEXT("(NULL)");
  3023. }
  3024. TraceMsg(TF_ALWAYS, "%s: \"%s\"", pszOutputString, lpsz);
  3025. }
  3026. }
  3027. #endif
  3028. // Variable argument version that ultimately call FormatMessageLiteW
  3029. BOOL __cdecl _FormatMessage(LPCWSTR szTemplate, LPWSTR szBuf, UINT cchBuf, ...)
  3030. {
  3031. BOOL fRet;
  3032. va_list ArgList;
  3033. va_start(ArgList, cchBuf);
  3034. fRet = FormatMessage(FORMAT_MESSAGE_FROM_STRING, szTemplate, 0, 0, szBuf, cchBuf, &ArgList);
  3035. va_end(ArgList);
  3036. return fRet;
  3037. }
  3038. // [msadek], On win9x we get the message thru a chain from explorer /iexplore (ANSI app.).
  3039. // and pass it to comctl32 (Unicode) so it will fail to match the hot key.
  3040. // the system sends the message with ANSI char and we treated it as Unicode.
  3041. // It looks like noone is affected with this bug (US, FE) since they have hot keys always in Latin.
  3042. // Bidi platforms are affected since they do have hot keys in native language.
  3043. WPARAM AnsiWparamToUnicode(WPARAM wParam)
  3044. {
  3045. char szCh[2];
  3046. WCHAR wszCh[2];
  3047. szCh[0] = (BYTE)wParam;
  3048. szCh[1] = '\0';
  3049. if (MultiByteToWideChar(CP_ACP, 0, (LPCSTR)szCh, ARRAYSIZE(szCh),
  3050. wszCh, ARRAYSIZE(wszCh)))
  3051. {
  3052. memcpy(&wParam, wszCh, sizeof(WCHAR));
  3053. }
  3054. return wParam;
  3055. }
  3056. void SHOutlineRect(HDC hdc, const RECT* prc, COLORREF cr)
  3057. {
  3058. RECT rc;
  3059. COLORREF clrSave = SetBkColor(hdc, cr);
  3060. //top
  3061. rc.left = prc->left;
  3062. rc.top = prc->top;
  3063. rc.right = prc->right;
  3064. rc.bottom = prc->top + 1;
  3065. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
  3066. //left
  3067. rc.left = prc->left;
  3068. rc.top = prc->top;
  3069. rc.right = prc->left + 1;
  3070. rc.bottom = prc->bottom;
  3071. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
  3072. //right
  3073. rc.left = prc->right - 1;
  3074. rc.top = prc->top;
  3075. rc.right = prc->right;
  3076. rc.bottom = prc->bottom;
  3077. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
  3078. // bottom
  3079. rc.left = prc->left;
  3080. rc.top = prc->bottom - 1;
  3081. rc.right = prc->right;
  3082. rc.bottom = prc->bottom;
  3083. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
  3084. SetBkColor(hdc, clrSave);
  3085. }
  3086. HMONITOR GetPrimaryMonitor()
  3087. {
  3088. POINT pt = {0,0};
  3089. return MonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY);
  3090. }
  3091. // Gets the Monitor's bounding or work rectangle, if the hMon is bad, return
  3092. // the primary monitor's bounding rectangle.
  3093. BOOL GetMonitorRects(HMONITOR hMon, LPRECT prc, BOOL bWork)
  3094. {
  3095. MONITORINFO mi;
  3096. mi.cbSize = sizeof(mi);
  3097. if (hMon && GetMonitorInfo(hMon, &mi))
  3098. {
  3099. if (!prc)
  3100. return TRUE;
  3101. else if (bWork)
  3102. CopyRect(prc, &mi.rcWork);
  3103. else
  3104. CopyRect(prc, &mi.rcMonitor);
  3105. return TRUE;
  3106. }
  3107. if (prc)
  3108. SetRect(prc, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
  3109. return FALSE;
  3110. }
  3111. ///////////////////////////////////////////////////////////////////////////////
  3112. ///////////////////////////////////////////////////////////////////////////////
  3113. // Utils to load background bitmap for toolbars etc.
  3114. ///////////////////////////////////////////////////////////////////////////////
  3115. ///////////////////////////////////////////////////////////////////////////////
  3116. //------------------------------------------------------------------------
  3117. // determine source name for bitmap, sift thru IE history....
  3118. HRESULT _GetBackBitmapLocation(LPTSTR psz, BOOL fInternet)
  3119. {
  3120. HRESULT hres = E_FAIL;
  3121. DWORD dwType;
  3122. DWORD dwcbData;
  3123. static const TCHAR c_szRegKeyCoolbar[] = TSZIEPATH TEXT("\\Toolbar");
  3124. // IE4 shipped back bitmap customization affecting both browser and shell.
  3125. // IE5 wants these to be separate customizations. But in the roaming
  3126. // case a customized IE4 customer shouldn't lose customization when going
  3127. // to the IE5 machine. So we might need to check twice:
  3128. //
  3129. if (fInternet)
  3130. {
  3131. // Try the IE5 internet location.
  3132. dwcbData = MAX_PATH * sizeof(TCHAR);
  3133. hres = SHGetValue(HKEY_CURRENT_USER, c_szRegKeyCoolbar, TEXT("BackBitmapIE5"), &dwType, psz, &dwcbData);
  3134. }
  3135. else
  3136. {
  3137. // Try the NT5 shell location.
  3138. dwcbData = MAX_PATH * sizeof(TCHAR);
  3139. hres = SHGetValue(HKEY_CURRENT_USER, c_szRegKeyCoolbar, TEXT("BackBitmapShell"), &dwType, psz, &dwcbData);
  3140. }
  3141. if (ERROR_SUCCESS != hres)
  3142. {
  3143. // Try the old combined internet/shell location
  3144. dwcbData = MAX_PATH * sizeof(TCHAR);
  3145. hres = SHGetValue(HKEY_CURRENT_USER, c_szRegKeyCoolbar, TEXT("BackBitmap"), &dwType, psz, &dwcbData);
  3146. }
  3147. return hres;
  3148. }
  3149. //------------------------------------------------------------------------
  3150. // determine background settings and source for toolbar,
  3151. // load bitmap (file/resource) and update cache
  3152. HBITMAP LoadToolbarBackBmp(LPTSTR * ppszBitmap, BMPCACHE * pbmpCache, BOOL fInternet)
  3153. {
  3154. HIGHCONTRAST hc;
  3155. HBITMAP hbmp = pbmpCache->hbmp;
  3156. COLORREF cr3D = GetSysColor(COLOR_3DFACE);
  3157. TCHAR szScratch[MAX_PATH];
  3158. LPTSTR pszBitmap = NULL;
  3159. BOOL fBitmapInvalid = FALSE;
  3160. ENTERCRITICAL;
  3161. // If the stashed hbmp's cr3D color changed, we need to mark invalid
  3162. if (pbmpCache->hbmp && pbmpCache->cr3D != cr3D)
  3163. fBitmapInvalid = TRUE;
  3164. // get the location spec for the bitmap
  3165. hc.cbSize = sizeof(HIGHCONTRAST);
  3166. if ((SystemParametersInfoA(SPI_GETHIGHCONTRAST, hc.cbSize, (LPVOID) &hc, FALSE)) &&
  3167. (hc.dwFlags & HCF_HIGHCONTRASTON))
  3168. {
  3169. // we have no bitmap in high contrast
  3170. }
  3171. else if (SUCCEEDED(_GetBackBitmapLocation(szScratch, fInternet)))
  3172. {
  3173. pszBitmap = szScratch;
  3174. }
  3175. // if they are removing the bitmap, we need to mark invalid
  3176. if (!pszBitmap && *ppszBitmap)
  3177. fBitmapInvalid = TRUE;
  3178. // or it's location has been changed, we need to mark invalid
  3179. if (pszBitmap && (!*ppszBitmap || lstrcmpi(pszBitmap, *ppszBitmap)))
  3180. fBitmapInvalid = TRUE;
  3181. if (fBitmapInvalid)
  3182. {
  3183. TraceMsg(DM_ITBAR, "LoadToolbarBackBmp: Loading Background Bitmap");
  3184. Str_SetPtr(ppszBitmap, pszBitmap);
  3185. hbmp=NULL;
  3186. if (*ppszBitmap)
  3187. {
  3188. if ((*ppszBitmap)[0])
  3189. {
  3190. hbmp = (HBITMAP) LoadImage(NULL, szScratch, IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE | LR_CREATEDIBSECTION | LR_LOADFROMFILE | LR_LOADMAP3DCOLORS );
  3191. }
  3192. if (!hbmp)
  3193. {
  3194. #ifdef OLD_SWIRLY_BACKDROP
  3195. if (SHGetCurColorRes() <= 8)
  3196. hbmp = (HBITMAP) LoadImage(HINST_THISDLL, MAKEINTRESOURCE(IDB_BACK), IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE | LR_CREATEDIBSECTION | LR_LOADMAP3DCOLORS );
  3197. #endif
  3198. }
  3199. }
  3200. #ifdef OLD_LEGACY_BAD_COLOUR_CODE
  3201. if (hbmp)
  3202. {
  3203. // mapping needed ?
  3204. // DONTWORRYABOUTTHIS: this will be removed as soon as I get the new backdrop....
  3205. if ( /* cr3D != RGB(192,192,192) */ FALSE)
  3206. {
  3207. RGBQUAD rgbTable[256];
  3208. RGBQUAD rgbFace;
  3209. HDC dc;
  3210. HBITMAP hbmSave;
  3211. UINT i;
  3212. UINT n;
  3213. dc = CreateCompatibleDC(NULL);
  3214. hbmSave = (HBITMAP)SelectObject(dc, hbmp);
  3215. n = GetDIBColorTable(dc, 0, 256, rgbTable);
  3216. rgbFace.rgbRed = GetRValue(cr3D);
  3217. rgbFace.rgbGreen = GetGValue(cr3D);
  3218. rgbFace.rgbBlue = GetBValue(cr3D);
  3219. for (i = 0; i < n; i++)
  3220. {
  3221. if ( rgbTable[i].rgbRed == 192 && rgbTable[i].rgbGreen == 192 && rgbTable[i].rgbBlue == 192 )
  3222. {
  3223. rgbTable[i] = rgbFace;
  3224. }
  3225. else
  3226. {
  3227. rgbTable[i].rgbRed = (rgbTable[i].rgbRed * rgbFace.rgbRed ) / 192;
  3228. rgbTable[i].rgbGreen = (rgbTable[i].rgbGreen * rgbFace.rgbGreen) / 192;
  3229. rgbTable[i].rgbBlue = (rgbTable[i].rgbBlue * rgbFace.rgbBlue ) / 192;
  3230. }
  3231. }
  3232. SetDIBColorTable(dc, 0, n, rgbTable);
  3233. SelectObject(dc, hbmSave);
  3234. DeleteDC(dc);
  3235. }
  3236. }
  3237. #endif
  3238. if (pbmpCache->hbmp)
  3239. DeleteObject(pbmpCache->hbmp);
  3240. pbmpCache->hbmp = hbmp;
  3241. pbmpCache->cr3D = cr3D;
  3242. }
  3243. LEAVECRITICAL;
  3244. return hbmp;
  3245. }
  3246. VOID StripDecorations(PTSTR pszTitle, BOOL fStripAmp)
  3247. {
  3248. LPTSTR pszCleaned = pszTitle; // work in-place
  3249. LPCTSTR psz = pszTitle;
  3250. while (*psz && (*psz != TEXT('\t')))
  3251. {
  3252. if (*psz != TEXT('&') || !fStripAmp)
  3253. {
  3254. *pszCleaned = *psz;
  3255. pszCleaned++;
  3256. }
  3257. psz++;
  3258. }
  3259. *pszCleaned = TEXT('\0');
  3260. }
  3261. //------------------------------------------------------------------------
  3262. LPCTSTR UnescapeDoubleAmpersand(LPTSTR pszTitle)
  3263. {
  3264. LPTSTR pszCleaned = pszTitle; // work in-place
  3265. LPCTSTR psz = pszTitle;
  3266. bool fEscapedAmp = false;
  3267. while (*psz)
  3268. {
  3269. if (*psz != TEXT('&') || fEscapedAmp)
  3270. {
  3271. // copy character
  3272. *pszCleaned = *psz;
  3273. pszCleaned++;
  3274. fEscapedAmp = false;
  3275. }
  3276. else
  3277. {
  3278. LPCTSTR pszNext = psz + 1;
  3279. if (pszNext && (*pszNext == TEXT('&'))) {
  3280. fEscapedAmp = true; // keep next ampersand
  3281. }
  3282. }
  3283. psz++;
  3284. }
  3285. *pszCleaned = TEXT('\0');
  3286. return pszTitle;
  3287. }
  3288. UINT MapClsidToID(REFCLSID rclsid)
  3289. {
  3290. UINT nCmdID;
  3291. nCmdID = 0;
  3292. if (IsEqualCLSID(CLSID_SearchBand, rclsid))
  3293. nCmdID = FCIDM_VBBSEARCHBAND;
  3294. else if (IsEqualCLSID(CLSID_FavBand, rclsid))
  3295. nCmdID = FCIDM_VBBFAVORITESBAND;
  3296. else if (IsEqualCLSID(CLSID_HistBand, rclsid))
  3297. nCmdID = FCIDM_VBBHISTORYBAND;
  3298. else if (IsEqualCLSID(CLSID_ExplorerBand, rclsid))
  3299. nCmdID = FCIDM_VBBEXPLORERBAND;
  3300. else if (IsEqualCLSID(CLSID_FileSearchBand, rclsid))
  3301. nCmdID = FCIDM_VBBSEARCHBAND;
  3302. return nCmdID;
  3303. }
  3304. // Create mask from given bitmap, use color at pixel (x/y) as transparent color
  3305. HBITMAP CreateMaskBitmap(HDC hdc, int x, int y, HBITMAP hbmpImage)
  3306. {
  3307. ASSERT(hbmpImage);
  3308. BITMAP bm;
  3309. if (::GetObject(hbmpImage, sizeof(BITMAP), &bm) != sizeof(BITMAP)) {
  3310. return FALSE;
  3311. }
  3312. HDC hdcImg = NULL;
  3313. HDC hdcMask = NULL;
  3314. HBITMAP hbmpMask = NULL;
  3315. HBITMAP hbmpOldImg = NULL;
  3316. HBITMAP hbmpOldMsk = NULL;
  3317. COLORREF clrTransparent = 0;
  3318. hdcImg = ::CreateCompatibleDC(hdc);
  3319. if (hdcImg == NULL) goto _CMBcleanup;
  3320. hdcMask = ::CreateCompatibleDC(hdc);
  3321. if (hdcMask == NULL) goto _CMBcleanup;
  3322. hbmpMask = ::CreateBitmap(bm.bmWidth, bm.bmHeight, 1, 1, NULL);
  3323. if (hbmpMask == NULL) goto _CMBcleanup;
  3324. hbmpOldImg = (HBITMAP) ::SelectObject(hdcImg, hbmpImage);
  3325. hbmpOldMsk = (HBITMAP) ::SelectObject(hdcMask, hbmpMask);
  3326. clrTransparent = ::GetPixel(hdcImg, 0, 0);
  3327. ::SetBkColor(hdcImg, clrTransparent);
  3328. ::BitBlt(hdcMask, 0, 0, bm.bmWidth, bm.bmHeight, hdcImg, 0, 0, SRCCOPY);
  3329. _CMBcleanup:
  3330. if (hbmpOldImg && hdcImg)
  3331. SelectObject(hdcImg, hbmpOldImg);
  3332. if (hdcImg)
  3333. DeleteDC(hdcImg);
  3334. if (hbmpOldMsk && hdcMask)
  3335. SelectObject(hdcMask, hbmpOldMsk);
  3336. if (hdcMask)
  3337. DeleteDC(hdcMask);
  3338. return hbmpMask;
  3339. }
  3340. // draw bitmap transparently; on Win2K and up, one could use MaskBlt()
  3341. BOOL DrawTransparentBitmapPart(HDC hdc, int x, int y, int dx, int dy, HBITMAP hbmpImage, HBITMAP hbmpMask)
  3342. {
  3343. ASSERT(hbmpImage);
  3344. BITMAP bm;
  3345. if (::GetObject(hbmpImage, sizeof(BITMAP), &bm) != sizeof(BITMAP)) {
  3346. return FALSE;
  3347. }
  3348. HBITMAP hbmpTmpMask = NULL;
  3349. // create temporary mask bitmap if none supplied
  3350. if (hbmpMask == NULL) {
  3351. hbmpMask = hbmpTmpMask = CreateMaskBitmap(hdc, 0, 0, hbmpImage);
  3352. }
  3353. if (hbmpMask == NULL) {
  3354. return FALSE;
  3355. }
  3356. HDC hdcOffScr = NULL;
  3357. HBITMAP hbmOffScr = NULL;
  3358. HBITMAP hbmOldOffScr = NULL;
  3359. HDC hdcImage = NULL;
  3360. HBITMAP hbmOldImage = NULL;
  3361. HDC hdcMask = NULL;
  3362. HBITMAP hbmOldMask = NULL;
  3363. // draw.to offscreen bitmap
  3364. hdcOffScr = ::CreateCompatibleDC(hdc);
  3365. if (hdcOffScr == NULL) goto _DTBcleanup;
  3366. hbmOffScr = ::CreateBitmap(dx, dy,GetDeviceCaps(hdc, PLANES),
  3367. (BYTE)GetDeviceCaps(hdc, BITSPIXEL), NULL);
  3368. if (hbmOffScr == NULL) goto _DTBcleanup;
  3369. hbmOldOffScr = (HBITMAP)::SelectObject(hdcOffScr, hbmOffScr);
  3370. // Copy the image of the destination rectangle to the
  3371. // off-screen buffer DC, so we can play with it.
  3372. ::BitBlt(hdcOffScr, 0, 0, dx, dy, hdc, x, y, SRCCOPY);
  3373. // prepare DCs for both image and mask
  3374. hdcImage = ::CreateCompatibleDC(hdc);
  3375. if (hdcImage == NULL) goto _DTBcleanup;
  3376. hbmOldImage = (HBITMAP)::SelectObject(hdcImage, hbmpImage);
  3377. hdcMask = ::CreateCompatibleDC(hdc);
  3378. if (hdcMask == NULL) goto _DTBcleanup;
  3379. hbmOldMask = (HBITMAP)::SelectObject(hdcMask, hbmpMask);
  3380. ::SetBkColor(hdcOffScr, RGB(255,255,255));
  3381. ::BitBlt(hdcOffScr, 0, 0, dx, dy, hdcImage, 0, 0, SRCINVERT);
  3382. ::BitBlt(hdcOffScr, 0, 0, dx, dy, hdcMask, 0, 0, SRCAND);
  3383. ::BitBlt(hdcOffScr, 0, 0, dx, dy, hdcImage, 0, 0, SRCINVERT);
  3384. // Copy the resultant image back to the screen DC.
  3385. ::BitBlt(hdc, x, y, dx, dy, hdcOffScr, 0, 0, SRCCOPY);
  3386. _DTBcleanup:
  3387. if (hdcOffScr && hbmOldOffScr)
  3388. ::SelectObject(hdcOffScr, hbmOldOffScr);
  3389. if (hdcOffScr)
  3390. ::DeleteDC(hdcOffScr);
  3391. if (hbmOffScr)
  3392. ::DeleteObject(hbmOffScr);
  3393. if (hdcImage && hbmOldImage)
  3394. ::SelectObject(hdcImage, hbmOldImage);
  3395. if (hdcImage)
  3396. ::DeleteDC(hdcImage);
  3397. if (hdcMask && hbmOldMask)
  3398. ::SelectObject(hdcMask, hbmOldMask);
  3399. if (hdcMask)
  3400. ::DeleteDC(hdcMask);
  3401. if (hbmpTmpMask)
  3402. ::DeleteObject(hbmpTmpMask);
  3403. return TRUE;
  3404. }
  3405. // draw bitmap transparently; on Win2K and up, one could use MaskBlt()
  3406. BOOL DrawTransparentBitmap(HDC hdc, int x, int y, HBITMAP hbmpImage, HBITMAP hbmpMask)
  3407. {
  3408. ASSERT(hbmpImage);
  3409. BITMAP bm;
  3410. if (::GetObject(hbmpImage, sizeof(BITMAP), &bm) != sizeof(BITMAP)) {
  3411. return FALSE;
  3412. }
  3413. return DrawTransparentBitmapPart(hdc, x, y, bm.bmWidth, bm.bmHeight, hbmpImage, hbmpMask);
  3414. }
  3415. //------------------------------------------------------------------------
  3416. BOOL
  3417. DrawAlphaBitmap(HDC hdc, int x, int y, int dx, int dy, HBITMAP hbmpImage)
  3418. {
  3419. BLENDFUNCTION bf = {0};
  3420. HDC hdcImage = ::CreateCompatibleDC(hdc);
  3421. if (hdcImage == NULL) {
  3422. return false;
  3423. }
  3424. HBITMAP hbmOldImage = (HBITMAP)::SelectObject(hdcImage, hbmpImage);
  3425. bf.BlendOp = AC_SRC_OVER;
  3426. bf.SourceConstantAlpha = 255;
  3427. bf.AlphaFormat = AC_SRC_ALPHA;
  3428. AlphaBlend(hdc, x, y, dx, dy, hdcImage, 0, 0, dx, dy, bf);
  3429. if (hbmOldImage) {
  3430. SelectObject(hdcImage, hbmOldImage);
  3431. }
  3432. DESTROY_OBJ_WITH_HANDLE(hdcImage, DeleteObject);
  3433. return true;
  3434. }
  3435. STDAPI_(IDeskBand *) FindBandByClsidBS(IBandSite *pbs, REFCLSID clsidToFind)
  3436. {
  3437. DWORD dwBandID;
  3438. for (int i = 0; SUCCEEDED(pbs->EnumBands(i, &dwBandID)); i++)
  3439. {
  3440. IDeskBand *pstb;
  3441. HRESULT hr = pbs->QueryBand(dwBandID, &pstb, NULL, NULL, 0);
  3442. if (SUCCEEDED(hr))
  3443. {
  3444. CLSID clsid;
  3445. hr = IUnknown_GetClassID(pstb, &clsid);
  3446. if (SUCCEEDED(hr) && IsEqualGUID(clsidToFind, clsid))
  3447. {
  3448. return pstb;
  3449. }
  3450. pstb->Release();
  3451. }
  3452. }
  3453. return NULL;
  3454. }
  3455. HIMAGELIST CreateImageList(HINSTANCE hi, LPCTSTR lpbmp, int cx, int cGrow, COLORREF crMask,
  3456. UINT uType, UINT uFlags, BOOL bUseNewMirroringSupport)
  3457. {
  3458. HBITMAP hbmImage;
  3459. HIMAGELIST piml = NULL;
  3460. BITMAP bm;
  3461. int cy, cInitial;
  3462. UINT flags;
  3463. hbmImage = (HBITMAP)LoadImage(hi, lpbmp, uType, 0, 0, uFlags);
  3464. if (hbmImage && (sizeof(bm) == GetObject(hbmImage, sizeof(bm), &bm)))
  3465. {
  3466. // If cx is not stated assume it is the same as cy.
  3467. // ASSERT(cx);
  3468. cy = bm.bmHeight;
  3469. if (cx == 0)
  3470. cx = cy;
  3471. cInitial = bm.bmWidth / cx;
  3472. ENTERCRITICAL;
  3473. if (bUseNewMirroringSupport)
  3474. {
  3475. flags = ILC_MIRROR | PrivateILC_PERITEMMIRROR;
  3476. }
  3477. else
  3478. {
  3479. flags = 0;
  3480. }
  3481. if (crMask != CLR_NONE)
  3482. flags |= ILC_MASK;
  3483. if (bm.bmBits)
  3484. flags |= (bm.bmBitsPixel & ILC_COLORMASK);
  3485. piml = ImageList_Create(cx, cy, flags, cInitial, cGrow);
  3486. if (piml)
  3487. {
  3488. int added;
  3489. if (crMask == CLR_NONE)
  3490. added = ImageList_Add(piml, hbmImage, NULL);
  3491. else
  3492. added = ImageList_AddMasked(piml, hbmImage, crMask);
  3493. if (added < 0)
  3494. {
  3495. ImageList_Destroy(piml);
  3496. piml = NULL;
  3497. }
  3498. }
  3499. LEAVECRITICAL;
  3500. }
  3501. if (hbmImage)
  3502. DeleteObject(hbmImage);
  3503. return piml;
  3504. }