上海论文网提供毕业论文和发表论文,专业服务20年。

上海交通大学本科毕业论文 电力监控SCADA软件开

  • 论文价格:免费
  • 用途: ---
  • 作者:上海论文网
  • 点击次数:542
  • 论文字数:0
  • 论文编号:el2009122812253945
  • 日期:2009-12-28
  • 来源:上海论文网
TAGS:

上海交通大学本科毕业论文

电力监控SCADA软件开发
electric power system of software exploitation scada

学    生:  陈燕武
学    号: 703901010011
专    业: 计算机科学与技术
导    师: 谢康林
                 学校代码: 10248
上海交通大学网络教育学院
二OO五年八月
 

电力监控SCADA软件开发

摘要

随着我国国民经济的快速发展,我国对电力的需求也越来越紧迫。尤其是在近几年里,我国每年的电力缺口逐年扩大,已经严重制约了各个行业的发展甚至影响到了居民的正常用电。正是由于这样,全国大量兴建各类发电站、变电站以及加快电网设施的建设改造。在这些兴建改造项目中,伴随着电力行业各类新技术、新产品的出现和推广,尤其是计算机技术的广泛应用,使电力设备在高效,安全,可靠运行的同时,大量减少了运行人员的工作强度,缩短了设备的维护周期,延长了使用寿命等等。从我国目前的情形看,电力继保行业是计算机技术应用最直接,最明显的体现。在上个世纪70年代末期,由ABB公司推出了第一台基于微处理器的继电器,随着时间的推移,到了90年代网络技术的成熟与普及以及计算机的硬件设备成本的迅速降低和运算能力的快速提高,软件技术的不断更新升级,使计算机对底层设备的监测控制变为可能。由于国内外同类软件的价格不菲,市场竞争激烈,由此使我萌发了借助于所学知识制作电力监控SCADA软件的想法。
本文正是围绕着电力SCADA系统的开发,针对目前我国电力电网的现状,依据自己在电力继电保护行业中七年的开发、设计和现场调试经验从以下几个方面进行论述:首先是对SCADA系统的出现和发展作一介绍;其次对各种终端设备通讯协议论文由#p#分页标题#e#上海论文 www.zhonghualw.com整理提供(规约)的应用现状以及发展前景进行介绍说明;然后是对windows下基于mfc的编程环境和VC++6.0编程软件的说明;再次对程序结构框架及源代码的实现进行较详细的论述;最后是应用案例举例。
论文的主要创新性工作在于:由于本人前一本科专业所学是工业自动化,毕业后又长期从事于继电保护行业,参与了多种型号下位机及上位机产品的开发,测试;长期接触使用ABB、SIEMENS、GE、SEL、ACE、MS等国外知名企业生产的电力自动化产品,因此对电力SCADA系统能较好的理论联系实际,并且根据所学知识开发出适合不同通讯协议的电力SCADA监控软件;达到安全、可靠、经济的目的,解决了国外软件价格高,界面不友好、兼容性不好等问题。
 
关键词:SCADA,VC++6.0,通讯协议,继电保护

ELECTRIC POWER SYSTEM
OF SOFTWARE EXPLOITATION SCADA

ABSTRACT

Along with the fast development of the our country national economy, the our country is to the need of the electric power also more and more urgent.Within last few years particularly, the our country electric power in- dentation extends year by year, already serious check and supervision at development of each profession even affects the residents normal to use the electricity.Exactly because of thus, the whole country builds every vari- variety to generate electricity the station in great quantities, transformer substation and speed the construction reformation of the charged barbed wire net facilities. In these build reform item, accompany with the electric  power profession emergence of each kind of new technique,  new product and expand, particularly technical and extensive application of calculator, make the electric power equipments at efficiently, safety,  dependable movement at the same time, a great deal of work strength that reduces to circulate the personnel,  shortenned the maintenance period of the equipments, prolong the service life etc..The current situation sees from the our country, electric power a#p#分页标题#e#论文上海论文 www.zhonghualw.com整理提供fter protect the profession and is the calculator technique to apply most direct, the m- st obvious body now.Last phase in 70's in last century, From the company of ABB the first relay according to microprocessor of after electric appliances, along with change of time, In 90's the network oftechnical mature and make widely available and calculator of the hardware equipments cost lower and operate the fast exaltat- ion of ability quickly, the software is technical to renew the upgrade continuously, making calculator changed into the possibility to the monitor control of the first floor equipments.Because the price of domestic and int- ernational of the same kind software is expensive, the market competition vehemence, makes me ask for help from the viewpoint that the knowledge creation electric power supervises and control the SCADA software l-  earn from here.
This text surrounds the development of the electric power SCADA system exactly,  aiming at the present  condition of the our country electric power charged barbed wire net currently, according to the oneself at the e- lectric power protect the profession after the electricity in seven years of development, design and adjust to try the experience on the scene from following severals carry on the treatise:Is the emergence to the system of SC- ADA and developments to introduce first;Carry on the introduction elucidation to applied present condition and the development foregrounds of various terminal equipments communication agreement(rules invite) the next in order;Then is the elucidation to the windows the bottom according to the mfc the plait distance environment an- d VC++6.0 plait distance softwares;Carry on the more detailed treatise to the realization of the procedure struct- ure frame and the source code again;End is the applied case example give examples.#p#分页标题#e#
The main and creative sex work of the thesis lie in:Because oneself last-one undergraduate course learn is is an industry automation, graduation the empress works on to protect the profession after the electricity over  a long period of time again, participating the development of various machines with next model number and  the place of honor machine products, test;Over a long period of time the electric power automation product t- hat foreign well-known the electric-power’s produce enterprise of contact usage ABB, SIEMENS, GE, SEL, ACE, MS etc.so to SCADA system can the better theories contact physically, and according to the electric po- power SCADA supervision software that the knowledge develops an in keeping with different communication agreement learn;Attain the purpose of the safety, credibility, economy, resolved the foreign software price high, the interface is not friendly, and permit sex not good etc. problem.
 
Key word:SCADA, VC++6.0, the communication agreement, protect of relay

第一章 绪论 …………………………………………….……………….…………………………1
1.1   引言 ……………………………………………………………...…………………………1
1.2   本文简述 .……………………………………...………………………..………………….1
第二章 SCADA系统 …………………………………………….……………….………………..2
2.1   SCADA系统概述 ………………………………………………………………………….2
2.2   SCADA系统的发展 .……………………………………...……………………………….2
2.3   本章小节 …………...……………………………………...……………………………….2
第三章 电力SCADA系统的通讯网络及规约 ...………….……………….……………………..3#p#分页标题#e#
3.1   电力SCADA系统通讯网络概述 …………………………...…………………………….3
3.2   电力SCADA系统通讯规约概述 …………………………...…………………………….3
3.3   本章小节 ……………………………………………………...………………………….…4
第四章 编程软件及环境 ...………….……………….……………………………………………..5
4.1   基于MFC的VC++6.0编程软件的特点 …………………………………….……………5
4.2   面向对象的程序设计思想 ……………………………...…………………………….……5
4.3   MFC类(主要几个)的衍生关系简述 ……………………………...……………………6
4.4   本章小节 ……………………………….……………………………...……………………7
第五章 需求及可行性分析 ...………….……………….……………………………………….....8
5.1   需求分析 ……………………………...………………………………………………....…8
5.2   可行性分析 ……………………………...…………………………………………………8
5.3   本章小节 ……………………………...……………………………………………………9#p#分页标题#e#
第六章 系统规划 ...………….……………….…………………………………………………....10
6.1   项目规划 ……………………………...………………………………………………….…10
6.1.1  公共模块(PUBLIC)……………………………...……………………………….….…..10
6.1.2  具体通讯单元模块(CKUNIT)……………………………...…………………………...11
6.1.3  主界面模块(MAIN)……………………………...………………………………….…..11
6.1.4  单元组态界面模块(UNITS)……………………………...……………………...……...11
6.1.5  图元组态界面模块(PICSET)……………………………...……………………..…..…11
6.2   功能框图 ……………………………...……………………………………………………11
6.3   系统结构图 ……………………………...……………………………………………...….12
6.4   本章小节 ………………………………...……………………………………………...….12
第七章 系统设计与实现 ...………….……………….…………………………………...……....13
7.1   典型模块的设计与实现 ……………………………...………………………………...….13#p#分页标题#e#
7.1.1  系统主界面(MAIN)的设计与实现 ……………………………...…………...……….13
7.1.2  单元组态界面(UNITS)的论文上海论文 www.zhonghualw.com整理提供设计与实现 ……………………………...………………...16
7.1.3  图元组态界面(PICSET)的设计与实现 ……………………………...……………….19
7.1.4  程序公共单元(PUBLIC)的设计与实现 ……………………………...………….……22
7.1.5  具体通讯单元(CKUNIT)的设计与实现 ……………………………...………………22#p#分页标题#e#
7.2   系统完成 ……………………………...……………………………………………………23
7.2.1  系统编译及调试 ……………………………...……………………………………….…..23
7.2.2  运行及案例 ……………………………...……………………………………………......23
7.3   本章小节 ………………………………...……………………………………………..….23
第八章 结束语 ...……………..….……………….……………..……………………………......24
参考文献 ……………………………………………………………….…………………….…...25
致谢 …………………………………………………………………….…………………….…...26
附录 …………………………………………………………….…………………………............27

第一章 绪论

1.1 引言
    伴随着在两年计算机专业学习的结束,在老师的辛勤培养下,我的软件知识得到了拓展,编程水平得到了提高,使我依靠自己的力量编写电力SCADA软件的想法成为可能。虽然自己过去也长久从事于电力继保行业的产品开发,调试和试验,但是由于过去所学专业的局限性,始终无法全面了解国外后台系统(即上位机系统)的具体实现原理;通过这两年的学习,不但使自己对国外系统的产品有了深入的了解而且使自己编写电力SCADA系统成为可能,借助这次毕业设计的机会,我将自己长久以来的一些想法,结合自己的工作,对不久前自己开发的这套软件进行了升级,在导师的鼓励和帮助下,完成了这篇毕业论文。#p#分页标题#e#
由于电力系统继电保护的专业性很强,论文上海论文 www.zhonghualw.com整理提供本人所学知识的有限,只能通过这篇文章,在保证一定的广度的基础上突出深度,阐述自己对电力SCADA系统的理解,错误难免;但是我将力求使自己在电力系统各个方面的知识得到比较好的展现,对我所编写的此软件进行尽可能详细的说明。
1.2 本文简述
本论文主要从以下几个章节进行论述:
第一章对SCADA系统进行了简要的说明,从SCADA系统的产生和发展两方面进行描述。
第二章对电力SCADA系统的通讯网络和规约做了简单的描述,由于电力SCADA系统的特殊要求,因此本章对电力SCADA系统通讯的特殊性进行了说明。
第三章对编程软件及环境的特点给出了自己的一些体会。
第四章进行了电力SCADA软件设计的需求分析和可行性分析。
第五章的内容比较丰富,同时它#p#分页标题#e#论文上海论文 www.zhonghualw.com整理提供也是本论文的一个重点,包含了系统的各个主要模块的规划设计,对各个模块的功能进行了划分,最后给出了软件结构功能框图和系统结构图。
第六章是本论文的另一个重点,它对上一章规划的各个典型模块进行设计与实现的详细论述。(此章中包含的部分关键类的程序源代码放于附录)
第七章是结束语和程序改进的展望。
然后是致谢和参考文献。
最后是附录,附录中主要包括了部分典型模块的程序源代码及其说明。

第二章 SCADA系统

2.1 SCADA系统概述
 SCADA(Supervisory Control And Data Acquisition)系统,即数据采集与监视控制系统。SCADA系统是以计算机为基础的DCS与电力自动化监控系统;它应用领域很广,可以应用于电力、冶金、石油、化工等领域的数据采集与监视控制以及过程控制等诸多领域。在电力系统又称远动系统。它可以对现场的运行设备进行监视和控制,以实现数据采集、设备控制、测量、参数调节以及各类信号报警等各项功能。#p#分页标题#e#
在电力系统中,SCADA系统应用最为广泛,技术发展也最为成熟。它作为配电网自动化系统的一个最主要的子系统,有着信息完整、提高效率、正确掌握系统运行状态、加快决策、能帮助快速诊断出系统故障状态等优势,现已经成为变电站无人值守及配电网自动化必不可少的工具。它对提高电网运行的可靠性、安全性与经济效益,减轻运行人员和调度员的负担,提高调度的效率和水平等方面有着不可替代的作用。
2.2 SCADA系统的发展
目前,国内比较流行的说法是SCADA系统到了第三代:第一代是基于专用计算机和专用操作系统的SCADA系统,这一阶段是从计算机运用到SCADA系统时开始到80年代;第二代是80年代基于通用计算机的SCADA系统,在第二代中,广泛采用VAX等其它计算机以及其它通用工作站,操作系统一般是通用的UNIX操作系统。第一代与第二代SCADA系统的共同特点是基于集中式计算机系统,并且系统不具有开放性,因而系统维护,升级以及与其它联网构成很大困难。目前,国外的SCADA软件已经发展到第三代,主论文上海论文 www.zhonghualw.com整理提供#p#分页标题#e#要特征是采用互联网、OOP等新技术,基于分布式计算机网络等。
2.3 SCADA系统的瞻望
SCADA系统在不断完善,不断发展,其技术进步一刻也没有停止过。当今,伴随着国家电网建设与改造,电力监控系统发挥着越来越重要的作用,SCADA系统的在以后的发展中必将朝着更加安全、可靠以及界面的更加友好快速发展。
2.4 本章小节
本章节从总体上简单介绍了SCADA系统的概述、发展和前景三个方面,初步对SCADA系统的应用范围做了一些必要的说明,有助于以后编程工作的顺利开展。

第三章 电力SCADA系统的通讯网络及规约

3.1 电力SCADA系统通讯网络概述
 电力自动化系统通讯网络结构实质上是由多台微机组成的分层分布式控制系统,一般分为设备层、间隔层、管理层,包括若干个子系统。在各个子系统及各个层间,必须通过内部数据通信,实现各子系统内部和各层之间的信息交换和信息共享,以达到减少重复投资,提高了系统整体的安全性和可靠性的目的。
电力SCADA系统的通讯网络主要分为以下几层次:
其一:基于RS422或RS485接口组成的网络,RS422和RS485串口传输速率指标是不错的,在1000m内传输速率可达100kb/s,短距离速率可达10Mb/s,RS422串口为全双工,RS485串口为半双工,媒介访问方式为主从问答式,属总线结构。但是他们接点数目比较少,无法实现多主冗余,有瓶颈问题,RS422的工作方式为点对点,上位机一个通信口最多只能接10个节点,RS485串口构成一主多从,只能接32个节点,此外有信号反射、中间节点问题。其二:采用CAN或LONWORK网络(标准现场总线),常用的有LonWorks网、CAN网。两个网络均为中速网络,500m时LonWorks网传输速率可达1Mb/s,CAN网在小于40m时达1Mb/s,CAN网在节点出错时可自动切除与总线的联系,LonWorks网在监测网络节点异常时可使该节点自动脱网,媒介访问方式CAN网为问答式,LonWorks网为载波监听多路访问/冲撞检测(CSMA/CD)方式论文#p#分页标题#e#上海论文 www.zhonghualw.com整理提供,内部通信遵循LonTalk协议。LonWorks网上的所有节点是平等的,CAN网可以方便的构成多主结构,不存在瓶颈问题,两个网络的节点数比RS485扩大多倍,CAN网络的节点数理论上不受限制,一般可连接110个节点。其三:Ethernet网或Profibus网。Ethernet网为总线式拓扑结构,采用CSMA/CD介质访问方式,传输速率高达10Mb/s,可容纳1024个节点,距离可达2.5km。Profibus网是由西门子公司最早提出,现已比广泛应用于工业领域。
3.2 电力SCADA系统通讯协议(规约)概述
 由于电力系统中设备终端种类烦杂,不同厂家、不同区域所使用的产品采用的不同的通讯规约,造成设备之间无法兼容,重复投资,管理困难。目前各个地方情况不一,现场大多采用各种形式的规约如CDT、SC-1801、u4F、DNP3.0等一些规约。为了达到兼容各个不同厂家设备信息互换的目的,1995年IEC(国际电工委员会)颁布了IEC60870-5-101传输规约(国内版本 DL/T634-1997),1997年又颁布了IEC60870-5-103规约(国内版本 DL/T667-1999),101规约为调度端和站端之间的信息传输制定了标准,今后变电站自动化设备的远方调度传输协议上应推荐采用此规约;103规约为继电保护和间隔层(IED)设备与变电站层设备间的数据通信传输规定了标准,今后变电站自动化站内协议推荐采用。但是时值今日,由于牵扯到各方的不同利益,在行业中仍然使用着不同厂家的各自协议,如:ABB公司的SPA,SIEMENS公司的PROFIBUS等等;目前由国际几家知名跨国企业联合推广的OPC(CLIENT/SERVER)也开始推广使用。
电力SCADA系统的通讯网规约主要分为以下几种:#p#分页标题#e#
其一:一些小厂商自己定义的规约,一般只能连接自己的设备,适应范围很小;这类规约一般多基于MODBUS开发,形式多样,但是无法推广。其二:采用CAN总线是一种串行数据通信协议,它是一种多主总线,通信介质可以是双绞线、同轴电缆或光纤,通信速率可达1Mb/s。CAN总线通信接口中集成了CAN协议的物理层和数据链路层功能,可完成对通信数据的成帧处理,包括位填充、数据块编码、循环冗余校验、优先级判别等项工作。CAN 协议的一个最大特点是废除了传统的站地址编码,而对通信数据块进行编码。采用这种方法的优点可使网络内的节点个数在理论上不受限制,数据块的标识码可由11位或29位二进制数组成,数据段长度最多为8个字节,可满足工业领域中控制命令、工作状态及测试数据的一般要求。8字节不会占用总线时间过长,从而保证了数据通信的实时性。其三:物理层和链路层遵循IEEE802.3协议,TCP/IP通讯协议,利用因特网的优势,直接将设备变成局域网的一个终端,可以实现万里之外的数据共享、监测和控制,但是目前此技术还不成熟。
3.3 本章小节
本章节着重介绍了各类通讯网络和规约及其现阶段存在的各类网络和规约的复杂性,从网络结构和通讯规约两个方面对SCADA系统的连接方式进行了说明,从网络的构架及其所支持的协议来说明此类方案的特点。

第四章 编程软件及环境

