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.

488 lines
8.8 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. ForceKeepFocus.cpp
  5. Abstract:
  6. Some applications destroy windows that are topmost. In this case, focus
  7. falls to the next topmost window. Of course, that window might be a window
  8. from another application. If that is that case, then the app will
  9. unexpectedly lose focus.
  10. The fix is to make sure that another app window has focus before we destroy
  11. the top one.
  12. An additional fix is included in this shim: after a window is created, we
  13. send a WM_TIMECHANGE message because Star Trek Generations blocked it's thread
  14. waiting for a message. On Win9x a WM_COMMAND comes through, but I haven't been
  15. able to repro this on other applications.
  16. Notes:
  17. This is a general purpose shim.
  18. History:
  19. 06/09/2000 linstev Created
  20. --*/
  21. #include "precomp.h"
  22. IMPLEMENT_SHIM_BEGIN(ForceKeepFocus)
  23. #include "ShimHookMacro.h"
  24. APIHOOK_ENUM_BEGIN
  25. APIHOOK_ENUM_ENTRY(CreateWindowExA)
  26. APIHOOK_ENUM_ENTRY(CreateWindowExW)
  27. APIHOOK_ENUM_ENTRY(CreateDialogParamA)
  28. APIHOOK_ENUM_ENTRY(CreateDialogParamW)
  29. APIHOOK_ENUM_ENTRY(CreateDialogIndirectParamA)
  30. APIHOOK_ENUM_ENTRY(CreateDialogIndirectParamW)
  31. APIHOOK_ENUM_ENTRY(CreateDialogIndirectParamAorW)
  32. APIHOOK_ENUM_ENTRY(DestroyWindow)
  33. APIHOOK_ENUM_END
  34. //
  35. // List of all app windows
  36. //
  37. struct HWNDITEM
  38. {
  39. HWND hWndParent;
  40. HWND hWnd;
  41. HWNDITEM *next;
  42. };
  43. HWNDITEM *g_hWndList = NULL;
  44. //
  45. // Critical section for list access
  46. //
  47. CRITICAL_SECTION g_csList;
  48. /*++
  49. Add a window to our list.
  50. --*/
  51. void
  52. AddItem(
  53. HWND hWndParent,
  54. HWND hWnd
  55. )
  56. {
  57. if (IsWindow(hWnd) && IsWindowVisible(hWndParent))
  58. {
  59. EnterCriticalSection(&g_csList);
  60. HWNDITEM *hitem = (HWNDITEM *) malloc(sizeof(HWNDITEM));
  61. if (hitem)
  62. {
  63. hitem->hWndParent = hWndParent;
  64. hitem->hWnd = hWnd;
  65. hitem->next = g_hWndList;
  66. g_hWndList = hitem;
  67. DPFN( eDbgLevelInfo, "Adding window %08lx with parent %08lx",
  68. hWnd,
  69. hWndParent);
  70. }
  71. else
  72. {
  73. DPFN( eDbgLevelError, "Failed to allocate list item");
  74. }
  75. LeaveCriticalSection(&g_csList);
  76. }
  77. //
  78. // Some apps get stuck waiting for a message: not really part of this
  79. // shim, but shouldn't be harmful
  80. //
  81. if (IsWindow(hWnd))
  82. {
  83. PostMessageA(hWnd, WM_TIMECHANGE, 0, 0);
  84. }
  85. }
  86. /*++
  87. Remove a window from the list and return another visible window that will
  88. become the next top window.
  89. --*/
  90. HWND
  91. RemoveItem(
  92. HWND hWnd
  93. )
  94. {
  95. HWND hRet = NULL;
  96. EnterCriticalSection(&g_csList);
  97. //
  98. // Remove the window and all it's children
  99. //
  100. HWNDITEM *hcurr = g_hWndList;
  101. HWNDITEM *hprev = NULL;
  102. while (hcurr)
  103. {
  104. if ((hcurr->hWndParent == hWnd) ||
  105. (hcurr->hWnd == hWnd))
  106. {
  107. HWNDITEM *hfree;
  108. DPFN( eDbgLevelInfo, "Removing %08lx", hcurr->hWnd);
  109. if (hprev)
  110. {
  111. hprev->next = hcurr->next;
  112. }
  113. else
  114. {
  115. g_hWndList = hcurr->next;
  116. }
  117. hfree = hcurr;
  118. hcurr = hcurr->next;
  119. free(hfree);
  120. continue;
  121. }
  122. hprev = hcurr;
  123. hcurr = hcurr->next;
  124. }
  125. //
  126. // Find another window to get focus
  127. //
  128. hcurr = g_hWndList;
  129. while (hcurr)
  130. {
  131. if (IsWindowVisible(hcurr->hWnd))
  132. {
  133. hRet = hcurr->hWnd;
  134. break;
  135. }
  136. hcurr = hcurr->next;
  137. }
  138. if (hRet)
  139. {
  140. DPFN( eDbgLevelInfo, "Giving focus to %08lx", hRet);
  141. }
  142. LeaveCriticalSection(&g_csList);
  143. return hRet;
  144. }
  145. /*++
  146. Track the created window and post a WM_COMMAND message.
  147. --*/
  148. HWND
  149. APIHOOK(CreateWindowExA)(
  150. DWORD dwExStyle,
  151. LPCSTR lpClassName,
  152. LPCSTR lpWindowName,
  153. DWORD dwStyle,
  154. int x,
  155. int y,
  156. int nWidth,
  157. int nHeight,
  158. HWND hWndParent,
  159. HMENU hMenu,
  160. HINSTANCE hInstance,
  161. LPVOID lpParam
  162. )
  163. {
  164. HWND hRet;
  165. hRet = ORIGINAL_API(CreateWindowExA)(
  166. dwExStyle,
  167. lpClassName,
  168. lpWindowName,
  169. dwStyle,
  170. x,
  171. y,
  172. nWidth,
  173. nHeight,
  174. hWndParent,
  175. hMenu,
  176. hInstance,
  177. lpParam);
  178. AddItem(hWndParent, hRet);
  179. return hRet;
  180. }
  181. /*++
  182. Track the created window and post a WM_COMMAND message.
  183. --*/
  184. HWND
  185. APIHOOK(CreateWindowExW)(
  186. DWORD dwExStyle,
  187. LPCWSTR lpClassName,
  188. LPCWSTR lpWindowName,
  189. DWORD dwStyle,
  190. int x,
  191. int y,
  192. int nWidth,
  193. int nHeight,
  194. HWND hWndParent,
  195. HMENU hMenu,
  196. HINSTANCE hInstance,
  197. LPVOID lpParam
  198. )
  199. {
  200. HWND hRet;
  201. hRet = ORIGINAL_API(CreateWindowExW)(
  202. dwExStyle,
  203. lpClassName,
  204. lpWindowName,
  205. dwStyle,
  206. x,
  207. y,
  208. nWidth,
  209. nHeight,
  210. hWndParent,
  211. hMenu,
  212. hInstance,
  213. lpParam);
  214. AddItem(hWndParent, hRet);
  215. return hRet;
  216. }
  217. /*++
  218. Track the created window and post a WM_COMMAND message.
  219. --*/
  220. HWND
  221. APIHOOK(CreateDialogParamA)(
  222. HINSTANCE hInstance,
  223. LPCSTR lpTemplateName,
  224. HWND hWndParent,
  225. DLGPROC lpDialogFunc,
  226. LPARAM dwInitParam
  227. )
  228. {
  229. HWND hRet;
  230. hRet = ORIGINAL_API(CreateDialogParamA)(
  231. hInstance,
  232. lpTemplateName,
  233. hWndParent,
  234. lpDialogFunc,
  235. dwInitParam);
  236. AddItem(hWndParent, hRet);
  237. return hRet;
  238. }
  239. /*++
  240. Track the created window and post a WM_COMMAND message.
  241. --*/
  242. HWND
  243. APIHOOK(CreateDialogParamW)(
  244. HINSTANCE hInstance,
  245. LPCWSTR lpTemplateName,
  246. HWND hWndParent,
  247. DLGPROC lpDialogFunc,
  248. LPARAM dwInitParam
  249. )
  250. {
  251. HWND hRet;
  252. hRet = ORIGINAL_API(CreateDialogParamW)(
  253. hInstance,
  254. lpTemplateName,
  255. hWndParent,
  256. lpDialogFunc,
  257. dwInitParam);
  258. AddItem(hWndParent, hRet);
  259. return hRet;
  260. }
  261. /*++
  262. Track the created window and post a WM_COMMAND message.
  263. --*/
  264. HWND
  265. APIHOOK(CreateDialogIndirectParamA)(
  266. HINSTANCE hInstance,
  267. LPCDLGTEMPLATE lpTemplate,
  268. HWND hWndParent,
  269. DLGPROC lpDialogFunc,
  270. LPARAM lParamInit
  271. )
  272. {
  273. HWND hRet;
  274. hRet = ORIGINAL_API(CreateDialogIndirectParamA)(
  275. hInstance,
  276. lpTemplate,
  277. hWndParent,
  278. lpDialogFunc,
  279. lParamInit);
  280. AddItem(hWndParent, hRet);
  281. return hRet;
  282. }
  283. /*++
  284. Track the created window and post a WM_COMMAND message.
  285. --*/
  286. HWND
  287. APIHOOK(CreateDialogIndirectParamW)(
  288. HINSTANCE hInstance,
  289. LPCDLGTEMPLATE lpTemplate,
  290. HWND hWndParent,
  291. DLGPROC lpDialogFunc,
  292. LPARAM lParamInit
  293. )
  294. {
  295. HWND hRet;
  296. hRet = ORIGINAL_API(CreateDialogIndirectParamW)(
  297. hInstance,
  298. lpTemplate,
  299. hWndParent,
  300. lpDialogFunc,
  301. lParamInit);
  302. AddItem(hWndParent, hRet);
  303. return hRet;
  304. }
  305. /*++
  306. Track the created window and post a WM_COMMAND message.
  307. --*/
  308. HWND
  309. APIHOOK(CreateDialogIndirectParamAorW)(
  310. HINSTANCE hInstance,
  311. LPCDLGTEMPLATE lpTemplate,
  312. HWND hWndParent,
  313. DLGPROC lpDialogFunc,
  314. LPARAM lParamInit
  315. )
  316. {
  317. HWND hRet;
  318. hRet = ORIGINAL_API(CreateDialogIndirectParamAorW)(
  319. hInstance,
  320. lpTemplate,
  321. hWndParent,
  322. lpDialogFunc,
  323. lParamInit);
  324. AddItem(hWndParent, hRet);
  325. return hRet;
  326. }
  327. /*++
  328. Destroy the window and make sure the focus falls to another app window,
  329. rather than another app altogether.
  330. --*/
  331. BOOL
  332. APIHOOK(DestroyWindow)(
  333. HWND hWnd
  334. )
  335. {
  336. HWND hWndNew = RemoveItem(hWnd);
  337. if (hWndNew)
  338. {
  339. SetForegroundWindow(hWndNew);
  340. }
  341. BOOL bRet = ORIGINAL_API(DestroyWindow)(hWnd);
  342. if (hWndNew)
  343. {
  344. SetForegroundWindow(hWndNew);
  345. }
  346. return bRet;
  347. }
  348. /*++
  349. Register hooked functions
  350. --*/
  351. BOOL
  352. NOTIFY_FUNCTION(
  353. DWORD fdwReason)
  354. {
  355. if (fdwReason == DLL_PROCESS_ATTACH)
  356. {
  357. InitializeCriticalSection(&g_csList);
  358. }
  359. return TRUE;
  360. }
  361. HOOK_BEGIN
  362. CALL_NOTIFY_FUNCTION
  363. APIHOOK_ENTRY(USER32.DLL, CreateWindowExA)
  364. APIHOOK_ENTRY(USER32.DLL, CreateWindowExW)
  365. APIHOOK_ENTRY(USER32.DLL, CreateDialogParamA)
  366. APIHOOK_ENTRY(USER32.DLL, CreateDialogParamW)
  367. APIHOOK_ENTRY(USER32.DLL, CreateDialogIndirectParamA)
  368. APIHOOK_ENTRY(USER32.DLL, CreateDialogIndirectParamW)
  369. APIHOOK_ENTRY(USER32.DLL, CreateDialogIndirectParamAorW)
  370. APIHOOK_ENTRY(USER32.DLL, DestroyWindow)
  371. HOOK_END
  372. IMPLEMENT_SHIM_END