从Java调用Windows内核函数的最简单方法是什么?
-
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),我会使用 JNA 。看起来大部分工作已在com.mucommander.file.util中完成。 Kernel32.java / Kernel32API.java 。
基于 NativeCall库,我做了以下 POC申请。
它使用 kernel32.dll 中的 MoveFileA
函数
它是一个带有run.bat和所有jar和dll的完整工作样本。
它将包含的test.txt移动到test2.txt
如果您不喜欢NativeCall库版本,我又做了另一个 POC应用程序基于/重新访问 Java Native Access(JNA)库。这次实现 MoveFileA
和 MoveFileW
。
不隶属于 StackOverflow