首先需要根据动态库的动能,自己编写黑板类与报文协议类的定义(头文件)。黑板类可以通过父子类来细分功能。在父类中定义接口函数BDInterface,如GetInterfaceName、GetInterfaceID、GetVersion、Initialize、Close、GetAuxInterface等。
在其子类IBlackboard中定义黑板操作函数,如Publish(为从黑板上发送在某报文协议下的数据做准备)、Subscribe(为黑板接收 报文做准备)、RegistEvent(注册报文到达或错误发送事件)、UnRegistEvent(撤销已注册的报文到达事件或错误发生事件)、Withdraw(撤销Publish/Subscribe的准备)、RegistSortEvent(注册的数据到达挑选)、UnRegistSortEvent(撤销注册数据到达)、Write(写数据,并由黑板对应接口发送数据)、Read(读取数据)等。
同样是BDInterface的子类,报文协议类Gmxp定义Prepare(为协议转做准备)、UnPrepare、GetInterfaceID(获得接口编号,一般黑板统一编号,协议统一编号)、::*fGramRCVHandle(处理接收的消息)、::*SorOut(黑板报文挑选)、Refresh(读取新数据,刷新协议对象)、SetRecordFile(设置协议录取数据文件名)等。
另外还有一个运行时接口识别与动态名称创建的结构体CRuntimeInterface,其中有五个变量和两个成员函数。五个变量中有m_pNextInterface是该结构体的指针变量,滚动自定义。函数CreateInterface()和CreateInterface(char *szInterfaceName),第一个函数用来返回下一接口作为当前接口。第二个函数用类名来创建对象,不能初始化此类的静态成员CRuntimeInterface。
需要注意的是,上述头文件定义的都是纯虚函数 ,是对动态库的申明,比如结构体、符号、函数等。除上述三类以外,还有根据不同硬件配置可拓展的数据的信息BDCARDCFG,以及按照HRESULT的格式自定义的返回值HBDRESULT(LONG)。该格式可自行查看MSDN,主要是由三个值组成Sev,Facility和code。(还有C位用于标记是否是自定义数值,R预保留位。)
这三部分分别可用#define来自定义值,然后用MAKE_HBDRESULT函数将其通过以为相或操作,集合成我们需要的完整信息返回值。
发送端:
在MAINDlg类中定义3个变量,分别是一个IBlackboard类,一个自定义的黑板功能类CBkboard和一个存储数据的Datastr。其中CBkboard中包括一个IBlackboard对象的指针,和两个函数,InitBkboard和SendPlats。
InitBkboard中动态加载黑板模型的动态库::LoadLibrary()。宏定义一个函数指针*fCreateBlackboard,输入参数无,返回值是一个IBlackboard的指针。用该函数指针定义变量fcBoard并用GetProcAddress赋值(为动态库的地址)。将fcBoard()函数的结果赋值给CBkboard中自定义的IBlackboard指针pboard。这里比较绕,需要细心去理解。这三步操作是为了把动态库调取并载入到我们定义的黑板类中去使用,并不能够直接加载动态库之后就直接使用。完成这些操作之后,就可以使用我们自己的黑板类中的pboard来使用动态库中的函数。利用pboard调用Initialize函数配置文件和参数,初始化协议类的实例对象,根据BDSUCCEEDED判断是否初始化成功,最后MAKE_HBDRESULT返回信息。在MAINDlg的OnInitDlg中直接调用该函数以载入动态库和配置信息。
SendPlats发送数据信息。首先用Publish函数为从黑板上发送某协议下的报文做准备工作,这一步在发送数据中必不可少。只有在Publish之后才能使用Write写数据,并由黑板所对应的接口发送数据。
在MAINDlg窗口设置一按钮开启发送数据服务。点击按钮,设置一计时器,每隔1000ms执行一次OnTimer。设置计时器之后,系统消息映射里会出现一个WM_TIME双击生成的消息映射函数,即为OnTimer()。结束计时器直接调用KillTimer(),参数为计时器的编号。
在OnTimer中利用MAINDlg中定义的CBkboard对象来使用其成员函数SendPlats发送数据。
在编辑框的消息映射函数中编写数组内容的更新显示。
接收端与此类似,初始化操作一样。在GetMsg中需要先调用Subscribe进行消息注册,然后把接收到的obj指针转化为CJIESHOUDlg类型,这样才能让我们载入的动态库等信息添加到创建的CJIESHOUDlg窗口的指针变量中来使用。这步的操作相应于上文中的粗体。接着使用RegistEvent判断注册报文到达。最后用自定义的DealMsg函数调用Read来接收数据并显示。
至此发送端的编写已完成,配合接收端可进行1s为刷新频率的数据传输。需要注意的是:
1.头文件避免重复声明,不能忘记添加Resource.h;
2.理解IBlackboard和CBkboard的区别。IBlackboard是动态库中定义的类,而CBkboard是自定义的黑板类,用来初始加载动态库和配置信息,并完成该黑板的自定义功能;
3.IBkboard就是自己写的子黑板,或者说是一名“专家”,来写你需要这名专家进行的操作;IBDInterface是黑板接口的一些虚函数;IBlackboard是IBDInerface的子类,包含了接发信息等的虚函数;IGramMXP同为子类定义协议的虚函数;
4.有一类应该是需要重复创建自己的黑板,也就是“专家”的时候需要用到的总接口创建类,日后有时间做IP黑板的时候再加以细述。
如有理解错误,请指点。