繁体   English   中英

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

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

接下来的情况是:我有用Delphi编写的“ .dll”文件。 它获取字符串参数并将其返回。 如果我在“ 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).

“ asp.net Web应用程序”中的其他非托管“ .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.

和简单的“ 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 />");
        }
    }
}

属性-检查“本机代码”,“平台目标”为“ x86”。

因此,此模拟代码生成相同的结果。

问题:错误在哪里以及如何解决?

建议将“ .dll”重写为“ C#”-请不要提供。 这是我的第一个主意,但是制作此“ .dll”的人会找到1000个无法实现的原因,因为这是他的“面包”,而他并不是学习新语言的灵感源泉。

模拟文件“ .dll”是用“ Delphi 2005”和“ Delphi XE5”编译的-结果相同。 “ asp.net Web应用程序”-“ VS 2013 Ultimate”。 我有“ .dll”的来源。

function DllTestas(var InputOutput: PAnsiChar): Longint; stdcall;

这个原型注定要失败。 它不能合理地用于互操作。 问题是,不清楚谁分配内存以及谁负责整理内存。

您的C#互操作代码已损坏,并且在某些情况下似乎可以使用。 您不能希望以此方式进行。

互操作字符串的最简单方法是使用为此目的而设计的COM字符串BSTR 在C#端,将其作为带有MarshalAs(UnmanagedType.BStr)属性的string传递。 在Delphi端使用WideString

现在,使用BSTR可以轻松地将字符串从非托管被叫方传递给托管呼叫者。 从另一个方向来看,这个问题不会出现。 您可以使用由调用方分配的以空终止的字符串。 在C#端以string传递,并以PAnsiCharPWideChar接收,具体取决于您如何对字符串进行编组。 同样,您可能更喜欢对所有字符串使用单一类型。 在这种情况下,请使用BSTR

一句话警告。 进行互操作时不要将WideString用作函数返回类型: 为什么不能将WideString用作互操作的函数返回值?

一些例子:

德尔福

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);
        }
    }
}

产量

Foo: Hello
Bar: World

暂无
暂无

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

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