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.

662 lines
16 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. EmulateUSER.cpp
  5. Abstract:
  6. EmulateSetWindowsHook:
  7. Handles a behaviour difference on the arguments passed to
  8. SetWindowsHook, for the case where:
  9. (hMod == NULL) && (dwThreadId == 0)
  10. According to MSDN:
  11. An error may occur if the hMod parameter is NULL and the dwThreadId
  12. parameter is zero or specifies the identifier of a thread created
  13. by another process.
  14. So the NT behaviour is correct. However, on win9x, hMod was assumed to
  15. be the current module if NULL and dwThreadId == 0.
  16. Note: this doesn't affect the case where the thread belongs to another
  17. process.
  18. ForceTemporaryModeChange:
  19. A hack for several apps that permanently change the display mode and
  20. fail to restore it correctly. Some of these apps do restore the
  21. resolution, but not the refresh rate. 1024x768 @ 60Hz looks really bad.
  22. Also includes a hack for cursors: the cursor visibility count is not
  23. persistent through mode changes.
  24. CorrectWndProc:
  25. When you specify a NULL window proc we make it DefWindowProc instead to
  26. mimic the 9x behavior.
  27. EmulateToASCII:
  28. Remove stray characters from ToAscii. This usually manifests itself as
  29. a locked keyboard since this is the API that's used to convert the scan
  30. codes to actual characters.
  31. EmulateShowWindow:
  32. Win9x didn't use the high bits of nCmdShow, which means they got
  33. stripped off.
  34. EmulateGetMessage:
  35. Check wMsgFilterMax in GetMessage and PeekMessage for bad values and if
  36. found change them to 0x7FFF.
  37. PaletteRestore:
  38. Persist palette state through mode switches. This includes the entries
  39. themselves and the usage flag (see SetSystemPaletteUse).
  40. Notes:
  41. This is a general purpose shim.
  42. History:
  43. 01/20/2000 linstev Created
  44. --*/
  45. #include "precomp.h"
  46. IMPLEMENT_SHIM_BEGIN(EmulateUSER)
  47. #include "ShimHookMacro.h"
  48. APIHOOK_ENUM_BEGIN
  49. APIHOOK_ENUM_ENTRY(SetWindowsHookExA)
  50. APIHOOK_ENUM_ENTRY(SetWindowLongA)
  51. APIHOOK_ENUM_ENTRY(RegisterClassA)
  52. APIHOOK_ENUM_ENTRY(ChangeDisplaySettingsA)
  53. APIHOOK_ENUM_ENTRY(ChangeDisplaySettingsExA)
  54. APIHOOK_ENUM_ENTRY(ToAscii)
  55. APIHOOK_ENUM_ENTRY(ToAsciiEx)
  56. APIHOOK_ENUM_ENTRY(ShowWindow)
  57. APIHOOK_ENUM_ENTRY(PeekMessageA)
  58. APIHOOK_ENUM_ENTRY(GetMessageA)
  59. APIHOOK_ENUM_ENTRY(SetSystemPaletteUse)
  60. APIHOOK_ENUM_ENTRY(AnimatePalette)
  61. APIHOOK_ENUM_ENTRY(RealizePalette)
  62. APIHOOK_ENUM_END
  63. CRITICAL_SECTION g_csPalette;
  64. UINT g_uPaletteLastUse = SYSPAL_STATIC;
  65. DWORD g_peTable[256] =
  66. {
  67. 0x00000000, 0x00000080, 0x00008000, 0x00008080,
  68. 0x00800000, 0x00800080, 0x00808000, 0x00C0C0C0,
  69. 0x00C0DCC0, 0x00F0CAA6, 0x00081824, 0x00142830,
  70. 0x0018303C, 0x00304D61, 0x0051514D, 0x004D7161,
  71. 0x00826D61, 0x000C1414, 0x00597582, 0x00759E08,
  72. 0x00303438, 0x00AA6938, 0x00203428, 0x00496161,
  73. 0x0049869E, 0x007D9A6D, 0x000869CB, 0x008E8682,
  74. 0x0075615D, 0x000061EB, 0x00000871, 0x002C3830,
  75. 0x000471EF, 0x008E92AA, 0x00306DF7, 0x0004C3C3,
  76. 0x0092AAB2, 0x00101814, 0x00040C08, 0x000C7110,
  77. 0x00CFA282, 0x000008AA, 0x0028412C, 0x00498EB2,
  78. 0x00204D61, 0x00555955, 0x0004D3D3, 0x001C3C4D,
  79. 0x0020A6F7, 0x0010A210, 0x0018241C, 0x005DAEF3,
  80. 0x00719EAA, 0x00B2E720, 0x00102871, 0x0086C3D3,
  81. 0x00288A2C, 0x000C51BA, 0x0059716D, 0x00494D4D,
  82. 0x00AAB6C3, 0x00005100, 0x0020CBF7, 0x004D8A51,
  83. 0x00BEC7B2, 0x00043CBA, 0x00101C18, 0x000851DF,
  84. 0x00A6E7A6, 0x009ECF24, 0x00797592, 0x00AE7559,
  85. 0x009E8269, 0x00CFE3DF, 0x000C2030, 0x0028692C,
  86. 0x009EA2A2, 0x00F7C782, 0x0034617D, 0x00B6BEBE,
  87. 0x00969E86, 0x00DBFBD3, 0x00655149, 0x0065EF65,
  88. 0x00AED3D3, 0x00E7924D, 0x00B2BEB2, 0x00D7DBDB,
  89. 0x00797571, 0x00344D59, 0x0086B2CF, 0x00512C14,
  90. 0x00A6FBFB, 0x00385965, 0x00828E92, 0x001C4161,
  91. 0x00595961, 0x00002000, 0x003C6D7D, 0x005DB2D7,
  92. 0x0038EF3C, 0x0051CB55, 0x001C2424, 0x0061C3F3,
  93. 0x0008A2A2, 0x0038413C, 0x00204951, 0x00108A14,
  94. 0x00103010, 0x007DE7F7, 0x00143449, 0x00B2652C,
  95. 0x00F7EBAA, 0x003C7192, 0x0004FBFB, 0x00696151,
  96. 0x00EFC796, 0x000441D7, 0x00000404, 0x00388AF7,
  97. 0x008AD3F3, 0x00006500, 0x000004E3, 0x00DBFFFF,
  98. 0x00F7AE69, 0x00CF864D, 0x0055A2D3, 0x00EBEFE3,
  99. 0x00EB8A41, 0x00CF9261, 0x00C3F710, 0x008E8E82,
  100. 0x00FBFFFF, 0x00104110, 0x00040851, 0x0082FBFB,
  101. 0x003CC734, 0x00088A8A, 0x00384545, 0x00514134,
  102. 0x003C7996, 0x001C6161, 0x00EBB282, 0x00004100,
  103. 0x00715951, 0x00A2AAA6, 0x00B2B6B2, 0x00C3FBFB,
  104. 0x00000834, 0x0028413C, 0x00C7C7CF, 0x00CFD3D3,
  105. 0x00824520, 0x0008CB0C, 0x001C1C1C, 0x00A6B29A,
  106. 0x0071A6BE, 0x00CF9E6D, 0x006D7161, 0x00008A04,
  107. 0x005171BE, 0x00C7D3C3, 0x00969E96, 0x00798696,
  108. 0x002C1C10, 0x00385149, 0x00BE7538, 0x0008141C,
  109. 0x00C3C7C7, 0x00202C28, 0x00D3E3CF, 0x0071826D,
  110. 0x00653C1C, 0x0004EF08, 0x00345575, 0x006D92A6,
  111. 0x00797979, 0x0086F38A, 0x00925528, 0x00E3E7E7,
  112. 0x00456151, 0x001C499A, 0x00656961, 0x008E9EA2,
  113. 0x007986D3, 0x00204151, 0x008AC7E3, 0x00007100,
  114. 0x00519EBE, 0x0010510C, 0x00A6AAAA, 0x002C3030,
  115. 0x00D37934, 0x00183030, 0x0049828E, 0x00CBFBC3,
  116. 0x006D7171, 0x000428A6, 0x004D4545, 0x00040C14,
  117. 0x00087575, 0x0071CB79, 0x004D6D0C, 0x00FBFBD3,
  118. 0x00AAB2AE, 0x00929292, 0x00F39E55, 0x00005D00,
  119. 0x00E3D7B2, 0x00F7FBC3, 0x003C5951, 0x0004B2B2,
  120. 0x0034658E, 0x000486EF, 0x00F7FBE3, 0x00616161,
  121. 0x00DFE3DF, 0x001C100C, 0x0008100C, 0x0008180C,
  122. 0x00598600, 0x0024FBFB, 0x00346171, 0x00042CC7,
  123. 0x00AEC79A, 0x0045AE4D, 0x0028A62C, 0x00EFA265,
  124. 0x007D8282, 0x00F7D79A, 0x0065D3F7, 0x00E3E7BA,
  125. 0x00003000, 0x00245571, 0x00DF823C, 0x008AAEC3,
  126. 0x00A2C3D3, 0x00A6FBA2, 0x00F3FFF3, 0x00AAD7E7,
  127. 0x00EFEFC3, 0x0055F7FB, 0x00EFF3F3, 0x00BED3B2,
  128. 0x0004EBEB, 0x00A6E3F7, 0x00F0FBFF, 0x00A4A0A0,
  129. 0x00808080, 0x000000FF, 0x0000FF00, 0x0000FFFF,
  130. 0x00FF0000, 0x00FF00FF, 0x00FFFF00, 0x00FFFFFF
  131. };
  132. #define MODE_MASK (CDS_UPDATEREGISTRY | CDS_TEST | CDS_FULLSCREEN | CDS_GLOBAL | CDS_SET_PRIMARY | CDS_VIDEOPARAMETERS | CDS_RESET | CDS_NORESET)
  133. /*++
  134. Handle NULL for hModule
  135. --*/
  136. HHOOK
  137. APIHOOK(SetWindowsHookExA)(
  138. int idHook,
  139. HOOKPROC lpfn,
  140. HINSTANCE hMod,
  141. DWORD dwThreadId
  142. )
  143. {
  144. if (!hMod && !dwThreadId) {
  145. LOGN(
  146. eDbgLevelError,
  147. "[SetWindowsHookExA] hMod is NULL - correcting.");
  148. hMod = GetModuleHandle(NULL);
  149. }
  150. return ORIGINAL_API(SetWindowsHookExA)(
  151. idHook,
  152. lpfn,
  153. hMod,
  154. dwThreadId);
  155. }
  156. /*++
  157. Set the WndProc to DefWndProc if it's NULL.
  158. --*/
  159. LONG
  160. APIHOOK(SetWindowLongA)(
  161. HWND hWnd,
  162. int nIndex,
  163. LONG dwNewLong
  164. )
  165. {
  166. if ((nIndex == GWL_WNDPROC) && (dwNewLong == 0)) {
  167. LOGN(eDbgLevelError, "[SetWindowLongA] Null WndProc specified - correcting.");
  168. dwNewLong = (LONG) DefWindowProcA;
  169. }
  170. return ORIGINAL_API(SetWindowLongA)(hWnd, nIndex, dwNewLong);
  171. }
  172. /*++
  173. Set the WndProc to DefWndProc if it's NULL.
  174. --*/
  175. ATOM
  176. APIHOOK(RegisterClassA)(
  177. CONST WNDCLASSA *lpWndClass
  178. )
  179. {
  180. if (!(lpWndClass->lpfnWndProc)) {
  181. WNDCLASSA wcNewWndClass = *lpWndClass;
  182. LOGN(eDbgLevelError, "[RegisterClassA] Null WndProc specified - correcting.");
  183. wcNewWndClass.lpfnWndProc = DefWindowProcA;
  184. return ORIGINAL_API(RegisterClassA)(&wcNewWndClass);
  185. }
  186. else
  187. {
  188. return ORIGINAL_API(RegisterClassA)(lpWndClass);
  189. }
  190. }
  191. /*++
  192. Change the palette entries if applicable.
  193. --*/
  194. void
  195. FixPalette()
  196. {
  197. EnterCriticalSection(&g_csPalette);
  198. //
  199. // We realized a palette before this, so let's have a go at restoring
  200. // all the palette state.
  201. //
  202. HDC hdc = GetDC(GetActiveWindow());
  203. if (hdc) {
  204. if (GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) {
  205. //
  206. // We're now in a palettized mode
  207. //
  208. SetSystemPaletteUse(hdc, g_uPaletteLastUse);
  209. LPLOGPALETTE plogpal = (LPLOGPALETTE) malloc(sizeof(LOGPALETTE) + sizeof(g_peTable));
  210. if (plogpal) {
  211. //
  212. // Create a palette we can realize
  213. //
  214. HPALETTE hPal;
  215. plogpal->palVersion = 0x0300;
  216. plogpal->palNumEntries = 256;
  217. MoveMemory(&plogpal->palPalEntry[0], &g_peTable[0], sizeof(g_peTable));
  218. if (hPal = CreatePalette(plogpal)) {
  219. //
  220. // Realize the palette
  221. //
  222. HPALETTE hOld = SelectPalette(hdc, hPal, FALSE);
  223. RealizePalette(hdc);
  224. SelectPalette(hdc, hOld, FALSE);
  225. DeleteObject(hPal);
  226. }
  227. free(plogpal);
  228. }
  229. }
  230. ReleaseDC(0, hdc);
  231. }
  232. LeaveCriticalSection(&g_csPalette);
  233. }
  234. /*++
  235. Force temporary change, fixup cursor and palette.
  236. --*/
  237. LONG
  238. APIHOOK(ChangeDisplaySettingsA)(
  239. LPDEVMODEA lpDevMode,
  240. DWORD dwFlags
  241. )
  242. {
  243. dwFlags &= MODE_MASK;
  244. if (dwFlags == 0 || dwFlags == CDS_UPDATEREGISTRY) {
  245. dwFlags = CDS_FULLSCREEN;
  246. LOGN(eDbgLevelError,
  247. "[ChangeDisplaySettingsA] Changing flags to CDS_FULLSCREEN.");
  248. }
  249. ShowCursor(FALSE);
  250. INT iCntOld = ShowCursor(TRUE);
  251. LONG lRet = ORIGINAL_API(ChangeDisplaySettingsA)(
  252. lpDevMode,
  253. dwFlags);
  254. INT iCntNew = ShowCursor(FALSE);
  255. while (iCntNew != iCntOld) {
  256. iCntNew = ShowCursor(iCntNew < iCntOld ? TRUE : FALSE);
  257. }
  258. FixPalette();
  259. return lRet;
  260. }
  261. /*++
  262. Force temporary change, fixup cursor and palette.
  263. --*/
  264. LONG
  265. APIHOOK(ChangeDisplaySettingsExA)(
  266. LPCSTR lpszDeviceName,
  267. LPDEVMODEA lpDevMode,
  268. HWND hwnd,
  269. DWORD dwFlags,
  270. LPVOID lParam
  271. )
  272. {
  273. dwFlags &= MODE_MASK;
  274. if (dwFlags == 0 || dwFlags == CDS_UPDATEREGISTRY) {
  275. dwFlags = CDS_FULLSCREEN;
  276. LOGN(eDbgLevelError,
  277. "[ChangeDisplaySettingsExA] Changing flags to CDS_FULLSCREEN.");
  278. }
  279. ShowCursor(FALSE);
  280. INT iCntOld = ShowCursor(TRUE);
  281. LONG lRet = ORIGINAL_API(ChangeDisplaySettingsExA)(
  282. lpszDeviceName,
  283. lpDevMode,
  284. hwnd,
  285. dwFlags,
  286. lParam);
  287. INT iCntNew = ShowCursor(FALSE);
  288. while (iCntNew != iCntOld) {
  289. iCntNew = ShowCursor(iCntNew < iCntOld ? TRUE : FALSE);
  290. }
  291. FixPalette();
  292. return lRet;
  293. }
  294. /*++
  295. Remove stray characters from the end of a translation.
  296. --*/
  297. int
  298. APIHOOK(ToAscii)(
  299. UINT wVirtKey,
  300. UINT wScanCode,
  301. PBYTE lpKeyState,
  302. LPWORD lpChar,
  303. UINT wFlags
  304. )
  305. {
  306. int iRet = ORIGINAL_API(ToAscii)(
  307. wVirtKey,
  308. wScanCode,
  309. lpKeyState,
  310. lpChar,
  311. wFlags);
  312. LPBYTE p = (LPBYTE)lpChar;
  313. p[iRet] = '\0';
  314. return iRet;
  315. }
  316. /*++
  317. Remove stray characters from the end of a translation.
  318. --*/
  319. int
  320. APIHOOK(ToAsciiEx)(
  321. UINT wVirtKey,
  322. UINT wScanCode,
  323. PBYTE lpKeyState,
  324. LPWORD lpChar,
  325. UINT wFlags,
  326. HKL dwhkl
  327. )
  328. {
  329. int iRet = ORIGINAL_API(ToAsciiEx)(
  330. wVirtKey,
  331. wScanCode,
  332. lpKeyState,
  333. lpChar,
  334. wFlags,
  335. dwhkl);
  336. LPBYTE p = (LPBYTE) lpChar;
  337. p[iRet] = '\0';
  338. return iRet;
  339. }
  340. /*++
  341. Strip the high bits off nCmdShow
  342. --*/
  343. LONG
  344. APIHOOK(ShowWindow)(
  345. HWND hWnd,
  346. int nCmdShow
  347. )
  348. {
  349. if (nCmdShow & 0xFFFF0000) {
  350. LOGN( eDbgLevelWarning, "[ShowWindow] Fixing invalid parameter");
  351. // Remove high bits
  352. nCmdShow &= 0xFFFF;
  353. }
  354. return ORIGINAL_API(ShowWindow)(hWnd, nCmdShow);
  355. }
  356. /*++
  357. This fixes the bad wMsgFilterMax parameter.
  358. --*/
  359. BOOL
  360. APIHOOK(PeekMessageA)(
  361. LPMSG lpMsg,
  362. HWND hWnd,
  363. UINT wMsgFilterMin,
  364. UINT wMsgFilterMax,
  365. UINT wRemoveMsg
  366. )
  367. {
  368. if ((wMsgFilterMin == 0) && (wMsgFilterMax == 0xFFFFFFFF)) {
  369. LOGN( eDbgLevelWarning, "[PeekMessageA] Correcting parameters");
  370. wMsgFilterMax = 0;
  371. }
  372. return ORIGINAL_API(PeekMessageA)(
  373. lpMsg,
  374. hWnd,
  375. wMsgFilterMin,
  376. wMsgFilterMax,
  377. wRemoveMsg);
  378. }
  379. /*++
  380. This fixes the bad wMsgFilterMax parameter.
  381. --*/
  382. BOOL
  383. APIHOOK(GetMessageA)(
  384. LPMSG lpMsg,
  385. HWND hWnd,
  386. UINT wMsgFilterMin,
  387. UINT wMsgFilterMax
  388. )
  389. {
  390. if ((wMsgFilterMin == 0) && (wMsgFilterMax == 0xFFFFFFFF)) {
  391. LOGN( eDbgLevelWarning, "[GetMessageA] Correcting parameters");
  392. wMsgFilterMax = 0;
  393. }
  394. return ORIGINAL_API(GetMessageA)(
  395. lpMsg,
  396. hWnd,
  397. wMsgFilterMin,
  398. wMsgFilterMax);
  399. }
  400. /*++
  401. Track the system palette use
  402. --*/
  403. UINT
  404. APIHOOK(SetSystemPaletteUse)(
  405. HDC hdc,
  406. UINT uUsage
  407. )
  408. {
  409. EnterCriticalSection(&g_csPalette);
  410. g_uPaletteLastUse = uUsage;
  411. UINT uRet = ORIGINAL_API(SetSystemPaletteUse)(hdc, uUsage);
  412. LeaveCriticalSection(&g_csPalette);
  413. return uRet;
  414. }
  415. /*++
  416. Fill in the last known palette if anything was realized
  417. --*/
  418. UINT
  419. APIHOOK(RealizePalette)(
  420. HDC hdc
  421. )
  422. {
  423. EnterCriticalSection(&g_csPalette);
  424. UINT uRet = ORIGINAL_API(RealizePalette)(hdc);
  425. if (uRet) {
  426. //
  427. // Copy the current logical palette to our global store
  428. //
  429. HPALETTE hPal = (HPALETTE) GetCurrentObject(hdc, OBJ_PAL);
  430. if (hPal) {
  431. GetPaletteEntries(hPal, 0, 256, (PALETTEENTRY *)&g_peTable);
  432. }
  433. }
  434. LeaveCriticalSection(&g_csPalette);
  435. return uRet;
  436. }
  437. /*++
  438. Update our private palette with the new entries.
  439. --*/
  440. BOOL
  441. APIHOOK(AnimatePalette)(
  442. HPALETTE hPal,
  443. UINT iStartIndex,
  444. UINT cEntries,
  445. CONST PALETTEENTRY *ppe
  446. )
  447. {
  448. EnterCriticalSection(&g_csPalette);
  449. BOOL bRet = ORIGINAL_API(AnimatePalette)(hPal, iStartIndex, cEntries, ppe);
  450. if (bRet) {
  451. //
  452. // We have to populate our global settings
  453. //
  454. PALETTEENTRY peTable[256];
  455. if (GetPaletteEntries(hPal, iStartIndex, cEntries, &peTable[iStartIndex]) == cEntries) {
  456. //
  457. // Replace all the entries in our global table that are reserved
  458. // for animation.
  459. //
  460. for (UINT i=iStartIndex; i<iStartIndex + cEntries; i++) {
  461. LPPALETTEENTRY p = (LPPALETTEENTRY)&g_peTable[i];
  462. if (p->peFlags & PC_RESERVED) {
  463. //
  464. // This entry is being animated
  465. //
  466. p->peRed = peTable[i].peRed;
  467. p->peGreen = peTable[i].peGreen;
  468. p->peBlue = peTable[i].peBlue;
  469. }
  470. }
  471. }
  472. }
  473. LeaveCriticalSection(&g_csPalette);
  474. return bRet;
  475. }
  476. /*++
  477. Register hooked functions
  478. --*/
  479. BOOL
  480. NOTIFY_FUNCTION(
  481. DWORD fdwReason
  482. )
  483. {
  484. if (fdwReason == DLL_PROCESS_ATTACH) {
  485. //
  486. // Critical section for palette globals
  487. //
  488. InitializeCriticalSection(&g_csPalette);
  489. }
  490. return TRUE;
  491. }
  492. HOOK_BEGIN
  493. CALL_NOTIFY_FUNCTION
  494. APIHOOK_ENTRY(USER32.DLL, SetWindowsHookExA)
  495. APIHOOK_ENTRY(USER32.DLL, SetWindowLongA)
  496. APIHOOK_ENTRY(USER32.DLL, RegisterClassA)
  497. APIHOOK_ENTRY(USER32.DLL, ChangeDisplaySettingsA)
  498. APIHOOK_ENTRY(USER32.DLL, ChangeDisplaySettingsExA)
  499. APIHOOK_ENTRY(USER32.DLL, ToAscii)
  500. APIHOOK_ENTRY(USER32.DLL, ToAsciiEx)
  501. APIHOOK_ENTRY(USER32.DLL, ShowWindow)
  502. APIHOOK_ENTRY(USER32.DLL, PeekMessageA)
  503. APIHOOK_ENTRY(USER32.DLL, GetMessageA)
  504. APIHOOK_ENTRY(GDI32.DLL, SetSystemPaletteUse);
  505. APIHOOK_ENTRY(GDI32.DLL, AnimatePalette);
  506. APIHOOK_ENTRY(GDI32.DLL, RealizePalette);
  507. HOOK_END
  508. IMPLEMENT_SHIM_END