EmbedPanel.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  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 (m_AppProcess == null || m_AppProcess.HasExited)
  34. {
  35. m_AppProcess = null;
  36. Application.Idle -= appIdleEvent;
  37. return;
  38. }
  39. if (m_AppProcess.MainWindowHandle == IntPtr.Zero) return;
  40. Application.Idle -= appIdleEvent;
  41. EmbedProcess(m_AppProcess, this);
  42. }
  43. /// <summary>
  44. /// 应用程序结束运行时要清除这里的标识
  45. /// </summary>
  46. /// <param name="sender"></param>
  47. /// <param name="e"></param>
  48. void m_AppProcess_Exited(object sender, EventArgs e)
  49. {
  50. m_AppProcess = null;
  51. }
  52. #region 属性
  53. /// <summary>
  54. /// application process
  55. /// </summary>
  56. Process m_AppProcess = null;
  57. public Process AppProcess
  58. {
  59. get { return this.m_AppProcess; }
  60. set { this.m_AppProcess = value; }
  61. }
  62. /// <summary>
  63. /// 要嵌入的程序文件名
  64. /// </summary>
  65. private string m_AppFilename = "";
  66. /// <summary>
  67. /// 要嵌入的程序文件名
  68. /// </summary>
  69. [Category("Data")]
  70. [Description("要嵌入的程序文件名")]
  71. [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
  72. //[Editor(typeof(AppFilenameEditor), typeof(UITypeEditor))]
  73. public string AppFilename
  74. {
  75. get
  76. {
  77. return m_AppFilename;
  78. }
  79. set
  80. {
  81. if (value == null || value == m_AppFilename) return;
  82. var self = Application.ExecutablePath;
  83. if (value.ToLower() == self.ToLower())
  84. {
  85. MessageBox.Show("不能自己嵌入自己!", "SmileWei.EmbeddedApp");
  86. return;
  87. }
  88. if (!value.ToLower().EndsWith(".exe"))
  89. {
  90. MessageBox.Show("要嵌入的文件扩展名不是exe!", "SmileWei.EmbeddedApp");
  91. }
  92. if (!File.Exists(value))
  93. {
  94. MessageBox.Show("要嵌入的程序不存在!", "SmileWei.EmbeddedApp");
  95. return;
  96. }
  97. m_AppFilename = value;
  98. }
  99. }
  100. /// <summary>
  101. /// 标识内嵌程序是否已经启动
  102. /// </summary>
  103. public bool IsStarted { get { return (m_AppProcess != null); } }
  104. #endregion 属性
  105. /// <summary>
  106. /// 启动嵌入程序并嵌入到控件
  107. /// </summary>
  108. /// <param name="appFilename"></param>
  109. public void Start(string appFilename)
  110. {
  111. AppFilename = appFilename;
  112. Start();
  113. }
  114. public void Start()
  115. {
  116. //停止正在运行的进程
  117. if (m_AppProcess != null) Stop();
  118. try
  119. {
  120. ProcessStartInfo info = new ProcessStartInfo(m_AppFilename);
  121. info.UseShellExecute = true;
  122. info.WindowStyle = ProcessWindowStyle.Minimized;
  123. //info.WindowStyle = ProcessWindowStyle.Hidden;
  124. m_AppProcess = Process.Start(info);
  125. //等待创建进程
  126. m_AppProcess.WaitForInputIdle();
  127. //todo:下面这两句会引发 NullReferenceException 异常,不知道怎么回事
  128. //m_AppProcess.Exited += new EventHandler(m_AppProcess_Exited);
  129. //m_AppProcess.EnableRaisingEvents = true;
  130. Application.Idle += appIdleEvent;
  131. //EmbedProcess(m_AppProcess, this);
  132. }
  133. catch (Exception ex)
  134. {
  135. //嵌入失败杀死进程
  136. if (m_AppProcess != null)
  137. {
  138. if (!m_AppProcess.HasExited)
  139. m_AppProcess.Kill();
  140. m_AppProcess = null;
  141. }
  142. }
  143. }
  144. /// <summary>
  145. /// 重新嵌入
  146. /// </summary>
  147. public void ReEmbed()
  148. {
  149. EmbedProcess(m_AppProcess, this);
  150. }
  151. /// <summary>
  152. /// 退出嵌入的程序
  153. /// </summary>
  154. public void Stop()
  155. {
  156. if (m_AppProcess != null)// && m_AppProcess.MainWindowHandle != IntPtr.Zero)
  157. {
  158. try
  159. {
  160. if (!m_AppProcess.HasExited)
  161. m_AppProcess.Kill();
  162. }
  163. catch (Exception) { }
  164. m_AppProcess = null;
  165. }
  166. }
  167. /// <summary>
  168. /// 将程序嵌入控件
  169. /// </summary>
  170. /// <param name="app">嵌入程序</param>
  171. /// <param name="control">指定控件</param>
  172. private void EmbedProcess(Process app, Control control)
  173. {
  174. //验证程序和控件非空
  175. if (app == null || app.MainWindowHandle == IntPtr.Zero || control == null) return;
  176. try
  177. {
  178. //核心代码:嵌入程序
  179. SetParent(app.MainWindowHandle, control.Handle);
  180. }
  181. catch (Exception) { }
  182. try
  183. {
  184. //移除嵌入的窗口的窗口标题栏
  185. SetWindowLong(new HandleRef(this, app.MainWindowHandle), GWL_STYLE, WS_VISIBLE);
  186. }
  187. catch (Exception) { }
  188. try
  189. {
  190. //将嵌入的窗口欧放置到合适位置,填满宽高
  191. MoveWindow(app.MainWindowHandle, 0, 0, control.Width, control.Height, true);
  192. }
  193. catch (Exception) { }
  194. }
  195. #region 重写部分方法
  196. /// <summary>
  197. /// 窗体句柄销毁
  198. /// </summary>
  199. /// <param name="e"></param>
  200. protected override void OnHandleDestroyed(EventArgs e)
  201. {
  202. Stop();//将应用关闭
  203. base.OnHandleDestroyed(e);
  204. }
  205. /// <summary>
  206. /// 窗体大小修改
  207. /// </summary>
  208. /// <param name="eventargs"></param>
  209. protected override void OnResize(EventArgs eventargs)
  210. {
  211. if (m_AppProcess != null)
  212. {
  213. MoveWindow(m_AppProcess.MainWindowHandle, 0, 0, this.Width, this.Height, true);
  214. }
  215. base.OnResize(eventargs);
  216. }
  217. /// <summary>
  218. /// 窗台属性修改
  219. /// </summary>
  220. /// <param name="e"></param>
  221. protected override void OnSizeChanged(EventArgs e)
  222. {
  223. this.Invalidate();
  224. base.OnSizeChanged(e);
  225. }
  226. #endregion
  227. #region Win32 API 常量
  228. private const int SWP_NOOWNERZORDER = 0x200;
  229. private const int SWP_NOREDRAW = 0x8;
  230. private const int SWP_NOZORDER = 0x4;
  231. private const int SWP_SHOWWINDOW = 0x0040;
  232. private const int WS_EX_MDICHILD = 0x40;
  233. private const int SWP_FRAMECHANGED = 0x20;
  234. private const int SWP_NOACTIVATE = 0x10;
  235. private const int SWP_ASYNCWINDOWPOS = 0x4000;
  236. private const int SWP_NOMOVE = 0x2;
  237. private const int SWP_NOSIZE = 0x1;
  238. private const int GWL_STYLE = (-16);
  239. private const int WS_VISIBLE = 0x10000000;
  240. private const int WM_CLOSE = 0x10;
  241. private const int WS_CHILD = 0x40000000;
  242. private const int SW_HIDE = 0; //{隐藏, 并且任务栏也没有最小化图标}
  243. private const int SW_SHOWNORMAL = 1; //{用最近的大小和位置显示, 激活}
  244. private const int SW_NORMAL = 1; //{同 SW_SHOWNORMAL}
  245. private const int SW_SHOWMINIMIZED = 2; //{最小化, 激活}
  246. private const int SW_SHOWMAXIMIZED = 3; //{最大化, 激活}
  247. private const int SW_MAXIMIZE = 3; //{同 SW_SHOWMAXIMIZED}
  248. private const int SW_SHOWNOACTIVATE = 4; //{用最近的大小和位置显示, 不激活}
  249. private const int SW_SHOW = 5; //{同 SW_SHOWNORMAL}
  250. private const int SW_MINIMIZE = 6; //{最小化, 不激活}
  251. private const int SW_SHOWMINNOACTIVE = 7; //{同 SW_MINIMIZE}
  252. private const int SW_SHOWNA = 8; //{同 SW_SHOWNOACTIVATE}
  253. private const int SW_RESTORE = 9; //{同 SW_SHOWNORMAL}
  254. private const int SW_SHOWDEFAULT = 10; //{同 SW_SHOWNORMAL}
  255. private const int SW_MAX = 10; //{同 SW_SHOWNORMAL}
  256. #endregion
  257. #region Win32 API 方法声明
  258. [DllImport("user32.dll", EntryPoint = "GetWindowThreadProcessId", SetLastError = true,
  259. CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
  260. private static extern long GetWindowThreadProcessId(long hWnd, long lpdwProcessId);
  261. [DllImport("user32.dll", SetLastError = true)]
  262. private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
  263. [DllImport("user32.dll", SetLastError = true)]
  264. public static extern long SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
  265. [DllImport("user32.dll", EntryPoint = "GetWindowLongA", SetLastError = true)]
  266. private static extern long GetWindowLong(IntPtr hwnd, int nIndex);
  267. public static IntPtr SetWindowLong(HandleRef hWnd, int nIndex, int dwNewLong)
  268. {
  269. if (IntPtr.Size == 4)
  270. {
  271. return SetWindowLongPtr32(hWnd, nIndex, dwNewLong);
  272. }
  273. return SetWindowLongPtr64(hWnd, nIndex, dwNewLong);
  274. }
  275. [DllImport("user32.dll", EntryPoint = "SetWindowLong", CharSet = CharSet.Auto)]
  276. public static extern IntPtr SetWindowLongPtr32(HandleRef hWnd, int nIndex, int dwNewLong);
  277. [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr", CharSet = CharSet.Auto)]
  278. public static extern IntPtr SetWindowLongPtr64(HandleRef hWnd, int nIndex, int dwNewLong);
  279. [DllImport("user32.dll", SetLastError = true)]
  280. private static extern long SetWindowPos(IntPtr hwnd, long hWndInsertAfter, long x, long y, long cx, long cy, long wFlags);
  281. [DllImport("user32.dll", SetLastError = true)]
  282. private static extern bool MoveWindow(IntPtr hwnd, int x, int y, int cx, int cy, bool repaint);
  283. [DllImport("user32.dll", EntryPoint = "PostMessageA", SetLastError = true)]
  284. private static extern bool PostMessage(IntPtr hwnd, uint Msg, uint wParam, uint lParam);
  285. [DllImport("user32.dll", SetLastError = true)]
  286. private static extern IntPtr GetParent(IntPtr hwnd);
  287. [DllImport("user32.dll", EntryPoint = "ShowWindow", SetLastError = true)]
  288. static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
  289. #endregion Win32 API
  290. }
  291. }