Duvidas JNI - Urgente

15 respostas
I

Fala pessoal,
o problema é o seguinte…dentro de um metodo “.cpp” que implementa um metodo java nativo atraves da tecnologia JNI, eu chamo outro método. Este outro metodo tem como argumentos um tipo WORD e DWORD que são do c, mas não possuem correspondente no java, o que faço? quando for chamar este metodo passo para ele uma jstring? Outra dúvida seria quando no mesmo metodo eu tenho um argumento que é um ponteiro, ou seja, um endereço. Eu tenho que passar este argumento do java para este método nativo…mas como se o java não aceita ponteiros?

bem…não sei se fui bem claro…mas logo abaixo eu ilustro os métodos:

Método c a ser chamado dentro de algum metodo JNI:
WORD P1602_Di (WORD *wDi, WORD wa);

Metodo JNI:

JNIEXPORT jstring JNICALL Java_TesteDll_P1602_1Di (JNIEnv *env, jobject obj, jobjectarray jwDi,jstring jwa){

jstring x = P1602_Di(jwDi,jwa);

return x;
}

Dentro do java eu tenho que passar os Argumentos " WORD *wDi " e " WORD wa " para que eu possa chamar o metodo " P1602_Di ". então eu tenho o metodo java:

public native ? P1602_Di (? wDi, ? wa);

o que colocar no lugar de “?” já que não posso usar WORD, DWORD ou ponteiros? no exemplo eu mapeei WORD e DWORD para String e o ponteiro para um Vetor de Strings. está certo?

15 Respostas

T

igorps:
Fala pessoal,
o problema é o seguinte…dentro de um metodo “.cpp” que implementa um metodo java nativo atraves da tecnologia JNI, eu chamo outro método. Este outro metodo tem como argumentos um tipo WORD e DWORD que são do c, mas não possuem correspondente no java, o que faço? quando for chamar este metodo passo para ele uma jstring? Outra dúvida seria quando no mesmo metodo eu tenho um argumento que é um ponteiro, ou seja, um endereço. Eu tenho que passar este argumento do java para este método nativo…mas como se o java não aceita ponteiros?

bem…não sei se fui bem claro…mas logo abaixo eu ilustro os métodos:

Método c a ser chamado dentro de algum metodo JNI:
WORD P1602_Di (WORD *wDi, WORD wa);

Metodo JNI:

JNIEXPORT jstring JNICALL Java_TesteDll_P1602_1Di (JNIEnv *env, jobject obj, jobjectarray jwDi,jstring jwa){

jstring x = P1602_Di(jwDi,jwa);

return x;
}

Dentro do java eu tenho que passar os Argumentos " WORD *wDi " e " WORD wa " para que eu possa chamar o metodo " P1602_Di ". então eu tenho o metodo java:

public native ? P1602_Di (? wDi, ? wa);

o que colocar no lugar de “?” já que não posso usar WORD, DWORD ou ponteiros? no exemplo eu mapeei WORD e DWORD para String e o ponteiro para um Vetor de Strings. está certo?

Não entendi bulhufas, normalmente em JNI a gente costuma fazer o seguinte:

WORD (= 2 bytes) -> Java short ou jshort do JNI;
DWORD (= 4 bytes) -> Java int ou jint do JNI;

Que raios de string que você está usando? As strings do Java (que devem ser convertidas e desconvertidas a toda hora), ou as do C++ (char *, ou se você é mais moderno, std::string)? Não estou entendendo nada.

Se você tem de passar um array de Strings java para uma rotina em C (como parâmetro de entrada), por favor crie um char** no C++ (ou um std::vector< std::string >) , aloque e copie uma por uma. É enfadonho mas dá menos problemas.

Por favor, poste qual é a interface Java que você quer dar à sua rotina, e como é a sua rotina C++. Aí dá para a gente tentar fazer o “casamento de impedâncias” entre o java e o C++.

I

cara…na verdade…o que eu queria saber era qual o tipo java que corresponde ao WORD do c…pq no meu metodo nativo do java eu teria que passar este argumento…uma vez que este seria passado a um outro metodo c++ cujo argumento em um tipo WORD…

fcmartins

O DWORD é um unsigned long, que é equivalente ao jlong do JNI, que por sua vez é equivalente ao long do Java.

Note que os tipos WORD e DWORD nada tem a ver com letras e strings, são uma referência ao tipo de dados padrão do processador (palavra). Assim um WORD correponde a um unsigned short (16 bits) e o DWORD a um unsigned long (32 bits).

