C# FreeLibrary在使用GetModuleFileName(x64平台)后引发AccessViolationException?

C# FreeLibrary在使用GetModuleFileName(x64平台)后引发AccessViolationException?,c#,winapi,dll,64-bit,pinvoke,C#,Winapi,Dll,64 Bit,Pinvoke,我完全不知道这怎么会发生。我试图使用GetModuleFileName获取可执行文件(cmd.exe)的实际全名。调试显示,GetModuleFileName输出正确的路径,但就在调用FreeLibrary时,它抛出异常AccessViolationException: 试图读取或写入受保护的内存。这通常表示其他内存已损坏 代码如下: [DllImport("kernel32")] public static extern IntPtr LoadLibrary(string path); [Dl

我完全不知道这怎么会发生。我试图使用
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没有bug(因为它可以正常工作),而构建的x64看起来像bug

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


谢谢大家!

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

var sb = new StringBuilder(260);
然后将
sb.Capacity
传递给
GetModuleFileName

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

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


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

所有这些是否仅适用于x64平台?因为正如我在以x86构建应用程序时所说的,它似乎工作正常。我做了一些简单的测试,看起来
LoadLibrary
可以按预期顺序正常加载exe文件。事实上,该进程并没有启动,我只是想让它帮助我找到exe完整路径(当前保存在磁盘上)而不是执行后的路径。谢谢你的回答,我不认为初始化StringBuilder的容量是如此重要(奇怪的是x86能以任何方式工作)。是的,所有平台上的代码都是不完整的。如果它似乎起作用,那是偶然的。LoadLibrary不会为exe提供可靠的结果?@IInspectable不确定您的意思,但我不想从环境变量获取任何路径,代码示例只是一个示例,我希望它获取
cmd.exe
的完整路径。可以使用任何其他DLL或exe文件。由于您没有明确声明cmd.exe只是一个示例,因此我提供了一个解决方案,将完全限定的路径名返回到默认的命令行解释器。