作者:马云冬(xacn) 版权所有:马云冬(xacn) 转载请与作者联系 刚到公司不久,接到领导的下达的一个任务,就是把对POS机操作功能封装在ActiveX控件中,在IE中调用。这样就能实现在IE上直接对POS机进行操作。而我要封装的这个动态库,厂家只提供了一个单的动态库和一百多字的说明,也就是说明一下动态库中有机个函数和其对应的参数。也就是厂家就连动态库对应的头文件也没有提供。:-( 这样也行?! 接到这个任务后,我第一想到的是用VC的ATL来实现它。你问我为什么要用ATL也不用别的,如CB、Delphi之类的。我只能说我觉得写ActiveX还是用VC好;况且还要对硬件进行操作,这样一来当然是用VC了。别说我没提醒你,用CB、Delphi之类的有可能会出现预想不到的惊奇...... 现在让我带着进入正题吧!先用ATL COM AppWizard生成一个名叫PosActiveX的工程,生成时系统会问你是生成DLL还是EXE。当然是DLL的了。生成好后加入一个接口叫IPosCtrl,当然了要在Web上用,所以生成的接口一定是要小所以选择Lite Control的。你可别问我怎么加入,如果这都不会,那我写的这文章是不适合你看的。所以等你学会加入接口后再看。接口加好后,我就要实现方法了。首先用接口一般都要对其进行初始化。所以加入一个叫Init(short nCom)的接口方法,该方法完成加载DLL和DLL中的功能函数,还有就是打开对POS机进行操作的COM口;还有一个是修改POS机的时间的方法叫ModifyPosDT(BSTR bstrDT);还有个是清空POS机中数据的方法--EmptyPos()。最后,当你不想用时就要关闭所打开的COM口--Quit()。在生成接口IPosCtrl时同时会生成CPosCtrl类。我有个习惯,就是我一般是把实现方法都写在类中,而接口只时输出该类中你想输出的方法。所以在类中我就写了以下几个方法: InitDll()----加载DLL库和其中的功能函数; ExitDll()----卸载DLL库,用完后不卸载是在占用内存。所以它是少不了的。 SetPosDateTime(char * pchDT)---设置POS机的时间。 ClearPos()----清空POS机中的记录。 在类中我就写了这几个方法。 在说一下我要输出的接口方法有: Init(short nCom)----初化接口,为调用做准备。 Quit()----退出程序时,调用它退出接口调用。 ModifyPosDT(BSTR bstrDT)----设置POS机时间。 EmptyPos()----清空POS机数据。 完了就这么多。 现在来看看我的源程序吧! // PosCtrl.cpp : Implementation of CPosCtrl #include "stdafx.h" #include "PosActiveX.h" #include "PosCtrl.h" //-------------------------------------------------------- // Police.dll所用到的常量定义 //-------------------------------------------------------- #define Com_UpRecord 1 #define Com_UpPoliceLen 2 #define Com_UpSimpleDataLen 3 #define Com_UpSimplePunishLen 4 #define Com_UpGeneralDataLen 5 #define Com_UpGeneralPunishLen 6 #define Com_EmptyPolice 7 #define Com_EmptySimpleData 8 #define Com_EmptySimplePunish 9 #define Com_EmptyGeneralData 10 #define Com_EmptyGeneralPunish 11 #define Com_DownRecord 0x80 #define Com_DownStreetCodeLen 0x81 #define Com_DownBlackListLen 0x82 #define Com_DownPeccancySimpleLen 0x83 #define Com_DownPeccancyGeneralLen 0x84 #define Com_DownDateTime 0x85 #define Com_Exit 0x86 #define Com_Init 0x87 #define Err_UpSimpleDataLen 0 #define Err_UpSimplePunishLen 1 #define Err_UpGeneralDataLen 2 #define Err_UpGeneralPunishLen 3 #define Err_UpPoliceLen 4 #define Err_UpRecord 5 #define Err_DownStreetCodeLen 6 #define Err_DownSimplePeccancyCodeLen 7 #define Err_DownGeneralPeccancyCodeLen 8 #define Err_DownBlackList 9 #define Err_DownDateTime 10 #define Err_EmptyData 11 #define Err_GetCode 12; #define Const_Terminator 0x20 #pragma data_seg("mydata") static HINSTANCE DLLInst = NULL; //动态库句柄 #pragma data_seg() // HANDLE hCom; //COM串口句柄 //------------------------------------------------------ //POLICE.DLL动态库函数功能定义 //------------------------------------------------------ HANDLE (__stdcall *Init_comm)(LPSTR str);//初始化通信口 BYTE (__stdcall *Exit)(HANDLE hCom);//关闭通信口 BYTE (__stdcall *Protocol)(HANDLE hCom,BYTE cmd,BYTE len,BYTE *_dt,BYTE *prlen,BYTE *prdt);//通信协议 BYTE (__stdcall *Pipe_control)(HANDLE hCom,BYTE mode);//多路控制typedef BYTE (__stdcall *Dev_escape)(HANDLE hCom);//断开多路控制 //----------------------------------------------------------------------------// // 功能:加载Police.dll动态库和其中的一些功能函数 // 输入/输出参数:无 // 版本:1.0 // 修改: //----------------------------------------------------------------------------// void CPosCtrl::InitDll() { DLLInst=LoadLibrary("police.dll"); if(DLLInst!=NULL) { Init_comm=(HANDLE(__stdcall *)(LPSTR))GetProcAddress(DLLInst,"Init_comm"); Exit=(BYTE(__stdcall *)(HANDLE))(GetProcAddress(DLLInst,"Exit")); Protocol=(BYTE(__stdcall *)(HANDLE,BYTE,BYTE,BYTE *_dt,BYTE *prlen,BYTE *prdt))(GetProcAddress(DLLInst,"Protocol")); Pipe_control=(BYTE(__stdcall *)(HANDLE,BYTE))(GetProcAddress(DLLInst,"Pipe_control")); Dev_escape=(BYTE(__stdcall *)(HANDLE))(GetProcAddress(DLLInst,"Dev_escape")); } else { ::MessageBox(NULL,"加载动态库失败!", "提示信息", MB_OK | MB_ICONINFORMATION); exit(0); } } //----------------------------------------------------------------------------// // 功能:释放动态库 // 输入/输出参数:无 // 版本:1.0 // 修改: //----------------------------------------------------------------------------// void CPosCtrl::ExitDll() { if(DLLInst!=NULL) FreeLibrary(DLLInst); } //----------------------------------------------------------------------------// // 功能:控件接口方法,对外提供关闭串口,释放动态库。 // 输入/输出参数:无 // 版本:1.0 // 修改: //----------------------------------------------------------------------------// STDMETHODIMP CPosCtrl::Quit() { // TODO: Add your implementation code here (*Exit)(hCom); ExitDll(); ::MessageBox(NULL,"关闭COM口成功","提示信息",MB_OK | MB_ICONINFORMATION); return S_OK; } STDMETHODIMP CPosCtrl::get_ComNo(short *pVal) { // TODO: Add your implementation code here *pVal = m_ComNo; return S_OK; } STDMETHODIMP CPosCtrl::put_ComNo(short newVal) { // TODO: Add your implementation code here m_ComNo = newVal; return S_OK; } //----------------------------------------------------------------------------// // 功能:提供初化动态库的对外接口,并实现打开口串口的功能。 // 输入/输出参数:11--要打开的串口号。 // 版本:1.0 // 修改: //----------------------------------------------------------------------------// STDMETHODIMP CPosCtrl::Init(short nComNo) { // TODO: Add your implementation code here InitDll(); char str[20] = ""; sprintf(str,"COM%d",nComNo); hCom = (*Init_comm)((LPSTR)str); sprintf(str,"%d",hCom); char temp[255] = ""; strcpy(temp,"打开的端口为COM1,句柄为:"); strcat(temp,str); ::MessageBox(NULL,temp,"提示信息",MB_OK | MB_ICONINFORMATION); //TCHAR str[255]; //sprintf(str,"%d",hCom); //MessageBox(str,"Caption",MB_OK); return S_OK; } //----------------------------------------------------------------------------// // 功能:实现ASCII码到BCD码的转换功能函数 // 输入/输出参数:11-想转换的ASCII码,22-返回的BCD码,13-ASCII码的长度,14-返回的BCD码长度 // 版本:1.0 // 修改: //----------------------------------------------------------------------------// void CPosCtrl::ASCII_TO_BCD(char *cSource, char *cResult, int iSourceLen, int iResultLen) { int iBegin,i; iBegin=0; if(iSourceLen%2) { iBegin=1; cResult[0]=cSource[0]-''0''; } for (i=iBegin;i<IRESULTLEN;I++) { cResult[i]=(cSource[2*i-iBegin]-''0'')*16+cSource[2*i-iBegin+1]-''0''; } //deprive off preData cResult[iResultLen]=''/0''; } //----------------------------------------------------------------------------// // 功能:设置POS机时间函数。 // 输入/输出参数:11-想要设置的时间 // 版本:1.0 // 修改: //----------------------------------------------------------------------------// BOOL CPosCtrl::SetPosDateTime(char * pchDateTime) { int n=1; unsigned char cInput[257],cOutput[256]; BYTE byOutput,retVal; for(int i=0;i<8;i++) { (*Pipe_control)(hCom,n); //多路控制 //修改POS机时间 { if(::MessageBox(NULL,"是否确定修改POS机时间?","提示信息",MB_YESNO)==IDNO) { return FALSE; } ASCII_TO_BCD(pchDateTime,(char *)cInput,10,5); retVal = (*Protocol)(hCom,Com_DownDateTime,5,cInput,&byOutput,cOutput); if (retVal) { ::MessageBox(NULL,"修改成功!","提示信息",MB_OK | MB_ICONINFORMATION); } else { ::MessageBox(NULL,"修改不成功!","提示信息",MB_OK | MB_ICONINFORMATION); } } n=n<<1 ; } (*Protocol)(hCom,0x86,5,cInput,&byOutput,cOutput); //下载成功 (*Dev_escape)(hCom); //关闭多路控制 (*Pipe_control)(hCom,0); //多路控制复位 return TRUE; } //----------------------------------------------------------------------------// // 功能:对外提供的修改时间的接口方法 // 输入/输出参数:11-想要设置的时间 // 版本:1.0 // 修改: //----------------------------------------------------------------------------// STDMETHODIMP CPosCtrl::ModifyPosDT(BSTR bstrDT) { // TODO: Add your implementation code here if(SetPosDateTime((char *)bstrDT)) { return S_OK; } { return S_FALSE; } } //----------------------------------------------------------------------------// // 功能:实现清空POS机内数据的函数。 // 输入/输出参数:无 // 版本:1.0 // 修改: //----------------------------------------------------------------------------// void CPosCtrl::ClearPos() { int n=1; unsigned char cInput[257],cOutput[256]; BYTE byOutput,retVal; for(int i=0;i<8;i++) { (*Pipe_control)(hCom,n); //多路控制 //清空POS机内的数据 if(::MessageBox(NULL,"是否要清空POS机内数据?","提示信息",MB_YESNO | MB_ICONQUESTION)==IDNO) { return; } retVal = Protocol(hCom,7,1,cInput,&byOutput,cOutput); //通信协议 if (!retVal) { retVal = Protocol(hCom,8,1,cInput,&byOutput,cOutput); if (!retVal) { retVal = Protocol(hCom,9,1,cInput,&byOutput,cOutput); if (!retVal) { retVal = Protocol(hCom,10,1,cInput,&byOutput,cOutput); if (!retVal) { retVal = Protocol(hCom,11,1,cInput,&byOutput,cOutput); } } } ::MessageBox(NULL,"POS机内数据已被清空!","提示信息",MB_OK | MB_ICONINFORMATION); } n=n<<1 ; } (*Protocol)(hCom,0x86,5,cInput,&byOutput,cOutput); //下载成功 (*Dev_escape)(hCom); //关闭多路控制 (*Pipe_control)(hCom,0); //多路控制复位 return; } //----------------------------------------------------------------------------// // 功能:对外提供的清空POS机内数据的接口方法 // 输入/输出参数:无 // 版本:1.0 // 修改: //----------------------------------------------------------------------------// STDMETHODIMP CPosCtrl::EmptyPos() { // TODO: Add your implementation code here ClearPos(); return S_OK; } 下面是调用PosActiveX.Dll的效果,调用时,要先对其进行注册,否则调用是不会成功的.注册是在"Windows的开始菜单中调用"运行",在"运行"对话框中输入:regsvr32 C:/PosActiveX/PosActiveX.dll 注册成功后就可对COM口进行操作了。还有一点是要特别注意的,必须把你要在ActiveX控件调用的Dll文件拷贝到Windows/System目录(对于Win9x系统),对于NT,2000系统就要拷贝到WINNT/System32目录下才能正确的运行。 开发环境:Windows2000和VC6 测试环境:Windows200 代码使用许可:可用 |