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只是一个示例,因此我提供了一个解决方案,将完全限定的路径名返回到默认的命令行解释器。