Студопедия

КАТЕГОРИИ:

АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция

Применение интеллектуальных указателей для доступа к серверам




Импорт библиотеки типов

 

Для создания и применения интеллектуальных указателей (smart pointer) на интерфейс необходимо, прежде всего, импортировать библиотеку типов сервера с помощью директивы препроцессора import, имеющей такой формат:

#import “имя_файла” [атрибуты]

Эту директиву надо включить в файл StdAfx.h, например:

#include <afx.h>

#include <afxwin.h>        // MFC core and standard components

#include <afxext.h>        // MFC extensions

#import "Server.tlb" no_namespace// импорт библиотеки типов

#ifndef _AFX_NO_AFXCMN_SUPPORT

#include <afxdtctl.h>       // MFC support for Internet Explorer 4 Common Controls

//

 

В качестве имени файла в директиве import можно указать любой из файлов, содержащий библиотеку типов:

· файл с библиотекой типов .tlb или .odl;

· исполняемый файл .exe, являющийся локальным сервером;

· библиотечный файл .dll или .ocx, содержащий внутрипроцессный сервер;

· составной документ, содержащий библиотеку типов;

· файл любого другого формата, который может быть воспринят функцией LoadTypeLib().

 

Замечание.MVS, конечно, является достаточно сложным программным продуктом, но в конечном итоге и в ней ИС выполняет и такие сравнительно простые действия, как открытие, интерпретацию и чтение файлов. Вспомним загрузку «старых» ОС с консоли

 

Директива import может включать атрибуты, как например no_namespace, назначение которых описано в MSDN.

Допустим, мы разработали внутрипроцессный сервер – библиотеку DLLMathServer.dll, в которой объявлены два интерфейса IMathem и IMathem2, в первом из которых имеется метод Cube(), а во втором – метод Summa().(см. подразд. «Доступ к серверу с помощью пользовательских интерфейсов»). Вот фрагмент файла DLLMathServer.idl, содержащий указанные объявления интерфейсов и методов:

// DLLMathServer.idl : IDL source for DLLMathServer

//

 

/* Этот файл будет обработан компилятором MIDL для создания

библиотеки типов (DLLMathServer.tlb)*/

import "oaidl.idl";

import "ocidl.idl";

[

object,

uuid(2CB07C07-F24C-4997-9BB3-F9436D291049),

helpstring("IMathem Interface"),

pointer_default(unique)

]

interface IMathem : IUnknown{

[, helpstring("method Cube")] HRESULT Cube([in] DOUBLE Arg,

      [out] DOUBLE* Res);

};

[

object,

uuid(60A322B4-F137-4f88-BC8A-EF45B977A99B),

helpstring("IMathem2 Interface"),

pointer_default(unique)

]

interface IMathem2 : IUnknown{

[, helpstring("method Summa")] HRESULT Summa([in] DOUBLE* Arr,

[in] LONG Num, [out] DOUBLE* Res);

};

 

Без использования интеллектуальных указателей нам бы пришлось поступать так, как описано в подразд. «Доступ к серверу с помощью пользовательских интерфейсов», а именно писать достаточно большой объем программного кода.

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

#import "DLLMathServer.dll" no_namespace

 

После включения обсуждаемой директивы надо выполнить компиляцию файлов проекта, в результате чего будут созданы файлы .tlhи .tli. Не надо искать где-то эти файлы и копировать их в папку проекта – они создаются компилятором на основе информации из библиотеки типов, т.е., например, из файла .tlb. Вы обнаружите эти файлы в каталоге Debug или Release в зависимости от выбранной конфигурации проекта. Заголовочный файл .tlh содержит описание библиотеки типов на языке C++, которым можно воспользоваться для получения имен интерфейсов и методов, описанных в библиотеке типов. Назначение же методов надо извлекать из справочной системы соответствующего сервера.

Пример файла dllmathserver.tlh (приведен с сокращениями):

 

//…

// Smart pointer typedef declarations

//

_COM_SMARTPTR_TYPEDEF(IMathem, __uuidof(IMathem));

_COM_SMARTPTR_TYPEDEF(IMathem2, __uuidof(IMathem2));

IMathem : IUnknown

