简体   繁体   中英

“ASP.NET web application” and unmanaged DLL

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM