概要
多重起動を防止する方法には、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;
}