Веб-приложение ASP.NET, вызывающее библиотеку Delphi DLL на веб-сервере IIS, блокируется при возврате строки PChar
Работает нормально, если я ничего не возвращаю, или я возвращаю целое число. Но если я попытаюсь вернуть PChar, т.е.
result := PChar('') or result:= PChar('Hello')
Веб-приложение просто зависает, и я наблюдаю, как его количество памяти постепенно увеличивается в диспетчере задач.
Странно то, что DLL работает нормально на сервере отладки VStudio или через приложение C#. Единственное, что я могу придумать, - это то, что сервер IIS работает в 64-битной Windows.
Это не похоже на проблему совместимости, потому что я могу успешно писать в текстовые файлы и делать другие вещи из DLL... Я просто НЕ могу вернуть строку PChar.
Пробовал использовать PWideChar, пытался вернуть 'что-то \0', пробовал все, что мог придумать. Не повезло, к сожалению.
[DllImport("TheLib.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
private static extern string SomeFunction();
string result = SomeFunction();
Дельфи:
library TheLib;
function SomeFunction() : PChar export; stdcall;
begin
return PChar('');
end;
exports
SomeFunction
3 ответа
Анализ Dampsquid является правильным, поэтому я не буду повторять это. Однако я предпочитаю другое решение, которое я считаю более элегантным. Мое предпочтительное решение для такой проблемы состоит в том, чтобы использовать Delphi Widestring
который является BSTR
,
На стороне Delphi вы пишете это так:
function SomeFunction: Widestring; stdcall;
begin
Result := 'Hello';
end;
А на стороне C# вы делаете это так:
[DllImport(@"TheLib.dll")]
[return: MarshalAs(UnmanagedType.BStr)]
private static extern string SomeFunction();
И это все. Поскольку обе стороны используют один и тот же COM-распределитель для выделения памяти, все это просто работает.
Обновление 1
@NoPyGod интересно указывает, что этот код завершается с ошибкой во время выполнения. Посмотрев на это, я чувствую, что это проблема в конце Delphi. Например, если мы оставим код C# как есть и будем использовать следующее, ошибки будут устранены:
function SomeFunction: PChar; stdcall;
begin
Result := SysAllocString(WideString('Hello'));
end;
Казалось бы, Delphi возвращает значения типа WideString
не обрабатываются, как они должны быть. Выходные параметры и параметры var обрабатываются так, как ожидалось. Я не знаю, почему возвращаемые значения терпят неудачу таким образом.
Обновление 2
Оказывается, что Delphi ABI для WideString
возвращаемые значения не совместимы с инструментами Microsoft. Вы не должны использовать WideString
в качестве типа возврата, вместо этого верните его через out
параметр. Для получения дополнительной информации см. Почему WideString не может использоваться как возвращаемое значение функции для взаимодействия?
Вы не можете вернуть строку, подобную этой, строка является локальной для функции и будет освобождена, как только она вернется, оставив возвращенный PChar, указывающий на неверное местоположение.
вам нужно передать указатель для заполнения внутри DLL, динамически создать строку и освободить ее обратно в коде C# или создать статический буфер в вашей DLL и вернуть его.
Безусловно, самый безопасный способ - передать указатель на функцию, т.е.
function SomeFunction( Buffer: PChar; MaxLength: PInteger ): wordbool; stdcall;
{
// fill in the buffer and set MaxLength to length of data
}
Вы должны установить MaxLength в шестерку буфера перед вызовом вашей dll, чтобы dll могла проверить, достаточно ли места для данных, которые будут возвращены.
Попробуйте включить 32-битные приложения в расширенных настройках пула приложений: