2009-06-16 4 views
7

これを行う方法を探しているうちに、JNIとJNAのようなさまざまなオプションについて曖昧な議論がありましたが、具体的な例はあまりありません。JavaからWindowsカーネル関数を呼び出す最も簡単な方法は何ですか?

コンテキスト:;:

Javaの File.renameTo()は、それが(何らかの理由で it is a little problematic)の仕事だ行うことができない場合、私は直接kernel32.dllの( from this answer)で定義されているこのネイティブのWindows機能を使用してにフォールバックしたいのですが
BOOL WINAPI MoveFile(
    __in LPCTSTR lpExistingFileName, 
    __in LPCTSTR lpNewFileName 
); 

どのような方法であれ、Javaコード内からその関数をどの程度正確に呼び出すことができますか?最小限の量のJava以外のコードや追加の手順(コンパイルやデプロイメントなど)をもっとも簡単な方法を探しています。

答えて

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

編集:私は、コードを確認した後に私の答えを編集した - 私は、署名に[]文字の使用について間違っていた - WStringを使用することをお勧めします。

+0

しかし、* MoveFileWを直接呼び出す方法は? Matthew Flaschenが示唆するように、または何を?サンプルコードのいくつかの行(Native.loadLibrary()などの使い方など)は高く評価されます。 – Jonik

+0

私の実例をチェックしましたか? – jitter

+0

JNAの例をありがとう! Btw、インターフェイスはMoveFileA(ジッタの回答で言及されている)のためにどのように見えるでしょうか?単に "MoveFileW"の代わりに "MoveFileA"を使用するだけでいいわけではありませんでした。私は実際にディレクトリを移動/名前を変更しようとしていますが、これで作業することはできませんでしたが、それがMoveFileWなのか他のものなのかわかりません。 – Jonik

1

これが本当に必要な場合(renameToは機能しませんが、MoveFileは確実です)、私はJNAを使用します。ほとんどの作業は既にcom.mucommander.file.utilで行われているようです。 Kernel32.java/Kernel32API.java

+0

そして、File.renameTo()と違って、失敗した移動の意味のある説明を得るためにGetLastError()を忘れないでください。 – akarnokd

+0

私は確かではありません/ MoveFileは動作しますが、renameToはそうではありません。 Btw、リンク先の2つのファイルは完全には適合しません。 Kernel32API.DEFAULT_OPTIONSがありません。 Native.loadLibraryに3番目のパラメータとして渡すべきは何ですか?私は空の地図を試しているし、それを動作させることはできません。 "ClassCastException:$ Proxy0をcom.sun.jna.Libraryにキャストできません"というエラーが発生します。 – Jonik

+0

私の例を試しましたか? – jitter

1

NativeCall libraryに基づいて、私は以下を行った:POC Application

それは場合run.batと場所にあるすべてのjarファイルとDLLと同じように、完全な作業サンプルが来るkernel32.dllの

からMoveFileA機能を使用しています。

は、それはあなたが、私は別のPOC ApplicationJava Native Access (JNA)のライブラリにresuing /に基づいて行ったNativeCallライブラリのバージョンが気に入らない場合は付属のtest.txtが


をtest2.txtという名前に移行します。今回はMoveFileAMoveFileWが実装され、実演されています。

+0

ありがとう! NativeCallを使用すると、Javaから大規模なディレクトリを素早く移動することができました(ただし、renameToが失敗することはまだありませんでしたが)。実際に呼び出すためのコードは単純です。しかし、私はNativeCallについていくつか疑問を抱いています。dllファイル - あなたが常に作業ディレクトリにある必要がある場合は、不器用に思えます(APIのユーザに透過的に使用される、ジャーの1つの中にあれば、libを埋め込むのが簡単になります) – Jonik

+0

あなたが気に入らないNativeCallの変種私はJNA POCアプリもやった。 MoveFileAとMoveFileWの両方を実装する – jitter

関連する問題