VBAとWin32 APIで実現する:UAC(ユーザーアカウント制御)設定状態の確実な判定手法

Tech

本記事はGeminiの出力をプロンプト工学で整理した業務ドラフト(未検証)です。

VBAとWin32 APIで実現する:UAC(ユーザーアカウント制御)設定状態の確実な判定手法

【背景と目的】

PC設定に依存するファイル操作エラーを防ぐため、UACの有効状態をレジストリから取得し、管理権限が必要な処理の実行可否を事前判定します。

【処理フロー図】

graph TD
A["開始"] --> B["Win32 API宣言"]
B --> C["レジストリキー HKLM を開く"]
C --> D{"キーの読込成功?"}
D -- No --> E["エラー終了"]
D -- Yes --> F["EnableLUA 値を取得"]
F --> G["レジストリキーを閉じる"]
G --> H["UAC状態を判定・返却"]
H --> I["終了"]

【実装:VBAコード】

Option Explicit

' --- Win32 API 宣言 (64bit/32bit両対応) ---
Private Declare PtrSafe Function RegOpenKeyEx Lib "advapi32.dll" Alias "RegOpenKeyExA" ( _
    ByVal hKey As LongPtr, _
    ByVal lpSubKey As String, _
    ByVal ulOptions As Long, _
    ByVal samDesired As Long, _
    ByRef phkResult As LongPtr) As Long

Private Declare PtrSafe Function RegQueryValueEx Lib "advapi32.dll" Alias "RegQueryValueExA" ( _
    ByVal hKey As LongPtr, _
    ByVal lpValueName As String, _
    ByVal lpReserved As Long, _
    ByRef lpType As Long, _
    ByRef lpData As Any, _
    ByRef lpcbData As Long) As Long

Private Declare PtrSafe Function RegCloseKey Lib "advapi32.dll" ( _
    ByVal hKey As LongPtr) As Long

' --- 定数定義 ---
Private Const HKEY_LOCAL_MACHINE As LongPtr = &H80000002
Private Const KEY_READ As Long = &H20019
Private Const REG_DWORD As Long = 4
Private Const UAC_PATH As String = "SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System"
Private Const UAC_VALUE_NAME As String = "EnableLUA"

''' <summary>
''' UAC(ユーザーアカウント制御)が有効化されているかを確認する
''' </summary>
''' <returns>True: 有効, False: 無効(または取得失敗)</returns>
Public Function IsUACEnabled() As Boolean
    Dim hKey As LongPtr
    Dim dwValue As Long
    Dim dwSize As Long
    Dim dwType As Long
    Dim lRet As Long

    ' 高速化設定(本処理では描画抑制は不要だが、作法として定義)
    On Error GoTo ErrorHandler

    ' 1. レジストリキーを読み取り専用で開く
    lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, UAC_PATH, 0, KEY_READ, hKey)

    If lRet = 0 Then
        dwSize = 4 ' DWORDのサイズ
        ' 2. EnableLUA の値を取得
        lRet = RegQueryValueEx(hKey, UAC_VALUE_NAME, 0, dwType, dwValue, dwSize)

        ' 3. キーを閉じる
        RegCloseKey hKey

        If lRet = 0 And dwType = REG_DWORD Then
            ' EnableLUAが1ならUAC有効
            IsUACEnabled = (dwValue = 1)
        Else
            IsUACEnabled = False
        End If
    Else
        ' キーが開けない場合は権限不足またはパス不備
        IsUACEnabled = False
    End If

    Exit Function

ErrorHandler:
    If hKey <> 0 Then RegCloseKey hKey
    IsUACEnabled = False
End Function

''' <summary>
''' 実行テスト用プロシージャ
''' </summary>
Sub TestUACCheck()
    Application.ScreenUpdating = False ' 高速化のお作法

    If IsUACEnabled() Then
        MsgBox "UACは[有効]です。管理者権限が必要な処理で警告が出る可能性があります。", vbInformation
    Else
        MsgBox "UACは[無効]です。システム設定が変更されている可能性があります。", vbExclamation
    End If

    Application.ScreenUpdating = True
End Sub

【技術解説】

  1. Win32 APIの活用: WScript.Shellでもレジストリ参照は可能ですが、API(advapi32.dll)を使用することで、レジストリ操作のオーバーヘッドを削減し、エラーハンドリングをより厳密に行うことができます。

  2. PtrSafeとLongPtr: 現代のExcel環境(64bit)において、メモリアドレスを保持するハンドル(hKey)を安全に扱うため、PtrSafe宣言とLongPtr型を適用しています。

  3. レジストリパス: UACの状態は HKEY_LOCAL_MACHINE 配下の EnableLUA というDWORD値で管理されています。ここを直接参照するのが最も確実な判定方法です。

【注意点と運用】

  • 読み取り権限: 通常、HKEY_LOCAL_MACHINE の読み取りには管理者権限は不要ですが、環境によってはセキュリティソフトによってブロックされる場合があります。

  • レジストリの役割: EnableLUA が 0 の場合は、UACが「通知しない」に設定されていることを意味します。この状態では、管理者権限が必要なディレクトリへの書き込みが制限なく行われる、あるいは仮想化(VirtualStore)が発生しない等の挙動になります。

  • 再起動の必要性: UACの設定変更は通常Windowsの再起動後に反映されます。本コードは「現在のレジストリ値」を返すため、変更直後の未再起動状態では実挙動と乖離する可能性があります。

【まとめ】

  1. 事前チェックの徹底: UAC状態を確認してから重いファイル処理を行うことで、実行中の「書き込み拒否」エラーを未然に防ぎます。

  2. APIによる堅牢性: 標準機能よりも高速かつ、OSのビット数に依存しない堅牢なツール作成が可能です。

  3. ユーザーへの配慮: UACが有効な環境では、必要に応じて「管理者として実行」を促すメッセージを出す等、UXの向上に繋げてください。

ライセンス:本記事のテキスト/コードは特記なき限り CC BY 4.0 です。引用の際は出典URL(本ページ)を明記してください。
利用ポリシー もご参照ください。

コメント

タイトルとURLをコピーしました