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

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

Как определить запуск кокого либо приложения? [D6, Win2k]


Страницы:   1 2

Piople ©   (2003-11-17 09:08:00) 

Скажите пожалуйста как можно перехватить запуск приложения, плизз. Я ставлю глобальный хук через dll на WM_create, но он ловит все сообщения в системе, а мне нужно только чтобы ловились вновь стартующие приложения, заранее ШПАШИБО.


Piople   (2003-11-27 08:30:00) [1]

Удалено модератором
Примечание: Offtopic


Digitman   (2003-11-27 08:26:00) [2]


> но там так стремно


"стремно" - это как ?
нет таких слов в алгоритмике и программировании

будь любезен изъясняться не на уровне детсада, а четко и конкретно : что тебе непонятно и/или вызывает сомнения


Piople   (2003-11-27 07:25:00) [3]

А ну все понял, создаем поток который просто будет крутиться в памяти и ждать хэндла. Но насчет самих потоков у меня есть книженция, но там так стремно все описано, нет ли ссылочки?


Digitman   (2003-11-25 10:17:00) [4]


> ведь он уже отработает


кто "отработает" ? DllEntryPoint() что ли ?

ну и что ? ты стартуешь в ней код.поток, коиторый будет с этого момента работать параллельно и независимо ни от чего, ожидая, когда ему каким-либо способом передадут хэндл окна для работы с этим хэндлом

когда в какой-то момент времени возникнет событие HSHELL_WINDOWCREATED и станет известен хэндл нужного тебе окна, ты в обработчике SysMsgProc() просто передашь работающему код.потоку этот хэндл, и далее твой код.поток уже сам будет работать с этим хэндлом, посылая по таймеру сообщение окну, хэндл которого он получил

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


Piople   (2003-11-25 09:49:00) [5]

Ну тогда я не понимаю как передать хэндл, ведь он уже отработает когда у нас появится хэндл?


Digitman   (2003-11-25 09:42:00) [6]


> Т.е. первем будет фильтр, а только потом DLLEntryPoint?

с какой стати ?

прежде чем любой библиотечный код получит управление, библиотека д.б. загружена и инициализирована

DllEntryPoint() как раз и вызывается в ходе инициализации библиотеки, и пока код DllEntryPoint() не отработает, никакой другой код библиотеки не м.б. вызван никем/ничем и не получит управление.

т.е. сначала ПОЛНОСТЬЮ отработает процедура DllEntryPoint() , а уж затем следует ожидать срабатывание и исполнение фильтр-функций


Piople   (2003-11-25 09:34:00) [7]

Т.е. первем будет фильтр, а только потом DLLEntryPoint?


Digitman   (2003-11-25 09:27:00) [8]


procedure DLLEntryPoint(dwReason: DWord); stdcall;
begin
case dwReason of
DLL_PROCESS_ATTACH:
begin
OpenGlobalData;
DetermineCurrentProcess;

//Здесь создАем доп.код.поток, при условии что IsNewProcess = True, с этого момента код.поток ждет, когда ему будет передан хэндл реально созданного окна

// никакого хэндла ему, потоку, здесь мы передать еще не можем
// ибо он нам еще неизвестен (известен он станет лишь когда фильтр в SysMsgproc() отработает и "поймает" момент создания гл.окна)
end;
DLL_PROCESS_DETACH:
//здесь, если IsNewProcess = True и код.поток еще работает, даем ему команду на завершение
CloseGlobalData;
end;
end;


Piople   (2003-11-25 09:17:00) [9]


> в фильтре SysMsgProc() для code = HSHELL_WINDOWCREATED тебе
> нужно всего лишь зафиксировать хэндл только что созданного
> окна, установить для него стиль WS_EX_LAYERED и установить
> layer-атрибут этого окна с параметром i = 0

Это ясно

> в ходе обработки DLL_PROCESS_ATTACH тебе необходимо запустить
> доп.код.поток, которому фильтр SysMsgProc() после фиксации
> hMainWnd будет передавать этот "пойманный" хэндл параметром

Ну хэндл, я так думаю, можно передать описав переменную в глобал варе, присвоить ей хэндл ну и передать, но как реализовать доп.код.поток, т.е.

