Twain JNA

9 respostas
F

Bom dia.

Estou usando JNA (https://jna.dev.java.net/) para tentar acessar o twain…

Basicamente é a mesma coisa que acessar via JNI (até porque é assim que o JNA acessa), mas o JNAerator (http://code.google.com/p/jnaerator/) já cria toda a estrutura de tipos e acesso às funções c que eu preciso, sem ter que me preocupar em criar o JNI na mão.

O problema é… quando eu tento carregar o twain.dll, recebo a seguinte mensagem de erro (imagino que o twain.dll seja 16 bits):

Loading twain.dll failed (java.lang.UnsatisfiedLinkError: twain.dll: Can’t load this .dll (machine code=0x130) on a IA 32-bit platform)

E quando eu carrego o twain_32.dll e tento acessar uma função (DS_Entry) recebo o seguinte erro:

java.lang.UnsatisfiedLinkError: Error looking up ‘DS_Entry’: Não foi possível encontrar o procedimento especificado.

O JNAerator usa o header do c para criar (em anexo na conversa) as estruturas para o Java… o único detalhe é que o header é da versão 2.1 do twain, as dlls eu não sei.

De qualquer forma a assinatura das duas funções da biblioteca do twain é sempre a mesma, então para eu obter um simples acesso à função não deveria ter problemas…

Por gentileza, qualquer ajuda com o acesso às funções do Twain via Java é bem-vinda.

9 Respostas

J

Fox McCloud:
Bom dia.

Estou usando JNA (https://jna.dev.java.net/) para tentar acessar o twain…

Basicamente é a mesma coisa que acessar via JNI (até porque é assim que o JNA acessa), mas o JNAerator (http://code.google.com/p/jnaerator/) já cria toda a estrutura de tipos e acesso às funções c que eu preciso, sem ter que me preocupar em criar o JNI na mão.

O problema é… quando eu tento carregar o twain.dll, recebo a seguinte mensagem de erro (imagino que o twain.dll seja 16 bits):

Loading twain.dll failed (java.lang.UnsatisfiedLinkError: twain.dll: Can’t load this .dll (machine code=0x130) on a IA 32-bit platform)

E quando eu carrego o twain_32.dll e tento acessar uma função (DS_Entry) recebo o seguinte erro:

java.lang.UnsatisfiedLinkError: Error looking up ‘DS_Entry’: Não foi possível encontrar o procedimento especificado.

O JNAerator usa o header do c para criar (em anexo na conversa) as estruturas para o Java… o único detalhe é que o header é da versão 2.1 do twain, as dlls eu não sei.

De qualquer forma a assinatura das duas funções da biblioteca do twain é sempre a mesma, então para eu obter um simples acesso à função não deveria ter problemas…

Por gentileza, qualquer ajuda com o acesso às funções do Twain via Java é bem-vinda.

esse erro acontece devido a inexistência da função que é acessada, ou no caso o nome pode estar errado. Provavelmente você vai precisar checar o código fonte.
Verifique também se a dll está no path correto.

F

juliocbq:
esse erro acontece devido a inexistência da função que é acessada, ou no caso o nome pode estar errado. Provavelmente você vai precisar checar o código fonte.
Verifique também se a dll está no path correto.

Então… o path está correto, eu sei que o twain.dll possui essa função, mas ele é 16 bit e não carrega em um Windows 32 bit. Entretanto carregando o twain_32.dll o carregamento da dll ocorre normalmente, mas a aplicação diz que a função não existe…

=P

J

Fox McCloud:
juliocbq:
esse erro acontece devido a inexistência da função que é acessada, ou no caso o nome pode estar errado. Provavelmente você vai precisar checar o código fonte.
Verifique também se a dll está no path correto.

Então… o path está correto, eu sei que o twain.dll possui essa função, mas ele é 16 bit e não carrega em um Windows 32 bit. Entretanto carregando o twain_32.dll o carregamento da dll ocorre normalmente, mas a aplicação diz que a função não existe…

=P

Vai precisar do codigo fonte para checar o nome da função e como ela está sendo exportada( se stdcall ou cdecl). Isso pode gerar esse tipo de problema.

F
juliocbq:
Vai precisar do codigo fonte para checar o nome da função e como ela está sendo exportada( se stdcall ou cdecl). Isso pode gerar esse tipo de problema.
Bom... no twain.h está assim:
extern "C" {
#endif  /* __cplusplus */

#ifdef TWH_CMP_MSC

  TW_UINT16 FAR PASCAL DS_Entry(pTW_IDENTITY pOrigin,
                                TW_UINT32 DG, 
                                TW_UINT16 DAT, 
                                TW_UINT16 MSG,
                                TW_MEMREF pData);

  typedef TW_UINT16 (FAR PASCAL *DSENTRYPROC)(pTW_IDENTITY pOrigin,
                                              TW_UINT32 DG,
                                              TW_UINT16 DAT,
                                              TW_UINT16 MSG,
                                              TW_MEMREF pData);

#else

  FAR PASCAL TW_UINT16 DS_Entry(pTW_IDENTITY pOrigin,
                                TW_UINT32 DG,
                                TW_UINT16 DAT,
                                TW_UINT16 MSG,
                                TW_MEMREF pData);

  typedef TW_UINT16 (*DSENTRYPROC)(pTW_IDENTITY pOrigin,
                                   TW_UINT32 DG,
                                   TW_UINT16 DAT,
                                   TW_UINT16 MSG,
                                   TW_MEMREF pData);

#endif /* TWH_CMP_MSC */


  typedef TW_HANDLE (PASCAL *DSM_MEMALLOCATE)(TW_UINT32 _size);
  typedef void (PASCAL *DSM_MEMFREE)(TW_HANDLE _handle);
  typedef TW_MEMREF (PASCAL *DSM_MEMLOCK)(TW_HANDLE _handle);
  typedef void (PASCAL *DSM_MEMUNLOCK)(TW_HANDLE _handle);

#ifdef  __cplusplus
}
Lembrando que não tenho o fonte do driver do twain, não é possível, preciso apenas acessá-lo via JNA (JNI).
F
Ou melhor, o trecho completo da declaração da função no header:
/* Don't mangle the name "DSM_Entry" if we're compiling in C++! */
#ifdef  __cplusplus
extern "C" {
#endif  /* __cplusplus */

#ifdef TWH_CMP_MSC

  TW_UINT16 FAR PASCAL DSM_Entry( pTW_IDENTITY pOrigin,
                                  pTW_IDENTITY pDest,
                                  TW_UINT32    DG,
                                  TW_UINT16    DAT,
                                  TW_UINT16    MSG,
                                  TW_MEMREF    pData);

  typedef TW_UINT16 (FAR PASCAL *DSMENTRYPROC)(pTW_IDENTITY pOrigin,
                                               pTW_IDENTITY pDest,
                                               TW_UINT32 DG,
                                               TW_UINT16 DAT,
                                               TW_UINT16 MSG,
                                               TW_MEMREF pData);

#else

  FAR PASCAL TW_UINT16 DSM_Entry( pTW_IDENTITY pOrigin,
                                  pTW_IDENTITY pDest,
                                  TW_UINT32    DG,
                                  TW_UINT16    DAT,
                                  TW_UINT16    MSG,
                                  TW_MEMREF    pData);

  typedef TW_UINT16 (*DSMENTRYPROC)(pTW_IDENTITY pOrigin, 
                                    pTW_IDENTITY pDest,
                                    TW_UINT32 DG, 
                                    TW_UINT16 DAT, 
                                    TW_UINT16 MSG,
                                    TW_MEMREF pData);

#endif  /* TWH_CMP_MSC */

#ifdef  __cplusplus
}
#endif  /* cplusplus */

/* Don't mangle the name "DS_Entry" if we're compiling in C++! */
#ifdef  __cplusplus
extern "C" {
#endif  /* __cplusplus */

#ifdef TWH_CMP_MSC

  TW_UINT16 FAR PASCAL DS_Entry(pTW_IDENTITY pOrigin,
                                TW_UINT32 DG, 
                                TW_UINT16 DAT, 
                                TW_UINT16 MSG,
                                TW_MEMREF pData);

  typedef TW_UINT16 (FAR PASCAL *DSENTRYPROC)(pTW_IDENTITY pOrigin,
                                              TW_UINT32 DG,
                                              TW_UINT16 DAT,
                                              TW_UINT16 MSG,
                                              TW_MEMREF pData);

#else

  FAR PASCAL TW_UINT16 DS_Entry(pTW_IDENTITY pOrigin,
                                TW_UINT32 DG,
                                TW_UINT16 DAT,
                                TW_UINT16 MSG,
                                TW_MEMREF pData);

  typedef TW_UINT16 (*DSENTRYPROC)(pTW_IDENTITY pOrigin,
                                   TW_UINT32 DG,
                                   TW_UINT16 DAT,
                                   TW_UINT16 MSG,
                                   TW_MEMREF pData);

#endif /* TWH_CMP_MSC */


  typedef TW_HANDLE (PASCAL *DSM_MEMALLOCATE)(TW_UINT32 _size);
  typedef void (PASCAL *DSM_MEMFREE)(TW_HANDLE _handle);
  typedef TW_MEMREF (PASCAL *DSM_MEMLOCK)(TW_HANDLE _handle);
  typedef void (PASCAL *DSM_MEMUNLOCK)(TW_HANDLE _handle);

#ifdef  __cplusplus
}
#endif  /* __cplusplus */
J

extern “C” {

é um padrão para exportar funções de linguagem c, e não c++. Você precisa especificar o padrão correto no mapeamento java. Se é stdcall ou cdecl

dá uma lida aqui, acho que pode te ajudar, apesar de ser c#.

http://bytes.com/topic/net/answers/155407-how-setup-cdecl-callback-c-delagate

F

juliocbq:
extern “C” {

é um padrão para exportar funções de linguagem c, e não c++. Você precisa especificar o padrão correto no mapeamento java. Se é stdcall ou cdecl

dá uma lida aqui, acho que pode te ajudar, apesar de ser c#.

http://bytes.com/topic/net/answers/155407-how-setup-cdecl-callback-c-delagate


Obrigado, vou olhar sim!

Mas provavelmente o JNAerator detecta isso automaticamente… bom, como ele gera código-fonte aberto eu posso verificar e corrigir se for o caso…

Muito obrigado, sugestões extras continuam bem-vindas!

:wink:

F

Hum… olhando o header agora é que eu notei o ifdef, e vi também que OU a função DS_Entry vai estar disponível OU a função DSM_Entry vai estar disponível…

E realmente usando o twain_32.dll e chamando a função DSM_Entry a chamada foi nativamente executada… deu erro porque eu enviei tudo nulo ou zerado, só pra testar…

Então, eu creio que esse tópico está RESOLVIDO…!

Valeu!

Twain_32Library.INSTANCE.DSM_Entry(null, null, null, (short)0, (short)0, null);

Extracting jar:file:/C:/Java/Workspaces/Default/JTwain/lib/twain.jar!/libraries/win32/twain_32.dll

A fatal error has been detected by the Java Runtime Environment:

EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x48f55016, pid=1248, tid=1400

JRE version: 6.0_14-b08

Java VM: Java HotSpot™ Client VM (14.0-b16 mixed mode windows-x86 )

Problematic frame:

C [twain_32.dll+0x5016]

An error report file with more information is saved as:

C:\Java\Workspaces\Default\JTwain\hs_err_pid1248.log

If you would like to submit a bug report, please visit:

http://java.sun.com/webapps/bugreport/crash.jsp

The crash happened outside the Java Virtual Machine in native code.

See problematic frame for where to report the bug.

J

Fala galera…desenterrando um tópico aki…hehehe…

Estou usando jnaerator tbm…e a lib do twain_32… Como o Fox McCloud disse…ele cria todas as estruturas declaradas no .h do twain…então fica bem simples de trabalhar e passar para a função o que ela precisa…
Mas estou enfrentando um problema… Debugando com o visual studio a minha aplicação java…ele lança várias " First chance Exception - Access Violation". Eu dei uma pesquisada e isso é como se fosse um nullPointer da vida…
E devido a essas exceptions a minha aplicação dá crash… Notei que isso acontece pq o jnaerator trabalha com ponteiros dos endereços de memória…e toda vez que o Garbage Collector passa…ele acaba movendo os objetos da youngGenerator para a oldGenerator área, e os ponteiros dos objetos acabam ficando com o valor desatualizado…

Alguém ja teve um problema semelhante?

Criado 20 de abril de 2010
Ultima resposta 10 de jan. de 2013
Respostas 9
Participantes 3