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 }