4.1 VC++6.0编程软件的发展历程
首先,要了解VC++6.0则必须先了解C/C++语言。在计算机领域,C/C++语言相信一定无人不知、无人不晓。1970年,贝尔实验室的ken thompson开发了一种解释型的计算机语言被命名为B语言,但B语言没有流传开。1972年贝尔实验室的dennis ritchie在B语言的基础上进行改进,开发出了C语言。C语言最初主要用于unix系统,大多数unix系统的程序都是用C编写的。借助早期unix系统的流行和C本身的优秀品质,C语言从此名扬天下、威震四方。而后,伴随着面向对象概念的提出和应用,形成了C++语言,AT&T公司于1985年正式推出了C++1.0版,它是c语言面向对象的扩充。C++1.0增加了类和实例、单继承、重载、虚函数、友员、内联等面向对象的程序设计机制。1989年推出#p#分页标题#e#论文上海论文 www.zhonghualw.com整理提供的C++2.0版和1993年推出的C++3.0版分别增加了支持多继承、保护接口、模板和异常等。(有一点值得说明,直到现在C++并没有正式的标准,以上所说的版本是以AT&T公司的版本为基准的。)C++被公认为“最好的面向对象的编程语言”,是学习面向对象编程技术人员较好的启蒙语言。当VB成功推出后,microsoft又将C++包装成为了面向windows的visual C++(以下简称VC)。从VC1.0到VC6.0,每一个版本的推出都激动人心。VC借助传统的C/C++的美名加上microsoft这个金字招牌,使广大的程序员和专业编程人员纷纷投靠在VC的大旗下。
VC++是微软公司开发的C++语言开发环境,VC的特点是微软公司做了一个自己独有的类库MFC,里面封装了绝大多数的API函数,使得WINDOWS程序的开发变的很高效和易于理解,如果用API直接开发WINDOWS程序的话,将会是一件非常烦琐的工作,WINDOWS对资源的管理是非常严格的这与DOS可直接用中断处理程序和I/O指令操作硬件端口是截然相反的;所以这个MFC就是VC和其他公司出产的编译器的最大区别了,当然了别的公司也有自己封装API的类库比如DELPHI(这个不是C++的是pascol的)等等,不过由于微软公司掌握着WINDOWS内核的全部秘密,所以他们的编译器与其他公司的相比有其独到的优势。
4.2 VC++6.0编程软件的特点
第一, 快速高效:C语言从诞生起最大的优点就是速度快,用C编写的代码可以达到汇编语言编写的代码执行速度的70%——80%。VC完全继承了这一特点,并且由于代码优化工作做的比较好,其代码的结构紧凑、效率极高。#p#分页标题#e#
第二,语言简练:VC还延续了传统C语言的简练风格,如pascal语言中的begin end在VC中可以用简单的{}表示。  
第三,贴近硬件:C语言被很多专业人士称为“介于高级语言和汇编语言之间的一种语言”由于C语言贴近硬件便于对硬件直接操作因此又有“系统程序设计语言”的美称。这一特点使得C语言特别擅长编写系统程序,如windows就是用C语言编写的。VC具有同样的优良品质。
第四,灵活多变:VC像C语言一样提供给编程者一个很自由的编程环境,丰富的表达方式可以表现程序的匠心独运,用VC编程可以让你体会到什么叫“天高任鸟飞”。 你可以彻底地控制整个开发环境。其它语言则更多地趋向于庇护论文上海论文 www.zhonghualw.com整理提供程序员,当要做一些基本的东西时,它们会做得很好。
第五,便于移植:C语言在unix系统上取得巨大成功的一个主要因素是C语言的移植度好,不依赖于特定的硬件环境,可以方便地跨平台移植。使用Visual C++主要的原因之一就在于它的灵活性。不幸的是,当你需要使用像C++这样的语言删除编程中的繁文缛节,并把任务完成时,这种保护作用就变成了开发工作的障碍。#p#分页标题#e#
长期以来,Visual C++一直拥有能够创建短小高效程序的美誉。使用这种语言编写的程序几乎可以与用汇编语言编写的程序达到相同的运行速度,并且避免了汇编语言存在的各种问题。C++实际上是介于汇编语言中寄存器编程和类Pascal编程环境之间语言。
    C++是编写诸如操作系统、设备驱动程序以及动态链接库(DLL)的强大语言,这三种领域代码的开发依然是Visual C++的主要优势。Visual C++生成的短小、快速的代码在操作系统类对时间要求很高的系统中获得了极高的赞誉。
    同时Visual C++6.0中具有一些独特的特性,Microsoft添加到这个版本的Visual C++中的最新特性之一是更佳的原型能力,这一点通过增强的向导来实现。现在,这个特性还不能把Visual C++提升到像Visual Basic向导相同的水平上,但它确实减少了开发应用程序的入门时间。另外,增强的向导使得这个版本的Visual C++比以前版本更为友好。
4.3 MFC类(主要几个)的衍生关系简述
 几乎所以的MFC (Microsoft Foundation Class――微软基本类库)全部是从CObject这个根类衍生出来的,由CObject这个类衍生出以下一个重要的类:CCmdTarget——他是MFC类库中消息映射体系的一个基类(消息映射是把命令或消息引导给用户为之编写的响应函数);再由CCmdTarget派生出应用程序线程类CWinThread和窗口类CWnd以及基本文档类CDocument(CWinThread类的对象代表在一个应用程序内运行的线程;CWnd类提供MFC中所有的窗口类的基本功能;CDocument类为用户定义的文档类提供基本的函数功能如:各类操作文档)。CWinThread类又派生出应用程序对象类CWinApp,可以通过他来继承Windows应用程序对象,同时提供MFC中所有的窗口类的基本功能;CWnd类派生出框架窗口类CFrameWnd、对话框类CDialog和视图类CView,CFrameWnd用以完成Windows文档界面重叠或弹出式框架窗口,以及管理窗口的成员,在其派生类中加入成员变量,实现窗口的消息处理与映射,CDialog类是在屏幕上显示的对话框基类(包含模式对话框和非模式对话框),CView类为用户提供视图类的基本功能。
■ 文档类从CDocument派生,应该包括任何属于应用程序文档的数据。对于真实的C++封装,不允许文档类对它的数据进行直接访问(甚至从视图类也不行),而应包含封装函数以访问它的数据。文档类还应包括装入和保存一个文档所必须的所有功能,这些文档包括从简单的二进制文件到ODBC数据库。如果应用程序不做任何其他事情而只访问一个ODBC数据库,则文档类可以只包含打开和关闭那个数据库所必须的逻辑,因为数据库是数据的主要仓储地,文档类对它自己来说是独立的。从一个存储设备中获得信息,并把它取出来交给视图,但是几乎不把信息存储到其他类中。一份文档可以有多个相关视图,文档作为窗口标准命令的一部分,接收标准用户界面组件的命令,当文档数据被修改时,各个视图都必须响应这些修改。#p#分页标题#e#
■ 应用程序类从CWinApp派生,并不对任何窗口进行控制。应用程序对象为用户提供了初始化应用程序(以及他的每一个实例)和运行应用程序所需的成员函数。除了控制应用程序的创建和卸载外,它自身应该有少数重要的附加功能,这些功能包括处理命令行标志和提供一种定制的打开文档的方法。应用程序类还提供一些应用程序范围的服务,诸如后台处理和超分类等。每个使用MFC的应用程序只包含一个从CWinApp继承的对象。
■ 主框架类从CFrameWnd类派生,控制应用程序的主窗口,负责所有应用程序范围的界面,包括工具栏、状态栏、菜单和对话条。然而,如果这些条中的任何一个有新增的功能的话,它应该被封装到它自己的类中。对用户优先论文上海论文 www.zhonghualw.com整理提供选项的支持也通常可以在主框架类中发现。有三种方法可以构造一个框架窗口:用Creat直接构造、用LoadFrame直接构造和用文档模板间接构造;使用Creat成员函数传递框架构造参数作为立即参数,LoadFrame从资源中获取大多数缺省值,为了能使资源被LoadFrame访问,所有的资源必须有相同的ID(如,IDR_MAINFRAME)。当一个CFrameWnd对象包含视图和文档时,它们由框架类间接构造而不是由程序员直接构造,由此他们之间的联系通过了CDocTemplate对象,他将视图的构造、视图与文档相联接,他的构造函数的三个参数指定了三个类(文档、框架、视图)的CRuntimeClass。#p#分页标题#e#
■ 视图类从CView派生,他是框架窗口的子窗口,视图类通过消息映射处理消息。这个类应当包括查看和编辑文档类中数据所必须的所有逻辑。任何专门作用于文档的菜单或工具栏命令,诸如剪切或粘贴,应该在视图类中得到处理;所有影响视图的鼠标消息应当在此处处理;所有绘图、报表、编辑、选择和打印应在此处使用;所有的对话框和弹出式菜单应在此处产生。如果这个类或任何一个类变得规模很大时,应该分解出任何公共的功能以形成一个新的基类。创建一个新的CMyBaseView类,并把一些基本功能放到该类中;或者可以把一些功能封装到它自己的类中。视图中选择、剪切和粘贴函数是它自己的类的一个很好代表。
■ 其他类应尽可能多地封装属于它们自己的功能。对话框类应包括提示用户所必需的任何内容,对话条、工具栏和任务栏也应该这样。一个自画控件应当从它自己的类中绘制。
■ 每当从应用程序中分解出公共功能,并把它们放到一个基类中时,可以把新的基类放进一个MFC扩展类中。然后就可以把该新的MFC扩展类放进一个动态链接库中,应用程序便可以共享这一功能了。注意作为另一个经验作法,如果发现一个类经常访问另一个类的函数和数据,则有必要把那个功能放到另一个类中。
4.4 本章小节
本章节描述了电力SCADA软件的编程工具和环境的发展历程和特点,并且从MFC类库的角度描述了VC++6.0的编程方式和他们的结构,理解清楚这些对编程大有裨益。

 第五章 需求及可行性分析

5.1 需求分析
 随着国内用电负荷的不断加大,电力设施的建设改造速度的滞后,我国国内近期大量上马了一批中小电厂,变电站。但是由于资金等因数的制约,不可能使用国外一些知名厂商的设备和系统,为了实现国外同类产品的主要功能,同时满足我国国内用户对价格上的要求,由此,迫切希望制作一套具有自主产权的电力SCADA软件。
 在市场竞争的今天,技术和价格成为了用户选择产品的主要参考指标,只有找到这两点的平衡点,才可以占有市场。
场景名称:变电站监控。
参与执行者实例:线路保护装置、电动机保护装置、变压器保护装置等。
前置条件:各类终端已正常工作、系统已开机。
事件流:
 ⑴保护终端监测到电流、电压或频率等参量发生异常。
⑵保护终端发出跳闸指令,同时通过通讯网络向软件系统报告异常事件。
⑶软件系统启动相应程序发出声光报警。
⑷同时记录相应事件发生的时间、地点和性质等。
⑸系统在显示器上显示时间和事件。
⑹保护终端无响应。#p#分页标题#e#
后置条件:系统处于“报警”状态,等待处理。
5.2 可行性分析
技术方面:目前,国内外有大量同类软件,如ABB的MicroSCADA,组态王等,但是都是价格不菲,并且由于没有源代码,无法随时更新,无法方便的连接各种其他设备,而目前借助VC++6.0以及windows下的编程环境,依靠自己的力量完全在可以满足技术要求的前提下实现国内外产品大部分主要功能。而由于自己掌握源程序,因此可以随时解决一些厂家的特殊要求,界面也可以参考国内外厂家的产品的特点,加上自己的一些想法,使自己的这套软件能更好的适应市场的要求。由于针对的客户基本上为一些中小型用户,因此网络选择RS485或RS422串论文上海论文 www.zhonghualw.com整理提供口通讯方式,这样即降低了成本,也可满足通讯要求。另一方面,技术上的难点在于程序设计人员要具备单片机的编程经验,熟悉串口通讯理论,了解通讯原理,熟悉各类通讯协议,由于监控软件是实时系统,所以要注意安全性和实时性,要设计三级密码制度(至少二级),最好具有变电站调试经验,这样,可以大大降低编程的难度。目前,从市场上看也有不少同类产品可以借鉴,这也有助于顺利实现各类编程模块的实现。#p#分页标题#e#
经济方面:相对的软、硬件投入成本不高(计算机三台,VC++6.0编程环境,相应的调试终端一台);同时开发时间周期也不会很长(一般控制在2-4个月),开发人员控制在2-4个人以内(其中必须要求人员要精通计算机,精通继电保护理论以及要求全面了解各个方面理论和实践的人员,而且要求人员必须都要具备较熟练的软件编程能力),因为可以参考国内外不同软件产品,针对用户明确,所以可以有的放矢,不至于走太多的弯路。由于不同用户的各类要求,可能会增加编程和调试的成本,但是,不至于造成成本的不可控。
5.3 本章小节
本章从需求和可行性两个方面对电力SCADA软件的开发进行了分析。从各个前期可以考虑到的方面对软件开发做了前期准备,为了不至于造成软件编程的不可控,做到在软件编程过程中人员心中有数,对软件开发的人员、环境、资金做了预计。 


第六章  系统规划

6.1 项目规划
为了完成用户需求,便于用户使用,此软件必须具有良好的人机界面,使用户能很好的上手。本软件是专用于输变电自动化系统,集数据采集、显示、控制、通信等功能于一体的可组态可扩展的电力自动化监控系统软件。为了适合电力系统使用设备多,纵向横向联系紧密,扩建、组建频繁等特点,本软件必须从分析、设计到具体编程,全部采用面向对象的方法,融合了最新的计算机编程技术,在满足严格的可靠性实时性的基础上,完成系统的可组态可扩展性、可用性、可维护性。因此,本软件是各变电站、集控中心、调度中心理想的自动化监控系统。
本软件具有以下几个主要模块:PUBLIC公共模块——包括各个公共子模块,如:菜单管理模块、口令管理模块、自动推画面管理模块、事件管理、时间管理、通讯口管理模块、通讯单元管理模块、工具箱管理模块、信息管理模块、公共模块等。此模块为动态链接文件,程序初始化必须载入的模块。CKUNIT具体通讯单元模块——此模块按照具体的通讯单元终端所要求的通讯规约建立具体动态链接文件,完成对相应具体设备的连接。MAIN主程序模块——此模块是用户主界面程序,负责调度各个模块的使用。UNITS单元组态程序模块——#p#分页标题#e#论文上海论文 www.zhonghualw.com整理提供此模块是完成通信口、单元的配置,各数据、操作、SOE事件的参数设定。PICSET图元组态程序模块——此模块提供的强大的界面设计工具,许多实时界面及报表的设计工作将在这里完成。以下对各个模块作详细规划:
6.1.1 公共模块(PUBLIC)
PUBLIC模块的作用是将很多模块细化到其中,通过一个公共类(public)联接,利用DLLMain作为程序入口,将各个功能衔接在一起,主程序初始化时,调入public.dll动态链接文件。这里包含的各类子模块有菜单管理(CommandMng、CommandDlg)他的作用包括命令行菜单的初始化,增加菜单项等;口令管理(PasswordMng、PasswordDlg)他的作用是实现口令的分级管理,在执行不同程序段时,增加此部分,已限制无权用户使用此软件或者此项目;通讯口管理(Comport、ComprotDlg)的作用是将通讯口的名称及具体通讯口号(com1,com2……..)等串口设定参数一一列示,用户可以根据实际情况选择相应参数,灵活的配置各个通讯口;自动推画面管理(AutopopMng、AutopopDlg、AutopopPage)包括的自动推画面的设置,初始化,针对于不同事件推出不同的事件框,同时将事件记录到数据库中;通讯单元组管理(Units)负责协调通讯口以及通讯单元之间的初始化,数据交换等;通讯单元(Unit、UnitDlg)包括通讯单元设置,如站号、单位名称、是否投入使用等,这里含有三个不同的类:其一是发送接收模式的,其二是接收发送模式的,其三是上层之间的模式(如双机热备模式);数据初始化及更新单元(Data、DataDlg)包含了手工置数及数据数据初始化和更新;数据文件存储及调用单元(Database、DatabaseDlg);信息管理单元(InfoMng、InfoDlg、DrawDlg)等等。另外还有一些其他模块,其程序模式基本相同,只是实现方式不一样而已。#p#分页标题#e#
6.1.2 具体通讯单元模块(CKUNIT)
CKUNIT模块的作用是将要通讯的终端设备的参数具体化,形成动态链接文件并在初始化时载入系统,由系统在单元组态图元中加入相应的单元并对其具体参数进行设定。在本系统中可以加载不同的此类动态链接文件,用于连接不同设备,实现不同设备在同一平台下的通讯。此模块同样利用DLLMain作为程序入口,将各个功能衔接在一起并且通过DLL.TXT文件调入ckunit.dll动态链接文件。由于不同厂家的设备可能具有不同的通讯规约,为了使系统的扩展性更好,能够接入不同厂家的设备,因此通过此模块将具体的通讯规约链接入系统——通过public中的通讯单元模块(Unit、UnitDlg)完成此类工作。
6.1.3 主程序模块(MAIN)
MAIN模块是程序的人机主界面,包含有程序主框架类、视图类、文档类、对话框类等,其目的是为了实现各类人机界面——常用工具、报表图片、系统维护、关于等等,此程序通过调入动态链接文件,完成各类功能论文上海论文 www.zhonghualw.com整理提供#p#分页标题#e#。此模块是可执行文件,是整个程序的入口,负责协调各个模块。主程序模块作为HMI(人机界面),要求具有好的操作性,易于维护性和优良的交互性;对于其他程序模块的衔接功能起着很重要的作用。
6.1.4 单元组态程序模块(UNIT)
UNIT模块是单元组态程序的人机界面,同样包含有程序主框架类、视图类、文档类、对话框类等,其目的也是为了实现各类人机界面——增加通讯口、增加通讯单元、设置通讯口及通讯单元参数等等,此程序通过调入动态链接文件,完成各类功能。
6.1.5 图元组态程序模块(PICSET)
PICSET模块是图元组态程序的人机界面,同样包含有程序主框架类、视图类、文档类、对话框类等,其目的也是为了实现各类人机界面——绘制各类报表图片、屏幕图片、快速布图,绘制3D图元,变色图元等。此程序同样通过调入各类动态链接文件,完成不同种类功能。
6.2 软件功能框图
 


 


图6-1 软件功能图

图6.1反映出了整个软件各个主要功能模块的关系以及模块中所含的软件功能系统说明。主控软件包含了主程序模块(MAIN)和公共模块(PUBLIC);单元组态软件包含了单元组态程序模块(UNIT);图元组态软件包含了图元组态程序模块(PICSET);通讯接口则是公共模块(PUBLIC)中UNIT部分;外部通讯单元就是具体通讯单元模块(CKUNIT)等等。
6.3 系统结构图
 

 

 
图6-2 系统结构图
6.4 本章小节
本章节着重介绍了项目规划中各个功能模块的作用及其所要实现的类的说明。通过软件功能图来更好的体现软件的结构,使软件的体系更加明确,使编程过程有的放矢,编程工作更好的有序开展。最后,介绍了整个系统的体系结构图。 


第七章  系统设计与实现

7.1  典型模块的设计与实现
7.1.1 系统主界面(MAIN)的设计与实现
 


 

图7-1 系统主界面
 工作环境介绍
主菜单有〈常用工具〉、〈屏幕图片〉、〈报表图片〉、〈系统维护〉,〈常用工具〉下放的是一些需要经常使用的实时界面与应用程序,如软件封面、通信状态检测、事件记录查看等。〈屏幕图片〉与〈报表图片〉这二个菜单下的内容是动态变化的,系统自动寻找图片目录下的所有屏幕图片(不包括屏幕子图)与报表图片,并把它们加到各自的菜单中。〈系统维护#p#分页标题#e#论文上海论文 www.zhonghualw.com整理提供〉下放的是一些与系统维护相关联的内容,进入这些条目必须输入系统管理员口令。菜单下是快捷工具条,使用户能快速切换到想要的界面。右边四个小按钮分别为打印预览/打印、选择日期、显示通信报文窗口、显示事件记录窗口。小按钮上面是信息显示窗口,用于显示一些辅助性的信息,包括安全运行天数、当前功率负荷时段、值班员、系统频率。


 
图7-2 口令管理界面
 通信状态检测
