之前写了一篇原始dll的创建过程,以及直接使用LoadLibrary加载动态库。
但ATL所做的一个很重要的功能就是引入COM对象这个概念。
首先, ATL active template library为活动模板库,ATL为asp代码中提供COM对象应用。而一般使用活动模版库来创建COM组件。简单来说ATL一般作为方便快捷的COM开发工具使用。而ATL中使用的基本技术为 COM技术,C++模版技术和C++多继承技术。
接下来是使用ATL开发一个COM组件的基本过程,附带截图:
1.新建一个ATL项目:
随便取个名字,然后确定。
设置向导里直接选完成,这里就是简单的创建一个dll文件。
2. 然后是在项目中选择添加一个新的类:
新类选择为ATL中的ATL简单对象:
3.在向导中添加类名:
会发现,向导会自动生成其他信息,如类名,组件类名,接口名等。
在选项中还有更具体的一些设置:
直接点完成。
4.在类视图中,我们看到有生成的Cfirst类和Ifirst 接口。
在接口上添加方法,会有以下详细的信息:
填上方法名,然后添加参数,com函数的返回值都是用来检测dll函数是否正确加载并运行的。所以要使用参数作为返回值来传递。这里实现一个简单的加法函数,对于这个函数,其参数为 A,B,和Ret,ret是一个long* ,用来储存返回值。
点in,说明这个参数是是输入的参数。在生成的代码处会自动添加_in_ ,提示这里是输入的参数,但没有太大的实际作用。在参数类型中寻找对应的数据类型,并填上相应的参数名:
对于函数没有返回值的话,一般会将最后一个参数设置为指针类型,用其记录函数返回值:
最后的参数为:
点完成。
5.修改生成的代码,添加实现。
首先我们双击接口,会进入一个MyFirstDll.idl 的文件中,其中有以下代码:
interface Ifirst : IUnknown{ [] HRESULT Add([in] LONG A, [in] LONG B, [out,retval] LONG* Ret); }; [ uuid(F7DAFD6A-C1DB-46AF-9CF9-62EC0D7D589F), version(1.0), ] library MyFirstDllLib { importlib("stdole2.tlb"); [ uuid(D2F7F834-D4A2-4AB7-B5BE-B08D1EB35564) ] coclass first { [default] interface Ifirst; }; };
是供其他语言或系统中使用的接口。
这里的IUnknown也是值得注意的地方,在COM的内部实现中,所有的类的是继承与这个UnKnown基类。
然后看 first.h, 头文件中关于Cfirst类的声明如下:
class ATL_NO_VTABLE Cfirst : public CComObjectRootEx<CComSingleThreadModel>, public CComCoClass<Cfirst, &CLSID_first>, public Ifirst { public: Cfirst() { } DECLARE_REGISTRY_RESOURCEID(IDR_FIRST) DECLARE_NOT_AGGREGATABLE(Cfirst) BEGIN_COM_MAP(Cfirst) COM_INTERFACE_ENTRY(Ifirst) END_COM_MAP() DECLARE_PROTECT_FINAL_CONSTRUCT() HRESULT FinalConstruct() { return S_OK; } void FinalRelease() { } public: STDMETHOD(Add)(LONG A, LONG B, LONG* Ret); };
这里就体现了ATL的基本技术,多继承以及模版。继承 的 内容 有一个 Ifirst , 为之前在idl文件中的接口。在编译器中,对于这个Ifirst接口直接是红下划线表示错误,说明其实现是一个动态的过程,至于具体是如何的,我就不想太深入了解了。
这个类声明中有许多复杂的宏的使用,这不是重点,重点是public 中的add函数声明。
然后我们进入 Cfirst.cpp中,在add函数中加上简单的实现:
STDMETHODIMP Cfirst::Add(LONG A, LONG B, LONG* Ret) { // TODO: 在此添加实现代码 *Ret = A+B; return S_OK; }
这样就实现了一个简单的COM组件。
6. 点生成,生成dll。
之后是调用COM对象。