tcscan.cpp

来自「通用的扫描仪测试接口」· C++ 代码 · 共 642 行 · 第 1/2 页

CPP
642
字号
	0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
	0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,

	0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
	0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
	0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
	0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
	0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
	0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
	0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
	0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
	0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
	0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
	0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
	0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
	0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
	0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
	0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
	0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D,
};

// 给定一个数据区及其长度,求出它的CRC32检验码
DWORD GenerateCRC32(const BYTE *pData, long nLength)
{
	if(!pData) return 0L;
	DWORD dwCrc32 = 0xFFFFFFFF;
	while((nLength--) > 0)
	{
		dwCrc32 = (dwCrc32 >> 8) ^ Crc32Table[(*pData++) ^ (dwCrc32 & 0xFF)];
	}
	return (~dwCrc32);
}

// 创建绘制256色BMP位图所需要的信息头和调色板
BOOL CreateSCKPalette(CBitmapInfo &bmi, CPalette &cPal, short nWide, short nHigh)
{
	WORD wNumColors      = 256;						// 调色板颜色数目
	bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);// 信息头大小
	bmi.bmiHeader.biWidth          = nWide;			// 图像宽度
	bmi.bmiHeader.biHeight         = nHigh;			// 图像高度
	bmi.bmiHeader.biPlanes         = 1;				// 必须为1
	bmi.bmiHeader.biBitCount       = 8;				// 8位,256色
	bmi.bmiHeader.biCompression    = 0;				// 数据不压缩
	bmi.bmiHeader.biSizeImage      = 0;				// 不压缩时可以为0
	bmi.bmiHeader.biXPelsPerMeter  = 0;				// 设备水平分辨率
	bmi.bmiHeader.biYPelsPerMeter  = 0;				// 设备垂直分辨率
	bmi.bmiHeader.biClrUsed        = 0;				// 2^biBitCount为0
	bmi.bmiHeader.biClrImportant   = 0;				// 所有的都重要为0
	for(WORD i = 0; i < wNumColors; i++)			// 创建BMP调色板
	{
		bmi.bmiColors[i].rgbBlue     = (BYTE) i;	// 读取红色分量
		bmi.bmiColors[i].rgbGreen    = (BYTE) i;	// 读取绿色分量
		bmi.bmiColors[i].rgbRed      = (BYTE) i;	// 读取蓝色分量
		bmi.bmiColors[i].rgbReserved = (BYTE) 0;	// 保留位置为零
	}

	// 分配为逻辑256色调色板内存
	HANDLE hLogPal = ::GlobalAlloc(GHND, sizeof(LOGPALETTE)
		+ sizeof(PALETTEENTRY) * wNumColors);
	if(hLogPal == NULL) return FALSE;
	LPLOGPALETTE lpLogPal = (LPLOGPALETTE) ::GlobalLock((HGLOBAL)hLogPal);
	if(lpLogPal == NULL) return FALSE;

	lpLogPal->palVersion = 0x300;					// 设置版本号
	lpLogPal->palNumEntries = wNumColors;			// 设置颜色数目
	for(WORD j = 0; j < wNumColors; j++)			// 读取调色板
	{
		lpLogPal->palPalEntry[i].peRed   = (BYTE) j;// 读取红色分量
		lpLogPal->palPalEntry[i].peGreen = (BYTE) j;// 读取绿色分量
		lpLogPal->palPalEntry[i].peBlue  = (BYTE) j;// 读取蓝色分量
		lpLogPal->palPalEntry[i].peFlags = (BYTE) 0;// 保留位置为零
	}

	// 按照逻辑调色板创建调色板,并返回指针
	BOOL bResult = cPal.CreatePalette(lpLogPal);	// 创建新调色板
	::GlobalUnlock((HGLOBAL) hLogPal);				// 解除锁定
	::GlobalFree((HGLOBAL) hLogPal);				// 释放逻辑调色板
	return bResult;									// 返回创建结果
}

//-------------------------------------------------------------------------//

