Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   Uso de dll externa en Delphi (https://www.clubdelphi.com/foros/showthread.php?t=94197)

Diego E. 27-09-2019 19:29:12

Uso de dll externa en Delphi
 
Hola amigos, estoy adentrándome en territorio nuevo y espero puedan ayudarme.

Estoy realizando un proyecto Delphi, para el que necesito usar una dll hecha para C/C++ o Visual Basic 6, en la documentación de la dll no viene la forma de implementar en Delphi(no es sorpresa) ni describe los comandos dentro de ella como para hacer el típico procedimiento de:

Código Delphi [-]
function DoMath(X, Y: Integer): Integer; cdecl; external 'exampleDLL.dll';

Es la primera vez que voy a trabajar con dll's y ciertamente no se usar C++, se que la información va de casi a totalmente nula, pero alguno tiene alguna referencia de como trabajar dicha dll (o en general cualquier dll hecha en un lenguaje externo a Delphi).

Adjunto un poco del código que viene en la documentación de la dll:

Código:


struct SSP_COMMAND {
SSP_FULL_KEY Key;
unsigned long BaudRate;
unsigned long Timeout;
unsigned char PortNumber;
unsigned char SSPAddress;
unsigned char RetryLevel;
unsigned char EncryptionStatus;
unsigned char CommandDataLength;
unsigned char CommandData[255];
unsigned char ResponseStatus;
unsigned char ResponseDataLength;
unsigned char ResponseData[255];
unsigned char IgnoreError;
};

typedef UINT (__stdcall* DLLFUNC3)(SSP_COMMAND* cmd, SSP_COMMAND_INFO* sspInfo); DLLFUNC3 sspSendCommand = (DLLFUNC3)GetProcAddress(hInst, "SSPSendCommand");

P.D. También existe una dll hecha para C# .NET or Visual Basic .NET

Neftali [Germán.Estévez] 30-09-2019 12:40:18

Cita:

Empezado por Diego E. (Mensaje 533643)
Estoy realizando un proyecto Delphi, para el que necesito usar una dll hecha para C/C++ o Visual Basic 6, en la documentación de la dll no viene la forma de implementar en Delphi(no es sorpresa) ni describe los comandos dentro de ella como para hacer el típico procedimiento de:

Es la primera vez que voy a trabajar con dll's y ciertamente no se usar C++, se que la información va de casi a totalmente nula, pero alguno tiene alguna referencia de como trabajar dicha dll (o en general cualquier dll hecha en un lenguaje externo a Delphi).

Al final, da igual en qué esté hecha la DLL (o debería dar igual), la llamada desde tu programa es indiferente.

Cita:

Empezado por Diego E. (Mensaje 533643)
Adjunto un poco del código que viene en la documentación de la dll:
Código:

struct SSP_COMMAND {
SSP_FULL_KEY Key;
unsigned long BaudRate;
unsigned long Timeout;
unsigned char PortNumber;
unsigned char SSPAddress;
unsigned char RetryLevel;
unsigned char EncryptionStatus;
unsigned char CommandDataLength;
unsigned char CommandData[255];
unsigned char ResponseStatus;
unsigned char ResponseDataLength;
unsigned char ResponseData[255];
unsigned char IgnoreError;
};
typedef UINT (__stdcall* DLLFUNC3)(SSP_COMMAND* cmd, SSP_COMMAND_INFO* sspInfo); DLLFUNC3 sspSendCommand = (DLLFUNC3)GetProcAddress(hInst, "SSPSendCommand");


En este caso tienes varias cosas.
Primero debes tener definida la cabecera de la función a la que vas a llamar.
Código Delphi [-]
function sspSendCommand (cmd:SSP_COMMAND; sspInfo:SSP_COMMAND_INFO):Integer; stdcall; external 'itlsspproc.dll';

Como la cabecera necesita unos tipos "específicos" denerás tenerlos definidos en tu unidad (.PAS), así que debes "covertir" los tipos que ya te dan a Delphi.

En tu caso, por ejemplo, el tipo:

Código:

struct SSP_COMMAND {
SSP_FULL_KEY Key;
unsigned long BaudRate;
unsigned long Timeout;
unsigned char PortNumber;
unsigned char SSPAddress;
unsigned char RetryLevel;
unsigned char EncryptionStatus;
unsigned char CommandDataLength;
unsigned char CommandData[255];
unsigned char ResponseStatus;
unsigned char ResponseDataLength;
unsigned char ResponseData[255];
unsigned char IgnoreError;
};

Se traduce como:

Código Delphi [-]
type
  SSP_COMMAND = record
    Key: SSP_FULL_KEY;
    BaudRate: LongInt;
    Timeout: LongInt;
    PortNumber: Byte;
    SSPAddress: Byte;
    RetryLevel: Byte;
    EncryptionStatus: Byte;
    CommandDataLength: Byte;
    CommandData: Array[0..255-1] of Byte;
    ResponseStatus: Byte;
    ResponseDataLength: Byte;
    ResponseData: Array[0..255-1] of Byte;
    IgnoreError: Byte;
  end {SSP_COMMAND};

Algo similar debes hacer con el resto.

Neftali [Germán.Estévez] 30-09-2019 13:05:37

Los otros tipos podrían ser algo así:


Código Delphi [-]
type
  SSP_FULL_KEY = record
    FixedKey: LongInt;
    EncryptKey: LongInt;
  end {SSP_FULL_KEY};

  SSP_PACKET = record
    packetTime: Word;
    PacketLength: Byte;
    PacketData: Array[0..255-1] of Byte;
  end {SSP_PACKET};


  SSP_COMMAND_INFO = record
    CommandName: PByte;
    LogFileName: PByte;
    Encrypted: Byte;
    Transmit: SSP_PACKET;
    Receive: SSP_PACKET;
    PreEncryptTransmit: SSP_PACKET;
    PreEncryptRecieve: SSP_PACKET;
  end {SSP_COMMAND_INFO};

  SSP_COMMAND = record
    Key: SSP_FULL_KEY;
    BaudRate: LongInt;
    Timeout: LongInt;
    PortNumber: Byte;
    SSPAddress: Byte;
    RetryLevel: Byte;
    EncryptionStatus: Byte;
    CommandDataLength: Byte;
    CommandData: Array[0..255-1] of Byte;
    ResponseStatus: Byte;
    ResponseDataLength: Byte;
    ResponseData: Array[0..255-1] of Byte;
    IgnoreError: Byte;
  end {SSP_COMMAND};

Neftali [Germán.Estévez] 30-09-2019 13:06:47

Supongo que si alguien más quiere mirar el tema, este documento le podría servir de ayuda.


http://www.marrginal.ru/files/cashma...ide%20v2.2.pdf


Si tienes algun otro link, estaría bien que lo añadieras.

Diego E. 01-10-2019 00:24:14

Antes que nada gracias por tomarte el tiempo de ver el tema y responder.
Comenzaré como dices con los encabezados del las funciones principales en el documento y de ahí me iré adentrando más en el tema, probando si lo que hago es correcto, tengo entendido que una vez logrando dicha instrucción ya sólo debo mandar llamar el método que me retornó el GetProcAddress y mandando como parámetos los tipos declarados con anterioridad. Cualquier cosa estaré reportándome de nuevo. Gracias.

Diego E. 06-10-2019 18:12:55

Cita:

Empezado por Neftali [Germán.Estévez] (Mensaje 533669)

Código Delphi [-]
function sspSendCommand (cmd:SSP_COMMAND; sspInfo:SSP_COMMAND_INFO):Integer; stdcall; external 'itlsspproc.dll';


Hola de nuevo, tengo algunas dudas más específicas acerca de este tema:

Tengo entendido que hay dos formas de usar las funciones dentro de la DLL(estática y dinámica), cuando intento llevar a cabo las siguientes lineas de C++ usando el dinámico tengo algo así:

Codigo de C++ a replicar(no tal cual, sólo lo que ocupo):
Código:

HINSTANCE hInst = LoadLibrary("ITLSSPProc.dll");
        if (hInst != NULL)
        {
                // Link function names

                // Opens the COM port
                OpenPort = (LPFNDLLFUNC1)GetProcAddress(hInst, "OpenSSPComPortUSB");
                if (OpenPort == NULL)
                {
                        FreeLibrary(hInst);
                        THREAD_UNLOCK
                        return false;
                }

Yo hago algo así:
Código Delphi [-]
hInst := LoadLibrary('ITLSSPProc.dll');

    if hInst <> 0 then
    begin

      OpenPort := GetProcAddress(hInst, 'OpenSSPComPortUSB');
      if @OpenPort = nil then //Linea de la duda
      begin
        FreeLibrary(hInst);
        ShowMessage('No se pudo traer el OpenPort');
        Exit;
      end;

Pero aqui hay dos cosas, si en la línea de la duda pogo el @(que tengo entendido que es como usar un apuntador, pero no se) al evaluarlo me da nil (cosa que no debería pasar si funciona bien la linea del GetProcAddess), si le quito el arroba ni siquiera compila y me arroja el mensaje "Not enough actual parameters" que si no me equivoco es por que está intentando ejecutar la función(Cosa que no trato de hacer, yo sólo quiero saber si el GetProcAddess funcionó).

¿Saben que estoy haciendo mal o cual sería forma correcta de hacer el GetProcAddress?

El código completo es:
Código Delphi [-]
unit LibDLL;

interface

uses
  Vcl.Dialogs, SysUtils, Variants, Classes, Db, Forms, IniFiles, ADODB, Buttons,
  Vcl.ExtCtrls, Vcl.StdCtrls, Vcl.Controls, Windows;


Type

TSSP_FULL_KEY = record
  FixedKey: LongInt;
  EncryptKey: LongInt;
end {SSP_FULL_KEY};

SSP_PACKET = record
  packetTime: Word;
  PacketLength: Byte;
  PacketData: Array[0..255-1] of Byte;
end {SSP_PACKET};

TSSP_COMMAND = record
  Key: TSSP_FULL_KEY;
  BaudRate: LongInt;
  Timeout: LongInt;
  PortNumber: Byte;
  SSPAddress: Byte;
  RetryLevel: Byte;
  EncryptionStatus: Byte;
  CommandDataLength: Byte;
  CommandData: Array[0..255-1] of Byte;
  ResponseStatus: Byte;
  ResponseDataLength: Byte;
  ResponseData: Array[0..255-1] of Byte;
  IgnoreError: Byte;
end {SSP_COMMAND};

TSSP_KEYS = Record
  Generator: int64;
  Modulus: int64;
  HostInter: int64;
  HostRandom: int64;
  SlaveInterKey: int64;
  SlaveRandom: int64;
  KeyHost: int64;
  KeySlave: int64;
End;

TSSP_COMMAND_INFO = record
  CommandName: PByte;
  LogFileName: PByte;
  Encrypted: Byte;
  Transmit: SSP_PACKET;
  Receive: SSP_PACKET;
  PreEncryptTransmit: SSP_PACKET;
  PreEncryptRecieve: SSP_PACKET;
end {SSP_COMMAND_INFO};

TPORT_CONFIG = Record
  NumberOfPorts: String;
  LogFileName: PChar;
  Encrypted: String;
End;

type
  TOpenPort = function (cmd: TSSP_COMMAND): Integer;
//  function OpenPort (cmd: TSSP_COMMAND): Integer; cdecl; external 'ITLSSPProc.dll';
  function SSPSendCommand (cmd:TSSP_COMMAND; sspInfo:TSSP_COMMAND_INFO):Integer; stdcall; external 'ITLSSPProc.dll';


  Function VerificarDLL(): Boolean;
  Procedure InitConfSPO();
  Procedure InitialiseLibrary();


var
  cmd: TSSP_COMMAND;
  keys: TSSP_KEYS;
  sspKey: TSSP_FULL_KEY;
  info: TSSP_COMMAND_INFO;

  OpenPort: function (cmd: TSSP_COMMAND): Integer; stdcall;

  hInst: THandle;

implementation

//------------------------------------------------------------------------------

Function VerificarDLL(): Boolean;
var
  fileName:String;

begin

  Result := False;
  fileName := 'ITLSSPProc.dll';

  if fileexists(fileName) then
  begin
    Result := True;
  end
  else ShowMessage(fileName+' does not exist');

end;

//------------------------------------------------------------------------------

Procedure InitConfSPO();
begin

  InitialiseLibrary

end;

Procedure InitialiseLibrary();
begin

  if VerificarDLL then
  begin

    hInst := LoadLibrary('ITLSSPProc.dll');

    if hInst <> 0 then
    begin

      OpenPort := GetProcAddress(hInst, 'OpenSSPComPortUSB');
      if OpenPort = nil then
      begin
        FreeLibrary(hInst);
        ShowMessage('No se pudo traer el OpenPort');
        Exit;
      end;

    end
    else ShowMEssage('No se pudo instanciar la DLL');

  end;

end;


end.

He intentado con diferentes combinaciones(estáticas y dinámicas) pero no funciona, ahora estoy tratando de apegarme lo más posible a la forma C++ que coloqué.

¿Alguna idea? Si requieren el código y archivos que estoy tratando de usar se los puedo enviar por e-mail


La franja horaria es GMT +2. Ahora son las 05:27:52.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi