多重起動を防止するやつをパワーアップさせたい。

返信する


答えを正確に入力してください。答えられるかどうかでスパムボットか否かを判定します。

BBCode: ON
[img]: ON
[url]: ON
スマイリー: OFF

トピックのレビュー
   

展開ビュー トピックのレビュー: 多重起動を防止するやつをパワーアップさせたい。

ありがとうございました。

by konisi » 2006年3月25日(土) 10:01

なんとなく分かっていました。皆さん、ありがとうございました。

by NoWest » 2006年3月23日(木) 13:14

konisi さんが書きました:> hiraさんのコードで多重起動は解決しました。ありがとうございました。
> ところで、どうやって元から起動していた実行ファイルの窓をアクティブにするかが分かりません。
>
> システム系無知ですみません^^;
確かに、いきなりEnumWindows関数は難しいですね。
しかし、英語名からある程度意味は推測できると思います。

このEnumWindows関数は現在デスクトップ上で実行中のあらゆるプログラムのウィンドウハンドルを列挙、つまり簡単にいうとウィンドウを1つずつ順番にお目当てのウィンドウハンドルが得られるまで調べていくものです。

コード: 全て選択

Declare Function EnumWindows Lib "user32" (lpEnumFunc As VoidPtr,lParam As LPARAM) As Long

Function EnumWindowsProc(hWnd As HWND,lParam As LPARAM) As Long
Dim dwProcessId As DWord
    GetWindowThreadProcessId(hWnd,VarPtr(dwProcessId))
    If dwProcessId=lParam And IsWindowVisible(hWnd)<>0 Then ShowWindow(hWnd,SW_RESTORE)
    EnumWindowsProc=1
End Function
そしてお目当てのウィンドウが見つかったらShowWindow関数を呼び出して
アクティブにしています。

この場合、ウィンドウを所有しているスレッドが属するプロセスIDが等しいかどうかで判断しているようですね。
よって、hira様のプログラムは非常に安全性が高い方法だと言えます。

ウィンドウ名やウィンドウクラスで調べる方法もありますが、
その場合、同じ名前のウィンドウが存在すると致命的なバグが発生します。
konisi さんが書きました:> そもそも私はミューテックスがどのようなものか知らずにレス返してましたが、BackSearchABで調べたらGetLastError関数で確実に183(ERROR_ALREADY_EXISTS)が返るようにするものかなと解釈したところです。間違ってたら指摘してやってください。
イメージとしてはそれで合っています。


~余談~

私の場合、共有メモリで実現します。

最初に起動したアプリケーションでは共有メモリを新規作成し、
共有メモリに自分のウィンドウハンドルを書き込んでおきます。

次に実行されるプログラムでは共有メモリの新規作成に失敗するので、
そのタイミングで共有メモリからウィンドウハンドルを取り出して、
アクティブ化した後、自分自身を終了させるという方法です。

by konisi » 2006年3月23日(木) 08:33

hiraさんのコードで多重起動は解決しました。ありがとうございました。
ところで、どうやって元から起動していた実行ファイルの窓をアクティブにするかが分かりません。

システム系無知ですみません^^;


そもそも私はミューテックスがどのようなものか知らずにレス返してましたが、BackSearchABで調べたらGetLastError関数で確実に183(ERROR_ALREADY_EXISTS)が返るようにするものかなと解釈したところです。間違ってたら指摘してやってください。

私の場合

by ケースケ » 2006年3月22日(水) 23:53

多重起動できないソフトを起動させた状態で同一ソフトを起動させようとした時に元々起動していた方のソフトのウインドウをアクティブにするということはできないのでしょうか?
というのを私の場合は、
ミューテックスで判断して多重起動していたらRegisterWindowMessageで何かメッセージを取得し、SendMessageで全てのウインドウに送っています。
メッセージループ内にRegisterWindowMessageのメッセージを調べる部分を作っておいて、最初から起動している方は強引にアクティブにします。
一方、あとから起動したほうは、メッセージを送信後に終了します。

