Q&A-プロセス・スレッド編

プロセス、スレッドやプロセス間通信に関する質問をまとめました。

ウィンドウ・アプリケーションを起動してから終了するまで待つ
関連付けられたファイルを起動し終了するまで待つ
実行時のコマンドライン引数を取得するには
VBのアプリケーションの戻り値によってバッチファイルで分岐するには?
二重起動を防止するには、どうすれば良いでしょうか?
SendKeys で DOSプロンプトに文字を送るには?
アプリケーションのアクティブ、非アクティブを知るには?


Q ウィンドウ・アプリケーションを起動してから終了するまで待つ

ウィンドウ・アプリケーションを起動して、終了するまで待つにはどうするのですか?

A APIの CreateProcess と WaitForSingleObject を使用します

まず、標準モジュールに以下の定数と宣言を入れます。
(注意) APIビューワでの入力とは、宣言や定数が幾つか異なります。

Option Explicit

'==============================
'CreateProcess 関連の宣言
'==============================
'作成フラグ
Public Const CREATE_DEFAULT_ERROR_MODE = &H4000000
Public Const CREATE_NEW_CONSOLE = &H10&
Public Const CREATE_NEW_PROCESS_GROUP = &H200&
Public Const CREATE_SEPARATE_WOW_VDM = &H800&
Public Const CREATE_SHARED_WOW_VDM = &H1000&
Public Const CREATE_SUSPENDED = &H4&
Public Const CREATE_UNICODE_ENVIRONMENT = &H400&
Public Const DEBUG_PROCESS = &H1&
Public Const DEBUG_ONLY_THIS_PROCESS = &H2&
Public Const DETACHED_PROCESS = &H8&

'優先順位クラスフラグ
Public Const HIGH_PRIORITY_CLASS = &H80&
Public Const IDLE_PRIORITY_CLASS = &H40&
Public Const NORMAL_PRIORITY_CLASS = &H20&
Public Const REALTIME_PRIORITY_CLASS = &H100&

Type SECURITY_ATTRIBUTES
     nLength As Long
     lpSecurityDescriptor As Long
     bInheritHandle As Long
End Type

Type PROCESS_INFORMATION
     hProcess As Long
     hThread As Long
     dwProcessId As Long
     dwThreadId As Long
End Type

Type STARTUPINFO
     cb As Long
      lpReserved As Long
     lpDesktop As Long
     lpTitle As Long
     dwX As Long
     dwY As Long
     dwXSize As Long
     dwYSize As Long
     dwXCountChars As Long
     dwYCountChars As Long
     dwFillAttribute As Long
     dwFlags As Long
     wShowWindow As Integer
     cbReserved2 As Integer
     lpReserved2 As Long
     hStdInput As Long
     hStdOutput As Long
     hStdError As Long
End Type

Declare Function CreateProcess Lib "kernel32" Alias "CreateProcessA" ( _
     ByVal lpApplicationName As String, _
     ByVal lpCommandLine As String, _
     lpProcessAttributes As Any, _
     lpThreadAttributes As Any, _
     ByVal bInheritHandles As Long, _
     ByVal dwCreationFlags As Long, _
     lpEnvironment As Any, _
     ByVal lpCurrentDriectory As String, _
     lpStartupInfo As STARTUPINFO, _
     lpProcessInformation As PROCESS_INFORMATION _
) As Long

Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long

'==============================
'WaitForSingleObject 関連の宣言
'==============================
Public Const INFINITE = &HFFFF          ' Infinite timeout

Public Const STATUS_WAIT_0 = 0&
Public Const STATUS_TIMEOUT = &H102&
Public Const STATUS_ABANDONED_WAIT_0 = &H80&

Public Const WAIT_OBJECT_0 = ((STATUS_WAIT_0) + 0&)
Public Const WAIT_ABANDONED = ((STATUS_ABANDONED_WAIT_0) + 0&)
Public Const WAIT_TIMEOUT = STATUS_TIMEOUT

Declare Function WaitForSingleObject Lib "kernel32" ( _
     ByVal hHandle As Long, _
     ByVal dwMilliseconds As Long _
) As Long

Declare Function GetLastError Lib "kernel32" () As Long

ウィンドウ・アプリケーションを起動するところで、以下の CreateProcess を呼んでください。

Dim si As STARTUPINFO
Dim pi As PROCESS_INFORMATION
Dim r As Long

si.cb = LenB(si)