最左边是通信口,右边是下挂于该通信口下面的所有单元。没投入使用的通信口和单元用暗色表示。通信口的红灯亮表示正在发送数据,绿灯亮表示正在接收数据,黄灯亮表示通信有故障。单元的青色灯亮表示该单元要求接收数据,黄色灯亮表示通信有故障。中间的小方块表示该单元发送或接收的帧类型。#p#分页标题#e#
 事件记录查看
上面的组合框内是当前查看的方式,可以不同的查看方式来查看事件。下面的列表中列出了这一天所有的事件,不同类型的事件以不同的颜色显示。要改变查看日期可按屏幕右上角的选择日期工具条按钮,系统弹出〈选择日期〉窗口,随着您选择不同的年月日,事件列表窗口中的内容自动刷新。带箭头的小按钮表示当前日期。按屏幕右上角的打印工具条按钮,可打印事件记录报表。
 通信报文检测窗口
按屏幕右上角的通信报文检测窗口工具条按钮,系统显示〈通信报文检测〉窗口,从通信口组合框中选通信口,可以看到该通信口收发的通信报文,红色表示发送的报文,绿色表示接收的报文,下面的启动/暂停按钮可以定格通信报文,定格时通信口仍然正常工作,只是不把通信报文送往〈通信报文检测〉窗口。
 事件记录窗口
按屏幕右上角的事件记录窗口工具条按钮,系统显示〈事件记录窗口〉,窗口内显示最近发生的八个事件,不同类型的事件以不同的颜色显示。时标用时:分:秒.毫秒格式显示。
 屏幕图片与报表图片
若图片的尺寸大于屏幕能显示的范围,系统自动提供卷滚条可以翻页,也可用鼠标拖拉进行浏览。按Ctrl键,系统反色显示所有连接有数据、操作、子图、备注的图元。在这些区域按鼠标右键,系统弹出快捷菜单,里面包含了所有能操作的条目,可以查看数据参数及手工置数,可以进行各种操作,可以进入子图,可以显示备注文本。
 口令管理
从〈系统维护〉菜单中选〈口令管理〉,系统弹出〈口令管理〉对话框,在这里您可增加、删除、修改各人员的姓名、级别、口令。级别分普通操作员与系统维护员。修改口令时,新口令与核对口令必须相同。在要求输入口令的场合下,用户只要输入本人口令即可,系统能根据口令自动找到该人员,并把所做的操作加入到事件记录中。
 事件管理
从〈系统维护〉菜单中选〈事件管理〉,系统弹出〈事件管理〉对话框,在这里#p#分页标题#e#论文上海论文 www.zhonghualw.com整理提供您可修改各种类型事件的属性,包括是否保存到数据库、是否自动弹出事件报警窗口、背景颜色、文本颜色、声音报警的声音文件。所列的事件类型中包含有系统预设的事件类型与用户通过动态连接库自己注册的事件类型。
 菜单管理
从〈系统维护〉菜单中选〈菜单管理〉,系统弹出〈菜单管理〉对话框。只有〈常用工具〉与〈系统维护〉这二个菜单可以挂接用户的应用程序。系统内置的菜单条目不能删除与修改。在〈命令属性设定〉对话框中,用户可寻找应用程序,并给一个合适的名字,系统自动将该应用程序挂接到相应的菜单中。
 工具条管理
从〈系统维护〉菜单中选〈工具条管理〉,系统弹出〈工具条管理〉对话框。在这里您可增加、删除、修改各工具条命令。工具条命令只能从已有的菜单命令中选择,可包括屏幕图片、报表图片。系统自动根据显示器的分辨率尽量多地显示工具条,超出屏幕显示范围的将不显示。
 自动推画面管理
从〈系统维护〉菜单中选〈自动推画面管理〉,系统弹出〈自动推画面管理〉对话框。〈总体属性〉内只有一个是否自动推画面检查按钮,作为总的自动推画面开关。〈遥测量报警〉、〈遥信量变位〉、〈SOE事件〉各属性页分别用于设定相对应的自动推画面条目,各条目之间是并列关系,当该条目中的一条满足时自动推出相关联的图片。当多个条目满足条件时,系统先推出第一个条目的相关图片,然后延时5秒,再推第二个条目的相关图片,依次类推。#p#分页标题#e#
 信息窗口管理
从〈系统维护〉菜单中选〈信息窗口管理〉,系统弹出〈信息窗口管理〉对话框。〈总体属性〉内只有一个是否显示信息窗口检查按钮。
 遥控遥调管理
从〈系统维护〉菜单中选〈遥控遥调管理〉,系统弹出〈遥控遥调管理〉对话框。在这里可设定本地遥控遥调允许、远程遥控遥调允许。
 直接存取数据库
从〈系统维护〉菜单中选〈直接存取数据库〉,系统弹出〈直接存取数据库〉对话框。左上角的按钮可选择一个数据库文件,列表框内显示该数据库文件的记录数据,第一列是时间,其它各列是相关的字段,该时间没记录则数据为空白,改变日期自动刷新数据框内的数据。在时间上双击鼠标左键,系统弹出〈修改数据〉对话框,这里可直接修改数据,按确认按钮自动保存修改后的数据。日期选择只能一天一天的前后翻,若要跨月,请先在公用的日期选择窗口内选择,然后再进入该对话框。为了保证数据记录的完整性和严肃性,我们不提倡直接修改数据库记录数据。

7.1.2 单元组态界面(UNITS)的设计与实现
 


 
图7-3 单元组态界面
单元组态软件是工程开始的第一步。将在这里完成通信口、单元的配置,各数据、操作、SOE事件的参数设定。
 进入单元组态软件
从主控程序的〈系统维护〉菜单中选择〈单元组态软件〉,输入系统管理员口令,可进入。
 通讯口操作
新建通信口——从〈编辑〉菜单中选择〈新建通信口…〉,系统自动弹出〈插入通信口〉对话框,选中您需要的通信口类型,按〈确定〉按钮,新的通信口便显示在屏幕上;选中通信口——把箭头光标移到通信口上面,按鼠标左键,可选中该通信口,论文#p#分页标题#e#上海论文 www.zhonghualw.com整理提供系统用亮色的矩形光环表示该通信口已经选中;删除通信口——请先选中要删除的通信口,从〈编辑〉菜单中选〈删除〉,该通信口及下挂的所有单元自动删除;复制通信口——请先选中要复制的通信口,从〈编辑〉菜单中选〈复制到内存〉,该通信口及所有参数全部复制的内存中。从〈编辑〉菜单中选〈从内存粘贴〉,系统将新建一通信口,而且新通信口的所有参数与内存中的完全相同;移动通信口——把箭头光标移到通信口上面,按鼠标左键不放,把通信口拖到新的位置后放开,该通信口自动搬移到新的位置。
 单元操作
新建单元——请先选中新单元要挂接的通信口,从〈编辑〉菜单中选择〈新建单元…〉,系统自动弹出〈插入单元〉对话框,选中您需要的单元类型,按〈确定〉按钮,新的单元便显示在屏幕上;选中单元、删除单元、复制单元、移动单元同通信口操作
 

 
图7-4 通讯口参数设定
 

 
 
图7-5 单元参数设定
 修改通信口参数
把箭头光标移到通信口上面,双击鼠标左键,系统弹出〈通信口参数设定〉对话框,可修改通信参数。〈总体属性〉中可修改通信口名称、是否投入使用。〈异步通信参数〉中可修改端口、波特率、数据位、校验位、停止位,对一些要求流量控制的通信设备可设流量控制的一些选项。系统列出从COM1-COM20共20个端口,具体用哪个端口,可查看Windows操作系统〈控制面板〉〈系统〉〈设备管理〉〈端口COM&LPT〉中的详细信息。〈异步通信参数〉只适合于那些异步通信类型的通信口,其他非异步通信的通信口,可能与上述情况不同,具体参阅该类型通信口的使用说明。系统用灰色表示该通信口不投入使用。#p#分页标题#e#
 修改单元参数
把箭头光标移到单元上面,双击鼠标左键,系统弹出〈单元参数设定〉对话框,可修改单元参数。〈总体属性〉中可修改单元名称、通信地址(十进制)、是否投入使用。另外几个属性页可修改单元成员的参数(具体见下面)。这种方式对一般的单元都可满足要求,对特殊的单元类型,可能与上述情况不同,具体参阅该类型单元的使用说明。系统用灰色表示该单元不投入使用。
单元成员属性页包括〈遥测量〉、〈累计量〉、〈遥信量〉、〈定值量〉、〈SOE事件〉、〈操作量〉,用鼠标点取属性页标题可显示相对应的属性页。属性页左边列表框内列出了该单元所有的该类型的成员,‘:’前面是该成员的字段名,‘:’后面是它的名称,属性页右边是关于该成员的具体参数,各成员的具体参数说明如下:
 遥测量:
专用名:该遥测量的描述性文字
最大值:当数据大于该值时,就取该值
最小值:当数据小于该值时,就取该值
高报警值:当数据大于该值时,产生高报警
低报警值:当数据小于该值时,产生低报警
(考虑到在边界状态可能频繁报警,系统采用了死区和延时的办法进行解决)
零位漂移:加到新数据的偏移量
比例缩放:乘到新数据的系数(新数据=零位漂移+比例缩放×原始数据)
精度:小数点后有效数论文#p#分页标题#e#上海论文 www.zhonghualw.com整理提供据位数,如最大值为10-100之间,建议取0.1
阈值:当数据小于该值时,置新数据为零,主要用于消除变送器残差
保存数据:选中则保存该数据及统计信息到数据库
(对不重要的数据,建议不保存,这样可明显提高系统性能,节省硬盘空间)
产生报警事件:选中,当该数据发生高/低报警时,将产生一条报警事件
 累计量:
(重复部分同遥测量)
满度值:当该累计量的数据超过该值时,自动返零
 遥信量:
(重复部分同遥测量)
状态0名称:状态0的描述性文字,如分、断开、退出等
状态1名称:状态1的描述性文字,如合、连通、投入等
接收时状态反转:自动取反,当外部接线接反时,此功能十分有用
 定值量:
(重复部分同遥测量)
 SOE事件量:
(重复部分同遥测量)
SOE事件量带时标及状态
状态0名称:状态0的描述性文字,如分闸、保护动作等
状态1名称:状态1的描述性文字,如合闸、报警等
事件类型:SOE事件量一般为SOE事件,但也可以其他事件类型方式出现,包括用户注册事件类型,如电气设备变位、电气设备故障等
 操作量:
(重复部分同遥测量)
操作量可以有二个配对操作,如合闸、分闸,升挡、降挡,对这种情况提供二种操作的不同名称
操作0名称:操作0的描述性文字,如分闸、降挡等
操作1名称:操作1的描述性文字,如合闸、升挡等
操作量可带安全保护,具体取决于单元对该操作量响应的实际行为
 打印参数表
从〈文件〉菜单中选〈打印…〉可打印参数表,选〈打印预览…〉可预览参数表。
 容量
系统最多能建100个通信口,每个通信口最多能挂100个单元。
 退出
从〈文件〉菜单中选〈退出〉菜单可退出单元组态软件。当发现有空的单元名字或重复的单元名字,则必须修改正确后才能退出系统。在保存新数据之前,主控程序一直以原来的数据运行。
7.1.3 图元组态界面(PICSET)的设计与实现
 
#p#分页标题#e#
 
 
图7-6 图元组态软件
图片组态软件是本系统提供的强大的界面设计工具,许多实时界面及报表的设计工作将在这里完成。从主控程序的〈系统维护〉菜单中选择〈图片组态软件〉,输入系统管理员口令,则可进入图片组态软件。
 图片属性
从〈图片操作〉菜单中选〈图片属性…〉,系统弹出〈图片属性〉对话框,图片分三种类型:报表图片、屏幕图片、屏幕子图,它们在屏幕显示时基本相似,打印时则采用不同的方法,报表图片打印时利用打印机分辨率,可得到高质量的报表,而屏幕图片、屏幕子图打印时采用硬拷贝技术,保留了屏幕显示时的风格。图片宽度、高度可直接输入,用右边的按钮可选取系统预设的一些尺寸,对报表图片,一个尺寸单位对应0.01英寸,显示时以一个尺寸单位对应一个像素;对屏幕图片,一个尺寸单位对应一个像素,论文上海论文 www.zhonghualw.com整理提供#p#分页标题#e#打印时以纸张能够容纳的最大方式打印。对报表图片,建议背景颜色选白色,前景颜色选黑色。屏幕图片将在主控程序的〈屏幕图片〉菜单中自动列出,而屏幕子图则必须通过图元的子图方式进入。
 画新的图元
若没有图元工具面板,请从〈工作环境〉菜单中选〈显示工具面板〉。在工具面板上有各种图元按钮,其中第一个箭头形状的按钮为选择按钮。移动光标到您要画的图元上面,按鼠标左键,该图元按钮显示为按下状态,然后将光标移到绘图区,此时光标形状为十字形,按鼠标左键不放并拖动,新的图元就画出来了,而且该图元自动处于选中状态,继续以上操作,可以画许多同类型的图元。
 选中图元
移动光标到您要选中的图元上面,按鼠标左键,可选中该图元,系统以亮色的八个小手柄来表示图元处于选中状态。在该图元外按鼠标左键,可使该图元落选。若在选中图元时按下键盘Shift键,则不落选以前选中的图元,用此方法可选中多个图元。除了点取法之外,也可用交叉法,在没有图元的地方按鼠标左键并拖动,将产生一个虚线矩形,与该矩形相交的图元全部被选中。特殊的选中方式可从菜单〈图元选中〉中实现,〈全部选中〉可以选中所有的图元,包括超出屏幕显示范围看不见的图元。
 移动图元
选中您要移动的图元,在选中的图元上按鼠标左键,选中的这些图元会随着鼠标的移动而移动,到合适的位置放开鼠标左键,完成移动操作。除了用鼠标移动之外,可用键盘进行移动。同样先选中图元,按键盘中的上下左右箭头键,可使图元上下左右移动,每次移动一个像素。在移动过程中按键盘Ctrl键,可快速移动,每次移动十个像素。
 复制图元、粘贴图元
选中您要复制的图元,从〈图元操作〉菜单中选〈复制到内存〉,可将图元完全复制到内存中。从〈图元操作〉菜单中选〈从内存粘贴〉,将新建与内存中完全一样的图元。可粘贴多次,每粘贴一次,图元自动偏移十个像素。这与快速移动图元刚好对应起来,熟练运用这种方式可使图元的对齐十分方便。
 删除图元、恢复删除图元
选中您要删除的图元,从〈图元操作〉菜单中选〈删除〉,则删除这些选中的图元。从〈图元操作〉菜单中选〈恢复删除图元〉,可将最近删除的图元自动还原,还原操作只能执行一次。
 翻转图元
选中您要翻转的图元,从〈图元操作〉菜单中选〈水平方向翻转〉或〈垂直方向翻转〉,可翻转选中的图元。
 前后移动图元
图元在图片中有前后次序,前面的图元可以盖住后面的图元。通过选〈图元操作〉菜单中的〈移到最前面〉或〈移到最后面〉可改变图元原有的次序。新加的图元、粘贴的图元及恢复删除的图元总是放到最前面。#p#分页标题#e#
 改变图元尺寸
选中您要改变尺寸的图元,把光标移到亮色的小手柄上,光标的形状会变化,然后按鼠标左键并拖动,图元的尺寸随着改变,放开鼠标左键完成该操作。也可用键盘完成该操作,按下键盘Shift键,同时按键盘中的上下左论文上海论文 www.zhonghualw.com整理提供右箭头键,图元的宽度、高度自动改变,每次改变一个像素点。需要细调时,用键盘操作是个很好的主意。图元的显示与宽度、高度有一定的关系,如〈文本〉图元,当宽度大于高度时,以水平方向显示文本,当宽度小于高度时,则以垂直方向显示文本。
 冻结与解冻
对一些已确认为不想再修改的图元,可冻结起来,以免无意中改动它。先选中您要冻结的图元,从〈图元操作〉菜单中选〈冻结〉,则可冻结图元,此后,这些图元以背景的方式显示,无法再选中它们。解冻可将已经冻结的所有图元还原为正常状态。熟练运用冻结与解冻操作对提高画图速度十分有用。#p#分页标题#e#
 单元快速布图
从〈图元操作〉菜单中选〈单元快速布图〉,系统弹出〈单元快速布图〉对话框,从单元列表中选择一个单元,按〈确认〉按钮,系统将自动建立一系列新的图元,这些图元都与该单元包含的所有数据、操作联系起来。这对调试一个新增加的单元是很有用的。
 图元对齐
图元对齐必须选中二个以上图元,并以最后选中的那个图元为准。从〈图元对齐〉菜单中选取合适的对齐方式,可将图元自动对齐。
 工作环境
绘图区有背景网格,从〈工作环境〉菜单中选〈显示网格〉可切换是否显示网格。网格的宽度与高度可在〈图片属性〉对话框中设定。对选中的图元,系统以亮色的小手柄表示,当需要细调或画很小的图元时,小手柄可能会带来视觉上的干扰,从〈工作环境〉菜单中选〈显示选中炳〉可切换是否显示小手柄。有时会觉得工具面板碍手碍脚,从〈工作环境〉菜单中选〈显示工具面板〉可切换是否显示工具面板。用鼠标可移动图元,虽然很有用,但有时在移动鼠标时会无意中改动本已定型的图元,为了避免这种失误,可从〈工作环境〉菜单中选〈允许鼠标移动〉可切换是否允许鼠标移动。进入图片的细调阶段,禁止鼠标移动就很好,因为移动工作可用键盘来完成,而且很精致。有一点要注意,禁止鼠标移动后,新建图元就不行了,此时只能先允许鼠标移动,再建新图元。对菜单的操作,系统提供快捷工具条和热键来完成同样的功能,多用这些工具,能提高绘图效率。
 设定图元属性
先选中图元,若选中了多个图元,则以最后选中的图元为准。从〈图元操作〉菜单中选〈属性…〉,系统弹出该图元的〈图元属性〉对话框,在这里您可修改图元的各种显示特性。通过在图元上双击鼠标左键,也可弹出〈图元属性〉对话框。除了白色背景的报表变量、变量组显示图元之外,其它图元都有数据、操作、子图、备注连接功能。数据连接可使数据通过图元反映出来。其中实时数据框、实时指针、实时曲线、实时棒图这四个图元专用于反映模拟量、累计量、简单显示量。其它图元都用于反映数字量。选中〈数据〉属性页,可以看到有二个组合框:单元组合框与数据组合框,从单元组合框中选一个单元,该单元包含的所有模拟量、累计量、简单显示量已全部出现在数据组合框内,选择其中的一个数据,就完成了数据连接操作。操作连接可使操作人员通过该图元执行单元提供的各种操作,如遥控遥调、复位下位机等。操作连接的过程与数据连接的过程一样。子图可使图片之间的切换十分方便直观。选中〈子图〉属性页,可以看到连接图片文件编辑框,您可以直接输入图片文件,或通过右边的小按钮查找。备注可进行一些辅助性的管理工作。选中〈备注〉属性页,可以看到一个很大的编辑框,在这里您可输入相关的一些描述性文字。对一些必须提供数据连接或变量连接的图元,当连接的数据或变量无效时,系统以灰色背景的一个打叉方块表示。#p#分页标题#e#
 动态颜色
