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.

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