JNA - como manipular parâmetros passados por referência a uma DLL?

Fala pessoal!

               Estou estudando o JNA para construir um wrapper de uma dll escrita em c++ para a minha aplicação Java. Dado a assinatura da função implementada pela DLL:
 extern "C" _declspec (dllexport) int funcaoAgoraVai(int a, bool b, char c, int* aPtr, bool *bPtr, unsigned char *cPtr)

Qual seria o tipo correto de Java para o mapeamento do último parâmetro passado por referência da função (unsigned char*)?

Ae você cai na questão terrível que o o gosling teima em ignorar:

O problema é que em java não tem byte não sinalizado (0 -255).

Leia aqui para entender melhor a dor de cabeça que isso causa. Você vai precisar desse texto.

http://www.darksleep.com/player/JavaAndUnsignedTypes.html

unsigned *char é um ponteiro para uma área na memória que guarda chars, ou seja, um vetor de bytes.

No endereço abaixo deve ter a resposta para sua pergunta…

https://jna.dev.java.net/#mapping

[quote]O problema é que em java não tem byte não sinalizado (0 -255).

Leia aqui para entender melhor a dor de cabeça que isso causa. Você vai precisar desse texto.

http://www.darksleep.com/player/JavaAndUnsignedTypes.html[/quote]

Obrigado, juliocbq. Realmente era o que eu estava procurando. Agora já consigo acessar o ponteiro passado como parâmetro por referência. Como java não possui o tipo sem sinal, então tive que operar diretamente nos bits. Tive que fazer assim:

        int a = 1;
        boolean b = true;
        char c = 'a';
        IntByReference aPtr = new IntByReference();
        IntByReference bPtr = new IntByReference();
        PointerByReference cPtr = new PointerByReference();
        
        int w = lib.funcaoAgoraVai(a, b, c, aPtr, bPtr, cPtr);

        Pointer p = cPtr.getPointer();
        byte[] baite = p.getByteArray(0, 4);
        int temp;

        short[] retornoUnsignedChar = new short[baite.length];
        for(int i=0 ; i < baite.length ; i++)
        {
        	temp = (0x000000FF & ((int)baite[i]));
        	retornoUnsignedChar[i] = (short) temp;
        }

        for(int j=0 ; j<retornoUnsignedChar.length ; j++)
        	System.out.println("unsigned char " + j + " : " + retornoUnsignedChar[j]);	

No entanto, mesmo quando o array de “unsigned char” possui mais de 4 parâmetros, eu não consigo acessar o quinto elemento, por exemplo. No trecho do código onde há uma chamada a byte[] baite = p.getByteArray(0, 4); se eu trocar por byte[] baite = p.getByteArray(0, 5);, É lançada a excessão: java.lang.IndexOutOfBoundsException. Alguém tem ideia por que está acontecendo isso?

[quote=gillianoPE][quote]O problema é que em java não tem byte não sinalizado (0 -255).

Leia aqui para entender melhor a dor de cabeça que isso causa. Você vai precisar desse texto.

http://www.darksleep.com/player/JavaAndUnsignedTypes.html[/quote]

Obrigado, juliocbq. Realmente era o que eu estava procurando. Agora já consigo acessar o ponteiro passado como parâmetro por referência. Como java não possui o tipo sem sinal, então tive que operar diretamente nos bits. Tive que fazer assim:

        int a = 1;
        boolean b = true;
        char c = 'a';
        IntByReference aPtr = new IntByReference();
        IntByReference bPtr = new IntByReference();
        PointerByReference cPtr = new PointerByReference();
        
        int w = lib.funcaoAgoraVai(a, b, c, aPtr, bPtr, cPtr);

        Pointer p = cPtr.getPointer();
        byte[] baite = p.getByteArray(0, 4);
        int temp;

        short[] retornoUnsignedChar = new short[baite.length];
        for(int i=0 ; i < baite.length ; i++)
        {
        	temp = (0x000000FF & ((int)baite[i]));
        	retornoUnsignedChar[i] = (short) temp;
        }

        for(int j=0 ; j<retornoUnsignedChar.length ; j++)
        	System.out.println("unsigned char " + j + " : " + retornoUnsignedChar[j]);	

