FreeLibrary 在使用 GetModuleFileName(x64 平台)后抛出 AccessViolationException?
FreeLibrary throws AccessViolationException after using GetModuleFileName (x64 platform)?
我完全不知道这是怎么发生的。我正在尝试使用 GetModuleFileName
获取可执行文件 (cmd.exe
) 的实际全名。调试显示 GetModuleFileName
输出正确的路径,但就在调用 FreeLibrary
时,它抛出异常 AccessViolationException
:
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
代码如下:
[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 位但是代码在试图找到 "cmd.exe"
与 x86 目标平台)。但是,如果可执行文件是 64 位的,平台应该是 x64,但代码将无法运行并抛出我提到的异常。
问题是构建的 x86 平台适用于 32 位文件,但构建的 x64 平台不适用于 64 位文件。所以很奇怪。至少构建的 x86 没有错误(因为它按预期工作),而构建的 x64 看起来像错误。
我想知道这是否是预期行为?使用提供的代码以及我描述的内容,您肯定可以轻松地重现问题。
谢谢!
您没有在字符串生成器对象中分配 space。因此错误。在调用函数之前设置容量。
var sb = new StringBuilder(260);
然后将sb.Capacity
传递给GetModuleFileName
。
您还应该检查错误。不要忽略 return 值。
您不应该使用 LoadLibrary
将可执行文件加载到您的进程中,只能使用 DLL。如果可执行文件是您的进程的可执行文件,那么将 LoadLibrary
与可执行文件一起使用才有意义,尽管那将毫无意义。
未使用 DLL 搜索顺序定位可执行文件。可执行文件的搜索过程取决于它们的启动方式。使用 CreateProcess
或 ShellExecuteEx
。查阅那里的文档。
我完全不知道这是怎么发生的。我正在尝试使用 GetModuleFileName
获取可执行文件 (cmd.exe
) 的实际全名。调试显示 GetModuleFileName
输出正确的路径,但就在调用 FreeLibrary
时,它抛出异常 AccessViolationException
:
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
代码如下:
[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 位但是代码在试图找到 "cmd.exe"
与 x86 目标平台)。但是,如果可执行文件是 64 位的,平台应该是 x64,但代码将无法运行并抛出我提到的异常。
问题是构建的 x86 平台适用于 32 位文件,但构建的 x64 平台不适用于 64 位文件。所以很奇怪。至少构建的 x86 没有错误(因为它按预期工作),而构建的 x64 看起来像错误。
我想知道这是否是预期行为?使用提供的代码以及我描述的内容,您肯定可以轻松地重现问题。
谢谢!
您没有在字符串生成器对象中分配 space。因此错误。在调用函数之前设置容量。
var sb = new StringBuilder(260);
然后将sb.Capacity
传递给GetModuleFileName
。
您还应该检查错误。不要忽略 return 值。
您不应该使用 LoadLibrary
将可执行文件加载到您的进程中,只能使用 DLL。如果可执行文件是您的进程的可执行文件,那么将 LoadLibrary
与可执行文件一起使用才有意义,尽管那将毫无意义。
未使用 DLL 搜索顺序定位可执行文件。可执行文件的搜索过程取决于它们的启动方式。使用 CreateProcess
或 ShellExecuteEx
。查阅那里的文档。