{

// Property data

__declspec(property(get=GetFoo,put=PutFoo))

_bstr_t Foo;

// Wrapper methods for error-handling

HRESULT Cube (double Arg, double * Res );

_bstr_t GetFoo ( );

void PutFoo (_bstr_t pVal);

//

// Raw methods provided by interface

// raw – префикс для избежания конфликта имен

virtual HRESULT __stdcall raw_Cube (

   /*[in]*/ double Arg,/*[out]*/ double * Res ) = 0;

virtual HRESULT __stdcall get_Foo (

   /*[out,retval]*/ BSTR * pVal ) = 0;

virtual HRESULT __stdcall put_Foo (/*[in]*/ BSTR pVal ) = 0;

};

//

// Wrapper method implementations

//

#include "dllmathserver.tli"

 

Файл .tli содержит сгенерированные мастером MVS оболочки методов сервера и используется компилятором для их вызова. Этот файл с помощью директивы include подключается к файлу .tlh. Пример описания метода в файле .tli:

inline HRESULT IMathem::Cube ( double Arg, double * Res )

{

HRESULT _hr = raw_Cube(Arg, Res);

if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));

return _hr;

}

 

Клиентское приложение должно обеспечить также инициализацию OLE-библиотек. С учетом этого клиентское приложение могло бы выглядеть так:

// SPMathDll.cpp: Клиентское приложение, использующее интеллектуальные

//           указатели

#include "stdafx.h"

#include "SPMathDll.h"

#include <Conio.h>

CWinApp theApp;

using namespace std;

Struct OleInit

{ OleInit() {CoInitialize(NULL);}

~OleInit() {CoUninitialize(); }

} Init;

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])

{

// инициализация MFC

IMathemPtr Math("DLLMathServer.Mathem");

IMathem2Ptr Math2("DLLMathServer.Mathem");

double Res;

Math->Cube(3,&Res);

cout<<Res<<endl;

double Arr[]={1,2,3};

int Num=sizeof(Arr)/sizeof(Arr[0]);

Math2->Summa(Arr,Num,&Res);

cout<<Res<<endl;

_getch();

Math=Math2=NULL;

return 0;

}

 

Если Вы запустите программу в режиме трассировки, то обнаружите, что при выполнении оператора

IMathemPtr Math("DLLMathServer.Mathem");

 

будет загружена библиотека DLLMathServer.dll и указатель Math будет указывать на интерфейс IMathem.

Откуда взялся идентификатор IMathemPtr или IMathem2Ptr? Если Вы даже запустите поиск этих идентификаторов во всех файлах проекта, то нигде их не найдете, кроме как в функции _tmain(). Эти идентификаторы генерируются макросом _COM_SMARTPTR_TYPEDEF, который Вы обнаружите в файле DLLMathServer.tlh, сгенерированном компилятором на основе библиотеки типов. Имя идентификатора получается очень просто – путем прибавления суффикса Ptr к имени интерфейса.

Макрос _COM_SMARTPTR_TYPEDEF определен в файле Comdef.h, который подключается к файлу DLLMathServer.tlh. Фрагмент файла Comdef.h:

#if !defined(_COM_SMARTPTR)

 #if !defined(_INC_COMIP)

#include <comip.h>

 #endif

 #define _COM_SMARTPTR   _com_ptr_t

 #define _COM_SMARTPTR_LEVEL2 _com_IIID

#endif

#if defined(_COM_SMARTPTR)

 #if !defined(_COM_SMARTPTR_TYPEDEF)

#if defined(_COM_SMARTPTR_LEVEL2)

#define _COM_SMARTPTR_TYPEDEF(Interface, IID) \

typedef _COM_SMARTPTR<_COM_SMARTPTR_LEVEL2<Interface, &IID> > \

       Interface ## Ptr

#else

#define _COM_SMARTPTR_TYPEDEF(Interface, IID) \

typedef _COM_SMARTPTR<Interface, &IID> \

       Interface ## Ptr

#endif

 #endif

#endif

 

За определением «умного» указателя IMathemPtr Math("DLLMathServer.Mathem") скрывается достаточно большой код: получение CLSID сервера по его внешнему имени, вызов функции CoCreateInstance() для создания СОМ-объекта сервера, вызов IUnknown::QueryInterface() для получения запрашиваемого интерфейса и присваивания значения полученного указателя переменной Math.

После того, как интеллектуальный указатель больше не нужен, рекомендуется присвоить ему значение NULL, чтобы форсировать вызов функции IUnknown::Release(). Естественно, что после этого указатель нельзя использовать для доступа к методам сервера.










Последнее изменение этой страницы: 2018-04-12; просмотров: 397.

stydopedya.ru не претендует на авторское право материалов, которые вылажены, но предоставляет бесплатный доступ к ним. В случае нарушения авторского права или персональных данных напишите сюда...