金融机具应用接口CEN/XFS规范汇总 (2) - 写出第一个SP程序

本文介绍了如何开发一个简单的SP(Service Provider)程序,SP是控制硬件设备的关键,将XFS指令转化为硬件驱动指令。文中以C++在Windows环境下创建动态库(dll)为例,阐述了SP所需实现的重要接口函数,如WFPOpen、WFPClose等,并提供了基本的函数实现框架。SP的异步处理和多进程并发情况下的管理将在后续文章中探讨。

SP,全称Service Provider,是CEN规范中,用于控制硬件设备(或虚拟设备)的程序,其最大的作用是将XFS指令,转化为硬件驱动的指令,并实现一定的控制流程。让我们来看一下,一个简单的SP程序需要从何开始开发:

  • 运行环境:Windows XP / Windows 7 32bit
  • 开发工具:VS 2003 或更新版本;
  • 程序类型:动态库(dll);
  • 开发语言:C++;

SP的dll是SP必须的部分(有些简单的SP只有一个dll),该dll由XFS Manager进行加载(但实际上是应用的进程空间,XFS Manager本身也是dll),加载过程将在后文单独描述;dll需要导出几个函数接口,供XFS Manager调用,这些函数接口在CEN文档的第1部分均有描述,代码如下:

LIBRARY  "SPInterface"

EXPORTS
    ; 此处可以是显式导出
    WFPOpen;
    WFPClose;
    WFPLock;
    WFPUnlock;
    WFPRegister;
    WFPDeregister;
    WFPGetInfo;
    WFPExecute;
    WFPCancelAsyncRequest;
    WFPSetTraceLevel;
    WFPUnloadService;

类SPInterface是该动态库对应的类名;

以上接口中,最重要的是WFPOpen、WFPClose、WFPRegister、WFPDeregister、WFPGetInfo、WFPExecute这几个接口函数,功能如下:

  • WFPOpen:顾名思义,打开SP;
  • WFPClose:关闭SP;
  • WFPRegister:注册事件窗口,注册完成后,SP将会向所有已经注册过的窗口抛送Event(特殊情况除外);
  • WFPDeregister:注销事件窗口,注销后,SP将不会向此窗口抛送Event(特殊情况除外);
  • WFPGetInfo:应用程序获取SP模块的某些状态信息;
  • WFPExecute:应用程序向SP模块下发指令;

这些接口函数需要SP一一实现,先贴代码:

//Function Name: WFPOpen//////////////////////////
HRESULT WINAPI WFPOpen ( HSERVICE hService, LPSTR lpszLogicalName, HAPP hApp, LPSTR lpszAppID, DWORD dwTraceLevel, DWORD dwTimeOut, HWND hWnd, REQUESTID ReqID, HPROVIDER hProvider, DWORD dwSPIVersionsRequired, LPWFSVERSION lpSPIVersion, DWORD dwSrvcVersionsRequired, LPWFSVERSION lpSrvcVersion)
{
	return ( InterfaceTask.WFP_Open( hService, lpszLogicalName, hApp, lpszAppID, dwTraceLevel, dwTimeOut, hWnd, ReqID, hProvider, dwSPIVersionsRequired, lpSPIVersion, dwSrvcVersionsRequired, lpSrvcVersion) );
}

//Function Name: WFPClose/////////////////////////
HRESULT WINAPI WFPClose ( HSERVICE hService, HWND hWnd, REQUESTID ReqID)
{
	return ( InterfaceTask.WFP_Close( hService, hWnd, ReqID) );
}

//Function Name: WFPExecute///////////////////////
HRESULT WINAPI WFPExecute ( HSERVICE hService, DWORD dwCommand, LPVOID lpCmdData, DWORD dwTimeOut, HWND hWnd, REQUESTID ReqID )
{
	return ( InterfaceTask.WFP_Execute( hService, dwCommand, lpCmdData, dwTimeOut, hWnd, ReqID ) );
}

//Function Name: WFPGetInfo//////////////////////
HRESULT WINAPI WFPGetInfo ( HSERVICE hService, DWORD dwCategory, LPVOID lpQueryDetails, DWORD dwTimeOut, HWND hWnd, REQUESTID ReqID)
{
	return ( InterfaceTask.WFP_GetInfo( hService, dwCategory, lpQueryDetails, dwTimeOut, hWnd, ReqID) );
}

其中InterfaceTask是类SPInterface的实例化对象,类定义如下:

