1. hg clone代碼回來后,還要下載對應的cef dll . 從http://xilium.bitbucket.org/cefglue/ 選擇對應的.
然后把dll和resource目錄里的內容都考到debug目錄里才能運行.
2.不能使用 Enable the Visual Studio hosting process 來運行. 因為還會啟動2個進程. 這兩個進程是相同的exe只是命令行不同, 如果使用了 hosting process ,那么就不能啟動另外兩個進程.
調試的時候把所有的項目類型從framework 2.0 3.5 統一到4.0 調試斷點才管用.
由於chrome是多進程運行, 有時候分不清楚代碼是在哪個進程中運行, 所以斷點很難下.
建議用Windbg 打開exe 並且 Debug child processes also ,來調試. 代碼里用Console.WriteLine message的形式來看是否執行到.
3. Js 於Clr 交互:
可以為window注冊一個external:
1 private ClrObjectAv8Handler m_extantHandler =new JavaScriptExtMethod(); 2 protected override void OnContextCreated(CefBrowser browser, CefFrame frame, CefV8Context context) 3 { 4 var global = context.GetGlobal(); 5 6 var extent = CefV8Value.CreateObject(null); 7 8 global.SetValue("external", extent, CefV8PropertyAttribute.None); 9 AddMethodToJSObject(this.m_extantHandler, extent); 10 } 11 //用反射的把所有公共方法注冊到js object 12 public static void AddMethodToJSObject(CefV8Handler hendlerObj, CefV8Value extent) 13 { 14 Type t = hendlerObj.GetType(); 15 var functions = t.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly); 16 17 foreach (var m in functions) 18 { 19 string funName =m.Name; 20 21 extent.SetValue(funName, CefV8Value.CreateFunction(m.Name, hendlerObj), CefV8PropertyAttribute.None); 22 23 } 24 25 }
JavaScriptExtMethod 繼承CefV8Handler 重載方法Execute.
1 protected override bool Execute(string name, CefV8Value obj, CefV8Value[] arguments, out CefV8Value returnValue, out string exception) 2 { 3 4 exception = null; 5 try 6 { 7 List<object> paras = V8ValueClrMap.ConvertToClrParameters(arguments); 8 Type t = this.GetType(); 9 10 var function = t.GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.InvokeMethod | 11 BindingFlags.IgnoreCase | BindingFlags.DeclaredOnly); 12 if (function != null) 13 { 14 var objRst = function.Invoke(this, paras.Count == 0 ? null : paras.ToArray()); 15 if (objRst is CefV8Handler) 16 { 17 returnValue = CefV8Value.CreateObject(null); 18 AddMethodToJSObject(objRst as CefV8Handler, returnValue); 19 } 20 else 21 { 22 23 returnValue = V8ValueClrMap.ConvertToV8Value(objRst); 24 } 25 } 26 else 27 { 28 exception = "Method no find:"+name; 29 returnValue = CefV8Value.CreateString(""); 30 var message3 = CefProcessMessage.Create("Exception"); 31 message3.Arguments.SetString(0, exception); 32 var success2 = Browser.SendProcessMessage(CefProcessId.Browser, message3); 33 34 return true; 35 } 36 return true; 37 } 38 catch (Exception ee) 39 { 40 returnValue = CefV8Value.CreateString(""); 41 exception = ee.Message; 42 43 returnValue = CefV8Value.CreateString(""); 44 var message3 = CefProcessMessage.Create("Exception"); 45 message3.Arguments.SetString(0, ee.ToString()); 46 var success2 = Browser.SendProcessMessage(CefProcessId.Browser, message3); 47 48 return true; 49 } 50 51 }
再實現一個V8Value與Clr的對應.
1 public class V8ValueClrMap 2 { 3 public static List<object> ConvertToClrParameters(CefV8Value[] arguments) 4 { 5 List<object> rtn = new List<object>(); 6 if (arguments == null || arguments.Length == 0) 7 { 8 return rtn; 9 } 10 foreach (var v in arguments) 11 { 12 rtn.Add(GetClrValue(v)); 13 } 14 return rtn; 15 } 16 public static object GetClrValue(CefV8Value v) 17 { 18 if (v.IsArray) 19 { 20 int length = v.GetArrayLength(); 21 object[] objs = new object[length]; 22 for (int i = 0; i < length; i++) 23 { 24 var value = v.GetValue(i); 25 objs[i] = GetClrValue(value); 26 } 27 return objs; 28 } 29 30 if (v.IsBool ) return v.GetBoolValue(); 31 32 if (v.IsDate) return v.GetDateValue(); 33 if (v.IsInt) return v.GetIntValue(); 34 35 if (v.IsDouble) return v.GetDoubleValue(); 36 37 if (v.IsFunction){ 38 throw new NotSupportedException("IsFunction"); 39 } 40 41 42 if (v.IsNull) return null; 43 if (v.IsObject) 44 { 45 //throw new NotSupportedException("IsObject"); 46 var map = v.GetUserData() as Clr2V8ValueWrapper; 47 if (map != null) 48 return map.ClrObject; 49 return null; 50 } 51 if (v.IsString) return v.GetStringValue(); 52 if (v.IsUInt) return v.GetUIntValue(); 53 if (v.IsUndefined) return null; 54 if (v.IsUserCreated) 55 { 56 throw new NotSupportedException("IsUserCreated"); 57 } 58 throw new NotSupportedException("??"); 59 60 } 61 62 public static CefV8Value ConvertToV8Value(object o) 63 { 64 if (o == null) return CefV8Value.CreateUndefined(); 65 if (o is bool) return CefV8Value.CreateBool((bool)o); 66 if (o is DateTime) return CefV8Value.CreateDate((DateTime)o); 67 if (o is double) return CefV8Value.CreateDouble((double)o); 68 if (o is int) return CefV8Value.CreateInt((int)o); 69 if (o is string) return CefV8Value.CreateString((string)o); 70 if (o is uint) return CefV8Value.CreateUInt((uint)o); 71 if (o is Array) 72 { 73 var a=(Array)o; 74 var rtn = CefV8Value.CreateArray(a.Length); 75 for(int i=0;i<a.Length;i++) 76 { 77 rtn.SetValue(i,ConvertToV8Value(a.GetValue(i))); 78 } 79 return rtn; 80 } 81 if (o is System.Collections.IList) 82 { 83 var a = (System.Collections.IList)o; 84 var rtn = CefV8Value.CreateArray(a.Count); 85 for (int i = 0; i < a.Count; i++) 86 { 87 rtn.SetValue(i, ConvertToV8Value(a[i])); 88 } 89 return rtn; 90 } 91 throw new NotSupportedException("??"); 92 } 93 }
然后就可以在js里調用JavaScriptExtMethod的方法: window.external.SomeMethod();
C# 里調用Js方法, 推薦使用發Message 到Render進程, 然后render進程執行完后再發消息給browser進程的方法.這樣才能方便的捕獲到js里的異常和返回值.
render進程:
1 protected override bool OnProcessMessageReceived(CefBrowser browser, CefProcessId sourceProcess, CefProcessMessage message) 2 { 3 if (message.Name == "ExecuteJavaScript") 4 { 5 string code = message.Arguments.GetString(0); 6 var context = browser.GetMainFrame().V8Context; 7 context.Enter(); 8 try 9 { 10 var global = context.GetGlobal(); 11 var evalFunc = global.GetValue("eval"); 12 CefV8Value arg0 = CefV8Value.CreateString(code); 13 14 var rtn = evalFunc.ExecuteFunctionWithContext(context, evalFunc, 15 new CefV8Value[] { arg0 }); 16 if (evalFunc.HasException) 17 { 18 var exception = evalFunc.GetException(); 19 var message3 = CefProcessMessage.Create("Exception"); 20 var arguments = message3.Arguments; 21 arguments.SetString(0, exception.Message + " At Line" + exception.LineNumber); 22 var success2 = browser.SendProcessMessage(CefProcessId.Browser, message3); 23 24 } 25 else 26 { 27 var message3 = CefProcessMessage.Create("JavascriptExecutedResult"); 28 var arguments = message3.Arguments; 29 arguments.SetString(0,rtn.GetStringValue()); 30 var success2 = browser.SendProcessMessage(CefProcessId.Browser, message3); 31 } 32 } 33 34 finally 35 { 36 context.Exit(); 37 } 38 } 39 40 41 42 return false; 43 }
4. javascript 的執行都在renderer 的Main Thread 上面.