简体   繁体   English

“ ASP.NET Web应用程序”和非托管DLL

[英]“ASP.NET web application” and unmanaged DLL

Situation is next: I have “.dll” file written in Delphi. 接下来的情况是:我有用Delphi编写的“ .dll”文件。 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: 如果我在“ Windows”的“ C#”应用程序中使用此“ .dll”-可以正常工作,但是我需要在“ asp.net Web应用程序”中使用它,并且在Web应用程序中会生成下一个异常:

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. “ asp.net Web应用程序”中的其他非托管“ .dll”文件运行正常。 So I make simple mock “.dll”, using ShareMem and borlandmm.dll: 因此,我使用ShareMem和borlandmm.dll制作了简单的模拟“ .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”: 和简单的“ asp.net Web应用程序”:

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”. 属性-检查“本机代码”,“平台目标”为“ 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. 建议将“ .dll”重写为“ C#”-请不要提供。 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. 这是我的第一个主意,但是制作此“ .dll”的人会找到1000个无法实现的原因,因为这是他的“面包”,而他并不是学习新语言的灵感源泉。

Mock “.dll” was compiled with “Delphi 2005” and “Delphi XE5” - result the same. 模拟文件“ .dll”是用“ Delphi 2005”和“ Delphi XE5”编译的-结果相同。 “asp.net web application” - “VS 2013 Ultimate”. “ asp.net Web应用程序”-“ VS 2013 Ultimate”。 I have source of “.dll”. 我有“ .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. 您的C#互操作代码已损坏,并且在某些情况下似乎可以使用。 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. 互操作字符串的最简单方法是使用为此目的而设计的COM字符串BSTR On the C# side pass it as string with the MarshalAs(UnmanagedType.BStr) attribute. 在C#端,将其作为带有MarshalAs(UnmanagedType.BStr)属性的string传递。 On the Delphi side use WideString . 在Delphi端使用WideString

Now, using BSTR makes it easy to pass strings from unmanaged callee to managed caller. 现在,使用BSTR可以轻松地将字符串从非托管被叫方传递给托管呼叫者。 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. 在C#端以string传递,并以PAnsiCharPWideChar接收,具体取决于您如何对字符串进行编组。 Then again you may prefer to use a single type for all strings. 同样,您可能更喜欢对所有字符串使用单一类型。 In which case use BSTR . 在这种情况下,请使用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? 进行互操作时不要将WideString用作函数返回类型: 为什么不能将WideString用作互操作的函数返回值?

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# 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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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