質問: VBSについての質問です。 フォルダ内のテキストメッセージ数を10分間隔で通知するシステムを作成しました。 なければ、通知は来ずという形のシステムになっています。 メッセージボックスが立ち上がるようにしているのですが、1回目の通知だけ、他のアプリケーションで作業していると、タスクバーに隠れていて、きちんと前面に出てきません 通知が来たら、オッケーを押し、次の通知の際は、前面に出てくるようになります。 1回目の通知から、きちんと前面に出すことはできますか?
回答: 【予備知識】 フォアグラウンドウィンドウ(アクティブウィンドウとも呼ばれますが、キーボード入力を受け取れるウィンドウのこと。)は「常に一つだけ」ということが大前提としてあります。 ある任意のウィンドウをフォアグラウンドウィンドウにするには、そのプロセスID を対象にして OS に申請する必要があります。 成功するとフォアグラウンドウィンドウの権限を取得している間だけ、ウィンドウは最前面に表示されてフォーカスがセットされます。 但し万が一、いま現在のフォアグラウンドウィンドウが、OS からの明け渡し要求を無効化する関数が実行されているアプリのウィンドウだった場合だけは、確実に失敗してタスクバーのアイコンが点滅するだけになってしまいます。そのため、開いているアプリとの組み合わせ次第で成功率100%には成らないケースがあります。 【環境構築】 成功率が高い Win32 API を利用した方法をご紹介しようと思いますが、Win32 API を動かすための実行環境の構築(Windows10 でも動作するフリーソフト)が必要になってきます。 私はインストールして使っていますが、インストールせずとも使う方法があるようです。 SFC mini (インストールの項目参照) ソフトのダウンロードはベクターから(32bit版のみ) SFC miniの詳細情報 : Vector ソフトを探す! 【動作の概要】 MsgBox 関数で表示されるウィンドウはモードレス動作には出来ないので、人間が応答するまでは以降のコードの実行が停止したままになります。 そのため、表示させているプロセスとは別のプロセスで、表示する毎に以下のコードを実行します。 64bitOS で、変数 lngAllowResult と lngFinalResult の実行後の値が 0 だった(関数の実行が失敗した)場合、スクリプトエンジンの WSH を SysWow64フォルダー内の WSH ("wscript.exe") を指定して実行してみてください。 【開発・テスト環境】 Windows10 Home 32bit 21H1 (SFC mini をインストール済み) 【ソースコード】 ' --- WSH (VBScript) --- SFC mini 必要 ---- ' ウィンドウタイトル(MsgBox 関数の第3引数)を識別して該当 ' するウィンドウをフォアグラウンドウィンドウに設定します。 Option Explicit Const strWindowTitle = "hogehoge" Call SetForegroundWindowByTitle(strWindowTitle) ' ------------------------------------- Private Sub SetForegroundWindowByTitle(strWindowTitle) Dim objWinAPI Set objWinAPI = WScript.CreateObject("SfcMini.DynaCall") With objWinAPI .LoadLibraries "user32", "kernel32" Dim hWnd hWnd = .FindWindowA(vbNullString, strWindTitle) Dim ThreadID ThreadID = .GetWindowThreadProcessId(hWnd, 0) Dim hThread Const THREAD_QUERY_INFORMATION = &H40 hThread = .OpenThread( _ THREAD_QUERY_INFORMATION, False, ThreadID) Dim ProcessID ProcessID = .GetProcessIdOfThread(hThread) Dim lngAllowResult lngAllowResult = .AllowSetForegroundWindow(ProcessID) If lngAllowResult = 0 Then Dim objWshShell Set objWshShell = WScript.CreateObject("WScript.Shell") objWshShell.Appactivate ProcessID Set objWshShell = Nothing Else Dim lngFinalResult lngFinalResult = .SetForegroundWindow(hWnd) End If End With Set objWinAPI = Nothing End Sub ' -------- コードここまで ----------------------