procedure DLLEntryPoint(dwReason: DWord); stdcall;
begin
case dwReason of
DLL_PROCESS_ATTACH:
begin
OpenGlobalData;
DetermineCurrentProcess;
//Здесь передаем хэндл и создоем доп.код.поток
end;
DLL_PROCESS_DETACH: CloseGlobalData;
end;
end;

Я правильно понял? Пока остановлюсь здесь, а то все не пойму :)


Digitman   (2003-11-25 08:52:00) [10]

разумеется, при такой логике ты не получишь ожидаемого эффекта.

в фильтре SysMsgProc() для code = HSHELL_WINDOWCREATED тебе нужно всего лишь зафиксировать хэндл только что созданного окна, установить для него стиль WS_EX_LAYERED и установить layer-атрибут этого окна с параметром i = 0

в ходе обработки DLL_PROCESS_ATTACH тебе необходимо запустить доп.код.поток, которому фильтр SysMsgProc() после фиксации hMainWnd будет передавать этот "пойманный" хэндл параметром

твой код.поток создает таймер с нужным тебе периодом смены альфа-параметра, в обработчике которого в окно hMainWnd вызовом SendMessage() будет посылаться некое предопределенное сообщение X.

кроме SysMsgProc() ты должен установить хук на WH_CALLWNDPROC, в обработчике которого ты должен фильтровать сообщения X, посланные твоим код.потоком окну hMainWnd, и по факту обнаружения таковых менять layer-атрибут окна hMainWnd на следующий по инкременту (у тебя это должно произойти 250 раз, судя по коду)

примерные условия завершения процедуры твоего код.потока :
- достигнуто макс.значения альфа;
- фильтр в SysMsgProc() обнаружил событие HSHELL_WINDOWDESTROYED, т.е. hMainWnd разрушено;
- потоком получено сообщение QM_QUIT
- факт вызова обработчика DLL_PROCESS_DETACH как следствие выгрузки хук-ДЛЛ перед завершением тек.процесса

кр.того неразумно многократно грузить/выгружать USER32.DLL в фильтрах, все же это длительная и сложная операция для системы

достаточно загрузить эту библ-ку в DLL_PROCESS_ATTACH и тут же получить адрес нужной ф-ции, а выгрузить в DLL_PROCESS_DETACH.

вот так я себе это вижу


Piople   (2003-11-25 06:45:00) [11]

Извените пожалуйсто за предыдущие 2-а коментария, затупил не подумав :(
Разобрался DetermineCurrentProcess копает в памяти и ищет первое верхнее окно, а чтобы оно его искало каждый раз при старте нового приложения его внедряют в DLLEntryPoint. Да и у вас небольшая опечатка в фильтре
result"у должен присваиваться:

Result := CallNextHookEx( GlobalData^.SysHook, Code, wParam, lParam);

А у вас:

Result := CallNextHookEx( SysHook, Code, wParam, lParam);

Забыли что мы используем CreateFileMapping, MapViewOfFile и UnmapViewOfFile.

Но это не столь важно, проблема в том что мы отлавливаем окно до того как оно прорисовалось, поэтому не получается то что мне нужно, вот весь листинг DLL"ки попробуйте откампилить, ну и соответственно установите его увидите что получится, если неохото, то получится следующее: после запуска вместо формы будет плавно появлятся черный экран и только после CallNextHookEx
окно прорисуется. Ну и сам листинг, для тех кому не лень :)))

library hook_dll;

uses
Windows,
Messages,
Forms, SysUtils;

const
MMFName: PChar = "MyMMF"; // имя объекта файлового отображения

{структура, поля которой будут отображены в файл подкачки}
type
PGlobalDLLData = ^TGlobalDLLData;
TGlobalDLLData = packed record
SysHook: HWND; // дескриптор установленной ловушки
end;

var
GlobalData: PGlobalDLLData;
MMFHandle: THandle;
hMainWnd: THandle = 0;
IsNewProcess: Boolean = True;
SetLayeredWindowAttributes: function(Hwnd: THandle; crKey: COLORREF; bAlpha: Byte; dwFlags: DWORD): Boolean; stdcall;

{Фильтр}
function SysMsgProc(code : integer; wParam : word; lParam : longint) : longint; stdcall;
var
LibHandle: THandle;
I : Integer;
begin
try
if IsNewProcess and (hMainWnd = 0) and (code = HSHELL_WINDOWCREATED) then
begin
hMainWnd := wParam;