O seu método P1602_Di está esperando receber um ponteiro para um unsigned short e o valor de um unsigned short. Em C, ponteiros também são usados para referenciar arrays, então o método P1602_Di pode estar esperando receber um array no primeiro argumento. Veja o que o método faz para saber o que é que você vai enviar.

T

Só para confundir um pouco mais.

No compilador de 32 bits:
WORD = short = 2 bytes = jshort = Java short
INT = int = 4 bytes = jint = Java int
DWORD = unsigned long em 32 bits = 4 bytes ~= jint = Java int
__int64 = inteiro de 64 bits = 8 bytes = jlong = Java long
unsigned __int64 = inteiro de 64 bits, sem sinal = 8 bytes ~= jlong = Java long
INT_PTR = int
LONG_PTR = long

No compilador de 64 bits (A Sun tem uma versão da JVM para Windows 64 bits, mas não sei se já saiu do beta), todas as definições acima valem, mas:
INT_PTR = __int64
LONG_PTR = __int64

Quanto a ponteiros e outras coisas: que tal ler o livro de JNI antes? Talvez você tenha uma idéia melhor do que está lhe aguardando.

ftp://ftp.javasoft.com/docs/specs/jni.pdf
ou
ftp://ftp.javasoft.com/docs/specs/jni_output.zip
ou então
http://java.sun.com/docs/books/jni/html/titlepage.html

fcmartins

thingol:
Só para confundir um pouco mais.

No compilador de 32 bits:
WORD = short = 2 bytes = jshort = Java short
INT = int = 4 bytes = jint = Java int
DWORD = unsigned long em 32 bits = 4 bytes ~= jint = Java int
__int64 = inteiro de 64 bits = 8 bytes = jlong = Java long
unsigned __int64 = inteiro de 64 bits, sem sinal = 8 bytes ~= jlong = Java long
INT_PTR = int
LONG_PTR = long

No compilador de 64 bits (A Sun tem uma versão da JVM para Windows 64 bits, mas não sei se já saiu do beta), todas as definições acima valem, mas:
INT_PTR = __int64
LONG_PTR = __int64

Quanto a ponteiros e outras coisas: que tal ler o livro de JNI antes? Talvez você tenha uma idéia melhor do que está lhe aguardando.

ftp://ftp.javasoft.com/docs/specs/jni.pdf
ou
ftp://ftp.javasoft.com/docs/specs/jni_output.zip
ou então
http://java.sun.com/docs/books/jni/html/titlepage.html


Só corrigindo, nos casos do WORD, DWORD e unsigned __int64, como são sem sinal a correspondência com os tipos do Java seria : int, long e BigInteger.

I

quanto ao word e dword tah blza…mas e quanto ao ponteiro? em java tudo é passado por referencia…mas não sei como eu vou atribuir um endereço a uma variavel em java para depois passar como argumento…

fcmartins

Se ela espera um Array, Arrays em Java são objetos e para trabalhar com objetos em JNI é meio chato, dê uma olhada nesse trecho da documentação:
:arrow: Array Operations
Nessa mesma página explica como trabalhar com Strings.

Se ela espera receber um ponteiro só para alterar o valor dos dados do mesmo, basta você criar um ponteiro na função JNI, atribuir o valor necessário e então passar o mesmo para a função.

O que é que a função P1602_Di está fazendo? Poste o código, entendendo fica mais fácil ajudar.

I

essa eh uma de muitas funções que estão definidas em uma dll para trabalhar com uma placa de aquisição de dados…entao existem muitas funções que teem como argumento um tipo ponteiro. Por exemplo, em uma determinada função temos como argumento o endereço do local onde vão ser armazenados os 16 bits que representam o dado convertido da forma analógica para forma digital…daí usa-se um ponteiro WORD que é de 16 bits… eu posso fixar este endereço e nem precisar passar do java para o c…mas eu keria deixar uma coisa genérica…

fcmartins

Depois você retorna o valor para o Java.

T

Ah! Agora entendi o que você queria fazer.

WORD P1602_Di (WORD *wDi, WORD wa)

Vou abstrair a diferença entre “signed” e “unsigned” aqui, e passar o protótipo acima para C++. Seria algo como:

short P1602_Di (short& wDi, short wa);

