Как создать MFC COM смотрите тут.
И так рассмотрим как создается COM объект в ATL, ATL — это библиотека которая генерирует каркас для COM компонент и ActiveX элементов. В книгах пишут что с ее помощью создавать COM компоненты также легко как и создавать с помощью MFC приложения. Ну сейчас посмотрим. Начнем с создания приложения.
1. Создание приложения COM в MFC
Запускаем Visual Studio 2010, выбираем «Файл» -> «Проект…», в появившемся окошке вводим «Создать проект» выбираем «проект ATL» и даем имя ему «CAtlProc»
жмем «Ок», потом жмем «Далее» в появившемся окошке
ничего не меняем и жмем «Готово», мы будем создавать COM DLL. Мастер у нас сгенерирует следующий набор файлов
2. Добавление COM класса
В общем добавим к нему наш COM класс, заходим в «Окно классов» кликаем правой клавишей мышки, в появившемся контекстном меню выбираем «Добавить» -> «Класс…», в появившемся окошке «Добавление класса» выбираем «Простой объект ATL»
жмем «Добавить», появится «Мастер простых объектов ATL», вводим имя нашего класса назовем его «CMyCOM», там где поле «Программный ИД» вводим строчку это будет у нас progID нашего приложения, введем туда «MY_COM» например.
жмем кнопку «Далее» и еще раз «Далее» в появившемся окошке с настройками ничего не меняем жмем «Готово», у нас создастся два файла
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
// CMyCOM.h: объявление CCMyCOM #pragma once #include "resource.h" // основные символы #include "CAtlProc_i.h" #if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA) #error "Однопотоковые COM-объекты не поддерживаются должным образом платформой Windows CE, например платформами Windows Mobile, в которых не предусмотрена полная поддержка DCOM. Определите _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA, чтобы принудить ATL поддерживать создание однопотоковых COM-объектов и разрешить использование его реализаций однопотоковых COM-объектов. Для потоковой модели в вашем rgs-файле задано значение 'Free', поскольку это единственная потоковая модель, поддерживаемая не-DCOM платформами Windows CE." #endif using namespace ATL; // CCMyCOM class ATL_NO_VTABLE CCMyCOM : public CComObjectRootEx<CComSingleThreadModel>, public CComCoClass<CCMyCOM, &CLSID_CMyCOM>, public IDispatchImpl<ICMyCOM, &IID_ICMyCOM, &LIBID_CAtlProcLib, /*wMajor =*/ 1, /*wMinor =*/ 0> { public: CCMyCOM() { } DECLARE_REGISTRY_RESOURCEID(IDR_CMYCOM) BEGIN_COM_MAP(CCMyCOM) COM_INTERFACE_ENTRY(ICMyCOM) COM_INTERFACE_ENTRY(IDispatch) END_COM_MAP() DECLARE_PROTECT_FINAL_CONSTRUCT() HRESULT FinalConstruct() { return S_OK; } void FinalRelease() { } public: }; OBJECT_ENTRY_AUTO(__uuidof(CMyCOM), CCMyCOM) |
1 2 3 4 5 6 7 |
// CMyCOM.cpp: реализация CCMyCOM #include "stdafx.h" #include "CMyCOM.h" // CCMyCOM |
Создался обычный С++ класс. В IDL файл добавился наш класс
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
// CAtlProc.idl: источник IDL для CAtlProc // // Этот файл будет обработан средством MIDL для // создания библиотеки типов (CAtlProc.tlb) и кода маршалирования. import "oaidl.idl"; import "ocidl.idl"; [ object, uuid(6ED7E28C-095F-429B-9FFF-5C5BBC11D698), dual, nonextensible, pointer_default(unique) ] interface ICMyCOM : IDispatch{ }; [ uuid(4DD4A978-1D87-4FE5-929B-E0BDC8A8129A), version(1.0), ] library CAtlProcLib { importlib("stdole2.tlb"); [ uuid(26959F44-0BBF-4247-B24A-01A65D0F7DED) ] coclass CMyCOM { [default] interface ICMyCOM; }; }; |
Этот файл он сам заполняется.
3. Добавление интерфейсов к COM классу.
Добавим интерфейсы к нашему сгенерированному COM классу. Увы это мы должны сделать вручную, для этого нам нужно редактировать наш idl файл например добавим от такой код
1 2 3 4 5 6 7 8 9 10 11 12 |
[ object, uuid(7D95CBC0-C33E-4E47-9405-AB4A01278878), dual, nonextensible, pointer_default(unique) ] interface IA : IDispatch { HRESULT P_A(); HRESULT Get_A([out,retval]long* nPosition); }; |
Этот код добавит дуальный интерфейс IA, дуальный потому что он наследуется от IDispatch, также мы определили функции Get_A и P_A.
Добавим следующий код к файлу idl
1 2 3 4 5 6 7 8 |
[ object, uuid(4D95CBC0-C33E-4E47-9405-AB4A01278878), ] interface IB : IUnknown { HRESULT P_B(); }; |
добавит интерфейс IB с функцией P_B. и полностью приведем файл idl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
// CAtlProc.idl: источник IDL для CAtlProc // // Этот файл будет обработан средством MIDL для // создания библиотеки типов (CAtlProc.tlb) и кода маршалирования. import "oaidl.idl"; import "ocidl.idl"; [ object, uuid(7D95CBC0-C33E-4E47-9405-AB4A01278878), dual, nonextensible, pointer_default(unique) ] interface IA : IDispatch { HRESULT P_A(); HRESULT Get_A([out,retval]long* nPosition); }; [ object, uuid(6ED7E28C-095F-429B-9FFF-5C5BBC11D698), dual, nonextensible, pointer_default(unique) ] interface ICMyCOM : IDispatch{ }; [ uuid(4DD4A978-1D87-4FE5-929B-E0BDC8A8129A), version(1.0), ] library CAtlProcLib { importlib("stdole2.tlb"); [ uuid(26959F44-0BBF-4247-B24A-01A65D0F7DED) ] coclass CMyCOM { [default] interface ICMyCOM; }; }; [ object, uuid(4D95CBC0-C33E-4E47-9405-AB4A01278878), ] interface IB : IUnknown { HRESULT P_B(); }; |
да чтобы создать GUID для интерфейсов, просто возьмите любой номер из этого же файла, скопируйте и измените несколько цифр например. Все дальше нажимаем F5 и нам пойдет компиляция, нам компилятор должен создать два файла из этого idl файла с определением интерфейсов и идентификаторами их. Жем F5 и у меня создалось 2 файла, вот их код
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 |
/* this ALWAYS GENERATED file contains the definitions for the interfaces */ /* File created by MIDL compiler version 7.00.0555 */ /* at Sun Aug 02 08:08:51 2015 */ /* Compiler settings for CAtlProc.idl: Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 7.00.0555 protocol : dce , ms_ext, c_ext, robust error checks: allocation ref bounds_check enum stub_data VC __declspec() decoration level: __declspec(uuid()), __declspec(selectany), __declspec(novtable) DECLSPEC_UUID(), MIDL_INTERFACE() */ /* @@MIDL_FILE_HEADING( ) */ #pragma warning( disable: 4049 ) /* more than 64k source lines */ /* verify that the <rpcndr.h> version is high enough to compile this file*/ #ifndef __REQUIRED_RPCNDR_H_VERSION__ #define __REQUIRED_RPCNDR_H_VERSION__ 475 #endif #include "rpc.h" #include "rpcndr.h" #ifndef __RPCNDR_H_VERSION__ #error this stub requires an updated version of <rpcndr.h> #endif // __RPCNDR_H_VERSION__ #ifndef COM_NO_WINDOWS_H #include "windows.h" #include "ole2.h" #endif /*COM_NO_WINDOWS_H*/ #ifndef __CAtlProc_i_h__ #define __CAtlProc_i_h__ #if defined(_MSC_VER) && (_MSC_VER >= 1020) #pragma once #endif /* Forward Declarations */ #ifndef __IA_FWD_DEFINED__ #define __IA_FWD_DEFINED__ typedef interface IA IA; #endif /* __IA_FWD_DEFINED__ */ #ifndef __ICMyCOM_FWD_DEFINED__ #define __ICMyCOM_FWD_DEFINED__ typedef interface ICMyCOM ICMyCOM; #endif /* __ICMyCOM_FWD_DEFINED__ */ #ifndef __CMyCOM_FWD_DEFINED__ #define __CMyCOM_FWD_DEFINED__ #ifdef __cplusplus typedef class CMyCOM CMyCOM; #else typedef struct CMyCOM CMyCOM; #endif /* __cplusplus */ #endif /* __CMyCOM_FWD_DEFINED__ */ #ifndef __IB_FWD_DEFINED__ #define __IB_FWD_DEFINED__ typedef interface IB IB; #endif /* __IB_FWD_DEFINED__ */ /* header files for imported files */ #include "oaidl.h" #include "ocidl.h" #ifdef __cplusplus extern "C"{ #endif #ifndef __IA_INTERFACE_DEFINED__ #define __IA_INTERFACE_DEFINED__ /* interface IA */ /* [unique][nonextensible][dual][uuid][object] */ EXTERN_C const IID IID_IA; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("7D95CBC0-C33E-4E47-9405-AB4A01278878") IA : public IDispatch { public: virtual HRESULT STDMETHODCALLTYPE P_A( void) = 0; virtual HRESULT STDMETHODCALLTYPE Get_A( /* [retval][out] */ long *nPosition) = 0; }; #else /* C style interface */ typedef struct IAVtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IA * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IA * This); ULONG ( STDMETHODCALLTYPE *Release )( IA * This); HRESULT ( STDMETHODCALLTYPE *GetTypeInfoCount )( IA * This, /* [out] */ UINT *pctinfo); HRESULT ( STDMETHODCALLTYPE *GetTypeInfo )( IA * This, /* [in] */ UINT iTInfo, /* [in] */ LCID lcid, /* [out] */ ITypeInfo **ppTInfo); HRESULT ( STDMETHODCALLTYPE *GetIDsOfNames )( IA * This, /* [in] */ REFIID riid, /* [size_is][in] */ LPOLESTR *rgszNames, /* [range][in] */ UINT cNames, /* [in] */ LCID lcid, /* [size_is][out] */ DISPID *rgDispId); /* [local] */ HRESULT ( STDMETHODCALLTYPE *Invoke )( IA * This, /* [in] */ DISPID dispIdMember, /* [in] */ REFIID riid, /* [in] */ LCID lcid, /* [in] */ WORD wFlags, /* [out][in] */ DISPPARAMS *pDispParams, /* [out] */ VARIANT *pVarResult, /* [out] */ EXCEPINFO *pExcepInfo, /* [out] */ UINT *puArgErr); HRESULT ( STDMETHODCALLTYPE *P_A )( IA * This); HRESULT ( STDMETHODCALLTYPE *Get_A )( IA * This, /* [retval][out] */ long *nPosition); END_INTERFACE } IAVtbl; interface IA { CONST_VTBL struct IAVtbl *lpVtbl; }; #ifdef COBJMACROS #define IA_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IA_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IA_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IA_GetTypeInfoCount(This,pctinfo) \ ( (This)->lpVtbl -> GetTypeInfoCount(This,pctinfo) ) #define IA_GetTypeInfo(This,iTInfo,lcid,ppTInfo) \ ( (This)->lpVtbl -> GetTypeInfo(This,iTInfo,lcid,ppTInfo) ) #define IA_GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) \ ( (This)->lpVtbl -> GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) ) #define IA_Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) \ ( (This)->lpVtbl -> Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) ) #define IA_P_A(This) \ ( (This)->lpVtbl -> P_A(This) ) #define IA_Get_A(This,nPosition) \ ( (This)->lpVtbl -> Get_A(This,nPosition) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IA_INTERFACE_DEFINED__ */ #ifndef __ICMyCOM_INTERFACE_DEFINED__ #define __ICMyCOM_INTERFACE_DEFINED__ /* interface ICMyCOM */ /* [unique][nonextensible][dual][uuid][object] */ EXTERN_C const IID IID_ICMyCOM; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("6ED7E28C-095F-429B-9FFF-5C5BBC11D698") ICMyCOM : public IDispatch { public: }; #else /* C style interface */ typedef struct ICMyCOMVtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( ICMyCOM * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( ICMyCOM * This); ULONG ( STDMETHODCALLTYPE *Release )( ICMyCOM * This); HRESULT ( STDMETHODCALLTYPE *GetTypeInfoCount )( ICMyCOM * This, /* [out] */ UINT *pctinfo); HRESULT ( STDMETHODCALLTYPE *GetTypeInfo )( ICMyCOM * This, /* [in] */ UINT iTInfo, /* [in] */ LCID lcid, /* [out] */ ITypeInfo **ppTInfo); HRESULT ( STDMETHODCALLTYPE *GetIDsOfNames )( ICMyCOM * This, /* [in] */ REFIID riid, /* [size_is][in] */ LPOLESTR *rgszNames, /* [range][in] */ UINT cNames, /* [in] */ LCID lcid, /* [size_is][out] */ DISPID *rgDispId); /* [local] */ HRESULT ( STDMETHODCALLTYPE *Invoke )( ICMyCOM * This, /* [in] */ DISPID dispIdMember, /* [in] */ REFIID riid, /* [in] */ LCID lcid, /* [in] */ WORD wFlags, /* [out][in] */ DISPPARAMS *pDispParams, /* [out] */ VARIANT *pVarResult, /* [out] */ EXCEPINFO *pExcepInfo, /* [out] */ UINT *puArgErr); END_INTERFACE } ICMyCOMVtbl; interface ICMyCOM { CONST_VTBL struct ICMyCOMVtbl *lpVtbl; }; #ifdef COBJMACROS #define ICMyCOM_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define ICMyCOM_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define ICMyCOM_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define ICMyCOM_GetTypeInfoCount(This,pctinfo) \ ( (This)->lpVtbl -> GetTypeInfoCount(This,pctinfo) ) #define ICMyCOM_GetTypeInfo(This,iTInfo,lcid,ppTInfo) \ ( (This)->lpVtbl -> GetTypeInfo(This,iTInfo,lcid,ppTInfo) ) #define ICMyCOM_GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) \ ( (This)->lpVtbl -> GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) ) #define ICMyCOM_Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) \ ( (This)->lpVtbl -> Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __ICMyCOM_INTERFACE_DEFINED__ */ #ifndef __CAtlProcLib_LIBRARY_DEFINED__ #define __CAtlProcLib_LIBRARY_DEFINED__ /* library CAtlProcLib */ /* [version][uuid] */ EXTERN_C const IID LIBID_CAtlProcLib; EXTERN_C const CLSID CLSID_CMyCOM; #ifdef __cplusplus class DECLSPEC_UUID("26959F44-0BBF-4247-B24A-01A65D0F7DED") CMyCOM; #endif #endif /* __CAtlProcLib_LIBRARY_DEFINED__ */ #ifndef __IB_INTERFACE_DEFINED__ #define __IB_INTERFACE_DEFINED__ /* interface IB */ /* [uuid][object] */ EXTERN_C const IID IID_IB; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("4D95CBC0-C33E-4E47-9405-AB4A01278878") IB : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE P_B( void) = 0; }; #else /* C style interface */ typedef struct IBVtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IB * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IB * This); ULONG ( STDMETHODCALLTYPE *Release )( IB * This); HRESULT ( STDMETHODCALLTYPE *P_B )( IB * This); END_INTERFACE } IBVtbl; interface IB { CONST_VTBL struct IBVtbl *lpVtbl; }; #ifdef COBJMACROS #define IB_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IB_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IB_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IB_P_B(This) \ ( (This)->lpVtbl -> P_B(This) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IB_INTERFACE_DEFINED__ */ /* Additional Prototypes for ALL interfaces */ /* end of Additional Prototypes */ #ifdef __cplusplus } #endif #endif |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
/* this ALWAYS GENERATED file contains the IIDs and CLSIDs */ /* link this file in with the server and any clients */ /* File created by MIDL compiler version 7.00.0555 */ /* at Sun Aug 02 08:08:51 2015 */ /* Compiler settings for CAtlProc.idl: Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 7.00.0555 protocol : dce , ms_ext, c_ext, robust error checks: allocation ref bounds_check enum stub_data VC __declspec() decoration level: __declspec(uuid()), __declspec(selectany), __declspec(novtable) DECLSPEC_UUID(), MIDL_INTERFACE() */ /* @@MIDL_FILE_HEADING( ) */ #pragma warning( disable: 4049 ) /* more than 64k source lines */ #ifdef __cplusplus extern "C"{ #endif #include <rpc.h> #include <rpcndr.h> #ifdef _MIDL_USE_GUIDDEF_ #ifndef INITGUID #define INITGUID #include <guiddef.h> #undef INITGUID #else #include <guiddef.h> #endif #define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \ DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) #else // !_MIDL_USE_GUIDDEF_ #ifndef __IID_DEFINED__ #define __IID_DEFINED__ typedef struct _IID { unsigned long x; unsigned short s1; unsigned short s2; unsigned char c[8]; } IID; #endif // __IID_DEFINED__ #ifndef CLSID_DEFINED #define CLSID_DEFINED typedef IID CLSID; #endif // CLSID_DEFINED #define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \ const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}} #endif !_MIDL_USE_GUIDDEF_ MIDL_DEFINE_GUID(IID, IID_IA,0x7D95CBC0,0xC33E,0x4E47,0x94,0x05,0xAB,0x4A,0x01,0x27,0x88,0x78); MIDL_DEFINE_GUID(IID, IID_ICMyCOM,0x6ED7E28C,0x095F,0x429B,0x9F,0xFF,0x5C,0x5B,0xBC,0x11,0xD6,0x98); MIDL_DEFINE_GUID(IID, LIBID_CAtlProcLib,0x4DD4A978,0x1D87,0x4FE5,0x92,0x9B,0xE0,0xBD,0xC8,0xA8,0x12,0x9A); MIDL_DEFINE_GUID(CLSID, CLSID_CMyCOM,0x26959F44,0x0BBF,0x4247,0xB2,0x4A,0x01,0xA6,0x5D,0x0F,0x7D,0xED); MIDL_DEFINE_GUID(IID, IID_IB,0x4D95CBC0,0xC33E,0x4E47,0x94,0x05,0xAB,0x4A,0x01,0x27,0x88,0x78); #undef MIDL_DEFINE_GUID #ifdef __cplusplus } #endif |
файлы с интерфейсами созданы, теперь нам нужно добавить эти интерфейсы к самому классу, пока у нас только два интерфейса добавлено в карту интерфейсов
1 2 3 4 |
BEGIN_COM_MAP(CCMyCOM) COM_INTERFACE_ENTRY(ICMyCOM) COM_INTERFACE_ENTRY(IDispatch) END_COM_MAP() |
и от здесь третье третья строчка наследования добавляет дуальный интерфейс
1 2 3 4 5 |
class ATL_NO_VTABLE CCMyCOM : public CComObjectRootEx<CComSingleThreadModel>, public CComCoClass<CCMyCOM, &CLSID_CMyCOM>, public IDispatchImpl<ICMyCOM, &IID_ICMyCOM, &LIBID_CAtlProcLib, /*wMajor =*/ 1, /*wMinor =*/ 0>//добавляется дуальный интерфейс { |
Добавим и мы наш дуальный интерфейс также, я просто приведу полностью код уже с добавленными интерфейсами и с наследованием.
1 2 3 4 5 6 7 |
class ATL_NO_VTABLE CCMyCOM : public CComObjectRootEx<CComSingleThreadModel>, public CComCoClass<CCMyCOM, &CLSID_CMyCOM>, public IDispatchImpl<IA, &IID_ICMyCOM, &LIBID_CAtlProcLib, /*wMajor =*/ 1, /*wMinor =*/ 0>,//добавляется дуальный интерфейс public IDispatchImpl<ICMyCOM, &IID_IA, &LIBID_CAtlProcLib, /*wMajor =*/ 1, /*wMinor =*/ 0>, public IB { |
видите мы просто сделали два наследования, похоже в ATL COM строится на наследовании.
1 2 3 4 5 6 |
BEGIN_COM_MAP(CCMyCOM) COM_INTERFACE_ENTRY(ICMyCOM) COM_INTERFACE_ENTRY(IA) COM_INTERFACE_ENTRY(IB) COM_INTERFACE_ENTRY2(IDispatch, ICMyCOM) END_COM_MAP() |
[warning]У нас получается в программе 2 дуальных интерфейса, чтобы при получении указателя на IDispatch у нас вызвался определенный интерфейс для этого существует специальный макрос COM_INTERFACE_ENTRY2 в котором вторым параметром указывается дуальный интерфейс который передается[/warning]
4. Добавление функций к нашему классу, перегрузка их
Заходим в окно классов, кликаем правой клавишей мышки по идентификатору интерфейса к которому мы хотим добавить функцию, например я хочу добавить функцию test к интерфейсу ICMyCOM, кликаю по нему правой клавишей, выбираю «Добавить»->»Добавить метод…», мы попадаем в окошко «Мастер добавления методов» в нем вводим такие настройки как на скрине ниже.
там есть атрибуты, в означает что мы вводим в функцию данные, а из означает что из нее выводим, retval означает что что результат вызова метода можно присвоить переменной языка высокого уровня.[warning] Атрибуты «из» и «retval» доступны только когда в качестве параметра указан указатель. [/warning]. Жмем «Далее» и «Готово» и у нас добавилась функция к интерфейсу в файле idl.
Давайте таким же способом попробуем добавить функцию к интерфейсу IB, так же само кликаем правой клавишей мышки в «Окне классов» на идентификаторе IB, в контекстном меню выбираем «Добавить»->»Добавить метод…», попадаем в окошко «Мастер добавления методов» в нем вводим такие настройки
жмем «Готово», все определение функции добавилось к файлу idl. А также определения добавились к классу COM
Теперь нам нужно добавить в наш COM класс все переменные и заполнить его. Так как мы для интерфейсов IA и IB задали функции вручную, то их каркас не сгенерировался в классе COM CCMyCOM, поэтому его туда нужно добавить вручную.
В общем добавляем в класс CCMyCOM
1 2 3 |
public: double m_a; double m_b; |
в конструкторе их инициализируем нулями.
Добавляем определения функций которых нет вручную
1 2 3 4 5 6 7 8 |
public: //сами добавляем STDMETHOD(P_A)(); STDMETHOD(Get_A)(LONG* nPosition); STDMETHOD(P_B)(); //мастер добавил STDMETHOD(test)(DOUBLE m_in, DOUBLE* m_out); STDMETHOD(get_and_set)(DOUBLE m_in, DOUBLE* m_out); |
Добавляем каркасы функций которых нету и заполняем все каркасы. Вот файл CMyCOM.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
// CMyCOM.cpp: реализация CCMyCOM #include "stdafx.h" #include "CMyCOM.h" // CCMyCOM STDMETHODIMP CCMyCOM::P_A() { // TODO: добавьте код реализации ATLTRACE("CCMyCOM::P_A() m_a=%f\n",m_a); return S_OK; } STDMETHODIMP CCMyCOM::Get_A(LONG* nPosition) { // TODO: добавьте код реализации ATLTRACE("CCMyCOM::Get_A() m_a=%f\n",m_a); *nPosition=m_a;//возврат return S_OK; } STDMETHODIMP CCMyCOM::P_B() { // TODO: добавьте код реализации ATLTRACE("CCMyCOM::P_B() m_b=%f\n",m_b); return S_OK; } STDMETHODIMP CCMyCOM::test(DOUBLE m_in, DOUBLE* m_out) { // TODO: добавьте код реализации m_a=m_in; m_a*=3; ATLTRACE("CCMyCOM::test() m_a=%f\n",m_a); *m_out=m_a;//возврат m_a return S_OK; } STDMETHODIMP CCMyCOM::get_and_set(DOUBLE m_in, DOUBLE* m_out) { // TODO: добавьте код реализации m_a=m_in; m_b=m_in; ATLTRACE("CCMyCOM::test() m_a=%f m_b=%f\n",m_a,m_b); *m_out=m_a+m_b;//возврат суммы return S_OK; } |
На этом все, жмем F5 и у нас создается dll и сам файл регистрируется в реестре.
5. Тестируем приложение
Для того чтобы протестировать приложение просто создаем обычное приложение MFC «на основе диалоговых окон» и добавляем туда одну кнопку «start»
в обработчик этой кнопки добавляем следующий код.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
void Ctest_COM2Dlg::OnBnClickedButton1() { // TODO: добавьте свой код обработчика уведомлений CLSID clsid;//GUID LPCLASSFACTORY pClf=NULL; //IClassFactory LPUNKNOWN pUnk=NULL; IA* pIA=NULL; IB* pIB=NULL; IDispatch* pIDis=NULL; ICMyCOM* pICMyC=NULL; HRESULT hr; hr=hr = ::CLSIDFromProgID(L"MY_COM.1", &clsid); if (!SUCCEEDED(hr)) { TRACE("unable to find Program ID -- error = %xn", hr); return; } if ((hr = ::CoGetClassObject(clsid, CLSCTX_INPROC_SERVER, NULL, IID_IClassFactory, (void **) &pClf)) != NOERROR) {; TRACE("unable to find CLSID -- error = %xn", hr); return; } pClf->CreateInstance(NULL, IID_IUnknown, (void**) &pUnk); pUnk->QueryInterface(IID_IA, (void**) &pIA); // All three pIA->QueryInterface(IID_IB, (void**) &pIB); // pointers pIB->QueryInterface(IID_IDispatch, (void**) &pIDis); pIDis->QueryInterface(IID_ICMyCOM, (void**) &pICMyC); TRACE("main: pUnk = %p, pIA = %p, pIB = %p, pIDis= %p, pICMyC = %p\n", pUnk, pIA, pIB, pIDis, pICMyC ); pIA->P_A(); long pos=30; pIA->Get_A(&pos); TRACE("pos=%f\n",pos); pIB->P_B(); double pos1; pIB->get_and_set(30,&pos1); TRACE("pos=%f\n",pos1); pICMyC->test(20,&pos1); TRACE("pos=%f\n",pos); pClf->Release(); pUnk->Release(); pIA->Release(); pIB->Release(); pIDis->Release(); pICMyC->Release(); AfxMessageBox(L"Test succeeded. See Debug window for output."); } |
[warning]Так важный момент, в настройках класса мы задавали porgID «MY_COM» но он изменяется и посмотреть его можно в файле CMyCOM.rgs, вот его код
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
HKCR { MY_COM.1 = s 'CMyCOM Class' { CLSID = s '{26959F44-0BBF-4247-B24A-01A65D0F7DED}' } MY_COM = s 'CMyCOM Class' { CurVer = s 'MY_COM.1' } NoRemove CLSID { ForceRemove {26959F44-0BBF-4247-B24A-01A65D0F7DED} = s 'CMyCOM Class' { ProgID = s 'MY_COM.1' VersionIndependentProgID = s 'MY_COM' ForceRemove Programmable InprocServer32 = s '%MODULE%' { val ThreadingModel = s 'Apartment' } TypeLib = s '{4DD4A978-1D87-4FE5-929B-E0BDC8A8129A}' Version = s '1.0' } } } |
progID у нас из кода видно что MY_COM.1, а не MY_COM, в общем в этом файле смотрите progID, также в него добавляйте если вы забыли добавить при создании класса.[/warning]
К нашему проекту мы должны подключить следующие файлы которые были сгенерированы в ATL это файлы CAtlProc_i.c и CAtlProc_i.h, вот их код
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 |
/* this ALWAYS GENERATED file contains the definitions for the interfaces */ /* File created by MIDL compiler version 7.00.0555 */ /* at Sun Aug 02 08:56:50 2015 */ /* Compiler settings for CAtlProc.idl: Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 7.00.0555 protocol : dce , ms_ext, c_ext, robust error checks: allocation ref bounds_check enum stub_data VC __declspec() decoration level: __declspec(uuid()), __declspec(selectany), __declspec(novtable) DECLSPEC_UUID(), MIDL_INTERFACE() */ /* @@MIDL_FILE_HEADING( ) */ #pragma warning( disable: 4049 ) /* more than 64k source lines */ /* verify that the <rpcndr.h> version is high enough to compile this file*/ #ifndef __REQUIRED_RPCNDR_H_VERSION__ #define __REQUIRED_RPCNDR_H_VERSION__ 475 #endif #include "rpc.h" #include "rpcndr.h" #ifndef __RPCNDR_H_VERSION__ #error this stub requires an updated version of <rpcndr.h> #endif // __RPCNDR_H_VERSION__ #ifndef COM_NO_WINDOWS_H #include "windows.h" #include "ole2.h" #endif /*COM_NO_WINDOWS_H*/ #ifndef __CAtlProc_i_h__ #define __CAtlProc_i_h__ #if defined(_MSC_VER) && (_MSC_VER >= 1020) #pragma once #endif /* Forward Declarations */ #ifndef __IA_FWD_DEFINED__ #define __IA_FWD_DEFINED__ typedef interface IA IA; #endif /* __IA_FWD_DEFINED__ */ #ifndef __ICMyCOM_FWD_DEFINED__ #define __ICMyCOM_FWD_DEFINED__ typedef interface ICMyCOM ICMyCOM; #endif /* __ICMyCOM_FWD_DEFINED__ */ #ifndef __CMyCOM_FWD_DEFINED__ #define __CMyCOM_FWD_DEFINED__ #ifdef __cplusplus typedef class CMyCOM CMyCOM; #else typedef struct CMyCOM CMyCOM; #endif /* __cplusplus */ #endif /* __CMyCOM_FWD_DEFINED__ */ #ifndef __IB_FWD_DEFINED__ #define __IB_FWD_DEFINED__ typedef interface IB IB; #endif /* __IB_FWD_DEFINED__ */ /* header files for imported files */ #include "oaidl.h" #include "ocidl.h" #ifdef __cplusplus extern "C"{ #endif #ifndef __IA_INTERFACE_DEFINED__ #define __IA_INTERFACE_DEFINED__ /* interface IA */ /* [unique][nonextensible][dual][uuid][object] */ EXTERN_C const IID IID_IA; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("7D95CBC0-C33E-4E47-9405-AB4A01278878") IA : public IDispatch { public: virtual HRESULT STDMETHODCALLTYPE P_A( void) = 0; virtual HRESULT STDMETHODCALLTYPE Get_A( /* [retval][out] */ long *nPosition) = 0; }; #else /* C style interface */ typedef struct IAVtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IA * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IA * This); ULONG ( STDMETHODCALLTYPE *Release )( IA * This); HRESULT ( STDMETHODCALLTYPE *GetTypeInfoCount )( IA * This, /* [out] */ UINT *pctinfo); HRESULT ( STDMETHODCALLTYPE *GetTypeInfo )( IA * This, /* [in] */ UINT iTInfo, /* [in] */ LCID lcid, /* [out] */ ITypeInfo **ppTInfo); HRESULT ( STDMETHODCALLTYPE *GetIDsOfNames )( IA * This, /* [in] */ REFIID riid, /* [size_is][in] */ LPOLESTR *rgszNames, /* [range][in] */ UINT cNames, /* [in] */ LCID lcid, /* [size_is][out] */ DISPID *rgDispId); /* [local] */ HRESULT ( STDMETHODCALLTYPE *Invoke )( IA * This, /* [in] */ DISPID dispIdMember, /* [in] */ REFIID riid, /* [in] */ LCID lcid, /* [in] */ WORD wFlags, /* [out][in] */ DISPPARAMS *pDispParams, /* [out] */ VARIANT *pVarResult, /* [out] */ EXCEPINFO *pExcepInfo, /* [out] */ UINT *puArgErr); HRESULT ( STDMETHODCALLTYPE *P_A )( IA * This); HRESULT ( STDMETHODCALLTYPE *Get_A )( IA * This, /* [retval][out] */ long *nPosition); END_INTERFACE } IAVtbl; interface IA { CONST_VTBL struct IAVtbl *lpVtbl; }; #ifdef COBJMACROS #define IA_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IA_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IA_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IA_GetTypeInfoCount(This,pctinfo) \ ( (This)->lpVtbl -> GetTypeInfoCount(This,pctinfo) ) #define IA_GetTypeInfo(This,iTInfo,lcid,ppTInfo) \ ( (This)->lpVtbl -> GetTypeInfo(This,iTInfo,lcid,ppTInfo) ) #define IA_GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) \ ( (This)->lpVtbl -> GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) ) #define IA_Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) \ ( (This)->lpVtbl -> Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) ) #define IA_P_A(This) \ ( (This)->lpVtbl -> P_A(This) ) #define IA_Get_A(This,nPosition) \ ( (This)->lpVtbl -> Get_A(This,nPosition) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IA_INTERFACE_DEFINED__ */ #ifndef __ICMyCOM_INTERFACE_DEFINED__ #define __ICMyCOM_INTERFACE_DEFINED__ /* interface ICMyCOM */ /* [unique][nonextensible][dual][uuid][object] */ EXTERN_C const IID IID_ICMyCOM; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("6ED7E28C-095F-429B-9FFF-5C5BBC11D698") ICMyCOM : public IDispatch { public: virtual /* [id] */ HRESULT STDMETHODCALLTYPE test( /* [in] */ DOUBLE m_in, /* [retval][out] */ DOUBLE *m_out) = 0; }; #else /* C style interface */ typedef struct ICMyCOMVtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( ICMyCOM * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( ICMyCOM * This); ULONG ( STDMETHODCALLTYPE *Release )( ICMyCOM * This); HRESULT ( STDMETHODCALLTYPE *GetTypeInfoCount )( ICMyCOM * This, /* [out] */ UINT *pctinfo); HRESULT ( STDMETHODCALLTYPE *GetTypeInfo )( ICMyCOM * This, /* [in] */ UINT iTInfo, /* [in] */ LCID lcid, /* [out] */ ITypeInfo **ppTInfo); HRESULT ( STDMETHODCALLTYPE *GetIDsOfNames )( ICMyCOM * This, /* [in] */ REFIID riid, /* [size_is][in] */ LPOLESTR *rgszNames, /* [range][in] */ UINT cNames, /* [in] */ LCID lcid, /* [size_is][out] */ DISPID *rgDispId); /* [local] */ HRESULT ( STDMETHODCALLTYPE *Invoke )( ICMyCOM * This, /* [in] */ DISPID dispIdMember, /* [in] */ REFIID riid, /* [in] */ LCID lcid, /* [in] */ WORD wFlags, /* [out][in] */ DISPPARAMS *pDispParams, /* [out] */ VARIANT *pVarResult, /* [out] */ EXCEPINFO *pExcepInfo, /* [out] */ UINT *puArgErr); /* [id] */ HRESULT ( STDMETHODCALLTYPE *test )( ICMyCOM * This, /* [in] */ DOUBLE m_in, /* [retval][out] */ DOUBLE *m_out); END_INTERFACE } ICMyCOMVtbl; interface ICMyCOM { CONST_VTBL struct ICMyCOMVtbl *lpVtbl; }; #ifdef COBJMACROS #define ICMyCOM_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define ICMyCOM_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define ICMyCOM_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define ICMyCOM_GetTypeInfoCount(This,pctinfo) \ ( (This)->lpVtbl -> GetTypeInfoCount(This,pctinfo) ) #define ICMyCOM_GetTypeInfo(This,iTInfo,lcid,ppTInfo) \ ( (This)->lpVtbl -> GetTypeInfo(This,iTInfo,lcid,ppTInfo) ) #define ICMyCOM_GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) \ ( (This)->lpVtbl -> GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) ) #define ICMyCOM_Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) \ ( (This)->lpVtbl -> Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) ) #define ICMyCOM_test(This,m_in,m_out) \ ( (This)->lpVtbl -> test(This,m_in,m_out) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __ICMyCOM_INTERFACE_DEFINED__ */ #ifndef __CAtlProcLib_LIBRARY_DEFINED__ #define __CAtlProcLib_LIBRARY_DEFINED__ /* library CAtlProcLib */ /* [version][uuid] */ EXTERN_C const IID LIBID_CAtlProcLib; EXTERN_C const CLSID CLSID_CMyCOM; #ifdef __cplusplus class DECLSPEC_UUID("26959F44-0BBF-4247-B24A-01A65D0F7DED") CMyCOM; #endif #endif /* __CAtlProcLib_LIBRARY_DEFINED__ */ #ifndef __IB_INTERFACE_DEFINED__ #define __IB_INTERFACE_DEFINED__ /* interface IB */ /* [uuid][object] */ EXTERN_C const IID IID_IB; #if defined(__cplusplus) && !defined(CINTERFACE) MIDL_INTERFACE("4D95CBC0-C33E-4E47-9405-AB4A01278878") IB : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE P_B( void) = 0; virtual HRESULT STDMETHODCALLTYPE get_and_set( /* [in] */ DOUBLE m_in, /* [retval][out] */ DOUBLE *m_out) = 0; }; #else /* C style interface */ typedef struct IBVtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IB * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IB * This); ULONG ( STDMETHODCALLTYPE *Release )( IB * This); HRESULT ( STDMETHODCALLTYPE *P_B )( IB * This); HRESULT ( STDMETHODCALLTYPE *get_and_set )( IB * This, /* [in] */ DOUBLE m_in, /* [retval][out] */ DOUBLE *m_out); END_INTERFACE } IBVtbl; interface IB { CONST_VTBL struct IBVtbl *lpVtbl; }; #ifdef COBJMACROS #define IB_QueryInterface(This,riid,ppvObject) \ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) #define IB_AddRef(This) \ ( (This)->lpVtbl -> AddRef(This) ) #define IB_Release(This) \ ( (This)->lpVtbl -> Release(This) ) #define IB_P_B(This) \ ( (This)->lpVtbl -> P_B(This) ) #define IB_get_and_set(This,m_in,m_out) \ ( (This)->lpVtbl -> get_and_set(This,m_in,m_out) ) #endif /* COBJMACROS */ #endif /* C style interface */ #endif /* __IB_INTERFACE_DEFINED__ */ /* Additional Prototypes for ALL interfaces */ /* end of Additional Prototypes */ #ifdef __cplusplus } #endif #endif |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
/* this ALWAYS GENERATED file contains the IIDs and CLSIDs */ /* link this file in with the server and any clients */ /* File created by MIDL compiler version 7.00.0555 */ /* at Sun Aug 02 08:56:50 2015 */ /* Compiler settings for CAtlProc.idl: Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 7.00.0555 protocol : dce , ms_ext, c_ext, robust error checks: allocation ref bounds_check enum stub_data VC __declspec() decoration level: __declspec(uuid()), __declspec(selectany), __declspec(novtable) DECLSPEC_UUID(), MIDL_INTERFACE() */ /* @@MIDL_FILE_HEADING( ) */ #pragma warning( disable: 4049 ) /* more than 64k source lines */ #ifdef __cplusplus extern "C"{ #endif #include <rpc.h> #include <rpcndr.h> #ifdef _MIDL_USE_GUIDDEF_ #ifndef INITGUID #define INITGUID #include <guiddef.h> #undef INITGUID #else #include <guiddef.h> #endif #define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \ DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) #else // !_MIDL_USE_GUIDDEF_ #ifndef __IID_DEFINED__ #define __IID_DEFINED__ typedef struct _IID { unsigned long x; unsigned short s1; unsigned short s2; unsigned char c[8]; } IID; #endif // __IID_DEFINED__ #ifndef CLSID_DEFINED #define CLSID_DEFINED typedef IID CLSID; #endif // CLSID_DEFINED #define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \ const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}} #endif !_MIDL_USE_GUIDDEF_ MIDL_DEFINE_GUID(IID, IID_IA,0x7D95CBC0,0xC33E,0x4E47,0x94,0x05,0xAB,0x4A,0x01,0x27,0x88,0x78); MIDL_DEFINE_GUID(IID, IID_ICMyCOM,0x6ED7E28C,0x095F,0x429B,0x9F,0xFF,0x5C,0x5B,0xBC,0x11,0xD6,0x98); MIDL_DEFINE_GUID(IID, LIBID_CAtlProcLib,0x4DD4A978,0x1D87,0x4FE5,0x92,0x9B,0xE0,0xBD,0xC8,0xA8,0x12,0x9A); MIDL_DEFINE_GUID(CLSID, CLSID_CMyCOM,0x26959F44,0x0BBF,0x4247,0xB2,0x4A,0x01,0xA6,0x5D,0x0F,0x7D,0xED); MIDL_DEFINE_GUID(IID, IID_IB,0x4D95CBC0,0xC33E,0x4E47,0x94,0x05,0xAB,0x4A,0x01,0x27,0x88,0x78); #undef MIDL_DEFINE_GUID #ifdef __cplusplus } #endif |
файл CAtlProc_i.c нужно переименовать в CAtlProc_i.сpp и подключить вот так
1 2 |
#include "CAtlProc_i.h" #include "CAtlProc_i.cpp" |
в каждый из этих файлов в начале файла нужно добавить строчку
1 |
#include "stdafx.h" |
Нажимаем F5, у нас компилируется и запускается программа, в программе нажимаем кнопку «start» и видим в отладчике следующее.
На это все.
[youtube]https://www.youtube.com/watch?v=aAXMwn9vbYI[/youtube]