私のソフトで使っている方法です。

by hira » 2006年3月22日(水) 22:30

すみません、多重起動防止機能は省略して書いていました(^^;;
ミューテックスで判断しておけばいいかな、と思ったので…。
とりあえず、この検索処理を利用して多重起動防止をしようとすると

コード: 全て選択

Type PROCESSENTRY32
	dwSize As DWord
	cntUsage As DWord
	th32ProcessID As DWord
	th32DefaultHeapID As *DWord
	th32ModuleID As DWord
	cntThreads As DWord
	th32ParentProcessID As DWord
	pcPriClassBase As Long
	dwFlags As DWord
	szExeFile[ELM(MAX_PATH)] As Byte
End Type
Const TH32CS_SNAPPROCESS=2

Declare Function CreateToolhelp32Snapshot Lib "kernel32" (dwFlag As DWord,th32ProcessID As DWord) As HANDLE
Declare Function Process32First Lib "kernel32" (hSnapshot As HANDLE,ByRef lppe As PROCESSENTRY32) As Long
Declare Function Process32Next Lib "kernel32" (hSnapshot As HANDLE,ByRef lppe As PROCESSENTRY32) As Long
Declare Function EnumWindows Lib "user32" (lpEnumFunc As VoidPtr,lParam As LPARAM) As Long

Function EnumWindowsProc(hWnd As HWND,lParam As LPARAM) As Long
Dim dwProcessId As DWord
	GetWindowThreadProcessId(hWnd,VarPtr(dwProcessId))
	If dwProcessId=lParam And IsWindowVisible(hWnd)<>0 Then ShowWindow(hWnd,SW_RESTORE)
	EnumWindowsProc=1
End Function

Dim hSnapHandle As HANDLE
Dim udtProcessEntry32 As PROCESSENTRY32
	'プロセスを列挙
	hSnapHandle=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0)
	With udtProcessEntry32
		.dwSize=SizeOf(PROCESSENTRY32)
		If Process32First(hSnapHandle,udtProcessEntry32) Then
			Do
			    '自分と同じファイル名か?
			    If lstrcmpi(.szExeFile,"test.exe")=0 Then
			        '自分自身は対象から外す
			        If .th32ProcessID<>GetCurrentProcessId() Then
			            'ウィンドウ列挙
						EnumWindows(AddressOf(EnumWindowsProc),.th32ProcessID)
			            '自分自身を終了する
			            CloseHandle(hSnapHandle)
			            End
			        End If
			    End If
			Loop While Process32Next(hSnapHandle,udtProcessEntry32)
		End If
	End With
	CloseHandle(hSnapHandle)
です。

kk

by lok » 2006年3月22日(水) 18:54

l

なぜだろ。

by konisi » 2006年3月22日(水) 14:49

hiraさんのコードの先頭に#consoleと付け加えて一番下にSleep(1000000)と書き足して・・・
とりあえずテストしてみたのですが、普通に多重起動します・・・

コード: 全て選択

#console
Type PROCESSENTRY32
    dwSize As DWord
    cntUsage As DWord
    th32ProcessID As DWord
    th32DefaultHeapID As *DWord
    th32ModuleID As DWord
    cntThreads As DWord
    th32ParentProcessID As DWord
    pcPriClassBase As Long
    dwFlags As DWord
    szExeFile[ELM(MAX_PATH)] As Byte
End Type
Const TH32CS_SNAPPROCESS=2
Declare Function CreateToolhelp32Snapshot Lib "kernel32" (dwFlag As DWord,th32ProcessID As DWord) As HANDLE
Declare Function Process32First Lib "kernel32" (hSnapshot As HANDLE,ByRef lppe As PROCESSENTRY32) As Long
Declare Function Process32Next Lib "kernel32" (hSnapshot As HANDLE,ByRef lppe As PROCESSENTRY32) As Long
Declare Function EnumWindows Lib "user32" (lpEnumFunc As VoidPtr,lParam As LPARAM) As Long

