[RESOLVIDO] Erro ao tentar acessar função dentro de uma DLL com JNA

Olá Pessoal!!

Este é o código da minha DLL em C++:

[code]//dllmain.cpp
#include “unidll.h”
#include <windows.h>
#include <winbase.h>

bool setDateTime(int year, int month, int day, int hour, int minute, int second) {
SYSTEMTIME time;
time.wYear = year;
time.wMonth = month;
time.wDay = day;
time.wHour = hour + 2;
time.wMinute= minute;
time.wSecond = second;
return SetSystemTime(&time);
}[/code]

[code]//unidll.h
#ifndef UNIDLL_H
#define UNIDLL_H

#if BUILDING_DLL

define DLLIMPORT __declspec (dllexport)

#else

define DLLIMPORT __declspec (dllimport)

#endif

class DLLIMPORT DllClass {
public:
bool setDateTime(int year, int month, int day, int hour, int minute, int second);

private:
};

#endif[/code]
Código java para acessar a função setDateTime();

[code]import com.sun.jna.Library;

/**
*

  • @author eliangela
    */
    public interface MySharedLibrary extends Library {

    public boolean setDateTime(int year, int month, int day, int hour,
    int minute, int second);
    }[/code]

[code]import com.sun.jna.Native;

/**
*

  • @author Eliangela
    */
    public class AcessaDLL {

    public boolean setDateTime(int year, int month, int day, int hour,
    int minute, int second) {
    MySharedLibrary lib = (MySharedLibrary) Native.loadLibrary(“C:/Users/eliangela/Desktop/testeDll/uni-dll”,
    MySharedLibrary.class);
    return lib.setDateTime(year, month, day, hour, minute, second);
    }

    public static void main(String[] args) {
    AcessaDLL dll = new AcessaDLL();
    dll.setDateTime(2008, 6, 1, 1, 0, 0);
    }
    }[/code]

Eu compilei o meu código em C++ pelo Dev-cpp da Borland e gerei minha DLL.
esse código da DLL está funcionando, porque eu já testei num executável, mas não funciona com o JNA.

gera esse erro:

[code]Exception in thread “main” java.lang.UnsatisfiedLinkError: Error looking up function ‘setDateTime’: Não foi possível encontrar o procedimento especificado.

    at com.sun.jna.Function.&lt;init&gt;(Function.java:128)
    at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:299)
    at com.sun.jna.Library$Handler.invoke(Library.java:199)
    at $Proxy0.setDateTime(Unknown Source)
    at br.com.unimake.nativo.AcessaDLL.setDateTime(AcessaDLL.java:15)
    at br.com.unimake.nativo.AcessaDLL.main(AcessaDLL.java:20)

Java Result: 1[/code]

O que estou fazendo de errado?

Obrigada!

Voce está exportando seu metodo?

Olá pessoal!

Eu precisava muito alterar a data e a hora do sistema e, segundo o site da Micosoft, essa é a função dentro da DLL kernel32.dll:

[code]typedef struct _SYSTEMTIME { // st
WORD wYear;
WORD wMonth;
WORD wDayOfWeek;
WORD wDay;
WORD wHour;
WORD wMinute;
WORD wSecond;
WORD wMilliseconds;
} SYSTEMTIME;

BOOL SetSystemTime(const SYSTEMTIME *lpSystemTime);
[/code]
e eu ficava me perguntando: “Que parâmetro que é esse?? Como que passo isso pra essa função??”

e com todos esses tutoriais ensinavam a fazer HELLO WORLD e nada de dizer como que eu faço pra passar esses tipos estranhos por parâmetros.

Bom, Consegui achar um tutorial ótimo na internet de como acessar essas DLL’s que já vem prontas.

http://javaniando.blogspot.com/2008/02/acessando-bibliotecas-nativas-com-jna.html

Até mais

olá fernando!

eu ia colocar que o tópico está resolvido, mas ainda quero saber como que eu faço pra acessar essa DLL que eu criei.

