Вопрос по примеру из MSDN
{
PROPERTY(VALUE, IMETH_ACCUM, IDMEMBER_ACCUM, VT_I4),
PROPERTY(ACCUM, IMETH_ACCUM, IDMEMBER_ACCUM, VT_I4),
PROPERTY(OPND, IMETH_OPERAND, IDMEMBER_OPERAND, VT_I4),
PROPERTY(OP, IMETH_OPERATOR, IDMEMBER_OPERATOR, VT_I2),
METHOD0(EVAL, IMETH_EVAL, IDMEMBER_EVAL, VT_BOOL),
METHOD0(CLEAR, IMETH_CLEAR, IDMEMBER_CLEAR, VT_EMPTY),
METHOD0(DISPLAY, IMETH_DISPLAY, IDMEMBER_DISPLAY, VT_EMPTY),
METHOD0(QUIT, IMETH_QUIT, IDMEMBER_QUIT, VT_EMPTY),
METHOD1(BUTTON, IMETH_BUTTON, IDMEMBER_BUTTON, VT_BOOL),
};
INTERFACEDATA NEARDATA g_idataCCalc =
{
rgmdataCCalc, DIM(rgmdataCCalc)
};
Где мне ,можно найти нужную информацию для нужного мне интерфейса(я так понял методы которые он содержит,и т.д.) ???
Получается (на сколько я смог разобратся в этом COM :confused: ) что реализовать.Это я насколько понял делается через IDispatch.
#include "imapi2.h"
class CEvent
{
STDMETHOD_(HRESULT, Update)(IDispatch *object, IDispatch *progress);
};
STDMETHODIMP_(HRESULT) CEvent::Update(IDispatch *object, IDispatch *progress)
{
//если всё нормально, то попадём сюда
return S_OK;
}
class CDiscFormatDataEvent : public IUnknown
{
public:
CDiscFormatDataEvent();
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, void**);
virtual ULONG STDMETHODCALLTYPE AddRef();
virtual ULONG STDMETHODCALLTYPE Release();
static CDiscFormatDataEvent* Create();
private:
unsigned long m_refs;
public:
CEvent m_event;
IUnknown* m_pPunk;
};
static PARAMDATA pUpdate [] =
{
{OLESTR("object"), VT_DISPATCH},
{OLESTR("progress"), VT_DISPATCH}
};
static METHODDATA mUpdate =
{
OLESTR("Update"), pUpdate, DISPID_DDISCFORMAT2DATAEVENTS_UPDATE, 0, CC_STDCALL, 2, DISPATCH_METHOD, VT_I4
};
static INTERFACEDATA iUpdate =
{
&mUpdate, 1
};
CDiscFormatDataEvent::CDiscFormatDataEvent() : m_refs(0)
{
}
CDiscFormatDataEvent* CDiscFormatDataEvent::Create()
{
HRESULT hr = S_OK;
CDiscFormatDataEvent* pEvent = NULL;
ITypeInfo *pTI = NULL;
CreateDispTypeInfo(&iUpdate, LOCALE_SYSTEM_DEFAULT, &pTI);
/* Вместо CreateDispTypeInfo, лучше делать так:
LPTYPELIB ptlib = NULL;
HRESULT hr = LoadRegTypeLib(LIBID_IMAPILib2, IMAPILib2_MajorVersion, IMAPILib2_MinorVersion, LOCALE_SYSTEM_DEFAULT, &ptlib);
hr = ptlib->GetTypeInfoOfGuid(IID_DDiscFormat2DataEvents, &pTI);
ptlib->Release(); */
if(SUCCEEDED(hr))
{
pEvent = new CDiscFormatDataEvent();
hr = CreateStdDispatch(pEvent, &pEvent->m_event, pTI, &pEvent->m_pPunk);
pTI->Release();
if(SUCCEEDED(hr)){
pEvent->AddRef();
}
else{
delete pEvent;
pEvent = NULL;
}
}
return pEvent;
}
HRESULT STDMETHODCALLTYPE CDiscFormatDataEvent::QueryInterface(REFIID riid, void **ppvObject)
{
if (IsEqualIID(riid, IID_IUnknown))
*ppvObject = this;
else if (IsEqualIID(riid, IID_IDispatch) || IsEqualIID(riid, IID_DDiscFormat2DataEvents)){
return m_pPunk->QueryInterface(IID_IDispatch, ppvObject);
}
else{
*ppvObject = NULL;
return ResultFromScode(E_NOINTERFACE);
}
AddRef();
return S_OK;
}
ULONG STDMETHODCALLTYPE CDiscFormatDataEvent::AddRef()
{
return ++m_refs;
}
ULONG STDMETHODCALLTYPE CDiscFormatDataEvent::Release()
{
if(--m_refs == 0 && m_pPunk)
m_pPunk->Release();
return m_refs;
}
int _tmain(int argc, _TCHAR* argv[])
{
::CoInitialize(NULL);
CDiscFormatDataEvent* pEvent = CDiscFormatDataEvent::Create();
if(pEvent == NULL) return 0;
IDiscFormat2Data* pDiscFormatData = NULL;
HRESULT hr = CoCreateInstance(CLSID_MsftDiscFormat2Data, NULL, CLSCTX_INPROC_SERVER,
IID_IDiscFormat2Data, (void**)&pDiscFormatData);
if(FAILED(hr)) return 0;
IConnectionPointContainer *pConnPtContainer = NULL;
hr = pDiscFormatData->QueryInterface(IID_IConnectionPointContainer,(void**)&pConnPtContainer);
if(FAILED(hr)) return 0;
IConnectionPoint* pConnectionPoint = NULL;
hr = pConnPtContainer->FindConnectionPoint(IID_DDiscFormat2DataEvents,&pConnectionPoint);
if(FAILED(hr)) return 0;
pConnPtContainer->Release();
//подписываемся на событие
DWORD Cookie = 0;
hr = pConnectionPoint->Advise(pEvent,&Cookie);
if(FAILED(hr)) return 0;
//отписываемся от события
hr = pConnectionPoint->Unadvise(Cookie);
return 0;
}
Не знаю уж, на сколько всё верно получилось, но суть должна быть понятна.
ЗЫ:REFOT мне не ясно где брать начинку для таких классов которые нужно вручную расписывать.
Для отслеживания прогресса "прожига" в IMAPI 2 , я на сколько понял мне надо вызвать интерефейс DDiscFormat2DataEvents что бы получить из него IDiscFormat2DataEventArgs
IDiscFormat2DataEventArgs тебе передатут в DDiscFormat2DataEvents::Update(IDispatch *object, IDispatch *progress), где progress и есть IDiscFormat2DataEventArgs.
ЗЫ:REFOT мне не ясно где брать начинку для таких классов которые нужно вручную расписывать.
;) Всю начинку я взял из imapi2.h. Так же можно и в библиотеку типов заглянуть :).
extern RPC_IF_HANDLE __MIDL_itf_imapi2_0000_0011_v0_0_c_ifspec;
extern RPC_IF_HANDLE __MIDL_itf_imapi2_0000_0011_v0_0_s_ifspec;
#ifndef __DDiscFormat2DataEvents_INTERFACE_DEFINED__
#define __DDiscFormat2DataEvents_INTERFACE_DEFINED__
/* interface DDiscFormat2DataEvents */
/* [helpstring][unique][uuid][oleautomation][nonextensible][object] */
EXTERN_C const IID IID_DDiscFormat2DataEvents;
#if defined(__cplusplus) && !defined(CINTERFACE)
MIDL_INTERFACE("2735413C-7F64-5B0F-8F00-5D77AFBE261E")
DDiscFormat2DataEvents : public IDispatch
{
public:
virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE Update(
/* [in] */ __RPC__in_opt IDispatch *object,
/* [in] */ __RPC__in_opt IDispatch *progress) = 0;
};
#else /* C style interface */
Тут мы видим, что интерфейс имеет метод Update, который имеет id = DISPID_DDISCFORMAT2DATAEVENTS_UPDATE, принимает два параметра IDispatch* и
возвращает значение HRESULT.
Дальше мы всё это описываем:
static PARAMDATA pUpdate [] =
{
{OLESTR("object") /* Название параметра */, VT_DISPATCH /* Тип параметра*/},
{OLESTR("progress") /* Название параметра */, VT_DISPATCH /* Тип параметра*/}
};
//Описываем сам метод
static METHODDATA mUpdate =
{
OLESTR("Update") // Название метода
,pUpdate // Параметры описанные выше
,DISPID_DDISCFORMAT2DATAEVENTS_UPDATE // Id метода
,0 // индекс в VTBL
,CC_STDCALL // Соглашение о вызове
,2 // количество аргументов метода
,DISPATCH_METHOD // указываем что это метод
VT_I4 // тип возвращаемого значения
};
//Описываем интерфейс
static INTERFACEDATA iUpdate =
{
&mUpdate // Описание метода Update
,1 // Количество членов интерфейса
};
Всё это можно не описывать, а просто загрузить информацию из библиотеки типа:
HRESULT hr = LoadRegTypeLib(LIBID_IMAPILib2,
IMAPILib2_MajorVersion,
IMAPILib2_MinorVersion,
LOCALE_SYSTEM_DEFAULT,
&ptlib);
hr = ptlib->GetTypeInfoOfGuid(IID_DDiscFormat2DataEvents, &pTI);
ptlib->Release();
После чего через функцию CreateStdDispatch создаём реализацию IDispatch для описанного интерфейса:
,&pEvent->m_event //Указатель на предоставляемый объект.
,pTI, //Указатель на информацию о типе
,&pEvent->m_pPunk // Возвращаемый интерфейс
);
Тут интерфейс IUnknown для объекта реализуем сами, это методы QueryInterface, AddRef, Release. Тут нет ничего сложного.
pEvent->m_event - этот объект реализует метод Update, который и будет вызываться при наступлении события связанного с прожигом.
Как устроены методы QueryInterface, AddRef, Release и как подписаться на событие, смотри выше.
Интерфейс DDiscFormat2DataEvents нигде не реализован, для него не реализованы ни IUnknown, ни IDispatch, всё нужно делать самому и CoCreateInstance тут не причём.
Смотри, ты хочешь получать информацию о состоянии прожига или чего-то ещё.
Обращаешься к MSDN, а там тебе говорят, да не вопрос, чувак, дай нам только указатель на объект который реализует интерфейс DDiscFormat2DataEvents,
и как только состояние прожига изменится, мы у твоего объекта вызовем метод Update(...);
Ты радостно, быстренько пишешь:
{
STDMETHOD_(HRESULT, Update)(IDispatch *object, IDispatch *progress);
};
STDMETHODIMP_(HRESULT) MyDDiscFormat2DataEvents::Update(IDispatch *object, IDispatch *progress)
{
return S_OK;
}
И думаешь вот и всё, делов-то, интерфейс DDiscFormat2DataEvents реализовал, можно теперь и подписаться на событие,
передав в Advise интерфейса IConnectionPoint указатель на объект MyDDiscFormat2DataEvents.
А тут фиг, не компилится! Требуют реализовать какие-то ещё IUnknown и IDispatch,
которые как оказывается наследует интерфейс DDiscFormat2DataEvents.
Думаешь, что за фигня?!
А потом, почитав немного, выясняешь, что Advice, вызывает у твоего объекта
метод QueryInterface интерфейса IUnknow, которому говорит, дай-ка, пожалуйста, мне указатель на объект DDiscFormat2DataEvents,
а если не дашь, на событие не подпишу!
Ну, а когда происходит само событие… О, ужас! Метод Update твоего объекта, вообще вызывается через интерфейс IDispatch:
DISPID_DDISCFORMAT2DATAEVENTS_UPDATE,
IID_NULL,
LOCALE_SYSTEM_DEFAULT,
DISPATCH_METHOD,
.....);
И ничего не поделаешь, придётся писать реализацию и IUnknow и IDispatch...
Выше я приводил пример, как реализовать интерфейс DDiscFormat2DataEvents и подписаться на событие.
Upd
Ссылки по теме:
http://www.rsdn.ru/article/com/introcom.xml
http://www.rsdn.ru/summary/2167.xml
Исходники рабочей программы:
http://narod.ru/disk/12569938000/BurnCD_src.zip.html
Дай лучше icq или ещё что-то, так прощё будет объяснить.