VBAでマルチモニタ情報を得よう

相変わらずExcel VBAをいじってます。
VBAで、ディスプレイ周りの話なら、こちらも参考にしてほしい。


今回はExcelのウィンドウ位置を邪魔にならないところに自動配置したかった。
が、マルチディスプレイのときにどうすんじゃい。
というわけで、ディスプレイの情報を全部チェックして、Excelの今いるモニタを取得する。
古い人間なので、ハンガリアン記法が好きです。

Option Explicit

' EnumDisplayMonitorsで使用するためのRECT構造体宣言
Private Type RECT
    Left As Long
    Top As Long
    Right As Long
    Bottom As Long
End Type

#If Win64 Then
    Private Declare PtrSafe Function EnumDisplayMonitors Lib "User32" (ByVal hdc As LongPtr, ByVal lprcClip As Long, ByVal lpfnEnum As LongPtr, ByVal dwData As LongPtr) As Long
    Private Declare PtrSafe Function GetSystemMetrics Lib "User32" (ByVal nIndex As Long) As Long
#Else
    Private Declare Function EnumDisplayMonitors Lib "User32" (ByVal hdc As Long, ByVal lprcClip As Long, ByVal lpfnEnum As Long, ByVal dwData As Long) As Long
    Private Declare Function GetSystemMetrics Lib "User32" (ByVal nIndex As Long) As Long
#End If

' EnumDisplayMonitorsで取得するモニタ情報を格納するためのメンバ変数
Private coMonitors As Collection

' EnumDisplayMonitors 関数によって呼び出されるコールバック
#If Win64 Then
Private Function monitorEnumProc(ByVal hMonitor As LongPtr, ByVal hdcMonitor As LongPtr, ByRef lprcMonitor As RECT, ByVal dwData As LongPtr) As Long
#Else
Private Function monitorEnumProc(ByVal hMonitor As Long, ByVal hdcMonitor As Long, ByRef lprcMonitor As RECT, ByVal dwData As Long) As Long
#End If
' 取得失敗とみなすのは呼び元で実施するので、ここではエラーは発生させない
On Error Resume Next
    ' Left、Top、Width、Heightの順に格納
    Call coMonitors.Add(Array(lprcMonitor.Left, lprcMonitor.Top, lprcMonitor.Right - lprcMonitor.Left, lprcMonitor.Bottom - lprcMonitor.Top))
    ' 続行
    monitorEnumProc = 1
End Function

' モニタ情報を取得
Public Function GetMonitorInfo(ByRef lngLeft As Long, ByRef lngTop As Long, ByRef lngWidth As Long, ByRef lngHeight As Long) As Boolean
On Error GoTo ErrorFunction
    
    ' メインモニタの情報で初期化
    GetMonitorInfo = True
    lngLeft = 0
    lngTop = 0
    lngWidth = GetSystemMetrics(0)
    lngHeight = GetSystemMetrics(1)
    
    Dim i As Long
    
    ' モニタ情報をすべて取得
    Set coMonitors = New Collection
    Call EnumDisplayMonitors(0, 0, AddressOf monitorEnumProc, 0)
    
    ' モニタ情報が取得できたか
    If Not coMonitors Is Nothing Then
        ' マルチモニタか
        If 1 < coMonitors.count Then
            ' 自身がいるモニタを検索
            For i = 1 To coMonitors.count
                If coMonitors(i)(0) <= Application.Left _
                    And Application.Left <= (coMonitors(i)(0) + coMonitors(i)(2)) _
                    And coMonitors(i)(1) <= Application.Top _
                    And Application.Top <= (coMonitors(i)(1) + coMonitors(i)(3)) Then
                    lngLeft = coMonitors(i)(0)
                    lngTop = coMonitors(i)(1)
                    lngWidth = coMonitors(i)(2)
                    lngHeight = coMonitors(i)(3)
                    Exit For
                End If
            Next i
        End If
    End If
    
    ' ここまで正常終了すればTrueを返す
    GetMonitorInfo = True
ErrorFunction:
End Function

例えば、Excelを今居るモニタの右上あたりに移動したいなら、こんな感じ。

Dim lngLeft As Long, lngTop As Long, lngWidth As Long, lngHeight As Long
If GetMonitorInfo(lngLeft, lngTop, lngWidth, lngHeight) Then
    ' 1ピクセル = 0.75ポイントに変換しながら右上1/4の場所に移動
    Application.Left = (lngLeft + (3 / 4 * lngWidth)) * 0.75
    Application.Top = (lngTop + (1 / 4 * lngHeight)) * 0.75
End If

他にもニッチなIT関連要素をまとめていますので、よければ一覧記事もご覧ください。

返信を残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)