#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
.