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.

672 lines
17 KiB

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