我完全不知道这是怎么发生的。我正在尝试使用cmd.exe
获取可执行文件的实际全名(GetModuleFileName
)。调试显示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位但是代码也可以在尝试查找"cmd.exe"
时使用x86目标平台)。但是,如果可执行文件是64位,那么平台应该是x64,但代码将不起作用并抛出我提到的异常。
问题是x86平台内置32位文件,但内置的x64平台不适用于64位文件。所以很奇怪。至少构建的x86是无bug的(因为它可以预期),而x64构建看起来像马车。
我想知道这是否是预期的行为?您可以使用提供的代码以及我所描述的内容轻松地重现问题。
谢谢!
答案 0 :(得分:1)
您没有在字符串构建器对象中分配空间。因此错误。在调用函数之前设置容量。
var sb = new StringBuilder(260);
然后将sb.Capacity
传递给GetModuleFileName
。
您还应该检查错误。不要忽略返回值。
您不应该使用LoadLibrary
将可执行文件加载到您的进程中,只能使用DLL。如果可执行文件是您的进程,那么将LoadLibrary
与可执行文件一起使用是有意义的。可执行文件,虽然那会毫无意义。
使用DLL搜索顺序找不到可执行文件。可执行文件的搜索过程取决于它们的启动方式。使用CreateProcess
或ShellExecuteEx
。请查阅那里的文档。