OpenBackupEventLog 函数意外返回 ERROR_FILE_NOT_FOUND
我正在尝试使用 OpenBackupEventLog 函数,但是我不断得到 ERROR_FILE_NOT_FOUND(错误代码 2 )即使文件确实存在。
我的 P/Invoke 声明/调用该文件的点是:
[DllImport("advapi32.dll", SetLastError = true, ExactSpelling = false, EntryPoint = "OpenBackupEventLog")]
public static extern IntPtr OpenBackupEventLog(
[MarshalAs(UnmanagedType.LPTStr)]string uncServerName,
[MarshalAs(UnmanagedType.LPTStr)]string fileName);
IntPtr ptr = NativeMethods.OpenBackupEventLog(null, filename);
if (ptr == IntPtr.Zero && File.Exists(filename))
{
// This exception is thrown and so the file does exist
throw new Win32Exception(string.Format("Failed to open event log archive '{0}'", filename));
}
请注意,这是在 x86 进程内。
我唯一能想到的是,问题在于 Unicode / ANSI 编组(之前我记得得到了 ERROR_INVALID_PARAMETER
),但是我已经仔细检查过,并且使用编组没有效果。
为什么无法打开文件/我该如何诊断?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
EntryPoint 属性是您的问题的根源。导出的函数名称为 OpenBackupEventLogA 和 OpenBackupEventLogW。该函数分别有 ANSI 和 Unicode 版本。您的声明将使用 ANSI 版本,因为您没有指定 CharSet 属性。
当 ExactSpelling = false(默认值)时,pinvoke 编组器可以自动查找 A 和 W 版本。但当您明确指定名称时则不然。
使用 ANSI 版本没有意义,请使用 CharSet.Auto 并省略 EntryPoint。 MarshalAs 也是不必要的,字符串已经被编组为 LPTStr。因此:
The EntryPoint property is the source of your problem here. The exported function names are OpenBackupEventLogA and OpenBackupEventLogW. Respectively the ANSI and the Unicode versions of this function. Your declaration would use the ANSI version since you didn't specify the CharSet property.
The pinvoke marshaller can find the A and W versions automatically when ExactSpelling = false (the default). But not when you specify the name explicitly.
There's no point in using the ANSI version, use CharSet.Auto and omit EntryPoint. MarshalAs is unnecessary as well, strings already are marshaled as LPTStr. Thus:
由于这是 64 位操作系统,并且您正在使用 32 位应用程序访问文件,因此导致此异常的最可能原因是操作系统非常“有帮助”自动重定向请求到
System
目录(C:\Windows\system
,例如)到SysWOW64
目录C:\Windows\SysWOW64
。幸运的是,有一个内置的解决方法: sysnative< /a> 目录。
生成文件名的路径时,请使用类似于以下内容的内容:
string filePath = @"%WINDIR%\sysnative\winevt\logs\mylog.evtx";
但是,仅当您将应用程序保留为 32 位应用程序时才执行此操作。它将无法正确解析为 64 位应用程序。
Since this is a 64-bit OS and you are accessing the files using a 32-bit app, the most likely cause of this exception is that the OS very "helpfully" automatically redirects requests for the
System
directory (C:\Windows\system
, e.g.) to theSysWOW64
directoryC:\Windows\SysWOW64
.Fortunately, there is a builtin workaround: the sysnative directory.
When you generate the path to the file name, use something similar to the following:
string filePath = @"%WINDIR%\sysnative\winevt\logs\mylog.evtx";
However, only do this if you retain the app as a 32-bit app. It will not resolve correctly as a 64-bit app.
这是一个
encodingUnicode 与 ANSI 问题 - 我似乎设法让它以某种方式再次开始工作,但后来意识到它返回的是 ANSI 字符串而不是 UNICODE 字符串 - 显然我不小心开始使用这些函数的 ANSI 版本是没有好处的。它现在使用以下 PInvoke 声明
关键点是我:
MarshalAs
属性CharSet = CharSet.Unicdoe
参数添加到我的DllImport
> 声明请注意,如果我从入口点名称的末尾删除 W,只要 s
CharSet = CharSet.Unicdoe
,它似乎也可以工作。参数在那里。This was a
encodingUnicode vs ANSI issue - I seemed to manage to get this to start working again somehow, but later realised that it was returning ANSI strings instead of UNICODE strings - obviously I had accidentally started using the ANSI versions of these functions which is no good.Its now working with the following PInvoke declaration
The key points being that I:
MarshalAs
attributesCharSet = CharSet.Unicdoe
paramter to myDllImport
declarationNote that it also seems to work if I remove the W from the end of the entry point name as long s the
CharSet = CharSet.Unicdoe
paramter is there.