Вход/Регистрация
Интернет-журнал "Домашняя лаборатория", 2007 №6
вернуться

Журнал «Домашняя лаборатория»

Шрифт:

10. В том же диалоге на вкладке Link в поле Object/library moduls добавить через пробел ссылки на библиотеки поддержки удаленного вызова процедур rpcndr.lib, rpcns4.lib, rpcrt4.lib.

11. Откомпилировать проект и зарегистрировать построенную DLL прокси/заглушки с помощью Tools|Register Control.

В процессе саморегистрации построенной DLL прокси/заглушки она получает CLSID равный CLSID интерфейса IPub. Под соответствующим ключом реестре имеется раздел InProcServer32 с параметром по умолчанию, задающим путь к построенной DLL. Кроме того, регистрируются все три интерфейса под ключом HKEY_CLASES_ROOT Interface. Интерфейсы регистрируются под своими собственными идентификаторами (GUID). Для каждого имеется подраздел NumMethods, в котором указывается число методов интерфейса (включая наследуемые), и подраздел ProxyStabClsid32, в котором указывается GUID для DLL прокси/заглушки.

Теперь клиент и сервер не только запускаются в различных процессах, но и могут обмениваться друг с другом необходимыми данными.

Говоря про маршалинг следует остановиться на вопросе передачи данных между клиентом и сервером. В случае, когда передаются, например, массивы, необходимо следить за тем, кто выделяет и освобождает память, сколько выделяется памяти. Приведенные ниже примеры взяты из работы Richard Grimes, "Marshaling Your Data: Efficient Data Transfer Techniques Using COM and Windows 2000", MSDN Magazine, September 2000.

Предположим, что некоторый интерфейс включает методы, описания которых на IDL приведено ниже

HRESULT PassLongs([in] ULONG ulNum,

[in, size_is(ulNum)] LONG* pArrln);

HRESULT GetLongs([in] ULONG ulNum,

[out, size_is(ulNum)] LONG* pArrOut);

Здесь от клиента к объекту и обратно передаются массивы. Проще всего случай передачи массива от клиента к объекту. В этом случае клиент сам выделяет память под массив и сам ее освобождает. При передаче массива от объекта к клиенту возможны два варианта. В первом клиент заранее, до вызова метода знает размер передаваемого массива, во втором этот размер сообщает объект уже после вызова метода. Рассмотрим обе эти возможности.

Начнем со случая, когда клиент до вызова метода имеет информацию о размере массива. Код клиента

ULONG ulNum = 10;

LONG 1 [10];

hr = pArrObj — > GetLongs(ulNum, 1);

Код сервера

STDMETHODIMP CArrays::GetLongs(ULONG ulNum, LONG* pArr)

{

for (ULONG x = 0; x < ulNum; x++) pArr[x] = x;

return S_OK;

}

Как все это работает. Клиент сам выделяет память под массив в виде стековой переменной. Это позволяет ему не заботится об ее освобождении. Маршалер (система объектов, обеспечивающая маршализацию данных, передаваемых между клиентом и сервером) как на стороне клиента, так и на стороне объекта имеет информацию о размере передаваемого массива еще до возврата из метода. Это позволяет ему выделить на стороне объекта память под этот массив и передать указатель на выделенную память объекту (рАгг). Объект заполняет массив данными, после чего эти данные передаются по каналу клиенту. После передачи данных маршалер сам освобождает выделенную на стороне объекта память.

Во втором случае клиент получает размер массива уже после вызова метода. На IDL описание метода выглядит следующим образом

HRESULT GetLongsAlloc([out] ULONG* pNum, [out, size_is(, *pNum)] LONG** ppArr);

Здесь запятая в size is говорит о том, что *pNum есть размер массива, УКАЗАТЕЛЬ на который есть ppArr.

В данном случае маршалер не может сам выделить память под массив на стороне объекта и, следовательно, это должен делать объект. Но освобождать выделенную память после передачи данных должен уже маршалер, т. к. объект к этому моменту уже завершит работу. Для выделения и освобождения памяти в данном случае следует использовать функции CoTaskMemAlloc и CoTaskMemFree , которые может вызывать и маршалер.

Код компонента

STDMETHODIMP CArrays::GetLongsAlloc(ULONG* pNum, LONG** ppArr);

{

*pNum = 10;

*ppArr = reinterpret_cast<LONG*>(CoTaskMemAlloc(*pNum * sizeof(LONG)));

for (ULONG x = 0; x < *pNum; x++) (*ppArr)[x] = x;

return S_OK;

}

Здесь reinterpret_cast<LONG*> используется для приведения типа указателя, возвращаемого при выделении памяти, к указателю на long. Освобождает выделенную память сам маршалер, вызывая CoTaskMemFree.

На стороне клиента память выделяет маршалер, получив информацию о размере массива — *pNum. Освобождает же эту память клиент

ULONG ulNum;

LONG* pi;

hr = pArrObj —> GetLongsAlloc(SulNum, &pl);

for (ULONG ul = 0; ul < ulNum; ul++)

printf("%ld\n", pi[ul]);

CoTaskMemFree(pi);

Потоковая модель и апартаменты

Процесс и поток

Прежде всего вспомним некоторые понятия, связанные с процессами и потоками.

Приложение — это один или несколько процессов.

Каждый процесс имеет ряд ресурсов, среди которых виртуальное адресное пространство процесса, исполняемый код, данные, дескрипторы объектов, переменные среды, базовый приоритет. Таким образом, процесс это скорее среда, в которой выполняется один или несколько потоков.

Поток — выполнение последовательности машинных команд. Потоки, живущие в одном процессе, делят все его ресурсы. Кроме того, каждый поток имеет и свои собственные, доступные только ему ресурсы-локальная память потока.

  • Читать дальше
  • 1
  • ...
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: