extract method: logging for possible NPE later
[idea/community.git] / native / focusKiller / focuskiller.cpp
1 #include <windows.h>
2
3 // NT 4 doesn't have FlashWindowEx.
4 typedef BOOL (WINAPI *t_FlashWindowEx)(FLASHWINFO*);
5 t_FlashWindowEx p_FlashWindowEx;
6 #define FlashWindowEx p_FlashWindowEx
7
8 #ifdef USE_DETOURS
9 #include "detours.h" // see http://research.microsoft.com/sn/detours/
10 extern "C" {
11     DETOUR_TRAMPOLINE(BOOL WINAPI Real_SetForegroundWindow(HWND hWnd), SetForegroundWindow);    
12 }
13 #else
14 // IAT patching hook method. See http://www.naughter.com/hookimportfunction.html
15 // compile with cl /LD focuskiller.cpp HookImportFunction.cpp user32.lib
16 #include "HookImportFunction.h"
17
18 typedef BOOL (WINAPI *t_SetForegroundWindow)(HWND);
19 t_SetForegroundWindow Real_SetForegroundWindow;
20 #endif
21
22 DWORD mypid;
23    
24 BOOL WINAPI Mine_SetForegroundWindow(HWND hWnd)
25 {    
26     DWORD pid;    
27     HWND fg = GetForegroundWindow();
28     HWND owner = GetWindow(hWnd, GW_OWNER);
29     GetWindowThreadProcessId(fg, &pid);
30     
31 #ifdef _DEBUG
32     char buf[500];
33     wsprintf(buf, "SetForegroundWindow(%x): owner = %x, %d <-> %d", hWnd, owner, pid, mypid);
34     OutputDebugString(buf);
35 #endif
36
37     // Disallow if
38     //  a) another process' window is in the foreground
39     //  b) the window to be put in front is a top-level window (should avoid putting one IDEA project in front of another one)
40     if (mypid != pid || owner == NULL) {
41         if (FlashWindowEx != NULL) {
42             FLASHWINFO fw;
43             fw.cbSize = sizeof(fw);
44             fw.hwnd = hWnd;
45             fw.uCount = 5;
46             fw.dwTimeout = 0;
47                     
48             fw.dwFlags = FLASHW_TRAY | FLASHW_TIMERNOFG;
49             FlashWindowEx(&fw);
50         } else {
51             FlashWindow(hWnd, TRUE);
52         }
53         return TRUE; // fake success
54     }
55     
56     return Real_SetForegroundWindow(hWnd);
57 }
58
59 void HookFunctions(HMODULE hModule)
60 {
61 #ifdef USE_DETOURS
62 #ifdef _DEBUG    
63     OutputDebugString("Using Detours hook...");
64 #endif
65
66     DetourFunctionWithTrampoline((PBYTE)Real_SetForegroundWindow,
67                                  (PBYTE)Mine_SetForegroundWindow);
68 #else
69 #ifdef _DEBUG    
70     OutputDebugString("Using IAT patching hook...");
71 #endif
72
73     HOOKFUNCDESC hook;
74     hook.szFunc = "SetForegroundWindow";
75     hook.pProc = (PROC)Mine_SetForegroundWindow;
76
77     // hooking LoadLibrary and waiting until awt.dll is being loaded by java would be more correct but this works too
78     HMODULE awtModule = LoadLibrary("awt.dll");
79     
80     BOOL b = HookImportFunctionsByName(awtModule, "user32.dll", 1, &hook, (PROC *)&Real_SetForegroundWindow, NULL);
81     if (!b) {
82         char buf[200];
83         wsprintf(buf, "Hooking SetForegroundWindow failed [0x%x]", GetLastError());
84         OutputDebugString(buf);
85     }
86 #endif
87
88 #ifdef _DEBUG    
89     OutputDebugString("Functions hooked");
90 #endif
91 }
92
93 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
94 {    
95     if (fdwReason == DLL_PROCESS_ATTACH) {
96 #ifdef _DEBUG    
97         char buf[200];
98         wsprintf(buf, "DLL Attached");
99         OutputDebugString(buf);
100 #endif
101         
102         mypid = GetCurrentProcessId();
103         p_FlashWindowEx = (t_FlashWindowEx)GetProcAddress(GetModuleHandle("user32.dll"), "FlashWindowEx");
104
105         DisableThreadLibraryCalls((HMODULE)hinstDLL);
106
107         HookFunctions((HMODULE)hinstDLL);        
108     }
109     
110     return TRUE;
111 }
112