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

发布于 2024-07-23 15:29:04 字数 637 浏览 5 评论 0 原文

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

上下文:如果 Java 的 File.renameTo() 无法完成其工作(无论出于何种原因;这有点问题),我想直接使用这个本机 Windows 函数,该函数在 kernel32.dll 中定义(来自这个答案):

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

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

While searching for how to do this, I found some vague discussion about different options, like JNI vs JNA, but not much in the way of concrete examples.

Context: if Java's File.renameTo() cannot do it's job (for whatever reason; it is a little problematic), I'd like to fall back to directly using this native Windows function, which is defined in kernel32.dll (from this answer):

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

So, using whatever approach, how exactly would you call that function from within Java code? I'm looking for the simplest way, with the minimum amount of non-Java code or extra steps (e.g. in compilation or deployment).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

独自←快乐 2024-07-30 15:29:04

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

If you go with JNA, consider invoking MoveFileW directly - it saves having to provide configuration info to choose between Unicode and ANSI calls.

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());
    }
  }
}

EDIT: I've edited my answer after checking the code - I was mistaken about using char[] in the signature - it is better to use WString.

小女人ら 2024-07-30 15:29:04

如果确实有必要(renameTo 不起作用,而你确定 MoveFile 会起作用),我会使用 JNA< /a>. 看起来大部分工作已经在 com.mucommander.file.util.Kernel32.java/Kernel32API.java

If this is really necessary (renameTo doesn't work and you're sure MoveFile will), I would use JNA. It looks like most of the work is already done in com.mucommander.file.util.Kernel32.java/Kernel32API.java.

抚笙 2024-07-30 15:29:04

基于 NativeCall 库 我做了以下 POC 应用程序

它使用 kernel32.dll 中的 MoveFileA 函数。

它是完整的工作示例,包含 run.bat 以及所有 jar 和 dll。

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


如果您不喜欢 NativeCall 库版本,我做了另一个 POC 应用程序基于/基于 Java Native Access (JNA) ) 库。 这次实现并演示了MoveFileAMoveFileW

Based on the NativeCall library I did the following POC Application.

It uses the MoveFileA function from kernel32.dll

It comes as complete working sample with a run.bat and all jar and dlls in place.

It moves the included test.txt to test2.txt


If you don't like the NativeCall library version I did another POC Application based on/resuing on the Java Native Access (JNA) library. This time MoveFileA and MoveFileW are implemented and demonstrated.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文