Створення сервера DCOM у вигляді dll, Windows IT Pro
Distributed Component Object Model (DCOM) - це розширення технології COM, що дозволяє проектувати власні компоненти, здатні працювати не тільки на одній машині, але й різних комп'ютерах мережі. Таким чином, можна створювати розподілені програми. Це може стати в нагоді, наприклад, у локальній мережі, коли один сервер обслуговує кількох клієнтів. Переваги такого підходу є очевидними.
MS Visual C++ дозволяє створювати сервери COM як модулів dll чи exe чи вигляді служби NT.
У цій статті я розповім про те, як створити сервер DCOM у вигляді dll та клієнта для нього. Передбачається, що читачі мають уявлення про технологію COM, тому тут торкнуться лише аспекти, специфічні для DCOM, - сурогатні процеси, маршалінг, побудова dll для заступника/заглушки.
Я розповім, як побудувати COM-сервер, що реалізує інтерфейс ICar з двома методами – «додати паливо» та «отримати пробіг», а також клієнта для цього сервера.
Як працює DCOM-сервер у dll
Сурогатний процес.Бібліотеки dll не мають свого процесу і підвантажуються в клієнтський процес. А що відбувається, якщо клієнтський процес працює на іншому комп'ютері?
У цьому випадку бібліотека COM, отримавши запит на активізацію сервера, запускає так званий сурогатний процес та завантажує в нього DLL сервера. За умовчанням сурогатний процес надається бібліотекою COM, однак розробник за бажанням може використовувати інший (користувальницький) процес.
Сурогатний процес (файл dllhost.exe), що використовується за умовчанням, являє собою псевдо-сервер СОМ зі змішаною потоковою моделлю. Коли кілька серверів dll завантажуються в такий сурогатний процес, бібліотека СОМ гарантує,що СОМ-об'єкти кожного сервера створюються з використанням потокової моделі, яка призначена в реєстрі для цього сервера.
Усі сервери з моделлю вільних потоків функціонуватимуть у багатопотоковому підрозділі (apartment), тоді як однопотокові сервери отримають однопоточкові підрозділи. Якщо СОМ-сервер підтримує обидві потокові моделі, бібліотека СОМ вибирає для такого сервера багатопотокову модель.
При використанні сурогатного процесу за замовчуванням бібліотека СОМ керує не тільки завантаженням СОМ-серверів, але й їх вивантаженням із процесу та завершенням самого процесу.
Маршалінг.У моделі DCOM сервер і клієнт знаходяться на різних комп'ютерах мережі. Отже, сервер та клієнт працюють у різних процесах і для взаємодії один з одним повинні використовувати маршаллінг.
Маршаллінг - це механізм, що дозволяє упаковувати та передавати виклики методів інтерфейсів через межі процесів.
У СОМ маршаллінг реалізований за допомогою так званих «заступника» та «заглушки» (proxy/stub), як показано на малюнку 1.
Заступник (Proxy) - це СОМ-об'єкт, що завантажується в процес клієнта, який упаковує виклики клієнта і передає їх відповідній заглушці за протоколом RPC.
Заглушка (Stub) – СОМ-об'єкт, який отримує упаковані виклики клієнта, розпаковує їх та викликає необхідні методи реального СОМ-об'єкта. Заглушка взаємодіє із відповідним заступником.
Можна сказати, що заступник для клієнта «прикидається» сервером, а заглушка для сервера «прикидається» клієнтом.
Кожна конкретна пара замісник/заглушка містить код для маршалінгу даних свого інтерфейсу.
Код замісника та заглушки можна помістити в той же dll, що і сам СОМ-сервер, а можнарозмістити в окремому DLL. Як і СОМ-сервер, dll заступника/заглушки має бути зареєстрований, тобто до системного реєстру необхідно внести відповідні записи (про це трохи пізніше).
При створенні віддаленого СОМ-сервера зручно помістити код заглушки/заступника в окремий невеликий dll, щоб не копіювати на клієнтський комп'ютер dll, що містить код сервера, і заступника/заглушки.
Реєстрація СОМ-сервера для роботи у сурогатному процесі з віддаленим клієнтом.
Для того щоб COM-сервер у бібліотеці dll можна було викликати віддалено і, отже, завантажити в сурогатний процес, у системному реєстрі сервера та клієнта повинні бути деякі розділи та параметри.
1. У розділі HKEY_CLASSES_ROOTCLSID сервера має бути підрозділ з ім'ям GUID СОМ-об'єкта. У нашому прикладі ім'я підрозділу ??. У ньому повинні бути параметр AppID зі значенням GUID СОМ-об'єкта та підрозділ InProc-Server32.
2. У розділі HKEY_CLASSES_ROOTAppID сервера повинен бути присутнім підрозділ з ім'ям GUID СОМ-об'єкта. У підрозділі повинен бути параметр з ім'ям DllSurrogate та відповідним значенням - порожній рядок або шлях до користувальницького сурогатного процесу.
3. У розділі HKEY_CLASSES_ROOTInterface і на клієнті та на сервері повинен бути присутнім підрозділ з ім'ям GUID СОМ-об'єкта, а в ньому - розділ з ім'ям Proxy-StubClsid32, де зберігається GUID заступника/заглушки.
RGS-файл.У числі інших файлів під час створення COM-сервера, Visual C++ генерує .rgs-файл. Цей файл містить сценарій для внесення/видалення записів до реєстру. Щоб наш сервер міг працювати з віддаленим клієнтом, необхідно внести деякі зміни до файлу сценарію (див. Лістинг 1). Виділені рядки додані вручну.
Файл .rgs побудований заієрархічний принцип. Кожен вузол позначається парою фігурних дужок. Головний вузол HKCR задає галузь системного реєстру HKEY_CLASSES_RO-OT, до якого сценарій вноситиме зміни.
Оператор NoRemove розділу CLSID означає, що при внесенні записів у CLSID всі інші підрозділи залишаються незмінними. Оператор For-ceRemove, навпаки, видаляє всі записи під заданим підрозділом з наступним внесенням нових записів.
Пояснимо зміст внесених змін. Рядок
додає розділ AppID у відповідний розділ CLSID, а останні виділені рядки Лістингу 1 додають параметр dllSurrogate до розділу AppID. Цей параметр вказує на те, що сервер із заданим ідентифікатором CLSID має бути запущений у сурогатному процесі. Значення параметра ( ` ` ) - порожній рядок - говорить про те, що використовуватиметься сурогатний процес за умовчанням. Якщо потрібно задіяти користувальницький сурогатний процес, параметр dllSurrogate повинен містити шлях до файлу користувальницького сурогатного процесу.
Налаштування локальної мережі.При запуску сервера на машині під Windows NT/2000 клієнтський комп'ютер повинен мати достатні повноваження для активізації сервера та роботи з ним.
Створення сервера
Тепер ми знаємо, як працює DCOM. Застосуємо наші знання практично. Для створення COM-компонентів за допомогою MS Visual C++ 6.0 у нашому розпорядженні є бібліотека ATL. Скористаємося нею та вбудованими майстрами. У меню New-Projects слід вибрати ATL COM AppWizard (див. Екран 1).