许多图元都支持动态颜色。选中该图元颜色设定属性页,可以看到有二个选项:静态颜色,动态颜色。静态颜色指图元显示时的颜色与连接的数字量状态无关。动态颜色指图元显示时的颜色会随连接的数字量状态的论文上海论文 www.zhonghualw.com整理提供变化而自动变化,以指示该数字量的当前状态。因此,选动态颜色时必须提供二种颜色,即状态0时颜色与状态1时颜色。当连接的数字量无效时,图元以静态颜色显示。根据需要还可选是否闪烁,闪烁时图元以间隔0.5秒轮流切换该状态时颜色与静态颜色。这种方式用于重要的数字量状态指示,以吸引操作人员的注意力。
 动态位图
该功能仅限于〈位图〉图元。与动态颜色一样,只是将某种颜色替换为一个位图文件。这是对动态颜色的一种扩充,使设计的界面更加漂亮、直观。
 编写报表命令#p#分页标题#e#
从〈工作环境〉菜单中选〈变量设定...〉,系统自动弹出〈变量设定〉对话框,在右边的编辑框内您可输入可种变量定义命令,具体命令的用法见附录B〈变量命令说明〉。按右下边的〈运行〉按钮,可以查看命令的执行结果。数据库取数命令比较复杂,为了避免写错,系统提供可视化取数界面,按〈取数...〉按钮,系统弹出〈从数据库取数〉对话框,在这里您可选择数据文件、字段、起始时间、间隔时间、取数方式、取数个数、变量名称,按〈确认〉按钮后,系统自动为您刚才设定的取数方式转化为一条取数命令加到命令编辑框中。
 显示变量
图元变量打印、变量组打印、变量组曲线、变量组棒图专用于显示变量、变量组。其中变量打印图元中选择变量时,可能会出现$Y、$M、$D的字样,这是日期变量,$Y表示报表显示的当前年,$M表示报表显示的当前月、$D表示报表显示的当前日。
 图元专有属性
每种图元都有自己的专有属性,如〈矩形〉图元的线、线颜色、填充、填充颜色。这种专有属性的设置是比较直观简单的,在这里不作详细介绍,用户可自己试着熟悉这些功能。
 退出
从〈图片操作〉菜单中选〈退出〉菜单可退出图片组态软件。系统自动记录文件是否被修改,若修改过则提示是否保存,按〈确认〉按钮系统保存图片文件,并自动将新的修改结果切入运行,在保存新内容之前,主控程序一直以原来的内容运行。
7.1.4程序公共单元(PUBLIC)的设计与实现
此单元模块是动态链接模块,是电力SCADA软件系统的核心,几乎涵盖了所有的程序子模块,其他模块都是围绕着这个模块来工作运行的。PUBLIC模块是在程序初始化时载入系统的,他包含有丰富的内容——大部分功能主模块的程序类都在其中(如:口令管理模块、信息管理模块、工具条管理模块、时间管理模块、事件管理模块、通讯口管理模块、单元管理模块等等)。以单元对象模块为例来说,他包含在这个模块中包括了一个基本类——myCUnit(Unit.h\Unit.cpp),通过这个类来联系与本模块关联着的各个数据的设置、更改、处理等等。比如说,此模块就关联了与他的资源文件resource.h相对应的对话框程序文件 (UnitDlg.h\UnitDlg.cpp),在这两个文件中涵盖了用于完成各个功能所有与单元设置的相关对话框类(如:单元属性页面——CUnitAttribPage;单元模拟量页面——CAnalogPage;单元累计量页面——CAccumulatePage;单元开关量页——CDigitalPage;单元操作量页面——COperatePage等)。
7.1.5具体通讯单元(CKUNIT)的设计与实现
此单元模块也是动态链接模块,是电力SCADA软件系统在按照具体通讯单元的协议所编写的程序,在初始化时载入系统,由系统在单元组态图元中加入相应的单元并对其具体参数进行设定。在本系统中可以加载不同的此类动态链接文件,用于连接不同设备,实现不同设备在同一平台下的通讯。此模块同样利用DLLMain作为程序入口,将各个功能衔接在一起并且通过DLL.TXT文件调入ckunit.dll动态链接文件。由于不同厂家的设备可能具有不同的通讯规约,为了使系统的扩展性更好,能够接入不同厂家的设备,因此通过此模块将具体的通讯规约链接入系统——通过public中的通讯单元模块(Unit、UnitDlg)完成此类工作。#p#分页标题#e#
7.2 系统完成
7.2.1系统的编译与调试
系统编译可以采用分部编译即各个模块(设mian、unit、picset、public、ckunit等为工程)各自独立编译,也可通过兴建一个scada工作台,将各个工程连接一起进行共同编译调试。VC++提供了完善的调试工具,可以通过设置断点跟踪等技术完成系统的调试,此外在调试中要善于使用MSDN(Microsoft Software Developer Network)联机文档,另外,此软件的调试具有特殊性——因为要连接不同的设备,所以还要通过串口对设备联调,测试各个指令的下达及接收。另外,在调试时,要注意程序的输出目录及链接文件。
7.2.2系统的运行及案例
系统调试完成后可以运行程序,本程序在装有VC++6.0环境下的windows2000系统下长期运行通过。针对windows xp系统稍作调整即可安全可靠运行。目前,此软件已在莱芜钢厂试运行,从目前的情况来看,系统能够安全、可靠运行,用户给予了较高的评价。
7.3 本章小节
本章从设计和实现两个方面对各个主要典型模块进行了详细的说明和解释,对于各个模块的使用及其功能的说明较全面的进行了介绍。

第八章 结束语

经过了两个多月的学习和工作,在导师的鼓励和帮助下,在同事们的共同参与下,我终于完成了《电力监控SCADA软件开发》的论文。
全文从绪论开始,并由此在第二章介绍了SCADA系统的概念和发展,第三章中阐述了电力SCADA系统的通讯网络和规约,第四章中又简单说明了编程软件和环境,在第五章又进行了需求和可行性分析,第六章和第七章详细论述了系统规划、设计与实现,最后是结束语、参考文献、致谢和附录。
在从开始接到论文题目到系统的实现,再到论文文章的完成,每走一步对我来说都是新的尝试与挑战,这也是我在工作以来独立完成的最大的一个项目。在这段时间里,我学到了很多知识也有很多感受,从对很多知识的一知半解,对很多相关技术不很熟悉的状态,我开始了的学习和试验,查看大量的相关资料和书籍,让自己头脑中模糊的概念逐渐清晰,使自己非常稚嫩作品一步步完善起来,每一次改进都是我学习的收获,每一次试验的成功都会让我兴奋好一段时间。从中我也充分认识到了VC++6.0给我的生活带来的乐趣,在属于自己的编程空间上,尽情的挥洒写意,有的时候,感觉编程就是一门艺术,有的时候把自己的新想法与他人分享,我们的同事往往会提出置疑,就是在这种争论中使我的想法不断的提高、成熟。
虽然我的论文作品还有很多不足之处,但我可以自本#p#分页标题#e#论文上海论文 www.zhonghualw.com整理提供豪的说,这里面的大部分程序代码,都有我的劳动。当看着自己的程序,自己成天相伴的系统能够健康的运行,真是莫大的幸福和欣慰。我相信其中的酸甜苦辣最终都会化为甜美的甘泉。
这次做论文的经历也会使我终身受益,我感受到做论文是要真真正正用心去做的一件事情,是真正的自己学习的过程和研究的过程,没有学习就不可能有研究的能力,没有自己的研究,就不会有所突破,那也就不叫论文了。希望这次的经历能让我在以后学习中激励我继续进步。
随着技术的不断更新,在以后的工作中,我将努力将OPC技术融入到本软件中,使不同规约的设备能够更方便的接入系统,将加入TCP/IP协议规约,使软件具有更好的生命力,提高系统的安全性和可靠性。

参考文献

【1】 黄维通著。Visual C++面向对象与可视化程序设计。北京:清华大学出版社,1997
【2】 尹立民著。Visual C++软件项目开发实例。北京:电子工业出版社,2004.11
【3】 《电脑编程技巧与维护》杂志社著。Visual C/C++编程精选集锦(网络与通信分册)。北京:科学出版社,2003#p#分页标题#e#
【4】 甘永梅著。现场总线技术及其应用。北京:机械工业出版社,2004.5
【5】 汪令江著。奇思妙想编程序(VC篇)。北京:国防工业出版社,2004
【6】 Kruse(美)著,钱丽萍译。C++数据结构与程序设计。北京:清华大学出版社,2003
【7】 Prata(美)著,孙建春译。C++ Primer Plus:第五版。北京:人民邮电出版社,2005.5
【8】 Pender.R(美),苏剑著。标准C++编程宝典。北京:电子工业出版社,2005.1
【9】 钱能著。C++程序设计教程。北京:清华大学出版社,1999.4
【10】 Shiflet著,夏兆彦译。C++程序设计(含选读内容和实验指导)。北京:清华大学出版社,2004
【11】 丁展,刘海英著。Visual C++网络通信编程实用案例精选。北京:人民邮电出版社,2004
【12】 求是科技,李现勇著。Visual C++串口通信技术与工程实践(第二版)。北京:人民邮电出版社,2004.7
【13】 求是科技著。Visual C++6.0程序设计与开发技术大全。北京:人民邮电出版社,2004.9
【14】 Allison.C。C&C++ Code Capsules:A Guide for Practitioners。1st Edition bychuck Allison,1998
【15】 Herbert Schildt。C++:The Complete Reference,Fourth Edition。The Mcgran-Hill Companies.Inc
【16】 刘晓华著。精通MFC。北京:电子工业出版社,2003.9
【17】 Charles Wright著,邓励生译。Visua论文#p#分页标题#e#上海论文 www.zhonghualw.com整理提供l C++程序员实用大全(精华版)。北京:中国水利水电出版社,2005
【18】 李鹏著。计算机通信技术及其程序设计。陕西:西安电子科技大学出版社,2002
【19】 侯俊杰著。深入浅出MFC。湖北:华中科技大学出版社,2001
【20】 David J.kruglinki 著。VC++技术内幕。北京:清华大学出版社,2001
 

致谢

在论文的最后,首先,感谢我的导师谢康林教授,本文正在在他的悉心指导下才顺利完成的。在我做论文期间,导师渊博的学识、严谨求实的科学精神、一丝不苟的治学态度和高尚的学者品格,深深的感染着我和每一个同学。论文的每次改动都离不开老师的辛勤工作,从各个方面来说,审查的工作往往比编写任务更复杂。正是导师百忙中不辞劳苦的帮助,才使我能够顺利完成这篇论文,在这里,对您衷心的表示感谢。
在做论文期间,我的同事们的帮助同样让我感谢,他们的一个好的意见和想法,有时让我茅塞顿开;陪我加班到很晚更是常事,这套系统的完成,没有他们的帮助,我可能至今仍然还在脑海中,无法变成实实在在的代码。
最后,感谢我的同学和这两年中教授我知识的各位老师,还有教务戴骝老师、我的班主任等等,正是他们孜孜不倦的工作才能使我在知识的殿堂中前行。
附录

