首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> VC 教學

VC++ 與 Delphi 通用單一實例技術:具名互斥體跨語言實戰

     編輯:VC 教學

核心原理:CreateMutex 全系統唯一命名

互斥體核心層面作業系統物件,跨語言、跨編譯器、跨進程邊界通用。CreateMutex 參數:

  • lpMutexAttributes:安全屬性,NULL=不可繼承
  • bInitialOwner:FALSE=建立者不立即擁有
  • lpName:全系統唯一名稱,建議格式 Global\\AppName_GUID

判斷邏輯

HANDLE hMutex = CreateMutex(NULL, FALSE, szUniqueName);
if (hMutex == NULL) {
    // 建立失敗 (權限/資源不足)
    ExitProcess(1);
}
if (GetLastError() == ERROR_ALREADY_EXISTS) {
    // 已有同名互斥體 = 已有實例在執行
    CloseHandle(hMutex);
    // 可選:尋找既有視窗並置前
    ExitProcess(0);
}
// 首次實例,繼續執行...
// 程式結束前 CloseHandle(hMutex);

VC++ 完整實作 (Win32 SDK 純 C)

#include <windows.h>

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, int nCmdShow) {
    const char* MUTEX_NAME = "Global\\MyVCApp_UniqueID_{12345678-ABCD-EF01-2345-6789ABCDEF00}";
    HANDLE hMutex = CreateMutex(NULL, FALSE, MUTEX_NAME);
    
    if (hMutex == NULL) {
        MessageBox(NULL, "建立互斥體失敗", "錯誤", MB_OK | MB_ICONERROR);
        return 1;
    }
    
    if (GetLastError() == ERROR_ALREADY_EXISTS) {
        MessageBox(NULL, "程式已在執行中!", "提示", MB_OK | MB_ICONINFORMATION);
        CloseHandle(hMutex);
        return 0;
    }
    
    // 首次實例主邏輯
    MessageBox(NULL, "首次啟動成功", "歡迎", MB_OK);
    
    // 模擬主迴圈
    Sleep(5000);
    
    CloseHandle(hMutex);
    return 0;
}

MFC 版本 (整合視窗置前)

// MyApp.cpp
BOOL CMyApp::InitInstance() {
    const TCHAR* MUTEX_NAME = _T("Global\\MyMFCApp_{GUID}");
    m_hMutex = CreateMutex(NULL, FALSE, MUTEX_NAME);
    
    if (GetLastError() == ERROR_ALREADY_EXISTS) {
        // 找到既有主視窗並置前
        CWnd* pWnd = CWnd::FindWindow(_T("MyMainFrameClass"), NULL);
        if (pWnd) {
            CWnd* pPopup = pWnd->GetLastActivePopup();
            if (pWnd->IsIconic()) pWnd->ShowWindow(SW_RESTORE);
            pPopup->SetForegroundWindow();
        }
        CloseHandle(m_hMutex);
        return FALSE;
    }
    // ... 正常初始化 ...
    return TRUE;
}

int CMyApp::ExitInstance() {
    if (m_hMutex) CloseHandle(m_hMutex);
    return CWinApp::ExitInstance();
}

Delphi 完整實作

program OnlyOneInstance;

uses
  Windows, Forms, SysUtils, uMain in 'uMain.pas' {FormMain};

{$R *.res}

var
  hAppMutex: THandle;
  MutexName: string;

begin
  MutexName := 'Global\MyDelphiApp_UniqueID_{GUID}';
  
  // 必須在 Application.Initialize 之前建立互斥體
  hAppMutex := CreateMutex(nil, False, PChar(MutexName));
  
  if (hAppMutex = 0) then begin
    MessageBox(0, '建立互斥體失敗!', '錯誤', MB_OK + MB_ICONERROR);
    Exit;
  end;
  
  if GetLastError = ERROR_ALREADY_EXISTS then begin
    MessageBox(0, '程式已在執行中!', '提示', MB_OK + MB_ICONINFORMATION);
    CloseHandle(hAppMutex);
    Exit;
  end;
  
  Application.Initialize;
  Application.CreateForm(TFormMain, FormMain);
  Application.Run;
  
  // 正常結束釋放
  CloseHandle(hAppMutex);
end.

關鍵注意事項 (跨語言通用)

項目說明
名稱唯一性使用 GUID + Global\\ 前綴,避免衝突並支援終端機多 Session
建立時機越早越好:WinMain 進入點 / MFC InitInstance 最前 / Delphi .dpr 開頭
錯誤碼檢查時機緊接著 CreateMutex 呼叫 GetLastError,中間不可插入其他 API 呼叫
釋放時機進程正常結束前 CloseHandle;異常結束 OS 會自動釋放
跨 Session 隔離無 Global\\ 前綴時,各 Terminal Services Session 互斥體獨立
惡意阻斷防護數位簽章驗證 + 互斥體名稱加密/混淆,防止惡意程式預先建立同名互斥體

進階:第二次啟動傳遞命令列參數

若需「雙擊關聯檔案 → 傳遞參數給主實例」:

  1. 主實例建立命名管道 \\.\pipe\MyApp_CmdPipe 執行緒監聽
  2. 第二實例偵測到互斥體存在 → 連接管道 → 寫入命令列 → 退出
  3. 主實例收到命令 → 解析執行 (開啟檔案、新增下載等)

掌握具名互斥體單一實例模式,您的 VC++ 與 Delphi 程式都將具備專業級的進程管理能力。

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