Como assim “exportando”?

Toda vez que vc cria uma dll vc deve exportar os metodos que vc deseja acessar por outra aplicacao por exemplo.

Se vc diz do arquivo .H, está assim:

[code]//unidll.h
#ifndef UNIDLL_H
#define UNIDLL_H

#if BUILDING_DLL

define DLLIMPORT __declspec (dllexport)

#else

define DLLIMPORT __declspec (dllimport)

#endif

class DLLIMPORT DllClass {
public:
bool setDateTime(int year, int month, int day, int hour, int minute, int second);

private:
};

#endif[/code]

Se não, então não exportei.
Por favor, me explique como fazer isso… ainda estou aprendendo C++ e estou cometendo erros muito bobos.

Google(por enquanto) é seu melhor amigo…

http://msdn.microsoft.com/pt-br/library/z4zxe9k8.aspx

Fazendo estes passos vc consegue exportar seu metodo =D

[]s

ps.: Isso nao é erro bobo. Criar e exportar metodos de dll nao sao coisas de iniciantes…

Eliangela, você está com um probleminha chato. O JNA não consegue importar classes C++. Aliás, só o Visual C++ (usando a mesma versão do compilador! - você não pode misturar versões, como 6.0 ou 2008) consegue importar classes C++ exportadas por uma DLL C++.

Você conseguiria importar a sua função se fosse um método global, e ainda por cima exportado como se fosse um método C puro. O que se faz é o seguinte:

#if defined (__cplusplus)
export "C" {
#endif
DLLIMPORT bool setDateTime(int year, int month, int day, int hour, int minute, int second);  
#if defined (__cplusplus)
};
#endif

E no seu arquivo .cpp você simplesmente escreve

DLLIMPORT bool setDateTime(int year, int month, int day, int hour, int minute, int second)
{
    // seu código C++...
}

Pelo que imagino, seu método é simplesmente um encapsulamento da API SetSystemTime, então isso não é complicado.

OK? (Não precisa criar um arquivo .def)

Obrigada pessoal pela ajuda!

Consegui fazer o JNA acessar minha DLL!!

o código em C++ ficou assim:

[code]//unidll.h
#ifndef UNIDLL_H
#define UNIDLL_H

#if BUILDING_DLL
# define DLLIMPORT __declspec (dllexport)
#else
# define DLLIMPORT __declspec (dllimport)
#endif

#if defined (__cplusplus)
extern “C” {
#endif
DLLIMPORT bool setDateTime(int year, int month, int day, int hour, int minute, int second);
#if defined (__cplusplus)
};
#endif

#endif[/code]

[code]//dllmain.cpp
#include “unidll.h”
#include <windows.h>
#include <winbase.h>

DLLIMPORT bool setDateTime(int year, int month, int day, int hour, int minute, int second) {
SYSTEMTIME time;
time.wYear = year;
time.wMonth = month;
time.wDay = day;
time.wHour = hour + 3;
time.wMinute= minute;
time.wSecond = second;
return SetSystemTime(&time);
}[/code]

Obrigada a todos, mas quem ainda tiver dúvidas de como acessra uma DLL já existente, acesse este tutorial:
http://javaniando.blogspot.com/2008/02/acessando-b…bliotecas-nativas-com-jna.html

Abraços a todos

Pessoal…
Eu estava percebendo que meu código em C++ estava alterando a hora do sistema, mas para 3 horas a menos.
Então eu descobri que isso tinha a ver com o fuso-horário e que, quando eu informava um horário, estava informando o horário universal.

Agora corrigindo:

[code]//uni-dll.cpp
#include “unidll.h”
#include <windows.h>
#include <winbase.h>

DLLIMPORT bool setDateTime(int year, int month, int day, int hour, int minute, int second) {
SYSTEMTIME time;
time.wYear = year;
time.wMonth = month;
time.wDay = day;
time.wHour = hour + 3;
time.wMinute= minute;
time.wSecond = second;
return SetLocalTime(&time); //Tem que ser SetLocalTime() ao invés de SetSystemTime()
}[/code]