r = CreateProcess( _
     "C:\WINNT\SYSTEM32\notepad.exe", _
     "", _
     ByVal 0&, _
     ByVal 0&, _
     0, _
     NORMAL_PRIORITY_CLASS, _
     ByVal 0&, _
     vbNullString, _
     si, _
     pi _
)

If r = 0 Then
     MsgBox "CreateProcess Error"
     Exit Sub
End If

ここで、CreateProcess の最初の引数である "C:\WINNT\SYSTEM32\notepad.exe"   に起動したいアプリケーションを指定します。
2番目の引数は、実行するアプリケーションのパラメータを指定できます。

アプリケーションが終了するまで待つには、CreateProcessで取得した pi.hProcess を指定して以下の WaitForSingleObjectCloseHandle を呼んでください。

r = WaitForSingleObject(pi.hProcess, INFINITE)
If r <> WAIT_OBJECT_0 Then
    MsgBox "WaitForSingleObject Error"
    Exit Sub
End If


CloseHandle pi.hProcess

WaitForSingleObject の2番目の引数で、 INFINITE と指定していますが、この引数は、アプリケーションの待ち時間を ms(ミリセカンド)で指定することができます。ただし、 INFINITE を指定した場合は、起動したアプリケーションが終了するまで WaitForSingleObject から制御を戻しません。

また、INFINITE を指定した場合、アプリケーションを起動した側のプログラムには、制御が戻らないので、起動側のプログラムがフリーズしたようになります。起動プログラムに制御を戻したい場合、以下のように INFINITE の代わりに、待ち時間を指定し、タイムアウトでなくなるまでループします。

Do
    r = WaitForSingleObject(pi.hProcess, 300)      ' 300ms 待ちます
    DoEvents
Loop Until r <> STATUS_TIMEOUT

If r <> WAIT_OBJECT_0 Then
    MsgBox "WaitForSingleObject Error"
    Exit Sub
End If

CloseHandle pi.hProcess

(注意)このページの内容は、Visual Basic5.0(SP3) を対象に記述されています。他のバージョンでは、対応できないこともあるので、ご注意願います。
(注意) ここでの情報については、あくまでも各自の責任にて、充分にテストを行ってご使用ください。内容に関する質問については、回答できる保証がありませんので、予めご了承願います。


Q 関連付けられたファイルを起動し終了するまで待つ

".TXT" で Notepad 、".HTM" で Internet Explorer を起動するように、関連付けられたファイルを起動して、終了するまで待つにはどうするのですか?

A APIの ShellExecute と WaitForSingleObject を使用します

まず、標準モジュールに以下の定数と宣言を入れます。
(注意) APIビューワでの入力とは、宣言や定数が幾つか異なります。

Option Explicit

'==============================
'ShellExecute 関連の宣言
'==============================
Public Const SW_SHOWNORMAL = 1

Public Const SEE_MASK_CLASSKEY = &H3
Public Const SEE_MASK_CLASSNAME = &H1
Public Const SEE_MASK_CONNECTNETDRV = &H80
Public Const SEE_MASK_DOENVSUBST = &H200
Public Const SEE_MASK_FLAG_DDEWAIT = &H100
Public Const SEE_MASK_FLAG_NO_UI = &H400
Public Const SEE_MASK_HOTKEY = &H20
Public Const SEE_MASK_ICON = &H10
Public Const SEE_MASK_IDLIST = &H4
Public Const SEE_MASK_INVOKEIDLIST = &HC
Public Const SEE_MASK_NOCLOSEPROCESS = &H40

Type SHELLEXECUTEINFO
    cbSize As Long
    fMask As Long
    hwnd As Long
    lpVerb As String
    lpFile As String
    lpParameters As String
    lpDirectory As String
    nShow As Long
    hInstApp As Long
    ' Optional fields
    lpIDList As Long
    lpClass As String
    hkeyClass As Long
    dwHotKey As Long
    hIcon As Long
    hProcess As Long
End Type

Declare Function ShellExecuteEx Lib "shell32.dll" Alias "ShellExecuteExA" ( _
    lpExecInfo As SHELLEXECUTEINFO _
) As Long

Public Const ERROR_FILE_NOT_FOUND = 2&
Public Const ERROR_PATH_NOT_FOUND = 3&
Public Const ERROR_DDE_FAIL = 1156&
Public Const ERROR_NO_ASSOCIATION = 1155&
Public Const ERROR_ACCESS_DENIED = 5&
Public Const ERROR_DLL_NOT_FOUND = 1157&
Public Const ERROR_CANCELLED = 1223&
Public Const ERROR_NOT_ENOUGH_MEMORY = 8
Public Const ERROR_SHARING_VIOLATION = 32&
Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long

