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

1571 lines
43 KiB

  1. #include "util.h"
  2. #include "rcids.h"
  3. #include "psapi.h"
  4. #include <regstr.h>
  5. #include <ntddapmt.h>
  6. #define DECL_CRTFREE
  7. #include <crtfree.h>
  8. #include <qsort.h>
  9. #include <ddraw.h> // DirectDraw stuff..
  10. //////////////////////////////////////////////////////////////////////////
  11. //
  12. // util.cpp
  13. //
  14. // miscellaneous explorer helper functions
  15. //
  16. //////////////////////////////////////////////////////////////////////////
  17. ULONG _RegisterNotify(HWND hwnd, UINT nMsg, LPITEMIDLIST pidl, BOOL fRecursive)
  18. {
  19. SHChangeNotifyEntry fsne;
  20. fsne.fRecursive = fRecursive;
  21. fsne.pidl = pidl;
  22. //
  23. // Don't watch for attribute changes since we just want the
  24. // name and icon. For example, if a printer is paused, we don't
  25. // want to re-enumerate everything.
  26. //
  27. return SHChangeNotifyRegister(hwnd, SHCNRF_NewDelivery | SHCNRF_ShellLevel | SHCNRF_InterruptLevel,
  28. ((SHCNE_DISKEVENTS | SHCNE_UPDATEIMAGE) & ~SHCNE_ATTRIBUTES), nMsg, 1, &fsne);
  29. }
  30. void _UnregisterNotify(ULONG nNotify)
  31. {
  32. if (nNotify)
  33. SHChangeNotifyDeregister(nNotify);
  34. }
  35. // Mirror a bitmap in a DC (mainly a text object in a DC)
  36. //
  37. // [samera]
  38. //
  39. void _MirrorBitmapInDC(HDC hdc , HBITMAP hbmOrig)
  40. {
  41. HDC hdcMem;
  42. HBITMAP hbm;
  43. BITMAP bm;
  44. if (!GetObject(hbmOrig, sizeof(bm) , &bm))
  45. return;
  46. hdcMem = CreateCompatibleDC(hdc);
  47. if (!hdcMem)
  48. return;
  49. hbm = CreateCompatibleBitmap(hdc , bm.bmWidth , bm.bmHeight);
  50. if (!hbm)
  51. {
  52. DeleteDC(hdcMem);
  53. return;
  54. }
  55. //
  56. // Flip the bitmap
  57. //
  58. SelectObject(hdcMem , hbm);
  59. SET_DC_RTL_MIRRORED(hdcMem);
  60. BitBlt(hdcMem , 0 , 0 , bm.bmWidth , bm.bmHeight ,
  61. hdc , 0 , 0 , SRCCOPY);
  62. SET_DC_LAYOUT(hdcMem,0);
  63. //
  64. // The offset by 1 in hdcMem is to solve the off-by-one problem. Removed.
  65. // [samera]
  66. //
  67. BitBlt(hdc , 0 , 0 , bm.bmWidth , bm.bmHeight ,
  68. hdcMem , 0 , 0 , SRCCOPY);
  69. DeleteDC(hdcMem);
  70. DeleteObject(hbm);
  71. return;
  72. }
  73. // Sort of a registry equivalent of the profile API's.
  74. BOOL Reg_GetStruct(HKEY hkey, LPCTSTR pszSubKey, LPCTSTR pszValue, void *pData, DWORD *pcbData)
  75. {
  76. BOOL fRet = FALSE;
  77. if (!g_fCleanBoot)
  78. {
  79. fRet = ERROR_SUCCESS == SHGetValue(hkey, pszSubKey, pszValue, NULL, pData, pcbData);
  80. }
  81. return fRet;
  82. }
  83. // Sort of a registry equivalent of the profile API's.
  84. BOOL Reg_SetStruct(HKEY hkey, LPCTSTR pszSubKey, LPCTSTR pszValue, void *lpData, DWORD cbData)
  85. {
  86. HKEY hkeyNew = hkey;
  87. BOOL fRet = FALSE;
  88. if (pszSubKey)
  89. {
  90. if (RegCreateKey(hkey, pszSubKey, &hkeyNew) != ERROR_SUCCESS)
  91. {
  92. return fRet;
  93. }
  94. }
  95. if (RegSetValueEx(hkeyNew, pszValue, 0, REG_BINARY, (BYTE*)lpData, cbData) == ERROR_SUCCESS)
  96. {
  97. fRet = TRUE;
  98. }
  99. if (pszSubKey)
  100. RegCloseKey(hkeyNew);
  101. return fRet;
  102. }
  103. HMENU LoadMenuPopup(LPCTSTR id)
  104. {
  105. HMENU hMenuSub = NULL;
  106. HMENU hMenu = LoadMenu(hinstCabinet, id);
  107. if (hMenu) {
  108. hMenuSub = GetSubMenu(hMenu, 0);
  109. if (hMenuSub) {
  110. RemoveMenu(hMenu, 0, MF_BYPOSITION);
  111. }
  112. DestroyMenu(hMenu);
  113. }
  114. return hMenuSub;
  115. }
  116. // this gets hotkeys for files given a folder and a pidls it is much faster
  117. // than _GetHotkeyFromPidls since it does not need to bind to an IShellFolder
  118. // to interrogate it. if you have access to the item's IShellFolder, call this
  119. // one, especially in a loop.
  120. //
  121. WORD _GetHotkeyFromFolderItem(IShellFolder *psf, LPCITEMIDLIST pidl)
  122. {
  123. WORD wHotkey = 0;
  124. DWORD dwAttrs = SFGAO_LINK;
  125. // Make sure it is an SFGAO_LINK so we don't load a big handler dll
  126. // just to get back E_NOINTERFACE...
  127. if (SUCCEEDED(psf->GetAttributesOf(1, &pidl, &dwAttrs)) &&
  128. (dwAttrs & SFGAO_LINK))
  129. {
  130. IShellLink *psl;
  131. if (SUCCEEDED(psf->GetUIObjectOf(NULL, 1, &pidl, IID_X_PPV_ARG(IShellLink, NULL, &psl))))
  132. {
  133. psl->GetHotkey(&wHotkey);
  134. psl->Release();
  135. }
  136. }
  137. return wHotkey;
  138. }
  139. // Just like shells SHRestricted() only this put up a message if the restricion
  140. // is in effect.
  141. BOOL _Restricted(HWND hwnd, RESTRICTIONS rest)
  142. {
  143. if (SHRestricted(rest))
  144. {
  145. ShellMessageBox(hinstCabinet, hwnd, MAKEINTRESOURCE(IDS_RESTRICTIONS),
  146. MAKEINTRESOURCE(IDS_RESTRICTIONSTITLE), MB_OK|MB_ICONSTOP);
  147. return TRUE;
  148. }
  149. return FALSE;
  150. }
  151. int Window_GetClientGapHeight(HWND hwnd)
  152. {
  153. RECT rc;
  154. SetRectEmpty(&rc);
  155. AdjustWindowRectEx(&rc, GetWindowLong(hwnd, GWL_STYLE), FALSE, GetWindowLong(hwnd, GWL_EXSTYLE));
  156. return RECTHEIGHT(rc);
  157. }
  158. const TCHAR c_szConfig[] = REGSTR_KEY_CONFIG;
  159. const TCHAR c_szSlashDisplaySettings[] = TEXT("\\") REGSTR_PATH_DISPLAYSETTINGS;
  160. const TCHAR c_szResolution[] = REGSTR_VAL_RESOLUTION;
  161. //
  162. // GetMinDisplayRes
  163. //
  164. // walk all the configs and find the minimum display resolution.
  165. //
  166. // when doing a hot undock we have no idea what config we are
  167. // going to undock into.
  168. //
  169. // we want to put the display into a "common" mode that all configs
  170. // can handle so we dont "fry" the display when we wake up in the
  171. // new mode.
  172. //
  173. DWORD GetMinDisplayRes(void)
  174. {
  175. TCHAR ach[128];
  176. ULONG cb;
  177. HKEY hkey;
  178. HKEY hkeyT;
  179. int i, n;
  180. int xres=0;
  181. int yres=0;
  182. if (RegOpenKey(HKEY_LOCAL_MACHINE, c_szConfig, &hkey) == ERROR_SUCCESS)
  183. {
  184. for (n=0; RegEnumKey(hkey, n, ach, ARRAYSIZE(ach)) == ERROR_SUCCESS; n++)
  185. {
  186. lstrcat(ach, c_szSlashDisplaySettings); // 0000\Display\Settings
  187. TraceMsg(TF_TRAY, "GetMinDisplayRes: found config %s", ach);
  188. if (RegOpenKey(hkey, ach, &hkeyT) == ERROR_SUCCESS)
  189. {
  190. cb = sizeof(ach);
  191. ach[0] = 0;
  192. RegQueryValueEx(hkeyT, c_szResolution, 0, NULL, (LPBYTE) &ach[0], &cb);
  193. TraceMsg(TF_TRAY, "GetMinDisplayRes: found res %s", ach);
  194. if (ach[0])
  195. {
  196. i = StrToInt(ach);
  197. if (i < xres || xres == 0)
  198. xres = i;
  199. for (i=1;ach[i] && ach[i-1]!=TEXT(','); i++)
  200. ;
  201. i = StrToInt(ach + i);
  202. if (i < yres || yres == 0)
  203. yres = i;
  204. }
  205. else
  206. {
  207. xres = 640;
  208. yres = 480;
  209. }
  210. RegCloseKey(hkeyT);
  211. }
  212. }
  213. RegCloseKey(hkey);
  214. }
  215. TraceMsg(TF_TRAY, "GetMinDisplayRes: xres=%d yres=%d", xres, yres);
  216. if (xres == 0 || yres == 0)
  217. return MAKELONG(640, 480);
  218. else
  219. return MAKELONG(xres, yres);
  220. }
  221. //
  222. // the user has done a un-doc or re-doc we may need to switch
  223. // to a new display mode.
  224. //
  225. // if fCritical is set the mode switch is critical, show a error
  226. // if it does not work.
  227. //
  228. void HandleDisplayChange(int x, int y, BOOL fCritical)
  229. {
  230. DEVMODE dm;
  231. LONG err;
  232. HDC hdc;
  233. //
  234. // try to change into the mode specific to this config
  235. // HKEY_CURRENT_CONFIG has already been updated by PnP
  236. // so all we have to do is re-init the current display
  237. //
  238. // we cant default to current bpp because we may have changed configs.
  239. // and the bpp may be different in the new config.
  240. //
  241. dm.dmSize = sizeof(dm);
  242. dm.dmFields = DM_BITSPERPEL;
  243. hdc = GetDC(NULL);
  244. dm.dmBitsPerPel = GetDeviceCaps(hdc, PLANES) * GetDeviceCaps(hdc, BITSPIXEL);
  245. ReleaseDC(NULL, hdc);
  246. if (x + y)
  247. {
  248. dm.dmFields |= DM_PELSWIDTH|DM_PELSHEIGHT;
  249. dm.dmPelsWidth = x;
  250. dm.dmPelsHeight = y;
  251. }
  252. err = ChangeDisplaySettings(&dm, 0);
  253. if (err != 0 && fCritical)
  254. {
  255. //
  256. // if it fails make a panic atempt to try 640x480, if
  257. // that fails also we should put up a big error message
  258. // in text mode and tell the user he is in big trouble.
  259. //
  260. dm.dmFields = DM_PELSWIDTH|DM_PELSHEIGHT|DM_BITSPERPEL;
  261. dm.dmPelsWidth = 640;
  262. dm.dmPelsHeight = 480;
  263. err = ChangeDisplaySettings(&dm, 0);
  264. }
  265. }
  266. UINT GetDDEExecMsg()
  267. {
  268. static UINT uDDEExec = 0;
  269. if (!uDDEExec)
  270. uDDEExec = RegisterWindowMessage(TEXT("DDEEXECUTESHORTCIRCUIT"));
  271. return uDDEExec;
  272. }
  273. TCHAR const c_szCheckAssociations[] = TEXT("CheckAssociations");
  274. // Returns true if GrpConv says we should check extensions again (and then
  275. // clears the flag).
  276. // The assumption here is that runonce gets run before we call this (so
  277. // GrpConv -s can set this).
  278. BOOL _CheckAssociations(void)
  279. {
  280. DWORD dw = 0, cb = sizeof(dw);
  281. if (Reg_GetStruct(g_hkeyExplorer, NULL, c_szCheckAssociations, &dw, &cb) && dw)
  282. {
  283. dw = 0;
  284. Reg_SetStruct(g_hkeyExplorer, NULL, c_szCheckAssociations, &dw, sizeof(dw));
  285. return TRUE;
  286. }
  287. return FALSE;
  288. }
  289. void _ShowFolder(HWND hwnd, UINT csidl, UINT uFlags)
  290. {
  291. SHELLEXECUTEINFO shei = { 0 };
  292. shei.cbSize = sizeof(shei);
  293. shei.fMask = SEE_MASK_IDLIST | SEE_MASK_INVOKEIDLIST;
  294. shei.nShow = SW_SHOWNORMAL;
  295. if (_Restricted(hwnd, REST_NOSETFOLDERS))
  296. return;
  297. if (uFlags & COF_EXPLORE)
  298. shei.lpVerb = TEXT("explore");
  299. shei.lpIDList = SHCloneSpecialIDList(NULL, csidl, FALSE);
  300. if (shei.lpIDList)
  301. {
  302. ShellExecuteEx(&shei);
  303. ILFree((LPITEMIDLIST)shei.lpIDList);
  304. }
  305. }
  306. EXTERN_C IShellFolder* BindToFolder(LPCITEMIDLIST pidl)
  307. {
  308. IShellFolder *psfDesktop;
  309. if (SUCCEEDED(SHGetDesktopFolder(&psfDesktop)))
  310. {
  311. IShellFolder* psf;
  312. psfDesktop->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &psf));
  313. psfDesktop->Release(); // not really needed
  314. return psf;
  315. }
  316. return NULL;
  317. }
  318. // RunSystemMonitor
  319. //
  320. // Launches system monitor (taskmgr.exe), which is expected to be able
  321. // to find any currently running instances of itself
  322. void RunSystemMonitor(void)
  323. {
  324. STARTUPINFO startup;
  325. PROCESS_INFORMATION pi;
  326. TCHAR szName[] = TEXT("taskmgr.exe");
  327. startup.cb = sizeof(startup);
  328. startup.lpReserved = NULL;
  329. startup.lpDesktop = NULL;
  330. startup.lpTitle = NULL;
  331. startup.dwFlags = 0L;
  332. startup.cbReserved2 = 0;
  333. startup.lpReserved2 = NULL;
  334. startup.wShowWindow = SW_SHOWNORMAL;
  335. // Used to pass "taskmgr.exe" here, but NT faulted in CreateProcess
  336. // Probably they are wacking on the command line, which is bogus, but
  337. // then again the paremeter is not marked const...
  338. if (CreateProcess(NULL, szName, NULL, NULL, FALSE, 0,
  339. NULL, NULL, &startup, &pi))
  340. {
  341. CloseHandle(pi.hProcess);
  342. CloseHandle(pi.hThread);
  343. }
  344. }
  345. HRESULT SHIsParentOwnerOrSelf(HWND hwndParent, HWND hwnd)
  346. {
  347. while (hwnd)
  348. {
  349. if (hwnd == hwndParent)
  350. return S_OK;
  351. hwnd = GetParent(hwnd);
  352. }
  353. return E_FAIL;
  354. }
  355. void SHAllowSetForegroundWindow(HWND hwnd)
  356. {
  357. DWORD dwProcessId = 0;
  358. GetWindowThreadProcessId(hwnd, &dwProcessId);
  359. AllowSetForegroundWindow(dwProcessId);
  360. }
  361. //////////////////////////////////////////////////////////////////////////
  362. //
  363. // BEGIN scary crt-wannabe code
  364. //
  365. // This code implements some stuff that crt main ordinarily does for
  366. // you. In particular it implements construction and destruction of
  367. // static C++ objects. We can't just use crt main, unfortunately,
  368. // because we need to reserve control over whether or not ExitProcess
  369. // is called when our WinMain returns (see SVTRAY_EXITEXPLORER).
  370. //
  371. //////////////////////////////////////////////////////////////////////////
  372. typedef void (__cdecl*_PVFV)(void);
  373. extern "C" _PVFV* __onexitbegin = NULL;
  374. extern "C" _PVFV* __onexitend = NULL;
  375. extern "C" _PVFV __xc_a[], __xc_z[]; // C++ initializers
  376. HANDLE g_hProcessHeap;
  377. void DoInitialization()
  378. {
  379. // code swiped from atl40\atlimpl.cpp
  380. g_hProcessHeap = GetProcessHeap();
  381. _PVFV* pf;
  382. // Call initialization routines (contructors for globals, etc.)
  383. for (pf = __xc_a; pf < __xc_z; pf++)
  384. {
  385. if (*pf != NULL)
  386. {
  387. (**pf)();
  388. }
  389. }
  390. }
  391. void DoCleanup()
  392. {
  393. // code swiped from atl40\atlimpl.cpp
  394. // leaving this code turned off for now, otherwise the tray object
  395. // will be destroyed on the desktop thread which is bad because the
  396. // tray thread might still be running... just leak these objects
  397. // (our process is going away immediately anyhow, so who cares) until
  398. // we think of something better to do
  399. #ifdef DESTROY_STATIC_OBJECTS
  400. _PVFV* pf;
  401. // Call routines registered with atexit() from most recently registered
  402. // to least recently registered
  403. if (__onexitbegin != NULL)
  404. {
  405. for (pf = __onexitend - 1; pf >= __onexitbegin; pf--)
  406. {
  407. (**pf)();
  408. }
  409. }
  410. #endif
  411. HeapFree(g_hProcessHeap, 0, __onexitbegin);
  412. __onexitbegin = NULL;
  413. __onexitend = NULL;
  414. }
  415. //
  416. // You might be wondering, "What's the deal with atexit?"
  417. //
  418. // This is the mechanism which static C++ objects use to register
  419. // their destructors so that they get called when WinMain is finished.
  420. // Each such object constructor simply calls atexit with the destructor
  421. // function pointer. atexit saves the pointers off in __onexitbegin.
  422. // DoCleanup iterates through __onexitbegin and calls each destructor.
  423. //
  424. EXTERN_C int __cdecl atexit(_PVFV pf)
  425. {
  426. if (__onexitbegin == NULL)
  427. {
  428. __onexitbegin = (_PVFV*)HeapAlloc(g_hProcessHeap, 0, 16 * sizeof(_PVFV));
  429. if (__onexitbegin == NULL)
  430. {
  431. return(-1);
  432. }
  433. __onexitend = __onexitbegin;
  434. }
  435. ULONG_PTR nCurrentSize = HeapSize(g_hProcessHeap, 0, __onexitbegin);
  436. if (nCurrentSize + sizeof(_PVFV) <
  437. ULONG_PTR(((const BYTE*)__onexitend - (const BYTE*)__onexitbegin)))
  438. {
  439. _PVFV* pNew;
  440. pNew = (_PVFV*)HeapReAlloc(g_hProcessHeap, 0, __onexitbegin, 2*nCurrentSize);
  441. if (pNew == NULL)
  442. {
  443. return(-1);
  444. }
  445. }
  446. *__onexitend = pf;
  447. __onexitend++;
  448. return(0);
  449. }
  450. //////////////////////////////////////////////////////////////////////////
  451. //
  452. // END scary crt-wannabe code
  453. //
  454. //////////////////////////////////////////////////////////////////////////
  455. //////////////////////////////////////////////////////////////////////////
  456. //
  457. // BEGIN stuff moved over from APITHK.C
  458. //
  459. //////////////////////////////////////////////////////////////////////////
  460. /*----------------------------------------------------------
  461. Returns: If the Eject PC option is available
  462. */
  463. BOOL IsEjectAllowed(BOOL fForceUpdateCache)
  464. {
  465. static BOOL fCachedEjectAllowed = FALSE;
  466. static BOOL fCacheValid = FALSE;
  467. // we called the function before and the caller did not
  468. // pass fForceUpdateCache so just use the cached value
  469. if (fForceUpdateCache || !fCacheValid)
  470. {
  471. CM_Is_Dock_Station_Present(&fCachedEjectAllowed);
  472. }
  473. return fCachedEjectAllowed;
  474. }
  475. /*----------------------------------------------------------
  476. Purpose: Checks if system is BiDi locale, and if so sets the
  477. date format to DATE_RTLREADING.
  478. */
  479. void SetBiDiDateFlags(int *piDateFormat)
  480. {
  481. // GetLocaleInfo with LOCALE_FONTSIGNATURE always returns 16 WCHARs (even w/o Unicode support)
  482. WCHAR wchLCIDFontSignature[16];
  483. CALTYPE defCalendar;
  484. LCID lcidUserDefault = GetUserDefaultLCID();
  485. if (!lcidUserDefault)
  486. return;
  487. // Let's verify the bits we have a BiDi UI locale. This will work for Win9x and NT
  488. if ((LANG_ARABIC == PRIMARYLANGID(LANGIDFROMLCID(lcidUserDefault))) ||
  489. (LANG_HEBREW == PRIMARYLANGID(LANGIDFROMLCID(lcidUserDefault))) ||
  490. ((GetLocaleInfo(LOCALE_USER_DEFAULT,
  491. LOCALE_FONTSIGNATURE,
  492. (TCHAR *) &wchLCIDFontSignature[0],
  493. (sizeof(wchLCIDFontSignature)/sizeof(WCHAR)))) &&
  494. (wchLCIDFontSignature[7] & (WCHAR)0x0800))
  495. )
  496. {
  497. //
  498. // Let's verify the calendar type.
  499. TCHAR szCalendarType[64];
  500. if (GetLocaleInfo(LOCALE_USER_DEFAULT,
  501. LOCALE_ICALENDARTYPE,
  502. (TCHAR *) &szCalendarType[0],
  503. (sizeof(szCalendarType)/sizeof(TCHAR))))
  504. {
  505. defCalendar = StrToInt((TCHAR *)&szCalendarType[0]);
  506. if ((defCalendar == CAL_GREGORIAN) ||
  507. (defCalendar == CAL_HIJRI) ||
  508. (defCalendar == CAL_GREGORIAN_ARABIC) ||
  509. (defCalendar == CAL_HEBREW) ||
  510. (defCalendar == CAL_GREGORIAN_XLIT_ENGLISH) ||
  511. (defCalendar == CAL_GREGORIAN_XLIT_FRENCH))
  512. {
  513. *piDateFormat |= DATE_RTLREADING;
  514. }
  515. else
  516. {
  517. *piDateFormat |= DATE_LTRREADING;
  518. }
  519. }
  520. }
  521. }
  522. // first chance hook at all HSHELL_APPCOMMAND commands
  523. // this covers the below keys that are registered by shell32.dll
  524. // that includes
  525. // APPCOMMAND_LAUNCH_MEDIA_SELECT
  526. // APPCOMMAND_BROWSER_HOME
  527. // APPCOMMAND_LAUNCH_APP1
  528. // APPCOMMAND_LAUNCH_APP2
  529. // APPCOMMAND_LAUNCH_MAIL
  530. //
  531. // registry format:
  532. // HKCU | HKLM
  533. // Software\Microsoft\Windows\CurrentVersion\Explorer\AppKey\<value>
  534. // <value> is one of the APPCOMMAND_ constants (see winuser.h)
  535. //
  536. // create values with one of the following names
  537. // "ShellExecute" = <cmd line>
  538. // calc.exe, ::{my computer}, etc
  539. // pass this strin to ShellExecute()
  540. // "Association" = <extension>
  541. // .mp3, http
  542. // launch the program associated with this file type
  543. // "RegisteredApp" = <app name>
  544. // Mail, Contacts, etc
  545. // launch the registered app for this
  546. BOOL AppCommandTryRegistry(int cmd)
  547. {
  548. BOOL bRet = FALSE;
  549. TCHAR szKey[128];
  550. HUSKEY hkey;
  551. wsprintf(szKey, REGSTR_PATH_EXPLORER TEXT("\\AppKey\\%d"), cmd);
  552. if (ERROR_SUCCESS == SHRegOpenUSKey(szKey, KEY_READ, NULL, &hkey, FALSE))
  553. {
  554. TCHAR szCmdLine[MAX_PATH];
  555. DWORD cb = sizeof(szCmdLine);
  556. szCmdLine[0] = 0;
  557. if (ERROR_SUCCESS != SHRegQueryUSValue(hkey, TEXT("ShellExecute"), NULL, szCmdLine, &cb, FALSE, NULL, 0))
  558. {
  559. TCHAR szExt[MAX_PATH];
  560. cb = ARRAYSIZE(szExt);
  561. if (ERROR_SUCCESS == SHRegQueryUSValue(hkey, TEXT("Association"), NULL, szExt, &cb, FALSE, NULL, 0))
  562. {
  563. cb = ARRAYSIZE(szCmdLine);
  564. AssocQueryString(ASSOCF_VERIFY, ASSOCSTR_EXECUTABLE, szExt, NULL, szCmdLine, &cb);
  565. }
  566. else
  567. {
  568. cb = ARRAYSIZE(szExt);
  569. if (ERROR_SUCCESS == SHRegQueryUSValue(hkey, TEXT("RegisteredApp"), NULL, szExt, &cb, FALSE, NULL, 0))
  570. {
  571. WCHAR szAppW[MAX_PATH];
  572. SHTCharToUnicode(szExt, szAppW, ARRAYSIZE(szAppW));
  573. SHRunIndirectRegClientCommand(NULL, szAppW);
  574. szCmdLine[0] = 0;
  575. bRet = TRUE;
  576. }
  577. }
  578. }
  579. if (szCmdLine[0])
  580. {
  581. // ShellExecuteRegApp does all the parsing for us, so apps
  582. // can register appcommands with command line arguments.
  583. // Pass the RRA_DELETE flag so this won't get logged as a failed
  584. // startup app.
  585. ShellExecuteRegApp(szCmdLine, RRA_DELETE | RRA_NOUI);
  586. bRet = TRUE;
  587. }
  588. SHRegCloseUSKey(hkey);
  589. }
  590. return bRet;
  591. }
  592. //////////////////////////////////////////////////////////////////////////
  593. //
  594. // END stuff moved over from APITHK.C
  595. //
  596. //////////////////////////////////////////////////////////////////////////
  597. void RECTtoRECTL(LPRECT prc, LPRECTL lprcl)
  598. {
  599. lprcl->left = prc->left;
  600. lprcl->top = prc->top;
  601. lprcl->bottom = prc->bottom;
  602. lprcl->right = prc->right;
  603. }
  604. #include <crt/malloc.h> // Get definition for alloca()
  605. int Toolbar_GetUniqueID(HWND hwndTB)
  606. {
  607. int iCount = ToolBar_ButtonCount(hwndTB);
  608. ASSERTMSG(iCount < 1024*16, "Toolbar_GetUniqueID: toolbar is huge, we don't want to use alloca here");
  609. int *rgCmds = (int *)alloca(iCount * sizeof(*rgCmds));
  610. TBBUTTONINFO tbbi;
  611. tbbi.cbSize = sizeof(TBBUTTONINFO);
  612. tbbi.dwMask = TBIF_BYINDEX | TBIF_COMMAND;
  613. for (int i = 0; i < iCount; i++)
  614. {
  615. ToolBar_GetButtonInfo(hwndTB, i, &tbbi);
  616. rgCmds[i] = tbbi.idCommand;
  617. }
  618. QSort<int>(rgCmds, iCount, TRUE);
  619. int iCmd = 0;
  620. for (i = 0; i < iCount; i++)
  621. {
  622. if (iCmd != rgCmds[i])
  623. break;
  624. iCmd++;
  625. }
  626. return iCmd;
  627. }
  628. BYTE ToolBar_GetStateByIndex(HWND hwnd, INT_PTR iIndex)
  629. {
  630. TBBUTTONINFO tbb;
  631. tbb.cbSize = sizeof(TBBUTTONINFO);
  632. tbb.dwMask = TBIF_STATE | TBIF_BYINDEX;
  633. ToolBar_GetButtonInfo(hwnd, iIndex, &tbb);
  634. return tbb.fsState;
  635. }
  636. int ToolBar_IndexToCommand(HWND hwnd, INT_PTR iIndex)
  637. {
  638. TBBUTTONINFO tbbi;
  639. tbbi.cbSize = sizeof(TBBUTTONINFO);
  640. tbbi.dwMask = TBIF_COMMAND | TBIF_BYINDEX;
  641. ToolBar_GetButtonInfo(hwnd, iIndex, &tbbi);
  642. return tbbi.idCommand;
  643. }
  644. //
  645. // Determine the flags for creating the tray notify icon imagelist.
  646. //
  647. //
  648. UINT SHGetImageListFlags(HWND hwnd)
  649. {
  650. UINT flags = ILC_MASK | ILC_COLOR32;
  651. // Mirrored if we are RTL
  652. if (IS_WINDOW_RTL_MIRRORED(hwnd))
  653. {
  654. flags |= ILC_MIRROR;
  655. }
  656. return flags;
  657. }
  658. // Copied from \\index2\src\sdktools\psapi\module.c
  659. BOOL
  660. SHFindModule(
  661. IN HANDLE hProcess,
  662. IN HMODULE hModule,
  663. OUT PLDR_DATA_TABLE_ENTRY LdrEntryData
  664. )
  665. /*++
  666. Routine Description:
  667. This function retrieves the loader table entry for the specified
  668. module. The function copies the entry into the buffer pointed to
  669. by the LdrEntryData parameter.
  670. Arguments:
  671. hProcess - Supplies the target process.
  672. hModule - Identifies the module whose loader entry is being
  673. requested. A value of NULL references the module handle
  674. associated with the image file that was used to create the
  675. process.
  676. LdrEntryData - Returns the requested table entry.
  677. Return Value:
  678. TRUE if a matching entry was found.
  679. --*/
  680. {
  681. PROCESS_BASIC_INFORMATION BasicInfo;
  682. NTSTATUS Status;
  683. PPEB Peb;
  684. PPEB_LDR_DATA Ldr;
  685. PLIST_ENTRY LdrHead;
  686. PLIST_ENTRY LdrNext;
  687. Status = NtQueryInformationProcess(
  688. hProcess,
  689. ProcessBasicInformation,
  690. &BasicInfo,
  691. sizeof(BasicInfo),
  692. NULL
  693. );
  694. if ( !NT_SUCCESS(Status) ) {
  695. SetLastError( RtlNtStatusToDosError( Status ) );
  696. return(FALSE);
  697. }
  698. Peb = BasicInfo.PebBaseAddress;
  699. if ( !ARGUMENT_PRESENT( hModule )) {
  700. if (!ReadProcessMemory(hProcess, &Peb->ImageBaseAddress, &hModule, sizeof(hModule), NULL)) {
  701. return(FALSE);
  702. }
  703. }
  704. //
  705. // Ldr = Peb->Ldr
  706. //
  707. if (!ReadProcessMemory(hProcess, &Peb->Ldr, &Ldr, sizeof(Ldr), NULL)) {
  708. return (FALSE);
  709. }
  710. if (!Ldr) {
  711. // Ldr might be null (for instance, if the process hasn't started yet).
  712. SetLastError(ERROR_INVALID_HANDLE);
  713. return (FALSE);
  714. }
  715. LdrHead = &Ldr->InMemoryOrderModuleList;
  716. //
  717. // LdrNext = Head->Flink;
  718. //
  719. if (!ReadProcessMemory(hProcess, &LdrHead->Flink, &LdrNext, sizeof(LdrNext), NULL)) {
  720. return(FALSE);
  721. }
  722. while (LdrNext != LdrHead) {
  723. PLDR_DATA_TABLE_ENTRY LdrEntry;
  724. LdrEntry = CONTAINING_RECORD(LdrNext, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
  725. if (!ReadProcessMemory(hProcess, LdrEntry, LdrEntryData, sizeof(*LdrEntryData), NULL)) {
  726. return(FALSE);
  727. }
  728. if ((HMODULE) LdrEntryData->DllBase == hModule) {
  729. return(TRUE);
  730. }
  731. LdrNext = LdrEntryData->InMemoryOrderLinks.Flink;
  732. }
  733. SetLastError(ERROR_INVALID_HANDLE);
  734. return(FALSE);
  735. }
  736. // Copied from \\index2\src\sdktools\psapi\module.c
  737. DWORD
  738. WINAPI
  739. SHGetModuleFileNameExW(
  740. HANDLE hProcess,
  741. HMODULE hModule,
  742. LPWSTR lpFilename,
  743. DWORD nSize
  744. )
  745. /*++
  746. Routine Description:
  747. This function retrieves the full pathname of the executable file
  748. from which the specified module was loaded. The function copies the
  749. null-terminated filename into the buffer pointed to by the
  750. lpFilename parameter.
  751. Routine Description:
  752. hModule - Identifies the module whose executable file name is being
  753. requested. A value of NULL references the module handle
  754. associated with the image file that was used to create the
  755. process.
  756. lpFilename - Points to the buffer that is to receive the filename.
  757. nSize - Specifies the maximum number of characters to copy. If the
  758. filename is longer than the maximum number of characters
  759. specified by the nSize parameter, it is truncated.
  760. Return Value:
  761. The return value specifies the actual length of the string copied to
  762. the buffer. A return value of zero indicates an error and extended
  763. error status is available using the GetLastError function.
  764. Arguments:
  765. --*/
  766. {
  767. LDR_DATA_TABLE_ENTRY LdrEntryData;
  768. DWORD cb;
  769. if (!SHFindModule(hProcess, hModule, &LdrEntryData)) {
  770. return(0);
  771. }
  772. nSize *= sizeof(WCHAR);
  773. cb = LdrEntryData.FullDllName.MaximumLength;
  774. if ( nSize < cb ) {
  775. cb = nSize;
  776. }
  777. if (!ReadProcessMemory(hProcess, LdrEntryData.FullDllName.Buffer, lpFilename, cb, NULL)) {
  778. return(0);
  779. }
  780. if (cb == LdrEntryData.FullDllName.MaximumLength) {
  781. cb -= sizeof(WCHAR);
  782. }
  783. return(cb / sizeof(WCHAR));
  784. }
  785. HRESULT SHExeNameFromHWND(HWND hWnd, LPWSTR pszExeName, UINT cbExeName)
  786. {
  787. /* Getting the Friendly App Name is fun, this is the general process:
  788. 1) Get ProcessId from the HWND
  789. 2) Open that process
  790. 3) Query for it's basic information, essentially getting the PEB
  791. 4) Read the PEB information from the process' memory
  792. 5) In the PEB information is the name of the imagefile (i.e. C:\WINNT\EXPLORER.EXE)
  793. */
  794. HRESULT hr = S_OK;
  795. UINT uWritten = 0;
  796. pszExeName[0] = 0;
  797. DWORD dwProcessID;
  798. DWORD dwThreadID = GetWindowThreadProcessId(hWnd, &dwProcessID);
  799. HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwProcessID);
  800. if (hProcess)
  801. {
  802. uWritten = SHGetModuleFileNameExW(hProcess, 0, pszExeName, cbExeName);
  803. pszExeName[cbExeName-1] = 0;
  804. CloseHandle(hProcess);
  805. }
  806. if (!uWritten)
  807. hr = E_FAIL;
  808. return hr;
  809. }
  810. // Gets the Monitor's bounding or work rectangle, if the hMon is bad, return
  811. // the primary monitor's bounding rectangle.
  812. BOOL GetMonitorRects(HMONITOR hMon, LPRECT prc, BOOL bWork)
  813. {
  814. MONITORINFO mi;
  815. mi.cbSize = sizeof(mi);
  816. if (hMon && GetMonitorInfo(hMon, &mi))
  817. {
  818. if (!prc)
  819. return TRUE;
  820. else if (bWork)
  821. CopyRect(prc, &mi.rcWork);
  822. else
  823. CopyRect(prc, &mi.rcMonitor);
  824. return TRUE;
  825. }
  826. if (prc)
  827. SetRect(prc, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
  828. return FALSE;
  829. }
  830. BOOL ShouldTaskbarAnimate()
  831. {
  832. BOOL fAnimate;
  833. SystemParametersInfo(SPI_GETUIEFFECTS, 0, (PVOID) &fAnimate, 0);
  834. if (fAnimate)
  835. {
  836. if (GetSystemMetrics(SM_REMOTESESSION))
  837. {
  838. DWORD dwSessionID = NtCurrentPeb()->SessionId;
  839. WCHAR szRegKey[MAX_PATH];
  840. wnsprintf(szRegKey, ARRAYSIZE(szRegKey), L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Remote\\%d", dwSessionID);
  841. fAnimate = SHRegGetBoolUSValue(szRegKey, TEXT("TaskbarAnimations"), FALSE, TRUE);
  842. }
  843. else
  844. {
  845. fAnimate = SHRegGetBoolUSValue(REGSTR_EXPLORER_ADVANCED, TEXT("TaskbarAnimations"), FALSE, TRUE);
  846. }
  847. }
  848. return fAnimate;
  849. }
  850. void FillRectClr(HDC hdc, LPRECT prc, COLORREF clr)
  851. {
  852. COLORREF clrSave = SetBkColor(hdc, clr);
  853. ExtTextOut(hdc,0,0,ETO_OPAQUE,prc,NULL,0,NULL);
  854. SetBkColor(hdc, clrSave);
  855. }
  856. BOOL CCDrawEdge(HDC hdc, LPRECT lprc, UINT edge, UINT flags, LPCOLORSCHEME lpclrsc)
  857. {
  858. RECT rc, rcD;
  859. UINT bdrType;
  860. COLORREF clrTL, clrBR;
  861. //
  862. // Enforce monochromicity and flatness
  863. //
  864. // if (oemInfo.BitCount == 1)
  865. // flags |= BF_MONO;
  866. if (flags & BF_MONO)
  867. flags |= BF_FLAT;
  868. CopyRect(&rc, lprc);
  869. //
  870. // Draw the border segment(s), and calculate the remaining space as we
  871. // go.
  872. //
  873. if (bdrType = (edge & BDR_OUTER))
  874. {
  875. DrawBorder:
  876. //
  877. // Get colors. Note the symmetry between raised outer, sunken inner and
  878. // sunken outer, raised inner.
  879. //
  880. if (flags & BF_FLAT)
  881. {
  882. if (flags & BF_MONO)
  883. clrBR = (bdrType & BDR_OUTER) ? GetSysColor(COLOR_WINDOWFRAME) : GetSysColor(COLOR_WINDOW);
  884. else
  885. clrBR = (bdrType & BDR_OUTER) ? GetSysColor(COLOR_BTNSHADOW): GetSysColor(COLOR_BTNFACE);
  886. clrTL = clrBR;
  887. }
  888. else
  889. {
  890. // 5 == HILIGHT
  891. // 4 == LIGHT
  892. // 3 == FACE
  893. // 2 == SHADOW
  894. // 1 == DKSHADOW
  895. switch (bdrType)
  896. {
  897. // +2 above surface
  898. case BDR_RAISEDOUTER: // 5 : 4
  899. clrTL = ((flags & BF_SOFT) ? GetSysColor(COLOR_BTNHIGHLIGHT) : GetSysColor(COLOR_3DLIGHT));
  900. clrBR = GetSysColor(COLOR_3DDKSHADOW); // 1
  901. if (lpclrsc) {
  902. if (lpclrsc->clrBtnHighlight != CLR_DEFAULT)
  903. clrTL = lpclrsc->clrBtnHighlight;
  904. if (lpclrsc->clrBtnShadow != CLR_DEFAULT)
  905. clrBR = lpclrsc->clrBtnShadow;
  906. }
  907. break;
  908. // +1 above surface
  909. case BDR_RAISEDINNER: // 4 : 5
  910. clrTL = ((flags & BF_SOFT) ? GetSysColor(COLOR_3DLIGHT) : GetSysColor(COLOR_BTNHIGHLIGHT));
  911. clrBR = GetSysColor(COLOR_BTNSHADOW); // 2
  912. if (lpclrsc) {
  913. if (lpclrsc->clrBtnHighlight != CLR_DEFAULT)
  914. clrTL = lpclrsc->clrBtnHighlight;
  915. if (lpclrsc->clrBtnShadow != CLR_DEFAULT)
  916. clrBR = lpclrsc->clrBtnShadow;
  917. }
  918. break;
  919. // -1 below surface
  920. case BDR_SUNKENOUTER: // 1 : 2
  921. clrTL = ((flags & BF_SOFT) ? GetSysColor(COLOR_3DDKSHADOW) : GetSysColor(COLOR_BTNSHADOW));
  922. clrBR = GetSysColor(COLOR_BTNHIGHLIGHT); // 5
  923. if (lpclrsc) {
  924. if (lpclrsc->clrBtnShadow != CLR_DEFAULT)
  925. clrTL = lpclrsc->clrBtnShadow;
  926. if (lpclrsc->clrBtnHighlight != CLR_DEFAULT)
  927. clrBR = lpclrsc->clrBtnHighlight;
  928. }
  929. break;
  930. // -2 below surface
  931. case BDR_SUNKENINNER: // 2 : 1
  932. clrTL = ((flags & BF_SOFT) ? GetSysColor(COLOR_BTNSHADOW) : GetSysColor(COLOR_3DDKSHADOW));
  933. clrBR = GetSysColor(COLOR_3DLIGHT); // 4
  934. if (lpclrsc) {
  935. if (lpclrsc->clrBtnShadow != CLR_DEFAULT)
  936. clrTL = lpclrsc->clrBtnShadow;
  937. if (lpclrsc->clrBtnHighlight != CLR_DEFAULT)
  938. clrBR = lpclrsc->clrBtnHighlight;
  939. }
  940. break;
  941. default:
  942. return(FALSE);
  943. }
  944. }
  945. //
  946. // Draw the sides of the border. NOTE THAT THE ALGORITHM FAVORS THE
  947. // BOTTOM AND RIGHT SIDES, since the light source is assumed to be top
  948. // left. If we ever decide to let the user set the light source to a
  949. // particular corner, then change this algorithm.
  950. //
  951. // Bottom Right edges
  952. if (flags & (BF_RIGHT | BF_BOTTOM))
  953. {
  954. // Right
  955. if (flags & BF_RIGHT)
  956. {
  957. rc.right -= g_cxBorder;
  958. // PatBlt(hdc, rc.right, rc.top, g_cxBorder, rc.bottom - rc.top, PATCOPY);
  959. rcD.left = rc.right;
  960. rcD.right = rc.right + g_cxBorder;
  961. rcD.top = rc.top;
  962. rcD.bottom = rc.bottom;
  963. FillRectClr(hdc, &rcD, clrBR);
  964. }
  965. // Bottom
  966. if (flags & BF_BOTTOM)
  967. {
  968. rc.bottom -= g_cyBorder;
  969. // PatBlt(hdc, rc.left, rc.bottom, rc.right - rc.left, g_cyBorder, PATCOPY);
  970. rcD.left = rc.left;
  971. rcD.right = rc.right;
  972. rcD.top = rc.bottom;
  973. rcD.bottom = rc.bottom + g_cyBorder;
  974. FillRectClr(hdc, &rcD, clrBR);
  975. }
  976. }
  977. // Top Left edges
  978. if (flags & (BF_TOP | BF_LEFT))
  979. {
  980. // Left
  981. if (flags & BF_LEFT)
  982. {
  983. // PatBlt(hdc, rc.left, rc.top, g_cxBorder, rc.bottom - rc.top, PATCOPY);
  984. rc.left += g_cxBorder;
  985. rcD.left = rc.left - g_cxBorder;
  986. rcD.right = rc.left;
  987. rcD.top = rc.top;
  988. rcD.bottom = rc.bottom;
  989. FillRectClr(hdc, &rcD, clrTL);
  990. }
  991. // Top
  992. if (flags & BF_TOP)
  993. {
  994. // PatBlt(hdc, rc.left, rc.top, rc.right - rc.left, g_cyBorder, PATCOPY);
  995. rc.top += g_cyBorder;
  996. rcD.left = rc.left;
  997. rcD.right = rc.right;
  998. rcD.top = rc.top - g_cyBorder;
  999. rcD.bottom = rc.top;
  1000. FillRectClr(hdc, &rcD, clrTL);
  1001. }
  1002. }
  1003. }
  1004. if (bdrType = (edge & BDR_INNER))
  1005. {
  1006. //
  1007. // Strip this so the next time through, bdrType will be 0.
  1008. // Otherwise, we'll loop forever.
  1009. //
  1010. edge &= ~BDR_INNER;
  1011. goto DrawBorder;
  1012. }
  1013. //
  1014. // Fill the middle & clean up if asked
  1015. //
  1016. if (flags & BF_MIDDLE)
  1017. FillRectClr(hdc, &rc, (flags & BF_MONO) ? GetSysColor(COLOR_WINDOW) : GetSysColor(COLOR_BTNFACE));
  1018. if (flags & BF_ADJUST)
  1019. CopyRect(lprc, &rc);
  1020. return(TRUE);
  1021. }
  1022. void DrawBlankButton(HDC hdc, LPRECT lprc, DWORD wControlState)
  1023. {
  1024. BOOL fAdjusted;
  1025. if (wControlState & (DCHF_HOT | DCHF_PUSHED) &&
  1026. !(wControlState & DCHF_NOBORDER)) {
  1027. COLORSCHEME clrsc;
  1028. clrsc.dwSize = 1;
  1029. if (GetBkColor(hdc) == GetSysColor(COLOR_BTNSHADOW)) {
  1030. clrsc.clrBtnHighlight = GetSysColor(COLOR_BTNHIGHLIGHT);
  1031. clrsc.clrBtnShadow = GetSysColor(COLOR_BTNTEXT);
  1032. } else
  1033. clrsc.clrBtnHighlight = clrsc.clrBtnShadow = CLR_DEFAULT;
  1034. // if button is both DCHF_HOT and DCHF_PUSHED, DCHF_HOT wins here
  1035. CCDrawEdge(hdc, lprc, (wControlState & DCHF_HOT) ? BDR_RAISEDINNER : BDR_SUNKENOUTER,
  1036. (UINT) (BF_ADJUST | BF_RECT), &clrsc);
  1037. fAdjusted = TRUE;
  1038. } else {
  1039. fAdjusted = FALSE;
  1040. }
  1041. if (!(wControlState & DCHF_TRANSPARENT))
  1042. FillRectClr(hdc, lprc, GetBkColor(hdc));
  1043. if (!fAdjusted)
  1044. InflateRect(lprc, -g_cxBorder, -g_cyBorder);
  1045. }
  1046. #define CX_INCREMENT 1
  1047. #define CX_DECREMENT (-CX_INCREMENT)
  1048. #define MIDPOINT(x1, x2) ((x1 + x2) / 2)
  1049. #define CHEVRON_WIDTH(dSeg) (4 * dSeg)
  1050. void DrawChevron(HDC hdc, LPRECT lprc, DWORD dwFlags)
  1051. {
  1052. RECT rc;
  1053. CopyRect(&rc, lprc);
  1054. // draw the border and background
  1055. DrawBlankButton(hdc, &rc, dwFlags);
  1056. // offset the arrow if pushed
  1057. if (dwFlags & DCHF_PUSHED)
  1058. OffsetRect(&rc, CX_INCREMENT, CX_INCREMENT);
  1059. // draw the arrow
  1060. HBRUSH hbrSave = SelectBrush(hdc, GetSysColorBrush(COLOR_BTNTEXT));
  1061. int dSeg = (g_cxVScroll / 7);
  1062. dSeg = max(2, dSeg);
  1063. BOOL fFlipped = (dwFlags & DCHF_FLIPPED);
  1064. if (dwFlags & DCHF_HORIZONTAL)
  1065. {
  1066. // horizontal arrow
  1067. int x = MIDPOINT(rc.left, rc.right - CHEVRON_WIDTH(dSeg));
  1068. if (!fFlipped)
  1069. x += dSeg;
  1070. int yBase;
  1071. if (dwFlags & DCHF_TOPALIGN)
  1072. yBase = rc.top + (3 * dSeg);
  1073. else
  1074. yBase = MIDPOINT(rc.top, rc.bottom);
  1075. for (int y = -dSeg; y <= dSeg; y++)
  1076. {
  1077. PatBlt(hdc, x, yBase + y, dSeg, CX_INCREMENT, PATCOPY);
  1078. PatBlt(hdc, x + (dSeg * 2), yBase + y, dSeg, CX_INCREMENT, PATCOPY);
  1079. x += (fFlipped ? (y < 0) : (y >= 0)) ? CX_INCREMENT : CX_DECREMENT;
  1080. }
  1081. }
  1082. else
  1083. {
  1084. // vertical arrow
  1085. int y;
  1086. if (dwFlags & DCHF_TOPALIGN)
  1087. y = rc.top + CX_INCREMENT;
  1088. else
  1089. {
  1090. y = MIDPOINT(rc.top, rc.bottom - CHEVRON_WIDTH(dSeg));
  1091. if (!fFlipped)
  1092. {
  1093. y += dSeg;
  1094. }
  1095. }
  1096. int xBase = MIDPOINT(rc.left, rc.right);
  1097. for (int x = -dSeg; x <= dSeg; x++)
  1098. {
  1099. PatBlt(hdc, xBase + x, y, CX_INCREMENT, dSeg, PATCOPY);
  1100. PatBlt(hdc, xBase + x, y + (dSeg * 2), CX_INCREMENT, dSeg, PATCOPY);
  1101. y += (fFlipped ? (x < 0) : (x >= 0)) ? CX_DECREMENT : CX_INCREMENT;
  1102. }
  1103. }
  1104. // clean up
  1105. SelectBrush(hdc, hbrSave);
  1106. }
  1107. void SetWindowStyle(HWND hwnd, DWORD dwStyle, BOOL fOn)
  1108. {
  1109. if (hwnd)
  1110. {
  1111. DWORD_PTR dwStyleOld = GetWindowLongPtr(hwnd, GWL_STYLE);
  1112. if (fOn)
  1113. {
  1114. dwStyleOld |= dwStyle;
  1115. }
  1116. else
  1117. {
  1118. dwStyleOld &= ~(DWORD_PTR)dwStyle;
  1119. }
  1120. SetWindowLongPtr(hwnd, GWL_STYLE, dwStyleOld);
  1121. }
  1122. }
  1123. void SetWindowStyleEx(HWND hwnd, DWORD dwStyleEx, BOOL fOn)
  1124. {
  1125. if (hwnd)
  1126. {
  1127. DWORD_PTR dwExStyleOld = GetWindowLongPtr(hwnd, GWL_EXSTYLE);
  1128. if (fOn)
  1129. {
  1130. dwExStyleOld |= dwStyleEx;
  1131. }
  1132. else
  1133. {
  1134. dwExStyleOld &= ~(DWORD_PTR)dwStyleEx;
  1135. }
  1136. SetWindowLongPtr(hwnd, GWL_EXSTYLE, dwExStyleOld);
  1137. }
  1138. }
  1139. // Review chrisny: this can be moved into an object easily to handle generic droptarget, dropcursor
  1140. // , autoscrool, etc. . .
  1141. void _DragEnter(HWND hwndTarget, const POINTL ptStart, IDataObject *pdtObject)
  1142. {
  1143. RECT rc;
  1144. POINT pt;
  1145. GetWindowRect(hwndTarget, &rc);
  1146. //
  1147. // If hwndTarget is RTL mirrored, then measure the
  1148. // the client point from the visual right edge
  1149. // (near edge in RTL mirrored windows). [msadek]
  1150. //
  1151. if (IS_WINDOW_RTL_MIRRORED(hwndTarget))
  1152. pt.x = rc.right - ptStart.x;
  1153. else
  1154. pt.x = ptStart.x - rc.left;
  1155. pt.y = ptStart.y - rc.top;
  1156. DAD_DragEnterEx2(hwndTarget, pt, pdtObject);
  1157. return;
  1158. }
  1159. void _DragMove(HWND hwndTarget, const POINTL ptStart)
  1160. {
  1161. RECT rc;
  1162. POINT pt;
  1163. GetWindowRect(hwndTarget, &rc);
  1164. //
  1165. // If hwndTarget is RTL mirrored, then measure the
  1166. // the client point from the visual right edge
  1167. // (near edge in RTL mirrored windows). [msadek]
  1168. //
  1169. if (IS_WINDOW_RTL_MIRRORED(hwndTarget))
  1170. pt.x = rc.right - ptStart.x;
  1171. else
  1172. pt.x = ptStart.x - rc.left;
  1173. pt.y = ptStart.y - rc.top;
  1174. DAD_DragMove(pt);
  1175. return;
  1176. }
  1177. // Gets the bits from the parent for a rect relative to the client
  1178. BOOL SHSendPrintRect(HWND hwndParent, HWND hwnd, HDC hdc, RECT* prc)
  1179. {
  1180. HRGN hrgnOld = NULL;
  1181. POINT pt;
  1182. RECT rc;
  1183. if (prc)
  1184. {
  1185. hrgnOld = CreateRectRgn(0,0,0,0);
  1186. // Is there a clipping rgn set on the context already?
  1187. if (GetClipRgn(hdc, hrgnOld) == 0)
  1188. {
  1189. // No, then get rid of the one I just created. NOTE: hrgnOld is NULL meaning we will
  1190. // remove the region later that we set in this next call to SelectClipRgn
  1191. DeleteObject(hrgnOld);
  1192. hrgnOld = NULL;
  1193. }
  1194. IntersectClipRect(hdc, prc->left, prc->top, prc->right, prc->bottom);
  1195. }
  1196. GetWindowRect(hwnd, &rc);
  1197. MapWindowPoints(NULL, hwndParent, (POINT*)&rc, 2);
  1198. GetViewportOrgEx(hdc, &pt);
  1199. SetViewportOrgEx(hdc, pt.x - rc.left, pt.y - rc.top, NULL);
  1200. SendMessage(hwndParent, WM_PRINTCLIENT, (WPARAM)hdc, (LPARAM)PRF_CLIENT);
  1201. SetViewportOrgEx(hdc, pt.x, pt.y, NULL);
  1202. if (hrgnOld)
  1203. {
  1204. SelectClipRgn(hdc, hrgnOld);
  1205. DeleteObject(hrgnOld);
  1206. }
  1207. return TRUE;
  1208. }
  1209. //
  1210. // For security purposes, we pass an explicit lpApplication to avoid
  1211. // being spoofed by a path search. This just does some of the grunt
  1212. // work. To execute the program C:\Foo.exe with the command line
  1213. // argument /bar, you have to pass
  1214. //
  1215. // lpApplication = C:\Program Files\Foo.exe
  1216. // lpCommandLine = "C:\Program Files\Foo.exe" /bar
  1217. //
  1218. BOOL CreateProcessWithArgs(LPCTSTR pszApp, LPCTSTR pszArgs, LPCTSTR pszDirectory, PROCESS_INFORMATION *ppi)
  1219. {
  1220. STARTUPINFO si = {0};
  1221. si.cb = sizeof(si);
  1222. TCHAR szCommandLine[MAX_PATH * 2];
  1223. lstrcpyn(szCommandLine, pszApp, ARRAYSIZE(szCommandLine));
  1224. PathQuoteSpaces(szCommandLine);
  1225. StrCatBuff(szCommandLine, TEXT(" "), ARRAYSIZE(szCommandLine));
  1226. StrCatBuff(szCommandLine, pszArgs, ARRAYSIZE(szCommandLine));
  1227. return CreateProcess(pszApp, szCommandLine, NULL, NULL, FALSE, 0, NULL, pszDirectory, &si, ppi);
  1228. }
  1229. // From a mail regarding the DirectX fct below:
  1230. //
  1231. // You can definitely count on the following:
  1232. //
  1233. // (1) If shadow cursors are on, there is definitely not an exclusive mode app running.
  1234. // (2) If hot tracking is on, there is definitely not an exclusive mode app running.
  1235. // (3) If message boxes for SEM_NOGPFAULTERRORBOX, SEM_FAILCRITICALERRORS, or
  1236. // SEM_NOOPENFILEERRORBOX have not been disabled via SetErrorMode, then there
  1237. // is definitely not an exclusive mode app running.
  1238. //
  1239. // Note: we cannot use (3) since this is per-process.
  1240. BOOL IsDirectXAppRunningFullScreen()
  1241. {
  1242. BOOL fRet = FALSE;
  1243. BOOL fSPI;
  1244. if (SystemParametersInfo(SPI_GETCURSORSHADOW, 0, &fSPI, 0) && !fSPI)
  1245. {
  1246. if (SystemParametersInfo(SPI_GETHOTTRACKING, 0, &fSPI, 0) && !fSPI)
  1247. {
  1248. // There's a chance that a DirectX app is running full screen. Let's do the
  1249. // expensive DirectX calls that will tell us for sure.
  1250. fRet = _IsDirectXExclusiveMode();
  1251. }
  1252. }
  1253. return fRet;
  1254. }
  1255. BOOL _IsDirectXExclusiveMode()
  1256. {
  1257. BOOL fRet = FALSE;
  1258. // This code determines whether a DirectDraw 7 process (game) is running and
  1259. // whether it's exclusively holding the video to the machine in full screen mode.
  1260. // The code is probably to be considered untrusted and hence is wrapped in a
  1261. // __try / __except block. It could AV and therefore bring down shell
  1262. // with it. Not very good. If the code does raise an exception the release
  1263. // call is skipped. Tough. Don't trust the release method either.
  1264. IDirectDraw7 *pIDirectDraw7 = NULL;
  1265. HRESULT hr = CoCreateInstance(CLSID_DirectDraw7, NULL, CLSCTX_INPROC_SERVER,
  1266. IID_IDirectDraw7, (void**)&pIDirectDraw7);
  1267. if (SUCCEEDED(hr))
  1268. {
  1269. ASSERT(pIDirectDraw7);
  1270. __try
  1271. {
  1272. hr = IDirectDraw7_Initialize(pIDirectDraw7, NULL);
  1273. if (DD_OK == hr)
  1274. {
  1275. fRet = (IDirectDraw7_TestCooperativeLevel(pIDirectDraw7) ==
  1276. DDERR_EXCLUSIVEMODEALREADYSET);
  1277. }
  1278. IDirectDraw7_Release(pIDirectDraw7);
  1279. }
  1280. __except (EXCEPTION_EXECUTE_HANDLER)
  1281. {
  1282. }
  1283. }
  1284. return fRet;
  1285. }