Часть 2. Разработка клиентского консольного приложения для тестирования внутрипроцессного сервера СОМ

В данной части л.р. требуется разхработать клиентское приложение (проект ConsClient), в котором иллюстрируется использование внутрипроцессного сервера DLLMathServer. В данном приложении показано, как можно организовать использование сервера практически «с нуля», управляя его загрузкой и вызовом методов сервера СОМ. Далее будет показано, как этот процесс можно существенно упростить, если воспользоваться интеллектуальными указателями.

В общем виде процесс взаимодействия клиентского приложения и сервера представлен на рис. 37.1.

Часть 2. Разработка клиентского консольного приложения для тестирования внутрипроцессного сервера СОМ - student2.ru

Рис. 37.1 Обобщенная схема взаимодействия клиент-сервер

Когда клиент запрашивает сервер по его GUID (или ProgID), то этот запрос перехватывает СОМ-библиотека (Ole32.dll) и пытается отыскать в реестре Windows путь к каталогу, в котором размещен сервер. Еслит сервер не находится, то, естественно, возникает ошибка. В противном – счастливом – случае сервер загружается в память и автоматически создается объект «фабрика классов» в соответствии с пожеланиями клиента (выраженными где-то в параметрах соответствующих функций).

Объект фабрика классов создает СОМ-объект и, в случае удачи, возвращает указатель на интерфейс IUnknown. Далее все элементарно: используя указатель на интерфейс IUnknown с помощью функции QueryInterface мы получаем указатели на требуемые интерфейсы сервера и с их помощью вызываем соответствующие функции, т.е. заставляем сервер, аки золотую рыбку, выполнять наши самые потаенные желания.

Сервер DLLMathServer имеет к этому моменту такие интерфейсы и методы (фрагменты файла DLLMathServer.idl):

[

object,

uuid(2E4FB046-98D8-4E74-8572-84D7133FFEF4), /* guid интерфейса

IMathem */

pointer_default(unique)

]

interface IMathem : IUnknown

{

[] HRESULT Cube([in] DOUBLE Arg, [out] DOUBLE* Res);

[propget] HRESULT Foo([out, retval] BSTR* pVal);

[propput] HRESULT Foo([in] BSTR newVal);

};

[

object,

uuid(EE0BAF52-B2DB-4CC7-BD5E-9DB352699F3F), /* guid интерфейса

IMathem2 */

pointer_default(unique)

]

interface IMathem2 : IUnknown{

[] HRESULT Interpol([in] DOUBLE* YVec, [in] DOUBLE* XVec,

[in] LONG N, [in] DOUBLE XVal, [out] DOUBLE* YVal);

};

Наверняка вы догадались, что метод Interpol() находит не преступников, а решает задачу интерполяции, означенную выше.

Обратите внимание на числовые константы, заданные в качестве аргумента атрибута uuid: это GUID интерфейсов, которые нам необходимы для получения этих интерфейсов с помощью метода IUnknown::QueryInterface().

Для разработки этого клиентского приложения создадим обычное консольное приложение (имя проекта ConsClient) с поддержкой MFC. Теперь создадим файл MathemInt.h с помощью команды FileèNewèFileèVisual C++èHeader File(.h). Наполним файл описанием интерфейсов и их методов, которое должно, конечно, семантически соответствовать содержимому файла DLLMathServer.idl:

struct IMathem : IUnknown{

STDMETHOD_(HRESULT, Cube)(DOUBLE Arg, DOUBLE* Res);

STDMETHOD_(HRESULT, GetFoo)(BSTR* pVal);

STDMETHOD_(HRESULT, PutFoo)(BSTR pVal);

};

struct IMathem2 : IUnknown{

STDMETHOD_(HRESULT, Interpol)(DOUBLE* YVec, DOUBLE* XVec, LONG N,

DOUBLE XVal, DOUBLE* YVal);

};

Очень-но рекомендую устремить свое внимание на описание методов интерфейсов в файле MathemInt.h, которое существенно отличается от их же описания на языке IDL. В первую очередь это касается описания функций, реализующих доступ к свойству Foo: очень важен порядок описания этих методов, как и вообще любых других методов интерфейсов. Если вы переставите местами описания функций GetFoo() и PutFoo(), то компиляция пройдет без ошибок, а на этапе выполнения будет глючокс, пренепременнос. С этим мы будем разбираться позднее, но уже сейчас желательно запомнить, что в программировании имеет значение не только размер, но и порядок.

Файл MathemInt.h надо подключить к главному и единственному файлу нашего приложения ConsClient.cpp.

Далее в начало этого же файла, например, после оператора using namespace std, надо ввести определения констант GUID интерфейсов, значения которых надо взять из файла DLLMathServer.idl, фрагмент которого приведен выше. Естественно, что в вашем случае эти значения будут другими, не совпадающими с приведенными в тексте!!!

Теперь модифицируем главный файл нашего приложения в соответствии со следующим листингом. Думаю вы догадаетесь вставить вызов функции DoIt() в _tmain().

// ConsClient.cpp : Defines the entry point for the console application.

#include "stdafx.h"

#include "ConsClient.h"

#include "MathemInt.h"

#include <ConIO.h>

#ifdef _DEBUG

#define new DEBUG_NEW

#endif

// The one and only application object

CWinApp theApp;

using namespace std;

static const GUID IID_IMathem =

{0x2E4FB046, 0x98D8, 0x4E74, {0x85,0x72,0x84,0xD7,0x13,0x3F,0xFE,0xF4}};

static const GUID IID_IMathem2 =

{0xEE0BAF52,0xB2DB,0x4CC7,{0xBD,0x5E,0x9D,0xB3,0x52,0x69,0x9F,0x3F}};

Часть 2. Разработка клиентского консольного приложения для тестирования внутрипроцессного сервера СОМ - student2.ru
Часть 2. Разработка клиентского консольного приложения для тестирования внутрипроцессного сервера СОМ - student2.ru
Часть 2. Разработка клиентского консольного приложения для тестирования внутрипроцессного сервера СОМ - student2.ru
Часть 2. Разработка клиентского консольного приложения для тестирования внутрипроцессного сервера СОМ - student2.ru

Если все сделано корректно, то при запуске на выполнение программа должна выполнить требуемые вычисления и вывести корректный результат. При необходимости можно в режиме трассировки просмотреть не только код клиентского приложения, но и код методов интерфейса.

Попробуйте ответить на вопрос: какой смысл в объявлении объекта Init, который нигде не используется? А ежели его удалить, то будет … что?

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

В программе проверяются возвращаемые значения не всех используемых функций: восполните этот ужасный пробел.


Наши рекомендации