Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.188.241.82] |
|
Сообщ.
#1
,
|
|
|
Необходимо завершать процесс и все его дочерние процессы в программе на Microsoft Visual C++
Используется немного измененный код. Функция SafeTerminateProcess для безопасного завершения процесса по этой ссылке. http://hyacinth.byus.net/moniwiki/wiki.php...erminateProcess И функция KillProcessTree для рекурсивного завершения дочерних процессов по этой ссылке: http://www.cyberforum.ru/cpp-builder/thread1202071.html Если не удается завершить процесс с помощью функции SafeTerminateProcess, завершаю его с помощью функции TerminateProcess. Завершение процессов работает, но для дочерних процессов отладка показывает, что в большинстве случаев не работает функция SafeTerminateProcess, и в результате вызывается функция TerminateProcess. Для основного процесса SafeTerminateProcess всегда работает. Появляется одна из двух ошибок (если не было первой, в большинстве случаев появляется вторая). Функция GetExitCodeProcess получает ExitCode для дочернего процесса, равный нулю. Или бывает вторая ошибка hRT == null с ошибкой код 0x5 - Access Denied. Если сделать следующий код, вместо нее появляется ошибка Error unknown revision 0x519 PSECURITY_DESCRIPTOR pSD; pSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH); SECURITY_ATTRIBUTES sa; sa.nLength = sizeof (SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = pSD; sa.bInheritHandle = TRUE; hRT = CreateRemoteThread((bDup) ? hProcessDup : hProcess, &sa, 0, (LPTHREAD_START_ROUTINE)pfnExitProc, (PVOID)uExitCode, 0, &dwTID); BOOL SafeTerminateProcess(HANDLE hProcess, UINT uExitCode) { DWORD dwTID, dwCode, dwErr = 0; HANDLE hProcessDup = INVALID_HANDLE_VALUE; HANDLE hRT = NULL; HINSTANCE hKernel = GetModuleHandle(_T("kernel32")); BOOL bSuccess = FALSE; BOOL bDup = DuplicateHandle(GetCurrentProcess(), hProcess, GetCurrentProcess(), &hProcessDup, PROCESS_ALL_ACCESS, FALSE, 0); if (GetExitCodeProcess((bDup) ? hProcessDup : hProcess, &dwCode) && (dwCode == STILL_ACTIVE)) { FARPROC pfnExitProc; pfnExitProc = GetProcAddress(hKernel, "ExitProcess"); hRT = CreateRemoteThread((bDup) ? hProcessDup : hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pfnExitProc, (PVOID)uExitCode, 0, &dwTID); if (hRT == NULL) dwErr = GetLastError(); } else { dwErr = ERROR_PROCESS_ABORTED; } if (hRT) { WaitForSingleObject((bDup) ? hProcessDup : hProcess, (DWORD) 10); CloseHandle(hRT); bSuccess = TRUE; } if (bDup) CloseHandle(hProcessDup); if (!bSuccess) SetLastError(dwErr); return bSuccess; } bool KillProcessTree(DWORD myprocID, DWORD dwTimeout) { bool bRet = true; HANDLE hWnd; PROCESSENTRY32 pe; memset(&pe, 0, sizeof(PROCESSENTRY32)); pe.dwSize = sizeof(PROCESSENTRY32); HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (Process32First(hSnap, &pe)) { BOOL bContinue = TRUE; while (bContinue) { if (pe.th32ParentProcessID == myprocID) { KillProcessTree(pe.th32ProcessID, dwTimeout); HANDLE hChildProc = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pe.th32ProcessID); if (hChildProc) { if (WaitForSingleObject(hChildProc, dwTimeout) == WAIT_OBJECT_0) bRet = true; else { bRet = SafeTerminateProcess(hChildProc, 0); if (!bRet) bRet = TerminateProcess(hChildProc, 0); } CloseHandle(hChildProc); } } bContinue = Process32Next(hSnap, &pe); } HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, myprocID); if (hProc) { if (!SafeTerminateProcess(hProc, 0)) TerminateProcess(hProc, 0); CloseHandle(hProc); } } return bRet; } |
Сообщ.
#2
,
|
|
|
Цитата Макс1 @ Можно ли исправить эти 2 ошибки и сделать, чтобы функция SafeTerminateProcess всегда завершала дочерние процессы? я бы попробовал так: BOOL SafeTerminateProcess(HANDLE hProcess, UINT uExitCode) { DWORD dwTID, dwCode, dwErr = 0; HANDLE hRT = NULL; HINSTANCE hKernel = GetModuleHandle(_T("kernel32")); BOOL bSuccess = FALSE; if (GetExitCodeProcess(hProcess, &dwCode)&&(dwCode == STILL_ACTIVE)) { FARPROC pfnExitProc; pfnExitProc = GetProcAddress(hKernel, "ExitProcess"); hRT = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pfnExitProc, (PVOID)uExitCode, 0, &dwTID); if (hRT == NULL) dwErr = GetLastError(); } else { dwErr = ERROR_PROCESS_ABORTED; } if (hRT) { WaitForSingleObject(hProcess, (DWORD)1000); CloseHandle(hRT); bSuccess = TRUE; } if (!bSuccess) SetLastError(dwErr); return bSuccess; } |
Сообщ.
#3
,
|
|
|
Цитата ЫукпШ @ я бы попробовал так: К сожалению, остаются те же ошибки. |
Сообщ.
#4
,
|
|
|
Цитата Макс1 @ Функция GetExitCodeProcess получает ExitCode для дочернего процесса, равный нулю. Дык это нормально - обычно процессы и завершаются с ExitCode = 0, а не нулевые значения имеют особый смысл, например, код ошибки Цитата Макс1 @ Или бывает вторая ошибка hRT == null с ошибкой код 0x5 - Access Denied. Можно попробовать получить отладочную привелегию (SeDebugPrivelege) через AdjustTokenPrivileges. Хотя не факт, что это поможет. PS: Вызов CreateRemoteThread может и безопасен для завершения процесса, но не безопасен для системы, поэтому не всегда работает. |
Сообщ.
#5
,
|
|
|
Цитата leo @ Цитата Макс1 @ Или бывает вторая ошибка hRT == null с ошибкой код 0x5 - Access Denied. Можно попробовать получить отладочную привелегию (SeDebugPrivelege) через AdjustTokenPrivileges. Хотя не факт, что это поможет. PS: Вызов CreateRemoteThread может и безопасен для завершения процесса, но не безопасен для системы, поэтому не всегда работает. Не встречался, всегда одинаково успешно работает. В диапазоне xp - win8, x86-x64.(win10 ещё не проверял.) Если речь идёт именно о дочернем процессе. Никаких дополнительных привилегий я не получал. Административные привилегии тоже не нужны. --- Возможно, ошибка где-то ещё. Например, процесс - не дочерний. Или есть не замеченные и не понятые тонкости, когда вместо потоковой процедуры пытаемся вызвать "ExitProcess". --- Можно посоветовать почитать это. По предложенной технологии, скопировать собственную процедуру в память подсудимого процесса. Это устойчиво работает. Наша процедура загрузит нашу dll в память... После этого комфортно проводить дополнительные опыты. |
Сообщ.
#6
,
|
|
|
Цитата leo @ Дык это нормально - обычно процессы и завершаются с ExitCode = 0 В этом случае функция SafeTerminateProcess не завершает процесс. Цитата ЫукпШ @ Можно попробовать получить отладочную привелегию (SeDebugPrivelege) через AdjustTokenPrivileges. Хотя не факт, что это поможет. Не помогает. |
Сообщ.
#7
,
|
|
|
Цитата Макс1 @ В этом случае функция SafeTerminateProcess не завершает процесс. Не завершает, но почему-то возвращает false, а не true, и соотв-но в KillProcessTree вызывается TerminateProcess, хотя процесс уже и так завершен |
Сообщ.
#8
,
|
|
|
Цитата leo @ хотя процесс уже и так завершен Не завершен. Проверял этот вопрос. |
Сообщ.
#9
,
|
|
|
"Не говорите ерундой!" (C)
Если GetExitCodeProcess возвращает true и ExitCode != STILL_ACTIVE, то процесс должен быть завершен. Другое дело, что ты, записывая в одно условие вызов функции и проверку ExitCode, в случае облома не можешь определить, то ли процесс действительно завершился с ExitCode = 0, то ли функция GetExitCodeProcess по какой-то причине вернула false (нужно проверить GetLastError), и переменная ExitCode не измнилась (осталась = 0 после инициализации). |
Сообщ.
#10
,
|
|
|
Цитата leo @ то процесс должен быть завершен Если возвращать true в случае ExitCode != STILL_ACTIVE, и не завершать процессы поcле SafeTerminateProcess с помощью TerminateProcess, то в списке процессов появляются незавершенные дочерние процессы. Но не в тот момент, когда было !STILL_ACTIVE. Если завершать после !STILL_ACTIVE в SafeTerminateProcess, не проверяя dwCode == STILL_ACTIVE, то все равно появляется ошибка 05h - Acess Denied. В обоих этих вариантах программа работает нестабильно. Пока оставил использование TerminateProcess при неудаче SafeTerminateProcess для основного процесса и использование только TerminateProcess для дочерних процессов. Не знаю, насколько безопаснее SafeTerminateProcess, и насколько нужно использовать эту функцию. Цитата leo @ функция GetExitCodeProcess по какой-то причине вернула false Всегда возвращает true. |
Сообщ.
#11
,
|
|
|
Цитата Макс1 @ Если возвращать true в случае ExitCode != STILL_ACTIVE, и не завершать процессы поcле SafeTerminateProcess с помощью TerminateProcess, то в списке процессов появляются незавершенные дочерние процессы. Попробуй тестировать завершение процесса посредством: if(WaitForSingleObject(hProcess, 0) == WAIT_OBJECT_0) { // процесс завершён } Появилась свободная минутка - проверил я твою процедуру. Всё работает, никаких ошибок не было получено ни разу. WinXpSp3 x86, Win7 x86. Именно эта процедура использовалась: BOOL SafeTerminateProcess(HANDLE hProcess, UINT uExitCode) { DWORD dwTID, dwCode, dwErr = 0; HANDLE hRT = NULL; HINSTANCE hKernel = GetModuleHandle(_T("kernel32")); BOOL bSuccess = FALSE; if (GetExitCodeProcess(hProcess, &dwCode)&&(dwCode == STILL_ACTIVE)) { FARPROC pfnExitProc; pfnExitProc = GetProcAddress(hKernel, "ExitProcess"); hRT = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pfnExitProc, (PVOID)uExitCode, 0, &dwTID); if (hRT == NULL) dwErr = GetLastError(); } else { dwErr = ERROR_PROCESS_ABORTED; } if (hRT) { DWORD wfso = WaitForSingleObject(hProcess, 5000); CloseHandle(hRT); if(wfso==WAIT_OBJECT_0) { bSuccess = TRUE; if(::GetExitCodeProcess(hProcess, &dwCode)) { if(dwCode==uExitCode) { ::OutputDebugString(_T("dwCode==uExitCode")); } } } } if (!bSuccess) SetLastError(dwErr); return bSuccess; } |