Olá!
Eu estou usando o novo compilador AOT da GraalVM, que gera imagens nativas, e quero usar a API do Windows na minha aplicação Java, mais especificamente a biblioteca User32.dll.
Para integrar o código Java com a biblioteca nativa, eu estou me baseando na documentação javadoc da Graal: https://www.graalvm.org/sdk/javadoc/index.html
E também neste tutorial oficial no Github: https://github.com/oracle/graal/blob/master/substratevm/src/com.oracle.svm.tutorial/src/com/oracle/svm/tutorial/CInterfaceTutorial.java
Estou tentando criar uma função que lista os teclados USB conectados, o código produzido em Java compila para nativo e executa sem erros, no entanto, o resultado da função GetRawInputDeviceInfo é sempre -1 , de acordo com a documentação da Microsoft isso significa que o parâmetro pData não tem espaço suficiente para os dados, mas estou passando um ponteiro nulo, e de acordo com a documentação, quando pData é nulo, o valor de retorno é zero, tenho dois códigos fazendo exatamente a mesma coisa, mas aquele escrito em C funciona e o escrito em Java não.
OBS: No código C existe uma diretiva #define, definindo a constante RIDI_DEVICENAME como 0x20000007, equivalente a 536870919, como não sei como “importar” as diretivas de pré-processamento no código Java, estou colocando o valor literal temporariamente.
Código em C:
int main() {
UINT nDevices;
if (GetRawInputDeviceList(NULL, &nDevices, sizeof(RAWINPUTDEVICELIST)) != 0) {
return 1;
}
PRAWINPUTDEVICELIST pRawInputDeviceList;
if ((pRawInputDeviceList = malloc(sizeof(RAWINPUTDEVICELIST) * nDevices)) == NULL) {
return 1;
}
if (GetRawInputDeviceList(pRawInputDeviceList, &nDevices, sizeof(RAWINPUTDEVICELIST)) == UINT_MAX) {
free(pRawInputDeviceList);
return 1;
}
for (size_t nDevice = 0; nDevice < nDevices; nDevice++) {
if (pRawInputDeviceList[nDevice].dwType != RIM_TYPEKEYBOARD)
continue;
char* deviceName = NULL;
UINT pcbSize;
if (GetRawInputDeviceInfo(pRawInputDeviceList[nDevice].hDevice, RIDI_DEVICENAME, NULL, &pcbSize) != UINT_MAX && pcbSize != 0) {
/*
char pdata[pcbSize];
if (GetRawInputDeviceInfo(pRawInputDeviceList[nDevice].hDevice, RIDI_DEVICENAME, pData, &pcbSize) != UINT_MAX) {
deviceName = pData;
printf("%s", deviceName);
}*/
}
}
return 0;
}
Código em Java:
public class Main {
public static void main(String[] args) {
var deviceAmountPointer = StackValue.get(CIntPointer.class);
if (getRawInputDeviceList(WordFactory.nullPointer(), deviceAmountPointer,
SizeOf.get(RawInputDeviceList.class)) != 0)
return;
var deviceAmount = deviceAmountPointer.read();
var deviceListPointer = UnmanagedMemory.<RawInputDeviceList>malloc(deviceAmount * SizeOf.get(RawInputDeviceList.class));
if (deviceListPointer.isNull())
return;
if (getRawInputDeviceList(deviceListPointer, deviceAmountPointer, SizeOf.get(RawInputDeviceList.class)) == -1) {
UnmanagedMemory.free(deviceListPointer);
return;
}
for (int i = 0; i <= deviceAmount; ++i) {
RawInputDeviceList device = deviceListPointer.addressOf(i);
if (device.deviceType() != 1)
continue;
var pcbSize = StackValue.get(CIntPointer.class);
if (getRawInputDeviceInfo(device.deviceHandle(), 536870919, WordFactory.nullPointer(), pcbSize) != -1 && pcbSize.read() != 0) {
var pData = UnmanagedMemory.<CCharPointer>malloc((pcbSize.read() + 1) * SizeOf.get(CCharPointer.class));
if (getRawInputDeviceInfo(device.deviceHandle(), 536870919, (VoidPointer) pData, pcbSize) != -1) {
System.out.println(CTypeConversion.toJavaString(pData));
}
}
}
}
}
@CContext(WindowsDirectives.class)
class Windows {
@CTypedefOfInfo("HANDLE")
@CPointerTo(nameOfCType = "void")
public interface Handle extends PointerBase { }
@CFunction("GetRawInputDeviceList")
public static native int getRawInputDeviceList(RawInputDeviceList inputDeviceList,
CIntPointer pointerDevicesAmount, int size);
@CFunction("GetRawInputDeviceInfoW")
public static native int getRawInputDeviceInfo(Handle deviceHandle, int uiCommand,
VoidPointer pData, CIntPointer pcbSize);
@CStruct("tagRAWINPUTDEVICELIST")
public interface RawInputDeviceList extends PointerBase {
@CFieldAddress("hDevice")
Handle deviceHandle();
@CField("dwType")
int deviceType();
RawInputDeviceList addressOf(int index);
}
}
class WindowsDirectives implements CContext.Directives {
@Override
public List<String> getHeaderFiles() {
return Collections.singletonList("<windows.h>");
}
@Override
public List<String> getLibraries() {
return Collections.singletonList("User32");
}
}
Documentação da Microsoft: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getrawinputdeviceinfoa
Alguém sabe o que estou fazendo de errado para a função GetRawInputDeviceInfo retornar -1 ao invés de zero?