//---cut--- эта часть отвечает за плавное появление
SetWindowLong(hMainWnd, GWL_EXSTYLE, GetWindowLong(hMainWnd, GWL_EXSTYLE) or WS_EX_LAYERED);

{гребем ее из USER32.DLL}
LibHandle := LoadLibrary("USER32.DLL");
if LibHandle <= 32 then Exit;

@SetLayeredWindowAttributes := GetProcAddress(LibHandle,"SetLayeredWindowAttributes");

if not Assigned(SetLayeredWindowAttributes) then
begin
FreeLibrary(LibHandle);
Exit;
end;
for i := 0 to 250 do
SetLayeredWindowAttributes(hMainWnd, 0, i, LWA_ALPHA);

FreeLibrary(LibHandle);
//---cut--- здесь заканчивается :)
end;
finally
Result:=CallNextHookEx(GlobalData^.SysHook, Code, wParam, lParam);
end;
end;

{Процедура установки HOOK-а}
procedure hook(switch : Boolean) export; stdcall;
begin
if switch=true then
begin
GlobalData^.SysHook := SetWindowsHookEx(WH_SHELL, @SysMsgProc, HInstance, 0);
if GlobalData^.SysHook <> 0 then
MessageBox(0, "HOOK установлен !", "Message", 0)
else
MessageBox(0, "HOOK установить не удалось !", "Error Message", 0);
end
else
begin
if UnhookWindowsHookEx(GlobalData^.SysHook) then
MessageBox(0, "HOOK снят !", "Message", 0)
else
MessageBox(0, "HOOK снять не удалось !", "Error Message", 0);
end;
end;

procedure OpenGlobalData();
begin
{получаем объект файлового отображения}
MMFHandle:= CreateFileMapping(INVALID_HANDLE_VALUE, nil, PAGE_READWRITE, 0, SizeOf(TGlobalDLLData), MMFName);

if MMFHandle = 0 then
MessageBox(0, "Низя создать FileMapping", "Error Message", 0);

{отображаем глобальные данные на АП вызывающего процесса и получаем указатель
на начало выделенного пространства}
GlobalData:= MapViewOfFile(MMFHandle, FILE_MAP_ALL_ACCESS, 0, 0, SizeOf(TGlobalDLLData));
if GlobalData = nil then
begin
CloseHandle(MMFHandle);
MessageBox(0, "Низя заюзать MapViewOfFile", "Error Message", 0);
end;

end;

procedure CloseGlobalData();
begin
UnmapViewOfFile(GlobalData);
CloseHandle(MMFHandle);
end;

procedure DetermineCurrentProcess;
var
ThreadId: DWORD;
ProcessID: DWORD;
function EnumProc(hWnd: Thandle; Param: Cardinal): Boolean; stdcall;
var
PID: DWORD;
begin
Result := True;
if (GetWindowThreadProcessId(hWnd, PID) = ThreadId) and (PID = ProcessID) then
begin
IsNewProcess := False; //существует по кр.мере одно top-level-окно, созданное осн.код.потоком тек.процесса, т.е. тек.процесс GUI-приложения - не новый, а уже работающий (нас не интересующий)
Result := False;
end;
end;
begin
ThreadId := GetCurrentThreadId;
ProcessId := GetCurrentProcessId;
EnumWindows(@EnumProc, 0);
end;

procedure DLLEntryPoint(dwReason: DWord); stdcall;
begin
case dwReason of
DLL_PROCESS_ATTACH:
begin
OpenGlobalData;
DetermineCurrentProcess;
end;
DLL_PROCESS_DETACH: CloseGlobalData;
end;
end;

exports hook;

begin
{назначим поцедуру переменной DLLProc}
DLLProc:= @DLLEntryPoint;

{вызываем назначенную процедуру для отражения факта присоединения данной библиотеки к процессу}
DLLEntryPoint(DLL_PROCESS_ATTACH);
end.


С уважение piople.


Digitman   (2003-11-24 12:12:00) [12]

ф-ция DetermineCurrentProcess вызывается на стадии иниц-ции экз-ра хук-ДЛЛ и определяет:

