COM Callable Wrapper не работает при вызове из программы Delphi

Мне было предложено создать.Net DLL для старой программы Delphi. Я пытаюсь сделать это с COM Callable Wrapper, но я продолжаю получать сообщение об ошибке, когда он пытается загрузить DLL (довольно общий, что-то вроде "Я не мог загрузить DLL"). Вот что говорится в технической документации:

The DLL only needs to export one function under the name 'AUTHORIZE'.

function Authorize(InXml: PChar): PChar; stdcall;
(Delphi syntax. May be different in other languages.)

Вот мой код для CCW:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace ComCallableWrapper
{
    [Guid("C3FD922A-FB44-47B1-9C0C-8F7FAF57098B")]
    [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
    public interface IAuthorizer
    {
        [DispId(1)]
        string Authorize(string lnpInXml);
    }

    [ProgId("ComCallableWrapper.Authorizer")]
    [ClassInterface(ClassInterfaceType.None)]
    public class Authorizer : IAuthorizer
    {
        public Authorizer()
        {
        }

        public string Authorize(string lnpInXml)
        {
            return "Approved!";
        }
    }
}

Я также запускаю эту команду "regasm /tlb:ComCallableWrapper.tlb ComCallableWrapper.dll /codebase" на компьютере, на котором выполняется программа delphi.

Я провел некоторое исследование на Google о том, как Delphi вызывает функции на DLL, и я нашел по крайней мере 2 способа:

function Authorize(lnpInXml: pchar): pchar; stdcall; external 'DLLName.dll';

а также

oleObject := CreateOleObject('ComCallableWrapper.Authorizer');
ShowMessage(oleObject.Authorize('Approved?'));

Похоже, COM работает немного по-другому. Есть ли способ изменить мой CCW, чтобы он работал как первый?

С уважением.

1 ответ

Решение

Вам не нужен COM. И действительно, использование COM является ошибкой, потому что программа Delphi не ищет COM DLL.

Что вам нужно сделать, это экспортировать неуправляемую функцию из вашей управляемой C# DLL. Это немного сложно и на самом деле не поддерживается. Это ваши самые привлекательные варианты:

  1. Используйте UnmanagedExports Роберта Гизеке.
  2. Напишите C++/CLI DLL в смешанном режиме, которая использует ваш код C#. Смешанный режим C++ / CLI способен экспортировать собственные функции, используя __declspec(dllexport).def файлы и т. д.

Если вы решили использовать UnmanagedExports, функция будет выглядеть следующим образом:

[DllExport]
public static IntPtr Authorize(string InXml)
{
    // your code goes here, for now return the input value
    return Marshal.StringToHGlobalAnsi(InXml);
}

Реализация функции немного сложнее, потому что вам нужно вернуть Delphi PAnsiChar это C++ char*, Вы не можете использовать string для типа возврата и должны использовать IntPtr, Но как вы распределяете строку так, чтобы она оставалась действительной для вызывающей стороны? Приведенный выше код пропускает строку в HGLOBAL,

Я не могу дать вам окончательный совет, как разрешить время жизни строки. Интерфейс, для которого вы кодируете, не очень хорошо разработан. Только вы с большим знанием интерфейса в состоянии решить эту проблему.

Другие вопросы по тегам