Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: WinAPI и системное программирование > Как определить окончание загрузки приложения?


Автор: Firster 17.9.2007, 15:54
Уважаемые эксперты! Возник вопрос, связанный с определением окончания(конца) загрузки приложения.  Например, как определить сколько секунд грузиться MS Word и т.п. Теоретически все легко. ДЛИТЕЛЬНОСТЬ ЗАГРУЗКИ=ОКОНЧАНИЕ ЗАГРУЗКИ-СТАРТ ЗАГРУЗКИ. А вот как определить ОКОНЧАНИЕ ЗАГРУЗКИ? Заранее спасибо всем откликнувшимся.

Автор: MetalFan 17.9.2007, 16:09
WaitForInputIdle

Добавлено через 49 секунд
правда если приложение не консольное и имеет цикл обработки сообщений

Автор: Firster 17.9.2007, 16:54
Спасибо! Для тех кто столкнулся с такой проблемой даю код как делал я :

Код

procedure TForm1.Button1Click(Sender: TObject);
var  StartInfo: TStartupInfo;
     ProcInfo: TProcessInformation;
begin
  Label1.Caption:=FormatDateTime('hh:nn:ss:zzz',Now-3600);

  ZeroMemory(@StartInfo, SizeOf(TStartupInfo));
  StartInfo.cb := SizeOf(TStartupInfo);
  CreateProcess(nil, 'C:\Program Files\Microsoft Office\Office\Frontpg.exe', nil, nil, False, 0, nil, nil, StartInfo, ProcInfo);

  WaitForInputIdle(ProcInfo.hProcess,INFINITE);
  Button1.Caption:=inttostr(ProcInfo.hProcess);
  Label2.Caption:=FormatDateTime('hh:nn:ss:zzz',Now-3600);
end;


Автор: MetalFan 17.9.2007, 18:12
Цитата(Firster @  17.9.2007,  16:54 Найти цитируемый пост)
Now-3600

эт зачем?

Автор: Firster 17.9.2007, 23:05
у меня разница в три часа идет. Поэтому отнимаю 3600 секунд

Автор: Riply 18.9.2007, 01:50
Цитата(Firster @  17.9.2007,  16:54 Найти цитируемый пост)
Спасибо! Для тех кто столкнулся с такой проблемой даю код как делал я :


Пыталась бороться с сабжевой темой.
К сожалению, ветка на www.delphimaster.ru, где это обсуждалось уже умерла.
Поэтому попробую привести выдержку из нее.
В общем случае задача не так уж и проста, см., например
http://groups.google.com/group/microsoft.public.win32.programmer.kernel/browse_thread/thread/a2a16a5753f49252/c49a244670a56d2b#c49a244670a56d2b
(в этом треде отметились не самые последние эксперты по подобным вопросам  smile )
См. также
http://groups.google.com/group/microsoft.public.win32.programmer.kernel/browse_thread/thread/1a2ec9ccd98d3979/77e944f5640757f3#77e944f5640757f3

Опираясь на приведенные ссылки и помощь Leonid Troyanovsky 
(он выполнил основную работу smile ),
получила следующий механизм решения задачи:

Подготавливаем APCProc, примерно такого вида:
(Требования к коду APCProc такие же, как в случае с CRT)
procedure APCProc(dwParam: Dword); stdcall;
var
 OldState: Boolean;
begin
 with PInjectInfo(dwParam) do  // InjectInfo - нами созданная структура. описание ниже
  begin
   //...
   LastStatus := _NtSetEvent(hReadyEvent, @OldState);
   if LastStatus <> STATUS_INVALID_HANDLE then
    begin
     LastStatus := _NtClose(hReadyEvent);
     //...


Создаем процесс: 
CreateProcess(..., CREATE_SUSPENDED, ..., Proc_Info);
и hEvent, сигнал котрого будем ожидать: hEvent := CreateEvent(nil, True, False, nil);
"Дупликатим" его smile
DuplicateHandle(GetCurrentProcess, hEvent, Proc_Info.hProcess, 
                           @hDupEvent, 0, False, DUPLICATE_SAME_ACCESS);
