Acessar um .dll usando JNI

Eu nem to usando nenhum desses aí não, só o DevC++, e todas as .DLL que eu criei até agora usando ele funcionaram.
Eu tenho o Visual aqui, mas ele não cria bibliotecas dinâmicas, só estáticas, e nem vejo porque usá-lo, já que com o DevC++ tava dando tudo certo até agora.

Teoricamente, o que eu estou fazendo no arquivo .cpp está certo? Seria só fazer essa chamada mesmo?

Se alguém quiser dar uma olhada, aí estão todos os arquivos que eu tenho:

cam.cpp - Arquivo original de onde foi feita a .dll, aí está a implementação da função InicializaSDK()

CDSDK.def, CDSDK.lib e libCDSDK.a - Vieram numa mesma pasta, chamada “lib”, a .LIB é a biblioteca que eu teria que chamar.

CDSDK.dll - Encontrei na pasta da camera digital também, imagino que seja a mesma coisa que a .lib

Inicia.h, Inicia.java e IniciaImp.cpp - Tudo que eu consegui fazer até agora. O arquivo .java chamando o método nativo, o arquivo .H criado pelo javah e o arquivo .CPP que deve chamar a função.

Possíveis novidades! Descobri algumas coisas, meu código atualmente é o seguinte:

Inicia.java

[code]public class Inicia{
public native void InicializaSDK();

public static void main (String[] args){
	Inicia c = new Inicia();
	c.InicializaSDK();
}

static{
	System.load("C://j2sdk1.4.2_12//bin//Inicia.dll");
}

}[/code]

Inicia.h (criado usando o javah):

[code]/* DO NOT EDIT THIS FILE - it is machine generated /
#include <jni.h>
/
Header for class Inicia */

