Blog do Urubatan
msgbartop
Desenvolvedor, Arquiteto, Palestrante, Coordenador do RSJUG, Patinador e Blogger
msgbarbottom

11 Sep 07 Chamando métodos nativos (.dll/.so/…) em java sem JNI

Uma das coisas mais chatas em java é que quando é necessário utilizar algum método nativo de qualquer biblioteca de qualquer sistema operacional, é necessário criar uma classe stub com métodos declarados como native, depois gerar um .h com o comando javah e implementar aquele método nativo com o compilador C de sua escolha, mesmo que isto seja apenas um proxy para alguma função de alguma DLL que já existe com exatamente os mesmos parametros, certo? errado!
Isto só era desta forma até criarem o projeto Java Native Access (JNA)
Na página do projeto existem alguns exemplos de chamadas a bibliotecas padrão do sistema operacional (tanto linux quando windows), mas eu não estava muito feliz com isto, imaginem se eu ja desenvolvi uma DLL/SO ou pior ainda, eu preciso chamar alguns métodos de uma DLL fornecida por alguem? e ai preciso ainda de toda aquela parafernalha do JNI?
Não precisa mais, e só para comprovar eu criei este exemplo simples!

Comecemos criando um biblioteca (a minha máquina é linux, por tanto vou criar um .so podem fazer o mesmo teste em um windows por ai se quiserem, mas por enquanto eu ja estou bastante feliz :D )
arquivo testejna.h

#ifndef testejna_H
#define testejna_H
void librarymethod(char* whatToSay);
#endif

vamos implementar isto no arquivo testejna.c

#include 
#include 
#include "testejna.h"

void librarymethod(char* whatToSay)
{
   printf("Java Rocks, I'm Calling this without JNI and telling the C code to Say: %s !\n",whatToSay);
}

tudo pronto, mandei o kdevelop compilar isto para mim, e ele criou o arquivo libtestejna.so, agora a nossa tarefa é chamar a função librarymethod desta biblioteca dinâmica (.so no linux, .dll no windows) a partir do nosso código java! preparem-se para passar trabalho :D
Só brincadeira, criei um projeto java novo no IntelliJ IDEA e adicionei o arquivo jna.jar no classpath (pode ser baixado do site do projeto)
Criei uma interface com a declaração do método que quero chamar, a idéia é uma interface possuir todos os métodos do .so/.dll que a aplicação for utilizar.

package testejna;

import com.sun.jna.Library;

public interface MySharedLibrary extends Library {
    public void librarymethod(String whatToSay);
}

Como podem ver, a única exigencia é que esta interface extenda com.sun.jna.Library, e esta tudo pronto, podemos agora utilizar a biblioteca dinâmica ja criada, e sem toda aquela encheção de saco do JNI!
Mas como?
Assim:

package testejna;

import com.sun.jna.Native;

public class TesteJNA {
    public static void main(String args[]){
        MySharedLibrary lib = (MySharedLibrary) Native.loadLibrary("testejna", MySharedLibrary.class);
        lib.librarymethod("Java Rocks");
    }
}

E executando o programa extremamente complexo em java que foi criado é impresso no console:

Java Rocks, I'm Calling this without JNI and telling the C code to Say: Java Rocks !

A idéia básica é que o método loadLibrary da classe com.sun.jna.Native cria um proxy para a interface que definimos, e cada método chamado deste próxy será direcionado para a biblioteca nativa.

O JNA ja tem suporte para diversas plataformas, olhando dentro do arquivo jna.jar, eles ja possuem suporte para:

  • darwin (Mac OS X)
  • freebsd-i386
  • linux-amd64
  • linux-i386
  • sunos-sparc
  • sunos-sparcv9
  • sunos-x86
  • win32
  • win32-x86

Ou seja, a grande maior parte dos sistemas utilizados por ai.
O que acontece é que eles possuem 1 biblioteca nativa para cada um destes sistemas operacionais que funciona de proxy para qualquer outra biblioteca do mesmo.

Eu achei o projeto espetacular, e a partir de hoje, não precisamos mais entrar em desespero sempre que for necessário chamar algum método nativo de alguma biblioteca proprietária (o pessoal que precisa trabalhar com impressoras fiscais que deve ficar bastante feliz :D )

Ai algum de vocês vai me perguntar por que coloquei a categoria “ruby” também neste post?
É por que o jruby ja esta utilizando o projeto para implementar as chamadas a métodos nativos necessários para compatibilidade com todos os módulos básicos do Ruby e para diversas extensões :D

As únicas perguntas que ficam depois disto é: por que isto não faz parte do JDK padrão, e por que desgraça ninguém tinha pensado nisto antes?

Se você gostou deste post, lembre-se de assinar o RSS feed do blog, para ser notificado de novos posts!

Tags: ,

