使用Delphi 11.3调用EvtQuery()遇ERROR_ACCESS_DENIED问题求助
问题描述
之前在Delphi 10.3 + Windows 7环境下可正常调用EvtQuery()读取Windows事件日志,但切换到Delphi 11.3 + Windows 10后,EvtQuery()返回0,GetLastError()返回5(ERROR_ACCESS_DENIED,拒绝访问)。
本地机器操作,无需跨机器凭据验证,理应返回有效句柄,请问哪里被忽略了?
测试代码
program EvtQueryTest; {$APPTYPE CONSOLE} uses Windows, SysUtils; type EVT_HANDLE = type THandle; function EvtQuery(Session: EVT_HANDLE; Path, Query: PWideChar; Flags: DWORD): EVT_HANDLE;stdcall; external 'wevtapi.dll'; procedure TestEvtQuery; // 参考事件查询官方文档 const EvtQueryChannelPath = $1; EvtQueryReverseDirection = $200; var Path, Query : string; HostHandle, EventLogHandle : EVT_Handle; begin Path := 'Security'; Query := '<QueryList><Query Path="Security"><Select>Event/System[EventID=4625]</Select></Query></QueryList>'; HostHandle := 0; EventLogHandle := EvtQuery(HostHandle, PWideChar(Path), PWideChar(Query), EvtQueryChannelPath + EvtQueryReverseDirection); if (EventLogHandle <> 0) then writeln('success !') else Writeln('ERROR Code: ' + IntToStr(GetLastError)); readln; CloseHandle(EventLogHandle); // 修正原代码的Close为CloseHandle end; begin TestEvtQuery; end.
完整代码片段
FEventLogHandle := EvtQuery.WinEvtDefs.EvtQuery(FHostHandle, PWideChar(FPath), PWideChar(FQuery), EvtQueryChannelPath + EvtQueryReverseDirection); result := (FEventLogHandle <> 0); if result then begin FEvent := TEvtEvent.Create(hSysContext, hUsrContext, FEventReaderMode); FEvent.UseXmlMode := XmlMode; end else begin Status := GetLastError; if (Status = ERROR_ACCESS_DENIED) then HandleEvtError('[E11A] - Access Denied'#13#10 + FPath + #13#10 + FQuery + #13#10, Status, false, true) else if (Status = ERROR_EVT_CHANNEL_NOT_FOUND) then HandleEvtError('[E11B] ' + pwsPath + ' 不是有效的事件通道', Status) else if (status = ERROR_EVT_INVALID_QUERY) then begin /// 可调用EvtGetExtendedStatus函数获取查询错误的详细信息 HandleEvtError('[E12] ' + pwsQuery + ' 不是有效的事件查询语句', Status); end else HandleEvtError('[E13] EvtQuery调用失败', status); end;
解决方法
出现ERROR_ACCESS_DENIED的核心原因是Windows 10及后续系统对安全日志(Security)的访问权限做了更严格的限制,即使是管理员账号,默认也没有直接读取安全日志的权限。以下是具体解决步骤:
以管理员身份运行程序
右键点击编译后的exe文件,选择“以管理员身份运行”,测试是否能正常读取。如果有效,说明是权限不足导致的问题。配置程序UAC清单
在Delphi项目中添加UAC清单,让程序启动时自动请求管理员权限:- 在项目文件(.dpr)中添加:
{$R 'UAC.RES' 'UAC.RC'} - 创建UAC.RC文件,内容为:
1 24 "UAC.Manifest" - 创建UAC.Manifest文件,内容如下:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> <security> <requestedPrivileges> <requestedExecutionLevel level="requireAdministrator" uiAccess="false"/> </requestedPrivileges> </security> </trustInfo> </assembly>
- 在项目文件(.dpr)中添加:
检查本地安全策略权限
如果管理员身份运行仍报错,需确认账号权限:- 打开“本地安全策略”(运行secpol.msc)
- 展开“本地策略”->“用户权限分配”
- 找到“管理审核和安全日志”权限,确保当前用户或Administrators组已添加
- 重启电脑生效
修正代码中的资源泄漏问题
原测试代码中用Close(EventLogHandle)是错误的,Windows内核句柄需用CloseHandle()关闭,避免资源泄漏。
内容的提问来源于stack exchange,提问作者ss2006
相关产品推荐
相关产品推荐

