Skip to content

嵌入exe

约 800 字大约 3 分钟

winform

2024-03-16

引入外部exe操作

在 C# 中,可以使用 Process 类来启动并与外部应用程序进行交互。示例代码片段,可以用来将外部 EXE 文件加载到 WinForm 程序中,并与之交互:

using System;
using System.Diagnostics;
using System.Windows.Forms;

class Program
{
    static void Main(string[] args)
    {
        // 启动外部应用程序
        Process process = new Process();
        process.StartInfo.FileName = "notepad.exe"; // 替换为要启动的外部 EXE 文件名
        process.Start();

        // 等待应用程序启动
        process.WaitForInputIdle();

        // 将外部应用程序嵌入 WinForm 程序中
        IntPtr hProcess = process.Handle;
        IntPtr hParent = this.Handle; // 替换为 WinForm 窗体的句柄
        SetParent(hProcess, hParent);
        MoveWindow(hProcess, 0, 0, this.ClientSize.Width, this.ClientSize.Height, true);
    }

    // 导入 Win32 API 函数和常量
    [DllImport("user32.dll")]
    static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
    [DllImport("user32.dll")]
    static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
}

首先使用 Process 类启动外部应用程序,并等待它启动完成。然后,使用 SetParent 函数将外部应用程序的主窗口句柄设置为 WinForm 窗体的子窗口,并使用 MoveWindow 函数将其调整为与 WinForm 窗体相同的大小和位置。这样,外部应用程序将被嵌入到 WinForm 程序中,并可以与之交互。

监听指定程序事件(切换窗体焦点)

SetWinEventHook 函数是 Windows API 中的一个函数,用于设置一个钩子函数,以便在发生指定系统事件时通知指定的回调函数。 要监听指定进程切换了窗体,可以使用 SetWinEventHook 函数来设置一个钩子函数,以便在系统发送 EVENT_SYSTEM_FOREGROUND 系统事件时通知指定的回调函数。 示例代码片段,可以用来演示 SetWinEventHook 函数的用法,以便在指定进程切换窗体时输出一条消息:

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

class Program
{
    // 导入 Win32 API 函数和常量
    [DllImport("user32.dll")]
    static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags);
    [DllImport("user32.dll")]
    static extern bool UnhookWinEvent(IntPtr hWinEventHook);
    const uint EVENT_SYSTEM_FOREGROUND = 3;

    // 定义 WinEventDelegate 委托类型
    delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);

    static void Main(string[] args)
    {
        int processId = 1234; // 替换为要监听窗体切换的进程 ID

        // 创建 WinEventDelegate 委托实例
        WinEventDelegate winEventDelegate = new WinEventDelegate(WinEventCallback);

        // 设置系统事件钩子
        IntPtr hWinEventHook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, winEventDelegate, (uint)processId, 0, 0);

        // 等待用户按下 Enter 键退出程序
        Console.ReadLine();

        // 卸载系统事件钩子 
        UnhookWinEvent(hWinEventHook);
    }

    static void WinEventCallback(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
    {
        Console.WriteLine("窗体切换了:{0}", hwnd);
    }
}

首先使用进程 ID 创建一个 WinEventDelegate 委托实例。然后,我们使用 SetWinEventHook 函数来设置一个 EVENT_SYSTEM_FOREGROUND 系统事件的钩子,并将委托实例传递给它。此钩子将在指定进程切换窗体时触发,并将其相关参数传递给委托实例。在 WinEventCallback 回调函数中,我们输出了窗体句柄。

    /// 根据进程id和句柄获取窗口下的控件
    public void GetWindowChild(int processId,IntPtr handle)
        {
            Thread.Sleep(500);
            // 获取进程的所有窗口句柄,包括子窗口
            IntPtr currentWindowHandle = GetWindow(handle, 5 /* GW_CHILD */);
            while (currentWindowHandle != IntPtr.Zero)
            {
                uint processIdForWindow;
                GetWindowThreadProcessId(currentWindowHandle, out processIdForWindow);

                if (processIdForWindow == processId)
                {
                    Debug.WriteLine(currentWindowHandle);
                    ShowWindowAsync(currentWindowHandle, SW_HIDE);
                 
                }

                currentWindowHandle = GetWindow(currentWindowHandle, 2 /* GW_HWNDNEXT */);
            }
        }