源代码(连接另存为方式下载,重命名为zip文件再解压就可以到到源文件了)
下载链接http://hi.csdn.net/attachment/201107/19/0_1311044325WNjx.gif
请先到twain官方网站下载twain32头文件定义。
BOOL SaveBitmap(HGLOBAL _hDIB, const int serial_number){ BITMAPFILEHEADER bfh = {0}; BITMAPINFOHEADER *pBIH = NULL; HANDLE hf = NULL; // 获取临时文件 char _szTempFile [MAX_PATH] = {0}; char _szTempDir [MAX_PATH] = {0}; srand(GetTickCount()); GetTempPathA(sizeof(_szTempDir), _szTempDir); sprintf_s(_szTempFile , sizeof(_szTempFile) , "%s//%d-%d.bmp" , _szTempDir , serial_number , rand()); hf = CreateFileA(_szTempFile , GENERIC_WRITE , 0 , NULL , CREATE_ALWAYS , FILE_ATTRIBUTE_NORMAL , NULL); if(hf == INVALID_HANDLE_VALUE) GlobalFree(_hDIB); return FALSE; // 解析成位图文件头 pBIH = (BITMAPINFOHEADER*)GlobalLock(_hDIB); DWORD dwBytesWritten = 0l; bfh.bfType = ( (WORD) ('M' << 8) | 'B'); bfh.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +((((pBIH->biWidth*pBIH->biBitCount+31)/32)*4)*pBIH->biHeight) + pBIH->biClrUsed * sizeof(RGBQUAD); bfh.bfReserved1 = 0; bfh.bfReserved2 = 0; bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + pBIH->biClrUsed * sizeof(RGBQUAD); // 写入位图到文件 WriteFile(hf , &bfh , sizeof(BITMAPFILEHEADER) , &dwBytesWritten , NULL); WriteFile(hf , pBIH , bfh.bfSize-sizeof(BITMAPFILEHEADER) , &dwBytesWritten , NULL); CloseHandle(hf);hf=INVALID_HANDLE_VALUE; TRACE("save bitmap to:");TRACE(_szTempFile); GlobalUnlock(_hDIB); GlobalFree(_hDIB); return TRUE; } unsigned long __stdcall ScanThread(void * args) { HWND _hWnd = NULL; MSG _msg = {0}; HMODULE _hDSM = NULL; HBITMAP _hBitmap = NULL; int _nCount = 0; TW_CAPABILITY _cap = {0}; TW_UINT16 _twRC = TWRC_FAILURE; pTW_ENUMERATION _pEnumeration = NULL; pTW_ONEVALUE _pOneValue = NULL; TW_EVENT _twEvent = {0}; TW_IDENTITY _dsid = {0}; TW_USERINTERFACE _twUI = {0}; TW_PENDINGXFERS _twPendingXfer = {0}; TW_UINT16 _ModeType = -1; TW_UINT32 _index = 0; TW_IDENTITY _dsmid = { 0, { 1, 703, TWLG_USA, TWCY_USA, "twain-1.7.0.3" }, 1, 7, (DG_IMAGE | DG_CONTROL), "xxxx IT Corp. Ltd.", "xxxx webctrl", "wuzh1230" }; // 初始化 _hDSM = LoadLibraryA("TWAIN_32.DLL"); // 获取接口指针 DSMENTRYPROC _pDSMEntryProc = (DSMENTRYPROC) GetProcAddress(_hDSM, "DSM_Entry"); // 创建窗口,利用窗口的消息循环收取位图 _hWnd = CreateWindowExA(0 , "#32770" , "Scan Client" , WS_OVERLAPPEDWINDOW , 0, 0, 1, 1 , NULL , NULL , GetModuleHandleA(0) , NULL); // 打开数据源管理器 _twRC = CallDSMEntry(&_dsmid , NULL , DG_CONTROL , DAT_PARENT , MSG_OPENDSM , (TW_MEMREF)&_hWnd); // 选择数据源 _twRC = CallDSMEntry(&_dsmid , NULL , DG_CONTROL , DAT_IDENTITY , MSG_GETDEFAULT , (TW_MEMREF)&_dsid); _twRC = CallDSMEntry(&_dsmid , NULL , DG_CONTROL , DAT_IDENTITY , MSG_USERSELECT , (TW_MEMREF)&_dsid); // 打开数据源 _twRC = CallDSMEntry(&_dsmid , NULL , DG_CONTROL , DAT_IDENTITY , MSG_OPENDS , &_dsid); // 读取并设置传输模式ICAP_XFERMECH memset(&_cap, 0, sizeof(TW_CAPABILITY)); _cap.Cap = ICAP_XFERMECH; _cap.ConType = TWON_ENUMERATION; _twRC = CallDSMEntry(&_dsmid , &_dsid , DG_CONTROL , DAT_CAPABILITY , MSG_GET , (TW_MEMREF)&_cap); _pEnumeration = (pTW_ENUMERATION)GlobalLock(_cap.hContainer); // 搜索native模式的索引 for (_index = 0; _index < _pEnumeration->NumItems; _index++) { if (((TW_UINT16*)_pEnumeration->ItemList)[_index] == TWSX_NATIVE) { break;} } // 没有搜索到native模式的索引 if (_index == _pEnumeration->NumItems) { goto end_of_function; } // 如果当前索引位置的模式已经是NATIVE if (_index == _pEnumeration->CurrentIndex) { TRACE("Current xfer mode is 'native(TWSX_NATIVE)'"); _ModeType = TWSX_NATIVE; GlobalUnlock(_cap.hContainer); GlobalFree(_cap.hContainer); } else { TRACE("Current Mode is not 'native(TWSX_NATIVE)'"); // 设置native模式, _index是搜索到的native模式的索引 _pEnumeration->CurrentIndex = _index; _pEnumeration->DefaultIndex = _index; GlobalUnlock(_cap.hContainer); _twRC = CallDSMEntry(&_dsmid , &_dsid , DG_CONTROL , DAT_CAPABILITY , MSG_SET , (TW_MEMREF)&_cap); if (_twRC != TWRC_SUCCESS) { TRACE("Failed to set xfer mode to 'native(TWSX_NATIVE)'"); goto end_of_function; } GlobalFree(_cap.hContainer); // 再次读取模式 _twRC = CallDSMEntry(&_dsmid , &_dsid , DG_CONTROL , DAT_CAPABILITY , MSG_GET , (TW_MEMREF)&_cap); if (_twRC != TWRC_SUCCESS) { TRACE("Failed to read back xfer mode."); goto end_of_function; } _pEnumeration = (pTW_ENUMERATION)GlobalLock(_cap.hContainer); // 读取 _ModeType = ((TW_UINT16*) _pEnumeration->ItemList)[_pEnumeration->CurrentIndex]; GlobalUnlock(_cap.hContainer); GlobalFree(_cap.hContainer); // 检查模式是否是native if (_ModeType != TWSX_NATIVE) { TRACE("xfer mode NOT 'native(TWSX_NATIVE)',quit."); goto end_of_function; } } TRACE("Current xfer mode is 'native(TWSX_NATIVE)'"); // 读取送纸参数CAP_FEEDERENABLED TRACE("Read capability 'feed enabled(CAP_FEEDERENABLED)'."); memset(&_cap, 0, sizeof(TW_CAPABILITY)); _cap.Cap = CAP_FEEDERENABLED; _cap.ConType = TWON_ONEVALUE; _twRC = CallDSMEntry(&_dsmid , &_dsid , DG_CONTROL , DAT_CAPABILITY , MSG_GET , (TW_MEMREF)&_cap); GlobalFree(_cap.hContainer); // 读取自动喂纸设备失败,可能是没有硬件支持 if (_twRC != TWRC_SUCCESS) { TRACE("Failed to read 'feed enabled(CAP_FEEDERENABLED)'"); TRACE("[possiblly NO this hardware.]."); if (FEED_ENABLED) { TRACE("NO Hardware to support feed, so Unable to set, quit."); goto end_of_function; } } else { // 有送纸硬件 TRACE("OK to read 'feed enabled(CAP_FEEDERENABLED)'"); TRACE("[Hardware present]."); // 先检查是否启用了 memset(&_cap, 0, sizeof(TW_CAPABILITY)); _cap.Cap = CAP_FEEDERENABLED; _cap.ConType = TWON_ONEVALUE; _twRC = CallDSMEntry(&_dsmid , &_dsid , DG_CONTROL , DAT_CAPABILITY , MSG_GET , (TW_MEMREF)&_cap); if (_twRC != TWRC_SUCCESS) { TRACE("Failed to set 'feed enabled(CAP_FEEDERENABLED)'"); GlobalFree(_cap.hContainer); goto end_of_function; } _pOneValue = (pTW_ONEVALUE)GlobalLock(_cap.hContainer); // 如果已经启用了 if (_pOneValue->Item == FEED_ENABLED) { TRACE("[feeder enabled(CAP_FEEDERENABLED)] is same as parameter") GlobalUnlock(_cap.hContainer); GlobalFree(_cap.hContainer); } // 没有启用,启用喂纸设备 else { _pOneValue->Item = FEED_ENABLED; GlobalUnlock(_cap.hContainer); _twRC = CallDSMEntry(&_dsmid , &_dsid , DG_CONTROL , DAT_CAPABILITY , MSG_SET , (TW_MEMREF)&_cap); GlobalFree(_cap.hContainer); if (_twRC != TWRC_SUCCESS) { TRACE("Faile to set [feeder enabled(CAP_FEEDERENABLED)]"); goto end_of_function; } } // 再次读取,检查是否设置成功 memset(&_cap, 0, sizeof(TW_CAPABILITY)); _cap.Cap = CAP_FEEDERENABLED; _cap.ConType = TWON_ONEVALUE; _twRC = CallDSMEntry(&_dsmid , &_dsid , DG_CONTROL , DAT_CAPABILITY , MSG_GET , (TW_MEMREF)&_cap); if (_twRC != TWRC_SUCCESS) { GlobalFree(_cap.hContainer); TRACE("Failed to read [feeder enabled(CAP_FEEDERENABLED)]"); goto end_of_function; } _pOneValue = (pTW_ONEVALUE)GlobalLock(_cap.hContainer); GlobalUnlock(_cap.hContainer); GlobalFree(_cap.hContainer); // 设置成功 TRACE("OK to read [feed enabled(CAP_FEEDERENABLED)]"); #if 0 // 启用送纸:read memset(&_cap, 0, sizeof(TW_CAPABILITY)); _cap.Cap = CAP_AUTOFEED; _cap.ConType = TWON_ONEVALUE; _twRC = CallDSMEntry(&_dsmid , &_dsid , DG_CONTROL , DAT_CAPABILITY , MSG_GET , (TW_MEMREF)&_cap); if (_twRC != TWRC_SUCCESS) { GlobalFree(_cap.hContainer); TRACE("设置'自动送纸(CAP_AUTOFEED)'失败"); goto end_of_function; } // 如果已经启用送纸 _pOneValue = (pTW_ONEVALUE)GlobalLock(_cap.hContainer); if (_pOneValue->Item == AUTOFEED_ENABLED) { GlobalUnlock(_cap.hContainer); GlobalFree(_cap.hContainer); } // 没有启用,设置 else { _pOneValue->Item = AUTOFEED_ENABLED; GlobalUnlock(_cap.hContainer); _twRC = CallDSMEntry(&_dsmid , &_dsid , DG_CONTROL , DAT_CAPABILITY , MSG_SET , (TW_MEMREF)&_cap); GlobalFree(_cap.hContainer); if (_twRC != TWRC_SUCCESS) { TRACE("设置'自动送纸(CAP_AUTOFEED)'失败"); goto end_of_function; } } // 再次读取,检查是否成功启用送纸 memset(&_cap, 0, sizeof(TW_CAPABILITY)); _cap.Cap = CAP_AUTOFEED; _cap.ConType = TWON_ONEVALUE; _twRC = CallDSMEntry(&_dsmid , &_dsid , DG_CONTROL , DAT_CAPABILITY , MSG_GET , (TW_MEMREF)&_cap); if (_twRC != TWRC_SUCCESS) { GlobalFree(_cap.hContainer); TRACE("设置'自动送纸(CAP_AUTOFEED)'失败"); goto end_of_function; } _pOneValue = (pTW_ONEVALUE)GlobalLock(_cap.hContainer); GlobalUnlock(_cap.hContainer); GlobalFree(_cap.hContainer); // 设置成功 TRACE("设置'自动送纸(CAP_AUTOFEED)'成功"); #endif } // 显示界面,扫描 _twUI.hParent = GetActiveWindow(); _twUI.ShowUI = TRUE; _twRC = CallDSMEntry(&_dsmid , &_dsid , DG_CONTROL , DAT_USERINTERFACE , MSG_ENABLEDS , (TW_MEMREF)&_twUI); if (_twRC != TWRC_SUCCESS) { TRACE("Faile to enable UI."); goto end_of_function; } // 消息循环 _twEvent.pEvent = (TW_MEMREF)&_msg; while (GetMessage(&_msg, NULL, 0, 0)) { _twRC = TWRC_FAILURE; _twEvent.TWMessage = -1; _twRC = CallDSMEntry(&_dsmid , &_dsid , DG_CONTROL , DAT_EVENT , MSG_PROCESSEVENT , (TW_MEMREF)&_twEvent); if (_twRC == TWRC_FAILURE || _twEvent.TWMessage == -1) { TRACE("Failed to get message."); goto end_of_function; } // 不是数据源发送过来的消息,交给窗口默认处理 if (_twRC == TWRC_NOTDSEVENT) { TranslateMessage(&_msg); DispatchMessage(&_msg); continue; } // 处理数据源发送来的消息 switch (_twEvent.TWMessage) { // 位图在扫描仪内就绪了 case MSG_XFERREADY: { // 循环接受每一张位图 memset(&_twPendingXfer, 0, sizeof(TW_PENDINGXFERS)); do { _hBitmap = NULL; // 接受一张位图 _twRC = CallDSMEntry(&_dsmid , &_dsid , DG_IMAGE , DAT_IMAGENATIVEXFER , MSG_GET , (TW_MEMREF)&_hBitmap); switch (_twRC) { case TWRC_XFERDONE: // 传输完成,保存位图 { TRACE("xfer is done.(TWRC_XFERDONE)"); if (SaveBitmap((HGLOBAL)_hBitmap, _nCount++)) { TRACE("OK to save bitmap to file."); } else { TRACE("Failed to save bitmap to file."); } TRACE("send endxfer[MSG_ENDXFER] message."); _twRC = CallDSMEntry(&_dsmid , &_dsid , DG_CONTROL , DAT_PENDINGXFERS , MSG_ENDXFER , (TW_MEMREF)&_twPendingXfer); }break; case TWRC_CANCEL: // 取消 case TWRC_FAILURE: // 失败 default: { // 结束位图传输 TRACE("User canceld(TWRC_CANCEL),"); TRACE("or xfer failed(TWRC_FAILURE)."); _twRC = CallDSMEntry(&_dsmid , &_dsid , DG_CONTROL , DAT_PENDINGXFERS , MSG_ENDXFER , (TW_MEMREF)&_twPendingXfer); TRACE("send endxfer message."); }break; } }while (_twPendingXfer.Count != 0); // 如果有多张位图 }break; case MSG_CLOSEDSREQ: // 关闭数据源请求 case MSG_CLOSEDSOK: // 数据源成功关闭 case MSG_NULL: // 空消息 TRACE("MSG_CLOSEDSREQ or MSG_CLOSEDSOK or MSG_NULL)"); default: break; // 忽略 } // 如果是关闭请求,就退出外层循环 if (_twEvent.TWMessage != MSG_NULL) { TRACE("Break up from Message loop."); break; } } end_of_function: TRACE("Start to cleanup resources of thread."); // 关闭用户界面 memset(&_twUI, 0, sizeof(TW_USERINTERFACE)); _twUI.hParent = _hWnd; _twUI.ShowUI = TWON_DONTCARE8; _twRC = CallDSMEntry(&_dsmid , &_dsid , DG_CONTROL , DAT_USERINTERFACE , MSG_DISABLEDS , (TW_MEMREF)&_twUI); // 关闭数据源 _twRC = CallDSMEntry(&_dsmid , NULL , DG_CONTROL , DAT_IDENTITY , MSG_CLOSEDS , &_dsid); // 关闭数据源管理器 _twRC = CallDSMEntry(&_dsmid , NULL , DG_CONTROL , DAT_PARENT , MSG_CLOSEDSM , &_hWnd); // 关闭窗口 DestroyWindow(_hWnd); // 释放管理库 FreeLibrary(_hDSM); return 0; }