在开发Windows桌面应用程序时,我们经常需要在自己的应用程序中嵌入并控制其他可执行程序。本文将详细介绍如何在C# WinForms应用程序中实现这一功能,并提供多个实用示例。 
基本概念 嵌入外部程序意味着将其他Windows应用程序的窗口作为子窗口嵌入到我们的WinForms应用程序中。这种技术通常用于: 
集成第三方工具 创建复合应用程序 提供统一的用户界面 控制和管理多个应用程序 技术实现 基本实现类 创建一个专门用于管理嵌入程序的类: 
using  System; using  System.Collections.Generic; using  System.Diagnostics; using  System.Linq; using  System.Runtime.InteropServices; using  System.Text; using  System.Threading.Tasks; namespace  AppEmbedding {      public class   ExternalProcessManager     {          // Windows API 常量            private const int  GWL_STYLE =  -16 ;          private const int  WS_CHILD =  0x40000000 ;          private const int  WS_VISIBLE =  0x10000000 ;          // Windows API 声明            private static class   WindowsAPI         {             [DllImport( "user32.dll" )]              public   static   extern  IntPtr  SetParent (IntPtr hWndChild, IntPtr hWndNewParent) ;             [DllImport( "user32.dll" )]              public   static   extern   int   GetWindowLong (IntPtr hWnd,  int  nIndex) ;             [DllImport( "user32.dll" )]              public   static   extern   int   SetWindowLong (IntPtr hWnd,  int  nIndex,  int  dwNewLong) ;             [DllImport( "user32.dll" )]              public   static   extern   bool   ShowWindow (IntPtr hWnd,  int  nCmdShow) ;             [DllImport( "user32.dll" )]              public   static   extern   bool   MoveWindow (IntPtr hWnd,  int  X,  int  Y,  int  nWidth,  int  nHeight,  bool  bRepaint) ;         }          private  Process _embeddedProcess;          private  Control _parentControl;          public   ExternalProcessManager (Control parentControl)          {             _parentControl = parentControl;         }          public   void   EmbedProcess ( string  processPath)          {              try             {                  // 启动进程 - 使用 UseShellExecute = false 可能对某些应用程序更有效                   ProcessStartInfo startInfo =  new  ProcessStartInfo(processPath)                 {                     UseShellExecute =  false ,                     CreateNoWindow =  false                 };                 _embeddedProcess = Process.Start(startInfo);                  // 使用超时机制等待窗口句柄创建,避免无限等待                   _embeddedProcess.WaitForInputIdle( 3000 );                  // 设置等待主窗口句柄的超时时间                   DateTime timeout = DateTime.Now.AddSeconds( 5 );                  while  (_embeddedProcess.MainWindowHandle == IntPtr.Zero)                 {                      if  (DateTime.Now > timeout)                     {                          throw new  TimeoutException( "无法获取进程主窗口句柄" );                     }                     Application.DoEvents();  // 保持UI响应                       System.Threading.Thread.Sleep( 100 );                 }                  // 设置父窗口                   WindowsAPI.SetParent(_embeddedProcess.MainWindowHandle, _parentControl.Handle);                  // 设置窗口样式                    int  style = WindowsAPI.GetWindowLong(_embeddedProcess.MainWindowHandle, GWL_STYLE);                 style |= WS_CHILD | WS_VISIBLE;  // 添加WS_VISIBLE确保窗口可见                   WindowsAPI.SetWindowLong(_embeddedProcess.MainWindowHandle, GWL_STYLE, style);                  // 调整窗口位置和大小                   WindowsAPI.MoveWindow(                     _embeddedProcess.MainWindowHandle,                      0 ,  0 ,                     _parentControl.ClientSize.Width,                     _parentControl.ClientSize.Height,                      true                 );                  // 确保父控件在尺寸变化时调整嵌入程序的大小                   _parentControl.SizeChanged += (sender, e) =>                 {                      if  (_embeddedProcess != null && !_embeddedProcess.HasExited)                     {                         WindowsAPI.MoveWindow(                             _embeddedProcess.MainWindowHandle,                              0 ,  0 ,                             _parentControl.ClientSize.Width,                             _parentControl.ClientSize.Height,                              true                         );                     }                 };             }              catch  (Exception ex)             {                 MessageBox.Show($ "嵌入进程时出错: {ex.Message}" ,  "错误" , MessageBoxButtons.OK, MessageBoxIcon.Error);             }         }          public   void   CloseEmbeddedProcess ()          {              if  (_embeddedProcess != null && !_embeddedProcess.HasExited)             {                  try                 {                     _embeddedProcess.CloseMainWindow();                      if  (!_embeddedProcess.WaitForExit( 3000 ))                     {                         _embeddedProcess.Kill();                     }                 }                  catch  (Exception ex)                 {                     MessageBox.Show($ "关闭进程时出错: {ex.Message}" ,  "错误" , MessageBoxButtons.OK, MessageBoxIcon.Error);                 }                 finally                 {                     _embeddedProcess.Dispose();                     _embeddedProcess = null;                 }             }         }     } } 实际应用示例 嵌入记事本示例 public  partial  class   NotePadForm  :  Form {      private  ExternalProcessManager _processManager;      public   NotePadForm ()      {         InitializeComponent();          // 创建一个Panel用于容纳记事本         Panel notepadPanel =  new  Panel         {             Dock = DockStyle.Fill         };          this .Controls.Add(notepadPanel);         _processManager =  new  ExternalProcessManager(notepadPanel);     }      private   void   btnEmbedNotepad_Click (object sender, EventArgs e)      {         _processManager.EmbedProcess( "notepad.exe" );     }      protected  override  void   OnFormClosing (FormClosingEventArgs e)      {         _processManager.CloseEmbeddedProcess();         base.OnFormClosing(e);     } } 
嵌入计算器示例 public  partial  class   CalculatorForm  :  Form {      private  ExternalProcessManager _processManager;      private  Panel _calcPanel;      public   CalculatorForm ()      {         InitializeComponent();          // 创建计算器面板         _calcPanel =  new  Panel         {             Size =  new  Size( 300 ,  400 ),             Location =  new  Point( 10 ,  10 )         };          this .Controls.Add(_calcPanel);         _processManager =  new  ExternalProcessManager(_calcPanel);         Button embedButton =  new  Button         {             Text =  "嵌入计算器" ,             Location =  new  Point( 320 ,  10 )         };         embedButton.Click += EmbedCalculator_Click;          this .Controls.Add(embedButton);     }      private   void   EmbedCalculator_Click (object sender, EventArgs e)      {         _processManager.EmbedProcess( "calc.exe" );     }      protected  override  void   OnFormClosing (FormClosingEventArgs e)      {         _processManager.CloseEmbeddedProcess();         base.OnFormClosing(e);     } } 常见问题解决 窗口无法正确嵌入 
// 确保等待窗口句柄创建 while  (process.MainWindowHandle == IntPtr.Zero) {     System.Threading.Thread.Sleep( 100 );     process.Refresh(); } DPI缩放问题 
protected  override  void   OnLoad (EventArgs e) {     base.OnLoad(e);      if  (Environment.OSVersion.Version.Major >=  6 )     {         SetProcessDPIAware();     } } [DllImport( "user32.dll" )] private   static   extern   bool   SetProcessDPIAware () ; 窗口大小调整 
protected  override  void   OnResize (EventArgs e) {     base.OnResize(e);      if  (_embeddedProcess != null && !_embeddedProcess.HasExited)     {         WindowsAPI.MoveWindow(_embeddedProcess.MainWindowHandle,               0 ,  0 , _parentControl.Width, _parentControl.Height,  true );     } } 总结 通过本文的详细介绍和示例,你应该能够在C# WinForms应用程序中成功实现外部程序的嵌入和控制。记住要注意进程管理、窗口处理、性能优化和安全性等关键方面。合理使用这些技术可以帮助你创建更强大和灵活的应用程序。 
阅读原文:原文链接 
 该文章在 2025/5/26 10:23:05 编辑过