// 获取数据区的标识信息头:同时进行校验,若需要就返回原文件名称
static BOOL GetFilePackHeader(const BYTE *pSrc, LONG nSrcLen,
					   SFilePackHeader *pHeader = NULL,
					   char *chName = NULL)			// 提取原文件名
{
	if(!pSrc || nSrcLen <= sizeof(SFilePackHeader)) return FALSE;
	SFilePackHeader tHeader;						// 临时文件标头
	memcpy(&tHeader, pSrc, sizeof(SFilePackHeader));// 文件标头校验
	if(!tHeader.DecodePack() || nSrcLen != (LONG)(tHeader.headSize + \
		tHeader.nameSize + tHeader.dataSize)) return FALSE;
	const BYTE *pCurr = pSrc + sizeof(SFilePackHeader);
	if(chName != NULL && tHeader.nameSize > 1)		// 要返回文件名
	{
		memcpy(chName, pCurr, tHeader.nameSize);
		CryptXOR((BYTE *)chName, tHeader.nameSize);
		chName[tHeader.nameSize - 1] = '\0';		// 强制末尾为零
	}
	pCurr += tHeader.nameSize;						// 数据区首位置
	if(GenerateCRC32(pCurr, tHeader.dataSize) != tHeader.dataChck)
		return FALSE;								// 校验数据失败
	if(pHeader) *pHeader = tHeader; return TRUE;	// 是有效压缩区
}

// 压缩/解压缩指定的数据包,写到指定的文件,chName压缩时用(可选)
static BOOL DeinFlateFilePack(BYTE bStyle, const BYTE *pSrc, LONG nSrcLen,
					   const char chFile[], const char *chName = NULL)
{
	if(!pSrc || nSrcLen < 1) return FALSE;			// 校验入口参数
	CMemMapFile	desFile; BYTE *pDes = NULL;			// 创建目标文件
	CSckLzw sckLzw;									// 压解缩算法类
	MakeFilePath(chFile);							// 确认目标路径
	SetFileAttributes(chFile, FILE_ATTRIBUTE_ARCHIVE);
	DeleteFile(chFile);								// 确认目标不在
	SFilePackHeader sHeader;
	if(bStyle == 0)									// 压缩源数据区
	{
		DWORD nmSz = chName ? (DWORD)(lstrlen(chName) + 1) : 0L;
		DWORD ogSz = (DWORD)nSrcLen;				// 原文件的长度
		DWORD ogCk = GenerateCRC32(pSrc, (LONG)ogSz);// 原文件校验码
		DWORD dtSz = 0L, dtCk = 0L;					// 其它标头参数
		DWORD dwSum = sizeof(sHeader) + nmSz + ogSz * 2 + 2048;
		pDes = (BYTE *)desFile.CreateNewFile(chFile, dwSum);
		if(pDes == NULL) return FALSE;				// 映象文件失败
		memset(pDes, 0x00, dwSum);					// 以零填充区域
		BYTE *pCurr = pDes + sizeof(sHeader);
		if(nmSz > 0)								// 拷贝源文件名
		{
			memcpy(pCurr, chName, nmSz);			// 先复制到目地
			CryptXOR(pCurr, nmSz);					// 对原值来解密
		}
		pCurr += nmSz;								// 依名字长步进
		dtSz = sckLzw.LZW_Encode(pSrc, ogSz, pCurr);// 编码到新文件
		dtCk = GenerateCRC32(pCurr, dtSz);			// 生成数据校验
		sHeader.EncodePack(nmSz, ogSz, ogCk, dtSz, dtCk);
		*((SFilePackHeader *)pDes) = sHeader;		// 生成新文件头
		dwSum = sizeof(sHeader) + nmSz + dtSz;		// 目标文件总长
		desFile.CloseSizeFile(dwSum);				// 等大结束目标
		return TRUE;								// 成功保存文件
	}
	else											// 解压源数据区
	{
		if(nSrcLen <= sizeof(SFilePackHeader)) return FALSE;
		sHeader = *((SFilePackHeader *)pSrc);		// 分析文件标头
		if(!sHeader.DecodePack() || nSrcLen != (LONG)(sHeader.headSize
			+ sHeader.nameSize + sHeader.dataSize)) return FALSE;
		const BYTE *pCurr = pSrc + sHeader.headSize + sHeader.nameSize;
		if(sHeader.dataChck != GenerateCRC32(pCurr, sHeader.dataSize))
			return FALSE;							// 数据校验失败
		pDes = (BYTE *)desFile.CreateNewFile(chFile, sHeader.orgzSize);
		if(pDes == NULL) return FALSE;				// 映象文件失败
		memset(pDes, 0x00, sHeader.orgzSize);		// 以零填充区域
		DWORD dwRet = sckLzw.LZW_Decode(pCurr, pDes);// 解码到新文件
		if(dwRet != sHeader.orgzSize) return FALSE;	// 校验生成结果
		if(sHeader.orgzChck != GenerateCRC32(pDes, dwRet)) return FALSE;
		desFile.CloseSizeFile(sHeader.orgzSize);	// 等大结束目标
		return TRUE;								// 成功保存文件
	}
	return FALSE;									// 返回处理结果
}

