我正在使用 JNA 并编写一些代码来枚举进程中可用的所有模块。我通过 CreateToolhelp32Snapshot 成功获取了快照句柄,但是在我的第一次 Module32First 调用中,我收到了“无效参数”的错误代码 87。
以下是我正在使用的相关代码:
有问题的代码:
private void getModule() {
Pointer hSnapshot = this.kernel32.CreateToolhelp32Snapshot(WinAPI.TH32CS_SNAPMODULE, this.processId);
if(hSnapshot != null) {
WinAPI.MODULEENTRY32 moduleEntry32 = new WinAPI.MODULEENTRY32();
moduleEntry32.write(); // Write the struct in memory (for dwSize to be registered)
Pointer moduleEntry32Pointer = moduleEntry32.getPointer();
if(this.kernel32.Module32First(hSnapshot, moduleEntry32Pointer)) {
// irrelevant stuff here
}
}
System.out.println(this.kernel32.GetLastError()); // Prints out "87"
this.kernel32.CloseHandle(hSnapshot);
}
Kernel32 映射器类:
Pointer CreateToolhelp32Snapshot(int dwFlags, int th32ProcessID);
boolean Module32First(Pointer hSnapshot, Pointer lpme);
boolean Module32Next(Pointer hSnapshot, Pointer lpme);
ModuleEntry32 结构:
public static class MODULEENTRY32 extends Structure {
public int dwSize = this.size();
public int th32ModuleID;
public int th32ProcessID;
public int GlblcntUsage;
public int ProccntUsage;
public Pointer modBaseAddr;
public int modBaseSize;
public Pointer hModule;
public String szModule;
public String szExePath;
public MODULEENTRY32() {
super();
}
public MODULEENTRY32(Pointer p) {
super(p);
}
protected List<String> getFieldOrder() {
return Arrays.asList(new String[] {"dwSize", "th32ModuleID", "th32ProcessID", "GlblcntUsage", "ProccntUsage", "modBaseAddr", "modBaseSize", "hModule", "szModule", "szExePath"});
}
}
最后,这是“WinAPI.TH32CS_SNAPMODULE”:
public static final int TH32CS_SNAPMODULE = 0x00000008;
注意:我列举的进程已经用 OpenProcess 打开并且是有效的。 processId 也是有效的,并且正确获取。
任何帮助将不胜感激。
答案 0 :(得分:1)
您将指针映射为第二个参数,虽然在技术上是正确的,但需要您在编写它时做更多的开销。最好简单地将结构类型作为参数。当用作函数/方法参数时,结构被视为 .ByReference
,并为您处理所有自动读取和写入。因此,如果您这样做,则可以省略 write()
调用:
boolean Module32First(Pointer hSnapshot, WinAPI.MODULEENTRY32 lpme);
boolean Module32Next(Pointer hSnapshot, WinAPI.MODULEENTRY32 lpme);
也就是说,对您的 write 调用的评论指向此处的根本原因:您需要将 dwSize
值设置为结构的大小。但是,由于 Java Objects 的初始化顺序,Structure 在初始化 dwSize
变量时没有确定大小所需的信息,所以这部分没有给你正确的大小:
public int dwSize = this.size();
要解决这个问题,只需声明该变量并稍后在构造函数中设置大小,例如
public static class MODULEENTRY32 extends Structure {
public int dwSize;
// other declarations
public MODULEENTRY32() {
super();
dwSize = size();
}
}
此外,您对 szModule
和 szExePath
的映射不正确。您只在结构的内存分配中提供了指针(总共 16 个字节),但这些是固定长度的字符数组。它们应该被定义:
public char[] szModule = new char[MAX_MODULE_NAME32 + 1];
public char[] szExePath = new char[MAX_PATH];
请注意,char[]
映射适用于映射的 Unicode (_W) 版本,这是一个相当安全的假设。
但与其自己编写,不如使用 jna-platform
中 JNA 用户贡献的映射中已经存在的映射。 The MODULEENTRY32W
type is already there(是的,它使用 DWORD
,因此您的版本更简单;但您可以查看代码以了解它们如何处理大小。)以及 Module32FirstW
和 Module32NextW
函数are also mapped。 (W 后缀表示现在所有现代 Windows 系统都使用的宽字符 (Unicode)。)