EmbedPanel.cs 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. using System;
  2. using System.ComponentModel;
  3. using System.Windows.Forms;
  4. using System.Diagnostics;
  5. using System.IO;
  6. using System.Runtime.InteropServices;
  7. namespace Y.Skin.YoPanel
  8. {
  9. public partial class EmbedPanel : Panel
  10. {
  11. Action<object, EventArgs> appIdleAction = null;
  12. EventHandler appIdleEvent = null;
  13. public EmbedPanel()
  14. {
  15. InitializeComponent();
  16. appIdleAction = new Action<object, EventArgs>(Application_Idle);
  17. appIdleEvent = new EventHandler(appIdleAction);
  18. }
  19. public EmbedPanel(IContainer container)
  20. {
  21. container.Add(this);
  22. InitializeComponent();
  23. appIdleAction = new Action<object, EventArgs>(Application_Idle);
  24. appIdleEvent = new EventHandler(appIdleAction);
  25. }
  26. /// <summary>
  27. /// 嵌入程序(保证程序嵌入)
  28. /// </summary>
  29. /// <param name="sender"></param>
  30. /// <param name="e"></param>
  31. void Application_Idle(object sender, EventArgs e)
  32. {
  33. if (_AppProcess == null || _AppProcess.HasExited)
  34. {
  35. _AppProcess = null;
  36. Application.Idle -= appIdleEvent;
  37. return;
  38. }
  39. if (_AppProcess.MainWindowHandle == IntPtr.Zero) return;
  40. Application.Idle -= appIdleEvent;
  41. EmbedProcess(_AppProcess, this);
  42. }
  43. #region 常规属性
  44. private string AppFile = "";
  45. private Process _AppProcess = null;
  46. public Process AppProcess
  47. {
  48. get { return _AppProcess; }
  49. set { _AppProcess = value; }
  50. }
  51. public bool IsStarted { get { return (_AppProcess != null); } }
  52. #endregion
  53. #region 控件面板属性
  54. #endregion
  55. /// <summary>
  56. /// 启动嵌入程序
  57. /// </summary>
  58. /// <param name="appFilename"></param>
  59. public void Start(string appFile)
  60. {
  61. if (appFile.ToLower() == Application.ExecutablePath.ToLower()) return;//禁止嵌入自己
  62. if (!appFile.ToLower().EndsWith(".exe")) return;//禁止嵌入非exe文件
  63. if (!File.Exists(appFile)) return;//禁止嵌入不存在文件
  64. AppFile = appFile;
  65. if (_AppProcess != null) Stop();//停止正在运行的进程
  66. try
  67. {
  68. ProcessStartInfo info = new ProcessStartInfo(AppFile);
  69. info.UseShellExecute = true;
  70. info.WindowStyle = ProcessWindowStyle.Minimized;
  71. //info.WindowStyle = ProcessWindowStyle.Hidden;
  72. _AppProcess = Process.Start(info);
  73. //等待创建进程
  74. _AppProcess.WaitForInputIdle();
  75. //todo:下面这两句会引发 NullReferenceException 异常,不知道怎么回事
  76. //m_AppProcess.Exited += new EventHandler(m_AppProcess_Exited);
  77. //m_AppProcess.EnableRaisingEvents = true;
  78. Application.Idle += appIdleEvent;
  79. }
  80. catch (Exception ex)
  81. {
  82. //嵌入失败杀死进程
  83. if (_AppProcess != null)
  84. {
  85. if (!_AppProcess.HasExited)
  86. _AppProcess.Kill();
  87. _AppProcess = null;
  88. }
  89. }
  90. }
  91. /// <summary>
  92. /// 重新嵌入
  93. /// </summary>
  94. public void ReEmbed()
  95. {
  96. EmbedProcess(_AppProcess, this);
  97. }
  98. /// <summary>
  99. /// 退出嵌入的程序
  100. /// </summary>
  101. public void Stop()
  102. {
  103. if (_AppProcess != null)// && m_AppProcess.MainWindowHandle != IntPtr.Zero)
  104. {
  105. try
  106. {
  107. if (!_AppProcess.HasExited)
  108. _AppProcess.Kill();
  109. }
  110. catch (Exception) { }
  111. _AppProcess = null;
  112. }
  113. }
  114. /// <summary>
  115. /// 将程序嵌入控件
  116. /// </summary>
  117. /// <param name="app">嵌入程序</param>
  118. /// <param name="control">指定控件</param>
  119. private void EmbedProcess(Process app, Control control)
  120. {
  121. //验证程序和控件非空
  122. if (app == null || app.MainWindowHandle == IntPtr.Zero || control == null) return;
  123. try
  124. {
  125. //核心代码:嵌入程序
  126. SetParent(app.MainWindowHandle, control.Handle);
  127. }
  128. catch (Exception) { }
  129. try
  130. {
  131. //移除嵌入的窗口的窗口标题栏
  132. SetWindowLong(new HandleRef(this, app.MainWindowHandle), GWL_STYLE, WS_VISIBLE);
  133. }
  134. catch (Exception) { }
  135. try
  136. {
  137. //将嵌入的窗口欧放置到合适位置,填满宽高
  138. MoveWindow(app.MainWindowHandle, 0, 0, control.Width, control.Height, true);
  139. }
  140. catch (Exception) { }
  141. }
  142. #region 重写部分方法
  143. /// <summary>
  144. /// 窗体句柄销毁
  145. /// </summary>
  146. /// <param name="e"></param>
  147. protected override void OnHandleDestroyed(EventArgs e)
  148. {
  149. Stop();//将应用关闭
  150. base.OnHandleDestroyed(e);
  151. }
  152. /// <summary>
  153. /// 窗体大小修改
  154. /// </summary>
  155. /// <param name="eventargs"></param>
  156. protected override void OnResize(EventArgs eventargs)
  157. {
  158. if (_AppProcess != null)
  159. {
  160. MoveWindow(_AppProcess.MainWindowHandle, 0, 0, this.Width, this.Height, true);
  161. }
  162. base.OnResize(eventargs);
  163. }
  164. /// <summary>
  165. /// 窗台属性修改
  166. /// </summary>
  167. /// <param name="e"></param>
  168. protected override void OnSizeChanged(EventArgs e)
  169. {
  170. this.Invalidate();
  171. base.OnSizeChanged(e);
  172. }
  173. #endregion
  174. #region Win32 API 常量
  175. private const int SWP_NOOWNERZORDER = 0x200;
  176. private const int SWP_NOREDRAW = 0x8;
  177. private const int SWP_NOZORDER = 0x4;
  178. private const int SWP_SHOWWINDOW = 0x0040;
  179. private const int WS_EX_MDICHILD = 0x40;
  180. private const int SWP_FRAMECHANGED = 0x20;
  181. private const int SWP_NOACTIVATE = 0x10;
  182. private const int SWP_ASYNCWINDOWPOS = 0x4000;
  183. private const int SWP_NOMOVE = 0x2;
  184. private const int SWP_NOSIZE = 0x1;
  185. private const int GWL_STYLE = (-16);
  186. private const int WS_VISIBLE = 0x10000000;
  187. private const int WM_CLOSE = 0x10;
  188. private const int WS_CHILD = 0x40000000;
  189. private const int SW_HIDE = 0; //{隐藏, 并且任务栏也没有最小化图标}
  190. private const int SW_SHOWNORMAL = 1; //{用最近的大小和位置显示, 激活}
  191. private const int SW_NORMAL = 1; //{同 SW_SHOWNORMAL}
  192. private const int SW_SHOWMINIMIZED = 2; //{最小化, 激活}
  193. private const int SW_SHOWMAXIMIZED = 3; //{最大化, 激活}
  194. private const int SW_MAXIMIZE = 3; //{同 SW_SHOWMAXIMIZED}
  195. private const int SW_SHOWNOACTIVATE = 4; //{用最近的大小和位置显示, 不激活}
  196. private const int SW_SHOW = 5; //{同 SW_SHOWNORMAL}
  197. private const int SW_MINIMIZE = 6; //{最小化, 不激活}
  198. private const int SW_SHOWMINNOACTIVE = 7; //{同 SW_MINIMIZE}
  199. private const int SW_SHOWNA = 8; //{同 SW_SHOWNOACTIVATE}
  200. private const int SW_RESTORE = 9; //{同 SW_SHOWNORMAL}
  201. private const int SW_SHOWDEFAULT = 10; //{同 SW_SHOWNORMAL}
  202. private const int SW_MAX = 10; //{同 SW_SHOWNORMAL}
  203. #endregion
  204. #region Win32 API 方法声明
  205. [DllImport("user32.dll", EntryPoint = "GetWindowThreadProcessId", SetLastError = true,
  206. CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
  207. private static extern long GetWindowThreadProcessId(long hWnd, long lpdwProcessId);
  208. [DllImport("user32.dll", SetLastError = true)]
  209. private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
  210. [DllImport("user32.dll", SetLastError = true)]
  211. public static extern long SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
  212. [DllImport("user32.dll", EntryPoint = "GetWindowLongA", SetLastError = true)]
  213. private static extern long GetWindowLong(IntPtr hwnd, int nIndex);
  214. public static IntPtr SetWindowLong(HandleRef hWnd, int nIndex, int dwNewLong)
  215. {
  216. if (IntPtr.Size == 4)
  217. {
  218. return SetWindowLongPtr32(hWnd, nIndex, dwNewLong);
  219. }
  220. return SetWindowLongPtr64(hWnd, nIndex, dwNewLong);
  221. }
  222. [DllImport("user32.dll", EntryPoint = "SetWindowLong", CharSet = CharSet.Auto)]
  223. public static extern IntPtr SetWindowLongPtr32(HandleRef hWnd, int nIndex, int dwNewLong);
  224. [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr", CharSet = CharSet.Auto)]
  225. public static extern IntPtr SetWindowLongPtr64(HandleRef hWnd, int nIndex, int dwNewLong);
  226. [DllImport("user32.dll", SetLastError = true)]
  227. private static extern long SetWindowPos(IntPtr hwnd, long hWndInsertAfter, long x, long y, long cx, long cy, long wFlags);
  228. [DllImport("user32.dll", SetLastError = true)]
  229. private static extern bool MoveWindow(IntPtr hwnd, int x, int y, int cx, int cy, bool repaint);
  230. [DllImport("user32.dll", EntryPoint = "PostMessageA", SetLastError = true)]
  231. private static extern bool PostMessage(IntPtr hwnd, uint Msg, uint wParam, uint lParam);
  232. [DllImport("user32.dll", SetLastError = true)]
  233. private static extern IntPtr GetParent(IntPtr hwnd);
  234. [DllImport("user32.dll", EntryPoint = "ShowWindow", SetLastError = true)]
  235. static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
  236. #endregion Win32 API
  237. }
  238. }