![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Hook wanted [D5, Win95/98]
Mihey_temporary © (2004-12-13 23:08:00)У кого-нибудь есть навскидку готовый пример глобального хука на мышь, отсылающего программе сообщения при передвижении мыши и нажатии на кнопки? Требуется и хук, и обработка сообщений в главной программе.
Piter (2004-12-16 20:16:00) [1]Юрий Зотов © (16.12.04 1:17) [31]
вы прирожденный учитель... это сколько же у вас терпения...
Mihey_temporary (2004-12-16 17:41:00) [2]
> P.S.
> Плз, исправьте страничку, на которую Вы ссылаетесь в "Потрепаться".
> Я хотел ее посмотреть, но через несколько секунд просмотра
> рисунок свернулся в тонкую полоску вдоль левого края экрана.
> Соответственно, высота букв стала примерно 0.2 мм и читать
> их стало довольно трудно.
Если вы используете IE, то дождитесь загрузки картинки, а затем наведите курсор на нижнюю часть картинки (сантиметр от нижнего края примерно). Прямо на ней появится кнопка, нажава на которую вы расширите картинку до первоначальных размеров. Также вы можете снять галочку с Enable Automatic Image Resizing в Tools -> Internet Options -> Advanced -> раздел Multimedia в списке. В Mozilla нужно просто щёлкнуть по картинке.
Юрий Зотов (2004-12-16 01:17:00) [3]> Mihey_temporary © (15.12.04 19:42) [29]
> автор статьи по использованию хуков в Delphi ссылается на
> примеры, написанные на C++. Вот как это воспринимать?
Так, что автор не считает нас, читателей, полнейшими чайниками. И он прав. Иначе бы ему пришлось писать не статью, а двадцатитомную книгу.
Есть такое понятие - ожидаемая аудитория. Учебник по матанализу пишется не для дошкольников, понимаете?
Вообще же, если программист Delphi не в состоянии понять код C (кстати, в данном случае даже без всяких плюсов), то ему стоит подумать о смене профессии. Потому что водителей "Жигулей" не бывает. Бывают просто водители.
> и не так уж много я узнал, чтобы так сказать, "добивать"
> досконально тему.
Дело Ваше. Но знайте: если Вы досконально не разобрались, что такое глобальные данные, зачем они здесь нужны и как реализуются - то тогда в этой теме Вы не поняли... ни-че-го.
Даже без всяких сомнений.
А решать - Вам.
P.S.
Плз, исправьте страничку, на которую Вы ссылаетесь в "Потрепаться". Я хотел ее посмотреть, но через несколько секунд просмотра рисунок свернулся в тонкую полоску вдоль левого края экрана. Соответственно, высота букв стала примерно 0.2 мм и читать их стало довольно трудно.
P.P.S.
ИМХО, уровень наших разговоров потихоньку растет. Как Вы считаете?
Leonid Troyanovsky (2004-12-15 21:48:00) [4]
> Mihey_temporary © (15.12.04 14:21) [20]
> Непонятно конечно ничего, но я так понял, что непорядок
> почему-то с внутренней переменной MouseHooker и почему то
> неопрядок с хендлом как будто он зависит от АП. А у Piter'а
> в коде:
> var
> GlobalData: PGlobalData ;
> MapHandle: THandle;
> И с ними порядок. Что-то тут не стыкуется открыто.
A library can be used by several applications at once, but each application has a copy of the library in its own process space with its own set of global variables. For multiple libraries—or multiple instances of a library—to share memory, they must use memory-mapped files. Refer to the your system documentation for further information.
Т.е., глобальности GlobalData, MapHandle хватает лишь
на то, чтобы обобщить их между OpenSharedData и
хуковой процедурой (исполняемых в чужом процессе).
Зато, данные записанные в mmf, действительно глобальны,
и разделяются всеми процессами, открывшими оный mmf.
--
С уважением, LVT.
PS Кстати, "the your system documentation" - MSDN ;)
Mihey_temporary (2004-12-15 19:42:00) [5]2 -=SS=-:
> Это творение Pitera переделанное на Мышь.... у меня работает
> незнаю чем ты там сдрадаешь Михей но требовалось поменять
> несколько строк кода ...
Так всё уже сделано. Кстати, интересно, как ты будешь принимать и обрабатывать сообщение в программе при своём решении?
2 Юрий Зотов:
> Этими словами Вы еще раз подтвердили, что "Вам действительно
> нужно прочесть статью и понять, ПОЧЕМУ и ЗАЧЕМ здесь нужен
> memory-mapped file".
Смотрите: ищу в статье информацию на тему WH_MOUSE. Автор пишет: "о которых каждый может прочитать в SDK, MSDN". Иду на MSDN. Там пишут, что обработка производится в специальной процедуре, например, с именем MouseProc и для подробностей смотрите её. Смотрим её и что мы видим:
LRESULT CALLBACK MouseProc( int nCode,
WPARAM wParam,
LPARAM lParam
);
Что это? Это что-то новое из языка Delphi? Ах нет, просто автор статьи по использованию хуков в Delphi ссылается на примеры, написанные на C++. Вот как это воспринимать?
В принципе, всё работает и не так уж много я узнал, чтобы так сказать, "добивать" досконально тему. Думаю, как нибудь в следующий раз почитаю, если актуальность такого подхода доживёт до этого раза.
Юрий Зотов (2004-12-15 18:24:00) [6]> Mihey_temporary © (15.12.04 15:42) [23]
> Как же он зависит, когда Handle - это уникальный идентификатор
> окна (в данном случае) в системе?
Этими словами Вы еще раз подтвердили, что "Вам действительно нужно прочесть статью и понять, ПОЧЕМУ и ЗАЧЕМ здесь нужен memory-mapped file".
Объяснять Вам всю кухню прямо здесь вряд ли кто станет. Потому что объяснения потянут еще на одну такую же статью - а зачем ее писать, если:
1. она и так уже написана;
2. читать Вы все равно не хотите.
-=SS=- (2004-12-15 17:52:00) [7]library M_Hook;
uses
Windows;
const
cMMFileName = 'piter-hook_{E891D15B-DD53-4BC8-81F4-E0BF8A5573B6}';
type
PGlobalData = ^TGlobalData;
TGlobalData = packed record
HookProcessId: DWORD;
HookHandle: HHOOK;
WindowHandle: THandle;
idMsg: LongWord;
end;
var
GlobalData: PGlobalData ;
MapHandle: THandle;
function DeleteHook(CheckProcess: boolean): boolean;
begin
Result := false;
if GlobalData <> nil then
with GlobalData^ do
if HookHandle<>0 then
if (not CheckProcess) or (GetCurrentProcessId = HookProcessId) then
begin
Result := UnHookWindowsHookEx(HookHandle) ;
if Result then
HookHandle := 0;
end;
end;
function RemoveMouseHook: boolean; stdcall;
begin
Result := DeleteHook(True);
end;
function MouseProc(nCode: integer; wParam: LongWord;
lParam: LongWord): integer; stdcall;
begin
Result := 0;
if GlobalData <> nil then
with GlobalData^ do
begin
if IsWindow(WindowHandle) then
SendMessage(WindowHandle, idMsg, wParam, nCode)
else
DeleteHook(False);
CallNextHookEx(HookHandle, nCode, wParam, lParam);
end;
end;
function SetMouseHook(CallbackWindow: THandle;
idCallBackMessage: LongWord): boolean;
begin
Result := false;
if GlobalData <> nil then
with GlobalData^ do
if ( HookHandle = 0 ) then
begin
HookHandle := SetWindowsHookEx(WH_MOUSE, @MouseProc, HInstance, 0);
Result := HookHandle <> 0;
if Result then
begin
HookProcessId := GetCurrentProcessId ;
WindowHandle := CallbackWindow ;
idMsg := idCallBackMessage ;
end;
end;
end;
procedure OpenSharedData;
var
Size: integer;
begin
Size := SizeOf(TGlobalData);
MapHandle := CreateFileMapping(INVALID_HANDLE_VALUE, nil, PAGE_READWRITE,
0, Size, cMMFileName);
if MapHandle = 0 then exit;
GlobalData := MapViewOfFile(MapHandle, FILE_MAP_ALL_ACCESS, 0, 0, Size);
end;
procedure CloseSharedData;
begin
UnmapViewOfFile(GlobalData);
CloseHandle(MapHandle);
end;
procedure DLLEntryProc(dwReason: DWord);
begin
case dwReason of
DLL_PROCESS_ATTACH: OpenSharedData;
DLL_PROCESS_DETACH:
begin
RemoveMouseHook ;
CloseSharedData;
end;
end;
end;
exports
SetMouseHook, RemoveMouseHook;
begin
DLLProc := @DLLEntryProc;
DLLEntryProc(DLL_PROCESS_ATTACH);
end.
в проге
function RemoveMouseHook: boolean; external 'm_hook.dll';
function SetMouseHook(CallbackWindow: THandle;
idCallBackMessage: LongWord): boolean; external 'm_hook.dll';
Это творение Pitera переделанное на Мышь.... у меня работает незнаю чем ты там сдрадаешь Михей но требовалось поменять несколько строк кода ...
Cobalt (2004-12-15 17:35:00) [8]#ifdef Offtopic
Мне кажется, что это такой эксперимент.
##endif //Offtopic
Piter (2004-12-15 17:28:00) [9]Блин, вроде Mihey_temporary - ник мне известный, на форуме не впервой... ну зачем же так неуважать людей...
Piter (2004-12-15 17:27:00) [10]Polevi © (15.12.04 9:40) [19]
да, это уже идет непрекрытое хамство. Самое интересное, что эти люди потом будут заводить тему, аналогичные этой - http://www.delphimaster.ru/cgi-bin/forum.pl?id=1102690000&n=3:(
Mihey_temporary (2004-12-15 15:42:00) [11]
> Именно. Зависит.
Как же он зависит, когда Handle - это уникальный идентификатор окна (в данном случае) в системе?
> Вам действительно нужно прочесть статью
Чтобы прочитать, мол, идите и читайте MSDN? Даром не надо.
Юрий Зотов (2004-12-15 15:33:00) [12]> Mihey_temporary © (15.12.04 14:21) [20]
> непорядок почему-то с внутренней переменной MouseHooker и
> почему то неопрядок с хендлом как будто он зависит от АП.
Именно. Зависит.
> а у Piter'а в коде:
> ...
> И с ними порядок. Что-то тут не стыкуется открыто.
Все прекрасно стыкуется. Piter использует ГЛОБАЛЬНЫЕ данные, а Вы - ЛОКАЛЬНЫЕ. Вот и вся разница, но на работу хука она оказывает РЕШАЮЩЕЕ влияние.
Вам действительно нужно прочесть статью и понять, ПОЧЕМУ и ЗАЧЕМ здесь нужен memory-mapped file.
Digitman (2004-12-15 14:35:00) [13]
> Непонятно конечно ничего
если "непонятно ничего" и впредь статьи ты читать/анализировать/вникать не намерен - подайся в управдомы .. ибо без теории ни-че-го путного из "программерских" потуг не выйдет.
Mihey_temporary (2004-12-15 14:21:00) [14]Всё нормально получилось, хук работает. Вот видите, статью не читал, а разобрался. Большое спасибо Piter'у за отличный пример. Юрий Зотов помог с WM_COPYDATA, а Leonid Troyanovsky с ошибками в коде - их тоже благодарю.
Осталась пара моментов.
У Piter'а в коде:
Result := false;
if GlobalData <> nil then
with GlobalData^ do
if ( HookHandle = 0 ) and ( IsWindow(CallbackWindow) ) then
begin
HookHandle := SetWindowsHookEx(WH_SHELL, @ShellProc, HInstance, 0);
Result := HookHandle <> 0;
if Result then
begin
HookProcessId := GetCurrentProcessId ;
WindowHandle := CallbackWindow ;
idMsg := idCallBackMessage ;
end;
end;
Так что же, если у нас будет глюк и GlobalData = nil, то цепочка хуков прервётся из-за нашей программы? Непорядок.
И вот ещё. Игорь Шевченко писал 15.12.04 в 00:23 в посте [14] следующее:
"> var
> MouseHooker: HHook;
> BackHandle: HWND;
Отгадай, чему будут равны эти переменные при загрузке DLL в чужое пространство, если учесть, что сегмент данных у каждого экземпляра DLL свой."
Непонятно конечно ничего, но я так понял, что непорядок почему-то с внутренней переменной MouseHooker и почему то неопрядок с хендлом как будто он зависит от АП. А у Piter'а в коде:
var
GlobalData: PGlobalData ;
MapHandle: THandle;
И с ними порядок. Что-то тут не стыкуется открыто.
Polevi (2004-12-15 09:40:00) [15]и вообще не понимаю людей которые чем-то помогают подобным личностям
Polevi (2004-12-15 09:39:00) [16]и ключи от квартиры
Mihey_temporary (2004-12-15 02:12:00) [17]
> Piter © (15.12.04 01:52) [16]
И код использования в программе, пожалуйста.
Piter (2004-12-15 01:52:00) [18]Ну что же МИХЕЙ-ИЩУЩИЙ-ЛЕГКИХ-ПУТЕЙ. Вот тебе код моей библиотеки:
library piter_hook;
uses
Windows;
const
cMMFileName = 'piter-hook_{E891D15B-DD53-4BC8-81F4-E0BF8A5573B6}';
type
PGlobalData = ^TGlobalData;
TGlobalData = packed record
HookProcessId: DWORD;
HookHandle: HHOOK;
WindowHandle: THandle;
idMsg: LongWord;
end;
var
GlobalData: PGlobalData ;
MapHandle: THandle;
function DeleteHook(CheckProcess: boolean): boolean;
begin
Result := false;
if GlobalData <> nil then
with GlobalData^ do
if HookHandle<>0 then
if (not CheckProcess) or (GetCurrentProcessId = HookProcessId) then
begin
Result := UnHookWindowsHookEx(HookHandle) ;
if Result then
HookHandle := 0;
end;
end;
function RemoveShellHook: boolean; stdcall;
begin
Result := DeleteHook(True);
end;
function ShellProc(nCode: integer; wParam: LongWord;
lParam: LongWord): integer; stdcall;
begin
Result := 0;
if GlobalData <> nil then
with GlobalData^ do
begin
if IsWindow(WindowHandle) then
SendMessage(WindowHandle, idMsg, wParam, nCode)
else
DeleteHook(False);
CallNextHookEx(HookHandle, nCode, wParam, lParam);
end;
end;
function SetShellHook(CallbackWindow: THandle;
idCallBackMessage: LongWord): boolean; stdcall;
begin
Result := false;
if GlobalData <> nil then
with GlobalData^ do
if ( HookHandle = 0 ) and ( IsWindow(CallbackWindow) ) then
begin
HookHandle := SetWindowsHookEx(WH_SHELL, @ShellProc, HInstance, 0);
Result := HookHandle <> 0;
if Result then
begin
HookProcessId := GetCurrentProcessId ;
WindowHandle := CallbackWindow ;
idMsg := idCallBackMessage ;
end;
end;
end;
procedure OpenSharedData;
var
Size: integer;
begin
Size := SizeOf(TGlobalData);
MapHandle := CreateFileMapping(INVALID_HANDLE_VALUE, nil, PAGE_READWRITE,
0, Size, cMMFileName);
if MapHandle = 0 then exit;
GlobalData := MapViewOfFile(MapHandle, FILE_MAP_ALL_ACCESS, 0, 0, Size);
end;
procedure CloseSharedData;
begin
UnmapViewOfFile(GlobalData);
CloseHandle(MapHandle);
end;
procedure DLLEntryProc(dwReason: DWord);
begin
case dwReason of
DLL_PROCESS_ATTACH: OpenSharedData;
DLL_PROCESS_DETACH:
begin
RemoveShellHook ;
CloseSharedData;
end;
end;
end;
exports
SetShellHook, RemoveShellHook;
begin
DLLProc := @DLLEntryProc;
DLLEntryProc(DLL_PROCESS_ATTACH);
end.
Правда, опять не все шоколадно. У меня хук WH_SHELL, а у тебя WH_MOUSE. Но если мы умеем хотя бы чуть чуть думать - то что-то может получится.
По крайней мере, продемонстрировано как работать с проецируемыми в память файлами.
А вообще интересная позиция - этого я читать не хочу, того тоже. А нафига ты вообще программированием занимаешься? Ты всегда планируешь чуть что - сюда со своими проблемами идти?
Mihey_temporary (2004-12-15 01:09:00) [19]
> Легкое решение - читать статью и искать способ разделения
> этих двух переменных между всеми экземплярами DLL, например,
> используя Memory-Mapped Files.
Да не буду я читать эту статью. Вообще у вас тут всё оффтопик - мне нужен пример готовый работающий, а не учения про сообщения и проецируемые файлы. Вот дали ссылку:
http://delphimaster.ru/cgi-bin/forum.pl?id=1102341741&n=0
Но чего-то не идёт. Возьмите, скопируйте код, если вам не сложно, добавьте пару волшебных штрихов и выдайте назад.
Игорь Шевченко (2004-12-15 00:23:00) [20]Mihey_temporary © (14.12.04 23:39) [13]
Ссылка на статью не зря ведь дадена была.
> var
> MouseHooker: HHook;
> BackHandle: HWND;
Отгадай, чему будут равны эти переменные при загрузке DLL в чужое пространство, если учесть, что сегмент данных у каждого экземпляра DLL свой.
> Я ищу лёгкое решение.
Легкое решение - читать статью и искать способ разделения этих двух переменных между всеми экземплярами DLL, например, используя Memory-Mapped Files.
С уважением,