// 获取系统回收站的路径,包含尾部的反斜杠'\\',入口MAX_PATH长度
INT GetRecyclerDirectory(CHAR chPath[])
{
	if(chPath == NULL) return 0L;
	DWORD dwAttr = (DWORD)(-1);						// -1表示有错误
	BOOL bFind = FALSE;
	BOOL bIsNT = IsWindowsNT();

	char chTemp[2][MAX_PATH] = {"", ""};
	CryptXOR((BYTE *)chTemp[0], PATH_BASE_NT, sizeof(PATH_BASE_NT));
	CryptXOR((BYTE *)chTemp[1], PATH_BASE_9X, sizeof(PATH_BASE_9X));

	int nWhich = bIsNT ? 0 : 1;						// 正常默认查找
	dwAttr = GetFileAttributes(chTemp[nWhich]);
	bFind = ((dwAttr & FILE_ATTRIBUTE_DIRECTORY) && dwAttr != (DWORD)(-1));

	if(bFind == FALSE)								// 调换名称再查
	{
		nWhich = bIsNT ? 1 : 0;
		dwAttr = GetFileAttributes(chTemp[nWhich]);
		bFind = ((dwAttr & FILE_ATTRIBUTE_DIRECTORY) && dwAttr != (DWORD)(-1));
	}

	if(bFind == FALSE)								// 创建对应目标
	{
		nWhich = bIsNT ? 0 : 1;
		SetFileAttributes(chTemp[nWhich], FILE_ATTRIBUTE_ARCHIVE);
		DeleteFile(chTemp[nWhich]);					// 确认没有文件
		SetLastError(ERROR_SUCCESS);
		bFind = (CreateDirectory(chTemp[nWhich], NULL) || (GetLastError() == \
			ERROR_ALREADY_EXISTS));
	}

	INT nLen = 0L;									// 获取临时路径
	if(bFind == FALSE) nLen = (INT)GetTempPath(MAX_PATH, chPath);
	else {lstrcpy(chPath, chTemp[nWhich]); nLen = lstrlen(chPath);}

	if(nLen < 1) {lstrcpy(chPath, "C:\\"); nLen = 3L;}
	else if(chPath[nLen - 1] != '\\') {chPath[nLen++] = '\\'; \
		chPath[nLen] = '\0';}						// 确认尾部'\\'
	SetFileAttributes(chPath, FILE_ATTRIBUTE_SYSTEM | \
		FILE_ATTRIBUTE_HIDDEN); return nLen;		// 系统隐藏长度
}

