ウインドウを一時的にアクティブにして最前面に持ってくる
後ろで動いてるアプリを手前に持ってくる関数です。いつも作るうえに、毎回調べないと作れないので載せておきます。
ちなみに、ウインドウが「常に」最前面に表示されるようにするには、SetWindowPos 関数で HWND_TOPMOST を渡します。でもこれはググればごろごろサンプル出てくるんですけどね。
Option Explicit Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hWnd As Long, lpdwProcessId As Long) As Long Private Declare Function GetForegroundWindow Lib "user32" () As Long Private Declare Function AttachThreadInput Lib "user32" (ByVal idAttach As Long, ByVal idAttachTo As Long, ByVal fAttach As Long) As Long Private Declare Function BringWindowToTop Lib "user32.dll" (ByVal hWnd As Long) As Long Private Declare Function SetForegroundWindow Lib "user32" (ByVal hWnd As Long) As Long Private Const FORMAT_MESSAGE_FROM_SYSTEM As Long = &H1000& Private Const FORMAT_MESSAGE_IGNORE_INSERTS As Long = &H200& Private Declare Function FormatMessage Lib "kernel32" Alias "FormatMessageA" (ByVal dwFlags As Long, lpSource As Any, ByVal dwMessageId As Long, ByVal dwLanguageId As Long, lpBuffer As Any, ByVal nSize As Long, Arguments As Long) As Long '****************************************************************** 'プロシージャ名 :ForceSetForegroundWindow '説明 :フォームを強制的にアクティブにする '引数 :pfrmTarget I アクティブにするウインドウ '****************************************************************** Public Sub ForceSetForegroundWindow(pfrmTarget As VB.Form) '============= Declare ============== Dim lngRet As Long Dim hWndActive As OLE_HANDLE Dim hThreadActive As OLE_HANDLE '============= Initiarize =========== On Error GoTo ERR_HANDLER_00 '============= Main ================= '' 現在アクティブなスレッドを取得する hWndActive = GetForegroundWindow() If (0& = hWndActive) Then Call DllErrRaise(Err.LastDllError, "GetForegroundWindow") End If hThreadActive = GetWindowThreadProcessId(hWndActive, ByVal 0&) If (0& = hThreadActive) Then Call DllErrRaise(Err.LastDllError, "GetWindowThreadProcessId") '' 自分自身がアクティブなら、ただ最前面にするだけ ElseIf App.ThreadID = hThreadActive Then lngRet = SetForegroundWindow(pfrmTarget.hWnd) If (0& = lngRet) Then Call DllErrRaise(Err.LastDllError, "SetForegroundWindow") End If '' 自分自身がアクティブでなければ、アクティブなスレッドにアタッチする Else lngRet = AttachThreadInput(App.ThreadID, hThreadActive, 1&) If (0& = lngRet) Then Call DllErrRaise(Err.LastDllError, "AttachThreadInput") Else On Error GoTo ERR_HANDLER_10 '' ウインドウをアクティブにする lngRet = SetForegroundWindow(pfrmTarget.hWnd) If (0& = lngRet) Then Call DllErrRaise(Err.LastDllError, "SetForegroundWindow") End If '' スレッドをデタッチする lngRet = AttachThreadInput(App.ThreadID, hThreadActive, 0&) If (0& = lngRet) Then Call DllErrRaise(Err.LastDllError, "AttachThreadInput") End If On Error GoTo ERR_HANDLER_00 End If End If '============= Release ============== RESUME_00: Exit Sub '============= Error ================ ERR_HANDLER_10: '' スレッドをデタッチする Call AttachThreadInput(App.ThreadID, hThreadActive, 0&) ERR_HANDLER_00: Call Err.Raise(Err.Number, "basCommonFunc.ForceSetForegroundWindow ← " & Err.Source, Err.Description, Err.HelpFile, Err.HelpContext) End Sub '****************************************************************** 'プロシージャ名: :DllErrRaise '説明: :Err.LastDllErrorよりエラーを発生する '引数: :plngLastDllError I Err.LastDllError ' :pstrErrSource I エラーソース文字列 '****************************************************************** Public Sub DllErrRaise(ByVal plngLastDllError As Long, pstrErrSource As String) '============= Declare ============== Const clngMAX_BUFFER As Long = 1024& Dim bytBuf(clngMAX_BUFFER - 1&) As Byte 'バッファ Dim lngRet As Long 'APIの戻り値 Dim strErrDescription As String '============= Initiarize =========== If plngLastDllError = 0& Then Exit Sub End If Erase bytBuf strErrDescription = "" '============= Main ================= ' エラー値に対応するメッセージを取得する lngRet = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM Or FORMAT_MESSAGE_IGNORE_INSERTS, _ ByVal 0&, _ plngLastDllError, _ 0&, _ bytBuf(0), _ clngMAX_BUFFER, _ ByVal 0&) If lngRet Then strErrDescription = StrConv(LeftB(bytBuf, lngRet - 2&), vbUnicode) End If ' エラーを発生する Call Err.Raise(plngLastDllError Or vbObjectError, pstrErrSource, strErrDescription) End Sub
トラックバック
- このエントリーにトラックバック:
- http://frog.raindrop.jp/cgi-bin/mt/mt-tb.cgi/836
コメント
大変参考になりました!
ありがとうございますm(_ _)m
> kk さん
いらっしゃいませ。お役に立てましたでしょうか。
また来てくださいね (^-^)/
こんばんわ。
ExcelVBAを裏で動かし、他のアプリからテキストデータを裏のExcelシートに貼り付けています。マクロでエラーが出たときに、Excelを最前面に表示し、MsgBoxの表示を確認できるようにするために使わせてもらおうと思います。
そこで、マクロの標準モジュールにコードをコピーして、UserFormから呼び出すようにしたのですが、”ユーザー定義型は定義されていません。”というコンパイルエラーが出てしまいました。VBAそのものが初心者なので、対応がわかりません。
ご教示よろしくお願いします。
> terasan さん
Excel VBA で動かしたということは、多分 VB.Form が引っ掛かったんでしょうね。
このソースコードは VB6 時代の物で、
VB.Form は Visual Basic objects and procedures (VB6.OLB) という
ライブラリで定義されているものなので、残念ながら Excel のウインドウや UserForm とは互換性がありません。
また、App.ThreadID を参照している部分もそのままでは使用できないと思います。
生憎、今環境がなくて試してみていないんですが、
Excel マクロから Excel 自身をアクティブにするのであれば、
Call AppActivate(Application.Caption)
が利用できる気がするんですけど、いかがでしょうか?
おはようございます。
早速ご回答いただきありがとうございました。
AppActivate Application.Caption
を実行してみましたが、Excelのウインドウは他のアプリの裏になったままでした。Excelのキャプションをアクティブにするということと、モニター上の表示順位は無関係なんでしょうかね。
力不足でよくわかりません。
こんにちわ。
いろいろ探索してみた結果、以下の方のサンプルで解決できました。ありがとうございました。御礼とご報告まで。
http://naruhodo.television.co.jp/qa4876776.html?order=DESC&by=datetime
こんにちは、またブログ覗かせていただきました。また、遊びに来ま~す。よろしくお願いします