windows-nsis-vs2005-20080409
[openafs.git] / src / WINNT / install / NSIS / killer.cpp
1 /*
2       Process Killer for NSIS script
3       
4       Rob Murawski
5       
6       Released under terms of IBM Open Source agreement for OpenAFS
7       
8       */
9
10
11 #include <windows.h>
12 #include <stdio.h>
13 #include <tlhelp32.h>
14 #include <vdmdbg.h>
15
16 char strProcessName[256];
17
18 typedef BOOL (CALLBACK *PROCENUMPROC)(DWORD, WORD, LPSTR, LPARAM);
19
20 typedef struct {
21    DWORD          dwPID;
22    PROCENUMPROC   lpProc;
23    DWORD          lParam;
24    BOOL           bEnd;
25 } EnumInfoStruct;
26
27 BOOL WINAPI EnumProcs(PROCENUMPROC lpProc, LPARAM lParam);
28
29 BOOL WINAPI Enum16(DWORD dwThreadId, WORD hMod16, WORD hTask16,
30       PSZ pszModName, PSZ pszFileName, LPARAM lpUserDefined);
31
32 // 
33 // The EnumProcs function takes a pointer to a callback function
34 // that will be called once per process with the process filename 
35 // and process ID.
36 // 
37 // lpProc -- Address of callback routine.
38 // 
39 // lParam -- A user-defined LPARAM value to be passed to
40 //           the callback routine.
41 // 
42 // Callback function definition:
43 // BOOL CALLBACK Proc(DWORD dw, WORD w, LPCSTR lpstr, LPARAM lParam);
44 // 
45 BOOL WINAPI EnumProcs(PROCENUMPROC lpProc, LPARAM lParam) {
46
47    OSVERSIONINFO  osver;
48    HINSTANCE      hInstLib  = NULL;
49    HINSTANCE      hInstLib2 = NULL;
50    HANDLE         hSnapShot = NULL;
51    LPDWORD        lpdwPIDs  = NULL;
52    PROCESSENTRY32 procentry;
53    BOOL           bFlag;
54    DWORD          dwSize;
55    DWORD          dwSize2;
56    DWORD          dwIndex;
57    HMODULE        hMod;
58    HANDLE         hProcess;
59    char           szFileName[MAX_PATH];
60    EnumInfoStruct sInfo;
61
62    // ToolHelp Function Pointers.
63    HANDLE (WINAPI *lpfCreateToolhelp32Snapshot)(DWORD, DWORD);
64    BOOL (WINAPI *lpfProcess32First)(HANDLE, LPPROCESSENTRY32);
65    BOOL (WINAPI *lpfProcess32Next)(HANDLE, LPPROCESSENTRY32);
66
67    // PSAPI Function Pointers.
68    BOOL (WINAPI *lpfEnumProcesses)(DWORD *, DWORD, DWORD *);
69    BOOL (WINAPI *lpfEnumProcessModules)(HANDLE, HMODULE *, DWORD, 
70          LPDWORD);
71    DWORD (WINAPI *lpfGetModuleBaseName)(HANDLE, HMODULE, LPTSTR, DWORD);
72
73    // VDMDBG Function Pointers.
74    INT (WINAPI *lpfVDMEnumTaskWOWEx)(DWORD, TASKENUMPROCEX, LPARAM);
75
76    // Retrieve the OS version
77    osver.dwOSVersionInfoSize = sizeof(osver);
78    if (!GetVersionEx(&osver))
79       return FALSE;
80    
81    // If Windows NT 4.0
82    if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT
83          && osver.dwMajorVersion == 4) {
84
85       __try {
86
87          // Get the procedure addresses explicitly. We do
88          // this so we don't have to worry about modules
89          // failing to load under OSes other than Windows NT 4.0 
90          // because references to PSAPI.DLL can't be resolved.
91          hInstLib = LoadLibraryA("PSAPI.DLL");
92          if (hInstLib == NULL)
93             __leave;
94
95          hInstLib2 = LoadLibraryA("VDMDBG.DLL");
96          if (hInstLib2 == NULL)
97             __leave;
98
99          // Get procedure addresses.
100          lpfEnumProcesses = (BOOL (WINAPI *)(DWORD *, DWORD, DWORD*))
101                GetProcAddress(hInstLib, "EnumProcesses");
102
103          lpfEnumProcessModules = (BOOL (WINAPI *)(HANDLE, HMODULE *,
104                DWORD, LPDWORD)) GetProcAddress(hInstLib,
105                "EnumProcessModules");
106
107          lpfGetModuleBaseName = (DWORD (WINAPI *)(HANDLE, HMODULE,
108                LPTSTR, DWORD)) GetProcAddress(hInstLib,
109                "GetModuleBaseNameA");
110
111          lpfVDMEnumTaskWOWEx = (INT (WINAPI *)(DWORD, TASKENUMPROCEX,
112                LPARAM)) GetProcAddress(hInstLib2, "VDMEnumTaskWOWEx");
113          
114          if (lpfEnumProcesses == NULL 
115                || lpfEnumProcessModules == NULL 
116                || lpfGetModuleBaseName == NULL 
117                || lpfVDMEnumTaskWOWEx == NULL)
118             __leave;
119
120          // 
121          // Call the PSAPI function EnumProcesses to get all of the
122          // ProcID's currently in the system.
123          // 
124          // NOTE: In the documentation, the third parameter of
125          // EnumProcesses is named cbNeeded, which implies that you
126          // can call the function once to find out how much space to
127          // allocate for a buffer and again to fill the buffer.
128          // This is not the case. The cbNeeded parameter returns
129          // the number of PIDs returned, so if your buffer size is
130          // zero cbNeeded returns zero.
131          // 
132          // NOTE: The "HeapAlloc" loop here ensures that we
133          // actually allocate a buffer large enough for all the
134          // PIDs in the system.
135          // 
136          dwSize2 = 256 * sizeof(DWORD);
137          do {
138
139             if (lpdwPIDs) {
140                HeapFree(GetProcessHeap(), 0, lpdwPIDs);
141                dwSize2 *= 2;
142             }
143
144             lpdwPIDs = (LPDWORD) HeapAlloc(GetProcessHeap(), 0, 
145                   dwSize2);
146             if (lpdwPIDs == NULL)
147                __leave;
148             
149             if (!lpfEnumProcesses(lpdwPIDs, dwSize2, &dwSize))
150                __leave;
151
152          } while (dwSize == dwSize2);
153
154          // How many ProcID's did we get?
155          dwSize /= sizeof(DWORD);
156
157          // Loop through each ProcID.
158          for (dwIndex = 0; dwIndex < dwSize; dwIndex++) {
159
160             szFileName[0] = 0;
161             
162             // Open the process (if we can... security does not
163             // permit every process in the system to be opened).
164             hProcess = OpenProcess(
165                   PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
166                   FALSE, lpdwPIDs[dwIndex]);
167             if (hProcess != NULL) {
168
169                // Here we call EnumProcessModules to get only the
170                // first module in the process. This will be the 
171                // EXE module for which we will retrieve the name.
172                if (lpfEnumProcessModules(hProcess, &hMod,
173                      sizeof(hMod), &dwSize2)) {
174
175                   // Get the module name
176                   if (!lpfGetModuleBaseName(hProcess, hMod,
177                         szFileName, sizeof(szFileName)))
178                      szFileName[0] = 0;
179                }
180                CloseHandle(hProcess);
181             }
182             // Regardless of OpenProcess success or failure, we
183             // still call the enum func with the ProcID.
184             if (!lpProc(lpdwPIDs[dwIndex], 0, szFileName, lParam))
185                break;
186
187             // Did we just bump into an NTVDM?
188             if (_stricmp(szFileName, "NTVDM.EXE") == 0) {
189
190                // Fill in some info for the 16-bit enum proc.
191                sInfo.dwPID = lpdwPIDs[dwIndex];
192                sInfo.lpProc = lpProc;
193                sInfo.lParam = (DWORD) lParam;
194                sInfo.bEnd = FALSE;
195
196                // Enum the 16-bit stuff.
197                lpfVDMEnumTaskWOWEx(lpdwPIDs[dwIndex],
198                   (TASKENUMPROCEX) Enum16, (LPARAM) &sInfo);
199
200                // Did our main enum func say quit?
201                if (sInfo.bEnd)
202                   break;
203             }
204          }
205
206       } __finally {
207
208          if (hInstLib)
209             FreeLibrary(hInstLib);
210
211          if (hInstLib2)
212             FreeLibrary(hInstLib2);
213
214          if (lpdwPIDs)
215             HeapFree(GetProcessHeap(), 0, lpdwPIDs);
216       }
217
218    // If any OS other than Windows NT 4.0.
219    } else if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS
220          || (osver.dwPlatformId == VER_PLATFORM_WIN32_NT
221          && osver.dwMajorVersion > 4)) {
222
223       __try {
224
225          hInstLib = LoadLibraryA("Kernel32.DLL");
226          if (hInstLib == NULL)
227             __leave;
228
229          // If NT-based OS, load VDMDBG.DLL.
230          if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) {
231             hInstLib2 = LoadLibraryA("VDMDBG.DLL");
232             if (hInstLib2 == NULL)
233                __leave;
234          }
235
236          // Get procedure addresses. We are linking to 
237          // these functions explicitly, because a module using
238          // this code would fail to load under Windows NT,
239          // which does not have the Toolhelp32
240          // functions in KERNEL32.DLL.
241          lpfCreateToolhelp32Snapshot =
242                (HANDLE (WINAPI *)(DWORD,DWORD))
243                GetProcAddress(hInstLib, "CreateToolhelp32Snapshot");
244
245          lpfProcess32First =
246                (BOOL (WINAPI *)(HANDLE,LPPROCESSENTRY32))
247                GetProcAddress(hInstLib, "Process32First");
248
249          lpfProcess32Next =
250                (BOOL (WINAPI *)(HANDLE,LPPROCESSENTRY32))
251                GetProcAddress(hInstLib, "Process32Next");
252
253          if (lpfProcess32Next == NULL
254                || lpfProcess32First == NULL
255                || lpfCreateToolhelp32Snapshot == NULL)
256             __leave;
257
258          if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) {
259             lpfVDMEnumTaskWOWEx = (INT (WINAPI *)(DWORD, TASKENUMPROCEX,
260                   LPARAM)) GetProcAddress(hInstLib2, "VDMEnumTaskWOWEx");
261             if (lpfVDMEnumTaskWOWEx == NULL)
262                __leave;
263          }
264
265          // Get a handle to a Toolhelp snapshot of all processes.
266          hSnapShot = lpfCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
267          if (hSnapShot == INVALID_HANDLE_VALUE) {
268             FreeLibrary(hInstLib);
269             return FALSE;
270          }
271
272          // Get the first process' information.
273          procentry.dwSize = sizeof(PROCESSENTRY32);
274          bFlag = lpfProcess32First(hSnapShot, &procentry);
275
276          // While there are processes, keep looping.
277          while (bFlag) {
278             
279             // Call the enum func with the filename and ProcID.
280             if (lpProc(procentry.th32ProcessID, 0,
281                   procentry.szExeFile, lParam)) {
282
283                // Did we just bump into an NTVDM?
284                if (_stricmp(procentry.szExeFile, "NTVDM.EXE") == 0) {
285
286                   // Fill in some info for the 16-bit enum proc.
287                   sInfo.dwPID = procentry.th32ProcessID;
288                   sInfo.lpProc = lpProc;
289                   sInfo.lParam = (DWORD) lParam;
290                   sInfo.bEnd = FALSE;
291
292                   // Enum the 16-bit stuff.
293                   lpfVDMEnumTaskWOWEx(procentry.th32ProcessID,
294                      (TASKENUMPROCEX) Enum16, (LPARAM) &sInfo);
295
296                   // Did our main enum func say quit?
297                   if (sInfo.bEnd)
298                      break;
299                }
300
301                procentry.dwSize = sizeof(PROCESSENTRY32);
302                bFlag = lpfProcess32Next(hSnapShot, &procentry);
303
304             } else
305                bFlag = FALSE;
306          }
307
308       } __finally {
309
310          if (hInstLib)
311             FreeLibrary(hInstLib);
312
313          if (hInstLib2)
314             FreeLibrary(hInstLib2);
315       }
316
317    } else
318       return FALSE;
319
320    // Free the library.
321    FreeLibrary(hInstLib);
322
323    return TRUE;
324 }
325
326
327 BOOL WINAPI Enum16(DWORD dwThreadId, WORD hMod16, WORD hTask16,
328       PSZ pszModName, PSZ pszFileName, LPARAM lpUserDefined) {
329
330    BOOL bRet;
331
332    EnumInfoStruct *psInfo = (EnumInfoStruct *)lpUserDefined;
333
334    bRet = psInfo->lpProc(psInfo->dwPID, hTask16, pszFileName,
335       psInfo->lParam);
336
337    if (!bRet) 
338       psInfo->bEnd = TRUE;
339
340    return !bRet;
341
342
343
344 BOOL CALLBACK MyProcessEnumerator(DWORD dwPID, WORD wTask, 
345       LPCSTR szProcess, LPARAM lParam) {
346
347    /*if (wTask == 0)
348       printf("%5u   %s\n", dwPID, szProcess);
349    else
350       printf("  %5u %s\n", wTask, szProcess);*/
351    
352    if(stricmp(szProcess,strProcessName)==0)
353    {
354       HANDLE hProcess=OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID);
355       if(hProcess!=NULL)
356          TerminateProcess(hProcess,0);
357       CloseHandle(hProcess);
358    }
359
360    return TRUE;
361 }
362
363
364 void main(int argc, char *argv[])
365 {
366    if(argc<2)
367    {
368       printf("Please specify the process name to kill\n");
369       
370       return;
371    }
372
373    if(strlen((argv[1]))<255)
374       strcpy(strProcessName,(argv[1]));
375    else
376       return;
377   
378    EnumProcs((PROCENUMPROC) MyProcessEnumerator, 0);
379   
380 }