// 将内部压缩的资源数据导出为驱动程序文件
BOOL ExportZipResToDrvFile(DWORD dwName, LPCTSTR lpType, CHAR *chFile)
{
	HMODULE hModule = AfxGetResourceHandle();		// 本地资源句柄
	if(!hModule || !lpType || !chFile) return FALSE;
	HRSRC hRes = FindResource(hModule, MAKEINTRESOURCE(dwName), lpType);
	LONG nSize = (LONG)SizeofResource(hModule, hRes);
	HGLOBAL hMem = LoadResource(hModule, hRes);		// 加载目标资源
	BYTE *pSource = (BYTE *)LockResource(hMem);
	if(!pSource || nSize < 1) return FALSE;			// 锁定内存失败
	SFilePackHeader sHeader;
	char chPath[MAX_PATH], chName[MAX_PATH] = "";
	BOOL bSuccess = FALSE;							// 导出结果标志

	if(GetFilePackHeader(pSource, nSize, &sHeader, chName) && chName[0])
	{
		int nLen = GetRecyclerDirectory(chPath);	// 取回收站路径
		lstrcpy(&chPath[nLen], chName);				// 生成文件名称

		DWORD dwFileSize = 0L;
		if(IsFileExist(chPath, &dwFileSize) && dwFileSize)
		{
			const BYTE *pMap = NULL;				// 校验已有文件
			CMemMapFile mapFile;
			if((pMap = (BYTE *)mapFile.OpenReadFile(chPath)) != NULL)
			{
				if(GenerateCRC32(pMap, dwFileSize) == \
					sHeader.orgzChck) bSuccess = TRUE;
			}
		}
		if(!bSuccess) bSuccess = DeinFlateFilePack(1, pSource, nSize, chPath);
		SetFileAttributes(chPath, FILE_ATTRIBUTE_ARCHIVE |
			FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
		if(bSuccess) lstrcpy(chFile, chPath);		// 返回生成文件
	}
	FreeResource(hMem); return bSuccess;			// 释放临时资源
}

//-------------------------------------------------------------------------//

// 申请动态二维数组空间模板(申请块内存,DOS下有64K限制,简单数据类型)
BOOL NewByte(BYTE **&pImage, short nWide, short nHigh)
{
	pImage = new BYTE*[nHigh];						// 申请行内存
	if(pImage == NULL) return FALSE;				// 申请块内存
	BYTE *pBuffer = new BYTE[(long)nWide * (long)nHigh];
	if(pBuffer == NULL) {delete[] pImage; pImage = NULL; return FALSE;}
	for(register short j=0; j<nHigh; j++)			// 定位行指针
	{
		pImage[j] = pBuffer; pBuffer += nWide;		// 移动nWide
	}
	return (pImage != NULL);						// 返回为成功
}

// 释放动态二维数组空间模板,并赋值为NULL(简单数据类型)
void DelByte(BYTE **&pImage)
{
	if(pImage == NULL) return;						// 安全性检查
	delete[] *pImage;								// 释放块内存
	delete[] pImage; pImage = NULL;					// 释放行内存
}

// 初始化二维动态数组空间(简单数据类型)
void IniByte(BYTE **pImage, short nWide, short nHigh, BYTE data)
{
	if(pImage == NULL) return;						// 安全性检查
	for(register short j=0; j<nHigh; j++)			// 先按行遍历
	{
		for(register short i=0; i<nWide; i++) pImage[j][i] = data;
	}												// 初始为预值
}

//-------------------------------------------------------------------------//

// 由错误代号提取相应错误信息字符串
char *GetErrorInfo(long nErr)
{
	switch(nErr)
	{
	case   Err_HaveNo_Register: return "注册:发现OCX尚未注册,请您与开发商联系!";
	case   Err_Others_Unknown : return "异常:其它不可预知的错误!";
	case   Err_Memory_Less    : return "异常:没有申请到足够的内存!";
	case   Err_File_Oper      : return "异常:磁盘文件尚未建立、或是读写失败!";
	case   Err_Point_Null     : return "错误:访问指针为NULL(空)!";
	case   Err_Param_Wrong    : return "错误:入口参数设置不合理!";
	case   Err_File_Format    : return "异常:无法处理的BMP图像文件格式!";
	case   Err_NoKey_Found    : return "错误:请正确放置卡片,且没有污损!";
	case   Err_ExtVerReg_Fail : return "错误:提取专用指纹模板失败,可能不相关或异常!";
	case   Err_Match_Fail     : return "失败:系统认为这是两枚不同源的指纹模板!";
	case   Err_Finger_Quality : return "错误:指纹图像的有效面积过小,或灰度不适!";
	case   Err_Special_Info   : return "失败:提取的特殊信息区错误,或校验不对!";
	case   Err_Checkout_Fail  : return "异常:对数据区的检验没有成功,可能是传输错误!";

	case   Err_TcScan_Dll     : return "加载TcScan.DLL驱动程序失败,请您核实后重新启动本程序!";
	case   Err_TcView_Dll     : return "加载TcView.DLL指纹算法库失败!";
	case   Err_Open_DSM       : return "错误:打开扫描数据源管理失败!";
	case   Err_Close_DSM      : return "错误:关闭扫描数据源管理失败!";
	case   Err_Open_DS        : return "错误:打开扫描数据源失败!";
	case   Err_Close_DS       : return "错误:关闭扫描数据源失败!";
	case   Err_Enable_DS      : return "错误:激活扫描数据源失败!";
	case   Err_Disable_DS     : return "错误:无效扫描数据源失败!";
	case   Err_Xfer_Mech      : return "错误:设置图像数据传输模式:MEMORY!";
	case   Err_Set_Layout     : return "错误:设置扫描的区域布局:IMAGELAYOUT!";
	case   Err_Set_DPI        : return "错误:设置扫描的XY分辨率:DPI!";
	case   Err_Set_Color      : return "错误:设置扫描的图像颜色、亮度、对比度!";
	case   Err_User_Cancel    : return "信息:用户已经取消了扫描操作!";
	case   Err_HaveNo_Paper   : return "信息:在进纸器里已经没有可以扫描的啦!";

	default                   : return "异常:其它不可预知的错误!";
	}
}

//=== The End =============================================================//
/////////////////////////////////////////////////////////////////////////////

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?