【问题标题】:“ASP.NET web application” and unmanaged DLL“ASP.NET Web 应用程序”和非托管 DLL
【发布时间】:2015-02-15 23:21:29
【问题描述】:

情况如下: 我有用 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 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 />");
        }
    }
}

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

所以这个模拟代码会产生相同的结果。

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

建议将“.dll”重写为“C#” - 请不要提供。这是我的第一个想法,但是制作这个“.dll”的人会找到 1000 个不可能的理由,因为这是他的“面包”,而他并没有那么灵感来学习新语言。

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

【问题讨论】:

标签: c# asp.net .net delphi dll


【解决方案1】:
function DllTestas(var InputOutput: PAnsiChar): Longint; stdcall;

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

您的 C# 互操作代码已损坏,并且在某些情况下似乎可以正常工作。你不能希望以这种方式进行。

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

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

一句警告。互操作时不要使用WideString作为函数返回类型:Why can a WideString not be used as a function return value for interop?

一些例子:

德尔福

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

输出

福:你好 酒吧:世界

【讨论】:

  • 所以我改了代码:

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

    “C#”:
    [DllImport("Testas.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)] public static extern int DllTestas([MarshalAs(UnmanagedType .BStr)] ref string InputOutput);

    现在是下一条消息:
    源不可用。此模块的调试信息中缺少源信息。您可以在反汇编窗口中查看反汇编。要始终查看缺失源文件的反汇编,请更改“选项”对话框中的设置。
  • 您将无法从 Visual Studio 调试 Delphi 代码。如果要调试Delphi代码,则需要Delphi调试器。
  • 我给你放了样本,它以任何方式生成 - “源不可用”。但是,如果我将您的示例放在 IIS 上,它就可以正常工作。有趣的是,我还有其他“.dll”(没有源代码),它使用“borlandmm.dll”,它不会在“VS”中生成任何异常或消息。所以我认为问题出在“Delphi”代码中。无论如何,代码在 IIS 中运行没有问题,所以我将您的消息标记为答案。
猜你喜欢
  • 2019-08-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-25
  • 1970-01-01
  • 2010-11-28
  • 2012-03-29
相关资源
最近更新 更多