Olá amigos do fórum. Venho até vocês pois estou com uma enorme dúvida… Usando JNA consigo acessar funções simples contidas em uma DLL (Delphi), porém, para uso da mesma DLL em um módulo Desktop e um modulo WEB, terei uma rotina em comum e, para não ter que duplicar, resolvi desenvolver uma dll. Porém esta dll possui uma interface com um type record e seu acesso via delphi é simples, mas no Java a coisa complicou…
Segue o código da dll (Delphi):
TESTELIB.DLL
library TESTELIB;
{$DEFINE TESTELIB}
uses
System.SysUtils,
System.Classes,
TesteInter in 'TesteInter.pas';
{$R *.res}
function Retornar(Teste: PTeste): PChar; stdcall;
begin
Result := 'Entrei!';
Teste^.vResultado := 'Teste 123';
end;
exports Retornar;
begin
end.
interface TesteInter.pas
unit TesteInter;
interface
type
PTeste = ^TTeste;
TTeste = record
vResultado: PChar;
end;
{$IFNDEF TESTELIB}
function Retornar(Teste: PTeste): PChar; stdcall;
{$ENDIF}
implementation
{$IFNDEF TESTELIB}
function Retornar; external 'TESTELIB.DLL' name 'Retornar';
{$ENDIF}
end.
gostaria de saber como acessar esta interface via java pois ela contem o type Teste e a variável vResultado (que é o que me interessa…)
A propósito, em DLLs não é aconselhável ter qualquer valor de retorno que não seja um primitivo (int, long, double etc.).
Se você precisa retornar um resultado que é uma string, é melhor que ela seja um parâmetro de entrada e saída (“var” em Pascal).
Isso é devido a problemas de alocação de memória.
Obrigado pela resposta entanglement. Mas o problema em si não é o retorno. Consigo obter o retorno normalmente (inteiros, pontos flutuantes). O problema maior é acessar via java esta Interface, já que ela que vai conter as informações para que eu as trate.
É que estou falando isso porque já tive muitos problemas de interfaceamento de DLLs escritas em C ou Pascal quando elas são chamadas por outra linguagem (como VB ou Java).
Um dos problemas recorrentes é quando um método retorna algo que não é um tipo primitivo.
Como retornar uma string implica em alocação de memória pela DLL, e como normalmente DLLs usam um alocador de memória que não é o mesmo que o da linguagem que está chamando a DLL, normalmente ocorrem problemas como “memory leaking” que só são resolvidos quando se desiste de retornar algo dessa maneira - normalmente, para evitar vazamentos de memória, faz-se com que o programa que chama a DLL é que aloca um bloco de memória e o passa para a DLL trabalhar em cima.
Como já tive muitos problemas desse tipo, eu acabo não usando JNA porque não tenho controle suficiente do que ocorre…
Sim. A passagem de parâmetros é de certa forma simples. Na DLL (acabei de fazer um debug) a passagem de parâmetros via String (java) deve ser do tipo PChar(Delphi) já que string no Delphi é uma classe (se não estou enganado).
A interface grava na memória vResultado que por sua vez é acessado (via ponteiro) pela aplicação. Isso no delphi é facil, agora passando pro Java o problema é, eu não consigo criar um tipo Teste…
abaixo exemplo de como é feito em Delphi:
unit FormPrincipal;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses TesteInter;
procedure TForm1.Button1Click(Sender: TObject);
var
Teste: TTeste; //Tipo declarado na Interface TesteInter.pas
begin
ShowMessage(Retornar(@Teste)); //Resultado da função -> Entrei!
ShowMessage(Teste.vResultado); //Conteudo armazenado em vResultado -> Teste 123
end;
end.
Acho que, se existir um tipo, maneira, método de passar a variável Teste via java de forma similar ao Delphi, irá funcionar…
Sim. A passagem de parâmetros é de certa forma simples. Na DLL (acabei de fazer um debug) a passagem de parâmetros via String (java) deve ser do tipo PChar(Delphi) já que string no Delphi é uma classe (se não estou enganado).
A interface grava na memória vResultado que por sua vez é acessado (via ponteiro) pela aplicação. Isso no delphi é facil, agora passando pro Java o problema é, eu não consigo criar um tipo Teste…
abaixo exemplo de como é feito em Delphi:
unit FormPrincipal;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses TesteInter;
procedure TForm1.Button1Click(Sender: TObject);
var
Teste: TTeste; //Tipo declarado na Interface TesteInter.pas
begin
ShowMessage(Retornar(@Teste)); //Resultado da função -> Entrei!
ShowMessage(Teste.vResultado); //Conteudo armazenado em vResultado -> Teste 123
end;
end.
Acho que, se existir um tipo, maneira, método de passar a variável Teste via java de forma similar ao Delphi, irá funcionar…[/quote]
Usando jna o tipo a ser usado é o pointer. Foi isso que quis dizer lá em cima. Quando você lida com referências não há como fugir dele.
Dá uma lida aqui, pode ser útil: http://stackoverflow.com/questions/494325/jna-struct-and-pointer-mapping
Com jni existe um tipo para isso representando também um ponteiro, mas faz tempo que não trabalho com isso. Precisa olhar na documentação do jni.
Venho até vocês para informar que não consegui fazer o que queria. Gostaria de pedir ao administrador para fechar o tópico se necessário. Fica o agradecimento a todos que responderam de de certa forma ajudaram. Valeu!.
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
Test test = new Test();
System.out.println(TestInt.INSTANCE.MyReturn(test));
System.out.println(test.vResult);
System.out.println(test.vResult2);
}
}[/code]
dessa forma é possível ter em java os resultados que a DLL armazena em suas variaveis (vResult e vResult2). Caso queira usar strings, deve-se usar PAnsiChar (Delphi). Agradeço a todos que de certa forma me ajudaram, meu filho que vai nascer e como diria o Guru do Himalaia: MÍTICO!
Pessoal, surgiu mais uma dúvida, estou alterando os métodos para a chamada da minha dll. Meu método na dll, se chama calcular e eu passo 3 parâmetros para ele, que são V1, OP, V2.
V1 e V2 são float, OP = String.
Estou na dúvida, de como passar estes parâmetros na chamada do método, segue como meu código está até o momento:
public class Teste {
public static void main(String[] args) {
CalculadoraDLL calculadora = CalculadoraDLL.INSTANCE;
float a = 1;
String op = "+";
float b = 2;
calculadora.calcular(a, op, b);
}
}