Пишем в адресное пространство жертвы структуру TInjectInfo, содержащую
 1. Адреса функций, которые будем использовать в APCProc
 2. hDupEvent - дубликат нашего hEvent
 3. Всякие полезные мелочи smile
 4. и сам код нашей APCProc
Proc_WriteMemory(Proc_Info.hProcess, pInjectInfo, TmpSize, 
                               MEM_COMMIT or MEM_RESERVE, PAGE_READWRITE, pRemoteData)

Создаем нить в теле жертвы: 
 QueueUserAPC(PInjectInfo(pRemoteData).pInjectTreadCode, 
                          Proc_Info.hThread, DWord(pRemoteData));
Будим целевой процесс:
 ResumeThread(Proc_Info.hThread)
И ждем срабатывания нашего hEvent - а.
 WaitArr := Make_Int64(Proc_Info.hProcess, hEvent);
 WaitResult := WaitForMultipleObjects(2, @WaitArr, False, TimeOut);
Вот, вроде, и все.
Тестировала на самых разных(специально для этого созданных) процессах.
Как и говорил Leonid Troyanovsky:
"APCProc срабатывает _непосредственно_после_инициализации процесса, 
  но _до_выполнения main & etc".     Очень удобное место  smile 

Автор: Firster 18.9.2007, 12:31
Riply  smile

Добавлено через 4 минуты и 25 секунд
а то как то сложновато....

Автор: Riply 18.9.2007, 14:07
Firster, 
Выдернуть пример из проекта сложновато: слишком много "внутренних ссылок" :(
Если будет время (которого всегда не хватает),  то напишу отдельный пример. 

Цитата(Firster @  18.9.2007,  12:31 Найти цитируемый пост)
а то как то сложновато.... 

Это только внешне так кажется. "Не так страшен черт, как его малюют"  smile 
Читай Help. Споткнулся на каком-то месте - спрашивай. 

Автор: Firster 20.9.2007, 23:22
Riply хочу спросить по ходу дела. Я так понял ты делала перехват запуска приложения и момент ЗАВЕРШЕНИЯ ЕГО работы. Меня вот что интересует.
Делаю инжект ДЛЛ к ВинКомандеру. ДЛЛка успешно перехватывает запуск любого приложения из него (ВинКомандера). При запуске нового приложения из ВинКомандера делаю инжект ДЛЛ к этому процессу. При закрытии процесса должен произойти перехват функции ExitProcess, но его НЕ ПРОИСХОДИТ. Может я не то перехватываю или не в ту степь пошел...? Если есть идеи будк очень благодарен.

Автор: Riply 21.9.2007, 03:26
Цитата(Firster @  20.9.2007,  23:22 Найти цитируемый пост)
Я так понял ты делала перехват запуска приложения и момент ЗАВЕРШЕНИЯ ЕГО работы. 

Нет. Не делала. Если ты про мой пост выше, 
то там ловиться момент завершения инициализации процесса.


Цитата(Firster @  20.9.2007,  23:22 Найти цитируемый пост)
При закрытии процесса должен произойти перехват функции ExitProcess, но его НЕ ПРОИСХОДИТ. 

Причины могут быть разные: от неправильно сделанного перехвата 
до "невызова" жертвой целевой функции.  smile 

Цитата(Firster @  20.9.2007,  23:22 Найти цитируемый пост)
Может я не то перехватываю или не в ту степь пошел...? Если есть идеи будк очень благодарен. 

Не понимаю зачем вообще он (перехват ExitProcess) нужен.
Можно организовать ожидание завершения процесса, благо его Handle известен.
Можно обрабатывать, например, DLL_PROCESS_DETACH - раз уж в него(процесс) залезли. smile 

Автор: Firster 22.9.2007, 10:37
Цитата

Можно обрабатывать, например, DLL_PROCESS_DETACH - раз уж в него(процесс) залезли.

Точно и как я не дошел до этой мысли!!! Спасибо.  smile 

Цитата

Можно организовать ожидание завершения процесса, благо его Handle известен.

А это какая функция?

Автор: Riply 22.9.2007, 16:49
Цитата(Firster @  22.9.2007,  10:37 Найти цитируемый пост)
А это какая функция? 

Можно попробовать WaitFor(Single)MultipleObject(s), только, наверное не 
стоит их использовать "внутри" жертвы smile 

Автор: Firster 22.9.2007, 21:27
Цитата(Riply @  22.9.2007,  16:49 Найти цитируемый пост)
Можно попробовать WaitFor(Single)MultipleObject(s),


WaitForSingleObject подошел. Но возник вопрос с ожиданием ответа функции. Придеться создавать отдельно поток для ожидания ответа о завершении каждого процесса. Буду обрабатывать DLL_PROCESS_DETACH. Но здесь у меня небольшие проблемы...

Автор: Riply 23.9.2007, 02:01
Цитата(Firster @  22.9.2007,  21:27 Найти цитируемый пост)
WaitForSingleObject подошел. Но возник вопрос с ожиданием ответа функции. Придеться создавать отдельно поток для ожидания ответа о завершении каждого процесса.

Если процессов меньше 64, то можно использовать WaitForMultipleObjects
- она как раз для этого. 
Если же их больше, то тоже можно красиво "выкрутиться" - например WaitForMultipleObjectsEx
(если правильно помню) или пул потоков.

Цитата(Firster @  22.9.2007,  21:27 Найти цитируемый пост)
Буду обрабатывать DLL_PROCESS_DETACH. Но здесь у меня небольшие проблемы... 

Что "не так" ?

Автор: Firster 23.9.2007, 02:12
Riply а не слишком ли ресурсы это забьет? Я просто еще не знаю как лучше, и нахожусь в так называемом творческом поиске ;)

