我正在尝试使用OpenBackupEventLog函数在Windows 7 x64计算机上打开.evtx文件但是我继续获取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
),但是我已经双重检查并且玩弄编组没有任何效果
为什么无法打开文件/我该如何诊断?
答案 0 :(得分:1)
[DllImport("advapi32.dll", ..., EntryPoint = "OpenBackupEventLog")]
EntryPoint属性是您的问题的根源。导出的函数名称是OpenBackupEventLogA和OpenBackupEventLogW。分别是此函数的ANSI和Unicode版本。您的声明将使用ANSI版本,因为您没有指定CharSet属性。
当ExactSpelling = false(默认值)时,pinvoke marshaller可以自动找到A和W版本。但不是在明确指定名称时。
使用ANSI版本没有意义,请使用CharSet.Auto并省略EntryPoint。 MarshalAs也是不必要的,字符串已经被编组为LPTStr。因此:
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr OpenBackupEventLog(string uncServerName, string fileName);
答案 1 :(得分:0)
由于这是一个64位操作系统,并且您使用32位应用程序访问这些文件,因此该异常的最可能原因是操作系统对System
非常“有用”automatically redirects requests }目录(C:\Windows\system
,例如)到SysWOW64
目录C:\Windows\SysWOW64
。
幸运的是,有一个内置的解决方法:sysnative目录。
生成文件名的路径时,请使用类似于以下内容的内容:
string filePath = @“%WINDIR%\ sysnative \ winevt \ logs \ mylog.evtx”;
但是,只有将应用程序保留为32位应用程序才能执行此操作。它无法作为64位应用程序正确解析。
答案 2 :(得分:0)
这是编码 Unicode vs ANSI问题 - 我似乎设法让它以某种方式再次开始工作,但后来意识到它返回ANSI字符串而不是UNICODE字符串 - 显然我不小心开始使用这些函数的ANSI版本并不好。
现在使用以下PInvoke声明
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "OpenBackupEventLogW")]
public static extern EventLogHandle OpenBackupEventLog(
string uncServerName,
string fileName);
关键点是我:
MarshalAs
属性CharSet = CharSet.Unicdoe
声明DllImport
参数
请注意,如果我在CharSet = CharSet.Unicdoe
参数存在的时间内从入口点名称的末尾删除了W,它似乎也有效。