- внедряется ли текущий экз-р в уже существующий процесс (который уже создал хотя бы одно окно верхнего уровня, читай - самое первое создаваемое им окно и есть главное); поскольку гл.окно уже создано, хендл его никогда уже не будет фигурировать в SysMsgProc() с code = HSHELL_WINDOWCREATED

- внедряется ли текущий экз-р в новый процесс, только что стартованный системой , точнее - идет его инициализация; ни одно окно еще не создано, поэтому хэндл окна, фигурирующий в первом же SysMsgProc() с code = HSHELL_WINDOWCREATED можно считать главным


Piople   (2003-11-24 10:41:00) [13]

Если можно непосредственно листинг


Piople   (2003-11-24 10:17:00) [14]

Об это я прочитал в статье которая лежит здесь, на мастаке.
И две процедуры которые вы мне дали, нижние, они зачем, что они делают?


Digitman   (2003-11-20 11:20:00) [15]


> ведь я работаю под 2000, а она(Винда 2000), как вы и сами
> знаете, делает следующее:
>
> если у вас имеется цепочка ловушек, то при выполнении функции
> CallNextHookEx(0, nCode, wParam, lParam ) вызывается следующая
> ловушка в цепочке, т.е. отпадает необходимость в передачи
> дескриптора, возвращаемого функцией SetWindowsHookEx.


где ты это выискал ? источник инф-ции ? я не вижу msdn подобных комментариев



var
hMainWnd: THandle = 0;
IsNewProcess: Boolean = True;

function SysMsgProc(code: integer; wParam, lParam : Cardinal) : LRESULT; stdcall;
begin
try
if IsNewProcess and (hMainWnd = 0) and (code = HSHELL_WINDOWCREATED) then
begin
hMainWnd := wParam; // хэндл самого первого созданного процессом окна
//Сдесь делаем с hMainWnd все что нужно
...

end;
finally
Result:=CallNextHookEx(SysHook, Code, wParam, lParam);
end;
end;

...

procedure DetermineCurrentProcess;
var
ThreadId: DWORD;
ProcessID: DWORD;
function EnumProc(hWnd: Thandle; Param: Cardinal): Boolean; stdcall;
var
PID: DWORD;
begin
Result := True;
if (GetWindowThreadProcessId(hWnd, PID) = ThreadId) and (PID = ProcessID) then
begin
IsNewProcess := False; //существует по кр.мере одно top-level-окно, созданное осн.код.потоком тек.процесса, т.е. тек.процесс GUI-приложения - не новый, а уже работающий (нас не интересующий)
Result := False;
end;
end;
begin
ThreadId := GetCurrentThreadId;
ProcessId := GetCurrentProcessId;
EnumWindows(@EnumProc, 0);
end;

...

procedure DLLEntryPoint(dwReason: DWord); stdcall;
begin
case dwReason of
DLL_PROCESS_ATTACH:
begin
OpenGlobalData;
DetermineCurrentProcess;
end;
DLL_PROCESS_DETACH: CloseGlobalData;
end;
end;


Piople   (2003-11-20 07:03:00) [16]

Все сделал, статью прочитал, разобрался зачем нужны CreateFileMapping, MapViewOfFile ну и UnmapViewOfFile соответсятвенно, если обобщить они нудны для сохранения значения дескриптора установленной ловушки. Но в моем случае это было не столь важно, ведь я работаю под 2000, а она(Винда 2000), как вы и сами знаете, делает следующее:

если у вас имеется цепочка ловушек, то при выполнении функции CallNextHookEx(0, nCode, wParam, lParam ) вызывается следующая ловушка в цепочке, т.е. отпадает необходимость в передачи дескриптора, возвращаемого функцией SetWindowsHookEx.

Но тем ни мение я код подправил, как и было мне сказано :), вот что у меня получилось:

library hook_dll;

uses
Windows,
Messages,
Forms;

const
MMFName: PChar = "MemMepFile"; // имя объекта файлового отображения

//структура, поля которой будут отображены в файл подкачки
type
PGlobalDLLData = ^TGlobalDLLData;
TGlobalDLLData = packed record
SysHook: HWND; // дескриптор установленной ловушки
end;

var
GlobalData: PGlobalDLLData;
MMFHandle: THandle;

function SysMsgProc(code : integer; wParam : word; lParam : longint) : longint; stdcall;
begin
if code = HSHELL_WINDOWCREATED then
begin

