VBAでWindowsのUAC(ユーザーアカウント制御)設定状態をAPIで判別する方法

Tech

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

VBAでWindowsのUAC(ユーザーアカウント制御)設定状態をAPIで判別する方法

【背景と目的】

管理者権限が必要なファイル操作やシステム設定をVBAで行う際、UAC(ユーザーアカウント制御)が有効だと予期せぬ中断やエラーが発生します。Win32 APIでレジストリを直接参照し、UACの状態を事前に把握することで、実行時エラーの回避と堅牢なエラーハンドリングを実現します。

【処理フロー図】

graph TD
A["開始"] --> B["Win32 APIでレジストリキーを開く"]
B --> C{"キーの展開に成功?"}
C -- No --> D["エラーを返して終了"]
C -- Yes --> E["EnableLUA値を取得"]
E --> F["レジストリハンドルを閉じる"]
F --> G["取得値に基づきUAC状態を判定"]
G --> H["終了"]

【実装:VBAコード】

Option Explicit

' --- Win32 API 宣言 (64bit環境対応) ---
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_QUERY_VALUE As Long = &H1
Private Const ERROR_SUCCESS As Long = 0&
Private Const REG_DWORD As Long = 4

''' <summary>
''' WindowsのUAC(ユーザーアカウント制御)が有効かどうかを確認します
''' </summary>
''' <returns>True: 有効, False: 無効または取得失敗</returns>
Public Function IsUACEnabled() As Boolean
    Dim hKey As LongPtr
    Dim res As Long
    Dim dwValue As Long
    Dim cbData As Long
    Dim dwType As Long
    Dim subKey As String

    ' 高速化のため画面更新を停止(本処理のみでは影響小だが標準作法として実施)
    Application.ScreenUpdating = False

    ' UAC設定が格納されているレジストリパス
    subKey = "SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System"

    ' 1. レジストリキーを読み取り専用権限でオープン
    res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, subKey, 0, KEY_QUERY_VALUE, hKey)

    If res = ERROR_SUCCESS Then
        cbData = 4 ' DWORD (4バイト)
        ' 2. "EnableLUA" キーの値を参照
        res = RegQueryValueEx(hKey, "EnableLUA", 0, dwType, dwValue, cbData)

        If res = ERROR_SUCCESS And dwType = REG_DWORD Then
            ' 3. 値が1ならUAC有効、0なら無効
            IsUACEnabled = (dwValue = 1)
        End If

        ' 4. ハンドルを閉じる
        RegCloseKey hKey
    Else
        ' キーが開けない(アクセス権限不足など)
        IsUACEnabled = False
    End If

    Application.ScreenUpdating = True
End Function

''' <summary>
''' 実装テスト用プロシージャ
''' </summary>
Sub CheckUACStatus()
    If IsUACEnabled() Then
        MsgBox "UACは「有効」です。管理者権限が必要な処理には注意してください。", vbInformation
    Else
        MsgBox "UACは「無効」です、または情報の取得に失敗しました。", vbExclamation
    End If
End Sub

【技術解説】

  1. レジストリパスの選定: WindowsのUAC設定(LUA: Limited User Account)は HKEY_LOCAL_MACHINE 内の EnableLUA というDWORD値で管理されています。

  2. Win32 APIの採用: VBA標準の Shell.RegRead は、レジストリが存在しない場合に実行時エラーをスローしますが、Win32 APIを使用することでリターンコードによる制御が可能になり、プログラムの安定性が向上します。

  3. PtrSafeとLongPtr: 現代のExcel環境(32bit/64bit混在)に対応するため、ハンドル型には LongPtr を使用し、64bit環境でもメモリ参照エラーが発生しないよう設計しています。

【注意点と運用】

  • 読み取り権限: HKEY_LOCAL_MACHINE はシステム領域ですが、KEY_QUERY_VALUE(読み取り)権限であれば、通常のユーザー権限で実行中のVBAからもアクセス可能です。

  • 再起動の反映: UACの設定をレジストリや設定画面から変更しても、Windowsを再起動するまでこのレジストリ値が実際の挙動と一致しない場合があります。

  • 例外処理: APIが ERROR_SUCCESS (0) 以外を返した場合は、レジストリが存在しないかアクセスが拒否されています。その場合は「有効」と見なして安全側に倒すロジックを検討してください。

【まとめ】

  • UACの状態はレジストリの EnableLUA キーで判別可能。

  • PtrSafeLongPtr を用いることで、64bit版Excelでも安全に動作する。

  • 管理者権限が必要な処理の前に本関数を呼ぶことで、実行時エラーを未然に防ぐ「ガード条件」として機能する。

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

コメント

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