Reader's Comments

  1. |

    Jorge Santos
    Penso que é por o teu dll necessitar de chamar outro dll e não conseguir chegar até ele…
    no teu caso:

    # C [kernel32.dll+0×12a5b]

    tenta compilar o dll com todas as bibliotecas que utiliza.
    ou então coloca o teu dll na mesma directoria que o kernel32.dll.

    fica bem

    Reply to this comment
  2. |

    Urubatan, estou tentando usar essa JNA para acessar o método que valida usuários no AD (active directory) do Windows. O código está assim:

    Login.java
    ————————————————————————————————————-
    package model.login;

    import com.sun.jna.Library;

    interface Login extends Library {
    public long LogonUserA(String username,String domain, String password, int logonType, int logonProvider, long token);
    }

    ExecutaLogin.java
    ————————————————————————————————————-
    package model.login;

    import com.sun.jna.Native;

    public class ExecutaLogin {
    public static void main(String[] args) {
    long token = 0;
    Login e = (Login)Native.loadLibrary(”advapi32″, Login.class);
    long i = e.LogonUserA(”C0072652″,”xxxx”,”xxxx”,3,0,token);
    System.out.println(i);
    }
    }

    —————————————————————————————————————-
    Quando executo da o seguinte erro:

    #
    # An unexpected error has been detected by HotSpot Virtual Machine:
    #
    # EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0×77f7fe75, pid=3972, tid=2008
    #
    # Java VM: Java HotSpot(TM) Client VM (1.5.0_06-b05 mixed mode)
    # Problematic frame:
    # C [ADVAPI32.dll+0x2fe75]
    #

    ————— T H R E A D —————

    Current thread (0×00357cc8): JavaThread “main” [_thread_in_native, id=2008]

    siginfo: ExceptionCode=0xc0000005, writing address 0×00000000

    Registers:
    EAX=0×00000000, EBX=0×00000000, ECX=0×00000010, EDX=0×0006da74
    ESP=0×0006da58, EBP=0×0006da94, ESI=0×7c9012d6, EDI=0×00000000
    EIP=0×77f7fe75, EFLAGS=0×00010246

    Top of Stack: (sp=0×0006da58)
    0×0006da58: 7c90f04c 7c901299 00000000 00000018
    0×0006da68: 00002923 00080000 0006d868 00120010
    0×0006da78: 000855a0 00000020 0006daec 0006dae4
    0×0006da88: 00000000 00000000 7c90f0aa 0006daf4
    0×0006da98: 77f90c2c 000855a0 000855c0 000855d8
    0×0006daa8: 00000003 00000003 00000000 00000000
    0×0006dab8: 00000000 00000000 00000000 00000000
    0×0006dac8: 00357cc8 06ca2848 77f90c7b 000a0008

    Instructions: (pc=0×77f7fe75)
    0×77f7fe65: ff 56 ff 15 c8 11 f5 77 e9 92 00 00 00 8b 7d 20
    0×77f7fe75: 83 27 00 e9 5d c5 fe ff 83 27 00 83 20 00 e9 47

    Stack: [0x00030000,0x00070000), sp=0x0006da58, free space=246k
    Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
    C [ADVAPI32.dll+0x2fe75]
    C [ADVAPI32.dll+0x40c2c]
    C [ADVAPI32.dll+0x40c9e]
    C [jna22446.tmp+0x8b87]
    C [jna22446.tmp+0x8799]
    C [jna22446.tmp+0x1ffd]
    C [jna22446.tmp+0x26e6]
    j com.sun.jna.Function.invokeLong(I[Ljava/lang/Object;)J+0
    j com.sun.jna.Function.invoke([Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;+361
    j com.sun.jna.Function.invoke(Ljava/lang/Class;[Ljava/lang/Object;Ljava/util/Map;)Ljava/lang/Object;+198
    j com.sun.jna.Library$Handler.invoke(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;+344
    j model.login.$Proxy0.LogonUserA(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IIJ)J+49
    j model.login.ExecutaLogin2.main([Ljava/lang/String;)V+23
    v ~StubRoutines::call_stub
    V [jvm.dll+0x845a9]
    V [jvm.dll+0xd9317]
    V [jvm.dll+0x8447a]
    V [jvm.dll+0x8b44a]
    C [javaw.exe+0x14c5]
    C [javaw.exe+0x3151]
    C [kernel32.dll+0x16fd7]

    Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
    j com.sun.jna.Function.invokeLong(I[Ljava/lang/Object;)J+0
    j com.sun.jna.Function.invoke([Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;+361
    j com.sun.jna.Function.invoke(Ljava/lang/Class;[Ljava/lang/Object;Ljava/util/Map;)Ljava/lang/Object;+198
    j com.sun.jna.Library$Handler.invoke(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;+344
    j model.login.$Proxy0.LogonUserA(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IIJ)J+49
    j model.login.ExecutaLogin2.main([Ljava/lang/String;)V+23
    v ~StubRoutines::call_stub

    --------------- P R O C E S S ---------------

    Java Threads: ( => current thread )
    0x00a332f8 JavaThread "Low Memory Detector" daemon [_thread_blocked, id=2244]
    0×00a31ec8 JavaThread “CompilerThread0″ daemon [_thread_blocked, id=2352]
    0×00a312b0 JavaThread “Signal Dispatcher” daemon [_thread_blocked, id=1480]
    0×009e8970 JavaThread “Finalizer” daemon [_thread_blocked, id=1032]
    0×00a27b68 JavaThread “Reference Handler” daemon [_thread_blocked, id=2500]
    =>0×00357cc8 JavaThread “main” [_thread_in_native, id=2008]

    Other Threads:
    0×0035f360 VMThread [id=2584]
    0×00a2f6c8 WatcherThread [id=1788]

    VM state:not at safepoint (normal execution)

    VM Mutex/Monitor currently owned by a thread: None

    Heap
    def new generation total 576K, used 549K [0×02a70000, 0×02b10000, 0×02f50000)
    eden space 512K, 94% used [0×02a70000, 0×02ae9478, 0×02af0000)
    from space 64K, 100% used [0×02b00000, 0×02b10000, 0×02b10000)
    to space 64K, 0% used [0×02af0000, 0×02af0000, 0×02b00000)
    tenured generation total 1408K, used 96K [0×02f50000, 0×030b0000, 0×06a70000)
    the space 1408K, 6% used [0×02f50000, 0×02f680e8, 0×02f68200, 0×030b0000)
    compacting perm gen total 8192K, used 2288K [0×06a70000, 0×07270000, 0×0aa70000)
    the space 8192K, 27% used [0×06a70000, 0×06cac0c8, 0×06cac200, 0×07270000)
    No shared spaces configured.

    Dynamic libraries:
    0×00400000 - 0×0040c000 C:\Arquivos de programas\CVRDPVI\Oracle JDeveloper 10.1.3.1.0\jdk\bin\javaw.exe
    0×7c900000 - 0×7c9b4000 C:\WINDOWS\system32\ntdll.dll
    0×7c800000 - 0×7c8ff000 C:\WINDOWS\system32\kernel32.dll
    0×77f50000 - 0×77ffb000 C:\WINDOWS\system32\ADVAPI32.dll
    0×77db0000 - 0×77e42000 C:\WINDOWS\system32\RPCRT4.dll
    0×77f20000 - 0×77f31000 C:\WINDOWS\system32\Secur32.dll
    0×7e360000 - 0×7e3f0000 C:\WINDOWS\system32\USER32.dll
    0×77e50000 - 0×77e97000 C:\WINDOWS\system32\GDI32.dll
    0×77bf0000 - 0×77c48000 C:\WINDOWS\system32\MSVCRT.dll
    0×6d6e0000 - 0×6d874000 C:\Arquivos de programas\CVRDPVI\Oracle JDeveloper 10.1.3.1.0\jdk\jre\bin\client\jvm.dll
    0×76b20000 - 0×76b4e000 C:\WINDOWS\system32\WINMM.dll
    0×6d2f0000 - 0×6d2f8000 C:\Arquivos de programas\CVRDPVI\Oracle JDeveloper 10.1.3.1.0\jdk\jre\bin\hpi.dll
    0×76bd0000 - 0×76bdb000 C:\WINDOWS\system32\PSAPI.DLL
    0×6d6b0000 - 0×6d6bc000 C:\Arquivos de programas\CVRDPVI\Oracle JDeveloper 10.1.3.1.0\jdk\jre\bin\verify.dll
    0×6d370000 - 0×6d38d000 C:\Arquivos de programas\CVRDPVI\Oracle JDeveloper 10.1.3.1.0\jdk\jre\bin\java.dll
    0×6d6d0000 - 0×6d6df000 C:\Arquivos de programas\CVRDPVI\Oracle JDeveloper 10.1.3.1.0\jdk\jre\bin\zip.dll
    0×10000000 - 0×10017000 C:\Documents and Settings\C0072652\Configurações locais\Temp\jna22446.tmp

    VM Arguments:
    java_command: model.login.ExecutaLogin2
    Launcher Type: SUN_STANDARD

    Environment Variables:
    CLASSPATH=C:\oracle\dev9i\jlib\bigraphbean.jar;c:\oracle\dev9i\jlib\LW_PfjBean.jar;c:\oracle\dev9i\jlib\bigraphbean-nls.zip;C:\Arquivos de Programas\cvrdpvi\tibco\tibrv\LIB\tibrvj.jar
    PATH=C:\oracle\ora92\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;c:\tibco\tibrv\bin;C:\TIBCO\tra\1.0\bin;C:\arquiv~1\Oracle\jre\1.1.8\bin;C:\arquiv~1\IBM\Trace Facility\;C:\arquiv~1\CVRDPVI\IBM\Personal Communications\;C:\arquiv~1\CVRDPVI\IBM\Person~1\;C:\arquiv~1\CVRDPVI\Microsoft Visual Studio\VC98\Bin;C:\arquiv~1\CVRDPVI\Microsoft Visual Studio\Common\MSDev98\Bin;c:\cool\gen;g:\cmgr95;C:\lotus\notes\;C:\lotus\notes\data\;C:\arquiv~1\Oracle\jre\1.1.8\bin;C:\TIBCO\TIBRV\BIN;C:\arquiv~1\InstallShield\AdminStudio\5.0\Common;C:\oracle\dev9i\jdk\jre\bin;C:\oracle\dev9i\jdk\jre\bin\classic;C:\oracle\dev9i\jlib;C:\oracle\dev9i\bin;C:\oracle\ORADEV9I\jlib;C:\arquiv~1\Oracle\jre\1.3.1\bin;C:\arquiv~1\Oracle\jre\1.1.8\bin;C:\TIBCO\TIBRV\bin;C:\arquiv~1\cvrdpvi\tibco\tibrv\BIN;C:\arquiv~1\InstallShield\AdminStudio\5.0\Common;C:\arquiv~1\CVRDPVI\Rational\ClearCase\bin;C:\Arquivos de progr;C:\arquiv~1\CVRDPVI\Rational\common;:\WINDOWS\system32;:\WINDOWS;:\WINDOWS\System32\Wbem;C:\Arquivos de programas\InstallShield\AdminStudio\5.0\Common;C:\Arquivos de programas\Oracle\jre\1.1.8\bin;C:\Arquivos de programas\IBM\Trace Facility;C:\Arquivos de programas\CVRDPVI\IBM\Personal Communications
    USERNAME=c0072652
    OS=Windows_NT
    PROCESSOR_IDENTIFIER=x86 Family 15 Model 2 Stepping 7, GenuineIntel

    ————— S Y S T E M —————

    OS: Windows XP Build 2600 Service Pack 2

    CPU:total 1 family 15, cmov, cx8, fxsr, mmx, sse, sse2, ht

    Memory: 4k page, physical 1039856k(352000k free), swap 2504164k(2012128k free)

    vm_info: Java HotSpot(TM) Client VM (1.5.0_06-b05) for windows-x86, built on Nov 10 2005 11:12:14 by “java_re” with MS VC++ 6.0

    ——————————————————————————————–

    Você sabe o que pode ser?

    Reply to this comment
  3. |

    Afim de obter os comentários desta entrada.

    Cumprimentos,

    Marcos de Sousa

    Reply to this comment
  4. |

    Cara seu que o post é meio antigo, mas realmente tenho que postar meu comentário.

    Eu já estava desesperado para implementar uma dll, já estava ficando assustado com o JNI e ao ler esse artigo percebi que vai ser tão fácil quanto programar em java, porque para mim Java é mais fácil que tudo. Nasci no Java morro com Java.

    Vlw mesmo, isso vai me ajudar um bocado….

    meu novo ídolo uahuaua.

    Reply to this comment
  5. |

    import com.sun.jna.Library;
    interface Exit extends Library {
    public int ExitWindowsEx(int uFlags, int dwReason);
    }

    import com.sun.jna.Native;
    public class ExitTeste {
    public static void main(String[] args) {
    Exit e = (Exit)Native.loadLibrary(”user32″, Exit.class);
    int i = e.ExitWindowsEx(0,0);
    System.out.println(i);

    Eu copiei o código do Fábio (lá nos primeiros posts) e não está rodando.
    Existe um erro nesta linha aqui:

    import com.sun.jna.Native;

    O erro é: “class” or “interface” expected.

    Alguém sabe me dizer o q fazer?
    Obs: Este é o único erro que aparece nas linhas de código.

    Reply to this comment
  6. |

    M’aidez pela mensagem de erro, parece que o jar do jna não esta no classpath da tua aplicação.

    Reply to this comment
  7. |

    Boa tarde Urubatan e pessoal que participa do blog.
    Questão é a seguinte:
    Qdo vc fez o exemplo Urubatan, vc usou o parâmetro whatToSay que era do tipo char* (em C), e depois passou para String (segunda consta na documentação da JNA). O que eu gostaria de saber é: E no caso de eu ter um parâmetro que é de um tipo não primitivo? Um tipo criado pelo próprio desenvolvedor da dll, como eu faço para usar este parâmetro lá no código em java? Como eu passo o tipo destes parâmetros que não são primitivos?

    Me desculpe se fui muito extenso na questão ou mesmo se não fui claro.

    Um grande abraço.

    Reply to this comment
  8. |

    tem uma interface do JNA que deve ser implementada para definir uma struct do C

    Reply to this comment
  9. |

    Só para salientar, eu gostaria de usar o método:

    EnviaBeep(pThreadIndex: Integer; pBeep: SBeep): WordBool (feito em delphi)

    que está uma dll nossa (a qual eu já coloquei no system32 do windows).

    Conseguindo usar este método (aprendendo o princípio), eu creio q o restante será na mesma linha de raciocínio.

    Abraços galera.

    “Ensinar é aprender 2 vezes”

    Reply to this comment
  10. |

    Será que alguém pode fazer um pequeno exemplo de como podemos usar estes métodos que tem parâmetros que não são do tipo primitivo? Pode ser Urubatan?

    Abraços

    Reply to this comment
  11. |

    Será que alguém pode fazer um pequeno exemplo de como podemos usar estes métodos que tem parâmetros que não são do tipo primitivo? Pode ser Urubatan?

    [aB[R]Aç[[o]]s]

    Reply to this comment
  12. |

    Olá Urubatan. Muito bom o artigo.

    Tentei reproduzir o exemplo, mas sem sucesso. recebi o seguonte erro:

    Exception in thread “main” java.lang.UnsatisfiedLinkError: Error looking up function ’solveEq2′: /usr/lib/libequationsolve.so: undefined symbol: solveEq2

    Ele acha a biblioteca mas não acha a função solveEq2. Achei que fosse um erro na biblioteca e por isso fiz um teste com um programa C++ e a função é encontrada sem problemas.

    A lib libequationsolve.so e equationsolve.h estão nos diretórios /usr/li e /usr/include. O jna.jar está no projeto do eclipse e é reconhecido.

    Bem. Não sei mas o que pode estar errado. Agradeço qualquer ajuda.

    Reply to this comment
  13. |

    Olá a todos.

    Consegui resolver meu problema anterior. No entato o único modo que encontrei fez o código ficar um pouco mais complexo do que o do artigo. Tive que fornecer um mapeamento entre os nomes que estão na lib e os nomes da interface. O código ficou assim:

    ———————————–
    import com.sun.jna.Library;

    public interface JEquationSolve extends Library {
    public double solveEq2(double a, double b, double c, double x);
    public double[] rootEq2(double a, double b, double c, double x);
    }

    ———————————–
    import java.util.HashMap;

    import com.sun.jna.Native;

    public class JEquationSolveTeste {
    protected static HashMap methods;
    protected static JEquationSolve jequation;

    static {
    methods = new HashMap();

    methods.put(”solveEq2″, “_Z8solveEq2dddd”);
    methods.put(”rootEq2″, “_Z7rootEq2dddd”);

    jequation = (JEquationSolve) Native.loadLibrary(”equationsolve”, JEquationSolve.class, methods);
    }

    public static void main(String args[]){
    double value = jequation.solveEq2(1, 0, 0, 3);

    System.out.println(value);
    }
    }

    Reply to this comment
  14. |

    olá, tenho o seguinte código em c, que lisa as janelas abertas:

    int main ()
    {
    char vetor[50][256];
    int i = 0;
    HWND janela = NULL;

    janela = GetDesktopWindow();
    janela = GetWindow(janela, GW_CHILD);

    while(janela != NULL){

    if(IsWindowVisible(janela) && !IsIconic(janela)){
    SendMessage(janela,WM_GETTEXT,256,(LPARAM)vetor[i]);
    printf(”%s\n”, vetor[i]);
    i++;
    }

    janela = GetWindow(janela, GW_HWNDNEXT);

    }

    return 0;
    }

    ele tá imprimindo os nomes no console, mas eu queria que ele retornasse um vetor com os nomes das janelas, via JNA, pra uma aplicação em java. como ficaria o código em c e em java? até agora eu nao consegui fazer nem um exemplo com JNA, pode colocar o código? obrigado!

    Reply to this comment
  15. |

    Olá Urubatan, muito obrigado.

    Reply to this comment
  16. |

    Urubatan, simplesmente muito obrigado.

    Reply to this comment
  17. |

    rodou perfeito!
    porém, a dll que tenho q manipular acredito ser feita em delphi e há alguns métodos onde há passagem de parametros por referencia (string).
    Ou seja, o parametro em questao é alterado pela dll, servindo como retorno.
    Mas em java não há passagem por referencia e nao consigo pegar o valor de retorno desta variavel.

    alguem tem alguma idéia?

    valeu!
    Gustavo.

    Reply to this comment
  18. |

    rodou perfeito!
    porém, a dll que tenho q manipular acredito ser feita em delphi e há alguns métodos onde há passagem de parametros por referencia (string).
    Ou seja, o parametro em questao é alterado pela dll, servindo como retorno.
    Mas em java não há passagem por referencia e nao consigo pegar o valor de retorno desta variavel.

    alguem tem alguma idéia?

    valeu!!
    Gustavo.

    Reply to this comment
  19. |

    eu consegui fazer funcionar redondinho só que notei que quando a DLL possui uma função que tem o tipo LPCTSTR eu não consigo faze-la funcionar…

    INT LlSetOptionString(HLLJOB hJob, INT nMode, LPCTSTR pszValue);

    algum comentario sobre isto?

    Dario

    Reply to this comment
  20. |

    Amigo desculpe se for muita ignorancia da minha parte mais poderia me ajudar? No meu caso deu esse seguinte erro:

    Exception in thread “main” java.lang.UnsatisfiedLinkError: Unable to load library ‘testejna’: Não foi possível encontrar o módulo especificado.

    at com.sun.jna.NativeLibrary.loadLibrary(NativeLibrary.java:114)
    at com.sun.jna.NativeLibrary.getInstance(NativeLibrary.java:157)
    at com.sun.jna.Library$Handler.(Library.java:123)
    at com.sun.jna.Native.loadLibrary(Native.java:259)
    at com.sun.jna.Native.loadLibrary(Native.java:245)
    at TesteJNA.main(TesteJNA.java:6)

    Reply to this comment
  21. |

    Amigo desculpe se for ignorância da minha parte, mas no meu caso deu esse seguinte erro:

    Exception in thread “main” java.lang.UnsatisfiedLinkError: Unable to load library ‘testejna’: Não foi possível encontrar o módulo especificado.

    at com.sun.jna.NativeLibrary.loadLibrary(NativeLibrary.java:114)
    at com.sun.jna.NativeLibrary.getInstance(NativeLibrary.java:157)
    at com.sun.jna.Library$Handler.(Library.java:123)
    at com.sun.jna.Native.loadLibrary(Native.java:259)
    at com.sun.jna.Native.loadLibrary(Native.java:245)
    at TesteJNA.main(TesteJNA.java:6)

    Pode me ajudar? Obrigado!

    Reply to this comment
  22. |

    Ola,
    Tenta copiar a sua dll para o diretorio Windows\system32
    []s

    Reply to this comment
  23. |

    Cara, tenho que fazer meu TCC utilizando uma porta paralela para controle de um motor de passo, agora com JNA vai ficar muito mais fácil.

    Parabéns pelo artigo, é excelente, e continue postando mais outros artigos como este.

    Reply to this comment
  24. |

    Há um tempo atrás tive que utilizar JNI pelo amor de deus!!! se tivesse encontrado o arquivo uns meses atrás hahaha , mas parabéns está muito bom seu artigo, adquiriu um leitor assíduo agora.
    abraços.

    Reply to this comment
  25. |

    Olá Urubatan,

    O JNA trabalha com multi-threads ou apenas single-thread???

    Reply to this comment
  26. |

    Urubatan, valeu pelo tutorial ajudou muito no meu projeto de graduação.

    Uma dica para quem utiliza dll em feita em Delphi declarem em as variáveis String com PChar que garanto que funciona.

    Abraços

    Wanderson

    Reply to this comment
  27. |

    Excelente!

    No entanto, não sei se já foi perguntado isso, mas como faço para utilizar uma .lib ou dlls de terceiros em uma aplicação java usando o JNA?

    Muito obrigado e parabéns!

    Reply to this comment
  28. |

    é só usar o JNA normalmente, ele foi feito para isto …
    cria a interface correspondente a tua dll e pronto.
    .lib é impossível, elas são apenas grupos de arquivos .obj não linkados normalmente do C++ e dependentes de compilador

    Reply to this comment
  29. |

    Olá, eu obtendo o seguinte erro quando executo seu exemplo (já coloquei a dll na pasta system32):
    Exception in thread “main” java.lang.UnsatisfiedLinkError: Error looking up function ‘librarymethod’: Não foi possível encontrar o procedimento especificado.

    at com.sun.jna.Function.(Function.java:129)
    at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:232)
    at com.sun.jna.Library$Handler.invoke(Library.java:191)
    at $Proxy0.librarymethod(Unknown Source)
    at pacote.TestandoJNA.main(TestandoJNA.java:18)
    Java Result: 1

    O que eu faço? Muito obrigado, ate mais!

    Reply to this comment
  30. |

    Olá novamente.

    Tenho um problema e quem sabe você pode me ajudar, pode ser?

    Tenho duas DLLs para programar uma placa de processamento de sinais digitais. Uma de baixo nível e outra de alto nível (os detalhes sao irrelevantes). Bom, a biblioteca de alto nível utiliza funçoes da biblioteca de baixo nível. Coloquei as duas DLLs no mesmo diretório e carregei em minha aplicaçao Java somente a biblioteca de alto nível. Obtenho entao o seguinte erro. O que vc me aconselha? A DLL de alto nível (que eu chamo no meu codigo e: SRanger_HL.dd e a de baixo nível é a SRanger.dll). Quando chamo a DLL SRanger_HL.dll, ele reporta um erro em SRanger.dll. O que fazer?

    #
    # An unexpected error has been detected by Java Runtime Environment:
    #
    # EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0×0afd113d, pid=1964, tid=2528
    #
    # Java VM: Java HotSpot(TM) Client VM (1.6.0_02-b06 mixed mode)
    # Problematic frame:
    # C [SRanger.dll+0x113d]
    #
    # An error report file with more information is saved as hs_err_pid1964.log
    #
    # If you would like to submit a bug report, please visit:
    # http://java.sun.com/webapps/bugreport/crash.jsp
    #
    Java Result: 1

    Reply to this comment
  31. |

    Alguma sugestão?

    Reply to this comment
  32. |

    Olá, estou tendo o mesmo problema apresentado no comentário de Jorge Santos. Já coloquei as DLLs no mesmo diretório e não funcionou. Não tenho como recompilar as dlls por que são fornecidas por terceiros. Se alguém puder me ajudar, ficaria muito agradecido. Se nao puderem, ao menos postem isso no blog, por favor. Aguardo retorno e até mais!

    Reply to this comment
  33. |

    Boa tarde… como faria para utilizar as funções dessa biblioteca C em JAVA usando JNA? Minhas dúvidas maiores é em relação a integração da dll e declaração das funções da mesma em JAVA.

    #ifndef __FIRMSYS_API_H__
    #define __FIRMSYS_API_H__

    #ifdef FIRMSYS_API_EXPORTS
    #define FIRMSYS_API_API __declspec(dllexport)
    #else
    #define FIRMSYS_API_API __declspec(dllimport)
    #endif

    #define RESPONSE 0 // Response
    #define ERROR_RESPONSE 1 // Error Code Response
    #define START_RESPONSE 2 // Start Code Response
    #define NOT_RESPONSE 3 // Not Response

    enum FS_CARDTYPE
    {
    TYPE_TI,
    TYPE_PHILIPS
    };

    enum FS_BR
    {
    BR_9600 = 0×67,
    BR_14400 = 0×44,
    BR_19200 = 0×33,
    BR_38400 = 0×19,
    BR_57600 = 0×10,
    BR_115200 = 0×08
    };

    enum FS_BZ
    {
    BZ_OFF = 0×00,
    BZ_ON = 0×01
    };

    struct FS_UID
    {
    BYTE digit[8];
    };

    struct FS_WD
    {
    BYTE digit[4];
    };

    struct FS_BD
    {
    BYTE digit[4];
    };

    struct FS_Version
    {
    BYTE digit[3];
    };

    struct FS_Send
    {
    BYTE digit[20];
    };

    struct FS_SYSTEMINFORMATION
    {
    BYTE FG;
    BYTE IF;
    FS_UID uid;
    BYTE DSFID;
    BYTE AFI;
    BYTE BSN;
    BYTE NBB;
    BYTE IMC;
    };

    extern “C” FIRMSYS_API_API BOOL WINAPI FS_Open(WORD portNum = 0, DWORD baudRate = CBR_38400);
    extern “C” FIRMSYS_API_API void WINAPI FS_Close();
    extern “C” FIRMSYS_API_API int WINAPI FS_ResetToReady();
    extern “C” FIRMSYS_API_API int WINAPI FS_RFPowerOn();
    extern “C” FIRMSYS_API_API int WINAPI FS_RFPowerOff();
    extern “C” FIRMSYS_API_API int WINAPI FS_GetSystemInformation(FS_SYSTEMINFORMATION *systeminformation);
    extern “C” FIRMSYS_API_API int WINAPI FS_LockAFI(FS_CARDTYPE cardType);
    extern “C” FIRMSYS_API_API int WINAPI FS_LockDSFID(FS_CARDTYPE cardType);
    extern “C” FIRMSYS_API_API int WINAPI FS_ReaderVersion(FS_Version *version);
    extern “C” FIRMSYS_API_API int WINAPI FS_Inventory(FS_SYSTEMINFORMATION *systeminformation);
    extern “C” FIRMSYS_API_API int WINAPI FS_StayQuiet(FS_UID *uid);
    extern “C” FIRMSYS_API_API int WINAPI FS_Anticollision(FS_SYSTEMINFORMATION *systeminformation, int *nTagCount);
    extern “C” FIRMSYS_API_API int WINAPI FS_ISO14443A(FS_UID *uid);
    extern “C” FIRMSYS_API_API int WINAPI FS_Select(FS_UID *uid);
    extern “C” FIRMSYS_API_API int WINAPI FS_WriteSingleBlock(FS_CARDTYPE cardType, BYTE BN, FS_WD *WD);
    extern “C” FIRMSYS_API_API int WINAPI FS_LockBlock(FS_CARDTYPE cardType, BYTE BN);
    extern “C” FIRMSYS_API_API int WINAPI FS_GetBlockSecurityStatus(BYTE BN, BYTE *BSS);
    extern “C” FIRMSYS_API_API int WINAPI FS_WriteReaderRegister(FS_BR BR, FS_BZ BZ);
    extern “C” FIRMSYS_API_API int WINAPI FS_ReadReaderRegister(FS_BR *BR, FS_BZ *BZ);
    extern “C” FIRMSYS_API_API int WINAPI FS_WriteDSFID(FS_CARDTYPE cardType, BYTE DSFID);
    extern “C” FIRMSYS_API_API int WINAPI FS_WriteAFI(FS_CARDTYPE cardType, BYTE AFI);
    extern “C” FIRMSYS_API_API int WINAPI FS_ReadSingleBlock(BYTE BN, FS_BD *BD);
    extern “C” FIRMSYS_API_API int WINAPI FS_ReadyToReader();

    Fico agradecido quem puder me ajudar. Um abraço.
    extern “C” FIRMSYS_API_API int WINAPI FS_Stop();
    extern “C” FIRMSYS_API_API int WINAPI FS_ContinueMode();
    extern “C” FIRMSYS_API_API int WINAPI FS_UIDGetBlockSecurityStatus(FS_UID *uid, BYTE BN, BYTE *BSS);
    extern “C” FIRMSYS_API_API int WINAPI FS_UIDGetSystemInformation(FS_UID *uid, FS_SYSTEMINFORMATION *systeminformation);
    extern “C” FIRMSYS_API_API int WINAPI FS_UIDLockDSFID(FS_CARDTYPE cardType, FS_UID *uid);
    extern “C” FIRMSYS_API_API int WINAPI FS_UIDWriteDSFID(FS_CARDTYPE cardType, FS_UID *uid, BYTE DSFID);
    extern “C” FIRMSYS_API_API int WINAPI FS_UIDLockAFI(FS_CARDTYPE cardType, FS_UID *uid);
    extern “C” FIRMSYS_API_API int WINAPI FS_UIDWriteAFI(FS_CARDTYPE cardType, FS_UID *uid, BYTE AFI);
    extern “C” FIRMSYS_API_API int WINAPI FS_UIDResetToReady(FS_UID *uid);
    extern “C” FIRMSYS_API_API int WINAPI FS_UIDLockBlock(FS_CARDTYPE cardType, FS_UID *uid, BYTE BN);
    extern “C” FIRMSYS_API_API int WINAPI FS_UIDWriteSingleBlock(FS_CARDTYPE cardType,FS_UID *uid, BYTE BN, FS_WD *WD);
    extern “C” FIRMSYS_API_API int WINAPI FS_UIDReadSingleBlock(FS_UID *uid, BYTE BN, FS_BD *BD);
    extern “C” FIRMSYS_API_API int WINAPI FS_Command(FS_Send *bySend, int *nRcvSize, BYTE *byRcv);
    extern “C” FIRMSYS_API_API int WINAPI FS_Receive(int *nRcvSize, BYTE *byRcv);
    #endif //

    Reply to this comment
  34. |

    Minha interface em java ficou assim. Mas não da certo.

    /*
    * To change this template, choose Tools | Templates
    * and open the template in the editor.
    */

    package rfid_kit_jna;
    /**
    *
    * @author LenardoCS
    */
    import com.sun.jna.Library;
    import com.sun.jna.Structure;
    import com.sun.jna.ptr.PointerByReference;

    public interface Firmsys extends Library{
    //public void librarymethod(String whatToSay);

    final int RESPONSE = 0; // Response
    final int ERROR_RESPONSE = 1; // Error Code Response
    final int START_RESPONSE = 2; // Start Code Response
    final int NOT_RESPONSE = 3; // Not Response

    enum FS_CARDTYPE {
    TYPE_TI,
    TYPE_PHILIPS
    }

    enum FS_BR {
    BR_9600(0×67),
    BR_14400(0×44),
    BR_19200(0×33),
    BR_38400(0×19),
    BR_57600(0×10),
    BR_115200(0×08);

    private int bit;

    FS_BR(int bitNumber)
    {
    bit = bitNumber;
    }

    public int getBitNumber()
    {
    return(bit);
    }
    }

    enum FS_BZ {
    BZ_OFF(0×00),
    BZ_ON(0×01);

    private int bit;

    FS_BZ(int bitNumber)
    {
    bit = bitNumber;
    }

    public int getBitNumber()
    {
    return(bit);
    }
    };

    public static class FS_UID extends Structure {
    byte[] uid = new byte[8];
    }

    public static class FS_WD extends Structure {
    byte[] uid = new byte[4];
    }

    public static class FS_BD extends Structure {
    byte[] uid = new byte[4];
    }

    public static class FS_Version extends Structure {
    byte[] uid = new byte[3];
    }

    public static class FS_Send extends Structure {
    byte[] uid = new byte[20];
    }

    public static class FS_SYSTEMINFORMATION extends Structure {
    byte FG;
    byte IF;
    FS_UID uid;
    byte DSFID;
    byte AFI;
    byte BSN;
    byte NBB;
    byte IMC;
    }

    public boolean FS_Open(int portNum, FS_BR baudRate);
    public void FS_Close();
    public int FS_ResetToReady();
    public int FS_RFPowerOn();
    public int FS_RFPowerOff();
    public int FS_GetSystemInformation(FS_SYSTEMINFORMATION systeminformation);
    public int FS_LockAFI(FS_CARDTYPE cardType);
    public int FS_LockDSFID(FS_CARDTYPE cardType);

    //public int FS_ReaderVersion(FS_Version version);
    // Quanto a ponteiros é desta forma?
    public int FS_ReaderVersion(PointerByReference version);

    public int FS_Inventory(FS_SYSTEMINFORMATION systeminformation);
    public int FS_StayQuiet(FS_UID uid);
    public int FS_Anticollision(FS_SYSTEMINFORMATION systeminformation, int nTagCount);
    public int FS_ISO14443A(FS_UID uid);
    public int FS_Select(FS_UID uid);
    public int FS_WriteSingleBlock(FS_CARDTYPE cardType, byte BN, FS_WD WD);
    public int FS_LockBlock(FS_CARDTYPE cardType, byte BN);
    public int FS_GetBlockSecurityStatus(byte BN, byte BSS);
    public int FS_WriteReaderRegister(FS_BR BR, FS_BZ BZ);
    public int FS_ReadReaderRegister(FS_BR BR, FS_BZ BZ);
    public int FS_WriteDSFID(FS_CARDTYPE cardType, byte DSFID);
    public int FS_WriteAFI(FS_CARDTYPE cardType, byte AFI);
    public int FS_ReadSingleBlock(byte BN, FS_BD BD);
    public int FS_ReadyToReader();
    public int FS_Stop();
    public int FS_ContinueMode();
    public int FS_UIDGetBlockSecurityStatus(FS_UID uid, byte BN, byte BSS);
    public int FS_UIDGetSystemInformation(FS_UID uid, FS_SYSTEMINFORMATION systeminformation);
    public int FS_UIDLockDSFID(FS_CARDTYPE cardType, FS_UID uid);
    public int FS_UIDWriteDSFID(FS_CARDTYPE cardType, FS_UID uid, byte DSFID);
    public int FS_UIDLockAFI(FS_CARDTYPE cardType, FS_UID uid);
    public int FS_UIDWriteAFI(FS_CARDTYPE cardType, FS_UID uid, byte AFI);
    public int FS_UIDResetToReady(FS_UID uid);
    public int FS_UIDLockBlock(FS_CARDTYPE cardType, FS_UID uid, byte BN);
    public int FS_UIDWriteSingleBlock(FS_CARDTYPE cardType,FS_UID uid, byte BN, FS_WD WD);
    public int FS_UIDReadSingleBlock(FS_UID uid, byte BN, FS_BD BD);
    public int FS_Command(FS_Send bySend, int nRcvSize, byte byRcv);
    public int FS_Receive(int nRcvSize, byte byRcv);

    }

    Reply to this comment
  35. |

    Minha classe principal ficou assim, mas só estou chamando dois métodos… alguém teria uma solução. Ficaria muito grato. Valeu

    /*
    * To change this template, choose Tools | Templates
    * and open the template in the editor.
    */

    package rfid_kit_jna;

    import com.sun.jna.Native;
    import com.sun.jna.ptr.PointerByReference;
    import com.sun.jna.Pointer;
    import javax.swing.JOptionPane;

    /**
    *
    * @author LenardoCS
    */
    public class Main {

    /**
    * @param args the command line arguments
    */
    public static void main(String[] args) {
    //lib.librarymethod(”Java Rocks”);

    System.setProperty(”jna.library.path”, “\\src\\Firmsys”);

    Firmsys lib = (Firmsys) Native.loadLibrary(”FirmSYS”, Firmsys.class);

    lib.FS_Open(0, Firmsys.FS_BR.BR_38400);

    PointerByReference version = new PointerByReference();
    lib.FS_ReaderVersion(version);
    Pointer p = version.getValue();
    JOptionPane.showMessageDialog(null, p.getString(0));

    }

    }

    Reply to this comment
  36. |

    Cara sua interface em java esta errada. Em java uma interface não possui métodos implementados. Só o prototipo dos métodos.Sem chaves nem nada.
    O erro inicial é esse!
    Oura coisa importante é o seguinte. As mesmas carateristicas das funções da dll devem estar presentes na interface. Inclusive a nomenclatura das funções. Lógico que levando em conta os tipos primitivos correspondentes as da dll só que em java!

    Exemplo se na dll tem a seguinte função teste(int x, char* y); na inerface em java vc coloca teste(int x, String y);
    Pra parametros primitivos é mais fácil. O problema é quado a função da dll tem como parametro um tipo originado de uma struct. Seu não me engano a é possivel uma classe java se um struct. Não precisei usar uma dll com struct em parametros das funções. Mas isso é muito importante. Vou dar uma olha e fazer uns testes aqui!

    Reply to this comment
  37. |

    Lenardo olha o exemplo de um interface para as funções de uma .dll de comunicação USB.

    import com.sun.jna.Library;
    public interface MinhaLibrary extends Library {
    public int _MPUSBGetDLLVersion();
    public int _MPUSBGetDeviceCount(String pVID_PID);
    public int _MPUSBOpen(int instance, String pVID_PID, String pEP, int dwDir, int dwReserved);
    public int _MPUSBRead(int iHandle, byte pData[], int dwLen, int pLength, int dwMilliseconds);
    public int _MPUSBWrite(int iHandle, byte pData[], int dwLen, int pLength, int dwMilliseconds);
    public boolean _MPUSBClose(int iHandle);
    }

    Essas funções que vc pode ver ai estão exatamente da mesma forma dentro da dll. Veja que não existe implementação alguma nas funções. Só o protótipo!

    Reply to this comment
  38. |

    Com algumas alterações na minha interface consegui, eu acho, conectar com a leitora RFID utilizando a função dll FS_Open(…); Isto porque a mesma retorna true quando executada, porém as demais funções que trabalahm com ponteiros na dll, mesmo mapeando para JAVA não funcionam. Gostaria, se possível que vcs me explicassem onde eu devo declarar as classes que são structures e como mapear os métodos em JAVA que possuem ponteiros??

    Me desculpem pela ignorância, mas eu só queria explicar que isto tudo que tô fazendo é para que eu possa implementar o meu projeto de monografia, desenvolvendo uma aplicação para um kit de RFID (Rádio Frequencia) que adquiri e o mesmo só fornece a dll mencionada nos posts anteriores.

    Um abraço, e ficarei aguardando respostas. Valeu.

    Reply to this comment
  39. |

    Bom dia a todos, ainda não consegui solucionar os problemas de mapeamento. Se aluém souber como faço para criar um ponteiro (referência) para uma classe que herda structure, por exemplo, na structure abaixo, por favor, me comunica e coloca um exemplo aqui. Um abraço.

    import com.sun.jna.Structure;

    /**
    *
    * @author LenardoCS
    */

    public class FS_Version extends Structure {
    public byte[] digit = new byte[3];
    }

    Reply to this comment
  40. |

    Leonardo, da uma olhada na documentação do JNA, tem exemplos disto la.

    Reply to this comment
  41. |

    Olá Urubatan!!! meu problema é o seguinte: Eu desenvolvi uma aplicação web para uma DLL que faz reconhecimento de STROKE, bem, com a DLL no Windows ele tah funcionando certinho, mas o cara compilou o código em um .SO para rodar no Linux, mas não funciona de jeito nenhum, no windows eu coloco a DLL numa pasta do meu projeto e dou um System.setProperty(”jna.library.path”, caminho da pasta); e ele funciona, mas no Linux não, vc tem uma idéia do que possa ser?

    Reply to this comment

Leave a Comment