Какой самый простой способ вызвать функцию ядра Windows из Java? - PullRequest
7 голосов
/ 16 июня 2009

В поисках того, как это сделать, я нашел смутное обсуждение различных вариантов, таких как JNI против JNA, но не так много, как в конкретных примерах.

Контекст: если Java File.renameTo() не может выполнить свою работу (по какой-либо причине; это немного проблематично ), я бы хотел вернуться к непосредственному использованию этой встроенной функции Windows, которая определена в kernel32.dll ( из этого ответа ):

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

Итак, используя любой подход, как именно вы бы вызвали эту функцию из Java-кода? Я ищу самый простой способ, с минимальным количеством не-Java кода или дополнительных шагов (например, при компиляции или развертывании).

Ответы [ 3 ]

7 голосов
/ 16 июня 2009

Если вы используете 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 голос
/ 16 июня 2009

На основе библиотеки NativeCall Я сделал следующее Приложение POC .

Используется функция MoveFileA из kernel32.dll

Он поставляется в виде полного рабочего образца с run.bat и всеми jar и dlls на месте.

Перемещает включенный test.txt в test2.txt


Если вам не нравится версия библиотеки NativeCall, я сделал еще одно POC-приложение на основе / возобновление работы Java Native Access (JNA) . На этот раз MoveFileA и MoveFileW реализованы и продемонстрированы.

1 голос
/ 16 июня 2009

Если это действительно необходимо (renameTo не работает, и вы уверены, что MoveFile будет работать), я бы использовал JNA . Похоже, большая часть работы уже выполнена в com.mucommander.file.util. Kernel32.java / Kernel32API.java .

...