ActiveX(ocx) + DLL(wosa) + JS:实现BS硬件调用框架(三)
今日从API层解读SP封装的ActiveX层,因为我的ActiveX层将调用基于wosa规范的SP也就是会调用wosa规范的API,那问题也就归到了综述文档(API和SPI的概述)中去。XFSManger将API经过预处理...等转换变成SP中的spi函数。因而调用第一步就是启动XFXManger环境。文档中给出的一个简单调用的流程:startup-open-register-lock-getinfo-execute..-unlock-deregister-close-cleanup.针对编码我们要注意以下几点问题。
1,版本处理,尽管在大部分测试应用中,版本管理经常是最后实现有时甚至忽略,但由于金融软件有着严格的版本管理体制,我的项目使用DWORD值表示版本号。
2,创建Application句柄及hService。
3,open代表着开启会话(session),具体的设备的状态信息需要通过后续的getinfo获取。
4,lock加锁是设备独占式访问机制的实现,主要对于多应用多会话的execute函数是非常必要的。
5,当然很关键的一点,由于sp只负责返回数据的内存分配,因而释放由ap层解决,调用support functions,WFMFreeBuffer();
贴上一段有注释的代码,展示整个过程,主要注意结构的使用。
CrdSan* l_poCrdSan; l_poCrdSan = (CrdSan*)p_pVoid; TCHAR l_acTempData[100]; memset(l_acTempData, 0x00, sizeof(l_acTempData)); l_poCrdSan->m_ContinueFlag = TRUE; // 连续工作标志,用于外面的线程循环的一个标志 // 下面是完整的XFS调用过程 // 启动XFS的环境 DWORD dwRVersion = l_poCrdSan->dwCombineVersion(LOW_APIVERSUPPORT, HIGH_APIVERSUPPORT); // 启动XFS的环境 WFSStartUp为即时调用函数,入口参数分别是应用可以支持的版本范围和一个用于接收当前xfsmanager信息的指针 HRESULT hr = WFSStartUp(dwRVersion, &(l_poCrdSan->m_wv)); //启动XFS Manager if (FAILED(hr)) { l_poCrdSan->Log("WFSStartUp Fail\n"); return 1; } else { l_poCrdSan->Log("WFSStartUp OK\n"); } // 创建Application句柄 hr = WFSCreateAppHandle(&l_poCrdSan->m_hXFSApp); if (FAILED(hr)) { l_poCrdSan->Log("WFSCreateAppHandle Fail\n"); return 1; } else { l_poCrdSan->Log("WFSCreateAppHandle OK\n"); } WFSVERSION w; DWORD l_dwSupVersion = l_poCrdSan->dwCombineVersion(LOW_SRVCVERSUPPORT, HIGH_SRVCVERSUPPORT); HSERVICE hService; hr = WFSOpen(l_poCrdSan->m_acLogicalName, l_poCrdSan->m_hXFSApp, NULL, NULL, WFS_INDEFINITE_WAIT, l_dwSupVersion, &l_poCrdSan->m_wv, &w, &hService); if (hr != WFS_SUCCESS) { sprintf(l_acTempData, "WFSOpen %s Fail %d\n", l_poCrdSan->m_acLogicalName, hr); l_poCrdSan->Log(l_acTempData); return 1; } /* 注册窗体部分代码 // hr = WFSRegister(hService, SERVICE_EVENTS, theApp.GetSafeHwnd()); // hr = WFSRegister(hService, USER_EVENTS, theApp.GetSafeHwnd()); // hr = WFSRegister(hService, EXECUTE_EVENTS, theApp.GetSafeHwnd()); */ WFSRESULT* pResult; // 加锁 hr = WFSLock(hService, WFS_INDEFINITE_WAIT, &pResult); if(hr != WFS_SUCCESS) { l_poCrdSan->Log("Lock failed"); return -1 ; } hr = WFSGetInfo(hService,WFS_INF_CRD_CAPABILITIES,NULL,WFS_INDEFINITE_WAIT,&pResult); if(hr == WFS_SUCCESS) { LPWFSCRDCAPS lpCaps = (LPWFSCRDCAPS)pResult->lpBuffer; } WFSCRDDISPENSE* lpcrddis = new WFSCRDDISPENSE; lpcrddis->usNumber = 1; lpcrddis->bPresent = false; hr = WFSExecute(hService,WFS_CMD_CRD_DISPENSE_CARD,lpcrddis,WFS_INDEFINITE_WAIT,&pResult); delete lpcrddis; if(hr == WFS_SUCCESS) { //LPWFSCRDCAPS lpCaps = (LPWFSCRDCAPS)pResult->lpBuffer; l_poCrdSan->Log("dispense success"); } // 解锁 hr = WFSUnlock(hService); //释放SP申请的内存 WFMFreeBuffer(&pResult);
这就在一个应用中调用了一个sp,而现实的封装要求需要在一个ActiveX空间中封装4个左右的sp操作,因而下一步任务就是通过设计模式实现在同一个应用中实现多个SP的调用,下篇我们将继续探讨。不过中途可能要插播一个DES的封装。