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);
        }
Example #5
0
        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);
        }