Krzysztof Skowronek
Krzysztof Skowronek

Reputation: 2936

Calling Delphi DLLs from C# and passing bitmap and byte array

I'm trying to call few Delphi functions from C#:

  MyType =array [1 .. 124] of byte
  procedure f(bytes: MyType); stdcall;
  external 'my.dll' name 'f';

That's my first problem. I've tried:

    [DllImport("Delphi/my.dll",
        CallingConvention = CallingConvention.StdCall,
        CharSet = CharSet.Auto)]
    public static extern
    void sygLadSyg([MarshalAs(UnmanagedType.LPArray)] byte[] myArray);
    void sygLadSyg([MarshalAs(UnmanagedType.SafeArray)] byte[] myArray); 

I get exception:

A call to PInvoke function has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.

What am I doing wrong?

Second problem is passing a bitmap.

function sygAnaliz(bitmapa: TBitmap): byte; stdcall;
  external 'awSygnat1.dll' name 'sygAnaliz';
 [DllImport("Delphi/awSygnat1.dll",
            CallingConvention = CallingConvention.StdCall,
            CharSet = CharSet.Ansi)]
        public static extern
        byte sygAnaliz(IntPtr bitmapPtr);
// and call itself
sygAnaliz(firstIMG.GetHbitmap());

I get exception: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

Both functions are memory safe for sure, since they have been used for few years to great effect. Maybe there is something obvious that I miss?

Upvotes: 0

Views: 1166

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 596166

You are not using a COM safe array, so UnmanagedType.SafeArray will not work.

In order to use UnmanagedType.LPArray, you will have to change your Delphi function to this instead:

procedure sygLadSyg(bytes: PByte); stdcall;
begin
  // use bytes as needed, but do not exceed 124 bytes...
end;

And then change your C# declaration to this:

DllImport("Delphi/my.dll",
    CallingConvention = CallingConvention.StdCall)]
public static extern
void sygLadSyg([MarshalAs(UnmanagedType.LPArray, SizeConst=124)] byte[] myArray);

As for your second problem, your Delphi function is accepting a VCL TBitmap object as input, but C# has no concept of that. It is passing a Win32 HBITMAP handle instead, so you need to change your Delphi function accordingly. It can internally create a temp TBitmap object and assign the HBITMAP to its Handle property:

function sygAnaliz(bitmapa: HBITMAP): byte; stdcall;
var
  Bmp: TBitmap;
begin
  try
    Bmp := TBitmap.Create;
    try
      Bmp.Handle := bitmapa;
      // use Bmp as needed...
    finally
      Bmp.Free;
    end;
    Result := ...;
  except
    Result := ...;
  end;
end;

And then the C# declaration should be:

[DllImport("Delphi/awSygnat1.dll",
    CallingConvention = CallingConvention.StdCall)]
public static extern
byte sygAnaliz(IntPtr bitmapPtr);

Upvotes: 6

Related Questions