[code]//unidll.h
#ifndef UNIDLL_H
#define UNIDLL_H

#if BUILDING_DLL
# define DLLIMPORT __declspec (dllexport)
#else
# define DLLIMPORT __declspec (dllimport)
#endif

#if defined (__cplusplus)
extern “C” {
#endif
DLLIMPORT bool setDateTime(int year, int month, int day, int hour, int minute, int second);
#if defined (__cplusplus)
};
#endif

#endif[/code]

Eliângela, seu código pode dar pau quando chegar a época do horário de verão :confused: Normalmente o Brasil está 3 horas atrasado em relação ao horário GMT, mas no horário de verão essa diferença diminui para 2. Então, acho que seria interessante alterar sua DLL para receber exatamente quantas horas é necessário deslocar em relação ao GMT.

É… eu realmente tinha visto isso… mas tem como resolver isso chamando a função SetDaylightTime(0) pra desativar o horário de verão.
http://msdn.microsoft.com/pt-br/library/bb202790.aspx

Opa!

Pode ser que o erro seja que a DLL não foi encontrada pelo SO.
Adicione o path da DLL a variável de ambiente PATH.

Pode ser que funcione!
Se assim não for, coloque a DLL direto na pasta C:\WINDOWS\System32, pois este diretório é mapeado por default.

Se não estou enganado vc pode fazer uma classe Java com as propriedades igual da struct SYSTEMTIME
e mapear diretamente a DLL do windows
o JNA fará a magica para vc…
não precisa usar uma DLL como ponte(bridge) para isso…

[quote=dyorgio]Se não estou enganado vc pode fazer uma classe Java com as propriedades igual da struct SYSTEMTIME
e mapear diretamente a DLL do windows
o JNA fará a magica para vc…
não precisa usar uma DLL como ponte(bridge) para isso…[/quote]

Olá!
Eu tinha feito isso tbem, mas foi importante pra mim fazer essa DLL, pois acabei aprendendo algumas coisas.
Vou passar pra vcs o meu código com a alternativa que o Dyorgio disse:

[code]import com.sun.jna.Structure;
/**
*

  • @author Eliangela
    */
    public class DataHoraSistema extends Structure {

    public short wYear;
    public short wMonth;
    public short wDayOfWeek;
    public short wDay;
    public short wHour;
    public short wMinute;
    public short wSecond;
    public short wMilliseconds;
    }[/code]

[code]import com.sun.jna.win32.StdCallLibrary;

/**
*

  • @author Eliangela
    */
    public interface Kernel32 extends StdCallLibrary {

    public void SetLocalTime(DataHoraSistema time);

    /**

    • Seta se o computador irá ajustar para horário de verão ou não.
    • @param horarioVerao Valor 1 indica que horário de verão é aplicado.
    • Valor 0 indica que horário padrão é aplicado.
      */
      public void SetDaylightTime(short horarioVerao);

}[/code]

[code]import com.sun.jna.Native;

/**
*

  • @author Eliangela
    */
    public class ExecutaDll {

    public static void setDateTime(short wYear, short wMonth, short wDay,
    short wDayOfWeek, short wHour, short wMinute, short wSecond) {
    try {
    Kernel32 lib = (Kernel32) Native.loadLibrary(“kernel32”, Kernel32.class);
    DataHoraSistema time = new DataHoraSistema();
    time.wYear = wYear;
    time.wMonth = wMonth;
    time.wDayOfWeek = wDayOfWeek;
    time.wDay = wDay;
    time.wHour = wHour;
    time.wMinute = wMinute;
    time.wSecond = wSecond;
    time.wMilliseconds = 0;

         //lib.SetDaylightTime((short) 0);
         lib.SetLocalTime(time);
     } catch (Exception e) {
         e.printStackTrace();
     }
    

    }
    }[/code]