Как я могу предотвратить доставку события в графический интерфейс, пока мой код не завершится? - PullRequest
1 голос
/ 26 мая 2010

Я установил глобальную функцию подключения мыши следующим образом:

mouseEventHook = ::SetWindowsHookEx( WH_MOUSE_LL, mouseEventHookFn, thisModule, 0 );

Функция хука выглядит следующим образом:

RESULT CALLBACK mouseEventHookFn( int code, WPARAM wParam, LPARAM lParam )
{
    if ( code == HC_ACTION ) {
        PMSLLHOOKSTRUCT mi = (PMSLLHOOKSTRUCT)lParam;
        // .. do interesting stuff ..
    }
    return ::CallNextHookEx( mouseEventHook, code, wParam, lParam );
}

Теперь, моя проблема в том, что я не могу контролировать, сколько времени точно занимает часть «делай интересные вещи». В частности, это может занять больше времени, чем LowLevelHooksTimeout, определенный в реестре Windows. Это означает, что, по крайней мере в Windows XP, система больше не доставляет события мыши в мою функцию ловушки. Я бы хотел этого избежать, но в то же время мне нужно, чтобы часть «делай интересные вещи» произошла за до того, как целевой графический интерфейс получит событие.

Я пытался решить эту проблему, выполняя работу с «интересными вещами» в отдельном потоке, чтобы вышеприведенный mouseEventHookFn мог отправить сообщение в рабочий поток, а затем немедленно выполнить return 1; (что завершает функцию перехвата, но избегает передачи события в GUI). Идея заключалась в том, что рабочий поток после завершения выполняет сам вызов CallNextHookEx.

Однако это вызывает сбой внутри CallNextHookEx (на самом деле сбой происходит внутри внутренней функции с именем PhkNextValid. Я предполагаю, что небезопасно вызывать CallNextHookEx извне функции перехвата, это правда?

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

Ответы [ 3 ]

1 голос
/ 27 мая 2010

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

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

Итак, вы начинаете с написания перехвата dll, который при отправке сообщения вызывает SetWindowLong для HWND, чтобы заменить GWL_WINDOWPROC вашим новым оконным процессом.

В WindowProc вы можете обрабатывать сообщения сколько угодно.

1 голос
/ 27 мая 2010

предположим, что вызывать CallNextHookEx из-за пределов функции перехвата небезопасно, это правда?

Я верю, что это правда.

Поскольку существует ограниченное количество операций, которые вы можете получить с помощью низкоуровневого хука мыши, вы можете просто поместить их в очередь для повторного размещения в окне получения после завершения длительной операции. Если вы поместите свою долгосрочную работу в другой поток, вы не «заблокируете» пользовательский интерфейс, а просто «съедите» или «отложите» действия пользователя. Верните 1, чтобы предотвратить появление других хуков. Используйте логический флаг, чтобы указать, собираете ли вы события (потому что ваша длительная операция еще не запущена) или повторно публикуете их (и, следовательно, не должны их перехватывать).

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

1 голос
/ 26 мая 2010

Нет исправлений, вам придется делать свой код быстрее. Эти хуки потенциально очень пагубны для отзывчивости пользовательского интерфейса, Windows следит за тем, чтобы в подвал попадало нехорошее поведение. Даже если бы тайм-аут был настраиваемым, он никогда не был бы задокументирован. Во-первых, это лишило бы цели тайм-аут.

...