1.1 部分典型源代码
UNIT.H 文件
// 单元通信错误类型:
enum ComErrorType
{
 CET_NOERROR,    // 无错误;
 CET_HEAD,     // 数据头错误;
 CET_ADDRESS,    // 地址错误;
 CET_LENGTH,    // 长度不匹配;
 CET_CMDTYPE,    // 命令类型不匹配;
 CET_SUM,     // 校验和错误;
 CET_TIMEOUT,    // 通信超时;
 CET_OTHERDATA,   // 接收到多余数据;
 CET_NOREPONSE,   // 没有反应;
 CET_NOTMYDATA,   // 不是我的数据;
 CET_MAYBEMYDATA,  // 可能是我的数据;
 CET_ERROROTHER   // 其他错误信息;
};
// 通信控制块:
struct COMCONTROL
{
 BOOL bNextUnitReceive;  // 允许下个单元接收标志;#p#分页标题#e#
 BOOL bNextUnitSend;   // 允许下个单元发送标志;
 BOOL bSendDelay;   // 发送后延时标志;
 BYTE *pTXData;    // 发送数据缓冲;
 BYTE *pRXData;    // 接收数据缓冲;
 int  nTXLength;    // 要求发送的数据长度;
 int  nRXLength;    // 已经接收的数据长度;
};
//---------------------------------------------- myCUnit ------------
class MYDECLARE_PUBLIC myCUnit:public CObject   // 单元对象;
{
protected:
 DECLARE_SERIAL(myCUnit);
 myCUnit();
public:
 static CMapStringToPtr mapUnits;
 static void RegisterClass(CString strType,CRuntimeClass* pType);
public:
 CString   m_strDefName;  // 该单元缺省名称;
 CString   m_strName;   // 该单元名称(唯一性);
 BOOL   m_bUsed;   // 是否投入使用标志;
 BYTE   m_Address;   // 站号;
public:
 myCSOEArray  m_soes;   // SOE事件;
 myCDataArray m_datas;    // 数据;
 myCOperateArray m_operates;   // 操作;
public:
 BOOL   m_bWaitReceive;  // 等待接收标志;
 clock_t   m_clockCom;         // 用于检查超时;
 clock_t         m_clockSet;
 ComErrorType m_ComError;   // 通信错误标志;
 int    m_nComLength;  // 已接收到的数据长度;
 BYTE*   m_pComBuffer;  // 通信接收数据缓冲区;
public:
 virtual ~myCUnit();
 myCUnit &operator=(myCUnit& unit);
 virtual myCUnit* Clone(void);
 virtual void Serialize(CArchive& ar);
 virtual void Create(void);
 virtual void Destroy(void);
 virtual BOOL OnAttrib(void);
 virtual BOOL OnAttrib(CPropertySheet& sheet);
 virtual void Fresh1s(void);
 virtual void Fresh10s(void);
 virtual void Fresh1min(void);
 virtual void SaveData(myCDataInfoArray& datainfos);
 virtual BOOL OnOperate(CString strOperateField){ return TRUE; };
 virtual BOOL OnOperate(CString st本#p#分页标题#e#论文上海论文 www.zhonghualw.com整理提供rOperateField,BYTE Operate){ return TRUE; };
public:
 int GetSOESize(CRuntimeClass* pSOEType);
 int GetDataSize(CRuntimeClass* pDataType);
 int GetOperateSize(CRuntimeClass* pOperateType);
 myCSOE* GetSOE(int nIndex,CRuntimeClass* pSOEType);
 myCSOE* GetSOE(CString strField,CRuntimeClass* pSOEType);
 myCData* GetData(int nIndex,CRuntimeClass* pDataType);
 myCData* GetData(CString strField,CRuntimeClass* pDataType);
 myCOperate* GetOperate(int nIndex,CRuntimeClass* pOperateType);
 myCOperate* GetOperate(CString strField,CRuntimeClass* pOperateType);
 void AddSOE(myCSOE* pSOE);
 void AddData(myCData* pData);
 void AddOperate(myCOperate* pOperate);
 void AddSOE(CString strField,CString strName,CString strSOE0,CString strSOE2);
 void AddData(CString strField,CString strName);
 void AddOperate(CString strField,CString strName,CString strOperate0,CString strOperate1);
public:
 virtual void ReceiveComData(COMCONTROL* pCC){};
 virtual void SendComData(COMCONTROL* pCC){};
 virtual void SetComAlarm(ComErrorType ComError);
 virtual BOOL IsComError(void){ return (m_ComError==CET_NOERROR)?FALSE:TRUE; };#p#分页标题#e#
 virtual int GetComStatusSize(void){ return 8; };
 virtual int GetComStatus(void){ return 0; };
public:
 virtual int GetPrintCount(void);
 virtual CString GetPrintHead(int nNo);
 virtual CString GetPrintContent(int nNo);
};
typedef CTypedPtrArray<CObArray, myCUnit*> myCUnitArray;
//---------------------------------------------- myCTRUnit ----------
//发送接收(呼叫响应)方式的类头
class MYDECLARE_PUBLIC myCTRUnit:public myCUnit
{
protected:
 DECLARE_SERIAL(myCTRUnit);
 myCTRUnit(){};
private:
 static BOOL bSendAllow;
 static BOOL bCheckTime;
 static time_t timeCheckTime;
protected:
 static void TrigCheckTime(void);
 static BOOL IsCheckTime(void);
public:
 virtual void Fresh1s(void);
 virtual ComErrorType CheckComData(void){ return CET_NOERROR; };
 virtual void SendComData论文上海论文 www.zhonghualw.com整理提供#p#分页标题#e#(COMCONTROL* pCC);
 virtual void ReceiveComData(COMCONTROL* pCC);
 virtual void SendHandler(COMCONTROL* pCC){};
 virtual void ReceiveHandler(COMCONTROL* pCC){};
 virtual void OnReceiveError(void){};
};
//---------------------------------------------- myCRTUnit ----------
//接收发送方式类头
class MYDECLARE_PUBLIC myCRTUnit:public myCUnit
{
protected:
 DECLARE_SERIAL(myCRTUnit);
 myCRTUnit(){};
public:
 virtual ComErrorType CheckComData(void){ return CET_NOTMYDATA; };
 virtual void SendComData(COMCONTROL* pCC);
 virtual void ReceiveComData(COMCONTROL* pCC);
 virtual void SendHandler(COMCONTROL* pCC){};
 virtual void ReceiveHandler(COMCONTROL* pCC){};
 virtual void OnReceiveError(void){};
};
//---------------------------------------------- myCPPUnit ----------
//上层通讯
class MYDECLARE_PUBLIC myCPPUnit:public myCUnit
{
protected:
 DECLARE_SERIAL(myCPPUnit);
 myCPPUnit();
public:
 int m_nHeadLength;
public:
 virtual void TrimHead(void){};
 virtual ComErrorType CheckComData(void){ return CET_NOTMYDATA; };
 virtual void SendComData(COMCONTROL* pCC);
 virtual void ReceiveComData(COMCONTROL* pCC);
 virtual void SendHandler(COMCONTROL* pCC){};
 virtual void ReceiveHandler(COMCONTROL* pCC){};
 virtual void OnReceiveError(void){};
};
UNIT.CPP 文件
#include "Public.h"
#include "resource.h"
#include "UnitDlg.h"
//---------------------------------------------- myCUnit ------------
IMPLEMENT_SERIAL(myCUnit, CObject, 0)
CMapStringToPtr myCUnit::mapUnits;
myCUnit::myCUnit():CObject()
{
 m_bUsed = TRUE;
 m_Address = 0;
 m_bWaitReceive = FALSE;
 m_ComError = CET_NOERROR;
 m_nComLength = 0;
 m_pComBuffer = new BYTE[1024];
 m_clockSet = 5000;
}
myCUnit::~myCUnit()
{
 Destroy();
 delete[] m_pComBuffer;
}
myCUnit &myCUnit::operator=(myCUnit& unit)
{
 m_strDefName = unit.m_strDefName;
 m_strName = unit.m_strName;
 m_bUsed = unit.m_bUsed;
 m_Address = unit.m_Address;
 Destroy();
 int i,nSize;
 nSize = unit.m_soes.GetSize();
 for(i=0;i<nSize;i++)
 {
  myCSOE* pSOE = unit.m_soes[i]->Clone();
  ASSERT(pSOE!=NULL);
  m_soes.Add(pSOE);
 }
 nSize = unit.m_datas.GetSize();
 for(i=0;i<nSize;i++)
 {
  myCData* pData = unit.m_datas[i]->Clone();
  ASSERT(pData!=NULL);
  m_datas.Add(pData);#p#分页标题#e#
 }
 nSize = unit.m_operates.GetSize();
 for(i=0;i<nSize;i++)
 {
  myCOperate* pOperate = unit.m_operates[i]->Clone();
  ASSERT(pOperate!=NULL);
  m_operates.Add(pOperate);
 }
 return *this;
}
myCUnit* myCUnit::Clone(void)
{
 myCUnit* pUnit = new myCUnit;
 *pUnit = *this;
 return pUnit;
}
void myCUnit::Serialize(CArchive& ar)
{
 CObject::Serialize(ar);
 if(ar.IsStoring())
 {
  ar << m_strDefName;
  ar << m_strName;
  ar << m_bUsed;
  ar << m_Address;
 }
 else
 {
  ar >> m_strDefName;
  ar >> m_strName;
  ar >> m_bUsed;
  ar >> m_Address;
 }
 m_soes.Serialize(ar);
 m_datas.Serialize(ar);
 m_operates.Serialize(ar);
 if(ar.IsLoading())
 {
  int i;
  for(i=0;i<m_soes.GetSize();i++) m_soes[i]->m_pOwnerUnit = this;
  for(i=0;i<m_datas.GetSize();i++) m_datas[i]->m_pOwnerUnit = this;
  for(i=0;i<m_operates.GetSize();i++) m_operates[i]->m_pOwnerUnit = this;
 }
}
void myCUnit::Create(void)
{
}
void myCUnit::Destroy(void)
{
 int i,nSize;
 
 nSize = m_soes.GetSize();
 for(i=0;i<nSize;i++) delete m_soes[i];
 m_soes.RemoveAll();

 nSize = m_datas.GetSize();
 for(i=0;i<nSize;i++) delete m_datas[i];
 m_datas.RemoveAll();

 nSize = m_operates.GetSize();
 for(i=0;i<nSize;i++) delete m_operates[i];
 m_operates.RemoveAll();
}
BOOL myCUnit::OnAttrib(void)
{
 HINSTANCE hInstOld = AfxGetResourceHandle();
 AfxSetResourceHandle(PublicDLL.hModule);
 CPropertySheet sheet;
 CUnitAttribPage pageAttrib;
 pageAttrib.m_strDefName = m_strDefName;
 pageAttrib.m_strName = m_strName;
 pageAttrib.m_Address = m_Address;
 pageAttrib.m_bUsed = m_bUsed;
 sheet.AddPage(&pageAttrib);
 int i,nSize;
 CAnalogPage pageAnalog;
 nSize = GetDataSize(RUNTIME_CLASS(myCAnalog));
 if(nSize)
 {
  for(i=0;i<nSize;i++)
  {
   myCData* pData = GetData(i,RUNTIME_CLASS(myCAnalog));
   myCAnalog* pAnalog = (myCAnalog*)((myCAnalog*)pData)->Clone();
   pageAnalog.m_analogs.Add(pAnalog);
  }
  sheet.AddPage(&pageAnalog);
 }
 CAccumulatePage pageAccumulate;#p#分页标题#e#
 nSize = GetDataSize(RUNTIME_CLASS(myCAccumulate));
 if(nSize)
 {
  for(i=0;i<nSize;i++)
  {
     myCData* pData = GetData(i,RUNTIME_CLASS(myCAccumulate));
     myCAccumulate*pAccumulate=(myCAccumulate*)((myCAccumulate*)pData)->Clone();
     pageAccumulate.m_accumulates.Add(pAccumulate);
  }
  sheet.AddPage(&pageAccumulate);
 }
 CDigitalPage pageDigital;
 nSize = GetDataSize(RUNTIME_CLASS(myCDigital));
 if(nSize)
 {
  for(i=0;i<nSize;i++)
  {
   myCData* pData = GetData(i,RUNTIME_CLASS(myCDigital));
   myCDigital* pDigital = (myCDigital*)((myCDigital*)pData)->Clone();
   pageDigital.m_digitals.Add(pDigital);
  }
  sheet.AddPage(&pageDigital);
 }
 CSimpleDataPage pageSimpleData;
 nSize = GetDataSize(RUNTIME_CLASS(myCSimpleData));
 if(nSize)
 {
  for(i=0;i<nSize;i++)
  {
     myCData* pData = GetData(i,RUNTIME_CLASS(myCSimpleData));
     myCSimpleData*pSimpleData=(myCSimpleData*)((myCSimpleData*)pData)->Clone();
     pageSimpleData.m_simpledatas.Add(pSimpleData);
  }
  sheet.AddPage(&pageSimpleData);
 }
 CSOEPage pageSOE;
 nSize = GetSOESize(RUNTIME_CLASS(myCSOE));
 if(nSize)
 {
  for(i=0;i<nSize;i++)
  {
   myCSOE* pSOE = GetSOE(i,RUNTIME_CLASS(myCSOE));
   pageSOE.m_soes.Add(pSOE->Clone());
  }
  sheet.AddPage(&pageSOE);
 }
 COperatePage pageOperate;
 nSize = GetOperateSize(RUNTIME_CLASS(myCOperate));
 if(nSize)
 {
  for(i=0;i<nSize;i++)
  {
   myCOperate* pOperate = GetOperate(i,RUNTIME_CLASS(myCOperate));
   pageOperate.m_operates.Add(pOperate->Clone());
  }
  sheet.AddPage(&pageOperate);
 }
 if(OnAttrib(sheet))
 {
  m_strName = pageAttrib.m_strName;
  m_Address = pageAttrib.m_Address;
  m_bUsed = pageAttrib.m_bUsed;
  int i,nSize;
  nSize = pageAnalog.m_analogs.GetSize();
  for(i=0;i<nSize;i++)
  {
   myCData* pData = GetData(i,RUNTIME_CLASS(myCAnalog));
   myCAnalog* pAnalog = (myCAnalog*)pData;
   *pAnalog = *pageAnalog.m_analogs[i];#p#分页标题#e#
   delete pageAnalog.m_analogs[i];
  }
  nSize = pageAccumulate.m_accumulates.GetSize();
  for(i=0;i<nSize;i++)
  {
   myCData* pData = GetData(i,RUNTIME_CLASS(myCAccumulate));
   myCAccumulate* pAccumulate = (myCAccumulate*)pData;
   *pAccumulate = *pageAccumulate.m_accumulates[i];
   delete pageAccumulate.m_accumulates[i];
  }
  nSize = pageDigital.m_digitals.GetSize();
  for(i=0;i<nSize;i++)
  {
   myCData* pData = GetData(i,RUNTIME_CLASS(myCDigital));
   myCDigital* pDigital = (myCDigital*)pData;
   *pDigital = *pageDigital.m_digitals[i];
   delete pageDigital.m_digitals[i];
  }
  nSize = pageSimpleData.m_simpledatas.GetSize();
  for(i=0;i<nSize;i++)
  {
   myCData* pData = GetData(i,RUNTIME_CLASS(myCSimpleData));
   myCSimpleData* pSimpleData = (myCSimpleData*)pData;
   *pSimpleData = *pageSimpleData.m_simpledatas[i];
   delete pageSimpleData.m_simpledatas[i];
  }
  nSize = pageSOE.m_soes.GetSize();
  for(i=0;i<nSize;i++)
  {
   myCSOE* pSOE = GetSOE(i,RUNTIME_CLASS(myCSOE));
   *pSOE = *pageSOE.m_soes[i];
   delete pageSOE.m_soes[i];
  }
  nSize = pageOperate.m_operates.GetSize();
  for(i=0;i<nSize;i++)
  {
   myCOperate* pOperate = GetOperate(i,RUNTIME_CLASS(myCOperate));
   *pOperate = *pageOperate.m_operates[i];
   delete pageOperate.m_operates[i];
  }
  AfxSetResourceHandle(hInstOld);
  return TRUE;
 }
 AfxSetResourceHandle(hInstOld);
 return FALSE;
}
BOOL myCUnit::OnAttrib(CPropertySheet& sheet)
{
 sheet.Construct("单元<"+m_strName+">参数设定");
 sheet.m_psh.dwFlags |= PSH_NOAPPLYNOW;
 if(sheet.DoModal()==IDOK) return TRUE;
 return FALSE;
}
void myCUnit::Fresh1s(void)
{
 int nSize = m_datas.GetSize();
 for(int i=0;i<nSize;i++) m_datas[i]->Fresh1s();
}
void myCUnit::Fresh10s(void)
{
 int nSize = m_datas.GetSize();
 for(int i=0;i<nSize;i++) m_datas[i]->Fresh10s();
}
void myCUnit::Fresh1min(void)
{
}
void myCUnit::SaveData(myCDataInfoArray& datainfos)

 
 time_t timeSaveData = pTimeManager->m_timeNow;#p#分页标题#e#
 timeSaveData += 30L;
 timeSaveData -= timeSaveData%60L;
 int nSize = m_datas.GetSize();
 for(int i=0;i<nSize;i++)
 {
  myCData* pData = m_datas[i];
  myCDataInfo* pDataInfo = new myCDataInfo;
  pDataInfo->m_strUnitName = m_strName;
  pDataInfo->m_strDataName = pData->m_strField;
  pDataInfo->m_timeCurrent = timeSaveData;
  pDataInfo->m_nNum = 0;
  pData->SaveData(pDataInfo);
  if(pDataInfo->m_nNum) datainfos.Add(pDataInfo);
 }
}
int myCUnit::GetSOESize(CRuntimeClass* pSOEType)
{
 int nCount = 0;
 int nSize = m_soes.GetSize();
 for(int i=0;i<nSize;i++)
 {
  if(m_soes[i]->IsKindOf(pSOEType)) nCount ++;
 }
 return nCount;
}
int myCUnit::GetDataSize(CRuntimeClass* pDataType)
{
 int nCount = 0;
 int nSize = m_datas.GetSize();
 for(int i=0;i<nSize;i++)
 {
  if(m_datas[i]->IsKindOf(pDataType)) nCount ++;
 }
 return nCount;
}
int myCUnit::GetOperateSize(CRuntimeClass* pOperateType)
{
 int nCount = 0;
 int nSize = m_operates.GetSize();
 for(int i=0;i<nSize;i++)
 {
  if(m_operates[i]->IsKindOf(pOperateType)) nCount ++;
 }
 return nCount;
}
myCSOE* myCUnit::GetSOE(int nIndex,CRuntimeClass* pSOEType)
{
 if(nIndex>=0 && nIndex<m_soes.GetSize())
 {
  int nSize = m_soes.GetSize();
  int nTemp = 0;
  for(int i=0;i<nSize;i++)
  {
   if(m_soes[i]->IsKindOf(pSOEType))
   {
    if(nTemp==nIndex) return m_soes[i];
    nTemp ++;
   }
  }
 }
 return NULL;
}
myCSOE* myCUnit::GetSOE(CString strField,CRuntimeClass* pSOEType)
{
 int nSize = m_soes.GetSize();
 for(int i=0;i<nSize;i++)
 {
  if(m_soes[i]->IsKindOf(pSOEType))
  {
   if(m_soes[i]->m_strField==strField) return m_soes[i];
  }
 }
 return NULL;
}
myCData* myCUnit::GetData(int nIndex,CRuntimeClass* pDataType)
{
 if(nIndex>=0 && nIndex<m_datas.GetSize())
 {
  int nSize = m_datas.GetSize();
  int nTemp = 0;
  for(int i=0;i<nSize;i++)
  {
   if(m_datas[i]->IsKindOf(pDataType))
   {
    if(nTemp==nIndex) return m_datas[i];#p#分页标题#e#
    nTemp ++;
   }
  }
 }
 return NULL;
}
myCData* myCUnit::GetData(CString strField,CRuntimeClass* pDataType)
{
 int nSize = m_datas.GetSize();
 for(int i=0;i<nSize;i++)
 {
  if(m_datas[i]->IsKindOf(pDataType))
  {
   if(m_datas[i]->m_strField==strField) return m_datas[i];
  }
 }
 return NULL;
}
myCOperate* myCUnit::GetOperate(int nIndex,CRuntimeClass* pOperateType)
{
 if(nIndex>=0 && nIndex<m_operates.GetSize())
 {
  int nSize = m_operates.GetSize();
  int nTemp = 0;
  for(int i=0;i<nSize;i++)
  {
   if(m_operates[i]->IsKindOf(pOperateType))
   {
    if(nTemp==nIndex) return m_operates[i];
    nTemp ++;
   }
  }
 }
 return NULL;
}
myCOperate* myCUnit::GetOperate(CString strField,CRuntimeClass* pOperateType)
{
 int nSize = m_operates.GetSize();
 for(int i=0;i<nSize;i++)
 {
  if(m_operates[i]->IsKindOf(pOperateType))
  {
   if(m_operates[i]->m_strField==strField) return m_operates[i];
  }
 }
 return NULL;
}
void myCUnit::AddSOE(myCSOE* pSOE)
{
 m_soes.Add(pSOE);
}
void myCUnit::AddData(myCData* pData)
{
 m_datas.Add(pData);
}
void myCUnit::AddOperate(myCOperate* pOperate)
{
 m_operates.Add(pOperate);
}
void myCUnit::AddSOE(CString strField,CString strName,CString strSOE0,CString strSOE1)
{
 myCSOE* pSOE = new myCSOE;
 pSOE->m_strField = strField;
 pSOE->m_strDefName = strName;
 pSOE->m_strName = strName;
 pSOE->m_strSOE0 = strSOE0;
 pSOE->m_strSOE1 = strSOE1;
 AddSOE(pSOE);
}
void myCUnit::AddData(CString strField,CString strName)
{
 myCData* pData = new myCData;
 pData->m_strField = strField;
 pData->m_strDefName = strName;
 pData->m_strName = strName;
 AddData(pData);
}
void myCUnit::AddOperate(CString strField,CString strName,CString strOperate0,CString strOperate1)
{
 myCOperate* pOperate = new myCOperate;
 pOperate->m_strField = strField;
 pOperate->m_strDefName = strName;
 pOperate->m_strName = strName;
 pOperate->m_strOperate0 = strOperate0;
 pOperate->m_strOperate1 = strOperate1;
 AddOperate(pOperate);#p#分页标题#e#
}
void myCUnit::SetComAlarm(ComErrorType ComError)
{
 CString strMessage;
 switch(ComError)
 {
 case CET_HEAD  : strMessage = "数据头错误!";  break;
 case CET_ADDRESS : strMessage = "单元地址错误!";  break;
 case CET_LENGTH : strMessage = "数据长度不匹配!"; break;
 case CET_CMDTYPE : strMessage = "命令类型不匹配!"; break;
 case CET_SUM  : strMessage = "校验和错误!";  break;
 case CET_TIMEOUT : strMessage = "通信超时!";   break;
 case CET_OTHERDATA : strMessage = "接收到多余数据!"; break;
 case CET_NOREPONSE : strMessage = "没有反应!";   break;
 }
 if(!strMessage.IsEmpty())
 {
  pEventManager->AddEvent("通信出错","<"+m_strName+">"+strMessage);
 }
 m_ComError = ComError;
}
void myCUnit::RegisterClass(CString strType,CRuntimeClass* pType)
{
 if(pType->IsDerivedFrom(RUNTIME_CLASS(myCUnit)))
 {
  mapUnits[strType] = pType;
 }
}
int myCUnit::GetPrintCount(void)
{
 return 2;
}
CString myCUnit::GetPrintHead(int nNo)
{
 CString strPrintHead;
 switch(nNo)
 {
 case 0: strPrintHead = "投入使用"; break;
 case 1: strPrintHead = "地址"; break;
 }
 return strPrintHead;
}
CString myCUnit::GetPrintContent(int nNo)
{
 CString strPrintContent;
 switch(nNo)
 {
 case 0: strPrintContent = (m_bUsed)?"√":"×"; break;
 case 1: strPrintContent.Format("%d(%XH)",m_Address,m_Address); break;
 }
 return strPrintContent;
}
//---------------------------------------------- myCTRUnit ----------
IMPLEMENT_SERIAL(myCTRUnit, myCUnit, 0)
BOOL myCTRUnit::bSendAllow = TRUE;
BOOL myCTRUnit::bCheckTime = FALSE;
time_t myCTRUnit::timeCheckTime = 0;
void myCTRUnit::TrigCheckTime(void)
{
 timeCheckTime = 0;
}
BOOL myCTRUnit::IsCheckTime(void)
{
 return bCheckTime;
}
void myCTRUnit::Fresh1s(void)
{
 myCUnit::Fresh1s();
 // 实现统一校时:
 if(timeCheckTime+300L<pTimeManager->m_timeNow)
 {
  timeCheckTime = pTimeManager->m_timeNow;
  clock_t clock0 = clock();
  bSendAllow = FALSE;
  while(1)
  {
   pUnitsManager->FreshCom();#p#分页标题#e#
   int nSize = pUnitsManager->m_comports.GetSize();
   for(int i=0;i<nSize;i++)
   {
    myCComport* pComport = pUnitsManager->m_comports[i];
    if(!pComport->m_bUsed) continue;
    myCUnit* pUnit = pComport->GetComUnit();
    if(pUnit==NULL) continue;
    if(pUnit->IsKindOf(RUNTIME_CLASS(myCTRUnit)))
    {
     if(((myCTRUnit*)pUnit)->m_bWaitReceive) break;
    }
   }
   if(i==nSize || clock()-clock0>10000L) break;
  }
  bSendAllow = TRUE;
  bCheckTime = TRUE;
  pTimeManager->Fresh();
  pUnitsManager->FreshCom();
  bCheckTime = FALSE;
  Sleep(200);
 }
}
void myCTRUnit::SendComData(COMCONTROL* pCC)
{
 if(m_bWaitReceive)
 {
  pCC->bNextUnitReceive = FALSE;
  pCC->bNextUnitSend = FALSE;
  return;
 }
 else
 {
  pCC->bNextUnitReceive = FALSE;
  if(bSendAllow) SendHandler(pCC);
  if(pCC->nTXLength)
  {
   if(m_bWaitReceive)
   {
    pCC->bSendDelay = FALSE;
    m_clockCom = clock();
   }
   else pCC->bSendDelay = TRUE;
   pCC->bNextUnitSend = FALSE;
  }
  else pCC->bNextUnitSend = TRUE;
 }
}
void myCTRUnit::ReceiveComData(COMCONTROL* pCC)
{
 if(m_bWaitReceive)
 {
  // 拼装接收到的数据;
  if(pCC->nRXLength)
  {
   int nLengthMax = min(pCC->nRXLength,1024-m_nComLength);
   memcpy(m_pComBuffer+m_nComLength,pCC->pRXData,nLengthMax);
   m_nComLength += nLengthMax;
  }
  // 对数据进行有效检查;
  ComErrorType ComError = CheckComData();
  // 去除5秒之内的没有反应与通信超时错,继续接收;
  if(ComError==CET_NOREPONSE||ComError==CET_TIMEOUT)
  {
   if(clock()-m_clockCom<m_clockSet)
   {
    pCC->bNextUnitReceive = FALSE;
    pCC->bNextUnitSend = FALSE;
    m_ComError = CET_NOERROR;
    return;
   }
  }
  m_bWaitReceive = FALSE;#p#分页标题#e#
  if(ComError==CET_NOERROR) // 接收数据正确,进行处理;
  {
   ReceiveHandler(pCC);
   m_ComError = CET_NOERROR;
  }
  else      // 接收数据错误,进行错误报警;
  {
   m_ComError = ComError;
   OnReceiveError();
   ComError = m_ComError;
   SetComAlarm(ComError);
  }
  m_nComLength = 0;
 }
 pCC->bNextUnitReceive = FALSE;
 pCC->bNextUnitSend = TRUE;
}
//---------------------------------------------- myCRTUnit ----------
IMPLEMENT_SERIAL(myCRTUnit, myCUnit, 0)

