对组件的十一个文件的剖析
一、stdafx.h
代码选取
…
#define STRICT
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0400
#endif
#define _ATL_APARTMENT_THREADED
#include
#include
#include
//You may derive a class from CComModule and use it if you want to override
//something, but do not change the name of _Module
extern CComModule _Module;
#include
…
代码剖析
n 包含了ATL头文件
#include
#include
n 两个声明
#define _ATL_APARTMENT_THREADED
定义了将成为apartment模型的DLL默认线程模型。
_Module是CComModule类型的对象,CComModule实现了COM服务器的基本功能,实现并提供了诸如注册、实例化所支持对象以及通过对象映射管理生命周期等服务。注意因为它通过ATL头文件所引用,所以CComModule对象必须是全局的且必须命名为_Module。
另外,这个类也是ATL的中心,正如主函数对任何程序的入口点(C/C++),这个类的模块对象处理几个任务,如:服务器锁计数、注册本地服务器的类工厂、根据注册表注册和反注册。
二、stdafx.cpp
…
#ifdef _ATL_STATIC_REGISTRY
#include
#include
#endif
#include
三、MyProj.def输出定义文件
代码选取
; MyProj.def : Declares the module parameters.
LIBRARY "MyProj.DLL"
EXPORTS
DllCanUnloadNow @1 PRIVATE
DllGetClassObject @2 PRIVATE
DllRegisterServer @3 PRIVATE
DllUnregisterServer @4 PRIVATE
代码剖析
也称模块定义文件,只有进程内服务器DLL才产生,它提供了被链接程序的信息(DLL文件的名字)
四、MyProj.tlb类型库
编绎后生成,客户端使用时用#import方式导入之。
五、MyProj.idl接口定义语言文件
代码选取
…
import "oaidl.idl"; //此文件包括IDispatch接口的定义,import相当于#include
import "ocidl.idl";
[
object,
uuid(65460F9C-3BAB-4055-885A-8ED59F5FA9B0),
dual,
helpstring("IMyCom Interface"),
pointer_default(unique)
]
interface IMyCom : IDispatch
{
[id(1), helpstring("method MyF1")] HRESULT MyF1();
[id(2), helpstring("method MyF2")] HRESULT MyF2([in] BSTR str,[out, retval] int* val);
[id(3), helpstring("method MyF3")] HRESULT MyF3([in] BSTR str,[out, retval] BSTR* retstr);
[id(4), helpstring("method MyF4")] HRESULT MyF4([in] int x,[out, retval] int* val);
};
[
uuid(FE651184-11DE-4D01-BD69-B07DDFA12D0C),
version(1.0),
helpstring("MyProj 1.0 Type Library")
]
library MYPROJLib
{
importlib("stdole32.tlb");
importlib("stdole2.tlb");
[
uuid(FEB7BDEF-FB6F-446B-BE31-DF0A3AD391BA),
helpstring("MyCom Class")
]
coclass MyCom
{
[default] interface IMyCom;
};
};
代码剖析
IDL文件由三部分组成,每部分又都由一对中括号和一对大括号组成。每部分也都包含一个UUID来唯一的标识自己
n 接口部分:COM接口定义
[
object,
uuid(65460F9C-3BAB-4055-885A-8ED59F5FA9B0), //接口唯一标识符(GUID/IID)
dual, //表示客户机可用两种方法访问这个接口,一种是支持指针的非脚本语言,如VC;一种是非脚本语言,如VB、ASP
helpstring("IMyCom Interface"), //将提示字符串与此接口建立联系
pointer_default(unique) //指定除参数表中所列属性之外所有指针的缺省特征,unique表示指针可以是NULL,但不支持别名
]
interface IMyCom : IDispatch
{
[id(1), helpstring("method MyF1")] HRESULT MyF1();
[id(2), helpstring("method MyF2")] HRESULT MyF2([in] BSTR str,[out, retval] int* val);
[id(3), helpstring("method MyF3")] HRESULT MyF3([in] BSTR str,[out, retval] BSTR* retstr);
[id(4), helpstring("method MyF4")] HRESULT MyF4([in] int x,[out, retval] int* val);
};//接口中的方法
n 类型库部分
[
uuid(FE651184-11DE-4D01-BD69-B07DDFA12D0C),
version(1.0),
helpstring("MyProj 1.0 Type Library")
]
library MYPROJLib
{
importlib("stdole32.tlb");
importlib("stdole2.tlb");
<组件类部分>
};
n 组件类部分(组件类嵌套在类型库里面)
[
uuid(FEB7BDEF-FB6F-446B-BE31-DF0A3AD391BA),
helpstring("MyCom Class")
]
coclass MyCom
{
[default] interface IMyCom;
};
手工为接口添加一个方法,该修改哪些地方?
假设组件类名叫CMyCom,接口叫IMyCom,要加入的方法是MyF5。
首先在IDL文件中找到接口IMyCom的定义,在其中加入如下方法定义:
[id(5), helpstring("method MyF5")] HRESULT MyF1([out,retval] VARIANT_BOOL *ret);
注意:id中的数字不要和已经存在的id重复。
其次,在CMyCom的类定义头文件中加入如下成员函数声明:
public:
STDMETHOD(MyF5)(/*[out, retval]*/ VARIANT_BOOL *ret);
最后,在CMyCom类的实现Cpp文件中加入函数的实现:
STDMETHODIMP CMyCom::MyF5(VARIANT_BOOL *ret)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState())
// TODO: Add your implementation code here
*ret = VARAINT_TRUE;
return S_OK;
}