VBAでDPI値を知りたいお年頃

どうも、ゆるめのミニマリスト&へっぽこSEのアシアです。
今日の話は…

avatar

アシア

DPI値っていうと堅苦しいけど、要は、ディスプレイ設定の「テキスト、アプリ、その他の項目のサイズ」ってやつが100%かどうかを知りたいお年頃です。
いくつか方法があるのでつらつらと説明していきます。

これね。

GetDpiForMonitorで取得する

このコードを書いたExcelブックを起動した状態のまま、テキストサイズを変更しても最新値は取れないので、Excelブックの再起動が必要です。

Option Explicit

Private Const S_OK = 0

Private Enum MONITOR_DPI_TYPE
  MDT_EFFECTIVE_DPI = 0
  MDT_ANGULAR_DPI = 1
  MDT_RAW_DPI = 2
  MDT_DEFAULT = MDT_EFFECTIVE_DPI
End Enum

Private Enum MONITOR_DEFAULTS
    MONITOR_DEFAULTTONULL = &H0&
    MONITOR_DEFAULTTOPRIMARY = &H1&
    MONITOR_DEFAULTTONEAREST = &H2&
End Enum

#If Win64 Then
    Private Declare PtrSafe Function GetDesktopWindow Lib "User32" () As Long
    Private Declare PtrSafe Function GetDpiForMonitor Lib "shcore" ( _
        ByVal hMonitor As Long, ByVal dpiType As MONITOR_DPI_TYPE, _
        ByRef dpiX As Long, ByRef dpiY As Long) As Long
    Private Declare PtrSafe Function MonitorFromWindow Lib "User32" ( _
        ByVal Hwnd As Long, ByVal dwFlags As MONITOR_DEFAULTS) As Long
#Else
    Private Declare Function GetDesktopWindow Lib "User32" () As Long
    Private Declare Function GetDpiForMonitor Lib "shcore" ( _
        ByVal hMonitor As Long, ByVal dpiType As MONITOR_DPI_TYPE, _
        ByRef dpiX As Long, ByRef dpiY As Long) As Long
    Private Declare Function MonitorFromWindow Lib "User32" ( _
        ByVal Hwnd As Long, ByVal dwFlags As MONITOR_DEFAULTS) As Long
#End If

Private Sub cmdGetDpi_Click()
    Dim dpiX As Long
    Dim dpiY As Long

    If GetDpiForMonitor(MonitorFromWindow(GetDesktopWindow(), MONITOR_DEFAULTTONEAREST), _
                        MDT_DEFAULT, dpiX, dpiY) = S_OK Then
        Debug.Print "dpiX = " & CStr(dpiX) & " (" & CStr(CSng(dpiX * 100) / 96) & "%)" & vbNewLine _
                   & "dpiY = " & CStr(dpiY) & " (" & CStr(CSng(dpiY * 100) / 96) & "%)"
    End If
End Sub

Twipから求める

Microsoft独自単位のTwipは96dpi(100%)であれば15Twip=1pixelであることを利用して求めます。
以前は変更後にサインアウトしないと最新の値が取れなかったのですが、最近は取れるようになった?
ただ、このコードを書いたExcelブックも、起動した状態のままテキストサイズを変更しても最新値は取れないので、Excelブックの再起動が必要です。

Option Explicit

#If Win64 Then
    Private Declare PtrSafe Function GetDesktopWindow Lib "User32" () As Long
    Private Declare PtrSafe Function GetDC Lib "User32" (ByVal Hwnd As Long) As Long
    Private Declare PtrSafe Function GetDeviceCaps Lib "gdi32" (ByVal hdc As Long, ByVal nIndex As Long) As Long
    Private Declare PtrSafe Function ReleaseDC Lib "User32" (ByVal Hwnd As Long, ByVal hdc As Long) As Long
#Else
    Private Declare Function GetDesktopWindow Lib "User32" () As Long
    Private Declare Function GetDC Lib "User32" (ByVal Hwnd As Long) As Long
    Private Declare Function GetDeviceCaps Lib "gdi32" (ByVal hdc As Long, ByVal nIndex As Long) As Long
    Private Declare Function ReleaseDC Lib "User32" (ByVal Hwnd As Long, ByVal hdc As Long) As Long
#End If

Sub test()
    Dim hWndDesk As Long        ' デスクトップのハンドル
    Dim hDCDesk As Long         ' デスクトップのDC
    Dim nPix As Long            ' 画面の水平方向での論理インチ当たりのピクセル数
    Dim nTwip As Long           ' ピクセルのTwip変換結果
    
    Const KLNG_LOGPIXELSX = 88  ' GetDeviceCapsに渡す引数
    Const KLNG_PIX = 1440       ' 1 論理インチは 1440twip
    Const KLNG_TWIP = 15        ' Microsoft Windowsの標準のシステム解像度では15Twipsで1ピクセル
    
    ' 画面の水平方向での論理インチ当たりのピクセル数を取得
    hWndDesk = GetDesktopWindow()
    hDCDesk = GetDC(hWndDesk)
    nPix = GetDeviceCaps(hDCDesk, KLNG_LOGPIXELSX)
    
    ' ピクセル->Twipに変換
    nTwip = KLNG_PIX / nPix
    
    ' 15なら100%
    Debug.Print "nTwip = " & nTwip
    
    Call ReleaseDC(hWndDesk, hDCDesk)
End Sub

Win32_DisplayConfigurationはダメっぽい?

150%にしてても96dpi(100%)が取得されちゃったんですが、なんで??
教えてすごい人!

Option Explicit

Sub test()
    Dim objClassSet As Object
    Dim objClass As Object
    
    Set objClassSet = CreateObject("WbemScripting.SWbemLocator") _
                        .ConnectServer _
                        .ExecQuery("Select * From Win32_DisplayConfiguration")
    For Each objClass In objClassSet
        Debug.Print "LogPixels = " & CStr(objClass.LogPixels)
    Next objClass
    
    Set objClassSet = Nothing
    Set objClass = Nothing
End Sub

レジストリから取得する

Windows8.1ならHKCU \ Control Panel \ Desktop \ logpixelsで取得できるってMicrosoft様がおっしゃるけれど、Windows10にはデフォルトで存在しなかった。
Win8DpiScalingっていうキナ臭いキーはありましたが、やりたいことから外れすぎてるので調査は中断。


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

返信を残す

メールアドレスが公開されることはありません。

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