【VB开源代码栏目提醒】:文章导读:在新的一年中,各位网友都进入紧张的学习或是工作阶段。
网学会员整理了VB开源代码-测控软件算法的组件封装技术研究 - 学士论文的相关内容供大家参考,祝大家在新的一年里工作和学习顺利!
第19卷 第8期 电子设计工程 2011年4月 V01.19 No.8 Electronic Design Engineering Apr.2011 测控软件算法的组件封装技术研究 张荣,聂飞,黄海莹,蒋宇 (中国工程物理研究院总体工程研究所,四川绵阳621900) 摘要:基于Visual C++开发测控系统软件,为保护开发者的知识产权,也为程序高效稳定执行,提出了应用DLL与 COM技术将核心信号处理算法封装起来,作为独立的组件使用,只留下调用接口供开发者调用,算法细节对调用者 不可见。
详细讨论了VC编程环境下各类复杂DLL的封装与调用技术,掌握并应用这些技术,可设计出基于客户/服 务器模式的测控系统软件。
既使测控软件运行效率高,也使开发者的知识产权得到充分保护。
笔者在多个项目中使用 这些封装技术。
结果表明,测控系统运行稳定可靠,核心算法得到了有效保护。
关键词:测控软件;组件封装;VC++;DLL;COM 中图分类号:11P75l 文献标识码:A 文章编号:1674—6236(2011)08—0022104 Research of algorithm component packaging technique for test and control software ZHANG Rong,NIE Fei,HUANG Hal—ying,JIANG Yu (Institute of跏te腓Engineering,CAEP,Mimyang 621900,China) Abstract:For the protection of inteHectuM property of developers and highly efficient and stable implementation of the test and control system program which developed by Visual C*language.this article proposed using DLL and COM technique to package the core signal processing algorithms to be a separate component,leaving only calling interface for the developers, but the algorithm code details a托not visible for caller.Several types of complex DLL packaging and calling techniques under the VC programming environment weI-e discussed in detail,mastering and applying these techniques。
test and control system could be designed based on client/server,not only the control software running efficiency,but also the intellectual property rights of developers wero fully protected.I used these packaging techniques in multiple projects,the results show that the control system run stable and reliably,the eoro algorithms have been effectively protected. Key words:test and control software;component packaging;VC++:DLL;COM 拥有可视化界面的工程测控软件通常按照模块化面向 开发效率,将程序员从繁琐的底层
代码设计
工作中解脱出来。
对象的程序设计方法进行编制,往往将数据采集部分设计为 由于大多数的测试软件由VC++语言编制,因此本文主要一个功能模块包括底层硬件控制以及数据缓冲等,数据后处 讨论基于Visual C++语言的测试软件功能模块封装技术.这理设计为另一个大功能模块,数据后处理模块又可分为多个 些封装技术主要包括D叫1I封装和COM咐装技术。
测试软件算法模块,如F盯谱分析模块、IIR滤波模块以及消除噪声的 的所有功能模块都可以封装到DLL和COM中去。
应用程序数据预处理模块等,这些模块通过合理封装后成为组件并利 开发者利用
软件服务商提供的二次开发包或库文件,在应用用规定的接口与上层界面应用程序
通信,直接或间接的为主 程序中动态加载这些文件就可以实现相关的测试功能。
笔者程序提供服务。
为什么要对测试功能模块进行组件封装呢? 根据自己在测控系统软件开发工作中遇到的实际模块封装这是由现代软件
设计的理念决定的,该理念就是“服务”,此 问题和解决经验,总结了大量的封装技术,并给出了封装的 ’“服务”可以提供给任何需要该项测试功能的使用者,而使用 关键
代码。
者并不需要熟悉实现某项测试功能的
代码,只需知道其接口—— 1基于DLL技术封装标准即可。
Matlab就是典型的例子,它将很多测试算法进行合理封装。
用户并不需要知道底层实现
代码,熟悉接I=I就可 link library)在Windows系统中占有非常重 DLL(Dynamic实现相关的功能。
其次,由于测试软件的数据结构与处理算 要的地位。
是功能模块封装技术中最重要的技术。
它是一种法等核心
代码封装后对用户不可见,实现了加密处理.这可 进程内模块,应用程序执行时,DLL被动态加载进应用程序以维护软件开发商的知识产权。
另外,在“服务”的理念下,用 的全局地址空间。
与应用程序共享全局地址。
基于DLL的这户可将大部分精力应用在设计测试软件的人机界面上。
提高 个特点,通常应用DLL建立单机测试平台,这就是用户经常 应用开发商提供的二次开发包和库开发测试
系统的原因。
收稿日期:201l一叭一20 稿件编号:201101072作者简介:张荣(1979一),男。
四川资阳人,硕士,工程师。
研究方向:测试系统的软硬件应用研发等。
-22- 万方数据 张荣,等 测控软件算法的组件封装技术研究DLL是一种二进制
代码,它一经调试成功,任何开发语言只 改变变量值程序:Exp void Addx(){MyVar=-15000;l需遵循调用的接口规则即可调用它.如用VC++开发的DLL Exp void Setx(int x){MyArray〔1〕=x;}可被DELPHI、VB、JAVA等语言调用。
主应用程序全局变量声明:_declspec(dllimport)int MyVar,1.1 DLL封装的程序元素 MyArray〔3601;Imp void Addx(); Visual C++中DLL的种类分为:非MFC〔31动态库、MFC规 Imp void Setx(int x);则动态库以及MFC扩展动态库几类。
其中非MFC动态库内 主调用程序:void CEXElDl譬::0nOK()不含有MFC类库,其封装的元素按照标准的C接151调用; I int xdata,ydata;MFC规则库内必须含有继承于CWinApp的类。
且DLL内不 Addx();//MyVar=-15000;支持消息循环;而MFC扩展动态库只能由MFC类库编写的 xdata=MyVar;应用程序调用,因此应用受限。
通常测试软件设计过程中应 Setx(100);//MyArray〔1〕=100;用最为广泛的是非MFC(Non—MFC)动态库,该类型库可以封 ydata=MyArray〔1】;}装的程序元素很多.应用最为广泛的是对函数的封装、对全 这样在程序中就实现了MyV盯和MyArray的值传递。
但局变量和常量的封装、对对象以及类的封装以及一个DLL对 应注意DLL与主程序只能互传全局变量。
不能传递局部变另一个DIJL的封装,更为复杂的是对线程进行封装以及主程 量,因为局部变量离开DLL的作用域就不存在了。
常量的定序与DLL中实现消息传递的封装技术.这些库内元素的封装 义为:declspec(dllexport)extem const int key=5:主程序对常和导出均基于C语言接口,因此容易被其他开发语言调用。
量的调用方法与对变量调用方法一样。
灵活应用非MFC动态库封装技术可以解决大多数测试系统 1.4 DLL对类和及其对象的封装功能模块的封装问题。
DLL对类及其对象的封装主要应用于对测试数据的数据1.2 DLL对函数的封装 结构及处理方法封装。
用户可以在应用程序中导人该类并应 DLL封装函数是最为广泛的封装,也是较简单的封装方 用其public方法。
VC++DLL中类的封装格式:class_declspee式,在测试系统软件开发中,可以用封装核心数据处理算法。
(dllcxport)CDataClass{CDataClass();一CDataClass();publieint在VC++中。
函数的封装按下面的格式进行:在DLL的.h文 function(…);l件中声明导出的函数名:extem…C_declspec(dllexport) 主应用程序中导人CDataClass类的方法:class_declspecfunName(…)。
此extem…C’标识符表明函数funName的输出 (dllimport)CDamClass Object;下面是一个数据采集类遵循标准C语言调用。
其他语言在调用该函数时,只需要在 CSampleData的伪
代码:声明处加上“stdcall”符号就可以了,“dllexport”代表将该函数 class_declspee(dllexport)CSampleData{private.10ng fs;//a’采样频率将被导出到应用程序中。
比如封装一个采样频率为fs,运算 float ts://采样持续时间点数为N的F盯算法。
其声明格式可以为:extem…C private:CSampleData();,,类构造函数_declspec(dllexport)int Fl,r(float data〔】,int fs,int N);然后在. ~CSampleData();,,类析构函数cpp文件中编写FFfI’函数的具体执行
代码并编译为DLL文 public:件即可。
界面程序按照下列格式声明调用该函数:extem“C” int DataArray://采集到的数据_declspec(dllimport)int F盯(…);此处应用关键词“dllimport” int SetFS(){fs=mOOO】;//i雯置采样频率代表导入函数到应用程序中,之后可按照应用程序内的普通 int SetTS(){ts=10;},,设置采样持续时间函数一样进行函数调用。
int GetData(float xdata){DataArray=xdata;}1.3 DLL对全局变量和常量的封装 …;,,后续类接口函数l 全局变量、常量的封装主要解决主程序与DLL中变量值 主应用
程序声明一个CSampleDam对象Objects:的相互传递
问题。
当然可以在DLL中设计具有输人参数和返 _declspec (dllimport) CSampleData Objects =new回值的导出函数来实现传递,但是当需要传递的变量非常多 (CSampleData);时,应用函数封装来解决问题就比较受限。
VC++中,DLL中常 Objects.GetData(10);//存放采样数据量、变量的声明格式为:一declspec(dllexport)int VarName;应 这样就实现了对DLL对类的封装和引用。
用程序中对变量VarName的引用为:_declspec(dllimport)int 1.5 DLL对线程及其对象的封装VarName;下例定义一个MyVar和MyArray数组变量,并通过 DLL对多线程的封装情况应用得相对少些。
主要是因为传递其值
演示其调用方法。
DLL程序中全局变量声明方式: 其封装具有一定难度。
往往应用主程序为多线程程序,又需#define Exp extem“C”_declspec(dllexport); 要将多线程部分
代码整个封装进DLL内的情况。
原本在主程#define Imp extem“C”_declspec(dllimport); 序中应用线程对象对线程控制是比较容易的事情。
现在转移_declspec(dllexport)int MyVar,MyArray〔360】; 到DLL中来,就需要将线程对象传递进DLL,如果对象一旦Exp void Addx();Exp void Setx(int x); 传错,整个线程运行都将失败,笔者根据自己的摸索,总结出 -23- 万方数据 《电子设计工程)2011年第8期下列方法可实现线程封装:首先在DLL头文件内定义用于控 1.7 DLL中的消息传递与封装制线程起停的Cevent事件对象g_eventStart、g_eventKill以及 因为Windows应用程序都是基于消息处理机制,因此一个线程处理函数ThreadFun():#define EXP_declspec(dllexport) 完整的可视化测试程序应该支持消息处理,所以在对
代码封EXP g_eventStart,g_eventKill;,,线程对象声明 装时,通常会遇到对消息封装的情况,即解决应用程序EXEextem“C”EXP UINT ThreadFun(HWND pPararn); 与DLL之间的消息传递问题,这种DLL属于MFc DLL。
这比DLL中线程处理函数实现的关键
代码为: 封装其他程序元素要复杂。
笔者总结如下:首先创建一个extern“C”EXP UINT-11lreadFun(HWND pParam) MFC DIJL框架,DLL类名为CMFCDLI.App,在DLL的头文件{::WaitForSingleObject(g_eventStart,INFINITE);//等待线程起 和应用程序的头文件中定义相同的消息号WM_MSG动事件的到来 WM_USER+20。
在DLL中声明消息输出函数extem…C…,,践程事件到时执行的
代码 declspee(dllexport)void BeginMessage(HWND hwnd);在if(::WaitForSingleObjeet(g_eventKill,0)一---WAIT_OBJECT O)H CMFCDUApP的类中添加SendMessage()成员函数:void等待线程结束事件的带来 SendMessage(HWND hwnd),该成员函数调用Windows API{..·,,执行资’源释棼}return O;l 函数PostMessage()实现DLL向主程序传递消息:::在主程序中导入线程对象及线程函数:#define IMP_DLL PostMessage(hwnd,WM_MSG,0,1),其中第一个参数hwnd代_decispee(dllimport); 表接收消息的窗口句柄。
主程序需要向DLL传递hwnd参数。
IMP_DLL CEvent g_eventStart,g_eventKill; 最后一步在BeginMessage()函数中添加出eApp.SendMessageextem”C”UINT ThreadFun(HWND pParam); (hwnd)语句。
theApp是DLL的全局程序对象。
主程序设计:主程序线程实现部分
代码: 程序类为CTestDLL。
首先在CTestDLL.h中的void CTestDllDlg::OnOK() DECLARE_MESSAGE_MAP()前一句上添加消息声明函数:lhwnd--tIIis一>GetSafeHwnd(); afx_msg LRESULT MyMsg(WPARAM wParam,U)ARAMg_eventStart.ResetEvent();,,线程事件复位 IParam)。
在CTestDLL类中On_Message(WM_USER,MyMsg),AfxBeginThread(ThPROC,hwnd);//执行线程函数 绑定消息处理函数,当应用程序获得WM MSG消息时,即执g_eventgtart.SetEvent();,,开始执行线程 行MyMsg函数。
最后。
主程序执行下面两条语句即可实现消g..eventl(j11.SetEvent();,,结束线程执行 息互传。
HWND hwnd=this一>GetSafeHwnd();,,获得窗体句柄l BeginMessage(hwnd);//向应用程序窗体发送消息。
上面
代码中将ThreadFun函数直接嵌入ThProc中即可。
1.8 DLL的调用方法对于线程的临界对象、信号量和互斥量的封装过程方法一 DLL的调用有显式调用〔41和隐式调用两种方式。
显式的调样.读者可自行测试。
用:在应用程序中用API函数LoadLibrary将自行设计的动态1.6 DLL对另一DLL的封装 链接库调进应用程序地址空间.动态连接库的文件名是 一个DLL可以对其他DLL的函数进行二次封装。
这种 LoadLibrary函数的调用参数.如果函数返回一个非NULL情况主要应用在:软件开发商提供给用户二次开发的DLL文 值,则DLL调用成功,再用GetPmcAddress函数获取DLL中件,用户在应用程序中调用该DLL中的函数或者变量.而最 封装的函数。
之后就可应用对普通函数的调用方式在应用程终用户需要将自己的所有应用程序完全封装进另一个DLL 序中调用DLL中的函数了,在应用程序的退出
代码中,应用中。
比如,开发一个数据采集系统,其包括对数据采集卡硬件 FreeLibrary释放动态连接库。
隐式调用:隐式调用需要在应用的控制模块以及数据分析处理模块。
而硬件的控制多半由硬 程序中加入DLL的.LIB库文件和.h头文件。
.h文件中包含了件开发商提供二次开发包完成,数据分析部分需要自行开 DLL中变量、常量以及.