目标:基于单文档程序生成一个程序框架来开发BSOPCServer。
为了方便管理和配置,我们的程序将会基于单文档类型,支持MFC,然后添加ATL支持。添加ATL是为了方便实现OPCServer的接口。
1.1 应用程序类型
这里用的开发环境是VS2008 + SP1。打开创建工程向导,创建基于单文档的应用程序:
由向导生成的文件列表:
1.2 添加ATL支持
我们可以通过添加一个ATL简单对象的办法让开发环境为我们自动添加支持ATL必须的代码。
因为在我们的程序中要有一个server对象实现IOPCServer等接口,这里我们不妨就直接添加一个类COPCServer,继承于IOPCServer:
1) 选择“AddClass …”:
2) 添加“ATL Simple Object”:
各项设置如图所示:
3) 设置线程模型:
线程模型:选择“Apartment”, 即套间模型,表示我们的COPCServer对象运行在套间里保证线程安全;
接口:选择“Custom”, 即定制接口。如果选择“Dual”则表示该对象支持自动化接口,将会继承IDispatch 接口。
聚合: 选择默认值,“允许聚合”,实际上不会用到。
连接点:COPCServer对象需要支持连接点(实现IConnectionPoint接口),但在这里我们不选,我们以后手动加进去。
现在来看看向导为我们添加的几个文件:
1) OPCServer.h
COPCServer类定义的头文件;
2) OPCServer.cpp
COPCServer 类的实现文件;
目前为空文件。
3) OPCServer.rgs
COPCServer 类的注册文件;
应用程序注册时会把该类的相关信息注册到注册表中,这样OPC client就可以根据注册的信息访问到我们的server了。下面我们会专门介绍server的注册。
4) BSOPCServer.idl
接口定义文件;
因为在向导里我们设置COPCServer是继承于IOPCServer的,IOPCServer的定义就在该文件里。我们来看看它的内容:
1: import "oaidl.idl"; 2: import "ocidl.idl";
3:
4: [
5: object,
6: uuid(3418B5C9-878F-436B-BFDA-6EB5EEFF4DF2),
7: helpstring("IOPCServer Interface"),
8: pointer_default(unique)
9: ]
10: interface IOPCServer : IUnknown{
11: };
12:
13: [
14: uuid(B34FC1D6-0D49-4352-B48C-C6C56E856ACA),
15: version(1.0),
16: helpstring("BSOPCServer 1.0 Type Library")
17: ]
18: library BSOPCServerLib
19: {
20: importlib("stdole2.tlb");
21: [
22: uuid(2C03FF28-FD3C-4B18-9149-5BFFD190BD38),
23: helpstring("OPCServer Class")
24: ]
25: coclass OPCServer
26: {
27: [default] interface IOPCServer;
28: };
29: };
|
文件定义了IOPCServer 接口和BSOPCServerLib类型库。
值得注意的是,因为我们最终要实现OPC标准里定义的IOPCServer接口而不是我们上面自己定义的接口,所以我们一会会把这部分code做一下修改。
编译一下,应该没有错误。
1.3 添加OPCGroup 对象
以同样的方法添加OPCGroup类:
向导生成的文件:
OPCGroup.h —— COPCGroup 类定义头文件
OPCGroup.cpp ——COPCGroup 类实现文件
OPCGroup.rgs ——COPCGroup 类注册文件
同时,相关代码会加到BSOPCServer.idl里面,我们看看都有哪些:
1: import "oaidl.idl"; 2: import "ocidl.idl";
3:
4: [
5: object,
6: uuid(3418B5C9-878F-436B-BFDA-6EB5EEFF4DF2),
7: helpstring("IOPCServer Interface"),
8: pointer_default(unique)
9: ]
10: interface IOPCServer : IUnknown{
11: };
12: [
13: object,
14: uuid(60948577-318D-46F9-948C-838DB34EF8EC),
15: helpstring("IOPCGroup Interface"),
16: pointer_default(unique)
17: ]
18: interface IOPCGroup : IUnknown{
19: };
20: [
21: uuid(B34FC1D6-0D49-4352-B48C-C6C56E856ACA),
22: version(1.0),
23: helpstring("BSOPCServer 1.0 Type Library")
24: ]
25: library BSOPCServerLib
26: {
27: importlib("stdole2.tlb");
28: [
29: uuid(2C03FF28-FD3C-4B18-9149-5BFFD190BD38),
30: helpstring("OPCServer Class")
31: ]
32: coclass OPCServer
33: {
34: [default] interface IOPCServer;
35: };
36: [
37: uuid(7E67188C-27CA-47E8-BB92-C22BD88272E2),
38: helpstring("OPCGroup Class")
39: ]
40: coclass OPCGroup
41: {
42: [default] interface IOPCGroup;
43: };
44: };
|
可以看到多了IOPCGroup 和 coclass OPCGroup的定义。因为我们将不对其他程序暴露OPCGroup对象,所以删掉OPCGroup.rgs并注释掉BSOPCServer.idl中关于OPCGroup的代码:
|
也就是说,我们虽然用向导生成了CCOPCGroup类的框架,但我们只保留了OPCGroup.h 和OPCGroup.cpp。
我们还需要对CCOPCGroup类定义进行修改:
在OPCGroup.h文件中注释掉:
1) public CComCoClass<COPCGroup, &CLSID_OPCGroup>,
2) public IOPCGroup
3) DECLARE_REGISTRY_RESOURCEID(IDR_OPCGROUP)
4) COM_INTERFACE_ENTRY(IOPCGroup)
5) OBJECT_ENTRY_AUTO(__uuidof(OPCGroup), COPCGroup)
1.4 继承IOPCServer
上面我们提到虽然我们自己利用向导生成了IOPCServer的定义,但是最终我们用到的是OPC标准里面定义的IOPCServer, 所以我们要把它替换掉。
1) 添加OPC 标准的include文件
OPC基金会为我们提供了一些开发OPC server的公共头文件和idl接口定义文件,为了便于使用,我们把它们拷贝到我们的工程目录下面。 上面提到的IOPCServer接口就在opcda.idl里面定义:
2) 修改BSOPCServer.idl文件
a. 添加import “opcda.idl”;
b. 注释掉IOPCServer的定义:
|
c. 设置编译BSOPCServer.idl包含的路径:
(opcda.idl 跟BSOPCServer.idl 不在一个文件夹下面。)
重新编译,在编译OPCServer.cpp时会得到如下错误提示:
c:/program files/microsoft visual studio 9.0/vc/atlmfc/include/atlcom.h(1867) : error C2259: 'ATL::CComObject<Base>' : cannot instantiate abstract class
这个错误主要是因为我们把COPCServer从IOPCServer继承,但是没有实现IOPCServer定义的方法。
在OPCServer.h里添加IOPCServer接口函数定义:
|
在OPCServer.CPP文件添加接口函数实现,这里我们没有具体实现每个函数,只是设置返回值:
|
重新build成功。
到此为止,应用程序框架已经生成,接下来我们来探讨OPC server的注册问题。