Какой самый простой способ вызвать функцию ядра Windows из Java?
-
05-07-2019 - |
Вопрос
В поисках того, как это сделать, я нашел смутное обсуждение различных вариантов, таких как JNI против JNA, но не так много, как в конкретных примерах.
Контекст: если Java File.renameTo ()
не может выполнить свою работу (по любой причине; это немного проблематично ), я бы хотел вернуться к непосредственному использованию этой встроенной функции Windows, которая определена в kernel32.dll ( из этого ответа ):
BOOL WINAPI MoveFile(
__in LPCTSTR lpExistingFileName,
__in LPCTSTR lpNewFileName
);
Итак, используя любой подход, как именно вы бы вызвали эту функцию из кода Java? Я ищу самый простой способ, с минимальным количеством не-Java кода или дополнительных шагов (например, при компиляции или развертывании).
Решение
Если вы используете JNA, рассмотрите возможность вызова MoveFileW напрямую - избавляет от необходимости предоставлять информацию о конфигурации для выбора между вызовами Unicode и ANSI.
import java.io.*;
import com.sun.jna.*;
public class Ren {
static interface Kernel32 extends Library {
public static Kernel32 INSTANCE = (Kernel32) Native
.loadLibrary("Kernel32", Kernel32.class);
public static int FORMAT_MESSAGE_FROM_SYSTEM = 4096;
public static int FORMAT_MESSAGE_IGNORE_INSERTS = 512;
public boolean MoveFileW(WString lpExistingFileName,
WString lpNewFileName);
public int GetLastError();
public int FormatMessageW(int dwFlags,
Pointer lpSource, int dwMessageId,
int dwLanguageId, char[] lpBuffer, int nSize,
Pointer Arguments);
}
public static String getLastError() {
int dwMessageId = Kernel32.INSTANCE.GetLastError();
char[] lpBuffer = new char[1024];
int lenW = Kernel32.INSTANCE.FormatMessageW(
Kernel32.FORMAT_MESSAGE_FROM_SYSTEM
| Kernel32.FORMAT_MESSAGE_IGNORE_INSERTS, null,
dwMessageId, 0, lpBuffer, lpBuffer.length, null);
return new String(lpBuffer, 0, lenW);
}
public static void main(String[] args) throws IOException {
String from = ".\\from.txt";
String to = ".\\to.txt";
new FileOutputStream(from).close();
if (!Kernel32.INSTANCE.MoveFileW(new WString(from),
new WString(to))) {
throw new IOException(getLastError());
}
}
}
<Ч>
РЕДАКТИРОВАТЬ: я отредактировал свой ответ после проверки кода - я ошибся из-за использования char [] в подписи - лучше использовать WString .
Другие советы
Если это действительно необходимо (renameTo не работает, и вы уверены, что MoveFile будет работать), я бы использовал ЮНА . Похоже, большая часть работы уже выполнена в com.mucommander.file.util. Kernel32.java / Kernel32API.java .
На основе библиотеки NativeCall я сделал следующее Приложение POC .
Использует функцию MoveFileA
из kernel32.dll
Он поставляется в виде полного рабочего образца с run.bat и всеми jar и dll на месте.
Перемещает включенный test.txt в test2.txt
<Ч> Если вам не нравится версия библиотеки NativeCall, я сделал еще одну Приложение POC , созданное на основе библиотеки Java Native Access (JNA) . На этот раз MoveFileA
и MoveFileW
реализованы и продемонстрированы.