O primeiro parâmetro é de saída, não de entrada. Acontece que o Java não aceita passagem de parâmetros por referência (diferentemente do C#).
Um truque muito usado em Java para passar parâmetros por referência é passar um parâmetro que é um array de 1 posição somente. Se você quisesse ter um método em Java que se comportasse igual a essa função, você teria:

public static short X_P1602_Di (short[] wDi, short wa);

e ela chamaria sua função mais ou menos como (sso não é JNI, é
pseudocódigo, mas o suficiente para você entender o que estou falando):

public static short X_P1602_Di (short[] wDi, short wa) {
     short sh = wDi[0];
# trecho em C
     P1602_Di (sh, wa);
# fim do trecho em C
     wDi[0] = sh;
}

e na hora de você chamar a função Java, você teria algo como

short[] wDi = new short[1];
short wa = 0;
X_P1601_Di (wDi, wa);
System.out.println (wDi[0]);
I

não…vc nao entendeu…o primeiro parametro que é um ponteiro…nao eh um parametro de saida…ele eh um endereço que a função vai precisar pra saber onde vai armazenar o outro argumento(WORD wa)… a kestão é em que tipo em java eu posso armazenar um endereço…?

T

Então vamos lá.

Quando trabalhamos com JNI devemos lembrar do seguinte:

  • O Java trabalha com garbage collection, portanto memória alocada em Java não tem uma posição fixa na memória.
  • Se você precisa trabalhar com uma posição fixada de memória (digamos que sua biblioteca faça isso - você programa o dispositivo, e o driver irá copiar os valores dentro de um buffer cujo endereço foi dado), você deve alocar essa memória em C/C++ mesmo, talvez usando alguma API do sistema operacional se houver algum “constraint” (por exemplo, o endereço de memória deve ser múltiplo de 8, ou então estar no início de uma página da memória de 1024 bytes etc.). Não lembro se o JNI também tem uma API que aloca memória “fixa” (ou seja, protegida contra garbage collection).
  • Aí esse endereço (que é de 32 bits em Windows 32 bits) pode ser guardado em uma variável de 32 bits (um int do Java), mas como um valor “opaco”, ou seja, não interessa ao Java saber o que é esse valor. Só é necessário guardá-lo entre chamadas.

Isso parece um pouco quando você trabalha com aquelas APIs do Windows que lhe retornam um HANDLE. É um valor de 32 bits (ou 64 bits no Windows 64 bits), mas você na verdade não faz manipulações com ele (para cada versão do Windows o HANDLE é um pouco diferente. Em algumas versões é um endereço dentro de um vetor do SO. Em outras é um índice dentro desse vetor. E em outras ainda não é nada disso.)
Da mesma maneira você pode trabalhar assim em Java: você tem um número que dentro da parte em C é um endereço de um buffer alocado pelo C, mas na parte em Java é apenas um identificador, ou um valor opaco.

T

Falei tudo isso só para lhe dizer que:

  • Não existe algo como o “endereço de uma variável” em Java, já que ela pode ser movida na memória pelo Garbage Collection. O que você pode fazer é copiar um valor que está em C para outro que está em Java, e vice-versa.
    Bom, se você estiver trabalhando com NIO (java.nio.*), existe o conceito de buffers, mas há rotinas que transformam um ByteBuffer, por exemplo (que representaria uma região de memória reservada para uma transferência de dados de hardware, tal como a usada para DMA) para um byte[], e vice-versa.
I

o garbage collection nao permite memoria fixa…mas essa memoria q eu to falando…eh a memoria presenta na Placa de aquisição de dados…nao a memoria do computador…existe posições de memoria nessa placa em que os dados da conversão são armazenados…

T

Hum, agora estou entendendo melhor.

Na verdade o parâmetro, embora seja um WORD*, não representa um endereço de memória virtual do seu programa C ou Java.
Ele é um endereço de memória físico na sua placa - isso dá quantos bits? Se fosse um endereço de memória físico do processador, poderia ser menos que 32 bits; da placa deve ser menos ainda, talvez uns 20 ou 16, ou até 8 (256 bytes de I/O).
Mas então pode ser tratado como um inteiro (java int) comum, já que o “endereço” cabe em um inteiro.

Algo como aquela programação antiga das placas de vídeo CGA - se você já ouviu falar de mostrar uma tela fazendo “peek” e “poke” dos bytes no endereço-base C800:0000 .

Criado 4 de maio de 2005
Ultima resposta 6 de mai. de 2005
Respostas 15
Participantes 3