private void CreateFunction(CefV8Value parent, CefV8Handler method, String name) { // Create the {name} function. CefV8Value value = CefV8Value.CreateFunction(name, method); // Add the {name} function to the {parent} object. parent.SetValue(name, value, CefV8PropertyAttribute.None); }
/// <summary> /// 通过反射机制 注册c#函数到JS /// </summary> public void RegisterJs() { JsEvent js = new JsEvent(mainView); Cef = new CefJsV8Handler(js); string javascriptCode = CefJavaScriptEx.CreateJsCodeByObject(js, "Cef"); CefRuntime.RegisterExtension("Cef", javascriptCode, Cef); }
/// <summary> /// 创建JavaScript方法 /// </summary> /// <param name="handler">处理程序</param> /// <param name="javascriptObject">经过V8 JS引擎处理后的对象</param> /// <param name="methodNames">方法键值对集合</param> public static void CreateJavascriptMethods(CefV8Handler handler, CefV8Value javascriptWrapper, IList <String> methodNames) { var unmanagedWrapper = (UnmanagedWrapper)(javascriptWrapper.GetUserData()); foreach (string methodName in methodNames) { string jsMethodName = LowercaseFirst(methodName); //unmanagedWrapper.AddMethodMapping(methodName, jsMethodName); javascriptWrapper.SetValue(jsMethodName, CefV8Value.CreateFunction(jsMethodName, handler), CefV8PropertyAttribute.None); } }
private void RegisterAsyncFunction(CefV8Value jsObject, string functionName, CefV8Handler handler) { jsObject.SetValue(functionName, CefV8Value.CreateFunction(functionName, handler)); }
static CefWin() { string exefile = CurrentProcess.MainModule.FileName; ApplicationIcon = System.Drawing.Icon.ExtractAssociatedIcon(exefile); SearchLibCefRootFolderList.Add(Path.GetDirectoryName(exefile)); SearchLibCefRootFolderList.Add(Environment.CurrentDirectory); // * * single-process is not recommanded by chromium team , If you get any strange issue , try removing this option: // * * see https://peter.sh/experiments/chromium-command-line-switches/ for more // * * ERROR msg in https://github.com/chromium/chromium/blob/bd61bd83c9ebcfdb162a447e4a01637d259ea358/chrome/browser/net/system_network_context_manager.cc CefAdditionArguments.Add("--single-process"); //use single process , memory usage is 170MB , otherwise 340MB CefAdditionArguments.Add("--winhttp-proxy-resolver"); CefAdditionArguments.Add("--no-proxy-server"); //https://code.google.com/archive/p/chromiumembedded/issues/81 CefAdditionArguments.Add("--disable-gpu-shader-disk-cache"); CefAdditionArguments.Add("--allow-running-insecure-content"); CefAdditionArguments.Add("--enable-speech-input"); CefAdditionArguments.Add("--enable-media-stream"); //TODO: ??? must work with --enable-usermedia-screen-capturing CefAdditionArguments.Add("--enable-usermedia-screen-capturing"); CefAdditionArguments.Add("--enable-aggressive-domstorage-flushing"); //save data more quickly // more tested : // --proxy-server=http://127.0.0.1:8080 new WF.Panel().Handle.ToString(); //Activate WindowsFormsSynchronizationContext MainThreadSynchronizationContext = SynchronizationContext.Current; Console.CancelKeyPress += delegate { //CTRL+C WriteDebugLine("Console.CancelKeyPress"); ApplicationCTS.Cancel(); }; WF.Application.ApplicationExit += delegate { _winformsExitFired = true; WriteDebugLine("Warning:do not call Application.Exit()"); ApplicationCTS.Cancel(); }; LibCefInterop.App.RenderProcessHandler.WebKitInitialized += delegate { CefV8Handler handler = new CefV8Handler(); AddStaticObject(handler); ConcurrentDictionary <string, Assembly> dllmap = new ConcurrentDictionary <string, Assembly>(); Assembly[] existAsms = null; object HandleExecute(CefV8Handler self, string name, CefV8Value[] args) { if (SettingsTrustedWebsiteHosts == null) { throw new Exception("TrustedWebsiteHosts is not configured"); } //TODO: v8c get current , get browser CefV8Context ctx = CefV8Context.GetCurrent(); if (ctx == null) { throw new Exception("no current v8context"); } string url = ctx.GetFrame().Url; Uri uri = new Uri(url); if (!SettingsTrustedWebsiteHosts.Contains(uri.Host)) { if (!SettingsTrustedWebsiteHosts.Contains(uri.Host + ":" + uri.Port)) { throw (new Exception(uri.Host + ":" + uri.Port + " is not trusted in TrustedWebsiteHosts")); } } if (existAsms == null) { existAsms = AppDomain.CurrentDomain.GetAssemblies(); } if (name == "_compileAssembly") { string dllname = args[0].GetStringValue(); string code = args[1].GetStringValue(); WriteDebugLine("_compileAssembly:" + dllname + ":" + code.Length); if (!SettingAllowCompileCSharpCode) { throw new Exception("AllowCompileCSharpCode is not setted to true"); } if (dllname.IndexOfAny(System.IO.Path.GetInvalidFileNameChars()) != -1) { throw new Exception("Invalid dllname."); } dllmap[dllname] = CompileCode(existAsms, dllname, code); } else if (name == "_installAssembly") { string dllname = args[0].GetStringValue(); string base64 = args[1].GetStringValue(); WriteDebugLine("_installAssembly:" + dllname + ":" + base64.Length); if (SettingTrustedPublicKeyTokens == null) { throw new Exception("CefWin.PublicKeyTokenList is not configured"); } byte[] data = Convert.FromBase64String(base64); Assembly asm = AppDomain.CurrentDomain.Load(data); byte[] tokendata = asm.GetName().GetPublicKeyToken(); if (tokendata == null) { throw new Exception("the dll " + dllname + " must signed for a PublicKeyToken and register it into CefWin.PublicKeyTokenList "); } string token = BitConverter.ToString(tokendata).Replace("-", "").ToLower(); if (!SettingTrustedPublicKeyTokens.Contains(token)) { throw new Exception("Invalid dll , " + token + " is not in CefWin.PublicKeyTokenList"); } WriteDebugLine("new assembly installed : " + asm.FullName); dllmap[dllname] = asm; } else if (name == "_executeAssembly") { string dllname = args[0].GetStringValue(); string clsname = args[1].GetStringValue(); string method = args[2].GetStringValue(); WriteDebugLine("_executeAssembly:" + dllname + ":" + clsname + ":" + method); object[] methodargs = (object[])args[3].ToObject() ?? Array.Empty <object>(); Assembly asm; if (!dllmap.TryGetValue(dllname, out asm)) { throw new Exception(dllname + " not exists"); } Type type = asm.GetType(clsname); WriteDebugLine("Type : " + type.AssemblyQualifiedName); var members = type.GetMember(method); if (members.Length == 0) { throw new Exception("Method " + method + " not exists in " + type.AssemblyQualifiedName); } if (members.Length != 1) { throw new Exception("Too many member " + method + " in " + type.AssemblyQualifiedName); } var minfo = members[0] as MethodInfo; if (minfo == null) { throw new Exception("Member " + method + " is not a method in " + type.AssemblyQualifiedName); } if (!minfo.IsStatic) { throw new Exception("Method " + method + " is not static in " + type.AssemblyQualifiedName); } if (!minfo.IsPublic) { throw new Exception("Method " + method + " is not public in " + type.AssemblyQualifiedName); } object result = null; InvokeInAppThread(delegate { result = minfo.Invoke(null, new object[] { methodargs }); }); } else { throw new Exception("Invalid func " + name); } return(null); } handler.Execute = HandleExecute; //TODO: shall use async return Promise ... now show dialog will block the JS executing, //TODO: Support multi-process : int r = CefV8Context.CefRegisterExtension("cefwin_extention", @" var CefWin={}; (function(){ var dllmap={}; CefWin.compileAssembly=function(dllname,code) { var dllitem=dllmap[dllname]; if(dllitem!=null&&dllitem.code==code) { console.log(dllname+' already compiled'); return; } console.log(dllname,code.length); dllitem={code:code}; native function _compileAssembly(); _compileAssembly(dllname, code); dllmap[dllname]=dllitem; } CefWin.installAssembly=function(dllname, base64) { var dllitem=dllmap[dllname]; if(dllitem!=null&&dllitem.base64==base64) { console.log(dllname+' already installed'); return; } console.log(dllname,base64.length); dllitem={base64:base64}; native function _installAssembly(); _installAssembly(dllname, base64); dllmap[dllname]=dllitem; } CefWin.executeAssembly=async function _ExecuteAssembly(dllname, clsname, method, args) { var dllitem=dllmap[dllname]; if(!dllitem)throw new Error(dllname+' not installed'); native function _executeAssembly(); console.log(dllname,clsname,method); _executeAssembly(dllname,clsname,method,args); return 'OK'+new Date().getTime(); } })(); ", handler); WriteDebugLine("CefRegisterExtension:" + r); }; //TODO: implement the Notification API //LibCefInterop.App.RenderProcessHandler.WebKitInitialized += delegate // { // int r = CefV8Context.CefRegisterExtension("CefWin1", "function cefwin(){alert(123);}"); // WriteDebugLine("CefRegisterExtension:" + r); // }; //LibCefInterop.App.RenderProcessHandler.ContextCreated += (rph, browser, frame, v8c) => // { // WriteDebugLine("OnContextCreated id:" + browser.Identifier); // WriteDebugLine("send msgfromrenderer"); // frame.SendProcessMessage(cef_process_id_t.PID_BROWSER, "msgfromrenderer"); // try // { // v8c.Eval("console.log('hello...')"); // WriteDebugLine("Eval DONE"); // } // catch (Exception x) // { // WriteDebugLine(x); // } // }; }
//CsNativeHandlerSwitchTableCodeGen::GenerateHandleNativeReq public static void HandleNativeReq(object inst, int met_id, IntPtr args) { switch ((met_id >> 16)) { case CefAccessibilityHandler._typeNAME: CefAccessibilityHandler.HandleNativeReq(inst as CefAccessibilityHandler.I0, inst as CefAccessibilityHandler.I1, met_id, args); break; case CefBrowserProcessHandler._typeNAME: CefBrowserProcessHandler.HandleNativeReq(inst as CefBrowserProcessHandler.I0, inst as CefBrowserProcessHandler.I1, met_id, args); break; case CefContextMenuHandler._typeNAME: CefContextMenuHandler.HandleNativeReq(inst as CefContextMenuHandler.I0, inst as CefContextMenuHandler.I1, met_id, args); break; case CefDialogHandler._typeNAME: CefDialogHandler.HandleNativeReq(inst as CefDialogHandler.I0, inst as CefDialogHandler.I1, met_id, args); break; case CefDisplayHandler._typeNAME: CefDisplayHandler.HandleNativeReq(inst as CefDisplayHandler.I0, inst as CefDisplayHandler.I1, met_id, args); break; case CefDownloadHandler._typeNAME: CefDownloadHandler.HandleNativeReq(inst as CefDownloadHandler.I0, inst as CefDownloadHandler.I1, met_id, args); break; case CefDragHandler._typeNAME: CefDragHandler.HandleNativeReq(inst as CefDragHandler.I0, inst as CefDragHandler.I1, met_id, args); break; case CefFindHandler._typeNAME: CefFindHandler.HandleNativeReq(inst as CefFindHandler.I0, inst as CefFindHandler.I1, met_id, args); break; case CefFocusHandler._typeNAME: CefFocusHandler.HandleNativeReq(inst as CefFocusHandler.I0, inst as CefFocusHandler.I1, met_id, args); break; case CefGeolocationHandler._typeNAME: CefGeolocationHandler.HandleNativeReq(inst as CefGeolocationHandler.I0, inst as CefGeolocationHandler.I1, met_id, args); break; case CefJSDialogHandler._typeNAME: CefJSDialogHandler.HandleNativeReq(inst as CefJSDialogHandler.I0, inst as CefJSDialogHandler.I1, met_id, args); break; case CefKeyboardHandler._typeNAME: CefKeyboardHandler.HandleNativeReq(inst as CefKeyboardHandler.I0, inst as CefKeyboardHandler.I1, met_id, args); break; case CefLifeSpanHandler._typeNAME: CefLifeSpanHandler.HandleNativeReq(inst as CefLifeSpanHandler.I0, inst as CefLifeSpanHandler.I1, met_id, args); break; case CefLoadHandler._typeNAME: CefLoadHandler.HandleNativeReq(inst as CefLoadHandler.I0, inst as CefLoadHandler.I1, met_id, args); break; case CefPrintHandler._typeNAME: CefPrintHandler.HandleNativeReq(inst as CefPrintHandler.I0, inst as CefPrintHandler.I1, met_id, args); break; case CefRenderHandler._typeNAME: CefRenderHandler.HandleNativeReq(inst as CefRenderHandler.I0, inst as CefRenderHandler.I1, met_id, args); break; case CefRenderProcessHandler._typeNAME: CefRenderProcessHandler.HandleNativeReq(inst as CefRenderProcessHandler.I0, inst as CefRenderProcessHandler.I1, met_id, args); break; case CefRequestContextHandler._typeNAME: CefRequestContextHandler.HandleNativeReq(inst as CefRequestContextHandler.I0, inst as CefRequestContextHandler.I1, met_id, args); break; case CefRequestHandler._typeNAME: CefRequestHandler.HandleNativeReq(inst as CefRequestHandler.I0, inst as CefRequestHandler.I1, met_id, args); break; case CefResourceBundleHandler._typeNAME: CefResourceBundleHandler.HandleNativeReq(inst as CefResourceBundleHandler.I0, inst as CefResourceBundleHandler.I1, met_id, args); break; case CefResourceHandler._typeNAME: CefResourceHandler.HandleNativeReq(inst as CefResourceHandler.I0, inst as CefResourceHandler.I1, met_id, args); break; case CefReadHandler._typeNAME: CefReadHandler.HandleNativeReq(inst as CefReadHandler.I0, inst as CefReadHandler.I1, met_id, args); break; case CefWriteHandler._typeNAME: CefWriteHandler.HandleNativeReq(inst as CefWriteHandler.I0, inst as CefWriteHandler.I1, met_id, args); break; case CefV8Handler._typeNAME: CefV8Handler.HandleNativeReq(inst as CefV8Handler.I0, inst as CefV8Handler.I1, met_id, args); break; } }
public void OnContextCreated(CefRenderProcessHandler.OnContextCreatedArgs args) { //----------------------- //this is TEST CODE //----------------------- return; //eg "<html><head><script>function docload(){ console.log(test001()); console.log(test_myobj.myprop);console.log(test_myobj[12345]);}</script><body onload=\"docload()\"><h1>hello!</h1></body></html>" dbugRenderProcessLog.WriteLine("context_created1"); CefV8Context context = args.context(); dbugRenderProcessLog.WriteLine("context_cx1"); //global => window object CefV8Value cefV8Global = context.GetGlobal(); // Auto.CefV8Handler funcHandler = new Auto.CefV8Handler(Cef3Binder.MyCefJs_New_V8Handler(Test002)); CefV8Value func = Auto.CefV8Value.CreateFunction("test001", funcHandler); cefV8Global.SetValue("test001", func, cef_v8_propertyattribute_t.V8_PROPERTY_ATTRIBUTE_READONLY); //------- dbugRenderProcessLog.WriteLine("context_cx2"); dbugRenderProcessLog.WriteLine("context_cx3"); CefV8Accessor accessor = CefV8Accessor.New((id, argPtr) => { //-------------------------- //this shows the unsafe and low-level interface to native. //you can use a 'higher' level wrapper. //-------------------------- //from https://github.com/v8/v8/wiki/Embedder%27s-Guide //accessor callbacks are invoked when a specific object property is accessed by a script //Accessors //An accessor is a C++callback that calculates and returns a value when an object property is accessed by a JavaScript script. //Accessors are configured through an object template, using the SetAccessor method. //This method takes the name of the property with which it is associated and two callbacks to run when a script attempts to read or write the property. CefV8Accessor.GetArgs arg = new CefV8Accessor.GetArgs(argPtr); arg.retval(CefV8Value.CreateString("hello! from accessor").nativePtr); arg.myext_setRetValue(true);//finish the accessor! }); CefV8Interceptor intercepter = CefV8Interceptor.New((id, argPtr) => { //from https://github.com/v8/v8/wiki/Embedder%27s-Guide //interceptor callbacks are invoked when any object property is accessed by a script Accessors and interceptors are discussed later in this document. // // //Interceptors // You can also specify a callback for whenever a script accesses any object property. These are called interceptors. For efficiency, there are two types of interceptors: // named property interceptors - called when accessing properties with string names. An example of this, in a browser environment, is document.theFormName.elementName. // indexed property interceptors - called when accessing indexed properties. An example of this, in a browser environment, is document.forms.elements[0]. //-------------------------- //this shows the unsafe and low-level interface to native. //you can use a 'higher' level wrapper. //-------------------------- if ((id >> 16) != CefV8Interceptor._typeNAME) { return; } //-------------------------- int met_id = id & 0xffff; switch (met_id) { case CefV8Interceptor.MyCefV8Interceptor_Get_1: { //by name CefV8Interceptor.get_bynameArgs arg = new CefV8Interceptor.get_bynameArgs(argPtr); arg.retval(CefV8Value.CreateString("hello! from intercepter" + arg.name()).nativePtr); } break; case CefV8Interceptor.MyCefV8Interceptor_Get_2: { //by indexed property } break; } }); //-------- //The difference between accessors and interceptors is that interceptors handle all properties, //while accessors are associated with one specific property. //-------- // CefV8Accessor empty = new CefV8Accessor(); CefV8Interceptor empty_interceptor = new CefV8Interceptor(); CefV8Value cef_object = CefV8Value.CreateObject(accessor, empty_interceptor); //if you want to use accessor, your must set it with SetValue() like this cef_object.SetValue("myprop", cef_v8_accesscontrol_t.V8_ACCESS_CONTROL_DEFAULT, cef_v8_propertyattribute_t.V8_PROPERTY_ATTRIBUTE_NONE); // //set to global object cefV8Global.SetValue("test_myobj", cef_object, cef_v8_propertyattribute_t.V8_PROPERTY_ATTRIBUTE_READONLY); //------ //-------------- //------- //TEST 1: raw, low level interface //------- IntPtr ret = IntPtr.Zero; IntPtr exception = IntPtr.Zero; //string jscode = "(function(){ return function (){return 1.25;}})()"; string jscode = "(function(){ return function (){ console.log('hello-eval1'); return 1.25;}})()"; if (context.Eval(jscode, "", 1, ref ret, ref exception)) { dbugRenderProcessLog.WriteLine("eval success"); } else { dbugRenderProcessLog.WriteLine("eval fail"); } // using (CefV8Value cefv8_ret = new CefV8Value(ret)) using (CefV8Value cefv8_excep = new CefV8Value(exception)) { if (cefv8_ret.IsFunction()) { CefV8Value obj1 = new CefV8Value(); //empty CefV8ValueList args1 = CefV8ValueList.NewList(); CefV8Value innerFuncResult = cefv8_ret.ExecuteFunction(obj1, args1); Cef3Binder.MyCefDeletePtr(args1.nativePtr); double innerDouble = innerFuncResult.GetDoubleValue(); } else { double v8ret_double = cefv8_ret.GetDoubleValue(); } } //low-level example, TODO: make this to O-O style //------ var myfunc2 = MyJsFunc <double> .Create(context, "function(a00){ console.log(a00);}"); myfunc2.Invoke(101); //------ var myfunc3 = MyJsFunc <string> .Create(context, "function(a00){ console.log(a00);}"); myfunc3.Invoke("HELLOO!"); //------ // var myfunc4 = MyJsFunc <double, string> .Create(context, "function(a00,a02){ console.log(a00); console.log(a02);}"); myfunc4.Invoke(101, "hello_myfunc4"); //------ var myfunc5 = MyJsFunc <string, string> .Create(context, "function(a00,a02){ console.log(a00); console.log(a02);}"); myfunc5.Invoke("HELLOO!", "hello_myfunc5"); //------ var myfunc6 = MyJsFunc.Create(context, "function(){ document.title='hello1'; document.write('0'); return document; }"); var doc = myfunc6.Invoke(); CefV8Value docTitle = doc.GetValue("title"); string docTitleAsString = docTitle.GetStringValue(); CefV8Value docBody = doc.GetValue("body"); if (!docBody.IsNull()) { //get innerHTML property CefV8Value innerHtmlProp = docBody.GetValue("innerHTML"); if (innerHtmlProp.IsString()) { } //set innerHTML property docBody.SetValue("innerHTML", CefV8Value.CreateString("A_Z"), cef_v8_propertyattribute_t.V8_PROPERTY_ATTRIBUTE_NONE); } CefV8Value docWrite = doc.GetValue("write"); if (docWrite.IsFunction()) //try getting 'write' method of the document object { CefV8ValueList writeArgs = CefV8ValueList.NewList(); writeArgs.AddElement(CefV8Value.CreateString("Hello_FROM_WRITE")); docWrite.ExecuteFunction(doc, writeArgs); Cef3Binder.MyCefDeletePtr(writeArgs.nativePtr); } //------ //if we write() all //we need to get doc again doc = myfunc6.Invoke(); cefV8Global = context.GetGlobal(); //low-level example, TODO: make this to O-O style CefV8Value cefGlobal_addEventListener = cefV8Global.GetValue("addEventListener"); if (cefGlobal_addEventListener.IsFunction()) { MyCefCallback cefWindowOnLoad = (id, argsPtr) => { //arg as mouse event args CefV8Handler.ExecuteArgs args2 = new CefV8Handler.ExecuteArgs(argsPtr); CefV8ValueList argumentList = args2.arguments(); int argCount = argumentList.GetListCount(); }; _cefCallbackKeeper.Add(cefWindowOnLoad); var v8Handler = new CefV8Handler(Cef3Binder.MyCefJs_New_V8Handler(cefWindowOnLoad)); CefV8ValueList handleArgs = CefV8ValueList.NewList(); //"load" handleArgs.AddElement(CefV8Value.CreateString("load")); CefV8Value v8Loadhandler = CefV8Value.CreateFunction("mydocload", v8Handler); //"eventHandler" handleArgs.AddElement(v8Loadhandler); cefGlobal_addEventListener.ExecuteFunction(cefV8Global, handleArgs); Cef3Binder.MyCefDeletePtr(handleArgs.nativePtr); } //------ //low-level example, TODO: make this to O-O style CefV8Value doc_addEventListener = doc.GetValue("addEventListener"); if (doc_addEventListener.IsFunction()) { MyCefCallback mouseDownCallback = (id, argsPtr) => { //arg as mouse event args CefV8Handler.ExecuteArgs args2 = new CefV8Handler.ExecuteArgs(argsPtr); CefV8ValueList argumentList = args2.arguments(); int argCount = argumentList.GetListCount(); CefV8Value v8arg = argumentList.GetElement(0); //get button propery CefV8Value v8button = v8arg.GetValue("button"); if (v8button.IsInt()) { int button = v8button.GetIntValue(); } }; _cefCallbackKeeper.Add(mouseDownCallback); var v8Handler = new CefV8Handler(Cef3Binder.MyCefJs_New_V8Handler(mouseDownCallback)); CefV8ValueList handleArgs = CefV8ValueList.NewList(); //"load" handleArgs.AddElement(CefV8Value.CreateString("mousedown")); CefV8Value v8Loadhandler = CefV8Value.CreateFunction("mycallback", v8Handler); //"eventHandler" handleArgs.AddElement(v8Loadhandler); cefGlobal_addEventListener.ExecuteFunction(doc, handleArgs); Cef3Binder.MyCefDeletePtr(handleArgs.nativePtr); } dbugRenderProcessLog.WriteLine("context_created-pass"); }