MicrosoftEdge / WebView2Feedback

Feedback and discussions about Microsoft Edge WebView2
https://aka.ms/webview2
444 stars 53 forks source link

WebView2 corespondent for CefSharp IJavascriptCallback #2632

Open lupusilviu opened 2 years ago

lupusilviu commented 2 years ago

I am using Microsoft.Web.WebView2 version 1.0.1185.39.

I have an object in C# that I use AddHostObjectToScript("MyObject", new MyObject()); to add it to the browser.

This was one of the methods from MyObject.cs in C#

 public string ExecuteTask(bool full, IJavascriptCallback callback= null)
 {
   Task.Run(() =>
            {
                    ( ... do stuff ...)
                    callback.ExecuteAsync(result);
            });
 return "";
 }

=================================== And this was the javascript code:

var objectCS = window["MyObject"];
            return new Promise((resolve) => {
                objectCS .ExecuteTask(full, (response) => {
                    var responseParsed = JSON.parse(response);
                    resolve(responseParsed );
              });
});

===================================

My problem is that I do not know for WebView2, what value should the callback parameter from C# have. Any idea is very much appreciated

AB#40833899

lupusilviu commented 2 years ago

So, I found the solution to this problem in a thread in here: https://github.com/MicrosoftEdge/WebView2Feedback/issues/75#issuecomment-711443711

With some changes done to the original code, I was able to do the callback and it works. It is a lot of code, and hopefully, a cleaner solution will be implemented in the future.

david-risney commented 2 years ago

Yes, thanks for the report. We will look into supporting this properly.

celery94 commented 1 year ago

Base on the solution of #75 I found another simple solution: C# code:

DispatchHelper.Invoke(callback, result);

    public class DispatchHelper
    {
        private const int DISPID_UNKNOWN = unchecked((int)0xFFFFFFFF);
        private const int LOCALE_USER_DEFAULT = 0x0400;
        private Guid IID_NULL = Guid.Empty;

        public void Invoke(object callback, string data)
        {
            IDispatch disp = callback as IDispatch;

            // Create the DISPPARAMS struct
            var pDispParams = default(System.Runtime.InteropServices.ComTypes.DISPPARAMS);
            // Set the number of unnamed parameters
            pDispParams.cArgs = 1;

            // Marshal a value to a variant
            var result = JsonConvert.SerializeObject(data);

            IntPtr pVariant = Marshal.AllocCoTaskMem(16); // Default VARIANT size
            Marshal.GetNativeVariantForObject(result, pVariant);

            // Set the unnamed parameter arguments
            pDispParams.rgvarg = pVariant;

            disp.Invoke(DISPID_UNKNOWN,
                IID_NULL,
                LOCALE_USER_DEFAULT,
                System.Runtime.InteropServices.ComTypes.INVOKEKIND.INVOKE_FUNC,
                ref pDispParams,
                IntPtr.Zero,
                IntPtr.Zero,
                IntPtr.Zero);
        }
    }

    [SuppressUnmanagedCodeSecurity]
    [ComImport]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    [Guid("00020400-0000-0000-C000-000000000046")]
    internal interface IDispatch
    {
        [SecurityCritical]
        void GetTypeInfoCount(out uint pctinfo);

        [SecurityCritical]
        void GetTypeInfo(uint iTInfo, int lcid, out IntPtr info);

        [SecurityCritical]
        void GetIDsOfNames(
            ref Guid iid,
            [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr, SizeParamIndex = 2)]
            string[] names,
            uint cNames,
            int lcid,
            [Out] [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.I4, SizeParamIndex = 2)]
            int[] rgDispId);

        [SecurityCritical]
        void Invoke(
            int dispIdMember,
            ref Guid riid,
            int lcid,
            INVOKEKIND wFlags,
            ref DISPPARAMS pDispParams,
            IntPtr pvarResult,
            IntPtr pExcepInfo,
            IntPtr puArgErr);
    }
PaulBol commented 1 year ago

@celery94 - Thanks for the excellent suggestion!

I would only like to add Marshal.FreeCoTaskMem(pVariant); after disp.Invoke to avoid a memory leak.

MhmdTabikh commented 8 months ago

@celery94 how would the call from JS look like ? I want to use it in angular using promises. It would be appreciated if you can provide a running example