プロが教える店舗&オフィスのセキュリティ対策術

いつもお世話になっております。
フォームにコマンドボタンを1つ配置たエクセルと、別にメモ帳を立上げています。
コマンドボタンを押す度にメモ帳 → VBAのフォーム → メモ帳とアクティブなアプリを切り替えて
行きたいです。
次のプログラムで試してみましたが、うまく切り替わりません。手動でALT + TABを押すと毎回切り替
わるのですが、VBAではうまく動作しません。単純なプログラムのためどこが間違っているのか見当が
つきません。よろしくご指導おねがいいたします。(Windows10 Excel 2016 64Bit)

'フォームモジュール
Private Sub UserForm_Initialize()
Dim ret As Long
Dim formHWnd As Long
formHWnd = FindWindow("ThunderDFrame", Me.Caption)
ret = SetWindowPos(formHWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE)
Application.WindowState = xlMinimized
End Sub

Private Sub CommandButton1_Click()
SendKeys "%({TAB})"
End Sub

'標準モジュール
Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" _
        (ByVal lpClassName As String, ByVal lpWindowName As String) As Long

Declare PtrSafe Function SetWindowPos Lib "user32" _
(ByVal hwnd As LongPtr, ByVal hWndInsertAfter As LongPtr, _
ByVal X As LongPtr, ByVal Y As LongPtr, ByVal cX As LongPtr, _
ByVal cY As LongPtr, ByVal uFlags As LongPtr) As Long

Public Const SWP_NOMOVE = &H2
Public Const SWP_NOSIZE = &H1
Public Const HWND_TOPMOST = -1

Sub Auto_Open()
Application.WindowState = xlMinimized
UserForm1.Show vbModeless
End Sub

A 回答 (1件)

具体的な現象がよく分からないのですが、コードから推測されるトラブルについて解説します。



・ウィンドウサムネイルが瞬間的に表示
Alt + Tab でのウィンドウ切替えは、Alt を Press しながらでの Tab の Down Up の繰り返しとなるだけに SendKeys では無理です。
少し動作は異なりますが、Ctrl + Alt + Tab で先ずウィンドウサムネイルを表示し、Tab または Shift + Tab でウィンドウを選択後に Enter で決定とした方が良いと思います。

・エラー発生
FindWindowA関数の戻り値は Win32型の HWND型 (メモリへの参照アドレスが格納される構造体のポインタ) です。
また、SetWindowPos関数の引数 hWndInsertAfter のデータ型は Win32型で HWND型ですが、今回は HWND_TOPMOST定数を使いますので VBA では Long型になります。モニタ座標は Win32型の int型 なので、同じく Long型です。
FindWindowA関数 | Microsoft Docs (英語)
https://docs.microsoft.com/en-us/windows/win32/a …
SetWindowPos関数 | Microsoft Docs (英語)
https://docs.microsoft.com/en-us/windows/win32/a …

' Excel 64Bit, 32Bit 共通コード。お好みでアレンジしてください。
' コード中の #If Win64 Then は Excel が 64Bit版かどうかを判定。
' Windows10 Excel 2007 (32Bit版のみ) で動作確認済み。
' Sleep関数の時間指定はミリ秒単位で少し長めに設定。

' フォームモジュール

Option Explicit


Private Sub UserForm_Initialize()

#If Win64 Then
Dim formHWnd As LongPtr
#Else
Dim formHWnd As Long
#End If

Const windowClassName As String = "ThunderDFrame"
formHWnd = FindWindow( _
windowClassName, _
Me.Caption)

Const HWND_TOPMOST As Long = -&H1
Const X As Long = 0
Const Y As Long = 0
Const cX As Long = 0
Const cY As Long = 0
Const SWP_NOMOVE As Long = &H2
Const SWP_NOSIZE As Long = &H1
Call SetWindowPos( _
formHWnd, _
HWND_TOPMOST, _
X, _
Y, _
cX, _
cY, _
SWP_NOMOVE Or SWP_NOSIZE)

Application.WindowState = xlMinimized

End Sub


Private Sub CommandButton1_Click()

Dim WshShell As Object
Set WshShell = CreateObject("WScript.Shell")

With WshShell
.SendKeys "^(%{TAB})"

Call Sleep(150)
.SendKeys "{TAB}"

Call Sleep(50)
.SendKeys "{ENTER}"
End With

Set WshShell = Nothing

End Sub


Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)

Application.WindowState = xlNormal

End Sub


' 標準モジュール
Option Explicit

#If Win64 Then
Public Declare PtrSafe Function FindWindow Lib "user32" _
Alias "FindWindowA" ( _
ByVal lpClassName As String, _
ByVal lpWindowName As String _
) As LongPtr

Public Declare PtrSafe Sub SetWindowPos Lib "user32" ( _
ByVal hwnd As LongPtr, _
ByVal hWndInsertAfter As Long, _
ByVal X As Long, _
ByVal Y As Long, _
ByVal cX As Long, _
ByVal cY As Long, _
ByVal uFlags As Long _
)

Public Declare PtrSafe Sub Sleep Lib "kernel32" ( _
ByVal ms As Long _
)
#Else
Public Declare Function FindWindow Lib "user32" _
Alias "FindWindowA" ( _
ByVal lpClassName As String, _
ByVal lpWindowName As String _
) As Long

Public Declare Sub SetWindowPos Lib "user32" ( _
ByVal hwnd As Long, _
ByVal hWndInsertAfter As Long, _
ByVal X As Long, _
ByVal Y As Long, _
ByVal cX As Long, _
ByVal cY As Long, _
ByVal uFlags As Long _
)

Public Declare Sub Sleep Lib "kernel32" ( _
ByVal ms As Long _
)
#End If


Sub Auto_Open()

Application.WindowState = xlMinimized
UserForm1.Show vbModeless

End Sub
    • good
    • 0
この回答へのお礼

大変ご丁寧なご指導ありがとうございました。勉強になりました。

>Ctrl + Alt + Tab で先ずウィンドウサムネイルを表示し、Tab または Shift + Tab で
>ウィンドウを選択後に Enter で決定とした方が良いと思います。

知らなかったです。またSleepをいれることも気が付かなかったです。
但しSleepを何mSceにするかは、PCの処理能力によっても変える必要があ
ると思い処理能力のことなる複数のPCで利用することを考えると、汎用的
ではないかなと思いました。

質問後、自分でも色々調べましたがSendKeysは不安定であまり評判が良くな
い記事が多くみられました。
なのでこれから以前自分でも使用実績のあるkeybd_eventを使って試してみ
ようと思います。ありがとうございました。

お礼日時:2021/01/01 06:51

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています