471,089 Members | 1,638 Online
Bytes | Software Development & Data Engineering Community
Post +

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 471,089 software developers and data experts.

Problems with DllImport and a Delphi native DLL.

Hi,

I manage an rather old application in which we have some fairly complex (ugly) Delphi code. This is Delphi 6 we're talking about.

Among all this Delphi code there is method for formating a print layout for slip printers. Pass a few parameters to this method and it returns a Delphi string which contains the entire slip, ready for sending to the slip printer.

Now, we're slowly migrating to .NET and am in need of printing this slip from a .NET application. However instead og re-inventing the wheel for generating this slip, we'd like to create a simple DLL in Delphi which is then consumed by the .NET application.

However, this has turned out to pose a few problems.

================================================== ===
My first attempt at this:

-------------------------
Delphi method prototype:
------------------------
function GetSlipData(
ARegNo: integer;
APrinterID: integer;
ASlipNo: integer) : string; stdcall;

-------------------------
C# DllImport declaration:
-------------------------
[DllImport("SlipPrint.dll",
CharSet = CharSet.Ansi,
CallingConvention = CallingConvention.StdCall)]
[return: MarshalAs(UnmanagedType.LPStr)]
internal static extern string GetSlipData(
int regNo,
int printerId,
int slipId);

This results in a

"Attempted to read or write protected memory. This is often an indication that other memory is corrupt."

Access violation exception.

So, I research and discover that I can't apparently return strings to .NET application through p/invoke, as "strings are immutable". Fair enough, I try using a StringBuilder instead.

================================================== ===
My second attempt at this:

-------------------------
Delphi method prototype:
------------------------
function GetSlipData(
AEkspNr: integer;
APrinterID: integer;
ASlipNo: integer;
var output : string) : integer; stdcall;

-------------------------
C# DllImport declaration:
-------------------------
[DllImport("SlipPrint.dll",
CharSet = CharSet.Ansi,
CallingConvention = CallingConvention.StdCall)]
internal static extern int GetSlipData(
int regNo,
int printerId,
int slipId,
[MarshalAs(UnmanagedType.LPStr)]StringBuilder output);

Now I don't get any exceptions, the method returns the correct length of the string, but the StringBuilder only contains five characters.

You see, the string may very well contain null characters, so how on earth do I solve this problem?

How do I pass a string that may contain null characters from a Delphi DLL to a .NET application?

--
Thomas Due
Posted with XanaNews version 1.18.1.6

"If you want a friend in Washington, get a dog."
-- Harry S. Truman
Jul 4 '07 #1
1 7609
Thomas Due a écrit :
Hi,

I manage an rather old application in which we have some fairly complex (ugly) Delphi code. This is Delphi 6 we're talking about.

Among all this Delphi code there is method for formating a print layout for slip printers. Pass a few parameters to this method and it returns a Delphi string which contains the entire slip, ready for sending to the slip printer.

Now, we're slowly migrating to .NET and am in need of printing this slip from a .NET application. However instead og re-inventing the wheel for generating this slip, we'd like to create a simple DLL in Delphi which is then consumed by the .NET application.

However, this has turned out to pose a few problems.

================================================== ===
My first attempt at this:

-------------------------
Delphi method prototype:
------------------------
function GetSlipData(
ARegNo: integer;
APrinterID: integer;
ASlipNo: integer) : string; stdcall;

-------------------------
C# DllImport declaration:
-------------------------
[DllImport("SlipPrint.dll",
CharSet = CharSet.Ansi,
CallingConvention = CallingConvention.StdCall)]
[return: MarshalAs(UnmanagedType.LPStr)]
internal static extern string GetSlipData(
int regNo,
int printerId,
int slipId);

This results in a

"Attempted to read or write protected memory. This is often an indication that other memory is corrupt."

Access violation exception.
From what I can remember, strings in Pascal (Delphi) are prefixed by
their length, and are allocated (and freed) by specific functions (in
the ShareMem unit).
This conflicts with the definition of strings in .NET, which are null
('\0') terminated, and allocated (and freed) by the .NET environment.

In your case, you want the delphi code to allocate a string, and the
..NET environment (GC) to free it automatically. So you have to choose a
string format that is recognized by both sides : BSTR.

1. Make a wrapper in Delphi for your function that return a BSTR (cf.
http://groups.google.com/group/borla...ff657886892ff).
2. Change your return type attribute to [MarshalAs(UnmanagedType.BStr)]
or [MarshalAs(UnmanagedType.AnsiBStr)] (you will have to determine this
by yourself).

That is all, your original BSTR will be automatically freed by the .NET
environment, calling the proper system API.
>
So, I research and discover that I can't apparently return strings to .NET application through p/invoke, as "strings are immutable". Fair enough, I try using a StringBuilder instead.
I am pretty sure you can. The truth is elsewhere...
>
================================================== ===
My second attempt at this:

-------------------------
Delphi method prototype:
------------------------
function GetSlipData(
AEkspNr: integer;
APrinterID: integer;
ASlipNo: integer;
var output : string) : integer; stdcall;

-------------------------
C# DllImport declaration:
-------------------------
[DllImport("SlipPrint.dll",
CharSet = CharSet.Ansi,
CallingConvention = CallingConvention.StdCall)]
internal static extern int GetSlipData(
int regNo,
int printerId,
int slipId,
[MarshalAs(UnmanagedType.LPStr)]StringBuilder output);

Now I don't get any exceptions, the method returns the correct length of the string, but the StringBuilder only contains five characters.

You see, the string may very well contain null characters, so how on earth do I solve this problem?

How do I pass a string that may contain null characters from a Delphi DLL to a .NET application?
See my answer above. Had there been no null character in your string,
you would very likely have got an exception as well.

Mathieu
Jul 4 '07 #2

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

1 post views Thread by Morten Rasmusssen | last post: by
2 posts views Thread by Leandro H. Delamare | last post: by
4 posts views Thread by erdosa | last post: by
4 posts views Thread by Islamegy | last post: by
13 posts views Thread by lukeharpin | last post: by
1 post views Thread by Brian Anderson | last post: by
2 posts views Thread by Brian Anderson | last post: by
3 posts views Thread by t0x3e8 | last post: by

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.