C # DLL в Inno Setup нарушение прав доступа

Я пытаюсь сослаться на C # DLL в моем проекте InnoSetup. Мне нужна простая функция с одним строковым параметром и строковым возвращаемым значением. Но даже следуя примеру и пробуя разные виды маршалинга, я всегда получаю нарушение прав доступа.

Это мой класс C #:

public class NKToolbox
{
    [DllExport("EncryptPassword", CallingConvention.StdCall)]
    static string EncryptPassword([MarshalAs(UnmanagedType.LPStr)] string password)
    {
        File.WriteAllText(@"C:\temp\test.txt", password);
        return password.Length.ToString();
    }       
}

Я поместил File.WriteAllText, чтобы увидеть, вызывается ли вообще метод. Но нет. Я использую пакет UnmanagedExports от Роберта Гизеке.

И Код установки Inno:

function EncryptPassword(pw: WideString): WideString;
external 'EncryptPassword@files:nktoolbox.dll stdcall';

function InitializeSetup: Boolean;
var
  str: WideString;
begin
  str := EncryptPassword('sdvadfva');
  log(str);
  result := False;
end;

В строке str := EncryptPassword('sdvadfva') я получаю сообщение «Нарушение доступа по адресу ...... Запись адреса .....» Я использую Inno Setup 5.5.9 Unicode.

Я пробовал это с разными операторами маршалинга, которые встречал в других потоках, я пробовал это с ключевым словом out, с нормальным типом string и WideString безнадежно.


person Marco Rebsamen    schedule 23.08.2016    source источник


Ответы (1)


[DllExport("EncryptPassword", CallingConvention.StdCall)]
static string EncryptPassword([MarshalAs(UnmanagedType.LPStr)] string password)

В коде Delphi это соответствует:

function EncryptPassword(password: PAnsiChar): PAnsiChar; stdcall;

Также обратите внимание, что код C # возвращает строку, выделенную вызовом CoTaskMemAlloc. Ожидается, что ваш код освободит этот буфер, вызвав CoTaskMemFree.

Ваш код, импортирующий эту функцию, пытается рассматривать текст как строки COM BSTR. Это совсем не так.

Использование COM BSTR, также известного как WideString, - хорошая идея. Но имейте в виду, что, вероятно, существует несоответствие между C # и Inno, предполагаемым ABI для возвращаемых значений. Лучше использовать параметр out. См. Почему может WideString не может использоваться в качестве возвращаемого значения функции для взаимодействия?

На вашем месте я бы объявил C # так:

[DllExport("EncryptPassword", CallingConvention.StdCall)]
static void EncryptPassword(
    [MarshalAs(UnmanagedType.BStr)] 
    string input
    [MarshalAs(UnmanagedType.BStr)] 
    out string output
)
{
    output = ...;
}       

А Инно был бы таким:

procedure EncryptPassword(input: WideString; out output: WideString);
  external 'EncryptPassword@files:nktoolbox.dll stdcall';

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

person David Heffernan    schedule 23.08.2016
comment
Извините за поздний ответ, до сих пор у меня не было времени его протестировать. Однако это работает как шарм! Спасибо. - person Marco Rebsamen; 24.08.2016