调用 Module32First 给出无效参数(错误代码 87)

时间:2021-06-09 16:43:35

标签: java jna

我正在使用 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 也是有效的,并且正确获取。

任何帮助将不胜感激。

1 个答案:

答案 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();
    }   
}

此外,您对 szModuleszExePath 的映射不正确。您只在结构的内存分配中提供了指针(总共 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,因此您的版本更简单;但您可以查看代码以了解它们如何处理大小。)以及 Module32FirstWModule32NextW 函数are also mapped。 (W 后缀表示现在所有现代 Windows 系统都使用的宽字符 (Unicode)。)

相关问题