Function EnumWindowsProc(hWnd As HWND,lParam As LPARAM) As Long
Dim dwProcessId As DWord
    '同じ名前のEXEの可視ウィンドウをすべてアクティブ表示
    GetWindowThreadProcessId(hWnd,VarPtr(dwProcessId))
    If dwProcessId=lParam And IsWindowVisible(hWnd)<>0 Then ShowWindow(hWnd,SW_SHOW)
    EnumWindowsProc=1
End Function

Dim hSnapHandle As HANDLE
Dim udtProcessEntry32 As PROCESSENTRY32
    'プロセスを列挙
    hSnapHandle=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0)
    With udtProcessEntry32
        .dwSize=SizeOf(PROCESSENTRY32)
        If Process32First(hSnapHandle,udtProcessEntry32) Then
            Do
                '自分と同じファイル名か?
                If lstrcmpi(.szExeFile,"test.exe")=0 Then
                    '自分自身は対象から外す
                    If .th32ProcessID<>GetCurrentProcessId() Then
                        'ウィンドウ列挙
                        EnumWindows(AddressOf(EnumWindowsProc),.th32ProcessID)
                    End If
                End If
            Loop While Process32Next(hSnapHandle,udtProcessEntry32)
        End If
    End With
    CloseHandle(hSnapHandle)
Sleep(1000000)
一応、#promptでもやってみましたが多重起動します。


スペック
OS:WindowsXP HomeEdition SP2
CPU:3GHz、デュアルコア
(デバイスマネージャの表記:Intel(R) Pentium(R) 4 CPU 3.00GHz)
メモリ:512MB

by ノッチ » 2006年3月22日(水) 14:48

> C言語は読めるので移植する上で問題は無いのですが、SECURITY_ATTRIBUTES構造体がどのようなものか分かりません。誰か知ってる人いますか?
>

コード: 全て選択


> 'ActiveBasic調に直してみる。
> Declare Function CriateFileMapping Lib "kernel32" (
>   hFile As HANDLE,
>   lpAttributes As LPSECURITY_ATTRIBUTES,
>   flProtect As DWord,
>   dwMaximumSizeHigh As DWord,
>   dwMaximumSizeLow As DWord,
>   lpName As BytePtr) As HANDLE
> 

コード: 全て選択

Declare Function CreateFileMapping Lib "kernel32" Alias "CreateFileMappingA" (
  hFile As HANDLE,
  lpAttributes As *SECURITY_ATTRIBUTES,
  flProtect As DWord,
  dwMaximumSizeHigh As DWord,
  dwMaximumSizeLow As DWord,
  lpName As BytePtr) As HANDLE
AB風な宣言はこんな感じでしょうか。

SECURITY_ATTRIBUTES構造体はCreateFile等でも使用されるもので、
ハンドルを継承する(?)場合なんかで使われるらしいですが・・・。
よくわからないのでいつもNULL渡してます。
NULLの場合デフォルトの設定が使われるらしいので問題ないはずです。

ちなみにhiraさんのコードの方が大変そうですがより正確にできますね。

Re: 多重起動を防止するやつをパワーアップさせたい。

by hira » 2006年3月22日(水) 14:37

