tagCANDY CGI VBレスキュー(花ちゃん)の Visual Basic 6.0用 掲示板 [ツリー表示へ]   [Home]
一括表示(VB6.0)
タイトル2重起動の後優先
記事No12614
投稿日: 2008/06/23(Mon) 13:47
投稿者コーヒーブレイク
いつもお世話になっています。

実行環境:WindowsXP SP2
開発言語:VB6 SP6


「アプリケーション起動時に2重起動判定を行い、後優先=すでに起動中の
自分自身を終了させ、後から起動している自分は起動したい」のです。

2重起動チェックあるいはチェック後に先優先=検知した側を終了の情報はたくさん
あったのですが(もちろん、VBレスキュー(花ちゃん)にも)、後優先の
情報でこれ!というものが見つからないというか、いろいろ自分で試して
いるのですが、うまくいきません。

FindWindowで取得しているハンドルが後起動のほうになっているのが原因
な気がします。 列挙かな?なんて思ったりしているのですが、列挙して
その後どうすれば・・・って悩んでいます。
何かヒントいただけると助かります。 よろしくお願いいたします。

[ツリー表示へ]
タイトルRe: 2重起動の後優先
記事No12616
投稿日: 2008/06/23(Mon) 14:16
投稿者花ちゃん
> 2重起動チェックあるいはチェック後に先優先=検知した側を終了の情報はたくさん
> あったのですが(もちろん、VBレスキュー(花ちゃん)にも)、後優先の
> 情報でこれ!というものが見つからないというか、いろいろ自分で試して
> いるのですが、うまくいきません。

発想の違いだけでは、指定のアプリが起動しているか調べ起動していたらVBから
終了するのと同じでは。

http://www.hanatyan.sakura.ne.jp/vbhlp/handle.htm

他にも色々方法ややり方はあるでしょう。

[ツリー表示へ]
タイトルRe^2: 2重起動の後優先
記事No12617
投稿日: 2008/06/23(Mon) 14:28
投稿者コーヒーブレイク
花ちゃん様、早速の回答ありがとうございます。

> 発想の違いだけでは、指定のアプリが起動しているか調べ起動していたらVBから
> 終了するのと同じでは。
>
> http://www.hanatyan.sakura.ne.jp/vbhlp/handle.htm
>
> 他にも色々方法ややり方はあるでしょう。

私の発想が貧弱なのかもしれませんが、参考の手法のキャプションから
実行する方法を私も行っているのですが、

hwnd = FindWindow(vbNullString, strCaptionName)

この部分で取得されるハンドルが後起動のほうなので先起動を終了
出来ないのでは?  と考えているのです。
理由は同一キャプションなため。

私のコーディングに間違いがあると本末転倒なので、参考のコードの
必要な部分をコピー&ペーストして再確認してみます。

[ツリー表示へ]
タイトルRe^3: 2重起動の後優先
記事No12618
投稿日: 2008/06/23(Mon) 14:37
投稿者コーヒーブレイク
新規プロジェクトにて以下のコードで行ってみましたが、やはり
終了は出来ないようです。

何か良い手法ないでしょうか?


-----------------------------------------------------------------
Attribute VB_Name = "Module1"
Option Explicit

'クラス名又はキャプションタイトルを与えて
'ウインドウのハンドルを取得する(P81)
Private Declare Function FindWindow Lib "user32" _
    Alias "FindWindowA" (ByVal lpClassName As String, _
    ByVal lpWindowName As String) As Long

'指定のウインドウにメッセージを送る(P750)
Private Declare Function SendMessage Lib "user32" _
    Alias "SendMessageA" (ByVal hwnd As Long, _
    ByVal wMsg As Long, ByVal wParam As Long, _
        lParam As Any) As Long
'アプリケーションをクローズする時
'ウインドウに送られるメッセージ(P835)
Private Const WM_CLOSE As Long = &H10
Dim strClassName   As String  'クラス名
Dim strCaptionName As String  'キャプション名


