簡體   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