#ifndef _Included_Inicia
#define _Included_Inicia
#ifdef __cplusplus
extern “C” {
#endif
/*

  • Class: Inicia
  • Method: InicializaSDK
  • Signature: ()V
    */
    JNIEXPORT void JNICALL Java_Inicia_InicializaSDK
    (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif
[/code]

…e, quem estava/está dando problema.
IniciaImp.cpp:

[code]#include <stdio.h>
#include <windows.h>
#include <jni.h>
#include “Inicia.h”

JNIEXPORT void JNICALL Java_Inicia_InicializaSDK
(JNIEnv *env, jobject obj){
typedef void (*inisdk)();
HINSTANCE hdll;
inisdk Inicio;

      hdll = LoadLibrary("CDSDK.dll");
      
      Inicio = (inisdk)GetProcAddress(hdll, "InicializaSDK");
      Inicio();

}
[/code]

Agora, quando eu compilo o projeto da DLL JNI (que contém o Inicia.h e o IniciaImp.cpp), ele avisa que “nenhuma aplicação local foi fornecida”, seja lá o que isso queira dizer, mas cria a Inicia.dll certinho.
E quando eu vou rodar o arquivo Inicia.java, ele dá um erro bizarro, falando que foi descoberto pela HotSpot Virtual Machine, chamado EXCEPTION_ACESS_VIOLATION.

Acho que to no caminho, mas ainda meio perdido, alguém?

Primeiro, ao invés de usar System.load() use System.loadLibrary() (NO CÓDIGO JAVA!). Para esta ultima forma funcionar a dll tem que está no PATH do SO.

Segundo, agora vc está programando em C!! Meu tutor em C me disse o seguinte: “Essa é uma linguagem de homem, vc precisa saber exatamente o que vc está fazendo, pq ela permite fazer tudo inclisive m****!”. Hehe

Esse erro Acess Violation é um erro comum no C/C++, é quando vc “pisa” na memoria.

Adicionei algumas verificações ao seu codigo! Tente coloca-las no seu projeto e diz se ainda rola o Acess Violation! Pq o erro pode está na implementação do metodo InicializaSDK.

#include <stdio.h>   
#include <windows.h>   
#include <jni.h>   
#include "Inicia.h"   
  
  
JNIEXPORT void JNICALL Java_Inicia_InicializaSDK   
  (JNIEnv *env, jobject obj){   
          typedef void (*inisdk)();   //Aqui vc está declarando um ponteiro de função
          HINSTANCE hdll;   //Handler
          inisdk Inicio;     
     
          //Aqui vc está carregando a DLL em memoria
          hdll = LoadLibrary("CDSDK.dll");   
          
          //Verificamos se o handler foi carregado com sucesso.
          if( !hdll ){
              printf( "Nao conseguir carregar a lib em memoria!\r\n" );
              exit(-1);
          }
             
          //Atribuindo o endereço de memoria do metodo a nossa variavel Inicio
          Inicio = (inisdk)GetProcAddress(hdll, "InicializaSDK");   
          if( !Inicio ){
              printf( "Nao conseguir localizar o metodo dentro da lib!\r\n" );
              exit(-2);
          }else
              Inicio();   
}

No C/C++ as verificações ficam por sua conta!
:slight_smile:
Luca

Nossa Luca, valeu mesmo cara! Funcionou! =)
Quer dizer, ele entrou no erro de “Nao conseguiu localizar o metodo dentro da lib”, (não entendi pq, enfim)mas já é uma bela evolução!
Vou tentar ver o que está errado. Valeu de novo!
Abraço!

Isso pode ocorrer, entre outras coisas, porque é necessário usar um arquivo .DEF. Veja como é que se criam arquivos .DEF no MSDN.

[quote=thingol][quote]
Nao conseguiu localizar o metodo dentro da lib
[/quote]
Isso pode ocorrer, entre outras coisas, porque é necessário usar um arquivo .DEF. Veja como é que se criam arquivos .DEF no MSDN.
[/quote]

Tipo, eu tenho a CDSDK.DLL e a CDSDK.LIB, mas a .LIB, quando eu tento carregá-la, ele fala que essa não é uma imagem válida para Windows, por isso eu to carregando a .DLL mesmo.
A biblioteca CDSDK.LIB já veio com um .DEF, mas onde devo colocá-lo? Ou devo criar um .DEF para a CDSDK.DLL?

Fabricio, esse metodo realmente existe? Se ele existe qual a assinatura dele? A assinatura consiste no nome, retorno e parametros do metodo.

Se assim não rolar a gente pode tentar uma outra alternativa que é ao invés do LoadLibrary, usaremos a diretiva de pré-compilação #pragma.

Luca, então, meu orientador disse que ele existe no CSDSK.lib, e eu imaginei que existisse também np CDSDK.dll.
Tentei carregar a .LIB e, como disse, ele fala que essa não é uma imagem válida para Windows.

Eu tenho o arquivo .cpp de onde foi criado o .LIB (e imaginei que a .DLL também), e lá está definida a função InicializaSDK() que não recebe parâmetros e nao retorna nada.

Sabe algum modo de carregar a .LIB?

Cara, estou sem compilador C/C++ aqui.
Inicialmente uns links de exemplo:

http://msdn.microsoft.com/en-us/library/7f0aews7(VS.80).aspx
http://doc.ddart.net/msdn/header/include/objbase.h.html

Coloque no seu header a seguinte diretiva:

#pragma comment(lib, "CDSDK.lib")

Lembre-se de colocar o .h que contem as prototipos da função que foi implementada na lib!

Na configuração de compilação adicione a lib.
Não me lembro como é no DevC++, mas na linha de chamando o compilador na mãe seria o parametro -l.

Se mesmo assim não der, tem como vc compartilhar o projeto? Assim eu posso testar por minha conta e assim até arriscar uma tentativa e erro.

Cara, na .lib e na .dll não existe nenhum metodo chamando InicializaSDK() , o mais próximo que encontrei foi CDStartSDK, julgando pela assinatura deve retornar um int. Nos arquivo publicador eu não vi um .h que contivesse a assinatura dos metodos, acho que está faltando.

Fala Luca!
Cara, não sei nem como agradecer vc e o Thingol!
Realmente não tinha nenhum método InicializaSDK(), e consegui carregar o CDStartSDK()! =) Vou avisar meu orientador sobre isso!
Como você conseguiu ver isso na .DLL?

