Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WebView2 corespondent for CefSharp IJavascriptCallback #2632

Open
lupusilviu opened this issue Jul 28, 2022 · 5 comments
Open

WebView2 corespondent for CefSharp IJavascriptCallback #2632

lupusilviu opened this issue Jul 28, 2022 · 5 comments
Assignees
Labels
bug Something isn't working tracked We are tracking this work internally.

Comments

@lupusilviu
Copy link

lupusilviu commented Jul 28, 2022

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
Copy link
Author

So, I found the solution to this problem in a thread in here:
#75 (comment)

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 david-risney added tracked We are tracking this work internally. bug Something isn't working labels Aug 8, 2022
@david-risney
Copy link
Contributor

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

@celery94
Copy link

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
Copy link

PaulBol commented Sep 14, 2023

@celery94 - Thanks for the excellent suggestion!

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

@MhmdTabikh
Copy link

@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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working tracked We are tracking this work internally.
Projects
None yet
Development

No branches or pull requests

6 participants