原始碼(串連另存新檔方式下載,重新命名為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;}