Устранение проблемы с NULL в COM-общении между C# и Delphi XE5: Путь к корректному передачи строк
При работе с COM-серверами, созданными в среде Delphi, иногда возникают проблемы, связанные с передачей строковых значений. В частности, при обмене данными между C# и Delphi XE5, пустое строковое значение может быть преобразовано в NULL, что приводит к ошибкам при выполнении программы. Рассмотрим, как можно решить эту проблему, опираясь на пример из контекста.
Проблема
Пользователь определил в C# интерфейс для COM-сервера:
Этот интерфейс импортируется и реализуется в программе на Delphi XE5:
IMyInterface = interface(IUnknown)
['{58C77969-0E7D-3778-9999-B7716E4E1111}']
function Get_MyName(out pRetVal: WideString): HResult; stdcall;
end;
type
TMyImpl = class(TInterfacedObject, IMyInterface)
public
function Get_MyName(out pRetVal: WideString): HResult; stdcall;
end;
function TMyImpl.Get_MyName(out pRetVal: WideString): HResult;
var
s: string;
begin
s := '';
pRetVal := s;
Result := S_OK;
end;
При вызове сервера из C#:
var server = new Server();
string s = server.MyName;
Переменная s принимает значение NULL вместо ожидаемой пустой строки.
Решение
Delphi по умолчанию обрабатывает пустые строки как NULL указатели. Для корректной передачи пустых строк в COM, необходимо использовать функцию SysAllocString(''), которая выделяет память под пустую строку:
function TMyImpl.Get_MyName(out pRetVal: WideString): HResult;
var
BStr: TBstr;
begin
BStr := SysAllocString('');
if Assigned(BStr) then
begin
Pointer(pRetVal) := BStr;
Result := S_OK;
end
else
Result := E_FAIL;
end;
Или можно создать вспомогательную функцию:
function EmptyWideString: WideString;
begin
Pointer(Result) := SysAllocString('');
end;
Альтернативное решение
Если интерфейс генерируется автоматически и изменять его напрямую нежелательно, можно попробовать изменить тип параметра в Delphi на BSTR:
IMyInterface = interface(IUnknown)
['{58C77969-0E7D-3778-9999-B7716E4E1111}']
function Get_MyName(out pRetVal: BSTR): HResult; stdcall;
end;
function TMyImpl.Get_MyName(out pRetVal: BSTR): HResult;
begin
pRetVal := SysAllocString('');
Result := S_OK;
end;
Для обработки возможной ошибки при выделении памяти можно использовать следующий код:
function TMyImpl.Get_MyName(out pRetVal: BSTR): HResult;
begin
pRetVal := SysAllocString('');
Result := IfThen(Assigned(pRetVal), S_OK, E_FAIL);
end;
Также стоит отметить, что Delphi может обрабатывать пустые WideString как NULL, что является, по мнению некоторых разработчиков, дефектом.
Заключение
Для устранения проблемы с передачей строк в COM между C# и Delphi XE5, необходимо использовать функцию SysAllocString('') для выделения памяти под пустую строку. Это позволит корректно передавать пустые строки, вместо преобразования их в NULL. Если интерфейс генерируется автоматически, можно использовать каст или постобработку интерфейса.
Проблема связана с корректной передачей строковых значений между C# и Delphi XE5 через COM, когда пустые строки некорректно интерпретируются как NULL, что приводит к ошибкам в программе.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.