Как заставить GetLastError надежно работать с JNA? - PullRequest
1 голос
/ 07 декабря 2011

Я использую различные функции Win32 API в своем Java-приложении и использую GetLastError для получения информации о неудачных вызовах API.

В большинстве случаев это работает, но теперь я обнаружил случай, когда что-то сбрасывает последнюю ошибку.

Это то, что я делаю как в своем приложении Java, так и в приложении VB6:

  1. Я открываю дескриптор процесса с помощью PID 4 (Система)
  2. Я звоню GetModuleFileNameEx с этой ручкой.
  3. Я звонюGetProcessImageFileName с этим дескриптором.

Теперь обе функции API завершаются неудачно, как и ожидалось (они возвращают ноль), и в моем приложении VB6 GetLastError возвращает 87(«Неверный параметр») после обоих вызовов API.

Но в моем приложении Java только после GetModuleFileNameEx последняя ошибка установлена ​​равной 87. После GetProcessImageFileName она всегда равна нулю.

Что я могу сделать с этим?

РЕДАКТИРОВАТЬ:

Вот декларации JNA:

public interface PsApi extends StdCallLibrary {
    PsApi INSTANCE = (PsApi) Native.loadLibrary("psapi", PsApi.class, 
            W32APIOptions.UNICODE_OPTIONS);
    int GetModuleFileNameEx(WinNT.HANDLE hProcess, WinDef.HMODULE hModule, 
            char[] lpFilename, int nSize);
    int GetProcessImageFileName(WinNT.HANDLE hProcess, char[] lpImageFileName, 
            int nSize);
}

И вызывающий код для GetProcessImageFileName

char[] buffer = new char[2048];
int result = PsApi.INSTANCE.GetProcessImageFileName(hProcess, buffer, 
   buffer.length);
if (result == 0) {
    throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}
return new String(Arrays.copyOf(buffer, result));

А для GetModuleFileNameEx

char[] buffer = new char[2048];
int result = PsApi.INSTANCE.GetModuleFileNameEx(hProcess, hModule, buffer,
    buffer.length);
if (result == 0) {
     throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}
return new String(Arrays.copyOf(buffer, result));

Ответы [ 2 ]

5 голосов
/ 07 декабря 2011

Документация описывает два варианта:

Если функция устанавливает свойство системной ошибки (errno или GetLastError ()), код ошибки будет сгенерирован как исключение LastErrorException, если вы объявите исключение в отображении JNA. Кроме того, вы можете использовать Native.getLastError (), чтобы получить его, при условии, что Native.setPreserveLastError (boolean) был вызван с истинным значением. Бросок исключения является предпочтительным, поскольку он имеет лучшую производительность.

Проблема с вызовом GetLastError заключается в том, что среда JNA и, действительно, среда выполнения Java могут вызывать функцию Windows, которая сбрасывает ошибку. Таким образом, вы не должны пытаться позвонить GetLastError напрямую.

1 голос
/ 05 августа 2015

Вы можете использовать «throws LastErrorException» и обычно это работает, но это не всегда лучшее решение.Безопаснее проверить возвращаемое значение функции API и вызвать Native.getLastError () , если возвращаемое значение функции API указывает на то, что произошла ошибка.

Native.getLastError () возвращает внутреннюю копию значения системной ошибки, которая была сохранена сразу после того, как был возвращен последний вызов метода API, отправленный JNA (это делается в native / dispatch.c после вызова ffi_call ()).Значение ошибки хранится JNA в локальном хранилище потока и не может быть изменено во время выполнения Java.Больше нет необходимости вызывать Native.setPreserveLastError (true) , поскольку всегда сохраняется последнее значение ошибки.

Если используется «throws LastErrorException», JNA устанавливает значение системной ошибки равным 0перед отправкой вызова функции.Обычно значение равно нулю после успешного завершения функции системного API, но нет явной гарантии.

Руководство программиста Linux ( man 3 errno ) гласит: " Его значение равноимеет значение только тогда, когда возвращаемое значение вызова указывает на ошибку (т. е. -1 из большинства системных вызовов; -1 или NULL из большинства библиотечных функций); успешно завершившейся функции разрешается изменять errno."
Wikipedia : " Любая библиотечная функция может изменять значение, сохраненное перед возвратом, независимо от того, обнаруживают ли они ошибки. "

В Windows документация GetLastError Функция API не гарантирует, что функция API, которая задокументирована для установки кода последней ошибки, устанавливает его в 0 или оставляет 0 в случае успеха.

...