トップ回答者
[Excel 2016] 特定の Excel ウィンドウ上のユーザーフォームがアクティブだったかどうかを調べる方法はないでしょうか

質問
-
例えば、ユーザーフォームをモードレスで表示させてそのユーザーフォーム上にあるボタンなどの
コントロールから新規ブックを作成したり (Workbooks.Add) 開いたり (Workbooks.Open) すると
その新しいうぶっくのウィンドウが勝手にアクティブになってしまいますよね。
(本当はアクティブにしないで新規作成や開けたらいいんですけど仕様のようなのであきらめてますが)そのあと手動でタスクバーや Ctrl + Tab によって元のウィンドウをアクティブにするとユーザーフォームは
(コントロール上のフォーカスは消えてしまうものの) アクティブなままです。しかし、新規作成したブックを閉じたり、ThisWorkbook.Activate などを使ってアクティブに戻すと
ワークブックのウィンドウの方がアクティブになってしまいます。具体的にはこれを防止、もしくは対策する方法が知りたいです。
(また、ユーザーフォームがアクティブでなかったときはアクティブにしないようにしたい)そこでひとつ案として浮かんだのがユーザーフォームが表示されているウィンドウのユーザーフォームが
アクティブだったかどうかを調べる方法がないかと、Spy++ で Excel ウィンドウやユーザーフォームの
メッセージを調べたり、SetWindowPos で Z オーダーを変えてみたりなどの試行錯誤したものの、
うまくいきません。
(SetWindowPos で Z オーダーを変更してもアクティブなウィンドウやフォーカスのあるウィンドウは
変わらないようですね)なにか、いい方法はないでしょうか。
タスクバーからアクティブにした時の動作が API で再現できればそれが一番いいとは思いますが。
回答
-
みなさま、お返事ありがとうございます。
その後、またいろいろと試行錯誤したり調べたところ、ずばりそのものといえる
GetLastActivePopup 関数でなんとかできました。Private Declare PtrSafe Function SetWindowPos Lib "user32" (ByVal hWnd As LongPtr, ByVal hWndInsertAfter As LongPtr, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long Private Declare PtrSafe Function SetForegroundWindow Lib "user32" (ByVal hWnd As LongPtr) As Long Private Declare PtrSafe Function GetLastActivePopup Lib "user32" (ByVal hwndOwnder As LongPtr) As LongPtr Private Declare PtrSafe Function WindowFromAccessibleObject Lib "oleacc" ( _ ByVal pacc As Object, ByRef phwnd As LongPtr) As Long Private Declare PtrSafe Function GetNextWindow Lib "user32" Alias "GetWindow" (ByVal hWnd As LongPtr, ByVal wFlag As Long) As LongPtr Private Const GW_OWNER As Integer = 4 Private Const HWND_TOP As Integer = 0 Private Const SWP_NOACTIVATE As Integer = &H10 Private Const SWP_NOSIZE As Integer = &H1 Private Const SWP_NOMOVE As Integer = &H2 Private Const SWP_NOSENDCHANGING As Integer = &H400 Private Sub CommandButton1_Click() Dim wb As Workbook Dim hWnd As LongPtr Set wb = Workbooks.Add hWnd = GetLastActivePopup(GetNextWindow(GetHwnd, GW_OWNER)) SetWindowPos hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE Or SWP_NOSIZE Or SWP_NOMOVE Or SWP_NOSENDCHANGING SetForegroundWindow hWnd wb.Close End Sub
Private Sub CommandButton2_Click()
SetForegroundWindow GetNextWindow(GetHwnd, GW_OWNER)
CommandButton1_Click
End Sub
Function GetHwnd() As LongPtr WindowFromAccessibleObject Me, GetHwnd End Function
- 回答としてマーク infade 2019年4月16日 8:16
すべての返信
-
みなさま、お返事ありがとうございます。
その後、またいろいろと試行錯誤したり調べたところ、ずばりそのものといえる
GetLastActivePopup 関数でなんとかできました。Private Declare PtrSafe Function SetWindowPos Lib "user32" (ByVal hWnd As LongPtr, ByVal hWndInsertAfter As LongPtr, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long Private Declare PtrSafe Function SetForegroundWindow Lib "user32" (ByVal hWnd As LongPtr) As Long Private Declare PtrSafe Function GetLastActivePopup Lib "user32" (ByVal hwndOwnder As LongPtr) As LongPtr Private Declare PtrSafe Function WindowFromAccessibleObject Lib "oleacc" ( _ ByVal pacc As Object, ByRef phwnd As LongPtr) As Long Private Declare PtrSafe Function GetNextWindow Lib "user32" Alias "GetWindow" (ByVal hWnd As LongPtr, ByVal wFlag As Long) As LongPtr Private Const GW_OWNER As Integer = 4 Private Const HWND_TOP As Integer = 0 Private Const SWP_NOACTIVATE As Integer = &H10 Private Const SWP_NOSIZE As Integer = &H1 Private Const SWP_NOMOVE As Integer = &H2 Private Const SWP_NOSENDCHANGING As Integer = &H400 Private Sub CommandButton1_Click() Dim wb As Workbook Dim hWnd As LongPtr Set wb = Workbooks.Add hWnd = GetLastActivePopup(GetNextWindow(GetHwnd, GW_OWNER)) SetWindowPos hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE Or SWP_NOSIZE Or SWP_NOMOVE Or SWP_NOSENDCHANGING SetForegroundWindow hWnd wb.Close End Sub
Private Sub CommandButton2_Click()
SetForegroundWindow GetNextWindow(GetHwnd, GW_OWNER)
CommandButton1_Click
End Sub
Function GetHwnd() As LongPtr WindowFromAccessibleObject Me, GetHwnd End Function
- 回答としてマーク infade 2019年4月16日 8:16