Здравствуйте.
Задача простая: передать память обекта TMemoryStream c COM-сервера на клиент (живут на разных компьютерах).
Решил так: создаю массив (встроенный динамический), заполняю из MemoryStream,
присваиваю вариантной переменной, отправляю.
Мне кажется, что это решение - тормоз. Нет ли других возможностей?
И более общий вопрос: каким способом лучше всего передавать массивы данных такого рода
от одного приложения другому, работающим на разных компьютерах. Если есть ссылки на
документацию - сбросьте пожалуйста.
Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице. Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.
20-05-2004 14:58
Для КоньВПальто
Отправил.
Она этого не понимает?
Если да, то значит библиотеку нужно писать на С/С++ и компилировать, как вы говорили, midl.exe?..
Не знаю, может, есть способ. Никогда не писал COM-серверы на Delphi.
С удовольствием прочитаю, спасибо.
Мой ящик, не трудно догадаться, CoatedHorse@mail.ru :)
Набираю в редакторе библиотеки типов:
HRESULT SendArray([in]int ElementSize; [in,size_is(ElementSize)] int* Element[]);
а Delphi ругается на size_is...
Она этого не понимает?
Если да, то значит библиотеку нужно писать на С/С++ и компилировать, как вы говорили, midl.exe?..
:(
(с учётом того, что параметры могут сами быть указателями, и те области памяти, на которые они указывают, тоже должны попасть в поток) - здорово.
Если вы уже успели близко познакомиться с IDL, то знаете, что параметры-указатели там обязательно сопровождаются атрибутами ref, unique или ptr. Если структура, описанная на IDL, содержит указатели, то они тоже должны иметь соответствующие атрибуты. Есть ещё атрибуты atring, size_is, iid_is и другие, которые служат для того, чтобы заместитель знал, как упаковывать в поток ту область памяти, на которую ссылается указатель.
В нашем учебном центре я читаю лекции, в т.ч. и по COM/DCOM. Когда-то я написал учебное пособие по своим материалам. Оно ориентировано на использование VC++, но там всё равно есть немало полезной для начинающего информации. Если хотите, могу выслать вам ту главу своего пособия, в которой идёт речь о COM/DCOM.
По MSDN'у если поискать, то там про маршалинг много чего есть. Но там всё очень сложно, для предварительного знакомства плохо подходит. Электронного источника для начинающих подсказать не могу, только печатную книгу Э.Трельсен "Модель COM и применение ATL 3.0".
Вкратче могу сказать следующее: в COM/DCOM клиент оперирует указателем на объект, который расположен в адресном пространстве другого процесса и, может быть, даже на другом компьютере. Понятно, что указатель на этот объект существовать не может. Реально в адресное пространство клиента загружается заместитель (proxy), а в адресное пространство сервера - заглушка (stub). Заместитель создаёт объект, на который реально ссылается клиент. Вызов функции сервера происходит следующим образом: на самом деле клиент вызывает функцию объекта заместителя. Этот объект упаковывает параметры функции в поток (с учётом того, что параметры могут сами быть указателями, и те области памяти, на которые они указывают, тоже должны попасть в поток) и передаёт этот поток стандартному системному объекту канала. Далее поток передаётся системными средствами объекту канала на стороне сервера, тот передаёт этот поток заглушке, заглушка восстанавливает в адресном пространстве сервера всю ту структуру данных, которая была передана клиентом, и вызывает требуемую функцию сервера, передавая ей копии параметров в адресном пространстве сервера. Результат работы функции сервера передаётся по этой же цепочке в обратном порядке.
Процесс упаковки данных в поток называется маршалингом (marshling), извлечения из потока - обратным маршалингом (unmarshaling). Очевидно, что для выполнения маршалинга необходимо учитывать специфику объекта, построение универсальной заглушки и заместителя невозможно. Существует три вида маршалинга:
1. Пользовательский. COM-объект реализует интерфейс IMarshal, функции которого осуществлят упаковку данных. Самый сложный и самый редкоиспользуемый способ.
2. Универсальный. Заместитель и заглушка строится стандартной системной библиотекой oleaut32.dll. Для их построения oleaut32.dll берёт информацию из т.н. библиотеки типов, которая может быть реализована в виде отдельного файла с расширением tlb или внедрена в файл сервера. Достоинтсва метода - простота, недостаток - oleaut32.dll может осуществлять маршалинг только функций, параметры которых имеют Variant-совместимые типы. Универсальный маршалинг иногда называют type-library marshaling. Библиотека типов должна быть создана разработчиком сервера (обычно она создаётся автоматически при компиляции IDL-файла).
3. Стандартный. Заместитель и заглушка реализуются специальной proxy/stub dll, которая индивидуальна для каждого сервера и должна создаваться автором сервера. Достоинства - практически нет ограничений на типы параметров, относительная простота (по сравнению с пользовательским маршалингом). Недостатки - автор сервера должен возиться с созданием этой библиотеки и таскать её всюду, где будет клиент или сервер.
Как создаётся proxy/stub dll средствами Delphi, я не знаю. Знаю только, что в составе VisualC++ есть компилятор IDL-файлов midl.exe, который на основе IDL-описания объекта генерирует для него исходники (на C и C++), из которых можно собрать эту библиотеку.
Юрию Хапёрскому:
Пробовал подобный вариант, только не блокировал массив. Взглянул на ваш вариант и вспомнил Тейксеру и Пачеку - читал, ведь, у них про VarArrayLock, но забыл :) - наверно нужно спать побольше :)
В третьей строке, я так понял, опечатка: BufPointer := VarArrayLock(LBuffer);
Спасибо за ответ.
Антону Григорьеву:
Вечером попробую реализовать. Сразу по следам ответа нашёл в W32' Developers Reference статьи "Arrays and Pointers", "Arrays" из раздела о RPC - там что-то похожее есть... Просто первый раз слышу об универсальном и стандартном маршалинге (сейчас я только обнюхиваю COM) - ни на что не сошлётесь?
Идея, думаю, понятна: передаётся указатель на первый элемент массива и его длина. Благодаря атрибуту size_is прокси знает, как осуществлять маршалинг. Проблема только в том, что oleaut32.dll такое не прожуёт, и вместо универсального маршалинга придётся использовать стандартный со всеми вытекающими неудобствами.
Способ не такой уж и тормозной, как вы думаете. В COM бинарные данные передаются как правило только с помощью Variant arrays (если не изощряться конечно). Так делают все, так что не заморачивайтесь по этому поводу. ;)
Удачи!
Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter. Функция может не работать в некоторых версиях броузеров.