从Java调用Windows内核函数的最简单方法是什么?

时间:2009-06-16 10:40:20

标签: java windows winapi java-native-interface jna

在搜索如何执行此操作时,我发现了一些关于不同选项的模糊讨论,例如JNI与JNA,但在具体示例方面并不多。

上下文:如果Java的File.renameTo()无法完成任务(无论出于何种原因; it is a little problematic),我想回到直接使用这个本机Windows函数,该函数在kernel32.dll中定义(from this answer):

BOOL WINAPI MoveFile(
  __in  LPCTSTR lpExistingFileName,
  __in  LPCTSTR lpNewFileName
);

那么,使用任何方法,您将如何从Java代码中调用该函数?我正在寻找最简单的方法,使用最少量的非Java代码或额外的步骤(例如在编译或部署中)。

3 个答案:

答案 0 :(得分:7)

如果您使用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

答案 1 :(得分:1)

如果这确实是必要的(renameTo不起作用,你确定MoveFile会),我会使用JNA。看起来大多数工作已在com.mucommander.file.util。Kernel32.java / Kernel32API.java中完成。

答案 2 :(得分:1)

根据NativeCall library,我执行了以下POC Application

它使用 kernel32.dll

中的MoveFileA函数

它是一个带有run.bat和所有jar和dll的完整工作样本。

它将包含的test.txt移动到test2.txt


如果您不喜欢NativeCall库版本,我会在POC Application库上基于/重新生成另一个Java Native Access (JNA)。此时MoveFileAMoveFileW已实施并展示。