Я неоднократно советовал людям использовать возвращаемое значение типа WideString
для взаимодействия.
Идея состоит в том, что WideString
- это то же самое, что и BSTR
. Поскольку BSTR
выделяется в общей куче COM, то нет проблем с размещением в одном модуле и освобождением в другом модуле. Это потому, что все стороны согласились использовать одну и ту же кучу, кучу COM.
Однако, похоже, что WideString
нельзя использовать в качестве возвращаемого значения функции для взаимодействия.
Рассмотрим следующую DLL-библиотеку Delphi.
library WideStringTest;
uses
ActiveX;
function TestWideString: WideString; stdcall;
begin
Result := 'TestWideString';
end;
function TestBSTR: TBstr; stdcall;
begin
Result := SysAllocString('TestBSTR');
end;
procedure TestWideStringOutParam(out str: WideString); stdcall;
begin
str := 'TestWideStringOutParam';
end;
exports
TestWideString, TestBSTR, TestWideStringOutParam;
begin
end.
и следующий код C ++:
typedef BSTR (__stdcall *Func)();
typedef void (__stdcall *OutParam)(BSTR &pstr);
HMODULE lib = LoadLibrary(DLLNAME);
Func TestWideString = (Func) GetProcAddress(lib, "TestWideString");
Func TestBSTR = (Func) GetProcAddress(lib, "TestBSTR");
OutParam TestWideStringOutParam = (OutParam) GetProcAddress(lib,
"TestWideStringOutParam");
BSTR str = TestBSTR();
wprintf(L"%s\n", str);
SysFreeString(str);
str = NULL;
TestWideStringOutParam(str);
wprintf(L"%s\n", str);
SysFreeString(str);
str = NULL;
str = TestWideString();//fails here
wprintf(L"%s\n", str);
SysFreeString(str);
Сбой вызова TestWideString
с этой ошибкой:
Необработанное исключение в 0x772015de в BSTRtest.exe: 0xC0000005: Место чтения нарушения доступа 0x00000000.
Точно так же, если мы пытаемся вызвать это из C # с помощью p / invoke, у нас возникает ошибка:
[DllImport(@"path\to\my\dll")]
[return: MarshalAs(UnmanagedType.BStr)]
static extern string TestWideString();
Ошибка:
Произошло необработанное исключение типа 'System.Runtime.InteropServices.SEHException' в ConsoleApplication10.exe
Дополнительная информация: внешний компонент выдал исключение.
Вызов TestWideString
через p / invoke работает как положено.
Таким образом, использование передачи по ссылке с параметрами WideString и отображение их на BSTR
, кажется, работает отлично. Но не для функции, возвращающей значения. Я проверил это на Delphi 5, 2010 и XE2 и наблюдаю одинаковое поведение во всех версиях.
Казнь входит в Delphi и почти сразу же перестает работать. Назначение на Result
превращается в вызов на System._WStrAsg
, первая строка которого гласит:
CMP [EAX],EDX
Теперь EAX
равно $00000000
и, естественно, имеет место нарушение прав доступа.
Может кто-нибудь объяснить это? Я делаю что-то неправильно? Разумно ли ожидать, что WideString
значения функций будут жизнеспособными BSTR
с? Или это просто дефект Delphi?