源代码(连接另存为方式下载,重命名为zip文件再解压就可以到到源文件了)
下载链接http://hi.youkuaiyun.com/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;
}