На наступній вкладці вибираємо тип нашого сервера – dll (див. Екран 2). Прапорець Allow merging of proxy/stub code виставляти не рекомендується. У цьому випадку код заглушки та заступника буде поміщений в окремий dll, що зручно дляреєстрації заглушки/заступника на віддаленій клієнтській машині.

Далі потрібно додати до проекту новий ATL-об'єкт, вибрати Simple Object і створити інтерфейс IСar. Тепер залишається додати методи інтерфейсу (див. Лістинг 2).
Метод AddFuel («Додати паливо»):
Метод GetHaul («Отримати пробіг»):
Зауважте, що аргумент методу GetHaul має тип long*, оскільки це параметр типу out.
Побудова та реєстрація dll заступника та заглушки.Для побудови бібліотеки dll заступника/заглушки потрібно скористатися утилітою NMAKE.EXE. Ця утиліта дозволяє побудувати проект на основі команд, що містяться у файлі описів - .mk-файлі.
Make-файл має ім'я «ІМ'Я_ПРОЕКТАps.mk». Літери "ps" в кінці імені вказують на те, що це make-файл для proxy/stub dll. Visual Studio позбавляє користувача рутинної роботи і дозволяє автоматизувати процес створення і реєстрації модуля dll заступника/заглушки.

Для цього на вкладці Project Settings->Post-build step (див. Екран 3) необхідно ввести дві команди:
1) nmake /f DCOM_Serverps.mk 2) regsvr32 DCOM_Serverps.dll
Дія цих команд варто поширити на всі конфігурації проекту, попередньо встановивши All Configurations у списку Settings For. В результаті роботи утиліти NMAKE буде створено dll заступника/заглушки з ім'ям «ІМ'Я_ПРОЕКТАps.dll». Утиліта regsvr32 зареєструє заступник/заглушку у реєстрі системи.
Ще раз нагадаю, що бібліотека dll заступника/заглушки має бути скопійована та зареєстрована і на комп'ютері сервера, і на комп'ютері клієнта.
Створення клієнта
Щоб включити у клієнтський проект опис інтерфейсів сервера, слід імпортувати бібліотеку типів сервера.Для цього у файл StdAfx.h клієнтського проекту потрібно вставити наступний рядок:
(Докладний опис директиви #import та її атрибутів є в MSDN).
Вкажіть шлях до каталогу серверного проекту на вкладці Project->Settings->C++->Preprocessor у вікні Additional include directories, інакше компілятор не знайде файл бібліотеки типів сервера.
Для компіляції коду потрібно визначити у проекті константу _WIN32_WINNT зі значенням 0x0400 (див. Екран 4).

Якщо всі виклики методів СОМ-об'єкта успішні, виконання передається оператору, наступний за останнім catch-блоком. Тоді об'єкт spI класу ICarPtr зруйнується при виході з блоку try. Якщо будь-який виклик повертає помилку, клас ICarPtr генерує виключення типу _com_error, і керування передається до блоку catch. При цьому для всіх стікових об'єктів, створених у межах try-блоку, викликаються деструктори у порядку, зворотному порядку створення цих об'єктів. Такий механізм називається "розкручування стека" (stack unwinding).
Ну от і все! Якщо сервер та клієнт успішно скомпілювалися та заробили, шукайте помилку в компіляторі. Жарт.
Найбільш ймовірними причинами run-time помилок можуть бути неправильна реєстрація сервера в системному реєстрі або відсутність бібліотеки dll заступника/заглушки (або незареєстрована бібліотека) на клієнтському та серверному комп'ютері.
Перевірте, чи буде працювати сервер під час локальних дзвінків. Для цього слід замінити другий аргумент функції CoCreateInstanceEx на CLSCTX_INPROC_SERVER та запустити клієнтську програму на серверному комп'ютері.
Якщо функція CoCreateInstanceEx під час виклику віддаленого сервера (другий аргумент CLSCTX_REMOTE_SERVER) повертає помилку «Клас не зареєстрований» (код помилки 0x80040154), а викликлокального сервера завершується успішно - швидше за все, не було внесено зміни в .rgs файл сервера.
Поділіться матеріалом з колегами та друзями