«Веб-приложение ASP.NET» и неуправляемая DLL

1

Ситуация следующая: у меня есть файл ".dll", написанный в Delphi. Он получает строковый параметр и возвращает его обратно. Если я использую этот ".dll" в приложении "С#" для "Windows" - он отлично работает, но мне нужно использовать его в "веб-приложении asp.net", а в веб-приложении он генерирует следующие исключения:

iisexpress.exe has triggered a breakpoint.

Unhandled exception at 0x77A9E753 (ntdll.dll) in iisexpress.exe: 0xC0000374: A heap has been corrupted (parameters: 0x77AD4270).

Другие неуправляемые файлы ".dll" в "веб-приложении asp.net" отлично работают. Поэтому я делаю простой mock ".dll", используя ShareMem и 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.

И простое "веб-приложение asp.net":

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" на "С#" - пожалуйста, не предлагайте. Это была моя первая идея, но человек, создавший эту ".dll", найдет 1000 причин, почему это невозможно, потому что это его "хлеб", и он не настолько вдохновлен идеей идеи изучать новый язык.

Mock ".dll" был скомпилирован с "Delphi 2005" и "Delphi XE5" - результат тот же. "веб-приложение asp.net" - "VS 2013 Ultimate". У меня есть источник.dll.

  • 1
    Сначала проверьте stackoverflow.com/questions/4163364/… и forums.asp.net/t/…
  • 1
    возможно, dll хорошо работает только в модели STA. Попробуйте: weblog.west-wind.com/posts/2012/Sep/18/…
Показать ещё 5 комментариев
Теги:
dll

1 ответ

2
Лучший ответ
function DllTestas(var InputOutput: PAnsiChar): Longint; stdcall;

Этот прототип обречен на провал. Он не может быть разумно использован для взаимодействия. Проблема в том, что нет ясности относительно того, кто распределяет память и кто несет ответственность за уборку.

Ваш код взаимодействия с С# сломан и просто работает в определенных сценариях. Вы не можете надеяться на продолжение этого пути.

Самый простой способ взаимодействия строк - использовать COM-строку BSTR которая была разработана для этой цели. На стороне С# передать его как string с MarshalAs(UnmanagedType.BStr). На стороне Delphi используйте WideString.

Теперь, используя BSTR легко передать строки от неуправляемого вызываемого абонента управляемому абоненту. В другом направлении вопрос не возникает. Вы можете использовать строку с нулевым завершением, выделенную вызывающим. Передайте string на стороне С# и получите как PAnsiChar и PWideChar зависимости от того, как вы упорядочили строку. Затем снова вы можете использовать один тип для всех строк. В этом случае используйте BSTR.

Одно слово предупреждения. Не используйте WideString в качестве возвращаемого типа функции при выполнении взаимодействия: почему WideString не может использоваться как возвращаемое значение функции для взаимодействия?

Некоторые примеры:

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.

С#

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
  • 0
    Поэтому я изменил код: <br/> <br/> function DllTestas (var InputOutput: WideString): Longint; stdcall; <br/> <br/> «C #»: <br/> [DllImport ("Testas.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)] общедоступный статический extern int DllTestas ([MarshalAs (UnmanagedType) .BStr)] ref string InputOutput); <br/> <br/> и теперь сообщение следующее: <br/> Источник недоступен. Исходная информация отсутствует в отладочной информации для этого модуля. Вы можете просмотреть дизассемблирование в окне Разборка. Чтобы всегда просматривать разборку для отсутствующих исходных файлов, измените настройку в диалоговом окне «Параметры».
  • 0
    Вы не сможете отлаживать код Delphi из Visual Studio. Если вы хотите отладить код Delphi, вам нужен отладчик Delphi.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню