1

I'm new in programming, Can someone help me call a pointer function from a delphi dll into Visual C# function.

Here is the Delphi Function stored into the DLL. // Delphi Code Stored in the DLL

function DeviceName(Size : Integer; Msg : Pointer) : Integer stdcall;
var
  i: Integer;
  TempByte : PByte;
  TempName : string;
begin
  if DLLClass.DevList.HidDevices.Count > 0 then
  begin
    TempName := (DLLClass.DevList.HidDevices.Name[DLLClass.HIDTool.CurrentDeviceIndex]);
    if Length(TempName) <= Size then
    begin
      try
        TempByte := Msg;
        for i := 0 to Length(TempName) - 1 do
        begin
          TempByte^ := Ord(TempName[i+1]);
          Inc(TempByte)
        end;
        Result := Length(TempName);
      except
        Result := -2;
      end;
    end
    else
    begin
      Result := -3;
    end;
  end
  else
  begin
    Result := -1;
  end;
end;

//C# Code ` //Import a Function Pointer

[DllImport("HID_DLL.dll", CallingConvention= CallingConvention.StdCall,  CharSet = CharSet.Ansi)]
public unsafe static extern int DeviceName(IntPtr Size, [MarshalAs(UnmanagedType.LPStr)] string Msg);



unsafe static void Main()
{
byte[] buffer = new byte[32768];

       DeviceName(255, &**buffer);

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

`

1
  • It does compiles, what i'm getting on the cmd line is not what i'm expecting. The end result would be for my code to detect the USB HID Device attached a print its name on the screen as the delphi code discribe. Commented Nov 17, 2014 at 12:23

1 Answer 1

2

This Delphi function is kind of messy. Its job is to copy a string into a buffer supplied by the caller. Normally that is done using null-terminated strings but the Delphi code does not do so.

Assuming that the Delphi code cannot be modified, here's how to call it from C#. Note that you don't need unsafe code here and I recommend that you stop using unsafe code.

First of all the p/invoke declaration:

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

The Size parameter has type Integer in Delphi. That's a 32 bit integer in C#. So use int, just as you did for the return value. Don't use IntPtr which is an integer whose size equals that of a pointer. That is incorrect in a 64 bit process. The Msg parameter should be allocated as a byte array since you are not adding a null-terminator. And that in turn means there is no need to specify CharSet.

Now the call:

byte[] Msg = new byte[256];
int retval = DeviceName(Msg.Length, Msg);
if (retval < 0)
{
    // handle error
}
else
{
    string name = Encoding.Default.GetString(Msg, 0, retval);
}

Your Delphi function is poorly designed though. As mentioned already, it is customary to use null-terminated strings in this scenario. Doing so allows you to let the p/invoke marshaller deal with the boiler plate code. Your error codes are poor also. If the user passes a size that is insufficient to store the string, you should let them know how much space is required.

The implementation of the Delphi function is also sub-optimal. Rather than copying byte-by-byte, you should copy the entire buffer in one shot.

One final piece of advice. Your function returns values indicating whether or not it succeeded. Your C# code simply ignores those return values. As a broad rule, if a function returns a value, you ought to be heeding it. Especially when you are performing interop, and the return value indicates success or failure.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.