多重起動できないソフトを起動させた状態で同一ソフトを起動させようとした時に元々起動していた方のソフトのウインドウをアクティブにする
こっちへのレスです(^^;

コード: 全て選択

Type PROCESSENTRY32
	dwSize As DWord
	cntUsage As DWord
	th32ProcessID As DWord
	th32DefaultHeapID As *DWord
	th32ModuleID As DWord
	cntThreads As DWord
	th32ParentProcessID As DWord
	pcPriClassBase As Long
	dwFlags As DWord
	szExeFile[ELM(MAX_PATH)] As Byte
End Type
Const TH32CS_SNAPPROCESS=2

Declare Function CreateToolhelp32Snapshot Lib "kernel32" (dwFlag As DWord,th32ProcessID As DWord) As HANDLE
Declare Function Process32First Lib "kernel32" (hSnapshot As HANDLE,ByRef lppe As PROCESSENTRY32) As Long
Declare Function Process32Next Lib "kernel32" (hSnapshot As HANDLE,ByRef lppe As PROCESSENTRY32) As Long
Declare Function EnumWindows Lib "user32" (lpEnumFunc As VoidPtr,lParam As LPARAM) As Long

Function EnumWindowsProc(hWnd As HWND,lParam As LPARAM) As Long
Dim dwProcessId As DWord
	'同じ名前のEXEの可視ウィンドウをすべてアクティブ表示
	GetWindowThreadProcessId(hWnd,VarPtr(dwProcessId))
	If dwProcessId=lParam And IsWindowVisible(hWnd)<>0 Then ShowWindow(hWnd,SW_SHOW)
	EnumWindowsProc=1
End Function

Dim hSnapHandle As HANDLE
Dim udtProcessEntry32 As PROCESSENTRY32
	'プロセスを列挙
	hSnapHandle=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0)
	With udtProcessEntry32
		.dwSize=SizeOf(PROCESSENTRY32)
		If Process32First(hSnapHandle,udtProcessEntry32) Then
			Do
				'自分と同じファイル名か?
				If lstrcmpi(.szExeFile,"test.exe")=0 Then
					'自分自身は対象から外す
					If .th32ProcessID<>GetCurrentProcessId() Then
						'ウィンドウ列挙
						EnumWindows(AddressOf(EnumWindowsProc),.th32ProcessID)
					End If
				End If
			Loop While Process32Next(hSnapHandle,udtProcessEntry32)
		End If
	End With
	CloseHandle(hSnapHandle)
例は test.exe という名前のEXEファイルだったときの処理です(適当に変えてください)。
簡単にしか実験していないので、ひょっとしたら動作がおかしいかもしれませんが、そのときは細かいところをいろいろ変更してみてください(^^;;

by konisi » 2006年3月22日(水) 14:21

ありがとうございました。とりあえずBasicHelpに載ってないようなのでBackSearchABで探して、サンプルが無いのでググルさんに聞いたのですが・・・
http://www.microsoft.com/japan/develope ... apping.htm

コード: 全て選択


HANDLE CreateFileMapping(
  HANDLE hFile,                       // ファイルのハンドル
  LPSECURITY_ATTRIBUTES lpAttributes, // セキュリティ
  DWORD flProtect,                    // 保護
  DWORD dwMaximumSizeHigh,            // サイズを表す上位 DWORD
  DWORD dwMaximumSizeLow,             // サイズを表す下位 DWORD
  LPCTSTR lpName                      // オブジェクト名
);
C言語は読めるので移植する上で問題は無いのですが、SECURITY_ATTRIBUTES構造体がどのようなものか分かりません。誰か知ってる人いますか?

コード: 全て選択


'ActiveBasic調に直してみる。
Declare Function CriateFileMapping Lib "kernel32" (
  hFile As HANDLE,
  lpAttributes As LPSECURITY_ATTRIBUTES,
  flProtect As DWord,
  dwMaximumSizeHigh As DWord,
  dwMaximumSizeLow As DWord,
  lpName As BytePtr) As HANDLE
ちなみに、GetLastError()で183が返るかどうかで2重起動をチェックしてました。

Re: 多重起動を防止するやつをパワーアップさせたい。

by ノッチ » 2006年3月22日(水) 14:06

2重起動防止はFindWindowかミューテックスを使用していると思いますが、
他にファイルマッピングという方法もあります。

CreateFileMapping

というAPIを調べてみてください。
簡単にいうとメモリをプロセス間で共有するということです。

多重起動を防止するやつをパワーアップさせたい。

by konisi » 2006年3月22日(水) 13:57

多重起動を防止する方法なら知っているのですが、多重起動できないソフトを起動させた状態で同一ソフトを起動させようとした時に元々起動していた方のソフトのウインドウをアクティブにするということはできないのでしょうか?

WinXPにてCtrl+Alt+Deleteを押すと出てくるタスクマネージャのような。

ページトップ