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.

491 lines
9.6 KiB

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