简体   繁体   中英

JNA mapping to pass in/out buffer to winapi function

I need to enumerate hardlinks to files in a Java app for Windows. I considered using Runtime with fsutil hardlink list , but requires administrative privileges. That led me to WINAPI (ugh). The Kernel32.dll functions, FindFirstFileNameW and FindNextFileNameW should do this, but I'm having trouble with calling it via the JNA API. FindFirstFileNameW has the specification:

HANDLE WINAPI FindFirstFileNameW(
 _In_     LPCWSTR lpFileName,
 _In_     DWORD dwFlags,
 _Inout_  LPDWORD StringLength,
 _Inout_  PWCHAR LinkName
);

My JNA mapping:

public interface Kernel32 extends StdCallLibrary { 
    Kernel32 INSTANCE = (Kernel32)Native.loadLibrary("kernel32",Kernel32.class, W32APIOptions.UNICODE_OPTIONS);
    HANDLE FindFirstFileNameW(WString wString, int dwFlags, IntByReference StringLength, ______ LinkName);

    boolean FindNextFileNameW(HANDLE hFindStream, IntByReference StringLength, ______ LinkName);
    boolean FindClose(HANDLE hFindFile);
    int GetLastError();
}

Relevant parts of calling function:

public String[] getHardLInks(Path path)
{
  Kernel32 lib = Kernel32.INSTANCE;
  IntByReference stringLength = new IntByReference();
  ______ linkName = ______;
  HANDLE hFile = lib.FindFirstFileNameW(new WString(path.toString()), 0, stringLength, linkName);
  String hardlink = //Convert linkName to String
  //Add to array
  // Loop through FindNextFileName
  //Close handle
}

The blanks are where I've tried mapping LinkName , "a pointer to a buffer to store the first link name found for lpFileName ", to many things, unsuccessfully. That includes, strings, char[], byte[], Buffer, Pointer, and Memory, but nothing ever comes back from the call. I believe the rest to be correct from the return values I get from StringLength in testing. However, GetLastError always returns ERROR_MORE_DATA (234), which according to the documentation means the buffer is too small, even when I've passed in kilobytes of Memory.

What datatype should I be using and how do I get it back into a String?

PWCHAR => char[] , although NIO Buffers or memory will also work (just keep in mind that Buffer and memory count in bytes, while the API expects the count in chars).

You also need to initialize the IntByReference to the size of your array, otherwise you're telling the API that your buffer is of size zero, and it will obediently fill your buffer with exactly zero characters.

Like most MS API functions of this sort, you can probably pass null for the buffer and then it'll write the required buffer size into your length reference.

EDIT

One other thing - since you're (correctly) using W32API_UNICODE_OPTIONS to initialize your library mapping, String will now automatically be mapped to wide character strings (so you don't have to use WString ), and the -A/W function suffix is taken care of automatically, so you can drop the -W suffix from your method names.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM