Королевство Дельфи"Knowledge itself is power"
F.Bacon
 Лицей
  
Главная
О лицее

Список семинаров

 
 К н и г и
 
Книжная полка
 
 
Библиотека
 
  
  
 


Поиск
 
Поиск по КС
Поиск в статьях
Яndex© + Google©
Поиск книг

 
  
Тематический каталог
Все манускрипты

 
  
Карта VCL
ОШИБКИ
Сообщения системы

 
Форумы
 
Круглый стол
Новые вопросы

 
  
Базарная площадь
Городская площадь

 
   
С Л С

 
Летопись
 
Королевские Хроники
Рыцарский Зал
Глас народа!

 
  
ТТХ
Конкурсы
Королевская клюква

 
Разделы
 
Hello, World!
Лицей

Квинтана

 
  
Сокровищница
Подземелье Магов
Подводные камни
Свитки

 
  
Школа ОБЕРОНА

 
  
Арсенальная башня
Фолианты
Полигон

 
  
Книга Песка
Дальние земли

 
  
АРХИВЫ

 
 

Сейчас на сайте присутствуют:
 
  
 
Во Флориде и в Королевстве сейчас  10:05[Войти] | [Зарегистрироваться]

Урок 10. Строки в COM/DCOM

Антон Григорьев
дата публикации 10-06-2008 09:08

урок из цикла: Использование COM/DCOM в Delphi


предыдущий урок содержание семинара следующий урок

Урок 10. Строки в COM/DCOM

В различных языках программирования используются разные форматы для хранения строк. Поэтому для передачи строк в COM/DCOM потребовался универсальный, не зависящий от языка формат.

Разумеется, ничто не мешает программисту, разрабатывающему сервер на Delphi, использовать, например, строки PChar, завершающиеся нулём. AnsiString и ShortString тоже, в принципе, можно использовать, но это предъявляет дополнительные требования к способу маршалинга (передаче данных из адресного пространства сервера в адресное пространство клиента). Кроме того, не на всяком языке можно написать клиент для работы с такими типами данных — для этого необходима либо их поддержка на уровне компилятора, либо возможности операций с указателями и явного перераспределения памяти, а эти средства есть далеко не во всех языках программирования.

Чтобы подобных проблем не возникало, для передачи строковых параметров следует использовать тип BSTR, который является стандартным строковым типом в COM/DCOM. Все компиляторы, поддерживающие COM/DCOM, обязаны иметь средства для низкоуровневой работы с этим типом и/или его высокоуровневую поддержку.

BSTR расшифровывается как Basic STRing. Такое название он получил потому, что в Visual Basic именно так хранятся строки. Переменная типа BSTR — это указатель на строку символов, причём тип символов зависит от платформы. Так, в Windows BSTR содержит 16-битные символы в кодировке Unicode, а в MacOS — 8-битные. При взаимодействии клиента и сервера, работающих на разных платформах, заглушка и заместитель (о них мы поговорим далее) обеспечивают трансляцию строк из одной кодировки в другую.

По отрицательному смещению от указателя типа BSTR хранит хранится 32-разрядное целое число — длина строки в байтах (а не в символах!). Это позволяет строке содержать нулевые символы в середине. В конце строки тоже должен быть нулевой символ. Это напоминает реализацию типа AnsiString в Delphi с той разницей, что BSTR не имеет счётчика ссылок, поэтому копирование только при необходимости для этого типа не реализовано.

Память для строк типа BSTR должна выделяться с помощью специальных системных функций (SysAllocString, SysReAllocString, SysAllocStringLen и т.п.), а освобождаться — с помощью функции SysFreeString. Для определения длины строки следует использовать функцию SysStringLen. В Delphi эти функции объявлены в модуле ActiveX.

Тип BSTR в Delphi называется TBStr и объявлен он также в модуле ActiveX. Это просто указатель, другое название типа PWideChar. Все операции по выделению и освобождении памяти, копированию строк и т.п. при использовании TBStr должны выполняться вручную.

В Delphi также существует более удобный тип для работы со строками COM/DCOM — это стандартный тип WideString, объявленный в модуле System. При использовании этого типа компилятор неявно вызывает функции SysXXXString для выделения памяти, копирования, сравнения и т.п. Когда переменная типа WideString выходит из области видимости, компилятор автоматически финализирует её, вызывая SysFreeString.

Чтобы понять разницу между TBStr и WideString, рассмотрим несколько примеров. Будем предполагать, что у нас объявлены переменные B1 и B2 типа TBStr и W1 и W2 типа WideString.

