LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

在C# WinForms中嵌入和控制外部程序的完整指南

admin
2025年5月25日 21:4 本文热度 138

在开发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
{
    publicclass ExternalProcessManager
    {

        // Windows API 常量  
        privateconstint GWL_STYLE = -16;
        privateconstint WS_CHILD = 0x40000000;
        privateconstint WS_VISIBLE = 0x10000000;

        // Windows API 声明  
        privatestaticclass 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)
                    {
                        thrownew 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,
                    00,
                    _parentControl.ClientSize.Width,
                    _parentControl.ClientSize.Height,
                    true
                );

                // 确保父控件在尺寸变化时调整嵌入程序的大小  
                _parentControl.SizeChanged += (sender, e) =>
                {
                    if (_embeddedProcess != null && !_embeddedProcess.HasExited)
                    {
                        WindowsAPI.MoveWindow(
                            _embeddedProcess.MainWindowHandle,
                            00,
                            _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(300400),
            Location = new Point(1010)
        };
        this.Controls.Add(_calcPanel);

        _processManager = new ExternalProcessManager(_calcPanel);

        Button embedButton = new Button
        {
            Text = "嵌入计算器",
            Location = new Point(32010)
        };
        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, 
            00, _parentControl.Width, _parentControl.Height, true);
    }
}

总结

通过本文的详细介绍和示例,你应该能够在C# WinForms应用程序中成功实现外部程序的嵌入和控制。记住要注意进程管理、窗口处理、性能优化和安全性等关键方面。合理使用这些技术可以帮助你创建更强大和灵活的应用程序。


阅读原文:原文链接


该文章在 2025/5/26 10:23:05 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2025 ClickSun All Rights Reserved