0

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?

Rudy Velthuis
  • 28,387
  • 5
  • 46
  • 94
Krzysztof Skowronek
  • 2,796
  • 1
  • 13
  • 29

1 Answers1

6

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);
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Thank you for your answer. As for first question, yes, I've tried void sygLadSyg([MarshalAs(UnmanagedType.LPArray)] byte[] myArray);, it did not work. I ended up disabling stack imbalance exception and now program proceeds and I think does what it should. As for bitmap, I don't have Delphi sources so I can't check it right now. I will contact the author and see if we can modify it a little. Still, great answer :) – Krzysztof Skowronek Feb 24 '16 at 19:08
  • @user disabling stack imbalance mda is a huge mistake. You clearly have no appreciation for what you are doing. Remy's answer is correct and you should accept it. – David Heffernan Feb 24 '16 at 19:16
  • @Remy `procedure f(const bytes: MyType); stdcall;` would also be an option – David Heffernan Feb 24 '16 at 19:18
  • Well, no offence intended, guys. It's just my last few days passed on trying to solve this issues. This is not the first exception I gave turned off (http://stackoverflow.com/questions/56642/loader-lock-error , this is just for now, since I just want to get those DLL working, later on I want to use them in much bigger application) and given answer did not help me, since it was a scenario I have already tried. When I will check bitmap answer and it works, of course I will mark post as answer :) – Krzysztof Skowronek Feb 24 '16 at 20:58
  • What Remy wrote is accurate, you can't have done what he said. – David Heffernan Feb 24 '16 at 21:49
  • @user3512524: If a stack imbalance error occurs, you have a mismatch somewhere. Disabling the stack imbalance exception is simply hiding the error, the code is still broken and not "working" correctly. Corrupting the stack is going to cause lots of problems, and not all of them are immediate or apparent, they can also be subtle and take time to crop up - long after the original code has finished and moved on. – Remy Lebeau Feb 24 '16 at 22:18
  • Presumably you changed the C# code but left the Delphi code that expected the array to be passed by value on the stack. That cannot be called from C# and the Delphi code has to change. As Remy described. The system told you that your code was wrong. Inserting ear plugs does not correct the problem. – David Heffernan Feb 25 '16 at 07:36
  • Thanks, I have just realized pbyte type in your declaration. I will try that one too. Thanks a lot guys :) – Krzysztof Skowronek Feb 25 '16 at 19:31
  • You'll need to re-enable the warnings that you've suppressed – David Heffernan Feb 26 '16 at 07:50