0
votes

for the first time I have to call an external DLL from Delphi. It's the DLL provided with a weight scale. First thing, I would like to connect to this scale. Here is my code:

unit XOdeca;

interface
[...]

type
  TXFSOdecaConnected = function: boolean; stdcall;
  TXFSOdecaConnect = procedure (SERIAL_PORT: PChar); stdcall;

  TXOdeca = class
  protected
    FOdecaDllHandle: THandle;
    FFLBilanciaConnessa: boolean;

  public
    constructor Create;
    destructor Destroy; override;

    procedure LoadOdeca;
  end;


implementation

uses
  System.UITypes;

[...]   

procedure TXOdeca.LoadOdeca;
const
    LibName = 'OdecaDeviceControl.dll';
var
    libreria: string;
    fnIsScanLibraryRegistered: TXFSOdecaConnected;
    fnConnectOdeca: TXFSOdecaConnect;
begin

    if FOdecaDllHandle = 0 then
    begin
        libreria := ExtractFilePath( Application.ExeName ) + LibName;
        if not FileExists( libreria ) then
            raise Exception.Create( 'Non posso aprire la libreria ' + libreria );

        try
            FOdecaDllHandle := LoadLibrary( @libreria[1] );
            if FOdecaDllHandle = 0 then
                raise Exception.Create('Errore in caricamento libreria "' + LibName + '"' );

            @fnConnectOdeca := GetProcAddress( FOdecaDllHandle, 'Odeca.SerialDevice.Connect');
            if not Assigned( @fnConnectOdeca ) then
                raise Exception.Create( 'Impossibile trovare il punto di ingresso "fnConnectOdeca" in "' + LibName + '"' );


            @fnIsScanLibraryRegistered := GetProcAddress( FOdecaDllHandle, 'Odeca.SerialDevice.Connected');
            if not Assigned( @fnIsScanLibraryRegistered ) then
                raise Exception.Create( 'Impossibile trovare il punto di ingresso "FSIsScanLibraryRegistered" in "' + LibName + '"' );

            FFLBilanciaConnessa := fnIsScanLibraryRegistered;

        except
        [...]    
        end;
    end;
end;


end.

I get to load correctly the library (FOdecaDllHandle gets a value different from 0), but then I can't connect to any function or procedure in the library, the GetProcAddress always returns 0.

From the documentation provided with the library, the names of the procedures are correct.

There are also two working examples in VB.net and C# coming with the library, and they both declare objects such as (VB.net)

Private odecaDevice As New Odeca.SerialDevice

but I think this is not possible in Delphi, since I don't add references to the objects of the library.

Does it have anything to do with the dot notation used in the library? (consider for example that every procedure comes in two versions, to be used depending on the connection type of the weight scale, e.g. Odeca.SerialDevice.Connect and Odeca.NetworkDevice.Connect).

Thank you very much, Fabio

--- UPDATE 29/03/2019

Following the examples at this link Work around with Delphi DLL I created the following OdecaWrapper.dll:

procedure CONNECT; export;
var
    adll: Thandle;
    afunc: function:Boolean;
begin
    adll:=LoadLibrary('OdecaDeviceControl.dll');
    afunc:= GetProcAddress(adll,'Odeca.SerialDevice.Connect');
    afunc;
    FreeLibrary(adll);
end;

    exports
        CONNECT;

In my Delphi code, I define.

procedure CONNECT; stdcall; external 'OdecaWrapper.dll';

with no implementation. In the same Delphi unit, I have a procedure calling this external procedure


procedure TXOdeca.LoadOdeca;
begin
    try
        CONNECT;
        [missing]
    except
        on E:Exception do
        begin
            MessageDlg( E.Message, mtWarning, [mbOK], 0 );
        end;
    end;
end; 

All I get is Access Violation when I get to the CONNECT command of my procedure, what am I doing wrong?

2
From the VB.net example, it appears that you might be using a COM library, which is not accessed via LoadLibrary/GetProcAddress, but typically by importing the type library. - Ken White
Equally likely is that this is a managed .net assembly. They are even hard to consume from Delphi. Step 1 is to find out what this library actually is. - David Heffernan
Odeca.SerialDevice.Connect for example, I'm pretty sure is not a valid function name for standard interop. It likely is something such as COM or .NET as mentioned. - Jerry Dodge
@David: I even think it is more likely that it is a .NET assembly, if the examples are in VB.NET and C#. - Rudy Velthuis
Check for plain C examples, if there are any. - dummzeuch

2 Answers

0
votes

It is not possible to communicate directly from delphi to this .NET library.

I had another programmer creating a .NET console application (OdecaReader.exe) that calls the library, reads the weight from the scale, and writes it into a temporary .txt.

From Delphi, I invoke this OdecaReader.exe, then I read the content of the temporary file.

0
votes

It is possible to use a .NET DLL. I actually use it - for C#, see Unmanaged Exports on NuGet. You can write a wrapper DLL and use just the functions you need.