Студия web-дизайна Хостмэйк
Наши работыКонтактыО компанииОтзывыГлоссарийСтатьи

Оформление класса в виде COM объекта в C++

Статьи Программирование на С/С++

Допустим у вас есть некоторое приложение, написанное на C++(VC++ если быть корректным). Как оно у
вас появилось не суть важно, может быть это ваша старая разработка, может быть
вы решили сначала отладить предметную часть. Важно то что вы горите желанием
вынести часть классов в объектные модули и оформить их в виде ActiveX, COM и ATL
объектов. Есть несколько типовых проблем связанных с таким
переносом.


Оформление класса в виде COM объекта.


Допустим
у вас есть некоторое приложение, написанное на C++(VC++ если быть корректным).
Как оно у вас появилось не суть важно, может быть это ваша старая разработка,
может быть вы решили сначала отладить предметную часть. Важно то что вы горите
желанием вынести часть классов в объектные модули и оформить их в виде ActiveX,
COM и ATL объектов. Есть несколько типовых проблем связанных с таким
переносом.

Множественные конструкторы.
class MyCOM

{
MyCOM();
MyCOM(long id);
MyCOM(long id,LPCSTR Name);

}

Знакомо и очень удобно, но в COM правила создания объекта строго определены
и ни одна из функции для созданий объектов не позволяет передавать параметры
конструктору класса.

Настройку объекта придется вынести в отдельный метод
например Init.
// IMyCOM cтандартная обертка наследник от
COleDispatchDriver
IMyCOM * d=new IMyCOM;
COleException pErr;
CString
SSS="Mylib.MyCOM";
d->CreateDispatch(
SSS,&pErr);
d->Init(15,”Матрица”); // Инициализируем

В
принципе вы можете создать свою фабрику объектов. Это позволит создавать объекты
вот так.
IMyOF * d=new IMyOF;
COleException pErr;
CString
SSS="MyLib.MyOF";
d->CreateDispatch( SSS,&pErr);
IMyCOM
Ob1(d->CraeteEmpty());
IMyCOM Ob2(d->CraeteId(15));
IMyCOM
Ob3(d->CraeteFull(15,SSS ));

Но зачем вам лишний промежуточный объект
если можно обойтись без него.


Перегруженные методы.
class MyCOM

{

LPCSTR GetMyRec(long id);
LPCSTR GetMyRec(LPCSTR
Name);
AddRec ();
AddRec (long id);
AddRec (long id, LPCSTR
Name);
….
}
Это вполне законный код С++, но COM не разрешит вам в
интерфейсе объявить два метода с одним именем. Это противоречит
концепции.
Решение
Можно связать функции с разными методами интерфейса для
этого в odl пишим

[id(1)] BSTR AddRecName(BSTR ID);
[id(2)] BSTR
AddRecID(long ID);
а в cpp осуществляем
привязку.
BEGIN_DISPATCH_MAP(….)
DISP_FUNCTION(CPSDG, "AddRecName",
AddRec, VTS_BSTR, VTS_BSTR)
DISP_FUNCTION(CPSDG, "AddRecId", AddRec,
VTS_BSTR, VTS_I2)

DISP_FUNCTION_ID(….)
END_DISPATCH_MAP()

Можно
написать прокси функции. Например для GetMyRec прототип может выглядеть
так
LPCSTR GetMyRec (VARIANT id)
{
switch id.vt
{case VT_I4: {
return GetMyRec(id.lVal); }
case VT_BSTR: { return GetMyRec(id.bstrVal);
}
}
return S_OK;
}

Для функции AddRec можно сделать вот
так

HRESULT AddRec (VARIANT id, VARIANT Name)
{
if
((id.vt==VT_EMPTY)&&(Name.vt==VT_EMPTY))
{AddRec() ; return
S_OK;}
if ((id.vt==VT_I4)&&(Name.vt==VT_EMPTY))
{AddRec(id.lVal) ;
return S_OK;}
if ((id.vt==VT_I4)&&(Name.vt==
VT_BSTR))
{AddRec(id.lVal, Name. bstrVal ) ; return S_OK;}

}
Этого
вполне достаточно, но можно еще изменить объявление метода интерфейса в odl вот
так
HRESULT Add(VARIANT [optional, in]id, [optional,in]VARIANT S);
это
позволит вызывать метод , более красиво.
Пример на VB
MyObject.Add //
Любой из вариантов должен работать
MyObject.Add 15
MyObject.Add 15,
“Var”




Пользовательские типы данных
В сложном проекте полно
собственных констант, структур, множеств используемых в качестве параметров
.
#define IDL_NEXT 5
#define IDL_STOP 6

struct UDT

{
unsigned long X;
unsigned long Y;

BSTR pbstr;
}
UDT;

typedef enum EnumType
{
First=1,
Seond=4,
Last
=10
};
class MyCOM
{
….
void SetType (EnumType T);
void
Do(UDT * Dat);
void SetMove (int val);
….
}

// а где то все это
вызывается
SetType(First);
UDT Dat,Dat1;

Do
(&Dat,Dat1);
SetMove (IDL_NEXT);

Понятно что, для того чтобы
подобным образом можно было вызывать методы COM объекта, служебные структуры,
множества и константы должны быть доступны из вне.
Для этого нужно включить
их описание в ODL файл.
Множества описываются так.
[
uuid(...),

version(1.0),
helpstring("...")
]
library
LibraryName
{
importlib("stdole32.tlb");
importlib("stdole2.tlb");

typedef
enum
{
valueName1 = 0,
valueName2 = 1,
...
valueNameN = N
}
EnumType;
..
}

Передавать в качестве параметров структуры тоже
можно. Такие структуры называются UDT - User Defined Type. В IDL описываются
так:
Typedef [uuid(C1D3A8C0-A4AA-11D0-819C-00A0C90FFFC3)] struct UDT

{
unsigned long X;
unsigned long Y;
BSTR pbstr;
}
UDT;

Описывать параметры метода можно как VARIANT но тогда придется
работать с интерфесом IRecordInfo или как UDT:

Do([in]UDT* pIn, [in,out]
pOut);


Передать UDT в такой метод проще простого:
UDT some_data,
some_returned_data;
p->Do(&some_data,
some_returned_data);

Членами UDT могут быть другие UDT или
oleautomation-совместимые типы.

У вы в VC нет автоматизации позволяющей
создавать пользовательские типы поэтом у все придется делать
ручками.

Пока все дальше будет больше.

По материаллам сайта: www.realcoding.net

16.02.2006

Телефон

+7 8636 237-836

Поиск

VSESMI.ru — новости в СМИ.
Один из больших по объему информации проектов, работающих под управлением HostCMS.

Tur-Hotel.ru — отзывы об отелях
На сайте представлено описание отелей, рейтинг отелей с отзывами туристов.