object FuncCallJs(params object[] objs) { object toNativeObject(object obj) { if (obj == null) { return(obj); } var nobj = obj as NativeObjectInfo; if (nobj == null) { return(obj); } var r = WebBrowserInfo.GetNativeObject(nobj.Id, false); if (r == null) { throw new Exception($"本机对象不存在{nobj.Id}"); } return(r); } var browser = objs[0] as IWebBrowser; var script = objs[1].ToString(); var args = new string[objs.Length - 2]; for (var i = 0; i < args.Length; i++) { args[i] = NativeToJsValue(objs[i + 2]); } var toRun = $"return Tnelab.OnCallJs(({script})({string.Join(",", args)}))"; var result = browser.RunJs(toRun); var robj = JsonConvert.DeserializeObject <OnCallJsInfo>(result); if (!robj.Status) { throw new Exception(robj.Data.ToString()); } return(toNativeObject(robj.Data)); }
public JsNativeInvokeContext(WebBrowserInfo info, MapActionInfo mapInfo, Func <string, string> getJsTypeName) { this.WebBrowserInfo = info; this.MapInfo = mapInfo; this.GetJsTypeName = getJsTypeName; }
public string NativeToJsValue(object nVal) { string getJvByTypeName(string tName, object val) { string gv = null; switch (tName) { case "System.Char": case "System.String": gv = $"\"{val.ToString()}\""; break; case "System.Int16": case "System.UInt16": case "System.Int32": case "System.UInt32": case "System.Int64": case "System.UInt64": case "System.Double": case "System.Decimal": case "System.Single": case "System.Boolean": case "System.Byte": case "System.SByte": gv = val.ToString(); break; } return(gv); } string getJvByTuple(long id, string type_name, string genericInfo) { var jsTypeName = GetJsTypeName(type_name); var b = jsTypeName.IndexOf("<"); if (b != -1) { jsTypeName = jsTypeName.Substring(0, b); } var strBuilder = new StringBuilder(); strBuilder.Append("(async function(){") .AppendLine("let no=new Tnelab.NativeObjectInfo();") .AppendLine($"no.Id = {id};") .AppendLine($"no.GenericInfo = \"{genericInfo}\";") .AppendLine($"let ro=new {jsTypeName}(no);") .AppendLine($"let r=await ro.Ready();") .AppendLine($"r.TneMapGcObject_ = Tnelab.OnGetGC(r.TneMapNativeObjectId);") .AppendLine($"return r;") .Append("})()"); return(strBuilder.ToString()); } string getJvByMaped(string type_name, object val, string genericInfo) { var id = WebBrowserInfo.AddNativeObject(val, genericInfo); var jsTypeName = GetJsTypeName(type_name); var b = jsTypeName.IndexOf("<"); if (b != -1) { jsTypeName = jsTypeName.Substring(0, b); } var strBuilder = new StringBuilder(); strBuilder.Append("(async function(){") .AppendLine("let no=new Tnelab.NativeObjectInfo();") .AppendLine($"no.Id = {id};") .AppendLine($"no.GenericInfo = \"{genericInfo}\";") .AppendLine($"let ro=new {jsTypeName}(no);") .AppendLine($"let r=await ro.Ready();") .AppendLine($"r.TneMapGcObject_ = Tnelab.OnGetGC(r.TneMapNativeObjectId);") .AppendLine($"return r;") .Append("})()"); return(strBuilder.ToString()); } string getJv(string type_name, object val, string genericInfo) { string gv; gv = getJvByTypeName(type_name, val); if (gv != null) { return(gv); } var tVal = val as Tuple <long, object>;//是否一个已存在的js同步对象 var id = WebBrowserInfo.GetNativeObjectId(val); if (val == null) { gv = "undefined"; } else if (tVal != null)//是否一个已存在的js同步对象 { var tmpNO = WebBrowserInfo.GetNativeObject(id, true); gv = getJvByTuple(tVal.Item1, type_name, genericInfo); } else if (id != -1)//是否一个已存在的js同步对象 { var tmpNO = WebBrowserInfo.GetNativeObject(id, true); gv = getJvByTuple(id, type_name, genericInfo); } else if (GetJsTypeName(type_name) != null)//一个已经映射的js类型,但是未存在的js对象 { gv = getJvByMaped(type_name, val, genericInfo); } else//其他,直接序列 { var json = JsonConvert.SerializeObject(val); gv = $"{json}"; } return(gv); } var browser = this.WebBrowserInfo.WebBrowser; var type = nVal.GetType(); var typeName = $"{type.Namespace}.{type.Name}"; if (type.IsGenericType) { typeName = $"{typeName}`{type.GenericTypeArguments.Length}"; } var rv = getJv(typeName, nVal, GetGenericInfo(type)); return(rv); }
public (Type, object) JsValueInfoToNative(MapDataInfo dataInfo) { //处理范型Action和func //(Type, bool) IsAction(string nativeTypePath) //{ // Type r_nativeType = GetTypeByString(nativeTypePath); // bool lisAction = false; // if (nativeTypePath.IndexOf("System.Action<") >= 0) // { // lisAction = true; // //isFunc = false; // } // else if (nativeTypePath.IndexOf("Func<") >= 0) // { // lisAction = false; // //isFunc = true; // } // return (lnativeType, lisAction); //} //(Type, bool) NativeTypePathNotNull() //{ // Type lnativeType = null; // bool lisAction = false; // var ntPath = dataInfo.NativeTypePath; // var sIdx = ntPath.IndexOf("<"); // if (sIdx > 0) // { // var (nt, ia) = IsFx(ntPath, sIdx); // lnativeType = nt; // lisAction = ia; // } // else // { // lnativeType = Type.GetType(dataInfo.NativeTypePath); // lisAction = lnativeType == typeof(Action); // } // return (lnativeType, lisAction); //} object IsFunctionId(Type theNativeType, IWebBrowser theBrowser, string script) { var delegateInfo = theNativeType.GetMethod("Invoke"); bool theIsAction = delegateInfo.ReturnType == typeof(void); var paramTypes = delegateInfo.GetParameters().Select(it => it.ParameterType).ToArray(); List <ParameterExpression> paramExps = new List <ParameterExpression>(); List <Expression> vParamExps = new List <Expression>() { Expression.Convert(Expression.Constant(theBrowser), typeof(object)), Expression.Convert(Expression.Constant(script), typeof(object)) }; var len = paramTypes.Length; if (!theIsAction) { len -= 1; } for (var i = 0; i < len; i++) { var pt = paramTypes[i]; var pEx = Expression.Parameter(pt); paramExps.Add(pEx); vParamExps.Add(Expression.Convert(pEx, typeof(object))); } var arrayExp = Expression.NewArrayInit(typeof(object), vParamExps); LambdaExpression lambdaExpr; if (theIsAction) { var method = typeof(JsNativeInvokeContext).GetMethod("ActionCallJs", BindingFlags.NonPublic | BindingFlags.Instance); lambdaExpr = Expression.Lambda(theNativeType, Expression.Call(Expression.Constant(this), method, arrayExp), paramExps); } else { var method = typeof(JsNativeInvokeContext).GetMethod("FuncCallJs", BindingFlags.NonPublic | BindingFlags.Instance); lambdaExpr = Expression.Lambda(theNativeType, Expression.Convert(Expression.Call(Expression.Constant(this), method, arrayExp), paramTypes[paramTypes.Length - 1]), paramExps); } return(lambdaExpr.Compile()); } var tobj = WebBrowserInfo.GetNativeObject(MapInfo.Id, false) as TneForm; var browser = tobj == null?WebBrowserInfo.WebBrowser:tobj.WebBrowser; Type nativeType = null; object obj = null; //bool isFunc = false; //if (dataInfo.NativeTypePath != null) //{ // var (nt, ia) = NativeTypePathNotNull(); // nativeType = nt; // isAction = ia; //} if (dataInfo.DataType == MapDataType.NativeObjectId) { dynamic dobj = dataInfo.Value; long hcode = dobj.Id; var nobj = WebBrowserInfo.GetNativeObject(hcode, false); if (nobj == null) { throw new Exception($"本机对象不存在{hcode}"); } nativeType = nobj.GetType(); obj = new Tuple <long, object>(hcode, nobj); } else if (dataInfo.DataType == MapDataType.FunctionId) { nativeType = GetTypeByString(dataInfo.NativeTypePath); bool isAction = nativeType.FullName.StartsWith("System.Action"); bool isFunction = nativeType.FullName.StartsWith("System.Func"); obj = IsFunctionId(nativeType, browser, dataInfo.Value.ToString()); } else { nativeType = GetTypeByString(dataInfo.NativeTypePath); obj = dataInfo.Value; if (nativeType != null) { if (typeof(Enum).IsAssignableFrom(nativeType)) { obj = Enum.Parse(nativeType, dataInfo.Value.ToString()); } else if (nativeType == typeof(IntPtr)) { obj = JsonConvert.DeserializeObject(dataInfo.Value.ToString(), nativeType); } else { obj = Convert.ChangeType(dataInfo.Value, nativeType); } } } if (nativeType == null) { nativeType = obj.GetType(); } return(nativeType, obj); }
public long AddBrowser(IWebBrowser browser, Func <object> getParentControl) { if (browser == null) { throw new ArgumentException("浏览器对象不能为空", "browser"); } browser.JsQuery += (webBrowser, args) => { switch ((TneQueryId)args.CustomMsg) { case TneQueryId.RegisterNativeMap: OnRegisterNativeMap(webBrowser as IWebBrowser, args); break; case TneQueryId.NativeMap: OnJavaScriptNativeMap(webBrowser as IWebBrowser, args); break; case TneQueryId.DeleteNativeObject: OnDeleteNativeObject(webBrowser as IWebBrowser, args); break; case TneQueryId.GetThisFormHashCode: { var wb = webBrowser as IWebBrowser; var wbinfo = GetBrowserInfo(wb); wb.ResponseJsQuery(args.WebView, args.QueryId, args.CustomMsg, wbinfo.ParentControlId.ToString()); } break; case TneQueryId.RunFunctionForTneForm: { var runInfo = JsonConvert.DeserializeObject <RunFunctionForTneFormInfo>(args.Request); var wb = webBrowser as IWebBrowser; var wbinfo = GetBrowserInfo(wb); var tneForm = wbinfo.GetNativeObject(runInfo.TneFormId, false) as TneForm; var result = tneForm.WebBrowser.RunJs($"return (async {runInfo.Function})(\"{runInfo.Arg}\").then(async function(result){{await Tnelab.TneQueryAsync(Tnelab.TneQueryId.RunFunctionResultForTneForm, result);}})"); if (taskRunFunctionResult_ != null) { throw new Exception("runfunction异常"); } taskRunFunctionResult_ = new TaskCompletionSource <string>(); Task.Factory.StartNew(() => { taskRunFunctionResult_.Task.Wait(); wb.UIInvoke(() => { wb.ResponseJsQuery(args.WebView, args.QueryId, args.CustomMsg, taskRunFunctionResult_.Task.Result); }); taskRunFunctionResult_ = null; }); } break; case TneQueryId.RunFunctionResultForTneForm: { var wb = webBrowser as IWebBrowser; wb.ResponseJsQuery(args.WebView, args.QueryId, args.CustomMsg, "OK"); taskRunFunctionResult_.SetResult(args.Request); } break; case TneQueryId.ShowContextMenuForTneForm: { OnShowContextMenu(webBrowser as IWebBrowser, args); } break; default: throw new Exception("未知JS消息"); } }; var info = new WebBrowserInfo(browser, getParentControl); lock (webBrowserDicLock_) { WebBrowserInfoDic.Add(browser, info); } return(info.ParentControlId); }