Фабрики Класса IDL
Создание компонента - 1 // // Функция создания // extern C IUnknown* CreateInstance() { IUnknown* pI = (IUnknown*)(void*)new CA; PI->AddRef(); return pI; }
Создание компонента - 1 #include #include // Объявление IUnknown typedef IUnknown* (*CREATEFUNCPTR)(); IUnknown* CallCreateInstance(char* name) { // Загрузить в процесс динамическую библиотеку HINSTANCE hComponent = ::LoadLibrary(name); if (hComponent == NULL) { } // Получить адрес функции CreateInstance CREATEFUNCPTR CreateInstance = (CREATEFUNCPTR)::GetProcAddress(hComponent, "CreateInstance"); if (CreateInstance == NULL) { } return CreateInstance(); }
Создание компонента - 1 cmpnt.dll Program.exe DLL pIface …F1() …F2() cmpnt.dll
Создание компонента - 2 HRESULT __stdcall CoCreateInstance( const CLSID& clsid,//ID создаваемого компонента IUnknown* pUnknownOuter,//Внешний компонент DWORD dwClsContext, //Контекст сервера const IID& iid,//ID требуемого интерфейса void** ppv//возвращаемый указатель );//на наш интерфейс
Создание компонента - 2 // Создать компонент IX* pIX = NULL; HRESULT hr = ::CoCreateInstance( CLSID_Component1, NULL, CLSCTX_INPROC_SERVER, IID_IX, (void**)&pIX ); if (SUCCEEDED(hr)) { pIX->Fx(); pIX->Release(); };
Создание компонента - 2 Program.exe DLL …F1() …F2() CoCreateInstance() Реестр cmpnt.dll CLSID_Component1 IID_IX pIX
Создание компонента – 2 Контекст класса CLSCTX_INPROC_SERVER Клиент принимает только компоненты, которые исполняются в одном с ним процессе. Подобные компоненты должны быть реализованы в DLL. CLSCTX_LOCAL_SERVER Клиент будет работать с компонентами, которые выполняются в другом процессе, но на той же самой машине. Локальные серверы реализуются в EXE. CLSCTX_REMOTE_SERVER Клиент допускает компоненты, выполняющиеся на другой машине. Использование этого флага требует задействования DCOM.
Создание компонента - 3 Program.exe DLL CoCreateInstance() CLSID_Component1 IID_IX pIX IClassFactory IX Cmpnt.dll
Создание компонента - 3 HRESULT __stdcall CoGetClassObject( const CLSID& clsid,//ID компонента DWORD dwClsContext,//контекст COSERVERINFO* pServerInfo, // Зарезервировано для DCOM const IID& iid,//ID интерфейса void** ppv//указатель на );//ФАБРИКУ КЛАССА
Создание компонента - 3 interface IClassFactory : IUnknown { HRESULT __stdcall CreateInstance(IUnknown* pUnknownOuter, const IID& iid, void** ppv); HRESULT __stdcall LockServer(BOOL bLock); }
Создание компонента - 3 HRESULT CoCreateInstance(const CLSID& clsid, IUnknown* pUnknownOuter, DWORD dwClsContext, const IID& iid, void** ppv) { // Установить в NULL выходной параметр *ppv = NULL; // Создать фабрику класса и получить указатель на интерфейс IClassFactory IClassFactory* pIFactory = NULL; HRESULT hr = CoGetClassObject(clsid, dwClsContext, NULL, IID_IClassFactory, (void**)&pIFactory); if (SUCCEEDED(hr)) { // Создать компонент hr = pIFactory->CreateInstance(pUnknownOuter, iid, ppv); // Освободить фабрику класса pIFactory->Release(); } return hr; }
Создание компонента - 3 Благодаря фабрике класса возможно: Создание набора компонентов Специфическое создание компонента
Создание компонента -3 Хранилище в DLL STDAPI DllGetClassObject( const CLSID& clsid, const IID& iid, void** ppv );
Создание компонента - 3
Несколько компонентов в одной DLL
Создание компонента - 3 Несколько компонентов в одной DLL, с одной фабрикой класса
IDL Interface Definition Language
Адресация в процессах
Общие требования к вызову Процесс должен иметь возможность вызвать функцию в другом процессе. Процесс должен иметь возможность передавать другому процессу данные. Клиент не должен беспокоиться о том, является ли компонент сервером внутри или вне процесса.
Вызов из другого процесса
«Потайной» вызов из другого процесса
IDL Язык описания интерфейсов Автоматическая генерация заместителя/заглушки Автоматическая генерация библиотеки типов
Описание интерфейсов import unknwn.idl; // Интерфейс IX [ object, uuid(32bb8323-b41b-11cf-a6bb-0080c7b2d682), helpstring(IX Interface), pointer_default(unique) ] interface IX : IUnknown { HRESULT FxStringIn([in, string] wchar_t* szIn); HRESULT FxStringOut([out, string] wchar_t** szOut); };
Pointer_default Ref – указатель как ссылка Unique – может иметь значение NULL Ptr – указатель С
Входные и выходные параметры в IDL HRESULT foo([in] int x, [in, out] int* y, [out] int* z);
Модификатор size_is // Интерфейс IY [ object, uuid(32bb8324-b41b-11cf-a6bb-0080c7b2d682), helpstring(Интерфейс IY), pointer_default(unique) ] interface IY : IUnknown { HRESULT FyCount([out] long* sizeArray); HRESULT FyArrayIn([in] long sizeIn, [in, size_is(sizeIn)] long arrayIn[]); HRESULT FyArrayOut([out, in] long* psizeInOut, [out, size_is(*psizeInOut)] long arrayOut[]); };
Структуры в IDL typedef struct { double x; double y; double z; } Point3d; [ object, uuid(32bb8325-b41b-11cf-a6bb-0080c7b2d682), helpstring(Интерфейс IZ), pointer_default(unique) ] interface IZ : IUnknown { HRESULT FzStructIn([in] Point3d pt); HRESULT FzStructOut([in] Point3d* pt); };
Компилятор MIDL midl foo.idl FOO.H Заголовочный файл (для С и С++), содержащий объявления всех интерфейсов, описанных в файле IDL. FOO_I.C Файл С, в котором определены все GUID, использованные в файле IDL. FOO_P.C Файл С, реализующий код заместителей и заглушек для всех описанных в файле IDL интерфейсов. DLLDATA.C Файл С, реализующий DLL, которая содержит код заместителей и заглушек.
Схема генерации с помощью MIDL
Информация в реестре после MIDL
Серверы в EXE - отличия Нет точек входа DllCanUnloadNow, DllRegisterServer, DllUnregisterServer, DllGetClassObject Запуск фабрики класса Блокировка/освобождение
Серверы в EXE - отличия Выгружается самостоятельно Ключи RegServer, UnregServer HRESULT hr = ::CoRegisterClassObject(*pData->m_pCLSID, static_cast (pIFactory), CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &dwRegister); ::CoRevokeClassObject() HKCR/CLSID/{x}/LocalServer32 Удалённый вызов
AppID в реестре