написал глобальный хук на движение формы, вот код:
library Project2;
uses Windows, Messages, Sysutils, Dialogs;
var myHook: HHook = 0; myFile:TextFile; {$R *.res} function MsgProc(Code: integer; wParam: Word; lParam: Longint): Longint; stdcall; var mas:array[0..255]of char; begin if Code<0 then begin<br /> result:=CallNextHookEx(myHook,Code,wParam,lParam); exit; end; if CWPRETSTRUCT(Pointer(LParam)^).message=wm_move then begin if IsWindowVisible(CWPRETSTRUCT(Pointer(LParam)^).hwnd) then begin getwindowtext(CWPRETSTRUCT(Pointer(LParam)^).hwnd,mas,sizeof(mas)); { SetWindowLong(CWPRETSTRUCT(Pointer(LParam)^).hwnd, GWL_EXSTYLE, GetWindowLong(CWPRETSTRUCT(Pointer(LParam)^).hwnd, GWL_EXSTYLE) or WS_EX_LAYERED); SetLayeredWindowAttributes(CWPRETSTRUCT(Pointer(LParam)^).hwnd, 0, 150, LWA_ALPHA); }
procedure setHook(Hook: boolean) export; stdcall; begin if Hook then begin // AssignFile(myFile, 'C:\Test.txt'); // ReWrite(myFile); if myHook=0 then myHook:=SetWindowsHookEx(WH_CALLWNDPROCRET,@MsgProc,HInstance,0); ShowMessage('Хук установлен'); end else begin // CloseFile(myFile); if myHook<>0 then UnHookWindowsHookEx(myHook); ShowMessage('Хук снят'); myHook:=0; end; end;
exports setHook name 'SetHook'; begin end.
в таком вот варианте работает все замечательно, т.е. при начале движения формы выскакивает сообщение с заголовком формы. Если раскомментировать эти строки
то при начале движение формы, форма становится полупрозрачной. НО если раскомментировать остальное, т.е. если я хочу что бы заголовки формы записывались в файл то получается вовсе не гуд. Поясню, запускаю хук пока двигаю свою форму все ок, ее заголовок пишется в файл, но стоит мне перейти на какую-нить чужую форму и попытаться сдвинуть ее тут же происходит "падение" проги (форму которой я двигаю). Как бы это не принципиально, мне важно что бы она становилось полупрозрачной и это работает, но меня заинтересовал этот вопрос, хочу разобраться в этом для самосовершенствования, из-за чего это происходит? Есть конечно догадки, но может они глупо звучат )) я думаю это из-за того что на выполнение Writeln нужно больше времени чем на ShowMessage т.е. не успевают остальные сообщения в очереди обрабатываться. Прошу разъяснить этот вопрос тех кто в теме )
У каждого приложения на которое ставят хук по сути заново загружается dll, свой экземпляр, и только в одном у тебя эти переменные будут "рабочие".
Цитата Возвращаемое значение: функция SetWindowsHookEx возвращает дескриптор установленной ловушки, именно этот дескриптор нам и надо будет сделать доступным ВСЕМ экземплярам отображаемой DLL. Как это сделать я расскажу после небольшого примера, показывающего на практике необходимость сохранять дескриптор ловушки для того, что бы суметь вызвать предыдущую ловушку в цепочке.
Для того, что бы все экземпляры DLL, находящиеся в разных процессах, имели доступ к дескриптору ловушки, надо выделить какую-то область, доступ к которой будут иметь все "желающие". Для этого воспользуемся одним из мощнейших механизмов Windows под названием "Файлы, отображённые в память" (Memory Mapped Files). Механизм файлов, отображённых в память (MMF - Memory Mapped Files) позволяет резервировать определённую область АП системы Windows, для которой назначаются страницы физической памяти. Таким образом, с помощью MMF можно отображать в память не только файлы, но и данные, ссылаясь на них из своих программ с помощью указателей.
пока не исправишь недочеты (а скорее всего их исправление приведет к работоспособности) смотреть смысла особого нет
Только что попробовал использовать MMF результат такой же, вот посмотрите код, может я что-то не так сделал?
library Project2;
uses Windows, Messages, Sysutils, Dialogs; type PGlobalDLLData = ^TGlobalDLLData; TGlobalDLLData = packed record SysHook: HWND; MyAppWnd: HWND; myFile:TextFile; end;
var GlobalData: PGlobalDLLData; MMFHandle: THandle;
{$R *.res} function MsgProc(Code: integer; wParam: Word; lParam: Longint): Longint; stdcall; var mas:array[0..255]of char; begin if Code<0 then begin<br /> result:=CallNextHookEx(GlobalData^.SysHook,Code,wParam,lParam); exit; end; if CWPRETSTRUCT(Pointer(LParam)^).message=wm_move then begin GlobalData^.MyAppWnd:=CWPRETSTRUCT(Pointer(LParam)^).hwnd; if IsWindowVisible(GlobalData^.MyAppWnd) then begin getwindowtext(GlobalData^.MyAppWnd,mas,sizeof(mas)); { SetWindowLong(GlobalData^.MyAppWnd, GWL_EXSTYLE, GetWindowLong(GlobalData^.MyAppWnd, GWL_EXSTYLE) or WS_EX_LAYERED); SetLayeredWindowAttributes(GlobalData^.MyAppWnd, 0, 150, LWA_ALPHA); } Write(GlobalData^.myFile,mas); //ShowMessage(mas); end; end;
procedure setHook(Hook: boolean) export; stdcall; begin if Hook then begin AssignFile(GlobalData^.myFile, 'C:\Test.txt'); ReWrite(GlobalData^.myFile); if GlobalData^.SysHook=0 then GlobalData^.SysHook:=SetWindowsHookEx(WH_CALLWNDPROCRET,@MsgProc,HInstance,0); ShowMessage('Хук установлен'); end else begin CloseFile(GlobalData^.myFile); if GlobalData^.SysHook<>0 then UnHookWindowsHookEx(GlobalData^.SysHook); ShowMessage('Хук снят'); GlobalData^.SysHook:=0; end; end;
procedure OpenGlobalData(); begin MMFHandle:= CreateFileMapping(INVALID_HANDLE_VALUE, nil, PAGE_READWRITE, 0, SizeOf(TGlobalDLLData), Pchar('KeyMMF'));
if MMFHandle = 0 then begin MessageBox(0, 'Can''t create FileMapping', 'Message from keyhook.dll', 0); Exit; end;
{отображаем глобальные данные на АП вызывающего процесса и получаем указатель на начало выделенного пространства} GlobalData:= MapViewOfFile(MMFHandle, FILE_MAP_ALL_ACCESS, 0, 0, SizeOf(TGlobalDLLData)); if GlobalData = nil then begin CloseHandle(MMFHandle); MessageBox(0, 'Can''t make MapViewOfFile', 'Message from keyhook.dll', 0); Exit; 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 setHook name 'SetHook'; begin DLLEntryPoint(DLL_PROCESS_ATTACH); end.
Что-то как-то мало букавок :) Вот OpenFileMapping() не вижу... обработки ошибок нет, там можно долго ловить багу.
что нибудь типа этого сооруди -
type PGlobalDLLData = ^TGlobalDLLData; TGlobalDLLData = packed record SysHook: HWND; MainWnd: HWND; end;
const MMFName: PChar = 'HAHAHA';
var MMFHandle: THandle; MMFData: PGlobalDLLData;
implementation
function CreateMMF(Name: string; Size: Integer): THandle; begin Result:=CreateFileMapping(INVALID_HANDLE_VALUE, nil, PAGE_READWRITE, 0, Size, PChar(Name)); if Result<>0 then begin if GetLastError=ERROR_ALREADY_EXISTS then begin CloseHandle(Result); Result:=0; end; end; end;
function OpenMMF(Name: string): THandle; begin Result:=OpenFileMapping(FILE_MAP_ALL_ACCESS, False, PChar(Name)); end;
function MapMMF(MMFHandle: THandle): Pointer; begin Result:=MapViewOfFile(MMFHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0); end;
function UnMapMMF(P:Pointer):Boolean; begin Result:=UnmapViewOfFile(P); end;
function CloseMMF(MMFHandle:THandle):Boolean; begin Result:=CloseHandle(MMFHandle); end;
function UnMapAndCloseMMF:Boolean; begin Result:=False; if(MMFData<>nil) then if UnMapMMF(MMFData) then begin MMFData:=nil; if CloseMMF(MMFHandle) then begin MMFHandle:=0; Result:=True; end; end; end;
function GetData(var MMFD:PGlobalDLLData):boolean; var MMFHandle:THandle; begin result:=false; MMFHandle:=OpenMMF(MMFName); if MMFHandle<>0 then begin MMFData:=MapMMF(MMFHandle); if MMFData<>nil then begin MMFD:=MMFData; result:=true; end; end; end;
и установка:
function MsgFilterFunc(Code: Integer; wParam, lParam: Longint): Longint; stdcall; var MMFHandle:THandle; MMFData:PGlobalDLLData; begin Result:=0; MMFHandle:=OpenMMF(MMFName); if MMFHandle<>0 then begin
MMFData:=MapMMF(MMFHandle); if MMFData<>nil then begin if (Code<0)or(wParam = PM_NOREMOVE) then<br /> Result:=CallNextHookEx(MMFData.SysHook, Code, wParam, lParam) else begin
Result:=CallNextHookEx(MMFData.SysHook, Code, wParam, lParam); end; UnMapMMF(MMFData); end else begin //Writelog('MapMMF filed: '+SysErrorMessage(GetLastError)+' ['+GetName_DLL+']'); end; CloseMMF(MMFHandle); end else begin //Writelog('OpenMMF filed: '+SysErrorMessage(GetLastError)+' ['+GetName_DLL+']'); end; end;
function SetHook(WinHandle:HWND): Boolean; stdcall; begin Result := False; if (MMFData = nil) and (MMFHandle = 0) then begin MMFHandle := CreateMMF(MMFName, SizeOf(TGlobalDLLData)); if MMFHandle <> 0 then begin MMFData := MapMMF(MMFHandle); if MMFData <> nil then begin MMFData.MainWnd := WinHandle; MMFData.SysHook := SetWindowsHookEx(WH_KEYBOARD, @MsgFilterFunc,HInstance, 0); if MMFData.SysHook = 0 then begin //Writelog('SetHook SetWindowsHookEx filed'); UnMapAndCloseMMF(); end else begin Result := True;
end; end else begin //Writelog('SetHook MapMMF filed: '+SysErrorMessage(GetLastError));
CloseMMF(MMFHandle); MMFHandle := 0; end; end else begin //Writelog('SetHook CreateMMF filed: '+SysErrorMessage(GetLastError)); end; end; end;
function FreeHook: Boolean; stdcall; begin Result:=False; try if (MMFData<>nil) and (MMFHandle<>0) then if UnHookWindowsHookEx(MMFData^.SysHook) then Result:=UnMapAndCloseMMF; except end; end;
shell32, код трудно читаем... Попытался что-то сотворить теперь ничего не происходит, не ошибки не моих действий ) Вместо Writelog я поставил ShowMessage, при установки хука сообщения не выскакивает, но и ничего не происходит. Вполне вероятно что я что-то напутал, может ты попробуешь дополнить мой код (мой код попроще будет и свой ты уже знаешь, что там к чему) Если конечно время позволяет )))
У меня код на хук клавы был, под свой подстрой и я вырезал то что должно быть внутри :) После
if (Code<0)or(wParam = PM_NOREMOVE) then<br />Result:=CallNextHookEx(MMFData.SysHook, Code, wParam, lParam) else begin
нужно вставить твой код. В MMFData хранится дескриптор ловушки (и у меня там хендл формы, но тебе не нужен, туда нужно myFile:TextFile; поместить) и все что тебе понадобится.
дельфи под рукой нет, не могу проверить (((
UPD: попробуй оттуда вызывать такое (т.е. вызывая assignfile() каждый раз), для теста в лог:
procedure Writelog(filename,value: string); var f:textFile; begin assignfile(f, filename); if fileexists(filename) then append(f) else rewrite(f); try writeln(f,Value); finally Closefile(f); end; end;