Читаем Сущность технологии СОМ. Библиотека программиста полностью

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

Важно отметить, что приведенный выше метод IDL задает многомерный массив; формально он представляет собой массив указателей на массив указателей на экземпляры. Это не то же самое, что многомерный массив в языке С, который может быть определен в IDL с использованием стандартного синтаксиса С:

HRESULT Method23([in] short rgrgs[3][4]);

Данный синтаксис предполагает, что все элементы массива будут размещены в памяти непрерывно, что определенно не совпадает с предположением предыдущего примера.

Допускается задавать первое измерение многомерного массива с помощью атрибута [size_is]:

HRESULT Method24([in, size_is(3)] short rgrgs[][4]);

однако нельзя задавать никакого иного измерения, кроме крайнего левого.

Выражения, использованные атрибутами [size_is], [length_is] и другими атрибутами задания размерности массива, не могут быть размещены в вызовах функций. При этом, например, стал бы затруднительным маршалинг строк, соответствие и/или переменная длина которых размещены в вызовах функций wcslen или strlen. Это означает, что такой код в IDL является недопустимым:

HRESULT Method24([in, size_is(wcslen(wsz) + 1)] const OLECHAR *wsz);

Поскольку это ограничение сделало бы использование строк чрезвычайно неудобным для клиентских программ, IDL поддерживает строковый атрибут, который требует на уровне маршалинга вызывать соответствующую функцию xxxlen для вычисления соответствия массива. Ниже приведено правильное задание строки в качестве входного параметра:

HRESULT Method25([in, string] const OLECHAR *wsz);

или:

HRESULT Method26([in, string] const OLECHAR wsz[]);

При использовании строк в качестве выходных или входных/выходных параметров почти всегда целесообразно явно задавать длину буфера вызывающей программы, для гарантии того, что он будет достаточно большим на стороне сервера. Рассмотрим следующий полный ошибок код IDL:

HRESULT Method27([in, out, string] OLECHAR *pwsz);

Если вызывающая программа запускает этот метод с помощью достаточно короткой строки:

void f(IFoo *pFoo)

{

OLECHAR wsz[1024];

wcscpy(wsz, OLESTR(«Hello»));

pFoo->Method27(wsz);

// .. process updated string

// .. обрабатываем обновленную строку

}

то длина массива, размещенного на стороне сервера, будет вычислена, исходя из длины входной строки (эта длина равна шести с учетом заключительного нулевого символа). Рассмотрим следующую реализацию метода со стороны сервера:

HRESULT CFoo::Method27(OLECHAR *wsz)

{

DisplayString(wsz);

// wsz only can hold 6 characters!

// wsz может хранить только 6 символов!

wcscpy(wsz, OLESTR(«Goodbye»));

return S_OK;

}

Поскольку соответствие массива основывалось на величине wcslen(OLESTR(«Hello»)+1), то, когда реализация метода перезапишет в данную строку что-то более длинное, «хвост» этой строки перезапишет случайное число байтов памяти, что приведет к неисправимым ошибкам (будем надеяться, еще до выпуска данной программы в свет). Это означает, что, хотя вызывающая программа и имела достаточно памяти, заранее выделенной для записи результирующей строки, уровень маршалинга со стороны сервера не знал об этой кажущейся внешней памяти и выделил место, достаточное для хранения только шести символов строки Unicode. Код на IDL должен был быть таким:

HRESULT Method28([in] long cchMax, [in, out, string, size_is(cchMax)] OLECHAR *wsz);

а вызывающая программа могла бы использовать это так:

void f(IFoo *pFoo)

{

OLECHAR wsz[1024];

wcscpy(wsz, OLESTR(«Hello»));

pFoo->Method28(1024, wsz);

// .. process updated string

// .. обрабатываем обновленную строку

}

Наиболее неприятным аспектом примера c [in, out, string] является то, что он прекрасно работает, когда входная строка имеет по крайней мере такую же длину, как выходная строка. Ошибки, связанные с этим методом, будут периодическими и могут ни разу не возникнуть на стадии тестирования проекта.

В большинстве обычных API-функций, когда функция возвращает в вызывающую программу данные переменной длины, вызывающая программа заранее выделяет буфер для хранения результатов функции, а реализация функции заполняет буфер, заготовленный вызывающей программой. Ответственность за задание правильного размера буфера лежит на вызывающей программе. При использовании заданных вызывающей программой буферов для возвращения структур данных переменной длины (таких, как строки) может возникнуть проблема. Возможно, реализация метода захочет возвратить больше данных, чем ожидает вызывающая программа. Рассмотрим следующий код Windows SDK, который отображает текст редактирующего управляющего элемента, то есть текстового окна, позволяющего набирать и редактировать текст:

void Show(HWND hwndEdit)

{

TCHAR sz[1024];

GetWindowText(hwndEdit, sz, 1024);

MessageBox(0, sz, _TEXT(«Hi!»), MB_OK);

}

Перейти на страницу:

Похожие книги

1С: Бухгалтерия 8 с нуля
1С: Бухгалтерия 8 с нуля

Книга содержит полное описание приемов и методов работы с программой 1С:Бухгалтерия 8. Рассматривается автоматизация всех основных участков бухгалтерии: учет наличных и безналичных денежных средств, основных средств и НМА, прихода и расхода товарно-материальных ценностей, зарплаты, производства. Описано, как вводить исходные данные, заполнять справочники и каталоги, работать с первичными документами, проводить их по учету, формировать разнообразные отчеты, выводить данные на печать, настраивать программу и использовать ее сервисные функции. Каждый урок содержит подробное описание рассматриваемой темы с детальным разбором и иллюстрированием всех этапов.Для широкого круга пользователей.

Алексей Анатольевич Гладкий

Программирование, программы, базы данных / Программное обеспечение / Бухучет и аудит / Финансы и бизнес / Книги по IT / Словари и Энциклопедии
1С: Управление торговлей 8.2
1С: Управление торговлей 8.2

Современные торговые предприятия предлагают своим клиентам широчайший ассортимент товаров, который исчисляется тысячами и десятками тысяч наименований. Причем многие позиции могут реализовываться на разных условиях: предоплата, отсрочка платежи, скидка, наценка, объем партии, и т.д. Клиенты зачастую делятся на категории – VIP-клиент, обычный клиент, постоянный клиент, мелкооптовый клиент, и т.д. Товарные позиции могут комплектоваться и разукомплектовываться, многие товары подлежат обязательной сертификации и гигиеническим исследованиям, некондиционные позиции необходимо списывать, на складах периодически должна проводиться инвентаризация, каждая компания должна иметь свою маркетинговую политику и т.д., вообщем – современное торговое предприятие представляет живой организм, находящийся в постоянном движении.Очевидно, что вся эта кипучая деятельность требует автоматизации. Для решения этой задачи существуют специальные программные средства, и в этой книге мы познакомим вам с самым популярным продуктом, предназначенным для автоматизации деятельности торгового предприятия – «1С Управление торговлей», которое реализовано на новейшей технологической платформе версии 1С 8.2.

Алексей Анатольевич Гладкий

Финансы / Программирование, программы, базы данных