class SPInterface : public CFrameWnd, public SPICtrl
{
public:
	SPInterface();
	~SPInterface();
	//XFS Functions:
	virtual HRESULT WFP_Open( HSERVICE hService, LPSTR lpszLogicalName, HAPP hApp, LPSTR lpszAppID, DWORD dwTraceLevel, DWORD dwTimeOut, HWND hWnd, REQUESTID ReqID, HPROVIDER hProvider, DWORD dwSPIVersionsRequired, LPWFSVERSION lpSPIVersion, DWORD dwSrvcVersionsRequired, LPWFSVERSION lpSrvcVersion );
	virtual HRESULT WFP_Close( HSERVICE hService, HWND hWnd, REQUESTID ReqID );
	virtual HRESULT WFP_Register( HSERVICE hService,  DWORD dwEventClass, HWND hWndReg, HWND hWnd, REQUESTID ReqID );
	virtual HRESULT WFP_Deregister( HSERVICE hService, DWORD dwEventClass, HWND hWndReg, HWND hWnd, REQUESTID ReqID );
	virtual HRESULT WFP_GetInfo( HSERVICE hService, DWORD dwCategory, LPVOID lpQueryDetails, DWORD dwTimeOut, HWND hWnd, REQUESTID ReqID );
	virtual HRESULT WFP_Execute( HSERVICE hService, DWORD dwCommand, LPVOID lpCmdData, DWORD dwTimeOut, HWND hWnd, REQUESTID ReqID );
	virtual HRESULT WFP_CancelAsyncRequest( HSERVICE hService, REQUESTID RequestID );
	virtual HRESULT WFP_Lock( HSERVICE hService, DWORD dwTimeOut, HWND hWnd, REQUESTID ReqID );
	virtual HRESULT WFP_Unlock( HSERVICE hService, HWND hWnd, REQUESTID ReqID );
	virtual HRESULT WFP_SetTraceLevel( HSERVICE hService, DWORD dwTraceLevel );
	virtual HRESULT WFP_UnloadService();
    ...
}

“SPICtrl”是我自己定义的一个SP通用处理的类,包含SP程序各种通用的处理,这里当做父类继承,可以方便直接使用“SPICtrl”的成员函数;

以上代码只列举了WFP指令对应的处理函数,类的内部处理函数需要根据SP类型的不同具体定义,这里暂不赘述;

WFP指令对应的函数必须包含如下处理(以WPF_Open为例):

HRESULT RFIDInterface::WFP_Open( HSERVICE hService, LPSTR lpszLogicalName, HAPP hApp, LPSTR lpszAppID, DWORD dwTraceLevel, DWORD dwTimeOut, HWND hWnd, REQUESTID ReqID, HPROVIDER hProvider, DWORD dwSPIVersionsRequired, LPWFSVERSION lpSPIVersion, DWORD dwSrvcVersionsRequired, LPWFSVERSION lpSrvcVersion )
{
    HRESULT        hResult = 0;
    LPWFSRESULT    lpwfsResult = NULL;

    //Check Application window
    if (!IsWindow(hWnd))
    {
        return WFS_ERR_INVALID_HWND;
    }

    //Make return buffer:
    hResult = WFMAllocateBuffer( sizeof(WFSRESULT), WFS_MEM_FLAGS, (LPVOID*)&lpwfsResult );
    if (hResult != WFS_SUCCESS)
    {
        return WFS_ERR_INTERNAL_ERROR;
    }
    lpwfsResult->hService  = hService;
    lpwfsResult->RequestID = ReqID;
    lpwfsResult->hResult   = WFS_SUCCESS;
    lpwfsResult->lpBuffer  = NULL;

    //Open process
    ...

    //Post completed message
    ::PostMessage( hWnd, WFS_OPEN_COMPLETE, 0, (LPARAM)lpwfsResult );

    return WFS_SUCCESS;
}

解释一下:

  • “WFMAllocateBuffer”为必要处理,该函数由CEN/XFS静态库提供,所有的WFP指令必须先使用该函数申请一个“WFSRESULT”类型的内存空间,存储一个“WFSRESULT”类型结构体,并将该结构体最终以抛消息的方式发送给应用窗口;该结构体的成员赋值如上述代码所示,其中“lpBuffer”成员为输出参数,如果该指令需要输出数据,则需要再调用“WFMAllocateMore”函数再次申请内存,并将内存地址赋值给“lpBuffer”;如果该指令不需要输出数据,则“lpBuffer=NULL”;具体参照CEN文档,凡是“Output Param”不是空的指令,均需要输出数据,如下示例:
  • “PostMessage”为必要处理,该处理将一条消息抛送给“hWnd”窗口(应用窗口),并附带“lpwfsResult”指向的内存内容,表明该条指令全部完成;
  • 中间的处理需要根据SP程序具体情况完成,反正我的程序只是设定一个标志位,其他什么都不做,因为Open之前实际上设备已经打开了,Open只是进行了软件逻辑上的开启,跟硬件无关;由于部分设备在开启的时候会有延迟,建议有条件的情况下都使用该种处理,以增强软件的运行效率;
  • 需要进行异步处理的时候,需要保存该指令的基本信息,并将“PostMessage”这个步骤挪到其他地方处理,而函数则直接返回,这样应用程序会先进行其他处理,直至收到SP抛送来的Completed Message再处理该命令的后续部分,异步处理将单独开辟一篇文章详细讲解;
  • 其他指令大同小异,请各位自行编写及测试;

这样,就实现了一个最基本的SP程序,但这只是万里长征第一步,光有一个dll会存在很多问题,尤其是应用程序多进程并发的情况,这时,就需要使用一个主进程来管理设备,而dll则主要负责和应用程序通信,并且,每个WFP指令都应以异步方式进行处理,具体的实现方式我将在后续文章里讲解。

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值