Конференция "WinAPI" » Как корректно прекратить отладку? [D6, Win2k, WinXP]
 
  • Валигози © (27.04.09 10:59) [0]
    Моё приложение запускает другое приложение в режиме отладки (
    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
  • Сергей М. © (27.04.09 13:38) [1]

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


    Ну так выясни какие конкретно..
  • clickmaker © (27.04.09 13:44) [2]
    а FatalExit() не поможет?
  • Валигози © (27.04.09 15:10) [3]

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

    Перечислить все открытые процессом хэндлы и сделать им всем
    CloseHandle

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


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

    FatalExit

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

    ), чтобы оно указывало на вход в функцию
    FatalExit

    :)))

    Просто странно, что с этой проблемой (почти) никто не сталкивался (а если и сталкивался, то не решил её). Или может я слишком сумбурно объяснил. Я только недавно занялся темой отладки и постоянно наступаю на грабли... :(
  • Rouse_ © (27.04.09 16:26) [4]
    Останови основной поток, потом GetThreadContext, EIP выставб на адрес ExitProcess, SetThreadContext - запусти основной поток.
  • Валигози © (27.04.09 17:44) [5]

    > 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', хотя в списках процессов он уже незначится... :(
  • Игорь Шевченко © (27.04.09 18:11) [6]

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

    ?
  • Валигози © (28.04.09 09:05) [7]

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

    .
  • Валигози © (28.04.09 15:15) [8]
    Эврика!!! Я нашёл! :)))
    Действительно остаётся открытым один хэндл. Вот он:
    DE.CreateProcessInfo.hFile


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

 
Конференция "WinAPI" » Как корректно прекратить отладку? [D6, Win2k, WinXP]
Есть новые Нет новых   [134435   +33][b:0][p:0.003]