Donate. I desperately need donations to survive due to my health

Get paid by answering surveys Click here

Click here to donate

Remote/Work from Home jobs

Trying to call Delphi procedures and functions from C#

I have a 3rd party DLL written in Delphi (no source code) that I need to call from C#. I also have a second DLL also written in Delphi (with source code) that calls the functions and procedures in the 3rd party DLL and exports those calls.

I can call the second DLL from C# to call indirectly to the functions and procedures in the first DLL, but there are (seemingly) random Access Violations in the second DLL, so I’d like to access the first DLL directly from C#.

An example of the exported code in the second Dll is:

type // Types used to cast function returns from GetProcAddress
  SetCommsDebugProc = procedure(DebugOnOff: boolean);

var // function pointers used when assigning GetProcAddress
  pSetCommsDebugProc: SetCommsDebugProc = nil;

function AttachComms(Handle: HWND; timeCount: Integer; simMode: Boolean): Boolean;
const
  FunctName = 'AttachComms';
var
  RC: Boolean;
begin
  RC := FALSE;
  if (_hThirdPartyWin32Dll <> 0) then
  begin
    if not assigned(pAttachCommsProc) then
      pAttachCommsProc := GetProcAddress(_hThirdPartyWin32Dll, pansichar(FunctName)); // get the address

    if assigned(pAttachCommsProc) then
    begin
      RC := pAttachCommsProc(Handle, timeCount, simMode); // call the function
    end
    else
      raise Exception.create('Unable to load ' + FunctionName + ' from ' + DLL_NAME + '.Dll');
  end;
  result := RC;
end;

Another example that has no return value is:

type // Types used to cast function returns from GetProcAddress
  AttachCommsProc = function(Handle: HWND; timeCount: Integer; simMode: Boolean): Boolean;

var // function pointers used when assigning GetProcAddress
  pSetCommsDebugProc: SetCommsDebugProc = nil;

procedure SetCommsDebug(DebugOnOff: boolean); stdcall;
const
  FunctName = 'SetCommsDebug';
begin
  if (_hThirdPartyWin32Dll <> 0) then
  begin
    if not assigned(pSetCommsDebugProc) then
      pSetCommsDebugProc := GetProcAddress(_hThirdPartyWin32Dll, pansichar(FunctName)); // get the address

    if assigned(pSetCommsDebugProc) then
    begin
      pSetCommsDebugProc(DebugOnOff); // call the function
    end
    else
      raise Exception.create('Unable to load ' + FunctionName + ' from ' + DLL_NAME + '.Dll');
  end;
end;

I've tried [DllImport] and [UnmanagedFunctionPointer] but with limited success. I've also tried several of the answers to similar questions here in StackOverflow.

Sometimes I get a PInvokeUnbalanceStackException, and sometimes it just hangs.

I'm using Windows 10, MSVS 2017 Enterprise, Delphi 10 Community

An example of the SecondDll [DllImport] that works is:

[DllImport("Second.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern void SetCommsDebug(bool onoff);

I tried the same code with the 3rd party DLL and with all combinations of CharSet and CallingConvention.

The [UnmanagedFunctionPointer] attempt was based on the Dynamic version in an answer to this question.

Unfortunately, I'm not able to post a Minimal, Complete, and Verifiable Example because of an NDA with the 3rd party, and it would be too big to comprehend.

Comments