No entanto, mesmo quando o array de “unsigned char” possui mais de 4 parâmetros, eu não consigo acessar o quinto elemento, por exemplo. No trecho do código onde há uma chamada a byte[] baite = p.getByteArray(0, 4); se eu trocar por byte[] baite = p.getByteArray(0, 5);, É lançada a excessão: java.lang.IndexOutOfBoundsException. Alguém tem ideia por que está acontecendo isso?[/quote]

Então giliano, acho que agora vc marcou. É o seguinte:

digamos que seu vetor de vetor de bytes, que é um ponteiro para um ponteiro (usigned char** pt), ou seja uma matriz possui mais de 4 elementos ok?

O índice de procura sempre começa em 0(zero). O quinto elemento seria p.getByteArray(0,4), e não p.getByteArray(0,5). É a idéia que tive quando vi seu código. Para ter certeza, use um breakpoint, depure e observe o que existe dentro do seu ponteiro.

Então, julio… Pra deixar mais claro o que estou tentando fazer:
Código C que gera a DLL:

extern "C" _declspec (dllexport) int funcaoAgoraVai(int a, bool b, char c, int* aPtr, bool *bPtr, unsigned char *cPtr)
  {
	  *aPtr = 3;
	  *bPtr = true;

	  cPtr[0] = 123; 
	  cPtr[1] = 255;
	  cPtr[2] = 0;
	  cPtr[3] = 3;
	  cPtr[4] = 30;
	  cPtr[5] = 125;

	  return 0;
  }

Tudo que eu preciso é ter acesso a todos os elementos de meu vetor de “unsigned char”. Só que, mesmo sabendo que originalmente a minha DLL altera o ponteiro passado por referencia para ter acesso a um vetor de 6 elementos, quando eu faço uma chamada no Java a p.getByteArray(0,6) é lançada a exceção:

Exception in thread "main" java.lang.IndexOutOfBoundsException: Bounds exceeds available space : size=4, offset=6 at com.sun.jna.Memory.boundsCheck(Memory.java:168) at com.sun.jna.Memory.read(Memory.java:185) at com.sun.jna.Pointer.getByteArray(Pointer.java:753) at jna_test.Main_Test.main(Main_Test.java:40)
O que acho estranho é ele sempre “acreditar” que meu vetor é de 4 elementos. Esclareceu um pouco mais o meu problema?

[quote=gillianoPE]Então, julio… Pra deixar mais claro o que estou tentando fazer:
Código C que gera a DLL:

extern "C" _declspec (dllexport) int funcaoAgoraVai(int a, bool b, char c, int* aPtr, bool *bPtr, unsigned char *cPtr)
  {
	  *aPtr = 3;
	  *bPtr = true;

	  cPtr[0] = 123; 
	  cPtr[1] = 255;
	  cPtr[2] = 0;
	  cPtr[3] = 3;
	  cPtr[4] = 30;
	  cPtr[5] = 125;

	  return 0;
  }

Tudo que eu preciso é ter acesso a todos os elementos de meu vetor de “unsigned char”. Só que, mesmo sabendo que originalmente a minha DLL altera o ponteiro passado por referencia para ter acesso a um vetor de 6 elementos, quando eu faço uma chamada no Java a p.getByteArray(0,6) é lançada a exceção:

Exception in thread "main" java.lang.IndexOutOfBoundsException: Bounds exceeds available space : size=4, offset=6 at com.sun.jna.Memory.boundsCheck(Memory.java:168) at com.sun.jna.Memory.read(Memory.java:185) at com.sun.jna.Pointer.getByteArray(Pointer.java:753) at jna_test.Main_Test.main(Main_Test.java:40)
O que acho estranho é ele sempre “acreditar” que meu vetor é de 4 elementos. Esclareceu um pouco mais o meu problema?

[/quote]

Esclareceu sim. O ponteiro está corrompendo os dados. Precisa depurar para ver o que tem dentro do ponteiro, e ver o que está saindo errado.