Bom, obrigado por tuuuuuuuudo mesmo velho! =) Qualuqer coisa eu volto aqui!
Abração!

fabriciocarraro

Boa tarde, voce sabe me dizer porque quando eu rodo o javah dá este erro?
O javac funciona certinho, mas esse bendito javah ta pho…

C:\Documents and Settings\hz6vhd\ProgramasNetBeans\JNI\src\jni>javah -jni OlaMundo error: cannot access OlaMundo class file for OlaMundo not found javadoc: error - Class OlaMundo not found. Error: No classes were specified on the command line. Try -help.
Muito obrigado.

Salve galera…

Tive muitas dificuldades em executar javah, entender o classpath, etc. Tenho tido novos resultados agora, to seguindo um tutorial e muitas, muitas dicas aqui do GUJ. Mas vamos lá…agora eu to tendo um probleminha com .dll. To fazendo um exemplo simples com o famoso “ola mundo”.

crie a parte do java

[code]
package jni;

class OlaMundo { //declaração da classe
public native void diga();//declaração do metodo nativo “diga”
public native void diga2();//declaração do metodo “diga2”

static {
    System.loadLibrary("OlaMundo"); //carrega a biblioteca "OlaMundo"
}
public static void main(String[] args) {//metodo main
    OlaMundo ola = new OlaMundo();//uma instancia da classe OlaMundo
    ola.diga();//ola chamando o metodo nativo "diga"
    ola.diga2();//ola chamando o metodo nativo "diga2"
}

}[/code]

compilei com javac.

gerei o .h com javah

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class jni_OlaMundo */

#ifndef _Included_jni_OlaMundo
#define _Included_jni_OlaMundo
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     jni_OlaMundo
 * Method:    diga
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_jni_OlaMundo_diga
  (JNIEnv *, jobject);

/*
 * Class:     jni_OlaMundo
 * Method:    diga2
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_jni_OlaMundo_diga2
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

criei o metodo nativo no Dev-C++ criando a dll OlaMundo.dll

[code]
#include <jni.h>
#include “jni_OlaMundo.h”

JNIEXPORT void JNICALL Java_jni_OlaMundo_diga (JNIEnv * env, jobject jobj){
printf(“Eu sou o metodo nativo >diga<, imprimeindo ‘Ola Mundo’.\n”);
}
JNIEXPORT void JNICALL Java_jni_OlaMundo_diga2 (JNIEnv * env, jobject jobj){
printf(“Eu sou o metodo nativo >diga2<, imprimeindo ‘Ola Mundo’ tambem.\n”);
}[/code]

Tudo parece estar correto, mas quando eu executo o código, é executado apenas um metodo da dll, e aparece este erro

Exception in thread "main" java.lang.UnsatisfiedLinkError: jni.OlaMundo.diga2()V at jni.OlaMundo.diga2(Native Method) at jni.OlaMundo.main(OlaMundo.java:13) Eu sou o metodo nativo >diga<, imprimeindo 'Ola Mundo'. Java Result: 1

A minha dll está no C:\Windows\System32

Se alguem puder me ajudar, muito agradecido.

Dá a impressão que você tem uma versão antiga da DLL em algum lugar do seu PATH.
Use o utilitário “depends” para saber afinal de contas que símbolos exporta sua DLL.

thingol

Obrigado pela dica amigo.

Cheguei em casa, tomei um café, esfriei a cabeça, segui a sua dica e acabei descobrindo que a dll estava sendo compilada com um .h antigo só com um método. Havia dois .h diferentes.

valeu mesmo.