B1 := AllocSysString('SomeString');
B2 := B1;

W1 := 'SomeString';
W2 := W1;

Переменной B1 просто присвоить строковую константу нельзя — необходимо явно выделить память для этой строки (которую потом, естественно, так же явно придётся освобождать). При присвоении строковой константы переменной W1 компилятор сам позаботится о выделении для неё памяти, причём сделает это так, чтобы была совместимость с системным BSTR, т.е. через функции для работы с этим типом (в частности, седьмая версия Delphi использует функцию SysReAllocStringLen).

Присвоение B2 := B1 не приводит ни к какому перераспределению памяти — мы просто получаем ещё один указатель, указывающий на ту же самую строку, что и первый. А вот присвоение W2 := W1 приводит к неявному выделению памяти для новой строки и копировании туда старой строки. После выполнения этого присваивания Pointer(W1) <> Pointer(W2).

Оператор сравнения для WideString сравнивает именно строки, а не указатели. Рассмотрим это на конкретном примере.

B1 := AllocSysString('SomeString');
B2 := AllocSysString('SomeString');
if B1 = B2 then ...

W1 := 'SomeString';
W2 := 'SomeString';
if W1 = W2 then ...

В первом случае условие в операторе if будет иметь значение False, потому что B1 и B2 сравниваются как указатели, без учёта содержимого, а они указывают на две разные строки. А вот сравнение W1 и W2 даст True, потому что будет сравниваться именно содержимое строк, а не то, в каком месте памяти они лежат. (При этом, естественно, Pointer(W1) <> Pointer(W2).)

Можно также сравнивать WideString с TBStr, и при этом будет сравниваться содержимое, а не указатели. Так, в вышеприведённом примере сравнение B1 и W1 даст True.

В подавляющем большинстве случаев в Delphi проще использовать WideString, чем TBStr. Исключения бывают в тех случаях, когда для работы со строками используются указатели, имеющие тип, отличный от WideString. Пусть, например, приходится реализовывать метод, имеющий следующий прототип:

function SomeMethod(pBStr: PPointer): HRESULT;

Здесь подразумевается, что pBStr — это указатель на значение типа BSTR, но формально он объявлен как указатель на нетипизированный указатель (для программиста, привыкшего к Delphi, такая конструкция выглядит, по меньшей мере, странно, но когда приходится реализовывать интерфейсы, написанные другими людьми, привыкшими к другим языкам, можно столкнуться и не с такими странностями). И пусть сервер при выполнении данного метода должен создать строку и поместить указатель на неё в pBStr. Рассмотрим гипотетическую реализацию такого метода:

function SomeMethod(pBStr: PPointer): HResult;
var
  ResStr: WideString;
begin
  ResStr := 'SomeString';
  pBStr^ := Pointer(ResStr);
  Result := S_OK
end;

При завершении этого метода компилятор финализирует переменную ResStr, и указатель pBStr^ потеряет свою актуальность. В результате клиент (или заглушка) получит некорректный указатель, что приведёт к ошибке. Чтобы такое не произошло, в данном случае следует отказаться от использования WideString и вызывать функции распределения памяти для строк вручную.

Другой способ решения данной проблемы заключается в изменении прототипа метода таким образом, чтобы на двоичном уровне он оставался совместимым с исходным прототипом, но компилятор понимал, с каким типом данных он на самом деле работает. В данном случае прототип можно сделать таким:

function SomeMethod(out Str: WideString):HResult;

Этот способ достаточно удобен, но пользоваться им нужно с осторожностью, потому что некорректное изменение прототипа может нарушить совместимость.


предыдущий урок содержание семинара следующий урок




Смотрите также материалы по темам:
[Строки] [Технологии ActiveX, COM, DCOM]

 Обсуждение материала [ 11-06-2008 04:25 ] 5 сообщений
  
Время на сайте: GMT минус 5 часов

Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter.
Функция может не работать в некоторых версиях броузеров.

Web hosting for this web site provided by DotNetPark (ASP.NET, SharePoint, MS SQL hosting)  
Software for IIS, Hyper-V, MS SQL. Tools for Windows server administrators. Server migration utilities  

 
© При использовании любых материалов «Королевства Delphi» необходимо указывать источник информации. Перепечатка авторских статей возможна только при согласии всех авторов и администрации сайта.
Все используемые на сайте торговые марки являются собственностью их производителей.

Яндекс цитирования