Оформлення класу у вигляді COM об'єкту в C + + h2>
Оформлення класу у вигляді COM об'єкту. p>
Припустимо у вас є якийсь додаток, написаний
на C + + (VC + + якщо бути коректним). Як воно у вас з'явилося не має значення, може
бути це ваша стара розробка, може бути ви вирішили спочатку налагодити
предметну частину. Важливо те що ви палко бажаєте винести частину класів в
об'єктні модулі і оформити їх у вигляді ActiveX, COM і ATL об'єктів. Є
кілька типових проблем пов'язаних з таким перенесенням. p>
Множинні конструктори. p>
class MyCOM p>
( p>
MyCOM (); p>
MyCOM (long id); p>
MyCOM (long
id, LPCSTR Name); p>
: p>
) p>
знайомим і дуже зручно, але в COM правила створення
об'єкта суворо визначені і жодна з функції для створінь об'єктів не
дозволяє передавати параметри конструктору класу. p>
Настройку об'єкта доведеться винести в окремий метод
наприклад Init. p>
// IMyCOM стандартних обгортка спадкоємець від
COleDispatchDriver p>
IMyCOM * d = new
IMyCOM; p>
COleException pErr;
p>
CString
SSS = "Mylib.MyCOM"; p>
d-> CreateDispatch (
SSS, & pErr); p>
d-> Init (15, "Матриця");// Ініціалізіруем p>
У принципі, ви можете створити свою фабрику об'єктів.
Це дозволить створювати об'єкти ось так. p>
IMyOF * d = new
IMyOF; p>
COleException pErr;
p>
CString
SSS = "MyLib.MyOF"; p>
d-> CreateDispatch (
SSS, & pErr); p>
IMyCOM
Ob1 (d-> CraeteEmpty ()); p>
IMyCOM
Ob2 (d-> CraeteId (15 )); p>
IMyCOM
Ob3 (d-> CraeteFull (15, SSS )); p>
Але навіщо вам зайвий проміжний об'єкт якщо можна
обійтися без нього. p>
Перевантажені методи. p>
class MyCOM p>
( p>
: p>
LPCSTR GetMyRec (long id); p>
LPCSTR
GetMyRec (LPCSTR Name); p>
AddRec (); p>
AddRec (long id); p>
AddRec (long id,
LPCSTR Name); p>
:. p>
) p>
Це цілком законний код С + +, але COM не дозволить вам у
інтерфейсі оголосити два методи з одним ім'ям. Це суперечить концепції. p>
Рішення p>
Можна зв'язати функції з різними методами інтерфейсу
для цього в odl Пішим p>
[id (1)] BSTR
AddRecName (BSTR ID); p>
[id (2)] BSTR
AddRecID (long ID); p>
а в cpp здійснюємо прив'язку. p>
BEGIN_DISPATCH_MAP (:.) p>
DISP_FUNCTION (CPSDG,
"AddRecName", AddRec, VTS_BSTR, VTS_BSTR) p>
DISP_FUNCTION (CPSDG,
"AddRecId", AddRec, VTS_BSTR, VTS_I2) p>
DISP_FUNCTION_ID (:.) p>
END_DISPATCH_MAP () p>
Можна написати проксі функції. Наприклад для GetMyRec
прототип може виглядати так p>
LPCSTR GetMyRec
(VARIANT id) p>
( p>
switch id.vt p>
(case VT_I4: (
return GetMyRec (id.lVal);) p>
case VT_BSTR: (
return GetMyRec (id.bstrVal);) p>
) p>
return S_OK; p>
) p>
Для функції AddRec можна зробити ось так p>
HRESULT AddRec
(VARIANT id, VARIANT Name) p>
( p>
if
((id.vt == VT_EMPTY) & & (Name.vt == VT_EMPTY)) p>
(AddRec (); return
S_OK;) p>
if
((id.vt == VT_I4) & & (Name.vt == VT_EMPTY)) p>
(AddRec (id.lVal);
return S_OK;) p>
if
((id.vt == VT_I4) & & (Name.vt == VT_BSTR)) p>
(AddRec (id.lVal,
Name. bstrVal); return S_OK;) p>
: p>
) p>
Цього цілком достатньо, але можна ще змінити
оголошення методу інтерфейсу в odl ось так p>
HRESULT Add (VARIANT
[optional, in] id, [optional, in] VARIANT S); p>
це дозволить викликати метод, красивіше. p>
Приклад на VB p>
MyObject.Add// Будь-який з варіантів повинен працювати p>
MyObject.Add 15 p>
MyObject.Add 15,
"Var" p>
Користувацькі типи даних p>
У складному проекті повно власних констант, структур,
множин використовуються в якості параметрів. p>
# define IDL_NEXT 5 p>
# define IDL_STOP 6 p>
: p>
struct UDT p>
( p>
unsigned long X; p>
unsigned long Y; p>
BSTR pbstr; p>
) UDT; p>
: p>
typedef enum
EnumType p>
( p>
First = 1, p>
Seond = 4, p>
Last = 10 p>
); p>
class MyCOM p>
( p>
:. p>
void SetType
(EnumType T); p>
void Do (UDT * Dat); p>
void SetMove (int
val); p>
:. p>
) p>
: p>
// а де то все це викликається p>
SetType (First); p>
UDT Dat, Dat1; p>
: p>
Do (& Dat, Dat1); p>
SetMove (IDL_NEXT); p>
Зрозуміло що, для того щоб у такий спосіб можна
було викликати методи COM об'єкту, службові структури, множини і константи
повинні бути доступні із зовні. p>
Для цього потрібно включити їх опис в ODL файл. p>
Безліч описуються так. p>
[ p>
uuid (...), p>
version (1.0), p>
helpstring ("...") p>
] p>
library LibraryName p>
( p>
importlib ( "stdole32.tlb "); p>
importlib ( "stdole2.tlb "); p>
typedef enum p>
( p>
valueName1 = 0, p>
valueName2 = 1, p>
... p>
valueNameN = N p>
) EnumType; p>
.. p>
) p>
Передавати в якості параметрів структури теж можна.
Такі структури називаються UDT - User Defined Type. У IDL описуються так: p>
Typedef [uuid (C1D3A8C0-A4AA-11D0-819C-00A0C90FFFC3)]
struct UDT p>
( p>
unsigned long X; p>
unsigned long Y; p>
BSTR pbstr; p>
) UDT; p>
Описувати параметри методу можна як VARIANT але тоді
доведеться працювати з інтерфесом IRecordInfo або як UDT: p>
Do ([in] UDT * pIn,
[in, out] pOut); p>
Надіслати UDT в такий метод дуже просто: p>
UDT some_data,
some_returned_data; p>
p-> Do (& some_data,
some_returned_data); p>
Членами UDT можуть бути інші UDT або
oleautomation-сумісні типи. p>
У ви в VC немає автоматизації дозволяє створювати
користувацькі типи поетом у все доведеться робити ручками p>
Список літератури h2>
Для підготовки даної роботи були використані
матеріали з сайту http://www.realcoding.net/
p>