Конференция "WinAPI" » Проблема с hook-ом на события мыши [D7]
 
  • inkognito (28.01.13 21:58) [0]
    Суть проблемы в следующем: ловушка на щелчки мыши, встроенная в тело исполняемой пр-мы(не dll), полностью перестает обрабатывать сообщения стоит только отправить машину в ждущий, спящий режимы. То есть она просто остается болтаться в процессах, не выполняя никакой полезной работы. Ошибка в результате внесенных мною в код изменений исключается, т.к. пробовал запускать чистый hook с единственной сигнализацией в виде диалог. сообщения - итог тот же. Можно ли исправить это поведение программы? Буду благодарен ответившим.
  • Eraser © (28.01.13 23:15) [1]

    > 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
  • inkognito (29.01.13 21:43) [2]
    Спасибо, нашел выход перекинув hook в обычную dll, но все же странно как-то..
  • Eraser © (30.01.13 04:42) [3]

    > inkognito   (29.01.13 21:43) [2]


    > перекинув hook в обычную dll

    у этого способа куча недостатков.
  • inkognito (30.01.13 05:18) [4]
    Согласен, замучился с отловом ошибок.. В особенности в момент выгрузки библиотеки, интересная закономерность: если закрываю все подопытные программы(то есть те в которых эти хук сообщения принимались) раньше чем выгружаю длл - видимых проблем нет, но стоит это сделать после и ошибки начинают сыпаться веером, включая и все остальные процессы, даже explorer.. :( По правде сказать, так и не нашел этому решения, в длл мало  что смыслю..
  • Eraser © (30.01.13 19:41) [5]

    > inkognito   (30.01.13 05:18) [4]

    поэтому не надо лезть с хуками в dll, особенно если не понимаешь как оно работает, используй LL hooks, в обработчике не выполняй длительные блокирующие операции.
  • Rouse_ © (30.01.13 19:47) [6]

    > но стоит это сделать после и ошибки начинают сыпаться веером,
    >  включая и все остальные процессы, даже explorer.. :(

    Финализация значит не верная.
  • inkognito (01.02.13 02:45) [7]
    Вот, собственно, сам модуль dll. Не знаю какая финализация здесь требуется, кроме разве что высвобождения popupmenu..

    library lib2;
    uses
     forms,
     menus,
     windows,
     dialogs,
     messages,
     controls,
     Unit1 in 'Unit1.pas' {Form1};

    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
     {popupmenu1.free}
    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.



    Баги начинают плодиться именно на выгрузке, но с условием, что не было закрыто хотя бы одно из чужих окон, куда был произведен правый щелчок мыши.
  • Eraser © (01.02.13 03:35) [8]

    > inkognito   (01.02.13 02:45) [7]

    даже не знаю с чего начать, тут все неправильно.
    начни с изучения книги Рихтера http://rouse.drkb.ru/books/rihter.zip
    там и про хуки есть тоже.
  • inkognito (01.02.13 04:21) [9]
    Ну незнаю )), вообще то это почти полный оригинал примера размещенного в небезизвестной DRKB 3, вполне рабочий, надо сказать, ну кроме выхода..)

    Думаю, вас прежде всего смутил:  

    type
    TFm = class(TForm)
    procedure x1Click(Sender: TObject);
    end;


    ..но для меня это стало производственной необходимостью, иначе не выходило вписать обработчик меню x1Click в аdd(newitem(..)). Подозреваю, что дело именно в нем, потому как с showmessage() заместо popupmenu1.popup() работает все распрекрасно.
  • Германн © (01.02.13 05:11) [10]

    > inkognito   (01.02.13 04:21) [9]
    >
    > Ну незнаю )), вообще то это почти полный оригинал примера
    > размещенного в небезизвестной DRKB 3

    http://www.gunsmoker.ru/2010/05/90.html
  • Eraser © (01.02.13 05:56) [11]

    > inkognito   (01.02.13 04:21) [9]

    ты неправильно понимаешь принцип работы данного вида хуков. эта область затрагивает чужие процессы, туда нельзя лезть, не понимая что делаешь. разобраться "по быстрому" с хуками не выйдет и не надейся.
  • inkognito (01.02.13 14:58) [12]
    Наверное так и есть и GunSmoker прав на 200%, но способ все-равно найду, уж больно заманчивая идейка!)
  • Rouse_ © (01.02.13 15:16) [13]

    > inkognito   (01.02.13 04:21) [9]
    > Ну незнаю )), вообще то это почти полный оригинал примера
    > размещенного в небезизвестной DRKB 3, вполне рабочий, надо
    > сказать, ну кроме выхода..)

    В DRKB опубликован правильный код:
    http://desksoft.ru/index.php?s_id=1e5dda75f785350294c84d7c5deafbbf&drkb=205&id=1655&str_path=0|126| 147|205

    А то что написано у тебя, очень мало общего имеет с оригиналом.
  • inkognito (01.02.13 15:45) [14]
    Rouse_: Да, но ведь изменения довольно косметические: убрал ненужный код  на прочие кнопки мыши в обработчике
    MouseHook

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

    Повторюсь, что если подменяю
    P.Popup()

    на банальный
    ShowMessage()

    - все работает без нареканий, по крайней мере с моей скромной стороны.
  • Rouse_ © (01.02.13 15:56) [15]
    А ты не добавляй dllproc, меню создал, отобразил - разрушай его сразу, а не в dllproc, избавишся и от проблем и от мемлика.
    Далее, форма у тебя не создается, тут вообще все упасть должно, да и зачем тебе нужна она?
    Хочешь показать свое меню, так и работай с ним нормально CreatePopupMenu + TrackPopupMenu + DestroyMenu, а не то что ты написал где все в кучу смешано и API и VCL.
  • inkognito (01.02.13 16:03) [16]
    Rouse_: Знаю что вы профи, одна только ваша статья о компиляторе Delphi очень даже мне пригодилась. Поэтому расчитываю на ваше компетентное мнение в отношении стратегии внедрения этого треклятого попапа грамотно и без последствий, если это возможно конечно...
  • inkognito (01.02.13 16:08) [17]
    Спасибо, попробую. Не подозревал о наличие CreаtPopupMenu, дилетант.. )) Немного опоздал с предпоследним комментарием. :)
  • Rouse_ © (01.02.13 16:15) [18]
    Если задача встроить свой пункт меню в уже существующее, то имеет смысл сделать так, по шагам:
    1. перехватить TrackPopupMenu
    2. в пойманном вызове удостоверится что это требуемое нам меню (ну например по составу его итемов или по хэндлу окна)
    3. добавить свой пункт через InsertMenuItem
    4. перекрыть обработчик окна указанный в параметре hWnd
    5. вызывать оригинальный обработчик TrackPopupMenu
    6. в перекрытом обработчике окна обработать WM_COMMAND где проверить, выбран наш пункт меню.
    6.1 если выбран наш - выполнить его обработчик (например показать сообщение)
    6.2 если не наш - вызвать оригинальный обработчик
    7. снять перехват обработчика окна
    8. по завершении работы снять перехват TrackPopupMenu
  • Rouse_ © (01.02.13 16:22) [19]
    ЗЫ: ну это при условии что в uFlag отсутствует TPM_RETURNCMD, если он присутствует, то пункты 4, 6, 6.1, 6.2, 7 лишние. В место 6.1 проверять то что вернула TrackPopupMenu и если это наш пункт меню - то выполнить его обработчик.
  • inkognito (01.02.13 16:42) [20]
    Задачка гораздо скромее, показать наше меню поверх родного, если такое имеется в дочернем компоненте чужого окна. Содержание меню представляет собой список выполняемых приложений для нужд пользователя, которое строится в зависимости от конкретного подкласса и( возможно, его текста), ну и, конечно родительского класса и заголовка. Бывает полезно из уже открытой пр-мы запустить какой-то кусок кода связанный с ней по функционалу, все это уже готово и работает.. Вся эта дребедень задается пользователем и сохраняется в ini. Смысл перезапуска dll в том чтобы добавлять новые позиции в это меню, а так же в новые окна. С внедрением тоже как-нибудь заморочусь))
  • Rouse_ © (01.02.13 18:28) [21]
    Тогда достаточно вот этого

    > Rouse_ ©   (01.02.13 15:56) [15]
  • Rouse_ © (01.02.13 18:30) [22]
    ЗЫ: то я бы остановился на перехвате вызова меню и лоадере, т.к. нет смысла мусорить во всех процессах.
    Подробнее можешь здесь глянуть (раз уж про отладчик читал): http://alexander-bagel.blogspot.ru/2013/01/intercept.html
  • Eraser © (01.02.13 19:23) [23]

    > Rouse_ ©   (01.02.13 18:30) [22]


    > т.к. нет смысла мусорить во всех процессах.

    для этого нужно размещать хук не в dll модуле, а самой программе. но тут появляется вопрос, а зачем вообще этот хук, когда речь о своем процесс.
  • Rouse_ © (01.02.13 19:40) [24]

    > Eraser ©   (01.02.13 19:23) [23]
    > для этого нужно размещать хук не в dll модуле, а самой программе

    Как я понял - проблема у автора с конкретным процессом, но не со своим. В этом случае, установка перехватчика непосредственно в тело работающего приложения, достаточно нетривиальная задача. Слишком хороший уровень должен быть для данной реализации. Гораздо проще разместить перехватчик в библиотеке, и инжектировать ее, чем разруливать проблемы с адресацией используемых АПИ во внедренном коде.
  • Rouse_ © (01.02.13 19:48) [25]

    > Eraser ©   (01.02.13 19:23) [23]

    Кстати, если ты прав и процесс свой, то тогда вообще готодить огорот с перехватом не имеет смысла, достаточно перекрыть OnPopup у меню в котором зачитать требуемые пункты меню, которые нужно добавить и накинуть их прямо в рантайме. И это с учетом что состав этих меню может меняться прямо в момент работы программы, а если нет, то вообще все делается на старте приложения.
 
Конференция "WinAPI" » Проблема с hook-ом на события мыши [D7]
Есть новые Нет новых   [134430   +4][b:0][p:0.002]