Chad
Chad

Reputation: 141

How do I call this Delphi method in C# using Dllimport?

New Programmer in need of Help!

The Delphi code that is compiled into the DLL

function SetCurrentSerial(Size : Integer; Msg : Pointer) : Integer stdcall;
var
  TempByte : PByte;
  TempStr : string;
  i: Integer;
begin
  Result := 0;
  TempByte := Msg;
  TempStr := '';
  for i := 0 to Size - 1 do
  begin
    TempStr := TempStr + ' ';
  end;

  for i := 0 to Size - 1 do
  begin
    TempStr[i+1] := Chr(TempByte^);
    Inc(TempByte);
  end;

  if not DLLClass.SelectDeviceSerial(TempStr) then
  begin
    Result := -1;
  end;
end;

The C# Code

//Import a Function Pointer
[DllImport("Test.dll", CallingConvention= CallingConvention.StdCall, CharSet =  CharSet.Ansi)]
public unsafe static extern int SetCurrentSerial(int Size, byte[] Msg);

I need to store the pointer value, Size and Msg in a buffer and print the value in a console window.

I will greatly appreciate a fully constructed code. Thank you in advance.

Here is the code I've so far tried. //C# Code

class Program
{
    [DllImport("Test.dll")]
    public unsafe static extern int SetCurrentSerial(int Size, void* Msg); 

    unsafe static void Main()
     {
        int Res;

        byte[] buffer = new byte[1024];

        Res = SetCurrentSerial(255, &buffer);

        Console.WriteLine("%s\n", buffer);
     }
}

Upvotes: 1

Views: 1772

Answers (1)

David Heffernan
David Heffernan

Reputation: 613053

Your DLL function is designed incorrectly. You are passing a string from the calling code to the DLL. That is really simple to do and you can remove almost all of your code. The Delphi code should be like this:

function SetCurrentSerial(Serial: PAnsiChar): LongBool; stdcall;
begin
  Result := DLLClass.SelectDeviceSerial(Serial);
end;

Then the C# code should be:

[DllImport("Test.dll", CallingConvention = CallingConvention.StdCall, 
    CharSet = CharSet.Ansi)]
public static extern bool SetCurrentSerial(string Serial);

Call the function like this:

bool succeeded = SetCurrentSerial(Serial);
if (!succeeded)
{
    // handle error
}

I've replaced your integer return value with a boolean indicating success or failure. Should you prefer to revert to an integer that would look like this:

Delphi

function SetCurrentSerial(Serial: PAnsiChar): Integer; stdcall;
begin
  if DLLClass.SelectDeviceSerial(Serial) then begin
    Result := 0;
  end else begin
    Result := -1;
  end;
end;

C#

[DllImport("Test.dll", CallingConvention = CallingConvention.StdCall, 
    CharSet = CharSet.Ansi)]
public static extern int SetCurrentSerial(string Serial);

Update

Apparently you cannot change this DLL. That is a shame because it is really very badly designed and implemented. However, to call that function from C# you need to declare the p/invoke like this:

[DllImport("Test.dll", CallingConvention = CallingConvention.StdCall)]
public static extern int SetCurrentSerial(int Size, byte[] Msg);

And then call it like this:

byte[] Msg = Encoding.Default.GetBytes(serial);
int retval = SetCurrentSerial(Msg.Length, Msg);
if (retval != 0)
{
    // handle error
}

Upvotes: 2

Related Questions