Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

二重起動の禁止について

188 views
Skip to first unread message

ポケットうえだ

unread,
Sep 11, 2009, 4:06:01 AM9/11/09
to
前に一度どこかで見かけたように思えるのですが、
プログラム駆動中に又駆動する、いわゆる二重駆動を禁止したいのですが
簡単な方法があったら教えて下さい。
VC++6、Win32APIで作成したプログラムでデータ異常が発生し、痕跡から
どうも二重駆動によるものと判明したからです。
よろしくお願いします。


ちゅ

unread,
Sep 11, 2009, 4:40:01 AM9/11/09
to
ちゅ です。

On Fri, 11 Sep 2009 01:06:01 -0700
"ポケットうえだ" wrote
in message news:8EC88C86-BB85-44CA...@microsoft.com...
> 二重起動の禁止について

MSDN 2001年10月リリースで
WinMain() の説明に

hPrevInstance
アプリケーションの前のインスタンスのハンドルが入ります。
Win32 アプリケーションでは、常に NULL です。
すでに他のインスタンスが存在するかどうかを調べるには、
CreateMutex 関数を使って一意の名前の付いたミューテックスを作成してください。
CreateMutex 関数は、すでのそのミューテックスが存在していても成功しますが、
GetLastError 関数を呼び出すと ERROR_ALREADY_EXISTS が返ります。
GetLastError 関数からこの値が返された場合、既に同じアプリケーションの他のインスタンスが
存在しており、それが最初のミューテックスを作成しています。

と有るので、説明文に従って CreateMutex関数で可能です。


UETA, Shin-ichi

unread,
Sep 12, 2009, 2:55:38 PM9/12/09
to
こんにちは、植田です。

ポケットうえだ wrote:
> プログラム駆動中に又駆動する、いわゆる二重駆動を禁止したいのですが
> 簡単な方法があったら教えて下さい。

ちゅさんからのリプライにあるとおり、ミューテックスなどの同期オブジェクトを
使用するのが真っ当なやり方ですが、以下のようにフラグを共有メモリに置く
方法もあります。

#pragma data_seg(".shared")
volatile bool bRunning = false;
#pragma data_seg()
#pragma comment(linker, "/SECTION:.shared,RWS")

当然ながらプログラマの責任の下で排他制御しなければなりませんが、
InterlockedExchangeなど、Interlocked系のAPIを併用すればそれなりの
信頼性は確保できるかと思います。

Limiting the Number of Instances Running
http://www.codeproject.com/KB/cpp/limitnumins.aspx

--
植田システム設計事務所
Ueta System Design Studio
http://www.usdesign.jp/
植田真一
mailto:ue...@usdesign.jp


ポケットうえだ

unread,
Sep 14, 2009, 11:45:01 PM9/14/09
to
回答ありがとうございます。
ご提案の通りのCreateMutexを使う方法を
試して見たいと思います。
 ちょっとあまく考えていました。実のところ、WinMainの頭の変数を若干いじくれば
シャッタアウトされる方法があるのではと考えていましたので。
 二重起動して困るソフトは多いと思うので、OSであるWindowsは当然その方法
を最初から準備していると期待していたのですが。

ポケットうえだ

unread,
Sep 15, 2009, 12:02:01 AM9/15/09
to
回答ありがとうございます。
別の方法は便宜的に考えました。
 起動直後に、特定の場所に「既に起動しているマーク」が書かれて
いるかどうかを確認し、無ければ「既に起動しているマーク」を書く。
 既に起動しているマークがあれば、二重起動だと判断してプログラムを終了
させる。正常に立ち上がった場合の終了時にはマークを消す。
こうすれば、突発的な事故がない限りうまく行くはず。
 ただ、突発的な事故のために、正常終了できない場合に「既に起動しているマーク」は消せないため、残るとやっかいな問題になる。
今度は初回であっても、二重起動となってすぐに終了せざるを得なくなる。
 ま、これはハードディスクにそんな場合のマークを書いた場合ですが、

 おっしゃるように、どこか共有メモリーに書いておけば、電源を落とした場合に
