not inside alt.chm .and the book named windows 2000 programming unleashed .it explain clearly.
hehehehehe.....
hehehehehe.....
解决方案 »
- sql如何引用float变量?
- vc大侠请进!!
- 在Excel的addin控件中,插入控件如何自动激活!!??
- OpenH.323支持视频(摄像头)捕捉吗?怎样用?
- 感谢winphoenix给我做的程序
- 新手提问:急!请大侠们帮忙
- error LNK2001: unresolved external symbol _RMACreateRMBuildEngine@4
- 求教啊,关于鼠标点击响应的问题
- Qt的界面线程 和Mfc 一点不一样的地方 引发我退群
- 怎么从“光标位置”得到窗口句柄
- 兄弟们,我的COM经历文章如何?
- SHFileOperation()函数的具体用法,为何同样的参数在VB中可实现,VC不行
总觉得入门非常难,上面那几个疙瘩真让我伤脑筋。各位老大快快出手吧!!!
1.
不管是什么线程模型,如果你的COM Object访问全局变量,或者类有静态数据成员,统统要加同步机制的。
对于MTA(Free),则类的所有数据成员也要加同步机制。
2.
有虚拟函数的C++类,它的每个实例都有一个指针,称为VPTR,它指向一个称为VTBL的虚拟函数表,该表存放该类的虚拟函数的函数地址。当你调用某一个类的实例的虚拟函数时,编译器生成的代码由类实例的VPTR找到VTBL,从而找到该类实现的虚拟函数版本的地址,从而调用正确的重载函数。
ATL中,你定义的对象类,假设叫CMyObject,是不能实例化的,因为它是抽象类,有纯虚函数未被实例化,这些纯虚函数是什么呢?是与AddRef、Release有关的函数。这些函数由谁实例化呢?CComObject<CMyObject>或CComAggObject<CMyObject>。你定义的类CMyObject的实例,它有一个若干字节的VTBL。而类CComObject<CMyObject>的实例,它又有自己的VTBL,这个VTBL有它实现的AddRef和Release等表项,也有CMyObject中有的很多虚拟函数地址。显然后者是与CMyObject的VTBL占有的字节重复的。这些字节能不能省去呢?如果不加ATL_NO_VTABLE,不行。因为你的程序中显然要引用CMyObject的函数,包括虚函数,所以CMyObject的VTBL必须保留。
想想看,你的CMyObject是从许多ATL类中派生的,它们都有很多虚函数,因此有很多VTBL,这要浪费许多字节。而ATL的设计意图,就是用精练的代码编写出高效的COM对象。ATL_NO_VTABLE将使CMyObject类不生成VTBL,而在派生树的最后一级(CComObject)才生成。
3.
Aggregation是将一个现成的组件对象A包装在一个新组件B中,使得外界看到的B也有A的接口而感觉不到A的存在。但需要处理的问题远没原理那么简单。支持Aggregation的对象类用CComAggObject实例化。
Tear-Off是这样的接口,当生成COM Object时,并不生成该接口的VTBL(接口在C++看来就是一个全是纯虚函数的类),只当用户用QueryInterface要求该接口时才生成。当该接口不在被使用时,VTBL被释放。
Aggregation和Tear-Off是各自独立的技术,不存在直接关系。
4.
Class A: public IDispatchImpl
{
public:
integer x1;
integer x2;
};
A a;offsetof(x1)的作用就象a.x1,不过offsetof的参数经常是一个类的基类,例如:
class B :public A;
offsetof(A)将返回A在B中的VPTR地址,有了它你就能找到VTBL,特别当A是个接口实现时,通过它你能访问A接口的方法实现。C++在X86平台的实现中,VPTR总是处在类的实例中的第一个字节。offsetof在我们编程序时很少用到,它是ATL在内部实现是经常用的。你问的这个问题很深啊,你不象是ATL新手啊?呵呵,你可让我费了不少时间写这么多东西,如果你觉得有道理的话,别忘了给我加分啊!
#define offsetofclass(base, derived) ((DWORD)(static_cast<base*>((derived*)_ATL_PACKING))-_ATL_PACKING)
我怎么算来算去offsetofclass结果都是零呢? static_cast<base*>, dynamic_cast<base*>与(base*)ptr强制转换有什么区别,仅仅只是为了在运行时进行类型安全校验吗?欢迎COM高手发表高见,只要跟COM相关的就行。
请注意Aggregation和继承的不同观念,这是两种不同的重用概念和方法。
如果你的类有多个基类,则你就会看出offsetof的作用。
1、线程模型
既然不要抄写 Inside ATL,我就从 Inside COM 上比葫芦画瓢吧!
COM 的消息管理和同步机制利用的是大家熟悉的 WIN32 线程管理机制,特别与线程和窗口的关系类似。一个线程可以拥有几个窗口,但是一个窗口只能同时被一个窗口所拥有。所以,尽管消息是随机的,不同步的,但是 Windows 发给每个线程的消息后,每个窗口所接受到的信息是按顺序的,同步的。
一个 Apartment 相当于一个线程,它有一个消息循环队列负责消息的分发,在同一个 Apartment 中的 COM 对象不必担心会同时(呵呵,意思是还没有处理完一个请求就被 Windows 打断了,再去处理另一个请求)收到两个调用请求,所以不会出现同步问题。一个 Apartment 的建立和销毁分别由 CoInitialize 和 CoUninitialize 来完成,所以每个要调用 COM 服务的线程必须要调用这两个 API。创建一个 Apartment 的线程拥有这个 Apartment,叫做 Apartment Thread。
这些工作都是由 COM 服务提供的,组件开发者不用去实现同步代码。
与 Apartment 模型相对比,Free Thread 模型就是指一个 COM 组件不被任何线程所拥有,可以在任何时候被任何线程调用。即,COM 服务不再创建一些机制(如,一个不可见的消息队列 - Apartment)用来保证 COM 组件的同步调用问题。
但是,并不意味着 Apartment Thread 模型所创建的组件就丝毫不用担心自己的共有数据(如,全局变量),有以下问题要考虑:
1、程内组件必须考虑 DllGetClassObject/DllCanUnloadNow 是否因该实现线程同步;
2、可能需要线程安全的 Class Factory;
其它还要涉及到 Marshaling 的问题,本人只有个大概概念,所以不再讨论。
#ifdef _ATL_DISABLE_NO_VTABLE
#define ATL_NO_VTABLE
#else
#define ATL_NO_VTABLE __declspec(novtable)
#endif
也就是说,在可以使用 ATL_NO_VTABLE 的功能的情况下,ATL_NO_VTABLE 相当于 __declspec(novtable),MSDN 上说得很明白(Sorry :-(),因为 COM 接口在 C++ 的类定义必须是纯虚类,不可被实例化,只能被继承,所以专门用来存储虚函数指针的 vtable ( vfptr) 就没有任何用处。禁止编译器和连接器生成没有作用的 vtable,可以大大减小最终代码的大小。
我觉得最重要得模型是APARTMENT,它的实现使得多线程访问同一个实例提供了简化的方法(好象是插入STUB串形访问实例记不清楚了)
推荐一本好书《COM原理与应用》,关于线程模型与COM重用都有比较详细的解说。不过给的例子好象是用MFC实现的,但这应该不是问题。
(bgsn用充满期盼的目光看着horris说)有没有电子版?给兄弟我MAIL一份如何?
CComObject的实例化过程是在client调CoCreateInstance时,是由ATL实现的CComCoClass(你的每个对象类几乎都从它派生)实现的。一般地,不用关心这个过程。
to bgsn:
非常遗憾, 我不知道有没有电子版。 你可以去www.awl.com/cseng看看, 这是Addison-Wesley Longman Press.的主页, 上面可以下载此书所附的源代码。