Sub main()
'ハンドル取得及び終了処理のサブプロシージャ
    Dim hwnd As Long
    Dim ret As Long
    
'    If Len(strClassName) Then
'        'クラス名を与えてハンドルを取得
'        '起動中ならハンドルが返り、起動していなければ 0 が返る
'        hwnd = FindWindow(strClassName, vbNullString)
'    ElseIf Len(strCaptionName) Then
        'キャプション名を与えてハンドルを取得する場合
        'strCaptionName = "Microsoft Excel - Book1"  '電卓の場合  "電卓"

    If App.hInstance = True Then
                
        strCaptionName = Frm_Main.Caption
        hwnd = FindWindow(vbNullString, strCaptionName)
'    End If
    '指定のハンドルに終了のメッセージを送る
        ret = SendMessage(hwnd, WM_CLOSE, 0&, 0&)

    Else
        Frm_Main.Show
    End If
End Sub

[ツリー表示へ]
タイトルRe^3: 2重起動の後優先
記事No12619
投稿日: 2008/06/23(Mon) 15:08
投稿者花ちゃん
> 理由は同一キャプションなため。
だったら調べる前に自分自身のキャプションを一時的に変更してから
調べるなりすればいいのでは。

その他、起動中のEXEのパスとハンドルを取得する等方法は色々あるかと。

[ツリー表示へ]
タイトルRe^4: 2重起動の後優先
記事No12620
投稿日: 2008/06/23(Mon) 15:15
投稿者コーヒーブレイク
> > 理由は同一キャプションなため。
> だったら調べる前に自分自身のキャプションを一時的に変更してから
> 調べるなりすればいいのでは。
>
> その他、起動中のEXEのパスとハンドルを取得する等方法は色々あるかと。


花ちゃん様、回答ありがとうございます。

キャプションの一時的な変更も含め、”色々”の部分への発想が完全に欠けて
いたというか、停止していました。
そう言われてみれば・・・な感じです。

花ちゃん様からの回答を元に色々試してみたいと思います。
本当にありがとうございました。

[ツリー表示へ]
タイトルRe^5: 2重起動の後優先
記事No12621
投稿日: 2008/06/23(Mon) 15:28
投稿者花ちゃん

> 花ちゃん様からの回答を元に色々試してみたいと思います。

そもそもそういった処理が必要なら、そのEXEが起動中は、ハンドルをどこかに
(ファイル・レジストリ等)保存しておき、起動時にそこを見てハンドルがあれば
そのハンドルに、WM_CLOSE を送る等の細工をした方が簡単かも。

[ツリー表示へ]
タイトルRe^6: 2重起動の後優先
記事No12622
投稿日: 2008/06/23(Mon) 15:35
投稿者コーヒーブレイク
> そもそもそういった処理が必要なら、そのEXEが起動中は、ハンドルをどこかに
> (ファイル・レジストリ等)保存しておき、起動時にそこを見てハンドルがあれば
> そのハンドルに、WM_CLOSE を送る等の細工をした方が簡単かも。

なるほど、そういう手もあるのですね。
ほんとお恥ずかしながら頭が固くなっていました。
リハビリがてら動作して完成ではなく、いろいろ試してみたいと思っています。
ありがとうございました。

[ツリー表示へ]
タイトルRe^7: 2重起動の後優先
記事No12623
投稿日: 2008/06/23(Mon) 15:44
投稿者YK
こんにちは。
テストで作ってみました。
VBのフォームが他にあればそちらも対象になります。
スタートアップを Sub Main にして下さい。

Option Explicit
Declare Function EnumWindows Lib "user32.dll" _
                        (ByVal lpEnumFunc As Long, _
                         ByVal lParam As Long) As Long

Declare Function GetClassName Lib "user32.dll" _
                        Alias "GetClassNameA" _
                        (ByVal hwnd As Long, _
                         ByVal lpClassName As String, _
                         ByVal nMaxCount As Long) As Long

Declare Function GetWindowText Lib "user32.dll" _
                        Alias "GetWindowTextA" _
                        (ByVal hwnd As Long, _
                         ByVal lpString As String, _
                         ByVal nMaxCount As Long) As Long

