From: "Berger, Daniel" Date: 2003-05-15T05:57:10+09:00 Subject: Kill support on Win32 Hi all, I would like to see Process.kill support added for Win32. I've written a module that does this (sys-win32process), but I would like to see it added to the core. Quick synopsis: kill 0 -> Test to see if process is running, don't kill kill 1, 4-8 -> Nice kill kill 2 -> Send Ctrl+Break (console only) kill 3 -> Send Ctrl+C (console only) kill 9 -> Hard kill The only problem I have with it now is that it sys_fail(0) returns Errno::E000 on kill 1-9 (and Errno::ENOENT for kill 0) if the process doesn't exist. I would like to force Errno::ESRCH to be consistent with *nix. A couple of quick notes: AFAIK there is no way to tell the difference between a failure attempting to get info on PID 0 and a process that isn't running. That's why I assume PID 0 (System Idle Process) is *always* running. Some processes (notably CSRSS.EXE) will return ERROR_ACCESS_DENIED. My opinion is that kill 0 should be considered successful in such a case. Here's the code I'm using currently: #include VALUE cWin32P; int os_supported; static VALUE win32p_kill(int argc, VALUE *argv) { int signal; int i; HANDLE hProcess; HANDLE hThread; DWORD dwPid; DWORD dwThreadId; DWORD dwTimeout = 5; VALUE killed_pids = rb_ary_new(); if(argc < 2) { rb_raise(rb_eArgError, "wrong number of arguments -- kill(sig, pid...)"); } if(TYPE(argv[0]) == T_FIXNUM) { signal = FIX2INT(argv[0]); } else { rb_raise(rb_eArgError, "bad signal type"); } for(i = 1; i < argc; i++) { dwPid = (DWORD)FIX2INT(argv[i]); /******************************************************************* * Attempting to get ALL_ACCESS on system processes will fail, so we * use different access for signal 0, where we simply want to know * if the process is running or not. *******************************************************************/ if(signal == 0) { hProcess = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, FALSE,dwPid); } else { hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwPid); } switch(signal) { case 0: if(hProcess) { rb_ary_push(killed_pids,argv[i]); } else { /************************************************************ * An ACCESS_DENIED error necessarily means that the process * is running. In addition, always assume that PID 0 (System * Idle Process) is running. *************************************************************/ if( (GetLastError == ERROR_ACCESS_DENIED) || (dwPid == 0) ) { rb_ary_push(killed_pids,argv[i]); } else { rb_sys_fail(0); } } break; case 2: if(GenerateConsoleCtrlEvent(CTRL_C_EVENT,dwPid)) { rb_ary_push(killed_pids,argv[i]); } else { rb_sys_fail(0); } break; case 3: if(GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,dwPid)) { rb_ary_push(killed_pids,argv[i]); } else { rb_sys_fail(0); } break; case 9: if(TerminateProcess(hProcess,signal)) { CloseHandle(hProcess); rb_ary_push(killed_pids,argv[i]); } else { rb_sys_fail(0); } break; default: if(hProcess) { if(os_supported == 1) { hThread = CreateRemoteThread(hProcess,NULL,0,(LPTHREAD_START_ROUTINE) (GetProcAddress(GetModuleHandle("KERNEL32.DLL"), "ExitProcess")),0,0,&dwThreadId); if(hThread) { WaitForSingleObject(hThread, dwTimeout); CloseHandle(hProcess); rb_ary_push(killed_pids,argv[i]); } else { CloseHandle(hProcess); rb_sys_fail(0); } } else { if(TerminateProcess(hProcess,signal)) { CloseHandle(hProcess); rb_ary_push(killed_pids,argv[i]); } else { rb_sys_fail(0); } } } else { rb_sys_fail(0); } break; } } return killed_pids; } /* Win9x does not support CreateRemoteThread */ int win32p_os_supported() { OSVERSIONINFO OSInfo; OSInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&OSInfo); if(OSInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) { return 1; } else { return 0; } } Regards, Dan