SteveSandersonMS / WebWindow

.NET Core library to open native OS windows containing web UI on Windows, Mac, and Linux. Experimental.
Apache License 2.0
1.99k stars 215 forks source link

Implement InvokeScript ==> IWebView2WebView supports ExecuteScript #64

Open ITAgnesmeyer opened 4 years ago

ITAgnesmeyer commented 4 years ago

Hi there, IWebView2WebView supports ExecuteScript. So it would be niche to implement this. I try it on Windows and it works fine.

WebWindow.Natvie:

//WebWindow.h
typedef void (*ScriptResponseCallback)(HRESULT hr,AutoString ideintifier, AutoString message);
void InvokeScript(AutoString caller,AutoString identifier, ScriptResponseCallback result);
//WebWindow.Windows.cpp
void WebWindow::InvokeScript(AutoString caller,AutoString identifier, 
    ScriptResponseCallback callback)
{

    this->_webviewWindow->ExecuteScript(caller, 
                Callback<IWebView2ExecuteScriptCompletedHandler>(
        [this,identifier,callback](HRESULT errorCode, 
                 LPCWSTR resultObjectAsJson) -> HRESULT {
            callback(errorCode,identifier,resultObjectAsJson);
            return S_OK;
        }).Get());

}
//Exports.cpp
EXPORTED void WebWindow_InvokeScript(WebWindow* instance, 
   AutoString scriptText, AutoString identifier,ScriptResponseCallback callback)
{
   return instance->InvokeScript(scriptText, identifier,callback);
}

DotNet - Side => WebWindow:

//Delegate
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void ScriptResponseCallback(uint hr, IntPtr identifier, IntPtr result);
//Declare
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)]
public static extern void WebWindow_InvokeScript(IntPtr instance, 
   string scriptText, string identifier, ScriptResponseCallback callback);
//Event
public event EventHandler<ScriptResultEventArgs> OnScriptInvoced;
//Implementation
public string InvokeScript(string scriptText)
{
   string identifier = Guid.NewGuid().ToString();
   NativeFunctions.WebWindow_InvokeScript(this._nativeWebWindow, 
       scriptText,identifier, (a,   b,c) =>
       {
          string id = Marshal.PtrToStringUni(b);
          string str = Marshal.PtrToStringUni(c);
          RaiseOnScriptInvoked(a,id, str);
        });

   return identifier;
 }
private void RaiseOnScriptInvoked(uint hr, string identifier,string resultValue)
{
   bool isError = hr != 0x0000;
    if (this.ResultList.ContainsKey(identifier))
    this.ResultList.Remove(identifier);
    this.ResultList.Add(identifier,new ScriptResult(identifier, resultValue, isError));
    if (OnScriptInvoced != null)
    {

      ScriptResultEventArgs args = new ScriptResultEventArgs(identifier,resultValue, isError);
            OnScriptInvoced.Invoke(this, args);
     }

}

//ScriptResultEventArgs.cs
public class ScriptResultEventArgs : EventArgs
{
    public string IdentiFier{get;set;}
    public string ResultMessage{get;}
    public bool IsError{get;}

    public ScriptResultEventArgs(string identifier,
       string resultMessage, bool isError)
    {
        this.IdentiFier = identifier;
        this.ResultMessage = resultMessage;
        this.IsError = isError;
    }
}

Client Side:

window.OnScriptInvoced += (snnder, e) =>
{
    if (e.IsError)
    {
        window.ShowMessage("error:" + e.IdentiFier, e.ResultMessage);
    }
    else
    {
        window.ShowMessage("Result:" + e.IdentiFier, e.ResultMessage);
    }
};

//Calling a script
string id = window.InvokeScript($"document.getElementById('{rpc.objId}').innerHTML='{rpc.param}'");

The InvokeScript function returns an ID that can be used to identify a return value. The only question is whether this also works on Mac and Linux. Unfortunately I don't have the possibility to test it. I also don't know if this function is available for Mac and Linux at all? So it would be good if one could do this.

Best regards