二重起動を防止するには?

解決


みみみ  2004-09-08 01:47:49  No: 54406

二重起動を防止する方法について質問があります。
以下のソースでメニューからボタン3でnotepadが起動され
ボタン3は見ため上、押せないんですが、
この状態でボタン3を押すと、notepadが終了後に、
再度notepadが起動されます。
ボタンが押せない状態で押しても起動できないようにする方法を
誰か教えてください。よろしくお願いします。

void CMENUDlg::OnButton3() 
{
  char exe[] = "C:\\WINNT\\NOTEPAD.EXE";

  STARTUPINFO si;
  PROCESS_INFORMATION pi;
  ZeroMemory( &si, sizeof(si) );
  ZeroMemory( &pi, sizeof(pi) );
  si.cb = sizeof(si);

  m_Button3.EnableWindow( 0 );  //非表示

  if( !CreateProcess(NULL, exe, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi) ) {
    MessageBox("起動失敗","error",MB_OK);
  }

  WaitForSingleObject(pi.hProcess, INFINITE);
  CloseHandle(pi.hProcess);
  CloseHandle(pi.hThread);

  m_Button3.EnableWindow( 1 );  //表示
  
}


isshi  2004-09-08 02:23:12  No: 54407

>ボタン3は見ため上、押せないんですが、
>この状態でボタン3を押すと、
押せないのに押せるとはどういうことでしょうか?


とおり  2004-09-08 02:48:11  No: 54408

クリックのメッセージが溜まってしまっているということですか?

良い方法か分かりませんが
>m_Button3.EnableWindow( 1 );    //表示
の後でPeekMessageを使ってキューに溜まったメッセージを
クリアしてしまうとか。


isshi  2004-09-08 03:32:54  No: 54409

>>ボタン3は見ため上、押せないんですが、
>>この状態でボタン3を押すと、
>押せないのに押せるとはどういうことでしょうか?
すみません。試したら再現しました。
(Win2000SP4, VC6SP6)

とおりさんの仰るとおり、メッセージが溜まってしまっているようです。

とりあえずは、
  m_Button3.EnableWindow( 0 );
ではなく、
  EnableWindow(FALSE);
でウィンドウ自体をディセーブルにすると良いようです。

ただこれだと、notepad が終了するまで呼び出し側が固まった状態で
(再描画等がされない)かっこ悪いので、私なら以下のようにします。
(動作確認はしていません。)

EnableWindow(FALSE) で呼び出し側アプリのウィンドウをディセーブルにする。
プロセス起動用スレッドを起動する。OnButton3 はスレッド起動後、すぐに処理を返す。
スレッド内でプロセスを起動し、WaitForSingleObject で待機する。
WaitForSingleObject から戻ったら、呼び出し側アプリのウィンドウをEnableWindow(TRUE) でイネーブルにする。


みみみ  2004-09-08 07:51:06  No: 54410

isshiさん、方法を教えていただきありがとうございます。
で、試してみたのですが、
スレッドを起動、プロセスを起動、
WaitForSingleObjectで待機、解放の一連の動作を
サンプルで教えていただきますでしょうか?


isshi  2004-09-08 08:27:47  No: 54411

文章で書いたとおりそのままですが。

UINT ThreadProc( LPVOID pParam )
{
  HWND hwnd = (HWND)pParam;

  char exe[] = "C:\\WINNT\\NOTEPAD.EXE";

  STARTUPINFO si;
  PROCESS_INFORMATION pi;
  ZeroMemory( &si, sizeof(si) );
  ZeroMemory( &pi, sizeof(pi) );
  si.cb = sizeof(si);

  if( !CreateProcess(NULL, exe, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi) ) {
    MessageBox(hwnd, "起動失敗", "error", MB_OK);
  }
  else {
    WaitForSingleObject(pi.hProcess, INFINITE);
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
  }
  EnableWindow(hwnd, TRUE);  
  return 0;
}

void CMENUDlg::OnButton3() 
{
  EnableWindow(FALSE);
  AfxBeginThread(ThreadProc, (LPVOID)m_hWnd);
}

(WinXP Home SP1, VC7.1, MFC, ダイアログベースで動作確認済み)


みみみ  2004-09-08 09:15:55  No: 54412

isshiさん、サンプルを教えていただきありがとうございました。
たびたびでもうしわけありませんが、
コンパイル時に
error C2665: 'AfxBeginThread' : 2 のオーバーロードは 1 番目の引数を 'unsigned int (void)' から要求の型に変換できません。
と出力されてしまいます。
何か不備な部分があるのでしょうか?
(環境はWin2000,VC6.0です)


みみみ  2004-09-08 09:27:36  No: 54413

isshiさん
どうもすみませんでした。
こちらの記述ミスでした。

思った通りの動きができました。
いろいろとありがとうございました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加