Вызов Module32First Дает Недопустимый Параметр (Код Ошибки 87)

#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);
 

Модульная структура 32:

     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 и действителен. Идентификатор процесса также действителен и также получен надлежащим образом.

Любая помощь будет признательна.

Ответ №1:

Ваше отображение указателя в качестве второго аргумента, хотя и является технически правильным, требует от вас гораздо больших затрат при его написании. Лучше просто указать тип структуры в качестве аргумента. Структуры обрабатываются так же, как .ByReference при использовании в качестве аргументов функции/метода, и обрабатывают все функции автоматического чтения и записи за вас. Поэтому, если вы сделаете это, вы можете пропустить свой write() звонок:

 boolean Module32First(Pointer hSnapshot, WinAPI.MODULEENTRY32 lpme);
boolean Module32Next(Pointer hSnapshot, WinAPI.MODULEENTRY32 lpme);
 

Тем не менее, комментарий к вашему вызову записи указывает на основную причину здесь: вам нужно установить dwSize значение размера структуры. Однако из-за порядка инициализации объектов Java Структура не содержит информации, необходимой для определения размера при инициализации 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[] внимание, что сопоставление предназначено для версии сопоставления в Юникоде (_W), что является достаточно безопасным предположением.

Но вместо того, чтобы писать самостоятельно, вы должны использовать сопоставления, которые уже существуют в сопоставлениях, предоставленных пользователем JNA jna-platform . Тип MODULEENTRY32W уже есть (да, он используется DWORD , поэтому ваша версия проще; но вы можете посмотреть код, чтобы увидеть, как они обрабатывали размер.) Module32FirstW И Module32NextW функции и также сопоставлены. (Суффикс W предназначен для широких символов (Unicode), которые сейчас используются во всех современных системах Windows.)

Комментарии:

1. Да, я просто перепутал слова. Я хотел сказать сначала модуль 32. Я отредактирую свой пост, чтобы исправить это.

2. Привет, так что обнови информацию. Я сделал именно так, как вы предложили — dwSize инициализируется в конструкторе и передается по ссылке на структуру MODULEENTRY32. Однако после запуска программы я все еще получаю «ложь», возвращенную и код ошибки 87 от GetLastError.

3. Проверьте свои сопоставления. Две строки szModule и szExePath являются массивами символов фиксированной длины. Это char[] на Java для юникода. Почему бы не использовать уже написанные, которые я связал?

4. Да, но я полагал, что это будет соответствовать строке, но, думаю, я ошибался. У JNA есть readme «Сопоставления» на их странице GitHub, но они предоставили только общие типы сопоставлений, поэтому мне пришлось угадать. Я попробую исправить эти сопоставления и дам вам знать. И я решил создать свои собственные структуры только в учебных целях и потому, что некоторые отображенные функции и структуры недоступны.

5. Отлично. Не забудьте включить 1 для нулевого терминатора szModule .