📄 deviceclass.cpp
字号:
} else {
// 假如千位和十位不为零但百位为0,累加声音“零”
if((m_clsTrans.Fare()/1000!=0)
&&(m_clsTrans.Fare()%100/10)!=0){
nSoundLen+=nNumber[0];
}
}
nValue=(m_clsTrans.Fare()%100)/10;
if(nValue>0){ //累计十位数字声音长度
nSoundLen+=nNumber[nValue];
nSoundLen+=nNumber[10]; //累计“十”声音长度
} else {
// 假如千位或百位不为零且个位不为0,累加声音“零”
if((m_clsTrans.Fare()/100!=0)
&&(m_clsTrans.Fare()%10!=0)){
nSoundLen+=nNumber[0];
}
}
nValue=m_clsTrans.Fare()%10;
switch(nValue){
case 0:
// 假如应收金额为0,合成“免费”;否则不合成
if(m_clsTrans.Fare()==0){
nSoundLen+=nFree; //累计“免费”声音长度
}
break;
case 2:
// 假如应收金额为两圆,合成“两”;否则合成“二”
if(m_clsTrans.Fare()==2){
nSoundLen+=nNumber[13]; //累计“两”声音文件长度
} else {
nSoundLen+=nNumber[nValue]; //累计“二”声音文件长度
}
break;
default:
nSoundLen+=nNumber[nValue];
break;
}
nSoundLen+=nRMB; //累计“圆”声音文件
// 若上次申请的内存尚未释放,释放该内存。这种情况发生快速连续收费
// 时,若上辆车的价格尚未播放完毕,该声音文件将会有内存泄露
if(pSoundImage!=NULL){
delete [] pSoundImage;
pSoundImage=NULL;
}
// 根据要合成的声音长度申请内存
pSoundImage=new char[nSoundLen];
if(pSoundImage==NULL){
SendMessage(theApp.m_pMainWnd->m_hWnd,WM_ABNORMAL,0,(LPARAM)"合成声音文件时内存不足");
return;
}
memset(pSoundImage,0,nSoundLen);
// 合成车型声音文件
memmove(pSoundImage,pClass,nClass);
AssembleSound(pNumber[nBusClass],pSoundImage);
// 在车型和金额之间增加空格
AssembleSound(pSpace,pSoundImage);
// 合成千位声音文件
nValue=m_clsTrans.Fare()/1000;
if(nValue>0){ //累计千位数字声音长度
AssembleSound(pNumber[nValue%10],pSoundImage);
AssembleSound(pNumber[12],pSoundImage);
}
// 合成百位声音文件
nValue=(m_clsTrans.Fare()%1000)/100;
if(nValue>0){ //累计百位数字声音长度
AssembleSound(pNumber[nValue],pSoundImage);
AssembleSound(pNumber[11],pSoundImage);
} else {
// 假如千位和十位不为零但百位为0,累计声音“零”
if((m_clsTrans.Fare()/1000!=0)&&
((m_clsTrans.Fare()%100)/10!=0)){
AssembleSound(pNumber[0],pSoundImage);
}
}
// 合成十位声音文件
nValue=(m_clsTrans.Fare()%100)/10;
if(nValue>0){ //累计十位数字声音长度
AssembleSound(pNumber[nValue],pSoundImage);
AssembleSound(pNumber[10],pSoundImage);
} else {
// 假如千位或百位不为零且个位不为零但十位为零,累计声音“零”
if((m_clsTrans.Fare()/100!=0)&&
(m_clsTrans.Fare()%10!=0)){
AssembleSound(pNumber[0],pSoundImage);
}
}
nValue=m_clsTrans.Fare()%10;
switch(nValue){
case 0:
// 假如应收金额为0,合成“免费”;否则不合成
if(m_clsTrans.Fare()==0){
AssembleSound(pFree,pSoundImage);
}
break;
case 2:
// 假如应收金额为两圆,合成“两”;否则合成“二”
if(m_clsTrans.Fare()==2){
AssembleSound(pNumber[13],pSoundImage);
} else {
AssembleSound(pNumber[nValue],pSoundImage);
}
break;
default:
AssembleSound(pNumber[nValue],pSoundImage);
break;
}
// 累计“圆”声音文件
if(m_clsTrans.Fare()!=0){
AssembleSound(pRMB,pSoundImage);
}
try{
sndPlaySound(pSoundImage,SND_MEMORY|SND_ASYNC);
// 启动定时器,定时器超时后清除合成的声音数据
// 合成的声音文件播放时间 = 数据长度 / 每秒的字节数,对WAV
// 文件,每秒的字节数固定位于第29 - 32字节
DWORD nAvgBytesPerSec=0;
memmove(&nAvgBytesPerSec,pSoundImage+28,sizeof(DWORD));
DWORD nTotalTime=nSoundLen*1000/nAvgBytesPerSec+200;
SendMessage(theApp.m_pMainWnd->m_hWnd,WM_STARTUP_TIMER,SOUND_TIMER,nTotalTime);
}
catch(...){
SendMessage(theApp.m_pMainWnd->m_hWnd,WM_ABNORMAL,0,(LPARAM)"CSound::PlayFare()出现异常\n");
}
}
// 定时器超时后删除合成的声音数据
void CSound::ProcessTimerOut()
{
if(pSoundImage!=NULL){
delete [] pSoundImage;
pSoundImage=NULL;
}
}
// 播放“祝您一路顺风”
void CSound::PlayThankYou()
{
try{
sndPlaySound(pThankYou,SND_MEMORY|SND_ASYNC);
}
catch(...){
SendMessage(theApp.m_pMainWnd->m_hWnd,WM_ABNORMAL,0,(LPARAM)"CSound::PlayThankYou()出现异常\n");
}
}
// 停止播放
void CSound::StopPlay()
{
try{
sndPlaySound(NULL,SND_ASYNC);
}
catch(...){
SendMessage(theApp.m_pMainWnd->m_hWnd,WM_ABNORMAL,0,(LPARAM)"CSound::StopPlay()出现异常\n");
}
}
// 按照实际情况重新组合并生成新的WAV文件
// WAV文件结构应当如下所述:
// 1、Microsoft WAV文件实际上是RIFF(Resource Intercharge File
// Format)数据块,RIFF数据块由四字节的标识符(对Microsoft
// WAV文件,为RIFF)、四字节的数据块尺寸(不包括4字节的标识符、
// 4字节的尺寸本身及文件未的填充字符。典型地:若文件尾无填充
// 字符,其值等于文件长度减8)、块的数据部分、填充字符(假如
// 数据长度为奇数,增加一个空字符作为占位符)
// 2、对Microsoft WAV文件,RIFF块的数据部分的前4个字节为WAVE,
// 指明本RIFF块的数据格式
// 3、RIFF块内可包含几种子块:"fmt "子块、"fact"子块及"data"子块,
// 其中"fact"子块并非必须
// 4、子块和RIFF块有相同的结构:四字节标识符、四字节数据块尺寸、
// 块的数据部分、填充字符
// 5、"fmt "块定义音频文件的格式,四字节标识符为"fmt ",数据长度
// 为以下结构的长度(若cbSize被忽略,则为16;否则为18),其数
// 据块定义音频文件格式,内容如下:
// typedef struct {
// WORD wFormatTag; 对Microsoft WAV文件,为1
// WORD nChannels; 声道数:单声道为1,双声道为2
// DWORD nSamplesPerSec; 每秒的样本数
// DWORD nAvgBytesPerSec; 每秒的字节数=每秒的样本数*每个数据块的尺寸
// WORD nBlockAlign; 每个数据块的尺寸=通道数*每个样本的字节数
// WORD wBitsPerSample; 每个样本的位数
// WORD cbSize; 指明附加在WAVEFORMATEX结构后的信息。若无附加信息,该字节应置0。对Microsoft WAV文件,该字可定义,也可被忽略
// } WAVEFORMATEX;
// 6、"fact"块存储实际数据样本长度(并非必须),四字节标识符为
// "fact",数据长度一般为4字节,数据块内容为波形样本的实际长度
// 7、"data"块存储实际的波形文件的实际长度,四字节标识符为"data",
// 数据长度为波形数据的实际长度(若存在"fact"块,则"data"的数据
// 长度等于"fact"块的数据块内容*每个样本所占字节数),数据块内
// 容即为实际的波形数据
void CSound::AssembleSound(char *pSrc,char *pObj)
{
// 首先判断入口参数是否合法的WAV数据
if((pSrc==NULL)||(pObj==NULL)) return;
DWORD nScrIndex=0;
DWORD nObjIndex=0;
// 合法WAV文件的前4个字节必须为RIFF,第9字节开始的8字节必须为WAVEfmt
if(strncmp(pSrc+nScrIndex,"RIFF",4)!=0) return;
if(strncmp(pObj+nObjIndex,"RIFF",4)!=0) return;
nScrIndex+=4;
nObjIndex+=4;
DWORD nFilePosition=nObjIndex;
DWORD nScrFileLen=ByteToDWORD(pSrc+nScrIndex);
DWORD nObjFileLen=ByteToDWORD(pObj+nObjIndex);
nScrIndex+=4;
nObjIndex+=4;
if(strncmp(pSrc+nScrIndex,"WAVEfmt ",8)!=0) return;
if(strncmp(pObj+nObjIndex,"WAVEfmt ",8)!=0) return;
nScrIndex+=8;
nObjIndex+=8;
// 读取fmt数据长度
DWORD nScrFmtLen=ByteToDWORD(pSrc+nScrIndex);
DWORD nObjFmtLen=ByteToDWORD(pObj+nObjIndex);
nScrIndex+=4;
nObjIndex+=4;
// 读取声音文件格式字段并判断要合并数据格式是否相同
WAVEFORMATEX structWave1,structWave2;
memmove(&structWave1,pSrc+nScrIndex,sizeof(WAVEFORMATEX));
memmove(&structWave2,pObj+nObjIndex,sizeof(WAVEFORMATEX));
if((structWave1.wFormatTag!=1)||(structWave2.wFormatTag!=1)) return;
if(structWave1.nChannels!=structWave2.nChannels) return;
if(structWave1.nSamplesPerSec!=structWave2.nSamplesPerSec) return;
if(structWave1.nAvgBytesPerSec!=structWave2.nAvgBytesPerSec) return;
if(structWave1.nBlockAlign!=structWave2.nBlockAlign) return;
if(structWave1.wBitsPerSample!=structWave2.wBitsPerSample) return;
// 检查是否有fact块,假如有,跳过该块的数据
nScrIndex+=nScrFmtLen;
nObjIndex+=nObjFmtLen;
if(strncmp(pSrc+nScrIndex,"fact",4)==0){
nScrIndex+=4;
nScrFmtLen=ByteToDWORD(pSrc+nScrIndex);
nScrIndex=nScrIndex+4+nScrFmtLen;
}
if(strncmp(pObj+nObjIndex,"fact",4)==0){
nObjIndex+=4;
nObjFmtLen=ByteToDWORD(pObj+nObjIndex);
nObjIndex=nObjIndex+4+nObjFmtLen;
}
// 检查是否为数据块,若否,说明文件格式错误,直接返回
if(strncmp(pSrc+nScrIndex,"data",4)!=0) return;
if(strncmp(pObj+nObjIndex,"data",4)!=0) return;
nScrIndex+=4;
nObjIndex+=4;
DWORD nDataPosition=nObjIndex;
// 读取有效数据长度
nScrFmtLen=ByteToDWORD(pSrc+nScrIndex);
nObjFmtLen=ByteToDWORD(pObj+nObjIndex);
// 将源数据连接到目标数据后面
nScrIndex+=4; //指向源有效数据其始位置
nObjIndex=nObjIndex+4+nObjFmtLen; //指向目标有效数据结束位置
memmove(pObj+nObjIndex,pSrc+nScrIndex,nScrFmtLen);
// 改变文件长度及有效数据长度
nObjFileLen+=nScrFmtLen;
nObjFmtLen+=nScrFmtLen;
// 假如数据长度为奇数,增加一填充符
// 以下几行导致声音文件播放时出现“波、波”声,故删除之
// if(nObjFmtLen%2!=0){
// nObjFileLen++;
// nObjFmtLen++;
// }
// 修改新生成数据的文件长度及有效数据长度
memmove(pObj+nFilePosition,&nObjFileLen,sizeof(DWORD));
memmove(pObj+nDataPosition,&nObjFmtLen,sizeof(DWORD));
}
UINT CSound::GetSoundLen(char *pFileName)
{
struct _finddata_t strFileInfo;
long hFile;
UINT nLen=0;
if((hFile=_findfirst(pFileName,&strFileInfo))!=-1L){
_findclose(hFile);
nLen=strFileInfo.size;
}
return nLen;
}
BOOL CSound::LoadSound(char *pFileName,char *pPointer,UINT nLen)
{
BOOL bSuccessFlag=FALSE;;
FILE *fp1;
if(pPointer==NULL) return bSuccessFlag;
memset(pPointer,0,nLen);
if((fp1=fopen(pFileName,"rb"))!=NULL){
fread(pPointer,1,nLen,fp1);
fclose(fp1);
bSuccessFlag=TRUE;
}
return bSuccessFlag;
}
// 将分字节存放的整数(4 byte)恢复成UINT
DWORD CSound::ByteToDWORD(char *pStr)
{
DWORD nValue=0;
memmove(&nValue,pStr,sizeof(DWORD));
return nValue;
}
// 释放声音文件所占用内存
void CSound::ReleaseDevice()
{
if(pClass!=NULL){
delete [] pClass;
pClass=NULL;
}
if(pRMB!=NULL){
delete [] pRMB;
pRMB=NULL;
}
for(int i=0;i<14;i++){
if(pNumber[i]!=NULL){
delete [] pNumber[i];
pNumber[i]=NULL;
}
}
if(pThankYou!=NULL){
delete [] pThankYou;
pThankYou=NULL;
}
if(pFree!=NULL){
delete [] pFree;
pFree=NULL;
}
if(pSpace!=NULL){
delete [] pSpace;
pSpace=NULL;
}
if(pSoundImage!=NULL){
delete [] pSoundImage;
pSoundImage=NULL;
}
}
char CPrinter::chPrinterStatus;
BOOL CPrinter::bNormalFlag=FALSE;
CPrinter::CPrinter()
{
}
// 打印机初始化:清空打印缓冲区的数据
void CPrinter::Initial()
{
char tmpStr[3];
memset(tmpStr,0,3);
tmpStr[0]=0x1b; //清除打印缓冲区
tmpStr[1]='@';
SendPrintData(tmpStr,2);
NormalFlag(TRUE);
}
// 处理打印机状态并生成相应的外设消息
void CPrinter::ProcessPrinterInfo(char Status)
{
if(chPrinterStatus!=Status){
chPrinterStatus=Status;
if(chPrinterStatus==0x11){
NormalFlag(TRUE);
} else {
NormalFlag(FALSE);
}
}
}
// 通过并口按指定的格式打印票据
BOOL CPrinter::PrintInvoice()
{
CTransInfo m_clsTrans;
CLaneInfo m_clsLane;
CStatInfo m_clsStat;
CTimeInfo m_clsTime;
char pBuff[PRINT_INFO_LEN];
char strMoney[20];//汉字金额
memset(strMoney,0,20);
ConvertMoney(m_clsTrans.Fare(),strMoney);//将整数金额转换为汉字
// 如果已经预先打印了发票的起始部分,继续打印发票的其余部分;
// 否则打印全部发票
UINT nPosition=0;
if(m_clsStat.HasPrePrint()){
memset(pBuff,0,PRINT_INFO_LEN);
sprintf(pBuff+nPosition," ");
nPosition+=3;
memmove(pBuff+nPosition,strMoney,16);
nPosition+=17; //打印金额
sprintf(pBuff+nPosition,"%.4d/%.2d/%.2d %.2d:%.2d",
m_clsTime.GetYear(),m_clsTime.GetMonth(),m_clsTime.GetDay(),
m_clsTime.GetHour(),m_clsTime.GetSecond());
nPosition+=23;
pBuff[nPosition]=0xc; //换页
nPosition++;
} else {
memset(pBuff,0,PRINT_INFO_LEN);
// 新程序运行时经常会造成打印机不动作,初步怀疑是清除打印缓冲区
// 造成,暂时注解该行
// 故障原因:打印车型时误将16进制的车型代码当作ASCII码放入打印缓冲区
nPosition=0;
pBuff[nPosition]=0x1b; //初始化打印机
nPosition++;
pBuff[nPosition]='@';
nPosition++;
pBuff[nPosition]=0x1b; //设置页长度
nPosition++;
pBuff[nPosition]='C';
nPosition++;
pBuff[nPosition]=15; //每页15行
nPosition++;
pBuff[nPosition]=0x1b; //设置底部空白量
nPosition++;
pBuff[nPosition]='N';
nPosition++;
pBuff[nPosition]=4; //每页的底部四行为空白行
nPosition++;
/*
pBuff[nPosition]=0x1b; //设置左边空白量
nPosition++;
pBuff[nPosition]='I';
nPosition++;
pBuff[nPosition]=3; //左边距为3
nPosition++;
pBuff[nPosition]=0x1b; //设置右边空白量
nPosition++;
pBuff[nPosition]='Q';
nPosition++;
pBuff[nPosition]=1; //右边距为8
nPosition++;
*/
pBuff[nPosition]=0x1c; //设置汉字方式打印
nPosition++;
pBuff[nPosition]='&';
nPosition++;
m_clsLane.GetPlazaName(pBuff+nPosition);
nPosition+=5; //打印收费站名称
// 打印车道号及收费员代码
sprintf(pBuff+nPosition,"%.2d %.5d\n\n",
m_clsLane.LaneNO(),m_clsStat.CollectNO());
nPosition+=15;
sprintf(pBuff+nPosition,"\n\n");
nPosition+=2;
sprintf(pBuff+nPosition," ");
nPosition+=3;
memmove(pBuff+nPosition,strMoney,16);
nPosition+=17; //打印金额
sprintf(pBuff+nPosition,"\n\n\n");
nPosition+=3;
sprintf(pBuff+nPosition,"%.4d/%.2d/%.2d %.2d:%.2d",
m_clsTime.GetYear(),m_clsTime.GetMonth(),m_clsTime.GetDay(),
m_clsTime.GetHour(),m_clsTime.GetSecond());
nPosition+=23;
pBuff[nPosition]=0xc; //换页
nPosition++;
}
m_clsStat.HasPrePrint(FALSE);
if(SendPrintData(pBuff,nPosition)){
// m_clsStat.IncInvoiceNow(0); //打印成功后发票号++
return TRUE;
}else
{
return FALSE;
}
}
// 预打印发票:为了增加发票打印的速度,收取通行费前先预先打印出
// 固定信息部分,操作员收钱后再打印其余部分发票
void CPrinter::PrePrintInvoice()
{
// 免费车和统缴车不打印发票,为防止多次预打发票造成发票打印错误,
// 若预打发票标志置位,说明已经预打了发票,直接返回
CStatInfo m_clsStat;
if(m_clsStat.HasPrePrint()) return;
CLaneInfo m_clsLane;
if(m_clsLane.bPrePrint()){
char pBuff[PRINT_INFO_LEN];
memset(pBuff,0,PRINT_INFO_LEN);
// 新程序运行时经常会造成打印机不动作,初步怀疑是清除打印缓冲区
// 造成,暂时注解该行
// 故障原因:打印车型时误将16进制的车型代码当作ASCII码放入打印缓冲区
int nPosition=0;
pBuff[nPosition]=0x1b; //初始化打印机
nPosition++;
pBuff[nPosition]=0x40;
nPosition++;
pBuff[nPosition]=0x1b; //设置页长度
nPosition++;
pBuff[nPosition]='C';
nPosition++;
pBuff[nPosition]=20; //每页20行
nPosition++;
pBuff[nPosition]=0x1b; //设置底部空白量
nPosition++;
pBuff[nPosition]='N';
nPosition++;
pBuff[nPosition]=4; //每页的底部四行为空白行
nPosition++;
pBuff[nPosition]=0x1b; //设置左边空白量
nPosition++;
/*
pBuff[nPosition]='I';
nPosition++;
pBuff[nPosition]=8; //左边距为8
nPosition++;
pBuff[nPosition]=0x1b; //设置右边空白量
nPosition++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -