<p><!-- META {"target": "VBA", "topic": "Win32API_UAC_Registry", "version": "1.0"} -->
本記事は<strong>Geminiの出力をプロンプト工学で整理した業務ドラフト(未検証)</strong>です。</p>
<h1 class="wp-block-heading">【VBA】Win32 APIでレジストリを参照しWindowsのUAC(ユーザーアカウント制御)状態を自動判定する</h1>
<h1 class="wp-block-heading">【背景と目的】</h1>
<p>管理者権限が必要なVBA処理で、UACが無効化されておらず権限エラーが発生する問題を防止するため、Win32 APIで安全に状態判定します。(68文字)</p>
<h1 class="wp-block-heading">【処理フロー図】</h1>
<div class="wp-block-merpress-mermaidjs diagram-source-mermaid"><pre class="mermaid">
graph TD
A["処理開始"] --> B["レジストリキーのオープン"]
B --> C{"オープン成功?"}
C -- Yes --> D["EnableLUA値の取得"]
C -- No --> E["判定不可・エラー処理"]
D --> F["レジストリキーのクローズ"]
F --> G{"EnableLUA = 1?"}
G -- Yes --> H["UAC有効と判定"]
G -- No --> I["UAC無効と判定"]
E --> J["終了"]
H --> J
I --> J
</pre></div>
<p>※本フローでは、Windowsレジストリ(HKLM)内のキーを取得し、UACの有効状態(EnableLUA)を判定する手順を示しています。</p>
<h1 class="wp-block-heading">【実装:VBAコード】</h1>
<pre data-enlighter-language="generic">Option Explicit
' ==============================================================================
' Win32 API 宣言(64bit / 32bit 両対応)
' ==============================================================================
#If VBA7 Then
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 LongPtr, _
ByRef lpType As Long, _
ByRef lpData As Long, _
ByRef lpcbData As Long) As Long
Private Declare PtrSafe Function RegCloseKey Lib "advapi32.dll" ( _
ByVal hKey As LongPtr) As Long
#Else
Private Declare Function RegOpenKeyEx Lib "advapi32.dll" Alias "RegOpenKeyExA" ( _
ByVal hKey As Long, _
ByVal lpSubKey As String, _
ByVal ulOptions As Long, _
ByVal samDesired As Long, _
ByRef phkResult As Long) As Long
Private Declare Function RegQueryValueEx Lib "advapi32.dll" Alias "RegQueryValueExA" ( _
ByVal hKey As Long, _
ByVal lpValueName As String, _
ByVal lpReserved As Long, _
ByRef lpType As Long, _
ByRef lpData As Long, _
ByRef lpcbData As Long) As Long
Private Declare Function RegCloseKey Lib "advapi32.dll" ( _
ByVal hKey As Long) As Long
#End If
' レジストリ定数
Private Const HKEY_LOCAL_MACHINE As Long = &H80000002
Private Const KEY_READ As Long = &H20019
Private Const ERROR_SUCCESS As Long = 0&
Private Const REG_DWORD As Long = 4
' UAC設定のレジストリパス
Private Const UAC_REG_PATH As String = "SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System"
Private Const UAC_VALUE_NAME As String = "EnableLUA"
''' <summary>
''' UAC(ユーザーアカウント制御)が有効かどうかを判定するメインプロシージャ
''' </summary>
Public Sub CheckUACStatus()
' 高速化設定
On Error GoTo ErrorHandler
Application.ScreenUpdating = False
Dim isUACEnabled As Boolean
isUACEnabled = IsUACActive()
' 画面更新の再開
Application.ScreenUpdating = True
' 判定結果の表示
If isUACEnabled Then
MsgBox "UAC(ユーザーアカウント制御)は【有効】です。", vbInformation, "UAC状態確認"
Else
MsgBox "UAC(ユーザーアカウント制御)は【無効】です。", vbExclamation, "UAC状態確認"
End If
Exit Sub
ErrorHandler:
Application.ScreenUpdating = True
MsgBox "エラーが発生しました: " & Err.Description, vbCritical, "エラー"
End Sub
''' <summary>
''' レジストリを参照してUACの有効状態(EnableLUA)を取得する関数
''' </summary>
''' <returns>True: 有効, False: 無効または取得失敗</returns>
Private Function IsUACActive() As Boolean
#If VBA7 Then
Dim hKeyHandle As LongPtr
#Else
Dim hKeyHandle As Long
#End If
Dim lResult As Long
Dim dwValue As Long
Dim cbData As Long
Dim dwType As Long
IsUACActive = False
cbData = 4 ' DWORDのバイトサイズ
' レジストリキーを読み込みモードでオープン
lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, UAC_REG_PATH, 0, KEY_READ, hKeyHandle)
If lResult = ERROR_SUCCESS Then
' EnableLUAの値を取得
lResult = RegQueryValueEx(hKeyHandle, UAC_VALUE_NAME, 0, dwType, dwValue, cbData)
If lResult = ERROR_SUCCESS And dwType = REG_DWORD Then
' 1 であれば UAC 有効
If dwValue = 1 Then
IsUACActive = True
End If
End If
' 開いたレジストリキーを確実にクローズ
Call RegCloseKey(hKeyHandle)
End If
End Function
</pre>
<h1 class="wp-block-heading">【技術解説】</h1>
<ul class="wp-block-list">
<li><p><strong>Win32 APIの活用</strong>: <code>WScript.Shell</code> などの外部スクリプトオブジェクトに依存せず、<code>advapi32.dll</code> の標準API(<code>RegOpenKeyExA</code> / <code>RegQueryValueExA</code>)を直接呼び出すことで高速かつ堅牢なレジストリ読み取りを実現しています。</p></li>
<li><p><strong>64bit/32bit互換性</strong>: <code>#If VBA7</code> 条件分岐と <code>PtrSafe</code> 属性を使用し、ハンドル保持用変数に <code>LongPtr</code> を指定することで、Office 32bit/64bit 環境の双方で安全に動作します。</p></li>
<li><p><strong>UAC判定ロジック</strong>: WindowsにおけるUACの有効状態は <code>HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System</code> の <code>EnableLUA</code> (DWORD) に保持されます。値が <code>1</code> の場合はUAC有効、<code>0</code> の場合は無効と判断できます。</p></li>
</ul>
<h1 class="wp-block-heading">【注意点と運用】</h1>
<ul class="wp-block-list">
<li><p><strong>レジストリハンドルの開放忘れ</strong>: <code>RegOpenKeyEx</code> で取得したハンドルは、エラー処理を含めて必ず <code>RegCloseKey</code> でクローズしてください。リソースリークの原因となります。</p></li>
<li><p><strong>読み取り権限</strong>: <code>KEY_READ</code> 権限でオープンしているため標準ユーザー権限でも取得可能ですが、極端にアクセス制限された環境ではキーオープンに失敗する可能性があります。その場合はデフォルト動作(False扱い等)にフォールバックさせる例外処理が必要です。</p></li>
<li><p><strong>再起動のタイムラグ</strong>: ユーザーが手動でUAC設定を変更しても、Windowsを再起動するまではレジストリ値が反映されない場合があります。</p></li>
</ul>
<h1 class="wp-block-heading">【まとめ】</h1>
<ol class="wp-block-list">
<li><p><strong>PtrSafeとLongPtrを徹底し、64bit Office環境での動作互換性を確保する。</strong></p></li>
<li><p><strong>API呼び出し後は必ず <code>RegCloseKey</code> を実行し、リソース解放漏れを防ぐ。</strong></p></li>
<li><p><strong>外部オブジェクト非依存のAPI実装により、権限エラー時の安全なフォールバック処理を構築する。</strong></p></li>
</ol>
本記事はGeminiの出力をプロンプト工学で整理した業務ドラフト(未検証)です。
【VBA】Win32 APIでレジストリを参照しWindowsのUAC(ユーザーアカウント制御)状態を自動判定する
【背景と目的】
管理者権限が必要なVBA処理で、UACが無効化されておらず権限エラーが発生する問題を防止するため、Win32 APIで安全に状態判定します。(68文字)
【処理フロー図】
graph TD
A["処理開始"] --> B["レジストリキーのオープン"]
B --> C{"オープン成功?"}
C -- Yes --> D["EnableLUA値の取得"]
C -- No --> E["判定不可・エラー処理"]
D --> F["レジストリキーのクローズ"]
F --> G{"EnableLUA = 1?"}
G -- Yes --> H["UAC有効と判定"]
G -- No --> I["UAC無効と判定"]
E --> J["終了"]
H --> J
I --> J
※本フローでは、Windowsレジストリ(HKLM)内のキーを取得し、UACの有効状態(EnableLUA)を判定する手順を示しています。
【実装:VBAコード】
Option Explicit
' ==============================================================================
' Win32 API 宣言(64bit / 32bit 両対応)
' ==============================================================================
#If VBA7 Then
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 LongPtr, _
ByRef lpType As Long, _
ByRef lpData As Long, _
ByRef lpcbData As Long) As Long
Private Declare PtrSafe Function RegCloseKey Lib "advapi32.dll" ( _
ByVal hKey As LongPtr) As Long
#Else
Private Declare Function RegOpenKeyEx Lib "advapi32.dll" Alias "RegOpenKeyExA" ( _
ByVal hKey As Long, _
ByVal lpSubKey As String, _
ByVal ulOptions As Long, _
ByVal samDesired As Long, _
ByRef phkResult As Long) As Long
Private Declare Function RegQueryValueEx Lib "advapi32.dll" Alias "RegQueryValueExA" ( _
ByVal hKey As Long, _
ByVal lpValueName As String, _
ByVal lpReserved As Long, _
ByRef lpType As Long, _
ByRef lpData As Long, _
ByRef lpcbData As Long) As Long
Private Declare Function RegCloseKey Lib "advapi32.dll" ( _
ByVal hKey As Long) As Long
#End If
' レジストリ定数
Private Const HKEY_LOCAL_MACHINE As Long = &H80000002
Private Const KEY_READ As Long = &H20019
Private Const ERROR_SUCCESS As Long = 0&
Private Const REG_DWORD As Long = 4
' UAC設定のレジストリパス
Private Const UAC_REG_PATH As String = "SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System"
Private Const UAC_VALUE_NAME As String = "EnableLUA"
''' <summary>
''' UAC(ユーザーアカウント制御)が有効かどうかを判定するメインプロシージャ
''' </summary>
Public Sub CheckUACStatus()
' 高速化設定
On Error GoTo ErrorHandler
Application.ScreenUpdating = False
Dim isUACEnabled As Boolean
isUACEnabled = IsUACActive()
' 画面更新の再開
Application.ScreenUpdating = True
' 判定結果の表示
If isUACEnabled Then
MsgBox "UAC(ユーザーアカウント制御)は【有効】です。", vbInformation, "UAC状態確認"
Else
MsgBox "UAC(ユーザーアカウント制御)は【無効】です。", vbExclamation, "UAC状態確認"
End If
Exit Sub
ErrorHandler:
Application.ScreenUpdating = True
MsgBox "エラーが発生しました: " & Err.Description, vbCritical, "エラー"
End Sub
''' <summary>
''' レジストリを参照してUACの有効状態(EnableLUA)を取得する関数
''' </summary>
''' <returns>True: 有効, False: 無効または取得失敗</returns>
Private Function IsUACActive() As Boolean
#If VBA7 Then
Dim hKeyHandle As LongPtr
#Else
Dim hKeyHandle As Long
#End If
Dim lResult As Long
Dim dwValue As Long
Dim cbData As Long
Dim dwType As Long
IsUACActive = False
cbData = 4 ' DWORDのバイトサイズ
' レジストリキーを読み込みモードでオープン
lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, UAC_REG_PATH, 0, KEY_READ, hKeyHandle)
If lResult = ERROR_SUCCESS Then
' EnableLUAの値を取得
lResult = RegQueryValueEx(hKeyHandle, UAC_VALUE_NAME, 0, dwType, dwValue, cbData)
If lResult = ERROR_SUCCESS And dwType = REG_DWORD Then
' 1 であれば UAC 有効
If dwValue = 1 Then
IsUACActive = True
End If
End If
' 開いたレジストリキーを確実にクローズ
Call RegCloseKey(hKeyHandle)
End If
End Function
【技術解説】
Win32 APIの活用: WScript.Shell などの外部スクリプトオブジェクトに依存せず、advapi32.dll の標準API(RegOpenKeyExA / RegQueryValueExA)を直接呼び出すことで高速かつ堅牢なレジストリ読み取りを実現しています。
64bit/32bit互換性: #If VBA7 条件分岐と PtrSafe 属性を使用し、ハンドル保持用変数に LongPtr を指定することで、Office 32bit/64bit 環境の双方で安全に動作します。
UAC判定ロジック: WindowsにおけるUACの有効状態は HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System の EnableLUA (DWORD) に保持されます。値が 1 の場合はUAC有効、0 の場合は無効と判断できます。
【注意点と運用】
レジストリハンドルの開放忘れ: RegOpenKeyEx で取得したハンドルは、エラー処理を含めて必ず RegCloseKey でクローズしてください。リソースリークの原因となります。
読み取り権限: KEY_READ 権限でオープンしているため標準ユーザー権限でも取得可能ですが、極端にアクセス制限された環境ではキーオープンに失敗する可能性があります。その場合はデフォルト動作(False扱い等)にフォールバックさせる例外処理が必要です。
再起動のタイムラグ: ユーザーが手動でUAC設定を変更しても、Windowsを再起動するまではレジストリ値が反映されない場合があります。
【まとめ】
PtrSafeとLongPtrを徹底し、64bit Office環境での動作互換性を確保する。
API呼び出し後は必ず RegCloseKey を実行し、リソース解放漏れを防ぐ。
外部オブジェクト非依存のAPI実装により、権限エラー時の安全なフォールバック処理を構築する。
コメント