Аннотация:
В этой главе, позаимствованной из книги "ActiveX-Создание Web-приложений" Тома Армстронга, рассматриваются основные понятия модели COM, такие как интерфейс IUnknown, GUID, фабрики классов и т. д. Кроме того, автор приводит примеры реализации COM-клиентов и COM-серверов с использованием языка C++, Visual Basic и библиотеки ATL.
Клиент на VB это конечно просто, однако IMHO недостаточно наглядно. Я не смог реализовать клиента для сервера на ATL с ранним связыванием:
IMath* pMath = NULL;
hr = pUnk->QueryInterface( IID_IMath, (LPVOID*)&pMath ); pUnk->Release();
if ( FAILED( hr ))
{
printf("QueryInterface() for IMath failed\n");
return -1;
}
long result;
pMath->Multiply( 100, 8, &result );
Вот здесь-то сервер и валится с эксцепшином. В чём трабла?
Никогда не занимался COM, решил попробовать. Скомпилировал пример (клиент и сервер без ATL), зарегистрировал компонент — CoGetClassObject возвращает ошибку, pCF=0.
Подскажите, в чем может быть проблема? VC++ 6.0, NT4.0.
Фабрика классов — это, по-моему не просто так себе, а серъезный шаг человечества...Однако, если Бог поступал таким же образом, создавая человека, то с
virtual HRESULT CreateInstance(LPUNKNOWN pUnk, REFIID riid, void** ppv)=0;
все и так ясно, а вот
virtual HRESULT LockServer (BOOL fLock) = 0;
выглядит интересно:))
Возможно вы проводили не объективные тесты или же не поняли сущности очень раннего, раннего и позднего связывания. Попробую объяснить ещё раз.
Фактически есть 2 типа связывания — ранее и позднее. Раннее — это когда информацию о типах СОМ-сервера вы предоставляете компилятору ещё на этапе разработки проекта, например с помощью tlb файла вашего сервера. Позднее связывание — это когда подобная информация становится вам доступна только во время выполнения с помощью метода Invoke.
Однако, клиент, использующий раннее связывание может вызывать как сервер реализованный в ЕХЕ, так и в ДЛЛ. Так вот, когда вызывается ДЛЛ, то это есть очень раннее связывание. И оно не может работать(если специально не постараться) медлееннее, чем просто раннее( ЕХЕ-сервер), так как сама ДЛЛ грузится в адресное пространство клиета и работает без каких-либо процедур межпроцессного маршалинга, которые применяются в случае ЕХЕ серверов.
А где-ж ваше мыло взять-то? Вопрос такой:
нужно попользоваться интерфейсом IHTMLRuleStyle (стандартный). Расскажите пожалуйста как нужно действовать чтоб это сделать, а то не получается. Проект могу выслать на мыло (150 Кб в архиве). Мне кажется что моя проблема в том, что зная имя интерфейса я не могу правильно определить его uuid и clsid. Мое мыло Earth@Tut.By
Всё конечно интересно написано, но прочитав где-то треть статьи (и параллельно пробуя компилировать код) застрял... дошёл где-то до создания фабрик.
Сам только изучаю C++ (всю жизнь писал на яве и C#), так что сорри, если некоторые вопросы покажутся очевидными или глупыми...
HRESULT Math::QueryInterface( REFIID riid, void** ppv )
{
switch( riid )
{
case IID_IUnknown: case IID_IMath;
*ppv = this;
// Поскольку мы возвращаем новый указатель на
// интерфейс, необходимо вызвать метод AddRef
AddRef();
return ( S_OK ) ;
default:
return ( E_NOINTERFACE );
}
}
3. Что такое IID_IUnknown, IID_IMath? Как генерить их значения?
(
Сделал временно заглушку
#define IID_IUnknown _HRESULT_TYPEDEF_(0x11111111L)
#define IID_IMath _HRESULT_TYPEDEF_(0x22222222L)
)
4. При компиляции следующего участка кода:
HRESULT Math::QueryInterface( REFIID riid, void** ppv )
{
switch( riid )
{
case IID_IUnknown:
case IID_IMath:
*ppv = this;
// Поскольку мы возвращаем новый указатель на
// интерфейс, необходимо вызвать метод AddRef
AddRef();
return ( S_OK ) ;
default:
return ( E_NOINTERFACE );
}
}
Выдаётся ошибка
Error 1 error C2450: switch expression of type 'const IID' is illegal c:\projects\cplusplustests\mathtest\mathtest\mathtest.cpp 58
5. При компиляции InterlockedDecrement( &m_lRef ); выдаётся ошибка:
Error 2 error C2664: 'InterlockedDecrement' : cannot convert parameter 1 from 'DWORD *__w64 ' to 'volatile LONG *' c:\projects\cplusplustests\mathtest\mathtest\mathtest.cpp 76
В VS C++ 2005 определение функции InterlockedDecrement:
WINBASEAPI
LONG
WINAPI
InterlockedDecrement (
__inout LONG volatile *lpAddend
);
6. То же самое и для InterlockedIncrement
Error 3 error C2664: 'InterlockedIncrement' : cannot convert parameter 1 from 'DWORD *__w64 ' to 'volatile LONG *' c:\projects\cplusplustests\mathtest\mathtest\mathtest.cpp 92
!!! Вроде бы должно решаться подключением #include "afxwin.h", где объявлен public typedef IUnknown* LPUNKNOWN;
Но тогда при компиляции выдаётся:
Error 1 fatal error C1189: #error : Building MFC application with /MD[d] (CRT dll version) requires MFC shared dll version. Please #define _AFXDLL or do not use /MD[d] c:\program files\microsoft visual studio 8\vc\atlmfc\include\afx.h 24
Если мне не изменяет знание C++, то
к каждому прототипу в данном примере
нужно приписать virtual.
class Math : public IMath
{
public:
long Add(long Op1, long Op2);
long Subtract(long Op1, long Op2);
long Multiply(long Op1, long Op2);
long Divide (long Op1, long Op2);
};
(не уверен)
Удвой число ошибок, если не получается добиться цели.
S>class Math : public IMath S>{ S>public: S> long Add(long Op1, long Op2); S> long Subtract(long Op1, long Op2); S> long Multiply(long Op1, long Op2); S> long Divide (long Op1, long Op2); S>};
S>(не уверен)
Виноват. ошибся.
Удвой число ошибок, если не получается добиться цели.