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

从Java调用Windows内核函数最简单的方法是什么?,java,windows,winapi,java-native-interface,jna,Java,Windows,Winapi,Java Native Interface,Jna,在寻找如何做到这一点的过程中,我发现了一些关于不同选项的模糊讨论,比如JNI与JNA,但具体的例子并不多 上下文:如果Java的文件.renameTo()无法完成它的工作(无论出于何种原因),我想退回到直接使用这个在kernel32.dll()中定义的本机Windows函数: 所以,无论使用何种方法,您将如何从Java代码中调用该函数?我正在寻找最简单的方法,使用最少的非Java代码或额外步骤(例如编译或部署)。如果真的有必要(renameTo不起作用,您肯定MoveFile会),我会使用。看起

在寻找如何做到这一点的过程中,我发现了一些关于不同选项的模糊讨论,比如JNI与JNA,但具体的例子并不多

上下文:如果Java的
文件.renameTo()
无法完成它的工作(无论出于何种原因),我想退回到直接使用这个在kernel32.dll()中定义的本机Windows函数:


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

如果真的有必要(renameTo不起作用,您肯定MoveFile会),我会使用。看起来大部分工作已经在com.mucommander.file.util./.

中完成了,这是基于我所做的以下工作

它使用kernel32.dll中的
MoveFileA
函数

它是一个完整的工作示例,带有run.bat和所有jar和dll

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



如果您不喜欢NativeCall库的版本,我会根据库/恢复库做另一个版本。这段时间 MOVELIAE和 MOVEFLIVE被实现和演示。

如果您与JNA一起,考虑直接调用-它节省了提供配置信息来选择Unicode和ANSI调用。< /P>

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[],最好使用。

并且不要忘记GetLastError(),以获得与File不同的失败移动的有意义的解释。renameTo()我不确定/MoveFile是否有效,但我可以尝试,因为renameTo-sure不起作用。顺便说一句,你链接到的两个文件并不完全匹配;缺少Kernel32API.DEFAULT\u选项。您应该将什么作为第三个参数传递给Native.loadLibrary?我正在尝试使用空地图,但无法使其工作;“ClassCastException:$Proxy0无法强制转换为com.sun.jna.Library”出现。@jitter,我正在检查它,Jonik,我已经修复了到最新版本的链接,因此它们应该是同步的。请注意,默认_选项是在com.sun.jna.examples.win32.W32API()中定义的,Kernel32API继承自.Ok,但是如何直接调用MoveFileW呢?就像Matthew Flaschen建议的,还是什么?如果您能提供几行示例代码(如如何使用Native.loadLibrary()等),我们将不胜感激。感谢您提供的JNA示例!顺便说一句,MoveFileA(在jitter的回答中提到)的接口看起来如何?简单地使用“MoveFileA”而不是“MoveFileW”是没有好处的。我确实在尝试移动/重命名目录,但无法使用它-尽管我不确定这是因为MoveFileW还是其他原因。该函数可以定义为MoveFileA(String,String),但这样做会限制您可以使用的文件名。您可能无法在系统上的所有文件上使用它,尤其是在使用NTFS时。我在一个目录上测试了上面的代码,所以你的问题可能是其他的。我接受这个,因为我认为解决方案和示例代码应该就在这里。(如果发布了更好/更简单的方式,我当然会更改它。)谢谢!使用NativeCall,我能够从Java快速移动大目录(尽管我还没有在renameTo经常失败的情况下尝试过),执行调用的代码确实很简单。但是我现在对NativeCall.dll文件有一些疑问——如果你总是需要将它放在工作目录中(如果它在一个JAR中,对API的用户来说是透明的,嵌入lib会更容易),这看起来很笨拙,因为你不喜欢NativeCall的变体,我也做了一个JNA POC应用程序。同时实现MoveFileA和MoveFileW
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());
    }
  }
}