Веб-приложение ASP.NET, вызывающее библиотеку Delphi DLL на веб-сервере IIS, блокируется при возврате строки PChar - PullRequest
4 голосов
/ 17 февраля 2012

Работает нормально, если я ничего не возвращаю или возвращаю целое число. Но если я попытаюсь вернуть 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 ]

5 голосов
/ 17 февраля 2012

Анализ 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 не может использоваться как возвращаемое значение функции для взаимодействия?

3 голосов
/ 17 февраля 2012

Вы не можете вернуть строку, подобную этой, строка является локальной для функции и будет освобождена, как только функция вернется, оставив возвращенный 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 могла проверить, достаточно ли места для данных, которые будут возвращены.

0 голосов
/ 17 февраля 2012

попробуйте включить 32-разрядные приложения в дополнительных настройках пула приложений:

enter image description here

...