vc编写com,谁能指导指导方向!!谢谢
解决方案 »
- 关于debug调试的问题?
- 如何根据系统进程判断程序所在的目录,急,恳请支招?
- 非MFC下,如何清空一个ListBox里的内容?
- 初学者学MFC到底应从哪本书学起?
- MFC 中如何动态创建ACTIVEX 控件? 急!急!急! 在线.
- 送分的问题
- 如何动态初始化对话框中的内容?
- CSDN怎么上传自己作的软件?别的地方有什么好的主页或上传或宣传自己的软件的地方吗?
- 为什么我的win32 console程序(dos模式)的循环有时候要敲回车才能继续运行?
- 标准COM组件中的私有方法怎么定义,望那位高手告知!!!
- 急问:属性页的中文版修改成英文版!!!!!在在线等
- 我在工程的一个静态库中放入了图像资源,为何无法用LOADBITMAP读取。
As part of a project I'm working on I need to implement multiple COM interfaces.
If I wanted to implement the IWidget interface and the IThingAMaBob interface it might look like this.class CWidgets : public IWidgets
{
public:
virtual HRESULT __stdcall QueryInterface(REFIID riid,
void __RPC_FAR *__RPC_FAR *ppvObject);
virtual ULONG __stdcall AddRef(void);
virtual ULONG __stdcall Release(void); virtual HRESULT __stdcall MyExtraFunction();
};and similarly for the IThingAMaBob interface. This is COM 101 material.
It becomes a bit tedious coding this all the time. Factor in the need to implement, for each interface, the IUnknown base methods correctly (especially QueryInterface) and the smart programmer starts researching better (easier) ways to do it.Fortunately, for the MFC programmer, MFC provides a much easier way to not only implement a COM interface, it provides an easy way to define multple interfaces in the one class.MFC COM Macros
We can rewrite our CWidgets class like this, using some MFC macros. class CWidgets : public CCmdTarget
{
public:
DECLARE_INTERFACE_MAP() BEGIN_INTERFACE_PART(Widgets, IWidgets)
STDMETHOD(MyExtraFunction)();
END_INTERFACE_PART(Widgets)
};The first thing you'll notice is that the class is now derived from CCmdTarget. It needs to be derived from CCmdTarget either directly or indirectly for reasons we'll see a little later. The class then declares an interface map followed by an interface part. The interface part defines a nested class called (in this case) XWidgets which is derived from the IWidgets interface. (The macro prepends an X to the first parameter of the macro to give the nested class a unique name that won't clash with the 'C' or 'I' names). The BEGIN_INTERFACE_PART macro also declares the 3 standard methods inherited from IUnknown for us. Any additional methods for this interface must be defined between the BEGIN_INTERFACE_PART and END_INTERFACE_PART macros.
In our implementation file we'd have something like this.BEGIN_INTERFACE_MAP(CWidgets, CCmdTarget)
INTERFACE_PART(CWidgets, IID_IWidgets, Widgets)
END_INTERFACE_MAP()plus our implementation of the methods of the IWidgets interface. Note that even though we don't have to declare the basic IUnknown methods we do have to implement them. The four methods of our IWidgets interface might look like this. STDMETHODIMP_(ULONG) CWidgets::XWidgets::AddRef()
{
METHOD_PROLOGUE(CWidgets, Widgets);
return pThis->ExternalAddRef();
}STDMETHODIMP_(ULONG) CWidgets::XWidgets::Release()
{
METHOD_PROLOGUE(CWidgets, Widgets) return pThis->ExternalRelease();
}STDMETHODIMP CWidgets::XWidgets::QueryInterface(REFIID iid, LPVOID far* ppvObj)
{
METHOD_PROLOGUE(CWidgets, Widgets) return pThis->ExternalQueryInterface(&iid, ppvObj);
}STDMETHODIMP CWidgets::XWidgets::MyExtraFunction()
{
METHOD_PROLOGUE(CWidgets, Widgets) // Do something
.
.
.
return S_OK;
}Before we dive into this let's recap. Our class is derived from CCmdTarget and, via the BEGIN_INTERFACE_PART macro, contains a nested class called XWidgets.
The first thing you'll notice in the nested class implementation is a new macro, METHOD_PROLOGUE. It takes two arguments. The first is the name of the enclosing class, the second is the name of the inner class (without the X). If we look at the definition of the macro we see this#define METHOD_PROLOGUE(theClass, localClass) \
theClass* pThis = \
((theClass*)((BYTE*)this - offsetof(theClass, m_x##localClass))); \
AFX_MANAGE_STATE(pThis->m_pModuleState) \
pThis; // avoid warning from compiler \which the preprocessor replaces with CWidgets* pThis = \
((CWidgets*)((BYTE*)this - offsetof(CWidgets, m_xWidgets:))); \
AFX_MANAGE_STATE(pThis->m_pModuleState) \
pThis; // avoid warning from compiler \.
Once we've defined our interface and written the implementation we need to have an instance of the class to use. One might be tempted to do this in our outer class. class CWidgets : public CCmdTarget
{
public:
DECLARE_INTERFACE_MAP() BEGIN_INTERFACE_PART(Widgets, IWidgets)
STDMETHOD(MyExtraFunction)();
END_INTERFACE_PART(Widgets)
XWidgets m_myWidget;
};which defines the XWidgets class and then creates an instance of it embedded in the CWidgets object. That'll certainly compile but when your client code calls QueryInterface() to get an instance of the XWidgets class it won't get a pointer to m_myWidget. What it gets is a pointer to an instance of XWidgets called m_xWidgets. Hang on! Where did m_xWidgets come from?Hidden inside the END_INTERFACE_PART macro is a declaration of an instance of the nested class. Note this well. Usually when you define a nested class you have to declare an instance of the nested class within the enclosing class. The MFC macros assume that you'll always have an embedded instance of the nested class in the enclosing object, so it creates one for you, naming the instance by prepending m_x to the nested class name.Steak knives anyone?
So far so good. But wait, there's more! The macros also make it very easy to implement multiple interfaces in the one object. Let's expand our class a little to incorporate an implementation of the IThingAMaBob interface. Of course, it only makes sense to combine the two interfaces in the one object if a Widget and a ThingAMaBob are related so let's assume they are. Our class would now look like this.class CWidgets : public CCmdTarget
{
public:
DECLARE_INTERFACE_MAP() BEGIN_INTERFACE_PART(Widgets, IWidgets)
STDMETHOD(MyExtraFunction)();
END_INTERFACE_PART(Widgets)
BEGIN_INTERFACE_PART(ThingAMaBob, IThingAMaBob)
STDMETHOD(SomeOtherFunction)();
END_INTERFACE_PART(ThingAMaBob)
};which defines a second nested class called XThingAMaBob. In our implementation file the interface map now looks like this. BEGIN_INTERFACE_MAP(CWidgets, CCmdTarget)
INTERFACE_PART(CWidgets, IID_IWidgets, Widgets)
INTERFACE_PART(CWidgets, IID_IThingAMaBob, ThingAMaBob)
END_INTERFACE_MAP()and we'd add whatever methods are part of the XThingAMaBob class (not forgetting the IUnknown methods). As part of all this we get a new member variable in the containing class called m_xThingAMaBob of type XThingAMaBob.
The really nice thing about this is that if QueryInterface() in your implementation calls pThis->ExternalQueryInterface() you'll automatically find and return the embedded m_xSomething instance associated with the iid you (or some other program) requested, with all the plumbing taken care of by the interface map and CCmdTarget. You don't have to write a bunch of code in each objects QueryInterface() method to make it aware of the other interfaces implemented on the containing object. More importantly, if you add an interface to the class, all you have to remember is to add it to the interface map in the implementation file and MFC will take care of the rest.Reference Counting
Because the interfaces are defined within an MFC object they have the same lifetime as the enclosing object. Thus, as you've already seen, it's possible to do reference counting in the enclosing object rather than make each interface responsible for it's own counting. All interfaces implemented on the class share a single reference counter. In debug builds MFC does an ASSERT(dwRef <= 1) on the reference counter during the CCmdTarget::~CCmdTarget() destructor. If you encounter that assert it means that someone somewhere hasn't done a Release() on one or more of your interface pointers.
Variables, methods and constructors in the nested class
As well as defining COM methods for a nested class it's possible to embed normal (non COM) methods, constructors and destructors and member variables inside a nested class. All you have to do is add them between the BEGIN_INTERFACE_PART and END_INTERFACE_PART macros. The only 'special' thing you have to remember is that the constructor / destructor names are the classname with an 'X' prepended. class CWidgets : public CCmdTarget
{
public:
DECLARE_INTERFACE_MAP() BEGIN_INTERFACE_PART(Widgets, IWidgets)
STDMETHOD(MyExtraFunction)();
END_INTERFACE_PART(Widgets)
BEGIN_INTERFACE_PART(ThingAMaBob, IThingAMaBob)
STDMETHOD(SomeOtherFunction)();
XThingAMaBob();
~XThingAMaBob();
private:
BOOL m_bMyBool;
END_INTERFACE_PART(ThingAMaBob)
};Which defines a constructor / destructor pair called XThingAMaBob and a private BOOL variable called m_bMyBool. Within your nested class code you access members defined this way just as you would in a non nested class, via the implicit this pointer
用ATL开发COM,里面可以用MFC的东西。`
不知道我这样理解这一问题是不是准确,错在那里??
还有就是 com中编程特别注意的地方是什么!(我是用mfc的)
不知道我这样理解这一问题是不是准确,错在那里??
---
当你深入学习后应该会站在另外一个层次看com了...
所以请赐教!!