-
Суть проблемы в следующем: ловушка на щелчки мыши, встроенная в тело исполняемой пр-мы(не dll), полностью перестает обрабатывать сообщения стоит только отправить машину в ждущий, спящий режимы. То есть она просто остается болтаться в процессах, не выполняя никакой полезной работы. Ошибка в результате внесенных мною в код изменений исключается, т.к. пробовал запускать чистый hook с единственной сигнализацией в виде диалог. сообщения - итог тот же. Можно ли исправить это поведение программы? Буду благодарен ответившим.
-
> inkognito (28.01.13 21:58) The hook procedure should process a message in less time than the data entry specified in the LowLevelHooksTimeout value in the following registry key: HKEY_CURRENT_USER\Control Panel\Desktop The value is in milliseconds. If the hook procedure times out, the system passes the message to the next hook. However, on Windows 7 and later, the hook is silently removed without being called. There is no way for the application to know whether the hook is removed.http://msdn.microsoft.com/en-us/library/windows/desktop/ms644986(v=vs.85).aspx
-
Спасибо, нашел выход перекинув hook в обычную dll, но все же странно как-то..
-
> inkognito (29.01.13 21:43) [2]
> перекинув hook в обычную dll
у этого способа куча недостатков.
-
Согласен, замучился с отловом ошибок.. В особенности в момент выгрузки библиотеки, интересная закономерность: если закрываю все подопытные программы(то есть те в которых эти хук сообщения принимались) раньше чем выгружаю длл - видимых проблем нет, но стоит это сделать после и ошибки начинают сыпаться веером, включая и все остальные процессы, даже explorer.. :( По правде сказать, так и не нашел этому решения, в длл мало что смыслю..
-
> inkognito (30.01.13 05:18) [4]
поэтому не надо лезть с хуками в dll, особенно если не понимаешь как оно работает, используй LL hooks, в обработчике не выполняй длительные блокирующие операции.
-
> но стоит это сделать после и ошибки начинают сыпаться веером, > включая и все остальные процессы, даже explorer.. :(
Финализация значит не верная.
-
Вот, собственно, сам модуль dll. Не знаю какая финализация здесь требуется, кроме разве что высвобождения popupmenu.. library lib2;
uses
forms,
menus,
windows,
dialogs,
messages,
controls,
Unit1 in 'Unit1.pas' ;
type
TFm = class(TForm)
procedure x1Click(Sender: TObject);
end;
var
pt : TPoint;
theHook : THandle;
fm:TFm;
popupmenu1:tpopupmenu;
procedure TFm.x1Click(Sender: TObject);
begin
showmessage('#')
end;
procedure DLLProc_(Reason: Integer);
var i:integer;
begin
if Reason = DLL_PROCESS_DETACH then
end;
function MouseHook(nCode, wParam, lParam : integer) : Lresult; stdcall;
Begin
case wParam of
WM_RBUTTONUP :
begin
popupmenu1 := tpopupmenu.create(application);
with popupmenu1.items do add(newitem('click',0,False,True,fm.x1Click,0,'MenuItem1'));
popupmenu1.popup(mouse.cursorpos.x,mouse.cursorpos.y);
end
else
Result := CallNextHookEx(theHook, nCode, wParam, lParam);
end;
End;
procedure Start;
begin
theHook := SetWindowsHookEx(wh_mouse, @mouseHook, hInstance, 0);
if theHook = 0 then
messageBox(0,'Error!','Error!',mb_ok);
end;
procedure Remove;
begin
UnhookWindowsHookEx(theHook);
end;
exports
Start index 1 name 'Start',
Remove index 2 name 'Remove';
begin
DLLProc:= @DLLProc_;
end. Баги начинают плодиться именно на выгрузке, но с условием, что не было закрыто хотя бы одно из чужих окон, куда был произведен правый щелчок мыши.
-
-
Ну незнаю )), вообще то это почти полный оригинал примера размещенного в небезизвестной DRKB 3, вполне рабочий, надо сказать, ну кроме выхода..) Думаю, вас прежде всего смутил:
type
TFm = class(TForm)
procedure x1Click(Sender: TObject);
end;
..но для меня это стало производственной необходимостью, иначе не выходило вписать обработчик меню x1Click в аdd(newitem(..)). Подозреваю, что дело именно в нем, потому как с showmessage() заместо popupmenu1.popup() работает все распрекрасно.
-
-
> inkognito (01.02.13 04:21) [9]
ты неправильно понимаешь принцип работы данного вида хуков. эта область затрагивает чужие процессы, туда нельзя лезть, не понимая что делаешь. разобраться "по быстрому" с хуками не выйдет и не надейся.
-
Наверное так и есть и GunSmoker прав на 200%, но способ все-равно найду, уж больно заманчивая идейка!)
-
-
Rouse_: Да, но ведь изменения довольно косметические: убрал ненужный код на прочие кнопки мыши в обработчике MouseHook , добавил пару переменных(одну, а именно fm вообще для совместимости только), добавил dllproc, которая здесь вообще ничего не делает.. Еще забыл убрать лишнюю глоб. переменную pt из этого примера. Вот, пожалуй, и все вроде бы.. Повторюсь, что если подменяю P.Popup() на банальный ShowMessage() - все работает без нареканий, по крайней мере с моей скромной стороны.
-
А ты не добавляй dllproc, меню создал, отобразил - разрушай его сразу, а не в dllproc, избавишся и от проблем и от мемлика. Далее, форма у тебя не создается, тут вообще все упасть должно, да и зачем тебе нужна она? Хочешь показать свое меню, так и работай с ним нормально CreatePopupMenu + TrackPopupMenu + DestroyMenu, а не то что ты написал где все в кучу смешано и API и VCL.
-
Rouse_: Знаю что вы профи, одна только ваша статья о компиляторе Delphi очень даже мне пригодилась. Поэтому расчитываю на ваше компетентное мнение в отношении стратегии внедрения этого треклятого попапа грамотно и без последствий, если это возможно конечно...
-
Спасибо, попробую. Не подозревал о наличие CreаtPopupMenu, дилетант.. )) Немного опоздал с предпоследним комментарием. :)
-
Если задача встроить свой пункт меню в уже существующее, то имеет смысл сделать так, по шагам: 1. перехватить TrackPopupMenu 2. в пойманном вызове удостоверится что это требуемое нам меню (ну например по составу его итемов или по хэндлу окна) 3. добавить свой пункт через InsertMenuItem 4. перекрыть обработчик окна указанный в параметре hWnd 5. вызывать оригинальный обработчик TrackPopupMenu 6. в перекрытом обработчике окна обработать WM_COMMAND где проверить, выбран наш пункт меню. 6.1 если выбран наш - выполнить его обработчик (например показать сообщение) 6.2 если не наш - вызвать оригинальный обработчик 7. снять перехват обработчика окна 8. по завершении работы снять перехват TrackPopupMenu
-
ЗЫ: ну это при условии что в uFlag отсутствует TPM_RETURNCMD, если он присутствует, то пункты 4, 6, 6.1, 6.2, 7 лишние. В место 6.1 проверять то что вернула TrackPopupMenu и если это наш пункт меню - то выполнить его обработчик.
-
Задачка гораздо скромее, показать наше меню поверх родного, если такое имеется в дочернем компоненте чужого окна. Содержание меню представляет собой список выполняемых приложений для нужд пользователя, которое строится в зависимости от конкретного подкласса и( возможно, его текста), ну и, конечно родительского класса и заголовка. Бывает полезно из уже открытой пр-мы запустить какой-то кусок кода связанный с ней по функционалу, все это уже готово и работает.. Вся эта дребедень задается пользователем и сохраняется в ini. Смысл перезапуска dll в том чтобы добавлять новые позиции в это меню, а так же в новые окна. С внедрением тоже как-нибудь заморочусь))
-
Тогда достаточно вот этого
> Rouse_ © (01.02.13 15:56) [15]
-
-
> Rouse_ © (01.02.13 18:30) [22]
> т.к. нет смысла мусорить во всех процессах.
для этого нужно размещать хук не в dll модуле, а самой программе. но тут появляется вопрос, а зачем вообще этот хук, когда речь о своем процесс.
-
> Eraser © (01.02.13 19:23) [23] > для этого нужно размещать хук не в dll модуле, а самой программе
Как я понял - проблема у автора с конкретным процессом, но не со своим. В этом случае, установка перехватчика непосредственно в тело работающего приложения, достаточно нетривиальная задача. Слишком хороший уровень должен быть для данной реализации. Гораздо проще разместить перехватчик в библиотеке, и инжектировать ее, чем разруливать проблемы с адресацией используемых АПИ во внедренном коде.
-
> Eraser © (01.02.13 19:23) [23]
Кстати, если ты прав и процесс свой, то тогда вообще готодить огорот с перехватом не имеет смысла, достаточно перекрыть OnPopup у меню в котором зачитать требуемые пункты меню, которые нужно добавить и накинуть их прямо в рантайме. И это с учетом что состав этих меню может меняться прямо в момент работы программы, а если нет, то вообще все делается на старте приложения.
|