当然その部分が消えるので安全でしょうね。ただ、強制的にプログラムを終了
させた場合で、電源を落としていない状態では共有メモリーも当然保持されて
いることになりますが。その辺は大丈夫なんでしょうか。
 

UETA, Shin-ichi

unread,
Sep 15, 2009, 2:10:12 AM9/15/09
to
どうも、植田です。

ポケットうえだ wrote:
>  おっしゃるように、どこか共有メモリーに書いておけば、電源を落とした場合に
> 当然その部分が消えるので安全でしょうね。ただ、強制的にプログラムを終了
> させた場合で、電源を落としていない状態では共有メモリーも当然保持されて
> いることになりますが。その辺は大丈夫なんでしょうか。

ここで言うところの「共有メモリ」は、複数の仮想アドレス空間に同じ物理メモリを
マッピングすることで実現しているものです。
たとえ共有メモリの仮想アドレスが各プロセスごとに異なっていても、実際には
同じ変数を参照しているわけです。
どこか他所に特別なメモリが用意されているわけではなく、仮想メモリの仕組み
に基づいた、ごく単純なトリックです。
裏を返せば、同じ共有メモリを参照するプロセスがすべてお亡くなりになれば、
その共有メモリも存在し得ないことになります。

# 通常のページ(4KB単位の物理メモリ)と同様、いらなくなった共有メモリの
# ページは回収され、再利用されるだけのことです。

ポケットうえだ

unread,
Sep 15, 2009, 4:29:02 AM9/15/09
to
CreateMutex関数を使って二重起動禁止をするとして
CreateMutex関数の記載位置について質問します。

  WinMain内に記載する場合に
1.変数宣言のすぐ後に書く
2.GetMessage関数のループの直前に書く
3.CALLBACK WndProcの
  WM_CREATE: に記載する
の三つが考えられます。
出来れば、二重起動の際に何事もなく起動を無視するようなのが
望ましいのですが、どうでしょうか。
デッドロック状態になってしまう可能性は避けたいのですが。

"ちゅ" からの元のメッセージ:

ちゅ

unread,
Sep 15, 2009, 8:44:00 PM9/15/09
to
ちゅ です。

On Tue, 15 Sep 2009 01:29:02 -0700
"ポケットうえだ" wrote
in message news:CB51D33D-0CA9-46D0...@microsoft.com...
> Re: 二重起動の禁止について

> 1.変数宣言のすぐ後に書く
> 2.GetMessage関数のループの直前に書く
> 3.CALLBACK WndProcの
>   WM_CREATE: に記載する

二重起動で破壊されそうなグローバル変数の設定前などに
チェックのコードを挿入した方が良いでしょうから
基本的に、メッセージループに入る前までに記述します。
1と2の間に記述することになるでしょう。

起動して各種環境設定や変数の設定を行っている筈なので
設定している値を破壊しない箇所としか言えません。

--
ちゅ

ポケットうえだ

unread,
Sep 15, 2009, 11:44:01 PM9/15/09
to
上田です。
回答ありがとうございます。

ご指摘のように
//エントリポイント
int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR
lpCmdLine,int nCmdShow)
{
WNDCLASSEX wcex; // ウインドウクラス構造体
HWND hWnd; // ウインドウハンドル
MSG msg; // メッセージ構造体

hMutex = CreateMutex(NULL,TRUE,"reptaexe");
       // 二重起動禁止のため
if( hMutex == NULL){ return(FALSE); }
// 二重起動を確認 起動を中止
if( GetLastError() == ERROR_ALREADY_EXISTS ){ return( FALSE ); }
// ウインドウクラス構造体を設定
wcex.cbSize = sizeof(WNDCLASSEX);
以下関数内省略
}

//ウインドウプロシージャ
LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
{
中略
ReleaseMutex( hMutex ); // 二重起動禁止のための後処理
CloseHandle( hMutex ); // 二重起動禁止のための後処理
sw = DestroyWindow(hWnd);
以下ソフトの最終処理に向かう

とし、テストを行いました。
今のところ、デッドロックなど不安定な動作はしてません。

0 new messages