void myCRTUnit::SendComData(COMCONTROL* pCC)
{
 pCC->bNextUnitReceive = FALSE;
 pCC->bNextUnitSend = FALSE;
 if(m_bWaitReceive) return;
 SendHandler(pCC);
 if(pCC->nTXLength)
 {
  pCC->bSendDelay = FALSE;
  if(m_bWaitReceive)
  {
   pCC->bSendDelay = FALSE;
   m_clockCom = clock();
  }
  pCC->bNextUnitSend = FALSE;
 }
 else pCC->bNextUnitSend = TRUE;
}
void myCRTUnit::ReceiveComData(COMCONTROL* pCC)
{
 // 拼装接收到的数据;
 if(pCC->nRXLength)
 {
  int nLengthMax = min(pCC->nRXLength,1024-m_nComLength);
  memcpy(m_pComBuffer+m_nComLength,pCC->pRXData,nLengthMax);
  m_nComLength += nLengthMax;
 }
 pCC->bNextUnitSend = FALSE;
 pCC->bNextUnitReceive = TRUE;
 if(m_nComLength==0) return;
 ComErrorType ComError = CheckComData();
 if(ComError==CET_NOTMYDATA)
 {
  m_nComLength = 0;
  return;
 }
 else if(ComError==CET_MAYBEMYDATA) return;
 if(ComError==CET_TIMEOUT)
 {
  if(m_bWaitReceive)
  {
   if(clock()-m_clockCom<3000)
   {
    m_ComError = CET_NOERROR;
    return;
   }
  }
  else
  {
   m_bWaitReceive = TRUE;
   m_clockCom = clock();
   return;
  }
 }
 m_bWaitReceive = FALSE;
 if(ComError==CET_NOERROR)
 {
  ReceiveHandler(pCC);
  m_ComError = CET_NOERROR;
 }
 else
 {
  OnReceiveError();
  SetComAlarm(ComError);
 }#p#分页标题#e#
 m_nComLength = 0;
}
//---------------------------------------------- myCPPUnit ----------
IMPLEMENT_SERIAL(myCPPUnit, myCUnit, 0)
myCPPUnit::myCPPUnit():myCUnit()
{
 m_nHeadLength = 1;
}
void myCPPUnit::SendComData(COMCONTROL* pCC)
{
 pCC->bNextUnitReceive = FALSE;
 pCC->bNextUnitSend = FALSE;
 SendHandler(pCC);
 pCC->bSendDelay = FALSE;
}
void myCPPUnit::ReceiveComData(COMCONTROL* pCC)
{
 // 拼装接收到的数据;
 if(pCC->nRXLength)
 {
  int nLengthMax = min(pCC->nRXLength,1024-m_nComLength);
  memcpy(m_pComBuffer+m_nComLength,pCC->pRXData,nLengthMax);
  m_nComLength += nLengthMax;
 }
 pCC->bNextUnitSend = FALSE;
 pCC->bNextUnitReceive = FALSE;
 TrimHead();
 if(m_nComLength<m_nHeadLength) return;
 ComErrorType ComError = CheckComData();
 if(ComError==CET_MAYBEMYDATA) return;
 if(ComError==CET_TIMEOUT)
 {
  if(m_bWaitReceive)
  {
   if(clock()-m_clockCom<3000)
   {
    m_ComError = CET_NOERROR;
    return;
   }
  }
  else
  {
   m_bWaitReceive = TRUE;
   m_clockCom = clock();
   return;
  }
 }
 m_bWaitReceive = FALSE;
 if(ComError==CET_NOERROR)
 {
  ReceiveHandler(pCC);
  m_ComError = CET_NOERROR;
 }
 else
 {
  OnReceiveError();
  SetComAlarm(ComError);
 }
 m_nComLength -= m_nHeadLength;
if(m_nComLength) memmove(m_pComBuffer,m_pComBuffer+m_nHeadLength,m_nComLength);
}
UNITDLG.H
#if !defined(AFX_UNITDLG_H__1FC3D582_1F8E_11D1_A31C_80E004C10000__INCLUDED_)
#define AFX_UNITDLG_H__1FC3D582_1F8E_11D1_A31C_80E004C10000__INCLUDED_
#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
// UnitDlg.h : header file
/////////////////////////////////////////////////////////////////////////////
// CUnitAttribPage dialog
class CUnitAttribPage : public CPropertyPage
{
 DECLARE_DYNCREATE(CUnitAttribPage)
// Construction
public:
 CUnitAttribPage();
 ~CUnitAttribPage();
// Dialog Data
 //{{AFX_DATA(CUnitAttribPage)
 enum { IDD = IDD_ATTRIB_UNIT };
 BYTE m_Address;
 CString m_strName;
 BOOL m_bUsed;
 CString m_strDefName;
 //}}AFX_DATA
// Overrides#p#分页标题#e#
 // ClassWizard generate virtual function overrides
 //{{AFX_VIRTUAL(CUnitAttribPage)
 protected:
 virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
 //}}AFX_VIRTUAL
// Implementation
protected:
 // Generated message map functions
 //{{AFX_MSG(CUnitAttribPage)
 //}}AFX_MSG
 DECLARE_MESSAGE_MAP()
};
/////////////////////////////////////////////////////////////////////////////
// CAnalogPage dialog
class CAnalogPage : public CPropertyPage
{
 DECLARE_DYNCREATE(CAnalogPage)
// Construction
public:
 myCAnalogArray m_analogs;
 int m_nCurSel;
 BOOL GetDataOk(void);
 CAnalogPage();
 ~CAnalogPage();
// Dialog Data
 //{{AFX_DATA(CAnalogPage)
 enum { IDD = IDD_MEMBER_ANALOG };
 float m_fA0;
 float m_fA1;
 float m_fHigh;
 float m_fLow;
 float m_fMax;
 float m_fMin;
 CString m_strName;
 float m_fThreshold;
 CString m_strUnitage;
 int  m_Format;
 BOOL m_bEvent;
 BOOL m_bSaveData;
 //}}AFX_DATA
// Overrides
 // ClassWizard generate virtual function overrides
 //{{AFX_VIRTUAL(CAnalogPage)
 public:
 virtual BOOL OnKillActive();
 protected:
 virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
 //}}AFX_VIRTUAL
// Implementation
protected:
 // Generated message map functions
 //{{AFX_MSG(CAnalogPage)
 virtual BOOL OnInitDialog();
 afx_msg void OnSelchangeList();
 afx_msg void OnChangeName();
 //}}AFX_MSG
 DECLARE_MESSAGE_MAP()
};
/////////////////////////////////////////////////////////////////////////////
// CAccumulatePage dialog
class CAccumulatePage : public CPropertyPage
{
 DECLARE_DYNCREATE(CAccumulatePage)
// Construction
public:
 myCAccumulateArray m_accumulates;
 int m_nCurSel;
 BOOL GetDataOk(void);
 CAccumulatePage();
 ~CAccumulatePage();
// Dialog Data
 //{{AFX_DATA(CAccumulatePage)
 enum { IDD = IDD_MEMBER_ACCUMULATE };
 float m_fA0;
 float m_fA1;
 CString m_strName;
 float m_fOver;
 int  m_Format;
 CString m_strUnitage;
 BOOL m_bSaveData;
 //}}AFX_DATA
// Overrides
 // ClassWizard generate virtual function overrides
 //{{AFX_VIRTUAL(CAccumulatePage)
 public:
 virtual BOOL OnKillActive();#p#分页标题#e#
 protected:
 virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
 //}}AFX_VIRTUAL
// Implementation
protected:
 // Generated message map functions
 //{{AFX_MSG(CAccumulatePage)
 virtual BOOL OnInitDialog();
 afx_msg void OnSelchangeList();
 afx_msg void OnChangeName();
 //}}AFX_MSG
 DECLARE_MESSAGE_MAP()
};
/////////////////////////////////////////////////////////////////////////////
// CDigitalPage dialog
class CDigitalPage : public CPropertyPage
{
 DECLARE_DYNCREATE(CDigitalPage)
// Construction
public:
 myCDigitalArray m_digitals;
 int m_nCurSel;
 BOOL GetDataOk(void);
 CDigitalPage();
 ~CDigitalPage();
// Dialog Data
 //{{AFX_DATA(CDigitalPage)
 enum { IDD = IDD_MEMBER_DIGITAL };
 CString m_strName;
 CString m_strStatus0;
 CString m_strStatus1;
 BOOL m_bInvert;
 BOOL m_bEvent;
 BOOL m_bSaveData;
 //}}AFX_DATA
// Overrides
 // ClassWizard generate virtual function overrides
 //{{AFX_VIRTUAL(CDigitalPage)
 public:
 virtual BOOL OnKillActive();
 protected:
 virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
 //}}AFX_VIRTUAL
// Implementation
protected:
 // Generated message map functions
 //{{AFX_MSG(CDigitalPage)
 virtual BOOL OnInitDialog();
 afx_msg void OnSelchangeList();
 afx_msg void OnChangeName();
 //}}AFX_MSG
 DECLARE_MESSAGE_MAP()
};
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// COperatePage dialog
class COperatePage : public CPropertyPage
{
 DECLARE_DYNCREATE(COperatePage)
// Construction
public:
 myCOperateArray m_operates;
 int m_nCurSel;
 BOOL GetDataOk(void);
 COperatePage();
 ~COperatePage();
// Dialog Data
 //{{AFX_DATA(COperatePage)
 enum { IDD = IDD_MEMBER_OPERATE };
 CString m_strName;
 CString m_strOperate0;
 CString m_strOperate1;
 //}}AFX_DATA
// Overrides
 // ClassWizard generate virtual function overrides
 //{{AFX_VIRTUAL(COperatePage)
 public:
 virtual BOOL OnKillActive();
 protected:
 virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
 //}}AFX_VIRTUAL
// Implementation
protected:#p#分页标题#e#
 // Generated message map functions
 //{{AFX_MSG(COperatePage)
 virtual BOOL OnInitDialog();
 afx_msg void OnSelchangeList();
 afx_msg void OnChangeName();
 //}}AFX_MSG
 DECLARE_MESSAGE_MAP()
};
/////////////////////////////////////////////////////////////////////////////
// CSimpleDataPage dialog
class CSimpleDataPage : public CPropertyPage
{
 DECLARE_DYNCREATE(CSimpleDataPage)
// Construction
public:
 myCSimpleDataArray m_simpledatas;
 int m_nCurSel;
 BOOL GetDataOk(void);
 CSimpleDataPage();
 ~CSimpleDataPage();
// Dialog Data
 //{{AFX_DATA(CSimpleDataPage)
 enum { IDD = IDD_MEMBER_SIMPLEDATA };
 float m_fA0;
 float m_fA1;
 int  m_Format;
 CString m_strName;
 CString m_strUnitage;
 //}}AFX_DATA
// Overrides
 // ClassWizard generate virtual function overrides
 //{{AFX_VIRTUAL(CSimpleDataPage)
 public:
 virtual BOOL OnKillActive();
 protected:
 virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
 //}}AFX_VIRTUAL
// Implementation
protected:
 // Generated message map functions
 //{{AFX_MSG(CSimpleDataPage)
 virtual BOOL OnInitDialog();
 afx_msg void OnSelchangeList();
 afx_msg void OnChangeName();
 //}}AFX_MSG
 DECLARE_MESSAGE_MAP()
};
/////////////////////////////////////////////////////////////////////////////
// CSOEPage dialog
class CSOEPage : public CPropertyPage
{
 DECLARE_DYNCREATE(CSOEPage)
// Construction
public:
 myCSOEArray m_soes;
 int m_nCurSel;
 BOOL GetDataOk(void);
 CSOEPage();
 ~CSOEPage();
// Dialog Data
 //{{AFX_DATA(CSOEPage)
 enum { IDD = IDD_MEMBER_SOE };
 CString m_strName;
 CString m_strSOE0;
 CString m_strSOE1;
 CString m_strEventType;
 //}}AFX_DATA
// Overrides
 // ClassWizard generate virtual function overrides
 //{{AFX_VIRTUAL(CSOEPage)
 public:
 virtual BOOL OnKillActive();
 protected:
 virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
 //}}AFX_VIRTUAL
// Implementation
protected:
 // Generated message map functions
 //{{AFX_MSG(CSOEPage)
 virtual BOOL OnInitDialog();
 afx_msg void OnSelchangeList();
 afx_msg void OnChangeName();
 //}}AFX_MSG
 DECLARE_MESSAGE_MAP()
};
//{{AFX_INSERT_LOCATION}}#p#分页标题#e#
// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_UNITDLG_H__1FC3D582_1F8E_11D1_A31C_80E004C10000__INCLUDED_)
UNITDLG.CPP
// UnitDlg.cpp : implementation file
#include "stdafx.h"
#include "Public.h"
#include "resource.h"
#include "UnitDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CUnitAttribPage property page
IMPLEMENT_DYNCREATE(CUnitAttribPage, CPropertyPage)
CUnitAttribPage::CUnitAttribPage() : CPropertyPage(CUnitAttribPage::IDD)
{
 //{{AFX_DATA_INIT(CUnitAttribPage)
 m_Address = 0;
 m_strName = _T("");
 m_bUsed = FALSE;
 m_strDefName = _T("");
 //}}AFX_DATA_INIT
}
CUnitAttribPage::~CUnitAttribPage()
{
}
void CUnitAttribPage::DoDataExchange(CDataExchange* pDX)
{
 CPropertyPage::DoDataExchange(pDX);
 //{{AFX_DATA_MAP(CUnitAttribPage)
 DDX_Text(pDX, IDC_ADDRESS, m_Address);
 DDX_Text(pDX, IDC_NAME, m_strName);
 DDX_Check(pDX, IDC_USED, m_bUsed);
 DDX_Text(pDX, IDC_TYPE, m_strDefName);
 //}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CUnitAttribPage, CPropertyPage)
 //{{AFX_MSG_MAP(CUnitAttribPage)
 //}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CUnitAttribPage message handlers
/////////////////////////////////////////////////////////////////////////////
// CAnalogPage property page
IMPLEMENT_DYNCREATE(CAnalogPage, CPropertyPage)
CAnalogPage::CAnalogPage() : CPropertyPage(CAnalogPage::IDD)
{
 //{{AFX_DATA_INIT(CAnalogPage)
 m_fA0 = 0.0f;
 m_fA1 = 0.0f;
 m_fHigh = 0.0f;
 m_fLow = 0.0f;
 m_fMax = 0.0f;
 m_fMin = 0.0f;
 m_strName = _T("");
 m_fThreshold = 0.0f;
 m_strUnitage = _T("");
 m_Format = -1;
 m_bEvent = FALSE;
 m_bSaveData = FALSE;
 //}}AFX_DATA_INIT
}
CAnalogPage::~CAnalogPage()
{
}
void CAnalogPage::DoDataExchange(CDataExchange* pDX)
{
 CPropertyPage::DoDataExchange(pDX);
 //{{AFX_DATA_MAP(CAnalogPage)
 DDX_Text(pDX, IDC_A0, m_fA0);
 DDX_Text(pDX, IDC_A1, m_fA1);
 DDX_Text(pDX, IDC_HIGH, m_fHigh);
 DDX_Text(pDX, IDC_LOW, m_fLow);
 DDX_Text(pDX, IDC_MAX, m_fMax);
 DDX_Text(pDX, IDC_MIN, m_fMin);
 DDX_Text(pDX, IDC_NAME, m_strName);
 DDX_Text(pDX, IDC_THRESHOLD, m_fThreshold);#p#分页标题#e#
 DDX_Text(pDX, IDC_UNITAGE, m_strUnitage);
 DDX_CBIndex(pDX, IDC_FORMAT, m_Format);
 DDX_Check(pDX, IDC_EVENT, m_bEvent);
 DDX_Check(pDX, IDC_SAVEDATA, m_bSaveData);
 //}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CAnalogPage, CPropertyPage)
 //{{AFX_MSG_MAP(CAnalogPage)
 ON_LBN_SELCHANGE(IDC_LIST, OnSelchangeList)
 ON_EN_CHANGE(IDC_NAME, OnChangeName)
 //}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CAnalogPage message handlers
BOOL CAnalogPage::OnInitDialog()
{
 CPropertyPage::OnInitDialog();
 // TODO: Add extra initialization here
 CListBox *pListBox = (CListBox *)GetDlgItem(IDC_LIST);
 int nSize = m_analogs.GetSize();
 for(int i=0;i<nSize;i++)
 {
  CString strTemp = m_analogs[i]->GetFieldAndName();
  pListBox->AddString(strTemp);
 }
 m_nCurSel = -1;
 pListBox->SetCurSel(0);
 OnSelchangeList();
 return TRUE;  // return TRUE unless you set the focus to a control
               // EXCEPTION: OCX Property Pages should return FALSE
}
void CAnalogPage::OnSelchangeList()
{
 // TODO: Add your control notification handler code here
 CListBox *pListBox = (CListBox *)GetDlgItem(IDC_LIST);
 BOOL bOk = TRUE;
 if(m_nCurSel>=0) bOk = GetDataOk();
 if(bOk)
 {
  int nTempCurSel = pListBox->GetCurSel();
  if(nTempCurSel!=LB_ERR)
  {
   m_nCurSel = nTempCurSel;
   m_strName = m_analogs[m_nCurSel]->m_strName;
   m_fMin = m_analogs[m_nCurSel]->m_fMin;  
   m_fMax = m_analogs[m_nCurSel]->m_fMax;
   m_fHigh = m_analogs[m_nCurSel]->m_fHigh;
   m_fLow = m_analogs[m_nCurSel]->m_fLow;
   m_strUnitage = m_analogs[m_nCurSel]->m_strUnitage;
   m_Format = m_analogs[m_nCurSel]->m_Format;
   m_fThreshold = m_analogs[m_nCurSel]->m_fThreshold;
   m_fA0 = m_analogs[m_nCurSel]->m_fA0;
   m_fA1 = m_analogs[m_nCurSel]->m_fA1;
   m_bEvent = m_analogs[m_nCurSel]->m_bEvent;
   m_bSaveData = m_analogs[m_nCurSel]->m_bSaveData;
   UpdateData(FALSE);
  }
  else pListBox->SetCurSel(m_nCurSel);
 }
}
BOOL CAnalogPage::GetDataOk(void)
{
 UpdateData(TRUE);
 if (m_fMin<=m_fLow && m_fLow<=m_fHigh && m_fHigh<=m_fMax)#p#分页标题#e#
 {
  m_analogs[m_nCurSel]->m_strName = m_strName;
  m_analogs[m_nCurSel]->m_fMin = m_fMin;
  m_analogs[m_nCurSel]->m_fMax = m_fMax;
  m_analogs[m_nCurSel]->m_fLow = m_fLow;
  m_analogs[m_nCurSel]->m_fHigh = m_fHigh;
  m_analogs[m_nCurSel]->m_strUnitage = m_strUnitage;
  m_analogs[m_nCurSel]->m_Format = m_Format;
  m_analogs[m_nCurSel]->m_fThreshold = m_fThreshold;
  m_analogs[m_nCurSel]->m_fA0 = m_fA0;
  m_analogs[m_nCurSel]->m_fA1 = m_fA1;
  m_analogs[m_nCurSel]->m_bEvent = m_bEvent;
  m_analogs[m_nCurSel]->m_bSaveData = m_bSaveData;
  return TRUE;
 }
 else
 {
  CListBox *pListBox = (CListBox *)GetDlgItem(IDC_LIST);
  pListBox->SetCurSel(m_nCurSel);
  MessageBox("从上到下各数据必须递减!","提示",MB_OK|MB_ICONWARNING);
  return FALSE;
 }
 return FALSE;
}
BOOL CAnalogPage::OnKillActive()
{
 // TODO: Add your specialized code here and/or call the base class
 return GetDataOk();
//return CPropertyPage::OnKillActive();
}
void CAnalogPage::OnChangeName()
{
 // TODO: If this is a RICHEDIT control, the control will not
 // send this notification unless you override the CPropertyPage::OnInitDialog()
 // function to send the EM_SETEVENTMASK message to the control
 // with the ENM_CHANGE flag ORed into the lParam mask.
 // TODO: Add your control notification handler code here
 UpdateData(TRUE);
 CListBox* pListBox = (CListBox*)GetDlgItem(IDC_LIST);
 pListBox->DeleteString(m_nCurSel);
 m_analogs[m_nCurSel]->m_strName = m_strName;
 pListBox->InsertString(m_nCurSel,m_analogs[m_nCurSel]->GetFieldAndName());
 pListBox->SetCurSel(m_nCurSel);
}
/////////////////////////////////////////////////////////////////////////////
// CAccumulatePage property page
IMPLEMENT_DYNCREATE(CAccumulatePage, CPropertyPage)
CAccumulatePage::CAccumulatePage() : CPropertyPage(CAccumulatePage::IDD)
{
 //{{AFX_DATA_INIT(CAccumulatePage)
 m_fA0 = 0.0f;
 m_fA1 = 0.0f;
 m_strName = _T("");
 m_fOver = 0.0f;
 m_Format = -1;
 m_strUnitage = _T("");
 m_bSaveData = FALSE;
 //}}AFX_DATA_INIT
}
CAccumulatePage::~CAccumulatePage()
{
}
void CAccumulatePage::DoDataExchange(CDataExchange* pDX)
{
 CPropertyPage::DoDataExchange(pDX);
 //{{AFX_DATA_MAP(CAccumulatePage)
 DDX_Text(pDX, IDC_A0, m_fA0);#p#分页标题#e#
 DDX_Text(pDX, IDC_A1, m_fA1);
 DDX_Text(pDX, IDC_NAME, m_strName);
 DDX_Text(pDX, IDC_OVER, m_fOver);
 DDX_CBIndex(pDX, IDC_FORMAT, m_Format);
 DDX_CBString(pDX, IDC_UNITAGE, m_strUnitage);
 DDX_Check(pDX, IDC_SAVEDATA, m_bSaveData);
 //}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CAccumulatePage, CPropertyPage)
 //{{AFX_MSG_MAP(CAccumulatePage)
 ON_LBN_SELCHANGE(IDC_LIST, OnSelchangeList)
 ON_EN_CHANGE(IDC_NAME, OnChangeName)
 //}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CAccumulatePage message handlers
BOOL CAccumulatePage::OnInitDialog()
{
 CPropertyPage::OnInitDialog();
 // TODO: Add extra initialization here
 CListBox *pListBox = (CListBox *)GetDlgItem(IDC_LIST);
 int nSize = m_accumulates.GetSize();
 for(int i=0;i<nSize;i++)
 {
  CString strTemp = m_accumulates[i]->GetFieldAndName();
  pListBox->AddString(strTemp);
 }
 m_nCurSel = -1;
 pListBox->SetCurSel(0);
 OnSelchangeList();
 return TRUE;  // return TRUE unless you set the focus to a control
               // EXCEPTION: OCX Property Pages should return FALSE
}
void CAccumulatePage::OnSelchangeList()
{
 // TODO: Add your control notification handler code here
 CListBox *pListBox = (CListBox *)GetDlgItem(IDC_LIST);
 BOOL bOk = TRUE;
 if(m_nCurSel>=0) bOk = GetDataOk();
 if(bOk)
 {
  int nTempCurSel = pListBox->GetCurSel();
  if(nTempCurSel!=LB_ERR)
  {
   m_nCurSel = nTempCurSel;
   m_strName = m_accumulates[m_nCurSel]->m_strName;
   m_strUnitage = m_accumulates[m_nCurSel]->m_strUnitage;
   m_Format = m_accumulates[m_nCurSel]->m_Format;
   m_fA0 = m_accumulates[m_nCurSel]->m_fA0;
   m_fA1 = m_accumulates[m_nCurSel]->m_fA1;
   m_fOver = m_accumulates[m_nCurSel]->m_fOver;
   m_bSaveData = m_accumulates[m_nCurSel]->m_bSaveData;
   UpdateData(FALSE);
  }
  else pListBox->SetCurSel(m_nCurSel);
 }
}
BOOL CAccumulatePage::GetDataOk(void)
{
 UpdateData(TRUE);
 m_accumulates[m_nCurSel]->m_strName = m_strName;
 m_accumulates[m_nCurSel]->m_strUnitage = m_strUnitage;
 m_accumulates[m_nCurSel]->m_Format = m_Format;
 m_accumulates[m_nCurSel]->m_fA0 = m_fA0;
 m_accumulates[m_nCurSel]->m_fA1 = m_fA1;#p#分页标题#e#
 m_accumulates[m_nCurSel]->m_fOver = m_fOver;
 m_accumulates[m_nCurSel]->m_bSaveData = m_bSaveData;
 return TRUE;
}
BOOL CAccumulatePage::OnKillActive()
{
 // TODO: Add your specialized code here and/or call the base class
 return GetDataOk(); 
// return CPropertyPage::OnKillActive();
}
void CAccumulatePage::OnChangeName()
{
 // TODO: If this is a RICHEDIT control, the control will not
 // send this notification unless you override the CPropertyPage::OnInitDialog()
 // function to send the EM_SETEVENTMASK message to the control
 // with the ENM_CHANGE flag ORed into the lParam mask.
 
 // TODO: Add your control notification handler code here
 UpdateData(TRUE);
 CListBox* pListBox = (CListBox*)GetDlgItem(IDC_LIST);
 pListBox->DeleteString(m_nCurSel);
 m_accumulates[m_nCurSel]->m_strName = m_strName;
 pListBox->InsertString(m_nCurSel,m_accumulates[m_nCurSel]->GetFieldAndName());
 pListBox->SetCurSel(m_nCurSel);
}
/////////////////////////////////////////////////////////////////////////////
// CDigitalPage property page
IMPLEMENT_DYNCREATE(CDigitalPage, CPropertyPage)
CDigitalPage::CDigitalPage() : CPropertyPage(CDigitalPage::IDD)
{
 //{{AFX_DATA_INIT(CDigitalPage)
 m_strName = _T("");
 m_strStatus0 = _T("");
 m_strStatus1 = _T("");
 m_bInvert = FALSE;
 m_bEvent = FALSE;
 m_bSaveData = FALSE;
 //}}AFX_DATA_INIT
}
CDigitalPage::~CDigitalPage()
{
}
void CDigitalPage::DoDataExchange(CDataExchange* pDX)
{
 CPropertyPage::DoDataExchange(pDX);
 //{{AFX_DATA_MAP(CDigitalPage)
 DDX_Text(pDX, IDC_NAME, m_strName);
 DDX_Text(pDX, IDC_STATUS0, m_strStatus0);
 DDX_Text(pDX, IDC_STATUS1, m_strStatus1);
 DDX_Check(pDX, IDC_INVERT, m_bInvert);
 DDX_Check(pDX, IDC_EVENT, m_bEvent);
 DDX_Check(pDX, IDC_SAVEDATA, m_bSaveData);
 //}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CDigitalPage, CPropertyPage)
 //{{AFX_MSG_MAP(CDigitalPage)
 ON_LBN_SELCHANGE(IDC_LIST, OnSelchangeList)
 ON_EN_CHANGE(IDC_NAME, OnChangeName)
 //}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CDigitalPage message handlers
BOOL CDigitalPage::OnInitDialog()
{
 CPropertyPage::OnInitDialog();
 
 // TODO: Add extra initialization here
 CListBox *pListBox = (CListBox *)GetDlgItem(IDC_LIST);
 int nSize = m_digitals.GetSize();
 for(int i=0;i<nSize;i++)
 {#p#分页标题#e#
  CString strTemp = m_digitals[i]->GetFieldAndName();
  pListBox->AddString(strTemp);
 }
 m_nCurSel = -1;
 pListBox->SetCurSel(0);
 OnSelchangeList();
 return TRUE;  // return TRUE unless you set the focus to a control
               // EXCEPTION: OCX Property Pages should return FALSE
}
void CDigitalPage::OnSelchangeList()
{
 // TODO: Add your control notification handler code here
 CListBox *pListBox = (CListBox *)GetDlgItem(IDC_LIST);
 BOOL bOk = TRUE;
 if(m_nCurSel>=0) bOk = GetDataOk();
 if(bOk)
 {
  int nTempCurSel = pListBox->GetCurSel();
  if(nTempCurSel!=LB_ERR)
  {
   m_nCurSel = nTempCurSel;
   m_strName = m_digitals[m_nCurSel]->m_strName;
   m_strStatus0 = m_digitals[m_nCurSel]->m_strStatus0;
   m_strStatus1 = m_digitals[m_nCurSel]->m_strStatus1;
   m_bInvert = m_digitals[m_nCurSel]->m_bInvert;
   m_bEvent = m_digitals[m_nCurSel]->m_bEvent;
   m_bSaveData = m_digitals[m_nCurSel]->m_bSaveData;
   UpdateData(FALSE);
  }
  else pListBox->SetCurSel(m_nCurSel);
 }
}
BOOL CDigitalPage::GetDataOk(void)
{
 UpdateData(TRUE);
 m_digitals[m_nCurSel]->m_strName = m_strName;
 m_digitals[m_nCurSel]->m_strStatus0= m_strStatus0;
 m_digitals[m_nCurSel]->m_strStatus1= m_strStatus1;
 m_digitals[m_nCurSel]->m_bInvert = m_bInvert;
 m_digitals[m_nCurSel]->m_bEvent = m_bEvent;
 m_digitals[m_nCurSel]->m_bSaveData = m_bSaveData;
 return TRUE;
}
BOOL CDigitalPage::OnKillActive()
{
 // TODO: Add your specialized code here and/or call the base class
 return GetDataOk(); 
// return CPropertyPage::OnKillActive();
}
void CDigitalPage::OnChangeName()
{
 // TODO: If this is a RICHEDIT control, the control will not
 // send this notification unless you override the CPropertyPage::OnInitDialog()
 // function to send the EM_SETEVENTMASK message to the control
 // with the ENM_CHANGE flag ORed into the lParam mask.
 // TODO: Add your control notification handler code here
 UpdateData(TRUE);
 CListBox* pListBox = (CListBox*)GetDlgItem(IDC_LIST);
 pListBox->DeleteString(m_nCurSel);
 m_digitals[m_nCurSel]->m_strName = m_strName;
 pListBox->InsertString(m_nCurSel,m_digitals[m_nCurSel]->GetFieldAndName());
 pListBox->SetCurSel(m_nCurSel);#p#分页标题#e#
}
/////////////////////////////////////////////////////////////////////////////
// COperatePage property page
IMPLEMENT_DYNCREATE(COperatePage, CPropertyPage)
COperatePage::COperatePage() : CPropertyPage(COperatePage::IDD)
{
 //{{AFX_DATA_INIT(COperatePage)
 m_strName = _T("");
 m_strOperate0 = _T("");
 m_strOperate1 = _T("");
 //}}AFX_DATA_INIT
}
COperatePage::~COperatePage()
{
}
void COperatePage::DoDataExchange(CDataExchange* pDX)
{
 CPropertyPage::DoDataExchange(pDX);
 //{{AFX_DATA_MAP(COperatePage)
 DDX_Text(pDX, IDC_NAME, m_strName);
 DDX_Text(pDX, IDC_OPERATE0, m_strOperate0);
 DDX_Text(pDX, IDC_OPERATE1, m_strOperate1);
 //}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(COperatePage, CPropertyPage)
 //{{AFX_MSG_MAP(COperatePage)
 ON_LBN_SELCHANGE(IDC_LIST, OnSelchangeList)
 ON_EN_CHANGE(IDC_NAME, OnChangeName)
 //}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// COperatePage message handlers
BOOL COperatePage::OnInitDialog()
{
 CPropertyPage::OnInitDialog();
 
 // TODO: Add extra initialization here
 CListBox *pListBox = (CListBox *)GetDlgItem(IDC_LIST);
 int nSize = m_operates.GetSize();
 for(int i=0;i<nSize;i++)
 {
  CString strTemp = m_operates[i]->GetFieldAndName();
  pListBox->AddString(strTemp);
 }
 m_nCurSel = -1;
 pListBox->SetCurSel(0);
 OnSelchangeList();
 return TRUE;  // return TRUE unless you set the focus to a control
               // EXCEPTION: OCX Property Pages should return FALSE
}
void COperatePage::OnSelchangeList()
{
 // TODO: Add your control notification handler code here
 CListBox *pListBox = (CListBox *)GetDlgItem(IDC_LIST);
 BOOL bOk = TRUE;
 if(m_nCurSel>=0) bOk = GetDataOk();
 if(bOk)
 {
  int nTempCurSel = pListBox->GetCurSel();
  if(nTempCurSel!=LB_ERR)
  {
   m_nCurSel = nTempCurSel;
   m_strName = m_operates[m_nCurSel]->m_strName;
   m_strOperate0 = m_operates[m_nCurSel]->m_strOperate0;
   m_strOperate1 = m_operates[m_nCurSel]->m_strOperate1;
   UpdateData(FALSE);
  }
  else pListBox->SetCurSel(m_nCurSel);
 }
}
BOOL COperatePage::GetDataOk(void)
{
 UpdateData(TRUE);
 m_operates[m_nCurSel]->m_strName = m_strName;#p#分页标题#e#
 m_operates[m_nCurSel]->m_strOperate0 = m_strOperate0;
 m_operates[m_nCurSel]->m_strOperate1 = m_strOperate1;
 return TRUE;
}
BOOL COperatePage::OnKillActive()
{
 // TODO: Add your specialized code here and/or call the base class
 return GetDataOk(); 
// return CPropertyPage::OnKillActive();
}
void COperatePage::OnChangeName()
{
 // TODO: If this is a RICHEDIT control, the control will not
 // send this notification unless you override the CPropertyPage::OnInitDialog()
 // function to send the EM_SETEVENTMASK message to the control
 // with the ENM_CHANGE flag ORed into the lParam mask.
 
 // TODO: Add your control notification handler code here
 UpdateData(TRUE);
 CListBox* pListBox = (CListBox*)GetDlgItem(IDC_LIST);
 pListBox->DeleteString(m_nCurSel);
 m_operates[m_nCurSel]->m_strName = m_strName;
 pListBox->InsertString(m_nCurSel,m_operates[m_nCurSel]->GetFieldAndName());
 pListBox->SetCurSel(m_nCurSel);
}
/////////////////////////////////////////////////////////////////////////////
// CSimpleDataPage property page
IMPLEMENT_DYNCREATE(CSimpleDataPage, CPropertyPage)
CSimpleDataPage::CSimpleDataPage() : CPropertyPage(CSimpleDataPage::IDD)
{
 //{{AFX_DATA_INIT(CSimpleDataPage)
 m_fA0 = 0.0f;
 m_fA1 = 0.0f;
 m_Format = -1;
 m_strName = _T("");
 m_strUnitage = _T("");
 //}}AFX_DATA_INIT
}
CSimpleDataPage::~CSimpleDataPage()
{
}
void CSimpleDataPage::DoDataExchange(CDataExchange* pDX)
{
 CPropertyPage::DoDataExchange(pDX);
 //{{AFX_DATA_MAP(CSimpleDataPage)
 DDX_Text(pDX, IDC_A0, m_fA0);
 DDX_Text(pDX, IDC_A1, m_fA1);
 DDX_CBIndex(pDX, IDC_FORMAT, m_Format);
 DDX_Text(pDX, IDC_NAME, m_strName);
 DDX_CBString(pDX, IDC_UNITAGE, m_strUnitage);
 //}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CSimpleDataPage, CPropertyPage)
 //{{AFX_MSG_MAP(CSimpleDataPage)
 ON_LBN_SELCHANGE(IDC_LIST, OnSelchangeList)
 ON_EN_CHANGE(IDC_NAME, OnChangeName)
 //}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CSimpleDataPage message handlers
BOOL CSimpleDataPage::OnInitDialog()
{
 CPropertyPage::OnInitDialog();
 
 // TODO: Add extra initialization here
 CListBox *pListBox = (CListBox *)GetDlgItem(IDC_LIST);
 int nSize = m_simpledatas.GetSize();
 for(int i=0;i<nSize;i++)
 {
  CString strTemp = m_simpledatas[i]->GetFieldAndName();
  pListBox->AddString(strTemp);#p#分页标题#e#
 }
 m_nCurSel = -1;
 pListBox->SetCurSel(0);
 OnSelchangeList();
 
 return TRUE;  // return TRUE unless you set the focus to a control
               // EXCEPTION: OCX Property Pages should return FALSE
}
void CSimpleDataPage::OnSelchangeList()
{
 // TODO: Add your control notification handler code here
 CListBox *pListBox = (CListBox *)GetDlgItem(IDC_LIST);
 BOOL bOk = TRUE;
 if(m_nCurSel>=0) bOk = GetDataOk();
 if(bOk)
 {
  int nTempCurSel = pListBox->GetCurSel();
  if(nTempCurSel!=LB_ERR)
  {
   m_nCurSel = nTempCurSel;
   m_strName = m_simpledatas[m_nCurSel]->m_strName;
   m_strUnitage= m_simpledatas[m_nCurSel]->m_strUnitage;
   m_Format = m_simpledatas[m_nCurSel]->m_Format;
   m_fA0  = m_simpledatas[m_nCurSel]->m_fA0;
   m_fA1  = m_simpledatas[m_nCurSel]->m_fA1;
   UpdateData(FALSE);
  }
  else pListBox->SetCurSel(m_nCurSel);
 }
}
BOOL CSimpleDataPage::GetDataOk(void)
{
 UpdateData(TRUE);
 m_simpledatas[m_nCurSel]->m_strName = m_strName;
 m_simpledatas[m_nCurSel]->m_strUnitage= m_strUnitage;
 m_simpledatas[m_nCurSel]->m_Format = m_Format;
 m_simpledatas[m_nCurSel]->m_fA0  = m_fA0;
 m_simpledatas[m_nCurSel]->m_fA1  = m_fA1;
 return TRUE;
}
BOOL CSimpleDataPage::OnKillActive()
{
 // TODO: Add your specialized code here and/or call the base class
 return GetDataOk();
// return CPropertyPage::OnKillActive();
}
void CSimpleDataPage::OnChangeName()
{
 // TODO: If this is a RICHEDIT control, the control will not
 // send this notification unless you override the CPropertyPage::OnInitDialog()
 // function to send the EM_SETEVENTMASK message to the control
 // with the ENM_CHANGE flag ORed into the lParam mask.
 
 // TODO: Add your control notification handler code here
 UpdateData(TRUE);
 CListBox* pListBox = (CListBox*)GetDlgItem(IDC_LIST);
 pListBox->DeleteString(m_nCurSel);
 m_simpledatas[m_nCurSel]->m_strName = m_strName;
 pListBox->InsertString(m_nCurSel,m_simpledatas[m_nCurSel]->GetFieldAndName());
 pListBox->SetCurSel(m_nCurSel);
}
/////////////////////////////////////////////////////////////////////////////
// CSOEPage property page
IMPLEMENT_DYNCREATE(CSOEPage, CPropertyPage)#p#分页标题#e#
CSOEPage::CSOEPage() : CPropertyPage(CSOEPage::IDD)
{
 //{{AFX_DATA_INIT(CSOEPage)
 m_strName = _T("");
 m_strSOE0 = _T("");
 m_strSOE1 = _T("");
 m_strEventType = _T("");
 //}}AFX_DATA_INIT
}
CSOEPage::~CSOEPage()
{
}
void CSOEPage::DoDataExchange(CDataExchange* pDX)
{
 CPropertyPage::DoDataExchange(pDX);
 //{{AFX_DATA_MAP(CSOEPage)
 DDX_Text(pDX, IDC_NAME, m_strName);
 DDX_Text(pDX, IDC_SOE0, m_strSOE0);
 DDX_Text(pDX, IDC_SOE1, m_strSOE1);
 DDX_CBString(pDX, IDC_EVENTTYPE, m_strEventType);
 //}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CSOEPage, CPropertyPage)
 //{{AFX_MSG_MAP(CSOEPage)
 ON_LBN_SELCHANGE(IDC_LIST, OnSelchangeList)
 ON_EN_CHANGE(IDC_NAME, OnChangeName)
 //}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CSOEPage message handlers
BOOL CSOEPage::OnInitDialog()
{
 CPropertyPage::OnInitDialog();
 
 // TODO: Add extra initialization here
 CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_EVENTTYPE);
 int nEventTypeSize = myCEventManager::eventSetupInfos.GetSize();
 for(int n=0;n<nEventTypeSize;n++)
 {
  pComboBox->AddString(myCEventManager::eventSetupInfos[n].strType);
 }
 CListBox* pListBox = (CListBox*)GetDlgItem(IDC_LIST);
 int nSize = m_soes.GetSize();
 for(int i=0;i<nSize;i++)
 {
  CString strTemp = m_soes[i]->GetFieldAndName();
  pListBox->AddString(strTemp);
 }
 m_nCurSel = -1;
 pListBox->SetCurSel(0);
 OnSelchangeList();
 
 return TRUE;  // return TRUE unless you set the focus to a control
               // EXCEPTION: OCX Property Pages should return FALSE
}
void CSOEPage::OnSelchangeList()
{
 // TODO: Add your control notification handler code here
 CListBox *pListBox = (CListBox *)GetDlgItem(IDC_LIST);
 BOOL bOk = TRUE;
 if(m_nCurSel>=0) bOk = GetDataOk();
 if(bOk)
 {
  int nTempCurSel = pListBox->GetCurSel();
  if(nTempCurSel!=LB_ERR)
  {
   m_nCurSel = nTempCurSel;
   m_strName = m_soes[m_nCurSel]->m_strName;
   m_strSOE0 = m_soes[m_nCurSel]->m_strSOE0;
   m_strSOE1 = m_soes[m_nCurSel]->m_strSOE1;
   m_strEventType = m_soes[m_nCurSel]->m_strEventType;
   UpdateData(FALSE);#p#分页标题#e#
  }
  else pListBox->SetCurSel(m_nCurSel);
 }
}
BOOL CSOEPage::GetDataOk(void)
{
 UpdateData(TRUE);
 m_soes[m_nCurSel]->m_strName = m_strName;
 m_soes[m_nCurSel]->m_strSOE0 = m_strSOE0;
 m_soes[m_nCurSel]->m_strSOE1 = m_strSOE1;
 m_soes[m_nCurSel]->m_strEventType = m_strEventType;
 return TRUE;
}
BOOL CSOEPage::OnKillActive()
{
 // TODO: Add your specialized code here and/or call the base class
 return GetDataOk();
// return CPropertyPage::OnKillActive();
}
void CSOEPage::OnChangeName()
{
 // TODO: If this is a RICHEDIT control, the control will not
 // send this notification unless you override the CPropertyPage::OnInitDialog()
 // function to send the EM_SETEVENTMASK message to the control
 // with the ENM_CHANGE flag ORed into the lParam mask.
 // TODO: Add your control notification handler code here
 UpdateData(TRUE);
 CListBox* pListBox = (CListBox*)GetDlgItem(IDC_LIST);
 pListBox->DeleteString(m_nCurSel);
 m_soes[m_nCurSel]->m_strName = m_strName;
 pListBox->InsertString(m_nCurSel,m_soes[m_nCurSel]->GetFieldAndName());
 pListBox->SetCurSel(m_nCurSel);
}
PUBLIC.H 文件
#include <afxwin.h>
#include <afxext.h>
#include <math.h>
#include <time.h>
#include <afxdao.h>
#include <afxtempl.h>
extern AFX_EXTENSION_MODULE PublicDLL;
#ifdef PUBLIC_IMPL
 #define MYDECLARE_PUBLIC _declspec(dllexport)
#else
 #define MYDECLARE_PUBLIC _declspec(dllimport)
#endif
#ifndef PUBLIC_H
#define PUBLIC_H
#include "Toolw.h"
#include "Variants.h"
#include "DataIO.h"
#include "Database.h"
#include "Member.h"
#include "Unit.h"
#include "Comport.h"
#include "Link.h"
#include "SelLink.h"
#include "Data.h"
#include "DrawObj.h"
#include "Picture.h"
#include "Monitor.h"
#include "TimeMng.h"
#include "EventMng.h"
#include "InfoMng.h"
#include "UnitsMng.h"
#include "CommandMng.h"
#include "ToolbarMng.h"
#include "AutopopMng.h"
#include "PasswordMng.h"
#include "YKYT.h"
#include "CtrlX.h"
#include "Control.h"
#endif
#define _SYSDIR   "\\system"
#define _CFGDIR   "\\system\\config"
#define _PICDIR   "#p#分页标题#e#\\system\\picture"
#define _BMPDIR   "\\system\\bitmap"
#define _SNDDIR   "\\system\\sound"
#define _DATADIR  "\\data"
#define _EVENTDIR  "\\event"
#define _FINDPICFILE  "\\system\\picture\\*.pic"
#define _FINDBMPFILE "\\system\\bitmap\\*.bmp"
#define _FINDSNDFILE "\\system\\sound\\*.wav"
#define _DLLTXT   "\\system\\config\\dll.txt"
#define _CAPTIONTXT "\\system\\config\\caption.txt"
#define _UNITSDAT  "\\system\\config\\units.dat"
#define _EVENTDAT  "\\system\\config\\event.dat"
#define _PASSWORDDAT "\\system\\config\\password.dat"
#define _COMMANDDAT "\\system\\config\\command.dat"
#define _TOOLBARDAT "\\system\\config\\toolbar.dat"
#define _AUTOPOPDAT "\\system\\config\\autopop.dat"
#define _INFODAT  "\\system\\config\\info.dat"
#define _YKYTDAT  "\\system\\config\\ykyt.dat"
#define _TEMPDAT  "\\data\\temp.dat"
extern MYDECLARE_PUBLIC BOOL bMainApp;   // 是否主控程序标志;
extern MYDECLARE_PUBLIC CString strSCADA;   // SCADA目录;
extern MYDECLARE_PUBLIC CString strAppCaption;  // 当前应用程序标题;
extern MYDECLARE_PUBLIC myCTimeManager*  pTimeManager;
extern MYDECLARE_PUBLIC myCInfoManager*  pInfoManager;
extern MYDECLARE_PUBLIC myCEventManager* pEventManager;
extern MYDECLARE_PUBLIC myCPasswordManager* pPasswordManager;
extern MYDECLARE_PUBLIC myCCommandManager* pCommandManager;
extern MYDECLARE_PUBLIC myCToolbarManager* pToolbarManager;
extern MYDECLARE_PUBLIC myCAutopopManager* pAutopopManager;
extern MYDECLARE_PUBLIC myCUnitsManager* pUnitsManager;
extern MYDECLARE_PUBLIC void CreateSystem(void);
extern MYDECLARE_PUBLIC void DestroySystem(void);
PUBLIC.CPP 文件#p#分页标题#e#
// Public.cpp : Defines the initialization routines for the DLL.
#include "stdafx.h"
#include <afxdllx.h>
#include <direct.h>
#include "Public.h"
BOOL bMainApp = FALSE;
CString strSCADA = "E:\\SCADA";
CString strAppCaption = "SCADA监控系统";
myCTimeManager*  pTimeManager = NULL;
myCInfoManager*  pInfoManager = NULL;
myCEventManager* pEventManager = NULL;
myCPasswordManager* pPasswordManager = NULL;
myCCommandManager* pCommandManager = NULL;
myCToolbarManager* pToolbarManager = NULL;
myCAutopopManager* pAutopopManager = NULL;
myCUnitsManager* pUnitsManager = NULL;
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
AFX_EXTENSION_MODULE PublicDLL = { NULL, NULL };
extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
 // Remove this if you use lpReserved
 UNREFERENCED_PARAMETER(lpReserved);
 if (dwReason == DLL_PROCESS_ATTACH)
 {
  TRACE0("PUBLIC.DLL Initializing!\n");
  
  // Extension DLL one-time initialization
  if (!AfxInitExtensionModule(PublicDLL, hInstance))
   return 0;
  // Insert this DLL into the resource chain
  // NOTE: If this Extension DLL is being implicitly linked to by
  //  an MFC Regular DLL (such as an ActiveX Control)
  //  instead of an MFC application, then you will want to
  //  remove this line from DllMain and put it in a separate
  //  function exported from this Extension DLL.  The Regular DLL
  //  that uses this Extension DLL should then explicitly call that
  //  function to initialize this Extension DLL.  Otherwise,
  //  the CDynLinkLibrary object will not be attached to the
  //  Regular DLL's resource chain, and serious problems will
  //  result.
  new CDynLinkLibrary(PublicDLL);
  myCComport::RegisterClass("普通串口",RUNTIME_CLASS(myCComX));
  myCComportMonitor::RegisterClass(RUNTIME_CLASS(myCComX),RUNTIME_CLASS(myCComportMonitor));
  myCEventManager::RegisterEvent("模拟量越限",RGB(255,0,255),RGB(255,255,255));
  myCEventManager::RegisterEvent("开关量变位",RGB(0,128,0),RGB(255,255,255));
  myCEventManager::RegisterEvent("SOE事件",RGB(128,0,0),RGB(255,255,255));
  myCEventManager::RegisterEvent("通信出错",RGB(255,255,0),RGB(0,0,0));
  myCEventManager::RegisterEvent("系统错误",RGB(0,0,0),RGB(255,255,0));#p#分页标题#e#
  myCEventManager::RegisterEvent("操作记录",RGB(255,255,255),RGB(0,0,0));
  myCEventManager::RegisterEvent("提示信息",RGB(0,255,255),RGB(0,0,0));
  myCDrawObj::RegisterClass("正交直线",RUNTIME_CLASS(myCDrawTLine));
  myCDrawObj::RegisterClass("斜直线",RUNTIME_CLASS(myCDrawXLine));
  myCDrawObj::RegisterClass("文本",RUNTIME_CLASS(myCDrawText));
  myCDrawObj::RegisterClass("矩形",RUNTIME_CLASS(myCDrawRect));
  myCDrawObj::RegisterClass("圆角矩形",RUNTIME_CLASS(myCDrawRound));
  myCDrawObj::RegisterClass("椭圆",RUNTIME_CLASS(myCDrawOval));
  myCDrawObj::RegisterClass("立体框",RUNTIME_CLASS(myCDraw3dRect));
  myCDrawObj::RegisterClass("圆弧",RUNTIME_CLASS(myCDrawArc));
  myCDrawObj::RegisterClass("圆弦",RUNTIME_CLASS(myCDrawChord));
  myCDrawObj::RegisterClass("扇形",RUNTIME_CLASS(myCDrawPie));
  myCDrawObj::RegisterClass("箭头",RUNTIME_CLASS(myCDrawArrow));
  myCDrawObj::RegisterClass("表格",RUNTIME_CLASS(myCDrawTable));
  myCDrawObj::RegisterClass("位图图像",RUNTIME_CLASS(myCDrawBitmap));
  myCDrawObj::RegisterClass("流向指示",RUNTIME_CLASS(myCDrawFlow));
  myCDrawObj::RegisterClass("指示灯",RUNTIME_CLASS(myCDrawLight));
  myCDrawObj::RegisterClass("实时数据框",RUNTIME_CLASS(myCDrawDatabox));
  myCDrawObj::RegisterClass("实时指针",RUNTIME_CLASS(myCDrawPointer));
  myCDrawObj::RegisterClass("实时曲线",RUNTIME_CLASS(myCDrawCurve));
  myCDrawObj::RegisterClass("实时棒图",RUNTIME_CLASS(myCDrawBar));
  myCDrawObj::RegisterClass("变量打印",RUNTIME_CLASS(myCDrawVarPrintOne));
  myCDrawObj::RegisterClass("变量组打印",RUNTIME_CLASS(myCDrawVarPrint));
  myCDrawObj::RegisterClass("变量组曲线",RUNTIME_CLASS(myCDrawVarCurve));
  myCDrawObj::RegisterClass("变量组棒图",RUNTIME_CLASS(myCDrawVarBar));
  myCDrawObj::RegisterClass("3d管道",RUNTIME_CLASS(myCDraw3dLine));
  myCDrawObj::RegisterClass("3d面板",RUNTIME_CLASS(myCDraw3dPanel));
  myCDrawObj::RegisterClass("3d球",RUNTIME_CLASS(myCDraw3dCircle));
  myCDrawObj::RegisterClass("3d孔",RUNTIME_CLASS(myCDraw3dHole));
 }
 else if (dwReason == DLL_PROCESS_DETACH)
 {
  TRACE0("PUBLIC.DLL Terminating!\n");
  // Terminate the library before destructors are called#p#分页标题#e#
  AfxTermExtensionModule(PublicDLL);
 }
 return 1;   // ok
}
void GetAppCaption(void)
{
 FILE* fp = fopen(strSCADA+_CAPTIONTXT,"rt");
 if(fp!=NULL)
 {
  char str[100];
  fgets(str,99,fp);
  strAppCaption = strtok(str,"\n");
  fclose(fp);
 }
}
static CPtrArray aInstance;
void LoadAllLibrary(void)
{
 aInstance.RemoveAll();
 CStdioFile file;
 if(file.Open(strSCADA+_DLLTXT,CFile::modeRead))
 {
  char str[100];
  while(file.ReadString(str,99)!=NULL)
  {
   CString strDllFile = strtok(str,"\n");
   if(strDllFile.IsEmpty()) continue;
   if(strDllFile.GetLength()>=2)
   {
    if(strDllFile.Left(2)=="//") continue;
   }
   HINSTANCE hInstance = AfxLoadLibrary(strDllFile);
   if(hInstance!=NULL) aInstance.Add(hInstance);
   else
   {
    CString strMessage;
    strMessage += "动态连接库文件";
    strMessage += strDllFile;
    strMessage += "无法装入!";
    myAbortSystem(strMessage);
   }
  }
 }
}
void FreeAllLibrary(void)
{
 int nSize = aInstance.GetSize();
 for(int i=0;i<nSize;i++)
 {
  HINSTANCE hInstance = (HINSTANCE)(aInstance[i]);
  AfxFreeLibrary(hInstance);
 }
}
void CreateSystem(void)
{
 strSCADA = getenv("SCADA");
 BOOL bOk = FALSE;
 if(strSCADA.CompareNoCase("C:\\SCADA")==0) bOk = TRUE;
 if(strSCADA.CompareNoCase("D:\\SCADA")==0) bOk = TRUE;
 if(strSCADA.CompareNoCase("E:\\SCADA")==0) bOk = TRUE;
 if(strSCADA.CompareNoCase("F:\\SCADA")==0) bOk = TRUE;
 if(strSCADA.CompareNoCase("G:\\SCADA")==0) bOk = TRUE;
 if(!bOk)
  strSCADA = "E:\\SCADA";
 GetAppCaption();
 _mkdir(strSCADA+_SYSDIR);
 _mkdir(strSCADA+_#p#分页标题#e#论文上海论文 www.zhonghualw.com整理提供CFGDIR);
 _mkdir(strSCADA+_PICDIR);
 _mkdir(strSCADA+_BMPDIR);
 _mkdir(strSCADA+_SNDDIR);
 _mkdir(strSCADA+_DATADIR);
 _mkdir(strSCADA+_EVENTDIR);
 LoadAllLibrary();
 pEventManager = new myCEventManager;
 pTimeManager = new myCTimeManager;
 pInfoManager = new myCInfoManager;
 pPasswordManager = new myCPasswordManager;
 pCommandManager = new myCCommandManager;
 pToolbarManager = new myCToolbarManager;
 pAutopopManager = new myCAutopopManager;
 pUnitsManager = new myCUnitsManager;
 myCYKYTUnit::LoadYKYTInfo();
}
void DestroySystem(void)
{
 if(pEventManager) delete pEventManager;
 if(pTimeManager) delete pTimeManager;
 if(pInfoManager) delete pInfoManager;
 if(pPasswordManager) delete pPasswordManager;
 if(pCommandManager) delete pCommandManager;
 if(pToolbarManager) delete pToolbarManager;
 if(pAutopopManager) delete pAutopopManager;
 if(pUnitsManager) delete pUnitsManager;
 FreeAllLibrary();
}

上海交通大学本科毕业论文#p#分页标题#e#

1,点击按钮复制下方QQ号!!
2,打开QQ >> 添加好友/群
3,粘贴QQ,完成添加!!