Public Declare Function PostMessage Lib "user32" Alias "PostMessageA" _
                        (ByVal hwnd As Long, _
                         ByVal wMsg As Long, _
                         ByVal wParam As Long, _
                         ByVal lParam As Long) As Long

Public Const WM_CLOSE = &H10
Dim AppFlag As Boolean
Dim ApphWnd As Long

' コールバック関数
Function EnumWindowsProc(ByVal hwnd As Long, _
                         lParam As Long) As Long
    
    Dim strClassBuff    As String * 128
    Dim strClass        As String
    Dim strTextBuff     As String * 516
    Dim strText         As String
    Dim lngRtn          As Long
    Dim lngStyle        As Long
    
    ' クラス名をバッファに
    lngRtn = GetClassName(hwnd, strClassBuff, Len(strClassBuff))
    ' クラス名取得
    strClass = Left(strClassBuff, InStr(strClassBuff, vbNullChar) - 1)
        
    If strClass = "ThunderRT6FormDC" Then
        AppFlag = True
        ApphWnd = hwnd
        EnumWindowsProc = False
        Exit Function
    End If
    ' 列挙を継続
EnumPass:
    EnumWindowsProc = True
End Function

Public Sub Main()
    Dim lngRtn  As Long
    
    If App.PrevInstance Then
        lngRtn = EnumWindows(AddressOf EnumWindowsProc, 0&)
        If ApphWnd > 0 And AppFlag Then
            lngRtn = PostMessage(ApphWnd, WM_CLOSE, 0&, 0&)
        End If
        Form1.Text1.Text = "BBBB"
    Else
        Form1.Text1.Text = "AAAA"
    End If
    Form1.Show
End Sub

[ツリー表示へ]
タイトルRe^8: 2重起動の後優先
記事No12624
投稿日: 2008/06/23(Mon) 15:54
投稿者コーヒーブレイク
YKさん、回答ありがとうございます。


サンプルソースまで書いていただいて、ほんとうにありがとうございます。

今花ちゃん様に教えていただいた手法をテストしていますので、その後に
是非試してみたいと思います。

記載されているコメントを参考にコードの意味を理解しつつ
参考にさせていただこうと思っています。
ありがとうございました。

[ツリー表示へ]
タイトルRe^9: 2重起動の後優先
記事No12625
投稿日: 2008/06/23(Mon) 19:15
投稿者コーヒーブレイク
花ちゃん様、YK様へ


1.キャプションの一時変更について
   サンプルを参考に新規作成のプロジェクトだと希望通りに動作することが
   確認出来ました。
   ただ理由がわからないのですが、作成中のアプリに組み込むとどうしても
   先起動が残って後起動が消えてしまいます。
   DoEvents、Msgbox等でいろいろ確認してみたいのですが、理由は判明しません
   でした。

2.列挙
   動作は完全でした。 変更すれば何とかなりそうですが、全VB対象という
   ことと作業量とのかねあいで今回はパスしました。
   でも大変参考になりました。 どこかで利用させていただきたいです。


ということで、起動時にファイルにハンドルを記述する方法を採用しました。
希望通りの動作とシンプルというところが理由です。
お二人のお力がなければここまで短時間で解決はしなかったと確信しています。
ほんとうにありがとうございました。

[ツリー表示へ]
タイトルRe^10: 2重起動の後優先
記事No12626
投稿日: 2008/06/24(Tue) 09:12
投稿者コーヒーブレイク
追加報告です。

> 1.キャプションの一時変更について
>    サンプルを参考に新規作成のプロジェクトだと希望通りに動作することが
>    確認出来ました。
>    ただ理由がわからないのですが、作成中のアプリに組み込むとどうしても
>    先起動が残って後起動が消えてしまいます。
>    DoEvents、Msgbox等でいろいろ確認してみたいのですが、理由は判明しません
>    でした。


この理由はキャプション名とプロジェクト名が同一であるのが原因でした。

[ツリー表示へ]