Добавлено через 1 минуту и 43 секунды
и спасибо ОГРОМНОЕ, что помогаешь разобраться в этом!!!

Автор: Riply 23.9.2007, 02:18
Цитата(Firster @  23.9.2007,  02:12 Найти цитируемый пост)
Riply а не слишком ли ресурсы это забьет?

Зависит от твоей задачи. Может и стоит пойти на жертвы smile
Почитай Рихтера. Он хорошо и доступно описал способы решения подобных задач, 
а так же их плюсы и минусы.

Автор: Riply 23.9.2007, 02:38
Цитата(Firster @  23.9.2007,  02:12 Найти цитируемый пост)
и спасибо ОГРОМНОЕ, что помогаешь разобраться в этом!!! 

Смотри не пожалей об этом smile 

Цитата(Firster @  17.9.2007,  16:54 Найти цитируемый пост)
Спасибо! Для тех кто столкнулся с такой проблемой даю код как делал я :

Делал ужасно:
Где проверка результатов, возвращаемых функциями CreateProcess и WaitForInputIdle ?
Почему ты после себя не закрываешь Handle`ы ?
Второе, лично я, отношу к разряду грубейших ошибок. 
Вот тебе для начала (чтобы жизнь медом не казалась). smile 

Автор: Firster 24.9.2007, 00:02
Цитата(Riply @  23.9.2007,  02:38 Найти цитируемый пост)
Где проверка результатов, возвращаемых функциями CreateProcess и WaitForInputIdle ?


Результат мне нужен только функции WaitForInputIdle грубо говоря, но это сейчас не основное для меня.

Цитата(Riply @  23.9.2007,  02:38 Найти цитируемый пост)
Почему ты после себя не закрываешь Handle`ы ?

То был пример ВООБЩЕ! В своей программе я хендлы закрываю. ;)

Но за замечания спасибо!

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)