//Здесь мне надо получить Handle гланого окна внось стартующего приложения

{Пытаемся передать сообщение дальше по цепочке hook-ов. }
Result:= CallNextHookEx(GlobalData^.SysHook, Code, wParam, lParam);
end;

{Процедура установки HOOK-а}
procedure hook(switch : Boolean) export; stdcall;
begin
if switch=true then
begin
GlobalData^.SysHook := SetWindowsHookEx(WH_SHELL, @SysMsgProc, HInstance, 0);
if GlobalData^.SysHook <> 0 then
MessageBox(0, "HOOK установлен !", "Message", 0)
else
MessageBox(0, "HOOK установить не удалось !", "Error Message", 0);
end
else
begin
if UnhookWindowsHookEx(GlobalData^.SysHook) then
MessageBox(0, "HOOK снят !", "Message", 0)
else
MessageBox(0, "HOOK снять не удалось !", "Error Message", 0);
end;
end;

procedure OpenGlobalData();
begin
{получаем объект файлового отображения}
MMFHandle:= CreateFileMapping(INVALID_HANDLE_VALUE, nil, PAGE_READWRITE, 0, SizeOf(TGlobalDLLData), MMFName);

if MMFHandle = 0 then
MessageBox(0, "Низя создать FileMapping", "Error Message", 0);

{отображаем глобальные данные на АП вызывающего процесса и получаем указатель
на начало выделенного пространства}
GlobalData:= MapViewOfFile(MMFHandle, FILE_MAP_ALL_ACCESS, 0, 0, SizeOf(TGlobalDLLData));
if GlobalData = nil then
begin
CloseHandle(MMFHandle);
MessageBox(0, "Низя заюзать MapViewOfFile", "Error Message", 0);
end;

end;

procedure CloseGlobalData();
begin
UnmapViewOfFile(GlobalData);
CloseHandle(MMFHandle);
end;

procedure DLLEntryPoint(dwReason: DWord); stdcall;
begin
case dwReason of
DLL_PROCESS_ATTACH: OpenGlobalData;
DLL_PROCESS_DETACH: CloseGlobalData;
end;
end;

exports hook;

begin
{назначим поцедуру переменной DLLProc}
DLLProc:= @DLLEntryPoint;

{вызываем назначенную процедуру для отражения факта присоединения данной библиотеки к процессу}
DLLEntryPoint(DLL_PROCESS_ATTACH);
end.


Теперь мне не понятно как получить Handle гланого окна внось стартующего приложения, если я еще не сильно досталь, то БООООЛЬШОЕ пожалуйста объясните как.


Piople   (2003-11-19 11:31:00) [17]

Понял!!!


Digitman   (2003-11-19 10:50:00) [18]

ты там, в примерах в статье, видел вызовы ф-ций CreateFileMapping, MapViewOfFile ? Думаешь, от балды ф-ции вызываются ? Как раз не от балды, а из-за необходимости сделать значение хэндла хука глобально-доступным для всех процессов, в которые хук-DLL внедряется.

у тебя этого нет, а это крайне важно !
исправляй, потом будет дальнейший разговор про твои беды)


Digitman   (2003-11-19 10:43:00) [19]


> да и зачем мне ссылка на сайт русского языка


потому что у тебя и с этим, чувствуется, большие проблемы)


> Моя ошибка заключется в том, на сколько я понял, что я не
> обрабатываю создания других окон


твоя ошибка уже в том, что SysHook у тебя в момент вызова CallNextHookEx() соответствует корректному хэндлу хука только в том экз-ре хук-DLL, который ты загрузил явно.

во всех прочих экз-рах SysHook у тебя равен нулю (про AV я погорячился, его не будет), и , соотв-но, ф-ция CallNextHookEx() дает гарантированный отказ


Piople   (2003-11-19 08:46:00) [20]


> Digitman

Статью изучил, и почитал еще ряд статей, но вот про AV-исключения, и GUI не слова не нашел. Моя ошибка заключется в том, на сколько я понял, что я не обрабатываю создания других окон (кнопок, разных боксов, и т.д.) и поэтму мой хук ловит все подряд от создаваемого прложения, поэтому мне надо обработывать только создание главного окна, а то что мне не нужно пропускать, так я понял? да и зачем мне ссылка на сайт русского языка :)?


Страницы:   1 2

Наверх

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