Reputation: 43
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?
Upvotes: 4
Views: 1194
Reputation: 10069
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.
Upvotes: 2