'==============================
'WaitForSingleObject 関連の宣言
'==============================
Public Const INFINITE = &HFFFF          ' Infinite timeout

Public Const STATUS_WAIT_0 = 0&
Public Const STATUS_TIMEOUT = &H102&
Public Const STATUS_ABANDONED_WAIT_0 = &H80&

Public Const WAIT_OBJECT_0 = ((STATUS_WAIT_0) + 0&)
Public Const WAIT_ABANDONED = ((STATUS_ABANDONED_WAIT_0) + 0&)
Public Const WAIT_TIMEOUT = STATUS_TIMEOUT

Declare Function WaitForSingleObject Lib "kernel32" ( _
     ByVal hHandle As Long, _
     ByVal dwMilliseconds As Long _
) As Long

Declare Function GetLastError Lib "kernel32" () As Long

関連付けられたファイルを起動するところで、以下の ShellExecuteEx を呼んでください。

Dim ei As SHELLEXECUTEINFO
Dim r As Long

ei.cbSize = LenB(ei)
ei.fMask = SEE_MASK_NOCLOSEPROCESS
ei.hwnd = Me.hwnd
ei.lpVerb = "Open"
ei.lpFile = "C:\WINNT\Readme.txt"
ei.lpParameters = ""
ei.lpDirectory = ""
ei.nShow = SW_SHOWNORMAL

r = ShellExecuteEx(ei)

If r = 0 Then
     MsgBox "ShellExecuteEx Error"
     Exit Sub
End If

ここで、Dim ei As SHELLEXECUTEINFO で定義された ei の lpFile に起動したいファイル(ここでは、"C:\WINNT\Readme.txt" )を指定します。ei.lpParameters は、実行するアプリケーションのパラメータを指定できます。

アプリケーションが終了するまで待つには、ShellExecuteEx で取得した ei.hProcess を指定して以下の WaitForSingleObjectCloseHandle を呼んでください。

r = WaitForSingleObject(ei.hProcess, INFINITE)
If r <> WAIT_OBJECT_0 Then
    MsgBox "WaitForSingleObject Error"
    Exit Sub
End If


CloseHandle pi.hProcess

WaitForSingleObject の2番目の引数で、 INFINITE と指定していますが、この引数は、アプリケーションの待ち時間を ms(ミリセカンド)で指定することができます。ただし、 INFINITE を指定した場合は、起動したアプリケーションが終了するまで WaitForSingleObject から制御を戻しません。

また、INFINITE を指定した場合、アプリケーションを起動した側のプログラムには、制御が戻らないので、起動側のプログラムがフリーズしたようになります。起動プログラムに制御を戻したい場合、以下のように INFINITE の代わりに、待ち時間を指定し、タイムアウトでなくなるまでループします。

Do
    r = WaitForSingleObject(ei.hProcess, 300)      ' 300ms 待ちます
    DoEvents
Loop Until r <> STATUS_TIMEOUT

If r <> WAIT_OBJECT_0 Then
    MsgBox "WaitForSingleObject Error"
    Exit Sub
End If

CloseHandle pi.hProcess

(注意)このページの内容は、Visual Basic5.0(SP3) を対象に記述されています。他のバージョンでは、対応できないこともあるので、ご注意願います。
(注意) ここでの情報については、あくまでも各自の責任にて、充分にテストを行ってご使用ください。内容に関する質問については、回答できる保証がありませんので、予めご了承願います。


Q 実行時のコマンドライン引数を取得するには

VBで作成した実行可能なプログラムの起動時に指定されたコマンドラインの引数を取得するにはどうするのですか?

A Command 関数で取得できます

VBで作成した実行可能なプログラムを起動時する時に以下のようなパラメータを指定する場合があります。

APP.EXE /F:TEMP.TXT

この引数を取得するには、Command という関数で取得できます。ただし、デバッグ時には、一見なにも Command に入っていないようですが、実行可能なプログラムにすれば、Command にコマンドラインの引数が入ります。
デバッグ時に Command に文字列を入れたい場合は、メニューの [プロジェクト]-[XXXX のプロパティ]を選択して、[実行可能ファイルの作成]タグを選択してください。「コマンドライン引数」という入力欄があるので、そこに入力すれば Command に文字列が入ります。

(注意)このページの内容は、Visual Basic5.0(SP3) を対象に記述されています。他のバージョンでは、対応できないこともあるので、ご注意願います。
(注意) ここでの情報については、あくまでも各自の責任にて、充分にテストを行ってご使用ください。内容に関する質問については、回答できる保証がありませんので、予めご了承願います。


Q VBのアプリケーションの戻り値によってバッチファイルで分岐するには?

MS-DOSで作成したアプリケーションでは、終了時に終了コードを指定すれば、バッチファイルの ERRORLEVEL によってプログラムを分岐できましたが、VBのアプリケーションの戻り値によってバッチファイルを分岐させる事はできるのでしょうか?

A ファイル経由で分岐できます。

まず、VBから ERRORLEVEL の設定はすることができません。そこで他の方法を考えると、バッチファイルの IF 文で使用できるのは環境変数か、ファイルの存在のチェックだけです。簡単な方法としては、ファイルを VBで作成して、それを IF 文で判別させるのが良いと思います。

例として、3つのボタン配列を作成して、押されたボタンによってバッチファイルを分岐させてみましょう。
まづ、VB側のプログラムです。

Private Sub Command1_Click(Index As Integer)
    On Error Resume Next

    Kill "C:\TEMP\0.TMP"
    Kill "C:\TEMP\1.TMP"
    Kill "C:\TEMP\2.TMP"

    Open "C:\TEMP\" & Format$(Index, "0") & ".TMP" For Output As #1
    Close #1

   End
End Sub

見ても分かるように、まず Kill で以前に作られたファイルを削除してから、 Index に渡された値によって、"C:\TEMP\0.TMP"、"C:\TEMP\1.TMP"、"C:\TEMP\2.TMP" のいずれかのファイルを作成します。ファイルを作成したらすぐに End で終了します。
次にバッチファイルですが、次のようなバッチファイルを作成します。

START /W Project1.exe
IF EXIST C:\TEMP\0.TMP GOTO LABEL0
IF EXIST C:\TEMP\1.TMP GOTO LABEL1
IF EXIST C:\TEMP\2.TMP GOTO LABEL2

:LABEL0
ECHO Return = 0
PAUSE
EXIT

:LABEL1
ECHO Return = 1
PAUSE
EXIT

:LABEL2
ECHO Return = 2
PAUSE
EXIT

最初の START というコマンドは、/W というオプションをつけると、/W 以降に書かれたプログラムを実行して、終了するまで待ってくれます。前述のVBのプログラムを Project1.exe とすれば、押されたボタンによって、"C:\TEMP\0.TMP"、"C:\TEMP\1.TMP"、"C:\TEMP\2.TMP" のいずれかが作成されているはずです。作成されたファイルによって、LABEL0、LABEL1、LABEL2のいずれかにジャンプして ECHO で Return = 0 等を表示します。

(注意)このページの内容は、Visual Basic5.0(SP3) を対象に記述されています。他のバージョンでは、対応できないこともあるので、ご注意願います。
(注意) ここでの情報については、あくまでも各自の責任にて、充分にテストを行ってご使用ください。内容に関する質問については、回答できる保証がありませんので、予めご了承願います。


Q 二重起動を防止するには、どうすれば良いでしょうか?

VBで作成したEXEが、2つ同時に起動するのを防ぐにはどうしたら良いでしょうか?

A App.PrevInstance を使えば簡単にできますが...

単純に、同じプログラムが起動されたら終了するだけならば、Form_Load で以下のようなコーディングをすれば、二重起動を防止できます。

Private Sub Form_Load()
    If App.PrevInstance Then
        End
    End If

End Sub

この App.PrevInstance は、最初にプルグラムが起動された時には False が返されます。次に、同じプログラムが起動されると、この値は True となってプログラムが終了します。メッセージを表示したい場合には、End の前に MsgBox を入れれば表示できます。
(注意) App.PrevInstance は、プログラムが実行形式(EXE)になった場合のみ値が変ります。開発環境上では値は変りません。

次に、もうちょっと工夫して、同じプログラムを起動した場合には、最初に動いたプログラムをアクティブにして終了してみましょう。

Private Sub Form_Load()
    Dim strCaption As String

    If App.PrevInstance Then

        '現在のキャプションを保存
        strCaption = Me.Caption


        'キャプションとタイトルをダミーの文字列に設定
        Me.Caption = "$$$"
        App.Title = "$$$"


        '以前のウィンドウをアクティブにする
        AppActivate strCaption


        'Alt+SPACE と R を送って元のサイズに戻す
        SendKeys "% R", True
    End If

