为OpenBackupEventLog函数意外返回了ERROR_FILE_NOT_FOUND

时间:2012-01-09 13:16:20

标签: c# .net winapi pinvoke marshalling

我正在尝试使用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),但是我已经双重检查并且玩弄编组没有任何效果

为什么无法打开文件/我该如何诊断?

3 个答案:

答案 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参数
  • 将W添加到入口点名称的末尾

请注意,如果我在CharSet = CharSet.Unicdoe参数存在的时间内从入口点名称的末尾删除了W,它似乎也有效。