Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Как корректно прекратить отладку? [D6, Win2k, WinXP]


Валигози ©   (2009-04-27 10:59:00) 

Моё приложение запускает другое приложение в режиме отладки ( CreateProcessс флажками DEBUG_PROCESS orDEBUG_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


Валигози   (2009-04-28 15:15:00) [1]

Эврика!!! Я нашёл! :)))
Действительно остаётся открытым один хэндл. Вот он: DE.CreateProcessInfo.hFile
Если в вышеприведённом примере произвести нижеприведённые ;) изменения, то файл отлаживаемого приложения, после завершения отладки ничем не лочится и легко удаляется...
CREATE_PROCESS_DEBUG_EVENT:
begin
 BaseOfImage:=DE.CreateProcessInfo.lpBaseOfImage;
 CloseHandle(DE.CreateProcessInfo.hFile);
end;


Валигози   (2009-04-28 09:05:00) [2]


> Игорь Шевченко ©   (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.


Игорь Шевченко   (2009-04-27 18:11:00) [3]


> Так вот, если запустить блокнот кнопкой 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);

?


Валигози   (2009-04-27 17:44:00) [4]


> 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
   { Private declarations }
 public
   { Public declarations }
   FHProcess: THandle;
 end;

var
 Form1: TForm1;

implementation

{$R *.dfm}

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', хотя в списках процессов он уже незначится... :(


Rouse_   (2009-04-27 16:26:00) [5]

Останови основной поток, потом GetThreadContext, EIP выставб на адрес ExitProcess, SetThreadContext - запусти основной поток.


Валигози   (2009-04-27 15:10:00) [6]


> Сергей М. ©   (27.04.09 13:38) [1]
> > видимо какие-то хэндлы всё же остаются открытыми
> Ну так выясни какие конкретно..

Перечислить все открытые процессом хэндлы и сделать им всем CloseHandle? Странно, если проблема в этом... Тогда получается, что микрософты сделали жутко сырые функции отладки...


> clickmaker ©   (27.04.09 13:44) [2]
> а FatalExit() не поможет?

FatalExitзавершает текущее приложение, а нужно чтобы приложение-отладчик завершило отлаживаемое приложение. Хотя конечно можно и извратнутся, подправив EIP (с помощью SetThreadContext), чтобы оно указывало на вход в функцию FatalExit:)))

Просто странно, что с этой проблемой (почти) никто не сталкивался (а если и сталкивался, то не решил её). Или может я слишком сумбурно объяснил. Я только недавно занялся темой отладки и постоянно наступаю на грабли... :(


clickmaker   (2009-04-27 13:44:00) [7]

а FatalExit() не поможет?


Сергей М.   (2009-04-27 13:38:00) [8]


> видимо какие-то хэндлы всё же остаются открытыми


Ну так выясни какие конкретно..


Наверх

Титульная страница Поиск, карта сайта Написать письмо