End Sub

まず最初に、このプログラムのキャプションを保存して、後から起動したウィンドウのキャプションを "$$$" という文字に変えます。これは、次の AppActivate で後から起動したプログラムをアクティブにしない為です。 AppActivate では、保存したキャプション(すなわち、最初に起動したプログラムのキャプション)のプログラムをアクティブにします。最後に SendKey ですが、Alt+SPACE を送ってコントロールボックスを開き、 "R" を送って、「元のサイズに戻す」を選択してます。この SendKey で、アイコン化されたプログラムも元のサイズに戻ります。

最後に、APIを使って開発環境でも使用できる方法を説明します。まず、標準モジュールに以下の定数と宣言を入れます。

(注意) APIビューワでの入力とは、宣言や定数が幾つか異なります。

Public Const MUTANT_ALL_ACCESS = &H1F0001

Declare Function OpenMutex Lib "kernel32" Alias "OpenMutexA" ( _
    ByVal dwDesiredAccess As Long, _
    ByVal bInheritHandle As Long, _
    ByVal lpName As String) As Long

Declare Function CreateMutex Lib "kernel32" Alias "CreateMutexA" ( _
    ByVal lpMutexAttributes As Long, _
    ByVal bInitialOwner As Long, _
    ByVal lpName As String) As Long

Declare Function CloseHandle Lib "kernel32" ( _
    ByVal hObject As Long) As Long

Declare Function ReleaseMutex Lib "kernel32" ( _
    ByVal hMutex As Long) As Long

Public Const SW_SHOWNORMAL = 1

Declare Function ShowWindow Lib "user32" ( _
    ByVal hwnd As Long, _
    ByVal nCmdShow As Long) As Long

Form_Load 、Form_QueryUnload に以下のようなコーディングを書きます。

Dim m_hMutex As Long

Private Sub
Form_Load()
    Dim PrevhMutex As Long

    PrevhMutex = OpenMutex(MUTANT_ALL_ACCESS, 0, Me.Caption)
    If PrevhMutex Then
        CloseHandle PrevhMutex
        End
    End If

    m_hMutex = CreateMutex(0, 0, Me.Caption)
End Sub


Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
    ReleaseMutex m_hMutex
    End
End Sub

これは、ミューテックスという手法を使用して、Windows のメモリ上に Me.Caption をキーとした領域を作成しています。最初の OpenMutex で、Me.Caption をキーとした領域があれば、PrevhMutex に 0 以外の数字が入ります。この領域があれば、既にプログラムが起動されたということで、この領域を CloseHandle でクローズして終了します。領域が無い場合は、まだ、このプログラムは起動されていないので、CreateMutex で Me.Caption をキーとした領域を作成して通常に起動します。プログラムの終了時に、ReleaseMutex でこの領域を消せば、次に起動したプログラムには領域が残っていないので、通常に起動します。
この方法は、開発環境で使用できるばかりでなく、本当に同じプログラムでなくとも
同じキーを使用したミューテックス同士で起動を制御する事ができます。
(注意)プログラムの終了は、Unload.Me 等を使用して、必ず Form_QueryUnload 経由で終了してください。

(注意)このページの内容は、Visual Basic5.0(SP3) を対象に記述されています。他のバージョンでは、対応できないこともあるので、ご注意願います。
(注意) ここでの情報については、あくまでも各自の責任にて、充分にテストを行ってご使用ください。内容に関する質問については、回答できる保証がありませんので、予めご了承願います。


Q SendKeys で DOSプロンプトに文字を送るには?

起動したDOSプロンプトに、SendKeys で文字を送っても、入力されません。どうしたら良いでしょうか?

A クリップボード経由で送れます

初めに、この方法は NT4.0(SP4) で cmd.exe を起動した場合には、必要ありません。そのまま、SendKeys でDOSプロンプトに文字を送ることができます。
Win98等のその他のバージョンの場合は、DOSプロンプトに送りたい文字をクリップボードにセットして、DOSプロンプトのメニューの貼付けを SendKeys で実行すれば、文字を送ることができます。
さっそくサンプルですが、以下の通りです。

