-
Моё приложение запускает другое приложение в режиме отладки ( CreateProcess с флажками DEBUG_PROCESS or DEBUG_ONLY_THIS_PROCESS ). Потом идёт сам цикл отладки ( WaitForDebugEvent и ContinueDebugEvent ). И в определённый процесс времени нужно прекратить отладку с завершением отлаживаемого процесса, но не завершая при этом отладчик. TerminateProcess (+ закрытие хэндлов в ProcessInformation) отлаживаемый процесс завершает, однако видимо какие-то хэндлы всё же остаются открытыми, так как файл приложения (которое отлаживали) не доступен для модификации... :( Как же всётаки корректно прекратить отладку? В интернете нашёл максимум такой же вопрос, но без ответа: http://forum.codenet.ru/showthread.php?t=10408На сайте microsoft, естественно, тоже ничего путного не нашёл: http://msdn.microsoft.com/en-us/library/ms681675(VS.85).aspx
-
> видимо какие-то хэндлы всё же остаются открытыми
Ну так выясни какие конкретно..
-
а FatalExit() не поможет?
-
> Сергей М. © (27.04.09 13:38) [1] > > видимо какие-то хэндлы всё же остаются открытыми > Ну так выясни какие конкретно..
Перечислить все открытые процессом хэндлы и сделать им всем CloseHandle ? Странно, если проблема в этом... Тогда получается, что микрософты сделали жутко сырые функции отладки... > clickmaker © (27.04.09 13:44) [2] > а FatalExit() не поможет?
FatalExit завершает текущее приложение, а нужно чтобы приложение-отладчик завершило отлаживаемое приложение. Хотя конечно можно и извратнутся, подправив EIP (с помощью SetThreadContext ), чтобы оно указывало на вход в функцию FatalExit :))) Просто странно, что с этой проблемой (почти) никто не сталкивался (а если и сталкивался, то не решил её). Или может я слишком сумбурно объяснил. Я только недавно занялся темой отладки и постоянно наступаю на грабли... :(
-
Останови основной поток, потом GetThreadContext, EIP выставб на адрес ExitProcess, SetThreadContext - запусти основной поток.
-
> Rouse_ © (27.04.09 16:26) [4] > Останови основной поток, потом GetThreadContext, EIP выставб > на адрес ExitProcess, SetThreadContext - запусти основной > поток.
Ну да, об этом я в предыдущем посте и писал, правда не о функции ExitProcess , а о функции FatalExit . Но вобщем, как я понимаю, проблема не в том. На вид, процесс вроде убивается нормально (из диспетчера задач исчезает), но файл отлаживаемого приложения нельзя удалить, пока не завершить также и приложение-отладчик. Я набросал урезанную версию отладчика, для экспериментов:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
public
FHProcess: THandle;
end;
var
Form1: TForm1;
implementation
procedure TForm1.Button1Click(Sender: TObject);
var
PI: TProcessInformation;
SI: TStartupInfo;
DE: TDebugEvent;
ContinueStatus: DWORD;
BaseOfImage: Pointer;
begin
BaseOfImage:=nil;
GetStartupInfo(SI);
if CreateProcess(
'C:\copy\Notepad.exe',
nil,
nil,
nil,
False,
DEBUG_PROCESS or DEBUG_ONLY_THIS_PROCESS,
nil,
nil,
SI,
PI) then
begin
FHProcess:=PI.hProcess;
try
while True do
begin
if not WaitForDebugEvent(DE, 100) then
begin
Application.ProcessMessages;
Continue;
end;
ContinueStatus:=DBG_EXCEPTION_NOT_HANDLED;
case de.dwDebugEventCode of
EXIT_PROCESS_DEBUG_EVENT:
begin
ContinueDebugEvent(DE.dwProcessId, DE.dwThreadId, DBG_CONTINUE);
Break;
end;
CREATE_PROCESS_DEBUG_EVENT:
begin
BaseOfImage:=DE.CreateProcessInfo.lpBaseOfImage;
end;
EXCEPTION_DEBUG_EVENT:
begin
if DE.Exception.ExceptionRecord.ExceptionCode=EXCEPTION_BREAKPOINT then
begin
ContinueStatus:=DBG_CONTINUE;
end;
end;
end;
ContinueDebugEvent(DE.dwProcessId, DE.dwThreadId, ContinueStatus);
end;
finally
FHProcess:=0;
CloseHandle(PI.hProcess);
CloseHandle(PI.hThread);
end;
end else RaiseLastWin32Error;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
if FHProcess<>0 then
begin
TerminateProcess(FHProcess, 999);
FHProcess:=0;
end;
end;
end.
На форме этого отладчика всего 2 кнопки. Button1 запускает отлаживаемое приложение, а Button2 завершает :) Для экспериментов я взял стандартный блокнот, скопировав его из 'C:\WINDOWS\Notepad.exe' в 'C:\copy\Notepad.exe'. Так вот, если запустить блокнот кнопкой Button1, а потом его завершить кнопкой Button2, то после этого невозможно удалить файл 'C:\copy\Notepad.exe', хотя в списках процессов он уже незначится... :(
-
> Так вот, если запустить блокнот кнопкой Button1, а потом > его завершить кнопкой Button2, то после этого невозможно > удалить файл 'C:\copy\Notepad.exe', хотя в списках процессов > он уже незначится... :(
А что говорит Process Explorer ?
> procedure TForm1.Button2Click(Sender: TObject); > begin > if FHProcess<>0 then > begin > TerminateProcess(FHProcess, 999); > FHProcess:=0; > end; > end;
TerminateProcess(FHProcess, 999); CloseHandle(FHProcess);
?
-
> Игорь Шевченко © (27.04.09 18:11) [6] > > А что говорит Process Explorer ?
Диспетчер задач? После нажатия Button2 процесс пропадает из диспетчера задач. Вобщем больше похоже на то, что я не до конца выполняю финализацию отладки (только вот как её правильно завершить?..). > Игорь Шевченко © (27.04.09 18:11) [6] > > TerminateProcess(FHProcess, 999); > CloseHandle(FHProcess); > > ?
FHProcess это просто копия PI.hProcess (присваивается после удачного CreateProcess ) специально для того чтобы этот хэндл было видно в обработчике Button2 для вызова TerminateProcess . А сам хэндл PI.hProcess закрывается в любом случае в блоке try..finally..end .
-
Эврика!!! Я нашёл! :))) Действительно остаётся открытым один хэндл. Вот он: DE.CreateProcessInfo.hFile Если в вышеприведённом примере произвести нижеприведённые ;) изменения, то файл отлаживаемого приложения, после завершения отладки ничем не лочится и легко удаляется... CREATE_PROCESS_DEBUG_EVENT:
begin
BaseOfImage:=DE.CreateProcessInfo.lpBaseOfImage;
CloseHandle(DE.CreateProcessInfo.hFile);
end;
|