How can I use await in this function?

109 Views Asked by At

How can I make HookFuncAsync an async function without causing issues?

private delegate IntPtr MouseHookHandler(int nCode, IntPtr wParam, IntPtr lParam);
private static MouseHookHandler hookHandler;


public static void Install() {
    hookHandler = HookFuncAsync;
    hookID = SetHook(hookHandler);
}


private static IntPtr SetHook(MouseHookHandler proc) {
    using (ProcessModule module = Process.GetCurrentProcess().MainModule)
         return SetWindowsHookEx(WH_MOUSE_LL, proc, WinAPI.GetModuleHandle(module.ModuleName), 0);
}


private static IntPtr HookFuncAsync(int nCode, IntPtr wParam, IntPtr lParam) {
    if (nCode >= 0) {
         if (MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam)
               await Task.Run(() => doSomething()); // <-- How can I use await here?
    ...
}

[DllImport("user32", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook, MouseHookHandler lpfn, IntPtr hMod, uint dwThreadId);

Tried setting the MouseHookHandler and HookFuncAsync to Task< IntPtr >, compiled fine but crashes on the SetWindowsHookEx because it requires IntPtr not Task< IntPtr >.

1

There are 1 best solutions below

4
Stephen Cleary On

Is there no way for me to change the HookFuncAsync to Task and then in the Install() some how alter it so that it can be called?

No.

Windows hook procedures have similar constraints to window procedures (WNDPROC). Specifically, they cannot be async. They run as part of the user interface, so they must return synchronously and within a very short amount of time.

So, it is not possible to make it async, and it is not appropriate to block (Wait).

Instead, you can treat this more like an event handler. Specifically, make an intermediate async void handler:

private static IntPtr HookFuncAsync(int nCode, IntPtr wParam, IntPtr lParam) {
    if (nCode >= 0) {
        if (MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam)
            OnLeftButtonDown();
    ...
}

private static async void OnLeftButtonDown() => await doSomething();