Private Sub Command1_Click()
    Dim r

   '予め、送りたい文字をクリップボードにセット
    Clipboard.Clear
    Clipboard.SetText "Dir" & vbCr

    'DOSプロンプトを起動する
    r = Shell("command.com", vbNormalFocus)
    AppActivate r

    ' ALT+" "、"e"、"p" を送る(貼付けを実行)
    SendKeys "% ep", True

End Sub

このサンプルでは、DOSプロンプトが起動して、"Dir" が実行されます。
また、タイミングによって AppActivate がエラーになる場合は、以下のようにループさせればOKです(^^

   On Error Resume Next
    Do
        Err = 0
        AppActivate r
        If Err = 0 Then Exit Do
    Loop


(注意) ここでの情報については、あくまでも各自の責任にて、充分にテストを行ってご使用ください。内容に関する質問については、回答できる保証がありませんので、予めご了承願います。


Q アプリケーションのアクティブ、非アクティブを知るには?

アプリケーションがアクティブになったり、非アクティブになったときに、画面の表示を止めるなどの処理を行いたい場合がありますが、Activate や Deactivate イベントはアプリケーションのアクティブ、非アクティブでは発生しません。どのようにして取得するのでしょうか?

A サブクラスを使用します

アプリケーションのアクティブ、非アクティブを知るには、APIを使用して、ウィンドウのメッセージを横取りすれば判別できます。この方法をサブクラス化と言います。
サブクラス化では、APIを使用して、ウィンドウのメッセージを横取りする関数を指定します。タイミングとしては、フォームのLoadイベント等で、以下のように設定します。

Private Sub Form_Load()
    lpDefaultProc = SetWindowLong(Me.hWnd, GWL_WNDPROC, AddressOf WindowProc)
End Sub

ここで、WindowProc は横取りする関数の関数名です。また、lpDefaultProc は最後に横取りした関数を、元のウィンドウの関数に戻すための変数です。lpDefaultProc は標準モジュールに Public で宣言してください。

Public lpDefaultProc As Long

元のウィンドウの関数に戻すには、フォームのUnloadイベント等で以下のように指定します。

Private Sub Form_Unload(Cancel As Integer)
    Call SetWindowLong(Me.hWnd, GWL_WNDPROC, lpDefaultProc)
End Sub

あとは、横取りした関数を作成します。この関数は、標準モジュールに作成してください。
(注意)この関数にバグがある場合には、実行するとVBごと飛びます。必ず作成したプログラムを保存してから実行してください。

Public Function WindowProc(ByVal hWnd As Long, ByVal uMsg As Long, _
            ByVal wParam As Long, ByVal lParam As Long) As Long


    If uMsg = WM_ACTIVATE Then
        If wParam = WA_INACTIVE Then
            '非アクティブの処理
        Else
            'アクティブの処理
        End If
    End If

   'デフォルトのウィンドウ関数を呼び出す
    WindowProc = CallWindowProc(lpDefaultProc, hWnd, uMsg, wParam, lParam)

End Function

uMsg が WM_ACTIVATE の場合、アクティブ、非アクティブが切替っています。その時、wParam には以下の状態が返されます。

wParam 意味
WA_ACTIVE アクティブとなった(クリックの場合以外)
WA_CLICKACTIVE クリックされてアクティブとなった
WA_INACTIVE 非アクティブとなった

コメントでアクティブの処理、非アクティブの処理と書かれたところに、各処理を記述します。

以下は、宣言部です。標準モジュールに入れてください。

Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" ( _
    ByVal hWnd As Long, _
    ByVal nIndex As Long, _
    ByVal dwNewLong As Long) As Long

Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" ( _
    ByVal lpPrevWndFunc As Long, _
    ByVal hWnd As Long, _
    ByVal Msg As Long, _
    ByVal wParam As Long, _
    ByVal lParam As Long) As Long

Public Const WM_ACTIVATE = &H6
Public Const WA_ACTIVE = 1
Public Const WA_INACTIVE = 0
Public Const WA_CLICKACTIVE = 2


Public Const GWL_WNDPROC = (-4)

(注意)くどいようですが(^^; このプログラムにバグがある場合には、実行するとVBごと飛びます。必ず作成したプログラムを保存してから実行してください。

(注意)このページの内容は、Visual Basic6.0(SP3) を対象に記述されています。他のバージョンでは、対応できないこともあるので、ご注意願います。

(注意) ここでの情報については、あくまでも各自の責任にて、充分にテストを行ってご使用ください。内容に関する質問については、回答できる保証がありませんので、予めご了承願います。