【发布时间】: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