首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 單一實例應用程式與自訂訊息跨進程通訊實作

     編輯:關於C#

當應用程式關聯檔案類型時,雙擊檔案若程式已在執行,應啟動現有實例開啟檔案而非新建進程。本文示範如何用 自訂 Windows 訊息 實現單一實例與跨進程檔案列表傳遞。

核心架構

  • Program.Main:啟動時檢查同名進程,若存在則發送自訂訊息並退出。
  • SingleInstanceHelper:封裝尋找進程、發送訊息、臨時檔案交換資料邏輯。
  • 主視窗 WndProc:覆寫 WndProc 接收自訂訊息,解析臨時檔案並開啟檔案。

自訂訊息定義

private static readonly int CUSTOM_MESSAGE = 0x400 + 2; // WM_USER + 2
private static readonly int RESULT_FILES_HANDLED = 2;

啟動邏輯:發送端

public static bool OpenFilesInPreviousInstance(string[] fileList) {
    int currentPid = Process.GetCurrentProcess().Id;
    string currentExe = Assembly.GetEntryAssembly().Location;
    string tempFile = Path.Combine(Path.GetTempPath(), $"sd{new Random().Next()}.tmp");

    try {
        File.WriteAllLines(tempFile, fileList); // 將檔案列表寫入暫存檔

        foreach (Process p in Process.GetProcessesByName("MyApplication")) {
            if (p.Id == currentPid) continue;
            if (string.Equals(currentExe, p.MainModule.FileName, StringComparison.OrdinalIgnoreCase)) {
                IntPtr hWnd = p.MainWindowHandle;
                if (hWnd != IntPtr.Zero) {
                    long result = NativeMethods.SendMessage(hWnd, CUSTOM_MESSAGE, new IntPtr(tempFile.GetHashCode()), IntPtr.Zero).ToInt64();
                    if (result == RESULT_FILES_HANDLED) return true;
                }
            }
        }
        return false;
    } finally {
        File.Delete(tempFile);
    }
}

接收端:WndProc 處理

protected override void WndProc(ref Message m) {
    if (!SingleInstanceHelper.PreFilterMessage(ref m, this))
        base.WndProc(ref m);
}

internal static bool PreFilterMessage(ref Message m, Form mainForm) {
    if (m.Msg != CUSTOM_MESSAGE) return false;

    long fileNumber = m.WParam.ToInt64();
    m.Result = new IntPtr(RESULT_FILES_HANDLED);

    try {
        // 切換到前景
        mainForm.Invoke((MethodInvoker)delegate {
            NativeMethods.SetForegroundWindow(mainForm.Handle);
        });

        string tempFile = Path.Combine(Path.GetTempPath(), $"sd{fileNumber}.tmp");
        foreach (string file in File.ReadAllLines(tempFile)) {
            mainForm.Invoke((MethodInvoker)delegate {
                // 開啟檔案邏輯
            });
        }
        return true;
    } catch { return false; }
}

關鍵設計決策

  • 使用 臨時檔案 而非 Marshal 跨進程傳遞複雜型別,避免序列化與安全性問題。
  • 隨機檔名避免衝突,處理完成即刪除。
  • SetForegroundWindow 確保舊實例取得焦點。
  • 適用於 WinForms、WPF 等所有基於訊息迴圈的桌面應用。

此模式廣泛應用於 Visual Studio、瀏覽器、編輯器等專業軟體,是單一實例應用的標準解法。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved