DLL delphi

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…)

obrigado!

vResultado é um pChar que é um ponteiro pra um byte, ou bytearray(como conhece no java)
Tenta usar o Pointer com ele.

juliocbq, obrigado pela resposta. Confesso que não entendi completamente (desculpe minha ignorância). Sem querer pedir de mais, teria um exemplo?

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… :frowning:

Obrigado pela resposta amigo.
Então do jeito que eu estou tentando usar a DLL é “impossível” ? :frowning:

Não por isso; mas você consegue mudar a DLL de modo que você passe a string como um parâmetro, em vez de ser um valor de retorno?

Obrigado novamente pela ajuda!

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=saureco]Obrigado novamente pela ajuda!

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.

Obrigado pela ajuda companheiro!

Vou efetuar algumas tentativas e obtendo sucesso postarei a solução. :stuck_out_tongue:

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!.

solução abaixo:

Interface TestInt

[code]/*

  • To change this template, choose Tools | Templates
  • and open the template in the editor.
  • Special thanks to technomage (stack overflow) -> http://stackoverflow.com
    */
    package teste_dll_01;

import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.win32.StdCallLibrary;
import java.util.Arrays;
import java.util.List;

/**
*

  • @author Saureco
    */

public interface TestInt extends StdCallLibrary {
TestInt INSTANCE = (TestInt)Native.loadLibrary(“C:/test/Win32/Debug/TESTLIB”, TestInt.class);

public void MyReturn(TestInt testInt);

class Test extends Structure {
    public String vResult;
    public String vResult2;
    public Test() { }
    public Test(Pointer p) { 
        super(p);
        read();
    }
    @Override
    protected List getFieldOrder() { return Arrays.asList(new String[] { "vResult", "vResult2" }); }
}

String MyReturn(Test test);

}[/code]
Classe main:

[code]/*

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

/**
*

  • @author Saureco
    */
    import teste_dll_01.TestInt.Test;

public class TESTE_DLL_01 {

/**
 * @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!

Meu quase 2 anos e ajudando muito obrigado serviu como uma luva esse post !
GUJ i like this ! :slight_smile:

[quote=jetset]Meu quase 2 anos e ajudando muito obrigado serviu como uma luva esse post !
GUJ i like this ! :)[/quote]

Fico feliz ao saber que esta solução está ajudando outras pessoas.

Boa tarde pessoal, tudo bem?

Sei que vão dar risada, mas sou completamente NOOB em java.

Tenho uma dll em delphi já pronta e “simplesmente” preciso chamar a mesma passando os parametros. Acredito que este posto do Saureco poderá me ajudar.

Porém, estou usando o netbeans com java 8.1 e eu não estou conseguindo nem importar as bibliotecas:

import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.win32.StdCallLibrary;
import java.util.Arrays;
import java.util.List;

Alguém pode me dar um help sobre esta questão?

Obrigado,
Leandro Giuriollo

Você precisa baixar o jna.jar e adicionar ao classpath de sua aplicação.

Obrigado Staroski, deu certo!

Pensei que o JNA era nativo do java =) .

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:

package teste_dll_01;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.win32.StdCallLibrary;
import java.util.Arrays;
import java.util.List;

public interface CalculadoraDLL extends StdCallLibrary {
CalculadoraDLL INSTANCE = (CalculadoraDLL)Native.loadLibrary(“C:\CalculadoraDLL”, CalculadoraDLL.class);
public void Calcular(CalculadoraDLL testInt);
class Test extends Structure {
public Integer vResult;
public Test() { }
public Test(Float V1, String Opr, Float V2) {
(1);
("+");
(2);
read();
}
@Override
//protected List getFieldOrder() { return Arrays.asList(new String[] { “vResult”, “vResult2” }); }
protected List getFieldOrder() { return Arrays.asList(new String[] { “vResult” }); }
}
String Calcular(Test test);
}

Desde já, Agradeço pela força = )

Declare sua interface assim:

import com.sun.jna.Library;
import com.sun.jna.Native;

public interface CalculadoraDLL extends Library {

	CalculadoraDLL INSTANCE = (CalculadoraDLL) Native.loadLibrary("CalculadoraDLL", CalculadoraDLL.class);

	public void calcular(float v1, String op, float v2);
}

E pode utilizar desta forma:

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);
	}
}