首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 更多程式設計知識

C# 啟動外部程式並等待視窗就緒:Process + FindWindow 實作範例

     編輯:更多程式設計知識

需求

啟動指定執行檔 (含參數),偵測主視窗建立完成,取得視窗句柄 (HWND) 以便後續 SendMessage 互動。

完整程式碼

private void btnCreate_Click(object sender, EventArgs e) {
    // 1. 檢查是否已啟動 (避免重複)
    int hWnd = FindWindow(null, "PowerReuse (Beta)"); // 視窗標題
    if (hWnd > 0) {
        MessageBox.Show("程式已執行,HWND=" + hWnd);
        return;
    }

    try {
        Process proc = new Process();
        proc.StartInfo.FileName = @"C:\Test.exe";           // 目標執行檔
        proc.StartInfo.Arguments = @"C:\Temp\abc.prj";      // 命令列參數
        proc.StartInfo.UseShellExecute = true;              // 使用 Shell 執行 (關聯檔案類型)
        proc.Start();

        // 2. 等待輸入閒置 (視窗初始化完成)
        proc.WaitForInputIdle(10000); // 10 秒逾時

        // 3. 輪詢尋找主視窗句柄
        for (int i = 0; i < 100; i++) {
            hWnd = FindWindow(null, "PowerReuse (Beta)");
            if (hWnd > 0) break;
            Thread.Sleep(100);
        }

        if (hWnd == 0) {
            MessageBox.Show("找不到主視窗句柄");
        } else {
            MessageBox.Show($"HWND={hWnd}, Process.Handle={proc.MainWindowHandle}, Title={proc.MainWindowTitle}");
            // 後續可用 SendMessage/PostMessage 與視窗互動
        }
    } catch (Exception ex) {
        MessageBox.Show("啟動失敗: " + ex.Message);
    }
}

// P/Invoke 宣告
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
private static extern int FindWindow(string lpClassName, string lpWindowName);

關鍵技術點

技術說明
Process.StartInfo設定檔案、參數、工作目錄、動詞、視窗樣式等。
UseShellExecute=true透過 Shell 執行,支援關聯檔案 (如 .html 開瀏覽器)、UAC 提權。
WaitForInputIdle等待進程進入訊息迴圈閒置狀態,代表主視窗已建立 (但不保證完全繪製完成)。
FindWindowWin32 API,依類別名/視窗標題尋找頂層視窗句柄。類別名可為 null。
輪詢迴圈視窗建立有時序差異,輪詢 100ms × 100 次 = 10 秒容錯。

進階:取得子視窗/控制項句柄

[DllImport("user32.dll")]
static extern int FindWindowEx(int hwndParent, int hwndChildAfter, string lpszClass, string lpszWindow);

// 遞迴尋找特定控制項
int FindChild(int parent, string className, string title) {
    int child = FindWindowEx(parent, 0, className, title);
    if (child != 0) return child;
    // 遞迴搜尋子孫...
    return 0;
}

常見問題

  • 視窗標題不固定:改用類別名 (FindWindow("MyClass", null)) 或 EnumWindows 回呼比對。
  • 多重視窗:FindWindow 只回傳第一個,需 EnumWindows 列舉全部。
  • 權限隔離:啟動進程若為高權限 (UAC),低權限呼叫端無法 SendMessage,需同權限或 ChangeWindowMessageFilterEx。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved