Discussion:
Need helping passing from C# to Delphi
(too old to reply)
Capt Laser Man
2008-12-03 04:14:36 UTC
Permalink
I have two methods I need to call in a Delphi DLL. They are bother pretty
simple but I am getting access errors so I must be doing something wrong.

The first function and documentation is:

function MLParams(h: word; c: word; p: PChar): boolean; stdcall;
p is a pointer to a Params structure
Params= packed record
size: word;
pointrate: longint;
invertblanking: boolean;
end;
size is the size in bytes of the complete structure.

The second is:
function MLDraw(h, c: word; d: PChar; n: integer): boolean; stdcall;
For a frame oriented device (Riya PCI Pro for example) this function is
called for each frame.
D is a pointer to an array with n points
Point= packed record
x,y,z: word;
r,g,b: byte;
reserved1, reserved2, reserved3: byte;
intensity, reserved4, repeatpoint: byte;
end;
I defined my functions as:

[DllImport(@".\drivers\EasyLase.mld")]private static extern bool
MLDraw(ushort handle, ushort c, LaserPoint[] dataPointer, int size);

[DllImport(@".\drivers\EasyLase.mld")]private static extern bool
MLParams(int handle, int c, ref Params mlParams);

[StructLayout(LayoutKind.Sequential, Pack = 1)]

struct Params

{

public ushort size;

public int pointRate;

public bool invertBlanking;

}

[StructLayout(LayoutKind.Sequential, Pack = 1)]

public struct LaserPoint

{

public ushort x;

public ushort y;

public byte r;

public byte g;

public byte b;

public byte reserved1;

public byte reserved2;

public byte reserved3;

public byte intensity;

public byte reserved4;

public byte repeatpoint;

}



Do you see anything wrong? Sorry about the weird spacing. That happened
when I copied and pasted and I couldn't make the double spacing go away.

Thanks,

Gary
Eusebiu
2008-12-07 09:05:00 UTC
Permalink
Hello...
First I want to say that I never invoked a Delphi dll but I invoked C++
dlls...

You can try using the Marshal class and it's static methods...
So you can modify you code like this...
[DllImport(@".\drivers\EasyLase.mld")]private static extern bool
MLDraw(ushort handle, ushort c, ref IntPtr dataPointer, int size);
and when you want to call this method you must allocate some memory for data
pointer... like this:
IntPtr dataPointer = Marshar.AllocHGlobal(3*Marshal.Sizeof(typeof(ushort)) +
9 * Marshal.Sizeof(typeof(byte)));
After this you must copy the data to newly allocated memory... using
Marshal.Copy method... like this,,
Marshal.Copy(BitConverter.GetBytes(x), 0, dataPointer,
Marshal.SizeOf(ushort));
Marshal.Copy(BitConverter.GetBytes(y), 1*Marshal.SizeOf(typeof(ushort)),
dataPointer, Marshal.SizeOf(typeof(ushort)));
Marshal.Copy(BitConverter.GetBytes(z), 2*Marshal.SizeOf(typeof(ushort)),
dataPointer, Marshal.SizeOf(typeof(ushort)));

Marshal.Copy(new byte[] {r}, 3* Marshal.SizeOf(typeof(ushort)), dataPointer,
Marshal.SizeOf(typeof(byte)));
Marshal.Copy(new byte[] {g}, 3*Marshal.SizeOf(typeof(ushort)) +
Marshal.SizeOf(typeof(byte)), dataPointer, Marshal.SizeOf(typeof(byte)));
Marshal.Copy(new byte[] {b}, 3*Marshal.SizeOf(typeof(ushort)) +
2*Marshal.SizeOf(typeof(byte)), dataPointer, Marshal.SizeOf(typeof(byte)));
and so on for every field in your structure...

After the call, you WILL call Marshal.FreeHGlobal(dataPointer);... I guess
you hate memory leaks, too.. :)

So this solution is marshaling data by hand...(I hope I've written the code
correctly... )

Of course, you can use Marshal::StructureToPtr method for not so complex
structures like yours... it's easier.. :)

What I am trying to say is that sometimes you can't just pass an array of
structures to "the other side".. you have to work a little .. :)....

Oh.. I guess that the Delphi dll is compiled with the same pack size... right?
Capt Laser Man
2008-12-08 00:21:14 UTC
Permalink
Hi,

Thanks for taking the time to write out that information. I managed to get
things working already, though. The code I posted turned out to be correct.
The problem was in my structure definition. I accidently left out a field
so everything was out of whack.

Calling a Delphi DLL is the same as calling a C DLL as far as I can tell.

On other problem I have is I have not figured out how to return a structure
from a DLL. I have another funtion that returns a pointer to a structure
and cannot get it to work. I tried writing my interop function so it
accepts a structure as a return value but this does not even compile. When
I tried to return an IntPtr my app just crashes.
Post by Eusebiu
Hello...
First I want to say that I never invoked a Delphi dll but I invoked C++
dlls...
You can try using the Marshal class and it's static methods...
So you can modify you code like this...
MLDraw(ushort handle, ushort c, ref IntPtr dataPointer, int size);
and when you want to call this method you must allocate some memory for data
IntPtr dataPointer = Marshar.AllocHGlobal(3*Marshal.Sizeof(typeof(ushort)) +
9 * Marshal.Sizeof(typeof(byte)));
After this you must copy the data to newly allocated memory... using
Marshal.Copy method... like this,,
Marshal.Copy(BitConverter.GetBytes(x), 0, dataPointer,
Marshal.SizeOf(ushort));
Marshal.Copy(BitConverter.GetBytes(y), 1*Marshal.SizeOf(typeof(ushort)),
dataPointer, Marshal.SizeOf(typeof(ushort)));
Marshal.Copy(BitConverter.GetBytes(z), 2*Marshal.SizeOf(typeof(ushort)),
dataPointer, Marshal.SizeOf(typeof(ushort)));
Marshal.Copy(new byte[] {r}, 3* Marshal.SizeOf(typeof(ushort)), dataPointer,
Marshal.SizeOf(typeof(byte)));
Marshal.Copy(new byte[] {g}, 3*Marshal.SizeOf(typeof(ushort)) +
Marshal.SizeOf(typeof(byte)), dataPointer, Marshal.SizeOf(typeof(byte)));
Marshal.Copy(new byte[] {b}, 3*Marshal.SizeOf(typeof(ushort)) +
2*Marshal.SizeOf(typeof(byte)), dataPointer,
Marshal.SizeOf(typeof(byte)));
and so on for every field in your structure...
After the call, you WILL call Marshal.FreeHGlobal(dataPointer);... I guess
you hate memory leaks, too.. :)
So this solution is marshaling data by hand...(I hope I've written the code
correctly... )
Of course, you can use Marshal::StructureToPtr method for not so complex
structures like yours... it's easier.. :)
What I am trying to say is that sometimes you can't just pass an array of
structures to "the other side".. you have to work a little .. :)....
Oh.. I guess that the Delphi dll is compiled with the same pack size... right?
Eusebiu
2008-12-08 06:56:04 UTC
Permalink
Hello....
An IntPtr is nothing more than a int32.
So you'll have to use marshaling from unmanaged to managed... like
Marshal.PtrToStructure or do it by hand with Marshal.Copy...

Loading...