Situation is next: I have “.dll” file written in Delphi. It get string parameter and return it back. If I use this “.dll” in “C#” application for “Windows” - it works fine, but I need to use it in “asp.net web application” and in web application it generate next exceptions:
iisexpress.exe has triggered a breakpoint.
Unhandled exception at 0x77A9E753 (ntdll.dll) in iisexpress.exe: 0xC0000374: A heap has been corrupted (parameters: 0x77AD4270).
Other unmanaged “.dll” files in “asp.net web application” works fine. So I make simple mock “.dll”, using ShareMem and borlandmm.dll:
library Testas;
uses
ShareMem, SysUtils, Classes;
{$R *.res}
function DllTestas(var InputOutput: PAnsiChar): Longint; stdcall;
begin
Result := StrToIntDef(InputOutput, 0);
InputOutput := 'aaaa';
end;
exports
DllTestas;
begin
end.
And simple “asp.net web application”:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Runtime.InteropServices;
namespace WebApplication1
{
public partial class Default : System.Web.UI.Page
{
[DllImport("Testas.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
public static extern int DllTestas([MarshalAsAttribute(UnmanagedType.AnsiBStr)] ref string InputOutput);
protected void Page_Load(object sender, EventArgs e)
{
string InOut = "123";
int result = DllTestas(ref InOut);
Response.Write("Testas.dll:" + "<br />" + result.ToString() + " " + InOut + "<br />" + "<br />");
}
}
}
Properties - “Native Code” is checked and “Platform target” is “x86”.
So this mock code generating the same result.
Question: Where is mistake and how to resolve it?
Suggestion to rewrite “.dll” to “C#” - please, not offer. It was my first idea, but person who make this “.dll” will find 1000 reason why it's impossible, because it's his “bread” and he is not so inspired form idea to learn new language.
Mock “.dll” was compiled with “Delphi 2005” and “Delphi XE5” - result the same. “asp.net web application” - “VS 2013 Ultimate”. I have source of “.dll”.
function DllTestas(var InputOutput: PAnsiChar): Longint; stdcall;
This prototype is doomed to failure. It cannot reasonably be used for interop. The problem is that that there is no clarity over who allocates memory and who is responsible for tidying up.
Your C# interop code is broken and just appears to work in certain scenarios. You cannot hope to proceed this way.
The simplest way to interop strings is to use the COM string, BSTR
which was designed for this purpose. On the C# side pass it as string
with the MarshalAs(UnmanagedType.BStr)
attribute. On the Delphi side use WideString
.
Now, using BSTR
makes it easy to pass strings from unmanaged callee to managed caller. In the other direction the issue doesn't arise. You can use a null terminated string, allocated by the caller. Pass as string
on the C# side and receive as either PAnsiChar
or PWideChar
depending on how you marshalled the string. Then again you may prefer to use a single type for all strings. In which case use BSTR
.
One word of warning. Don't use WideString
as a function return type when doing interop: Why can a WideString not be used as a function return value for interop?
Some examples:
Delphi
library Project1;
procedure Foo(InputVal: PWideChar; out OutputVal: WideString); stdcall;
begin
OutputVal := 'Foo: ' + InputVal;
end;
procedure Bar(InputVal: WideString; out OutputVal: WideString); stdcall;
begin
OutputVal := 'Bar: ' + InputVal;
end;
exports
Foo, Bar;
begin
end.
C#
using System;
using System.Runtime.InteropServices;
namespace ConsoleApplication1
{
class Program
{
const string dllname = @"Project1.dll";
[DllImport(dllname, CharSet = CharSet.Unicode)]
static extern void Foo(
string InputVal,
[MarshalAs(UnmanagedType.BStr)]
out string OutputVal
);
[DllImport(dllname)]
static extern void Bar(
[MarshalAs(UnmanagedType.BStr)]
string InputVal,
[MarshalAs(UnmanagedType.BStr)]
out string OutputVal
);
static void Main(string[] args)
{
string OutputVal;
Foo("Hello", out OutputVal);
Console.WriteLine(OutputVal);
Bar("World", out OutputVal);
Console.WriteLine(OutputVal);
}
}
}
Output
Foo: Hello Bar: World
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.