【问题标题】:FreeLibrary throws AccessViolationException after using GetModuleFileName (x64 platform)?FreeLibrary 使用 GetModuleFileName(x64 平台)后抛出 AccessViolationException?
【发布时间】:2015-08-22 08:44:58
【问题描述】:

我完全不知道这是怎么发生的。我正在尝试使用GetModuleFileName 获取可执行文件的实际全名(cmd.exe)。调试显示GetModuleFileName 输出了正确的路径,但在调用FreeLibrary 时,它会抛出异常AccessViolationException

试图读取或写入受保护的内存。这通常表明其他内存已损坏。

代码如下:

[DllImport("kernel32")]
public static extern IntPtr LoadLibrary(string path);
[DllImport("kernel32")]
public static extern int FreeLibrary(IntPtr hModule);
[DllImport("kernel32.dll", SetLastError = true)]
[PreserveSig]
public static extern uint GetModuleFileName([In] IntPtr hModule,[Out] StringBuilder lpFilename,[In] [MarshalAs(UnmanagedType.U4)] int nSize);

var hm = LoadLibrary("cmd.exe");
if (hm != IntPtr.Zero) {
     var s = new StringBuilder();
     GetModuleFileName(hm, s, 255);//at here s contains the correct path
     FreeLibrary(hm);//the exception throws at here.
}

经过一些试验,我发现它只发生在 x64(或 AnyCPU)平台上。如果可执行文件(查找其全名)是 32 位文件,则平台应该是 x86,然后它可以正常工作(虽然我的 Windows 是 64 位,但在尝试使用 x86 目标查找 "cmd.exe" 时代码也可以工作平台)。但是,如果可执行文件是 64 位的,则平台应该是 x64,但代码将不起作用并抛出我提到的异常。

问题是构建的 x86 平台适用于 32 位文件,但构建的 x64 平台不适用于 64 位文件。所以很奇怪。至少构建的 x86 没有错误(因为它可以正常工作),而构建的 x64 看起来像错误。

我想知道这是否是预期行为?使用提供的代码和我描述的内容,您肯定可以轻松重现问题。

谢谢!

【问题讨论】:

  • var s = Environment.GetEnvironmentVariable( "ComSpec" ); 怎么样?
  • @IInspectable 不确定您的意思,但我并不是要从 EnvironmentVariable 中获取任何路径,代码示例只是我希望它获取 cmd.exe 的完整路径的示例。可以使用任何其他 dll 或 exe 文件。
  • 由于您没有明确说明,cmd.exe 只是一个示例,我提供了一个解决方案,将完全限定的路径名​​返回给默认命令行解释器。

标签: c# winapi dll 64-bit pinvoke


【解决方案1】:

您没有在字符串生成器对象中分配空间。因此错误。在调用函数之前设置容量。

var sb = new StringBuilder(260);

然后将sb.Capacity 传递给GetModuleFileName

您还应该检查错误。不要忽略返回值。

您不应使用LoadLibrary 将可执行文件加载到您的进程中,而只能使用 DLL。仅当可执行文件是您的进程的可执行文件时,将 LoadLibrary 与可执行文件一起使用才有意义,尽管这毫无意义。

不使用 DLL 搜索顺序定位可执行文件。可执行文件的搜索过程取决于它们的启动方式。使用CreateProcessShellExecuteEx。查阅那里的文档。

【讨论】:

  • 这一切都适用于 x64 平台吗?因为正如我在将应用程序构建为 x86 时所说,它似乎工作正常。我做了一些简单的测试,看起来LoadLibrary 可以正常加载 exe 文件并按照预期的顺序。实际上这个过程并没有开始,我只是想帮助我找到执行后的exe完整路径(当前保存在磁盘上)而不是它的路径。感谢您的回答,我认为初始化 StringBuilder 的容量并不重要(奇怪的是 x86 以任何方式工作)。
  • 是的,代码在所有平台上都被破坏了。如果它似乎有效,那是偶然的。 LoadLibrary 不会为您提供 exe 的可靠结果。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多