Search code examples
c#async-awaitvstowebview2

Issue with async code when using WebView2 control inside VSTO Outlook plugin


I want to use the latest Microsoft WebView2 control (Chromium) on a VSTO plugin for Outlook. I have the trouble with wiring together async interface of WebView2 with VSTO Outlook.Inspector and Outlook.ItemEvents_10_Event, like Send or Close.

I want to execute some JS script on WebView2 on these events by calling ExecuteScriptAsync from WebView2 control.

The trouble is that for instance Send event is declared as void ItemEvents_10_SendEventHandler(ref bool Cancel) The problem is with ref variable that it cannot be used for async.

I need to wrap this async code into sync to determine the result for ref Cancel, but I have no idea for it. I'm ending up with deadlock or the error from WebView2 control CoreWebView2 can only be accessed from the UI thread.

The setup is VS2019, Outlook PIA 15 and WebView2 1.0.1020.30


Solution

  • In your event handler, run Windows message loop while waiting for the async method to return

            MSG msg;
            while (PeekMessage(out msg, IntPtr.Zero, 0, 0, 1/*PM_REMOVE*/))
            {
    
                TranslateMessage(ref msg);
                DispatchMessage(ref msg);
                if (OnlyOnce) break;
            }
    

    Win API functions are defined below:

    [StructLayout(LayoutKind.Sequential)]
            public struct POINT
            {
                public int X;
                public int Y;
            }
    
            [StructLayout(LayoutKind.Sequential)]
            public struct MSG
            {
                public IntPtr hwnd;
                public uint message;
                public UIntPtr wParam;
                public IntPtr lParam;
                public int time;
                public POINT pt;
                public int lPrivate;
            }
            [DllImport("user32.dll")]
            static extern sbyte GetMessage(out MSG lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax);
            [DllImport("user32.dll")]
            static extern bool TranslateMessage([In] ref MSG lpMsg);
            [DllImport("user32.dll")]
            static extern IntPtr DispatchMessage([In] ref MSG lpmsg);
            [DllImport("user32.dll")]
            [return: MarshalAs(UnmanagedType.Bool)]
            static extern bool PeekMessage(out MSG lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax, uint wRemoveMsg);