<p><meta/>PLAN:RegistryAccess_UAC_Check|CHECK:PtrSafe_Implementation
本記事は<strong>Geminiの出力をプロンプト工学で整理した業務ドラフト(未検証)</strong>です。</p>
<h1 class="wp-block-heading">VBAでWin32 APIを叩き、レジストリからUAC(ユーザーアカウント制御)の有効状態を判定する</h1>
<h3 class="wp-block-heading">【背景と目的】</h3>
<p>管理者権限が必要なファイル操作やシステム設定を行う際、UAC設定による予期せぬ中断や実行エラーを未然に防ぐため、Win32 APIでレジストリを直接参照し状態を判定します。</p>
<h3 class="wp-block-heading">【処理フロー図】</h3>
<div class="wp-block-merpress-mermaidjs diagram-source-mermaid"><pre class="mermaid">
graph TD
A["開始"] --> B["Win32 APIの宣言"]
B --> C["レジストリキー HKLM をオープン"]
C --> D["EnableLUA 値をクエリ"]
D --> E{"値が 1 か?"}
E -->|Yes| F["UAC 有効と判定"]
E -->|No| G["UAC 無効と判定"]
F --> H["レジストリハンドルをクローズ"]
G --> H
H --> I["終了"]
</pre></div>
<h3 class="wp-block-heading">【実装:VBAコード】</h3>
<pre data-enlighter-language="generic">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 ERROR_SUCCESS As Long = 0&
Private Const REG_DWORD As Long = 4
''' <summary>
''' UAC (EnableLUA) の状態を確認するメインルーチン
''' </summary>
Public Sub CheckUACStatus()
Dim uacEnabled As Boolean
' 高速化設定(本処理では描画停止は影響少ないが、実務テンプレートとして含める)
Application.ScreenUpdating = False
On Error GoTo ErrorHandler
uacEnabled = IsUACEnabled()
If uacEnabled Then
MsgBox "UAC(ユーザーアカウント制御)は [有効] です。" & vbCrLf & _
"管理者権限が必要な処理では昇格が必要です。", vbInformation
Else
MsgBox "UAC(ユーザーアカウント制御)は [無効] です。", vbExclamation
End If
CleanUp:
Application.ScreenUpdating = True
Exit Sub
ErrorHandler:
MsgBox "エラーが発生しました: " & Err.Description, vbCritical
Resume CleanUp
End Sub
''' <summary>
''' レジストリを参照し、EnableLUAの値を取得する
''' </summary>
Private Function IsUACEnabled() As Boolean
Dim hKey As LongPtr
Dim subKey As String
Dim valueName As String
Dim dwValue As Long
Dim dwSize As Long
Dim result As Long
' UAC設定のレジストリパス
subKey = "SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System"
valueName = "EnableLUA"
dwSize = 4 ' DWORDのサイズ
' キーをオープン
result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, subKey, 0, KEY_READ, hKey)
If result = ERROR_SUCCESS Then
' 値をクエリ
result = RegQueryValueEx(hKey, valueName, 0, REG_DWORD, dwValue, dwSize)
' ハンドルを確実に閉じる
RegCloseKey hKey
If result = ERROR_SUCCESS Then
' 1 なら UAC 有効
IsUACEnabled = (dwValue = 1)
Exit Function
End If
End If
' 取得失敗時は安全のため True (有効) とみなすかエラー処理
IsUACEnabled = True
End Function
</pre>
<h3 class="wp-block-heading">【技術解説】</h3>
<ol class="wp-block-list">
<li><p><strong>Win32 APIの採用理由</strong>: <code>WScript.Shell</code> の <code>RegRead</code> メソッドでも取得可能ですが、Win32 APIを使用することで外部オブジェクトの依存を減らし、読み取り専用(<code>KEY_READ</code>)のアクセス権限を明示的に指定することで、セキュリティソフトによる過度な検知を回避しやすくなります。</p></li>
<li><p><strong>PtrSafe と LongPtr</strong>: 64bit版Excelでの動作を保証するため、ポインタを扱う変数(<code>hKey</code>)には <code>LongPtr</code> を適用しています。</p></li>
<li><p><strong>レジストリパス</strong>: <code>HKEY_LOCAL_MACHINE</code> 直下の <code>EnableLUA</code> 値は、WindowsのUAC機能そのもののオン/オフを司るフラグです。</p></li>
</ol>
<h3 class="wp-block-heading">【注意点と運用】</h3>
<ul class="wp-block-list">
<li><p><strong>読み取り権限</strong>: 通常、このレジストリパスは一般ユーザー権限でも読み取り可能ですが、極端に制限された環境では <code>RegOpenKeyEx</code> が失敗する可能性があります。その場合は戻り値 <code>result</code> を確認してください。</p></li>
<li><p><strong>再起動の反映</strong>: UAC設定をレジストリで変更しても、OSを再起動するまでは <code>EnableLUA</code> の実際の挙動とレジストリ値が一致しない場合があります。本コードはあくまで「現在の設定値」を取得するものです。</p></li>
<li><p><strong>例外処理</strong>: <code>RegCloseKey</code> を忘れるとリソースリークの原因となるため、必ず <code>RegOpenKeyEx</code> が成功した後はクローズ処理を通るように設計しています。</p></li>
</ul>
<h3 class="wp-block-heading">【まとめ】</h3>
<ul class="wp-block-list">
<li><p><strong>Win32 APIの活用</strong>: <code>PtrSafe</code> 宣言により、32bit/64bitを問わない堅牢なツール開発が可能。</p></li>
<li><p><strong>事前チェックの重要性</strong>: 重い処理の前にUAC状態を確認することで、権限エラーによる不完全なデータ更新を防止。</p></li>
<li><p><strong>リソース管理</strong>: ハンドルのオープンとクローズを対にすることで、安定したVBA実行環境を維持。</p></li>
</ul>
PLAN:RegistryAccess_UAC_Check|CHECK:PtrSafe_Implementation
本記事はGeminiの出力をプロンプト工学で整理した業務ドラフト(未検証)です。
VBAでWin32 APIを叩き、レジストリからUAC(ユーザーアカウント制御)の有効状態を判定する
【背景と目的】
管理者権限が必要なファイル操作やシステム設定を行う際、UAC設定による予期せぬ中断や実行エラーを未然に防ぐため、Win32 APIでレジストリを直接参照し状態を判定します。
【処理フロー図】
graph TD
A["開始"] --> B["Win32 APIの宣言"]
B --> C["レジストリキー HKLM をオープン"]
C --> D["EnableLUA 値をクエリ"]
D --> E{"値が 1 か?"}
E -->|Yes| F["UAC 有効と判定"]
E -->|No| G["UAC 無効と判定"]
F --> H["レジストリハンドルをクローズ"]
G --> H
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 ERROR_SUCCESS As Long = 0&
Private Const REG_DWORD As Long = 4
''' <summary>
''' UAC (EnableLUA) の状態を確認するメインルーチン
''' </summary>
Public Sub CheckUACStatus()
Dim uacEnabled As Boolean
' 高速化設定(本処理では描画停止は影響少ないが、実務テンプレートとして含める)
Application.ScreenUpdating = False
On Error GoTo ErrorHandler
uacEnabled = IsUACEnabled()
If uacEnabled Then
MsgBox "UAC(ユーザーアカウント制御)は [有効] です。" & vbCrLf & _
"管理者権限が必要な処理では昇格が必要です。", vbInformation
Else
MsgBox "UAC(ユーザーアカウント制御)は [無効] です。", vbExclamation
End If
CleanUp:
Application.ScreenUpdating = True
Exit Sub
ErrorHandler:
MsgBox "エラーが発生しました: " & Err.Description, vbCritical
Resume CleanUp
End Sub
''' <summary>
''' レジストリを参照し、EnableLUAの値を取得する
''' </summary>
Private Function IsUACEnabled() As Boolean
Dim hKey As LongPtr
Dim subKey As String
Dim valueName As String
Dim dwValue As Long
Dim dwSize As Long
Dim result As Long
' UAC設定のレジストリパス
subKey = "SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System"
valueName = "EnableLUA"
dwSize = 4 ' DWORDのサイズ
' キーをオープン
result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, subKey, 0, KEY_READ, hKey)
If result = ERROR_SUCCESS Then
' 値をクエリ
result = RegQueryValueEx(hKey, valueName, 0, REG_DWORD, dwValue, dwSize)
' ハンドルを確実に閉じる
RegCloseKey hKey
If result = ERROR_SUCCESS Then
' 1 なら UAC 有効
IsUACEnabled = (dwValue = 1)
Exit Function
End If
End If
' 取得失敗時は安全のため True (有効) とみなすかエラー処理
IsUACEnabled = True
End Function
【技術解説】
Win32 APIの採用理由: WScript.Shell の RegRead メソッドでも取得可能ですが、Win32 APIを使用することで外部オブジェクトの依存を減らし、読み取り専用(KEY_READ)のアクセス権限を明示的に指定することで、セキュリティソフトによる過度な検知を回避しやすくなります。
PtrSafe と LongPtr: 64bit版Excelでの動作を保証するため、ポインタを扱う変数(hKey)には LongPtr を適用しています。
レジストリパス: HKEY_LOCAL_MACHINE 直下の EnableLUA 値は、WindowsのUAC機能そのもののオン/オフを司るフラグです。
【注意点と運用】
読み取り権限: 通常、このレジストリパスは一般ユーザー権限でも読み取り可能ですが、極端に制限された環境では RegOpenKeyEx が失敗する可能性があります。その場合は戻り値 result を確認してください。
再起動の反映: UAC設定をレジストリで変更しても、OSを再起動するまでは EnableLUA の実際の挙動とレジストリ値が一致しない場合があります。本コードはあくまで「現在の設定値」を取得するものです。
例外処理: RegCloseKey を忘れるとリソースリークの原因となるため、必ず RegOpenKeyEx が成功した後はクローズ処理を通るように設計しています。
【まとめ】
Win32 APIの活用: PtrSafe 宣言により、32bit/64bitを問わない堅牢なツール開発が可能。
事前チェックの重要性: 重い処理の前にUAC状態を確認することで、権限エラーによる不完全なデータ更新を防止。
リソース管理: ハンドルのオープンとクローズを対にすることで、安定したVBA実行環境を維持。
コメント