1 //新的一个子进程浏览器 2 private void OpenNewWebBrowser(string webBrowserName, string url) 3 { 4 IntPtr targetPtr = this.CreateWebProcess(); 5 6 IntPtr pagePtr = this.GetOrAddNewPage(webBrowserName, url); 7 8 lock (_lockObj) 9 { 10 _webBrowserPtr.Add(webBrowserName, targetPtr); 11 } 12 13 this.SetWebBrowserLoc(webBrowserName, pagePtr); 14 15 this.SendParam(webBrowserName, url); 16 } 17 18 19 //创建一个新的webbrowser进程 20 private IntPtr CreateWebProcess() 21 { 22 ProcessStartInfo psi = new ProcessStartInfo(_webBrowserStartPath); 23 psi.WindowStyle = ProcessWindowStyle.Hidden; 24 var process = Process.Start(psi); 25 IntPtr targetPtr = IntPtr.Zero; 26 while (targetPtr == IntPtr.Zero) //循环目标窗口启动完成 27 { 28 targetPtr = process.MainWindowHandle; 29 if (targetPtr != IntPtr.Zero) 30 { 31 break; 32 } 33 Thread.Sleep(10); 34 } 35 return targetPtr; 36 } 37 38 private IntPtr GetOrAddNewPage(string webBrowserName, string url) 39 { 40 // if (!_urlAndPanelPtr.ContainsKey(url)) 41 { 42 System.Windows.Forms.Panel p = new System.Windows.Forms.Panel(); 43 WindowsFormsHost host = new WindowsFormsHost(); 44 host.Tag = webBrowserName; 45 host.Background = Brushes.Transparent; 46 host.Child = p; 47 48 host.Visibility = System.Windows.Visibility.Visible; 49 _webContainer.Children.Add(host); 50 51 // lock (_lockObj) 52 // _urlAndPanelPtr.Add(url, p.Handle); 53 return p.Handle;// 允许一个地址打开多个 54 } 55 // return _urlAndPanelPtr[url]; 56 } 57 58 //设置浏览器位置 59 private void SetWebBrowserLoc(string webBrowserName, IntPtr pagePtr) 60 { 61 if (!_webBrowserPtr.ContainsKey(webBrowserName)) 62 return; 63 64 IntPtr webBrowserPtr = _webBrowserPtr[webBrowserName]; 65 66 double h = _webContainer.ActualHeight; 67 68 double w = _webContainer.ActualWidth; 69 70 IntPtr preParentHandle= Win32Helper.SetParent(webBrowserPtr, pagePtr); 71 72 //如果设置父窗体失败,则重试5次 73 int tryNum = 5; 74 while(preParentHandle==IntPtr.Zero) 75 { 76 Thread.Sleep(10); 77 78 preParentHandle = Win32Helper.SetParent(webBrowserPtr, pagePtr); 79 80 if (tryNum <= 0) break; 81 82 tryNum--; 83 } 84 85 bool moveResult= Win32Helper.MoveWindow(webBrowserPtr, 0, 0, (int)w, (int)h, true); 86 87 //如果窗体位置移动失败,则尝试5次 88 tryNum = 5; 89 while(!moveResult) 90 { 91 Thread.Sleep(10); 92 moveResult = Win32Helper.MoveWindow(webBrowserPtr, 0, 0, (int)w, (int)h, true); 93 if (tryNum <= 0) break; 94 95 tryNum--; 96 } 97 } 98 99 100 101 102 103 104 105 public class WebEmbedHelper: IWebEmbedHelper 106 { 107 string _isNeedReflesh = "0";//是否需要刷新url页面 108 readonly Grid _webContainer = null; 109 /// <summary> 110 /// webbrowser容器句柄 111 /// </summary> 112 readonly IntPtr _parentIntPrt; 113 static Dictionary<string, IntPtr> _urlAndPanelPtr = new Dictionary<string, IntPtr>();//url- panel句柄 114 static Dictionary<string, IntPtr> _webBrowserPtr = new Dictionary<string, IntPtr>();//名称 - webbrowser窗体句柄 115 static Dictionary<string, IntPtr> _urlAndBroserPrt = new Dictionary<string, IntPtr>();//url -webbrowser窗体句柄 116 //url - 回调函数 117 static Dictionary<string, Action<string, string>> _msgCallBackDic = new Dictionary<string, Action<string, string>>(); 118 readonly string _webBrowserStartPath; 119 120 string _currentOpenUrl;//当前打开的url页面 121 IntPtr _webProcessPtr;//当前的WebBrowser进程句柄 122 bool _isChrome = false; 123 public IntPtr WebProcessPtr 124 { 125 get 126 { 127 return _webProcessPtr; 128 } 129 set 130 { 131 _webProcessPtr = value; 132 } 133 } 134 public Action<int, object> GetWinAction { get; set; }//获取主客户端进程消息的action 135 136 static object _lockObj = new object(); 137 138 /// <summary> 139 /// WebBrowser构造函数 140 /// </summary> 141 /// <param name="parentIntPrt">WebBrowser容器父窗体句柄</param> 142 /// <param name="grid">用于装载WebBrowser的容器</param> 143 /// <param name="webBrowserStartPath">WebBrowser启动完整路径</param> 144 public WebEmbedHelper(IntPtr parentIntPrt, Grid grid, string webBrowserStartPath) 145 { 146 _parentIntPrt = parentIntPrt; 147 _webContainer = grid; 148 _webBrowserStartPath = webBrowserStartPath; 149 150 this.GetWinAction = ReceiveWinMsg; 151 152 _webContainer.SizeChanged += webContainer_SizeChanged; 153 } 154 155 //窗体大小变更,对应的页面也应该自适应 156 private void webContainer_SizeChanged(object sender, System.Windows.SizeChangedEventArgs e) 157 { 158 double w = _webContainer.ActualWidth; 159 double h = _webContainer.ActualHeight; 160 foreach (var itm in _webBrowserPtr) 161 { 162 Win32Helper.MoveWindow(itm.Value, 0, 0, (int)w, (int)h, true); 163 } 164 } 165 166 #region//打开web相关的私有方法 167 private IntPtr GetOrAddNewPage(string webBrowserName, string url) 168 { 169 // if (!_urlAndPanelPtr.ContainsKey(url)) 170 { 171 System.Windows.Forms.Panel p = new System.Windows.Forms.Panel(); 172 WindowsFormsHost host = new WindowsFormsHost(); 173 host.Tag = webBrowserName; 174 host.Background = Brushes.Transparent; 175 host.Child = p; 176 177 host.Visibility = System.Windows.Visibility.Visible; 178 _webContainer.Children.Add(host); 179 180 // lock (_lockObj) 181 // _urlAndPanelPtr.Add(url, p.Handle); 182 return p.Handle;// 允许一个地址打开多个 183 } 184 // return _urlAndPanelPtr[url]; 185 } 186 187 private void FindAndOpenWebBrowser(string webBrowserName, string url) 188 { 189 if (!_webBrowserPtr.ContainsKey(webBrowserName)) 190 { 191 this.OpenNewWebBrowser(webBrowserName, url); 192 } 193 else 194 { 195 OpenExistWebBrowser(webBrowserName, url); 196 } 197 } 198 199 //打开新的浏览器 200 private void OpenNewWebBrowser(string webBrowserName, string url) 201 { 202 IntPtr targetPtr = this.CreateWebProcess(); 203 204 IntPtr pagePtr = this.GetOrAddNewPage(webBrowserName, url); 205 206 lock (_lockObj) 207 { 208 _webBrowserPtr.Add(webBrowserName, targetPtr); 209 } 210 211 this.SetWebBrowserLoc(webBrowserName, pagePtr); 212 213 this.SendParam(webBrowserName, url); 214 } 215 //打开已存在的页面 216 private void OpenExistWebBrowser(string webBrowserName, string url) 217 { 218 //显示隐藏窗体 219 foreach (var itm in _webContainer.Children) 220 { 221 WindowsFormsHost wfh = itm as WindowsFormsHost; 222 if (wfh == null) continue; 223 if (wfh.Tag.ToString() == webBrowserName) 224 wfh.Visibility = Visibility.Visible; 225 else 226 wfh.Visibility = Visibility.Collapsed; 227 } 228 229 IntPtr webBrowserPtr = _webBrowserPtr[webBrowserName]; 230 231 double h = _webContainer.ActualHeight - 10; 232 233 double w = _webContainer.ActualWidth - 10; 234 235 Win32Helper.MoveWindow(webBrowserPtr, 0, 0, (int)w, (int)h, true); 236 237 this.SendParam(webBrowserName, url); 238 } 239 //设置浏览器位置 240 private void SetWebBrowserLoc(string webBrowserName, IntPtr pagePtr) 241 { 242 if (!_webBrowserPtr.ContainsKey(webBrowserName)) 243 return; 244 245 IntPtr webBrowserPtr = _webBrowserPtr[webBrowserName]; 246 247 double h = _webContainer.ActualHeight; 248 249 double w = _webContainer.ActualWidth; 250 251 IntPtr preParentHandle= Win32Helper.SetParent(webBrowserPtr, pagePtr); 252 253 //如果设置父窗体失败,则重试5次 254 int tryNum = 5; 255 while(preParentHandle==IntPtr.Zero) 256 { 257 Thread.Sleep(10); 258 259 preParentHandle = Win32Helper.SetParent(webBrowserPtr, pagePtr); 260 261 if (tryNum <= 0) break; 262 263 tryNum--; 264 } 265 266 bool moveResult= Win32Helper.MoveWindow(webBrowserPtr, 0, 0, (int)w, (int)h, true); 267 268 //如果窗体位置移动失败,则尝试5次 269 tryNum = 5; 270 while(!moveResult) 271 { 272 Thread.Sleep(10); 273 moveResult = Win32Helper.MoveWindow(webBrowserPtr, 0, 0, (int)w, (int)h, true); 274 if (tryNum <= 0) break; 275 276 tryNum--; 277 } 278 } 279 //向浏览器发送数据 280 private void SendParam(string webBrowserName, string url) 281 { 282 if (!_webBrowserPtr.ContainsKey(webBrowserName)) 283 return; 284 285 _webProcessPtr = _webBrowserPtr[webBrowserName]; 286 287 UrlModel um = new UrlModel() { Url = url, isChrome = _isChrome }; 288 289 if (this._isNeedReflesh == "1") 290 um.IsNeedRefresh = true; 291 292 //发送message 293 this.SendMessage(um); 294 } 295 296 297 public void SendLoadedParam(string pMsgId, string pUrl) 298 { 299 300 UrlModel um = new UrlModel() { MsgId = pMsgId, Url = pUrl }; 301 //发送message 302 this.SendMessage(um); 303 } 304 305 #endregion 306 307 //创建一个新的webbrowser进程 308 private IntPtr CreateWebProcess() 309 { 310 ProcessStartInfo psi = new ProcessStartInfo(_webBrowserStartPath); 311 psi.WindowStyle = ProcessWindowStyle.Hidden; 312 var process = Process.Start(psi); 313 IntPtr targetPtr = IntPtr.Zero; 314 while (targetPtr == IntPtr.Zero) //循环目标窗口启动完成 315 { 316 targetPtr = process.MainWindowHandle; 317 if (targetPtr != IntPtr.Zero) 318 { 319 break; 320 } 321 Thread.Sleep(10); 322 } 323 return targetPtr; 324 } 325 /// <summary> 326 /// 接收web页面JS调用发送的数据 327 /// </summary> 328 private void ReceiveWinMsg(int index,object msg) 329 { 330 if (msg == null) return; 331 string data = msg.ToString(); 332 333 if (!data.Contains("MsgId")) return; 334 335 ////js->web->web进程-->客户端主进程 336 JsInvokeClientModel jm = JsonConvert.DeserializeObject<JsInvokeClientModel>(data); 337 if (jm != null && _msgCallBackDic.ContainsKey(jm.Url)) 338 { 339 //将web页面js调用的参数回调到具体订阅的业务模块中 340 _msgCallBackDic[jm.Url](jm.Cmd, jm.Params); 341 } 342 343 //客户端主进程->web进程->js 344 ClientInvokeJsModel jsResp = JsonConvert.DeserializeObject<ClientInvokeJsModel>(data); 345 if (jsResp != null && _jsCallBackData.ContainsKey(jsResp.MsgId)) 346 { 347 jsResp.IsCompleted = true; 348 _jsCallBackData[jsResp.MsgId] = jsResp; 349 } 350 } 351 /// <summary> 352 /// 发送message 353 /// </summary> 354 /// <param name="message"></param> 355 private void SendMessage(MessageBase message) 356 { 357 ////将message序列化为json传输 358 string json = JsonConvert.SerializeObject(message); 359 byte[] sarr = System.Text.Encoding.Default.GetBytes(json); 360 int len = sarr.Length; 361 CopyDataStruct cds = new CopyDataStruct 362 { 363 DwData = (IntPtr)100, 364 LpData = json, 365 CbData = len + 1 366 }; 367 var value= Win32Helper.SendMessage(this._webProcessPtr, WmConst.WM_COPYDATA, this._parentIntPrt, ref cds); 368 } 369 370 371 372 #region//Interface实现 373 public void Open(string url, string webBrowserName = null, bool isNeedReflesh = false, Action<string, string> callBack = null, bool pIsChrome=false) 374 { 375 _currentOpenUrl = url; 376 _isChrome = pIsChrome; 377 _isNeedReflesh = isNeedReflesh ? "1" : "0"; 378 379 if (string.IsNullOrEmpty(webBrowserName)) 380 webBrowserName = "defaultName"; 381 382 //IE浏览器打开方式:查找webBrowser进程窗体句柄 383 this.FindAndOpenWebBrowser(webBrowserName, url); 384 //谷歌的打开方式 385 386 //绑定委托 387 if (callBack != null) 388 { 389 if (!_msgCallBackDic.ContainsKey(url)) 390 _msgCallBackDic.Add(url, callBack); 391 else 392 _msgCallBackDic[url] = callBack; 393 } 394 395 // 移除允许 一个url地址 多个窗体打开 396 //if (!_urlAndBroserPrt.ContainsKey(url) && _webBrowserPtr.ContainsKey(webBrowserName)) 397 //{ 398 // _urlAndBroserPrt.Add(url, _webBrowserPtr[webBrowserName]); 399 //} 400 } 401 402 public void Close(string webBrowserName, string url = null) 403 { 404 //特殊处置,为了兼容模块嵌入页面同时“设置”项也嵌入页面问题,先查询key的前6位 405 if (webBrowserName.Length > 6) 406 webBrowserName = webBrowserName.Substring(0, 6); 407 408 List<string> delKeys = new List<string>(); 409 foreach(var itm in _webBrowserPtr) 410 { 411 if(itm.Key.Contains(webBrowserName)) 412 { 413 delKeys.Add(itm.Key); 414 } 415 } 416 417 foreach(var key in delKeys) 418 { 419 if (_webBrowserPtr.ContainsKey(key)) 420 { 421 IntPtr ptr = _webBrowserPtr[key]; 422 //发送关闭命令 423 Win32Helper.SendMessage(ptr, WmConst.C_WM_CLOSE, 0, 0); 424 _webBrowserPtr.Remove(key); 425 } 426 } 427 428 if (!string.IsNullOrEmpty(url)) 429 { 430 //_urlAndPanelPtr.Remove(url); 431 _msgCallBackDic.Remove(url); 432 } 433 } 434 435 static Dictionary<string, ClientInvokeJsModel> _jsCallBackData = new Dictionary<string, ClientInvokeJsModel>(); 436 //public async Task<object> InvokeScript(string scriptName) 437 //{ 438 // return await this.InvokeScript(scriptName, null); 439 //} 440 441 //public async Task<object> InvokeScript(string scriptName, params object[] args) 442 //{ 443 // ClientInvokeJsModel js = new ClientInvokeJsModel() { Url = _currentOpenUrl, ScriptName = scriptName, ReqParamList = args }; 444 445 // js.MsgId = Guid.NewGuid().ToString(); 446 447 // if (!_jsCallBackData.ContainsKey(js.MsgId)) 448 // { 449 // _jsCallBackData.Add(js.MsgId, js); 450 // } 451 // this.SendMessage(js); 452 // object result = null; 453 // await Task<object>.Run(() => 454 // { 455 // while (true) 456 // { 457 // if (_jsCallBackData[js.MsgId].IsCompleted) 458 // { 459 // result = _jsCallBackData[js.MsgId]; 460 // _jsCallBackData.Remove(js.MsgId); break; 461 // } 462 // } 463 // }); 464 465 // return result; 466 //} 467 468 469 #endregion 470 }