0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

日記 Visual Studio 2019 C++ Windowsアプリの二重起動を防止する方法を調べた

Last updated at Posted at 2021-08-03

概要

多重起動を防止する方法には、Atomを使用する、Mutexを使用する、MFCを使用する、といった方法があるらしいのですが、よく分からなかったので、exe名からプロセスの存在チェックをする方法を取りました。

処理概要

  • 自分のプロセスIDから自分のexe名を取得
  • 同じexe名のプロセスIDを全て取得
  • 自分以外のプロセスIDが既にあった場合
    • タスクトレイの中に入っている場合、元のサイズに戻す
    • フォアグラウンドにする

プログラム

起動時の初期処理に追加

Sample.cpp
// グローバル変数
// プロセスIDからウインドウハンドルを取得用
HWND hWnd_existed;

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
    _In_opt_ HINSTANCE hPrevInstance,
    _In_ LPWSTR    lpCmdLine,
    _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // ------------------------------------------------------------------------
    // 二重起動防止
    // ------------------------------------------------------------------------

    // 自分のプロセスIDから自分のexe名を取得
    DWORD dwCurrentProcessId = GetCurrentProcessId();
    HANDLE hProcess = OpenProcess(
        PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
        FALSE,
        dwCurrentProcessId
    );
    TCHAR szModuleName[MAX_PATH];
    GetModuleBaseName(hProcess, NULL, szModuleName, MAX_PATH);

    // 自分のexe名と同じプロセスのプロセスIDを取得(自分のプロセスIDは除く)
    DWORD dwExeProcessIds[1024] = { 0 };
    GetExeOtherProcessIds(szModuleName, dwExeProcessIds, dwCurrentProcessId);

    // 既に起動済みだった場合
    if (0 < dwExeProcessIds[0])
    {
        // プロセスIDからウインドウハンドルを取得
        EnumWindows(EnumWindowsProcMy, dwExeProcessIds[0]);
        if (hWnd_existed)
        {
            // タスクトレイの中に入っている場合、元のサイズに戻す
            if (IsIconic(hWnd_existed))
            {
                ShowWindow(hWnd_existed, SW_RESTORE);
            }
            else
            {
                // 見つかったウィンドウをフォアグラウンドにする
                SetForegroundWindow(GetLastActivePopup(hWnd_existed));
            }
        }
        return FALSE;
    }

EXE名から同じEXE名のプロセスIDを取得する関数

Sample.cpp
// sTargetExeNameのプロセスIDをdwExeProcessIdsに設定
// dwIgnoreProcessIdのプロセスIDは除外
VOID GetExeOtherProcessIds(CString sTargetExeName, DWORD* dwExeProcessIds, DWORD dwIgnoreProcessId)
{
    DWORD dwAllProcessIds[1024] = { 0 };
    DWORD cbNeeded = 0;
    if (!EnumProcesses(dwAllProcessIds, sizeof(dwAllProcessIds), &cbNeeded))
    {
        return;
    }

    int j = 0;
    int nProc = cbNeeded / sizeof(DWORD);
    for (int i = 0; i < nProc; i++)
    {
        if (dwAllProcessIds[i] == dwIgnoreProcessId)
        {
            continue;
        }

        TCHAR szProcessName[MAX_PATH] = TEXT("<unknown>");

        // Get a handle to the process.
        HANDLE hProcess = OpenProcess(
            PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
            FALSE,
            dwAllProcessIds[i]
        );

        // Get the process name.
        if (hProcess)
        {
            HMODULE hMod;
            DWORD cbNeeded;

            if (EnumProcessModules(hProcess, &hMod, sizeof(hMod),
                &cbNeeded))
            {
                GetModuleBaseName(hProcess, hMod, szProcessName,
                    sizeof(szProcessName) / sizeof(TCHAR));

                CString sProcName = CString(szProcessName).MakeUpper();
                if (sProcName == sTargetExeName.MakeUpper())
                {
                    dwExeProcessIds[j] = dwAllProcessIds[i];
                    ++j;
                }
            }

            // Release the handle to the process.
            CloseHandle(hProcess);
        }
    }
}

プロセスIDからウインドウハンドルを取得する関数

Sample.cpp
// プロセスIDからウインドウハンドルを取得
// https://stackoverflow.com/questions/11711417/get-hwnd-by-process-id-c
BOOL CALLBACK EnumWindowsProcMy(HWND hwnd, LPARAM lParam)
{
    DWORD lpdwProcessId;
    GetWindowThreadProcessId(hwnd, &lpdwProcessId);
    if (lpdwProcessId == lParam)
    {
        hWnd_existed = hwnd;
        return FALSE;
    }
    return TRUE;
}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?