Java Native Access: Calling kernel32 GetShortPathNameA.
Published Date: January 15th, 2010Category: General Practice |
Few days ago, my client was frustrated by the application which is not working properly in several cases. After a deep investigation, we find out that somehow, his tablet PC (windows-platform) is converting some paths into DOS 8.3 format. Which makes C:\Documents and Settings\ becomes C:\DOCUME~1\, but funnily also converting some paths in normal full Windows path. It causes some functions are not working because they are trying to match different format.
For example, we have two variables path and folderPath. Somehow, his machine read path in DOS 8.3 format, but read folderPath in full format. So when the line of code here is executed:
path.toLowerCase().contains(folderPath.toLowerCase())
it will always return false. Even though path is actually inside the folderPath.
Since my client was a continent apart from me, it’s not possible to investigate why the inconsistency happens, but the best I can do is trying to compare both ways. So the steps that popped out of my head are:
- Read kernel32.dll from Windows Library.
- Try to convert full folderPath to short DOS 8.3 format with kernel32 function, GetShortPathName with alias GetShortPathNameA.
- Match path with full path folderPath or, match path with short DOS 8.3 folderPath .
- If one of them is correct, then returns true.
I decide to use Java Native Access from https://jna.dev.java.net/. This library is LGPL. And so, here are two functions that makes it work:
1st function, matching path and folderPath:
private boolean checkInsideFolder(String path, String folderPath) {
boolean insideFolder = false;
byte[] shortt= new byte[256];
//Call CKernel32 interface to execute GetShortPathNameA method
int a = CKernel32.INSTANCE.GetShortPathNameA(folderPath, shortt, 256);
//Just check if platform = windows and CKernel32 returns a result
if(Platform.isWindows() && a !=0) {
String shortPath = Native.toString(shortt);
if(path.toLowerCase().contains(shortPath.toLowerCase()) ||
path.toLowerCase().contains(folderPath.toLowerCase())) {
insideFolder = true;
}
} else {
if(path.toLowerCase().contains(folderPath.toLowerCase())) {
insideFolder = true;
}
}
return insideFolder;
}
2nd function, CKernel32 interface which extends Kernel32 from JNA:
public interface CKernel32 extends Kernel32 {
CKernel32 INSTANCE = (CKernel32)
Native.loadLibrary("kernel32", CKernel32.class);
int GetShortPathNameA (String LongName, byte[] ShortName, int BufferCount);
}
OK, so I hope it works!

















