#include "HGTwainImpl.hpp" #include "../base/HGInc.h" #include "../base/HGInfo.h" #include "../base/HGUtility.h" #include "app_cfg.h" std::map HGTwainDSMImpl::m_mapWnd; HGTwainDSMImpl::HGTwainDSMImpl() { m_hDll = NULL; m_pDSMProc = NULL; m_AppId.Id = 0; // Initialize to 0 (Source Manager will assign real value) m_AppId.Version.MajorNum = 3; //Your app's version number m_AppId.Version.MinorNum = 8; m_AppId.Version.Language = TWLG_USA; m_AppId.Version.Country = TWCY_USA; strcpy(m_AppId.Version.Info, "3.8"); m_AppId.ProtocolMajor = TWON_PROTOCOLMAJOR; m_AppId.ProtocolMinor = TWON_PROTOCOLMINOR; m_AppId.SupportedGroups = DG_IMAGE | DG_CONTROL; strcpy(m_AppId.Manufacturer, "MICSS"); strcpy(m_AppId.ProductFamily, "Generic"); strcpy(m_AppId.ProductName, "MyTwain"); m_hWnd = NULL; m_oldWndProc = NULL; m_vds.clear(); } HGTwainDSMImpl::~HGTwainDSMImpl() { } HGResult HGTwainDSMImpl::Create(HWND hwnd) { assert(NULL == m_oldWndProc); if (NULL == hwnd) { return HGBASE_ERR_INVALIDARG; } assert(NULL == m_hDll); #ifdef _WIN64 HGBase_CreateDll("TWAINDSM.dll", &m_hDll); #else HGBase_CreateDll("twain_32.dll", &m_hDll); #endif if (NULL == m_hDll) { return HGBASE_ERR_FAIL; } assert(NULL == m_pDSMProc); HGBase_GetDllProcAddress(m_hDll, MAKEINTRESOURCEA(1), (HGPointer*)&m_pDSMProc); if (NULL == m_pDSMProc) { HGBase_DestroyDll(m_hDll); m_hDll = NULL; return HGBASE_ERR_FAIL; } USHORT ret = m_pDSMProc(&m_AppId, NULL, DG_CONTROL, DAT_PARENT, MSG_OPENDSM, (TW_MEMREF)&hwnd); if (TWRC_SUCCESS != ret) { m_pDSMProc = NULL; HGBase_DestroyDll(m_hDll); m_hDll = NULL; return HGTWAIN_ERR_FAIL; } m_hWnd = hwnd; m_mapWnd[m_hWnd] = this; m_oldWndProc = (WNDPROC)SetWindowLongPtrW(m_hWnd, GWLP_WNDPROC, (LONG_PTR)NewWndProc); TW_IDENTITY ds; if (TWRC_SUCCESS == m_pDSMProc(&m_AppId, NULL, DG_CONTROL, DAT_IDENTITY, MSG_GETFIRST, &ds)) { if (!filterTwainSource(ds.ProductName, ds.Version.MajorNum)) m_vds.push_back(ds); while (TWRC_SUCCESS == m_pDSMProc(&m_AppId, NULL, DG_CONTROL, DAT_IDENTITY, MSG_GETNEXT, &ds)) { if (!filterTwainSource(ds.ProductName, ds.Version.MajorNum)) m_vds.push_back(ds); } } return HGBASE_ERR_OK; } HGResult HGTwainDSMImpl::Destroy() { assert(NULL != m_oldWndProc); if (!m_listDSImpl.empty()) { return HGBASE_ERR_FAIL; } m_vds.clear(); m_pDSMProc(&m_AppId, NULL, DG_CONTROL, DAT_PARENT, MSG_CLOSEDSM, (TW_MEMREF)&m_hWnd); SetWindowLongPtrW(m_hWnd, GWLP_WNDPROC, (LONG_PTR)m_oldWndProc); m_oldWndProc = NULL; std::map::iterator iter; for (iter = m_mapWnd.begin(); iter != m_mapWnd.end(); ++iter) { if (iter->first == m_hWnd) { m_mapWnd.erase(iter); break; } } m_hWnd = NULL; m_pDSMProc = NULL; HGBase_DestroyDll(m_hDll); m_hDll = NULL; return HGBASE_ERR_OK; } HGResult HGTwainDSMImpl::GetDSCount(HGUInt* count) { if (NULL == count) { return HGBASE_ERR_INVALIDARG; } *count = m_vds.size(); return HGBASE_ERR_OK; } HGResult HGTwainDSMImpl::GetDSName(HGUInt index, HGChar* name, HGUInt maxLen) { if (NULL == name || 0 == maxLen) { return HGBASE_ERR_INVALIDARG; } if (index >= (HGUInt)m_vds.size()) return HGBASE_ERR_INVALIDARG; if (maxLen < strlen(m_vds[index].ProductName) + 1) return HGBASE_ERR_FAIL; strcpy(name, m_vds[index].ProductName); return HGBASE_ERR_OK; } HGResult HGTwainDSMImpl::CreateDS(HGUInt index, class HGTwainDSImpl** dsImpl) { if (NULL == dsImpl) { return HGBASE_ERR_INVALIDARG; } if (index >= (HGUInt)m_vds.size()) return HGBASE_ERR_INVALIDARG; class HGTwainDSImpl* newDSImpl = new HGTwainDSImpl(this, &m_vds[index]); std::string DSName = m_vds[index].ProductName; saveCfgValue("twain", "source", DSName); m_listDSImpl.push_back(newDSImpl); *dsImpl = newDSImpl; return HGBASE_ERR_OK; } HGResult HGTwainDSMImpl::CreateDefaultDS(class HGTwainDSImpl** dsImpl) { if (NULL == dsImpl) { return HGBASE_ERR_INVALIDARG; } if (m_vds.empty()) { return HGBASE_ERR_FAIL; } std::string sourceName = getCfgValue("twain", "source", std::string("")); int index = -1; for (int i = 0; i < m_vds.size(); ++i) { if (strcmp(m_vds[i].ProductName, sourceName.c_str()) == 0) { index = i; break; } } if (-1 == index) { index = 0; } class HGTwainDSImpl* newDSImpl = new HGTwainDSImpl(this, &m_vds[index]); std::string DSName = m_vds[index].ProductName; saveCfgValue("twain", "source", DSName); m_listDSImpl.push_back(newDSImpl); *dsImpl = newDSImpl; return HGBASE_ERR_OK; } HGResult HGTwainDSMImpl::CreateSelectedDS(class HGTwainDSImpl** dsImpl) { if (NULL == dsImpl) { return HGBASE_ERR_INVALIDARG; } TW_IDENTITY selectDS; if (TWRC_SUCCESS != m_pDSMProc(&m_AppId, NULL, DG_CONTROL, DAT_IDENTITY, MSG_USERSELECT, &selectDS)) { return HGTWAIN_ERR_CANCELUI; } class HGTwainDSImpl* newDSImpl = new HGTwainDSImpl(this, &selectDS); std::string DSName = selectDS.ProductName; saveCfgValue("twain", "source", DSName); m_listDSImpl.push_back(newDSImpl); *dsImpl = newDSImpl; return HGBASE_ERR_OK; } HGResult HGTwainDSMImpl::CreateSelectedDSEx(class HGTwainDSImpl** dsImpl) { if (NULL == dsImpl) { return HGBASE_ERR_INVALIDARG; } std::string sourceName = getCfgValue("twain", "source", std::string("")); TW_IDENTITY selectDS; memset(&selectDS, 0, sizeof(TW_IDENTITY)); if (-2 == show_twain_srclist_ui(&m_vds[0], m_vds.size(), sourceName.c_str(), m_hWnd, &selectDS)) { return HGBASE_ERR_NOTSUPPORT; } if (0 == selectDS.Id) { return HGTWAIN_ERR_CANCELUI; } class HGTwainDSImpl* newDSImpl = new HGTwainDSImpl(this, &selectDS); std::string DSName = selectDS.ProductName; saveCfgValue("twain", "source", DSName); m_listDSImpl.push_back(newDSImpl); *dsImpl = newDSImpl; return HGBASE_ERR_OK; } void HGTwainDSMImpl::RemoveDS(class HGTwainDSImpl* dsImpl) { std::vector::iterator iter; for (iter = m_listDSImpl.begin(); iter != m_listDSImpl.end(); ++iter) { if (*iter == dsImpl) { m_listDSImpl.erase(iter); delete dsImpl; break; } } } LRESULT CALLBACK HGTwainDSMImpl::NewWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { HGTwainDSMImpl* p = m_mapWnd[hWnd]; assert(NULL != p); MSG msg2 = { 0 }; msg2.hwnd = hWnd; msg2.message = msg; msg2.wParam = wParam; msg2.lParam = lParam; for (int i = 0; i < (int)p->m_listDSImpl.size(); ++i) { TW_EVENT twEvent; twEvent.pEvent = (TW_MEMREF)&msg2; twEvent.TWMessage = MSG_NULL; USHORT ret = p->m_pDSMProc(&p->m_AppId, &p->m_listDSImpl[i]->m_iden, DG_CONTROL, DAT_EVENT, MSG_PROCESSEVENT, (TW_MEMREF)&twEvent); if (TWRC_DSEVENT == ret) { if (MSG_XFERREADY == twEvent.TWMessage) { HGBase_SetEvent(p->m_listDSImpl[i]->m_event); } else if (MSG_CLOSEDSREQ == twEvent.TWMessage) { if (p->m_listDSImpl[i]->m_eventFunc) { p->m_listDSImpl[i]->m_eventFunc((HGTwainDS)p->m_listDSImpl[i], HGTWAIN_EVENT_TYPE_CLOSEDSREQ, p->m_listDSImpl[i]->m_eventParam); } } } } return CallWindowProcW(p->m_oldWndProc, hWnd, msg, wParam, lParam); } bool HGTwainDSMImpl::filterTwainSource(const char* sourceName, int majorNum) { #if !defined(OEM_HANWANG) && !defined(OEM_LISICHENG) && !defined(OEM_CANGTIAN) && !defined(OEM_ZHONGJING) && !defined(OEM_ZIGUANG) && !defined(OEM_NEUTRAL) && !defined(OEM_DELI) std::string oemIden = "HUAGOSCAN"; #elif defined(OEM_HANWANG) std::string oemIden = "Hanvon"; #elif defined(OEM_LISICHENG) std::string oemIden = "LANXUMSCAN"; #elif defined(OEM_CANGTIAN) std::string oemIden = "CUMTENN"; #elif defined(OEM_ZHONGJING) std::string oemIden = "Microtek"; #elif defined(OEM_ZIGUANG) std::string oemIden = "Uniscan"; #elif defined(OEM_NEUTRAL) std::string oemIden = "NeuScan"; #elif defined(OEM_DELI) std::string oemIden = "DELI SCAN"; #endif if (sourceName != strstr(sourceName, oemIden.c_str()) || 4 != majorNum) { return true; } return false; } HGTwainDSImpl::HGTwainDSImpl(HGTwainDSMImpl* dsmImpl, TW_IDENTITY* iden) { m_dsmImpl = dsmImpl; assert(NULL != iden); memcpy(&m_iden, iden, sizeof(TW_IDENTITY)); m_open = HGFALSE; m_singleScan = HGFALSE; m_oldXferCount = -1; m_showUI = HGFALSE; m_parent = NULL; m_eventFunc = NULL; m_eventParam = NULL; m_imageFunc = NULL; m_imageParam = NULL; m_event = NULL; m_stopThread = HGFALSE; m_thread = NULL; } HGTwainDSImpl::~HGTwainDSImpl() { } HGResult HGTwainDSImpl::Destroy() { Close(); m_dsmImpl->RemoveDS(this); return HGBASE_ERR_OK; } HGResult HGTwainDSImpl::Open() { if (m_open) { return HGTWAIN_ERR_FAIL; } USHORT ret = m_dsmImpl->m_pDSMProc(&m_dsmImpl->m_AppId, NULL, DG_CONTROL, DAT_IDENTITY, MSG_OPENDS, &m_iden); if (TWRC_SUCCESS != ret) { return HGTWAIN_ERR_FAIL; } HGBase_CreateEvent(HGFALSE, HGFALSE, &m_event); m_stopThread = HGFALSE; HGBase_OpenThread(ThreadFunc, this, &m_thread); m_open = HGTRUE; return HGBASE_ERR_OK; } HGResult HGTwainDSImpl::Close() { if (!m_open) { return HGTWAIN_ERR_FAIL; } Disable(); m_dsmImpl->m_pDSMProc(&m_dsmImpl->m_AppId, NULL, DG_CONTROL, DAT_IDENTITY, MSG_CLOSEDS, (TW_MEMREF)&m_iden); m_stopThread = HGTRUE; HGBase_SetEvent(m_event); HGBase_CloseThread(m_thread); m_thread = NULL; HGBase_DestroyEvent(m_event); m_event = NULL; m_open = HGFALSE; return HGBASE_ERR_OK; } HGResult HGTwainDSImpl::GetName(HGChar* name, HGUInt maxLen) { if (NULL == name || 0 == maxLen) { return HGBASE_ERR_INVALIDARG; } if (maxLen < strlen(m_iden.ProductName) + 1) return HGBASE_ERR_FAIL; strcpy(name, m_iden.ProductName); return HGBASE_ERR_OK; } HGResult HGTwainDSImpl::GetDeviceName(HGChar* name, HGUInt maxLen) { if (NULL == name || 0 == maxLen) { return HGBASE_ERR_INVALIDARG; } HGCapValue value; HGResult ret = GetCapbility(0x8854, &value); if (HGBASE_ERR_OK == ret) { if (value.type == HGCAPVALUE_TYPE_STR32) strcpy(name, value.valueStr32); else if (value.type == HGCAPVALUE_TYPE_STR64) strcpy(name, value.valueStr64); else if (value.type == HGCAPVALUE_TYPE_STR128) strcpy(name, value.valueStr128); else if (value.type == HGCAPVALUE_TYPE_STR255) strcpy(name, value.valueStr255); } return ret; } HGResult HGTwainDSImpl::GetDeviceCustomInfo(HGTwainDeviceCustomInfo *info) { if (NULL == info) { return HGBASE_ERR_INVALIDARG; } memset(info, 0, sizeof(HGTwainDeviceCustomInfo)); HGCapValue value; GetCapbility(0x8852, &value); info->vid = value.valueInt; GetCapbility(0x8853, &value); info->pid = value.valueInt; GetCapbility(0x8856, &value); strcpy(info->sn, value.valueStr255); GetCapbility(0x8855, &value); strcpy(info->type, value.valueStr255); GetCapbility(0x8857, &value); strcpy(info->fwVer, value.valueStr255); GetCapbility(0x8858, &value); strcpy(info->ip, value.valueStr255); GetCapbility(0x8859, &value); strcpy(info->mac, value.valueStr255); GetCapbility(0x884A, &value); strcpy(info->driverVer, value.valueStr255); GetCapbility(0x884B, &value); strcpy(info->vendor, value.valueStr255); GetCapbility(0x884C, &value); strcpy(info->copyright, value.valueStr255); GetCapbility(0x884D, &value); strcpy(info->comUrl, value.valueStr255); GetCapbility(0x884E, &value); strcpy(info->comTel, value.valueStr255); GetCapbility(0x884F, &value); strcpy(info->comAddr, value.valueStr255); GetCapbility(0x8850, &value); strcpy(info->comGps, value.valueStr255); GetCapbility(0x9902, &value); info->rollerCount = value.valueInt; GetCapbility(0x8849, &value); info->totalCount = value.valueInt; return HGBASE_ERR_OK; } #pragma pack(push) #pragma pack(1) struct LoginType { TW_UINT16 ItemType; TW_UINT32 NumItems; TW_STR32 Value[2]; }; #pragma pack(pop) HGResult HGTwainDSImpl::Login(const HGChar *user, const HGChar *pwd) { if (NULL == user || strlen(user) >= sizeof(TW_STR32) || NULL == pwd || strlen(pwd) >= sizeof(TW_STR32)) { return HGBASE_ERR_INVALIDARG; } TW_CAPABILITY twCap; twCap.Cap = (TW_UINT16)0x9900; twCap.ConType = TWON_ARRAY; twCap.hContainer = GlobalAlloc(GHND, sizeof(LoginType)); if (NULL == twCap.hContainer) { return HGBASE_ERR_FAIL; } LoginType *pVal = (LoginType *)GlobalLock(twCap.hContainer); assert(NULL != pVal); pVal->ItemType = TWTY_STR32; pVal->NumItems = 2; strcpy(pVal->Value[0], user); strcpy(pVal->Value[1], pwd); GlobalUnlock(twCap.hContainer); USHORT ret = m_dsmImpl->m_pDSMProc(&m_dsmImpl->m_AppId, &m_iden, DG_CONTROL, DAT_CAPABILITY, MSG_SET, &twCap); GlobalFree(twCap.hContainer); return (TWRC_SUCCESS == ret) ? HGBASE_ERR_OK : HGTWAIN_ERR_FAIL; } HGResult HGTwainDSImpl::Logout() { TW_CAPABILITY twCap; twCap.Cap = (TW_UINT16)0x9901; twCap.ConType = TWON_ARRAY; twCap.hContainer = GlobalAlloc(GHND, sizeof(LoginType)); if (NULL == twCap.hContainer) { return HGBASE_ERR_FAIL; } LoginType *pVal = (LoginType *)GlobalLock(twCap.hContainer); assert(NULL != pVal); pVal->ItemType = TWTY_STR32; pVal->NumItems = 2; memset(pVal->Value[0], 0, sizeof(pVal->Value[0])); memset(pVal->Value[1], 0, sizeof(pVal->Value[1])); GlobalUnlock(twCap.hContainer); USHORT ret = m_dsmImpl->m_pDSMProc(&m_dsmImpl->m_AppId, &m_iden, DG_CONTROL, DAT_CAPABILITY, MSG_SET, &twCap); GlobalFree(twCap.hContainer); return (TWRC_SUCCESS == ret) ? HGBASE_ERR_OK : HGTWAIN_ERR_FAIL; } HGResult HGTwainDSImpl::ClearRollerCount() { HGCapValue value; value.type = HGCAPVALUE_TYPE_INT; value.valueInt = 0; return SetCapbility(0x9902, &value, true); } #pragma pack(push) #pragma pack(1) struct CapInt8Type { TW_UINT16 ItemType; TW_INT8 Value; }; struct CapInt16Type { TW_UINT16 ItemType; TW_INT16 Value; }; struct CapInt32Type { TW_UINT16 ItemType; TW_INT32 Value; }; struct CapUInt8Type { TW_UINT16 ItemType; TW_UINT8 Value; }; struct CapUInt16Type { TW_UINT16 ItemType; TW_UINT16 Value; }; struct CapUInt32Type { TW_UINT16 ItemType; TW_UINT32 Value; }; struct CapBoolType { TW_UINT16 ItemType; TW_BOOL Value; }; struct CapFix32Type { TW_UINT16 ItemType; TW_FIX32 Value; }; struct CapStr32Type { TW_UINT16 ItemType; TW_STR32 Value; }; struct CapStr64Type { TW_UINT16 ItemType; TW_STR64 Value; }; struct CapStr128Type { TW_UINT16 ItemType; TW_STR128 Value; }; struct CapStr255Type { TW_UINT16 ItemType; TW_STR255 Value; }; #pragma pack(pop) HGResult HGTwainDSImpl::GetDriverLog(const HGChar *fileName) { if (NULL == fileName || strlen(fileName) >= sizeof(TW_STR255)) { return HGBASE_ERR_INVALIDARG; } TW_CAPABILITY twCap; twCap.Cap = (TW_UINT16)0x9903; twCap.ConType = TWON_ONEVALUE; twCap.hContainer = GlobalAlloc(GHND, sizeof(CapStr255Type)); if (NULL == twCap.hContainer) { return HGBASE_ERR_FAIL; } CapStr255Type* pVal = (CapStr255Type*)GlobalLock(twCap.hContainer); assert(NULL != pVal); pVal->ItemType = TWTY_STR255; strcpy(pVal->Value, fileName); GlobalUnlock(twCap.hContainer); USHORT ret = m_dsmImpl->m_pDSMProc(&m_dsmImpl->m_AppId, &m_iden, DG_CONTROL, DAT_CAPABILITY, MSG_GETCURRENT, &twCap); GlobalFree(twCap.hContainer); return (TWRC_SUCCESS == ret) ? HGBASE_ERR_OK : HGTWAIN_ERR_FAIL; } HGResult HGTwainDSImpl::ClearDriverLog() { HGCapValue value; value.type = HGCAPVALUE_TYPE_STR255; return SetCapbility(0x9903, &value, true); } HGResult HGTwainDSImpl::GetDeviceLog(const HGChar *fileName) { if (NULL == fileName || strlen(fileName) >= sizeof(TW_STR255)) { return HGBASE_ERR_INVALIDARG; } TW_CAPABILITY twCap; twCap.Cap = (TW_UINT16)0x9904; twCap.ConType = TWON_ONEVALUE; twCap.hContainer = GlobalAlloc(GHND, sizeof(CapStr255Type)); if (NULL == twCap.hContainer) { return HGBASE_ERR_FAIL; } CapStr255Type* pVal = (CapStr255Type*)GlobalLock(twCap.hContainer); assert(NULL != pVal); pVal->ItemType = TWTY_STR255; strcpy(pVal->Value, fileName); GlobalUnlock(twCap.hContainer); USHORT ret = m_dsmImpl->m_pDSMProc(&m_dsmImpl->m_AppId, &m_iden, DG_CONTROL, DAT_CAPABILITY, MSG_GETCURRENT, &twCap); GlobalFree(twCap.hContainer); return (TWRC_SUCCESS == ret) ? HGBASE_ERR_OK : HGTWAIN_ERR_FAIL; } HGResult HGTwainDSImpl::ClearDeviceLog() { HGCapValue value; value.type = HGCAPVALUE_TYPE_STR255; return SetCapbility(0x9904, &value, true); } HGResult HGTwainDSImpl::EnableUIOnly(HWND parent, HGDSEventFunc eventFunc, HGPointer eventParam) { TW_USERINTERFACE twUI; twUI.ShowUI = (TW_BOOL)HGTRUE; twUI.hParent = (TW_HANDLE)parent; USHORT ret = m_dsmImpl->m_pDSMProc(&m_dsmImpl->m_AppId, &m_iden, DG_CONTROL, DAT_USERINTERFACE, MSG_ENABLEDSUIONLY, (TW_MEMREF)&twUI); if (TWRC_SUCCESS != ret) { TW_STATUS status; m_dsmImpl->m_pDSMProc(&m_dsmImpl->m_AppId, &m_iden, DG_CONTROL, DAT_STATUS, MSG_GET, (TW_MEMREF)&status); if (status.ConditionCode == TWCC_CHECKDEVICEONLINE) return HGTWAIN_ERR_DEVICEOFFLINE; return HGTWAIN_ERR_FAIL; } m_showUI = HGTRUE; m_parent = parent; m_eventFunc = eventFunc; m_eventParam = eventParam; m_imageFunc = NULL; m_imageParam = NULL; return HGBASE_ERR_OK; } HGResult HGTwainDSImpl::Enable(HGBool showUI, HWND parent, HGDSEventFunc eventFunc, HGPointer eventParam, HGDSImageFunc imageFunc, HGPointer imageParam) { TW_USERINTERFACE twUI; twUI.ShowUI = (TW_BOOL)showUI; twUI.hParent = (TW_HANDLE)parent; USHORT ret = m_dsmImpl->m_pDSMProc(&m_dsmImpl->m_AppId, &m_iden, DG_CONTROL, DAT_USERINTERFACE, MSG_ENABLEDS, (TW_MEMREF)&twUI); if (TWRC_SUCCESS != ret) { TW_STATUS status; m_dsmImpl->m_pDSMProc(&m_dsmImpl->m_AppId, &m_iden, DG_CONTROL, DAT_STATUS, MSG_GET, (TW_MEMREF)&status); if (status.ConditionCode == TWCC_CHECKDEVICEONLINE) return HGTWAIN_ERR_DEVICEOFFLINE; return HGTWAIN_ERR_FAIL; } m_showUI = showUI; m_parent = parent; m_eventFunc = eventFunc; m_eventParam = eventParam; m_imageFunc = imageFunc; m_imageParam = imageParam; return HGBASE_ERR_OK; } HGResult HGTwainDSImpl::EnableWithSingleScan(HWND parent, HGDSEventFunc eventFunc, HGPointer eventParam, HGDSImageFunc imageFunc, HGPointer imageParam) { HGCapValue value; HGResult ret = GetCapbility(CAP_XFERCOUNT, &value); HGInt oldXferCount = value.valueInt; if (HGBASE_ERR_OK != ret) { TW_STATUS status; m_dsmImpl->m_pDSMProc(&m_dsmImpl->m_AppId, &m_iden, DG_CONTROL, DAT_STATUS, MSG_GET, (TW_MEMREF)&status); if (status.ConditionCode == TWCC_CHECKDEVICEONLINE) return HGTWAIN_ERR_DEVICEOFFLINE; return ret; } HGCapValue value2; value2.type = HGCAPVALUE_TYPE_SHORT; value2.valueInt = 1; ret = SetCapbility(CAP_XFERCOUNT, &value2, false); if (HGBASE_ERR_OK != ret) { TW_STATUS status; m_dsmImpl->m_pDSMProc(&m_dsmImpl->m_AppId, &m_iden, DG_CONTROL, DAT_STATUS, MSG_GET, (TW_MEMREF)&status); if (status.ConditionCode == TWCC_CHECKDEVICEONLINE) return HGTWAIN_ERR_DEVICEOFFLINE; return ret; } TW_USERINTERFACE twUI; twUI.ShowUI = (TW_BOOL)HGFALSE; twUI.hParent = (TW_HANDLE)parent; if (TWRC_SUCCESS != m_dsmImpl->m_pDSMProc(&m_dsmImpl->m_AppId, &m_iden, DG_CONTROL, DAT_USERINTERFACE, MSG_ENABLEDS, (TW_MEMREF)&twUI)) { HGCapValue value3; value3.type = HGCAPVALUE_TYPE_SHORT; value3.valueInt = oldXferCount; SetCapbility(CAP_XFERCOUNT, &value3, false); TW_STATUS status; m_dsmImpl->m_pDSMProc(&m_dsmImpl->m_AppId, &m_iden, DG_CONTROL, DAT_STATUS, MSG_GET, (TW_MEMREF)&status); if (status.ConditionCode == TWCC_CHECKDEVICEONLINE) return HGTWAIN_ERR_DEVICEOFFLINE; return HGTWAIN_ERR_FAIL; } m_singleScan = HGTRUE; m_oldXferCount = oldXferCount; m_showUI = HGFALSE; m_parent = parent; m_eventFunc = eventFunc; m_eventParam = eventParam; m_imageFunc = imageFunc; m_imageParam = imageParam; return HGBASE_ERR_OK; } HGResult HGTwainDSImpl::Disable() { TW_USERINTERFACE twUI; twUI.ShowUI = (TW_BOOL)m_showUI; twUI.hParent = (TW_HANDLE)m_parent; m_dsmImpl->m_pDSMProc(&m_dsmImpl->m_AppId, &m_iden, DG_CONTROL, DAT_USERINTERFACE, MSG_DISABLEDS, &twUI); if (m_singleScan) { HGCapValue value; value.type = HGCAPVALUE_TYPE_SHORT; value.valueInt = m_oldXferCount; SetCapbility(CAP_XFERCOUNT, &value, false); } m_singleScan = FALSE; m_oldXferCount = -1; m_showUI = HGFALSE; m_parent = NULL; m_eventFunc = NULL; m_eventParam = NULL; m_imageFunc = NULL; m_imageParam = NULL; return HGBASE_ERR_OK; } HGResult HGTwainDSImpl::SetCapbility(HGUShort cap, const HGCapValue* value, HGBool reset) { TW_CAPABILITY twCap; twCap.Cap = (TW_UINT16)cap; twCap.ConType = TWON_ONEVALUE; twCap.hContainer = NULL; HGInt size = 0; TW_UINT16 itemType = 0; if (HGCAPVALUE_TYPE_CHAR == value->type) { size = sizeof(CapInt8Type); itemType = TWTY_INT8; } else if (HGCAPVALUE_TYPE_BYTE == value->type) { size = sizeof(CapUInt8Type); itemType = TWTY_UINT8; } else if (HGCAPVALUE_TYPE_SHORT == value->type) { size = sizeof(CapInt16Type); itemType = TWTY_INT16; } else if (HGCAPVALUE_TYPE_USHORT == value->type) { size = sizeof(CapUInt16Type); itemType = TWTY_UINT16; } else if (HGCAPVALUE_TYPE_INT == value->type) { size = sizeof(CapInt32Type); itemType = TWTY_INT32; } else if (HGCAPVALUE_TYPE_UINT == value->type) { size = sizeof(CapUInt32Type); itemType = TWTY_UINT32; } else if (HGCAPVALUE_TYPE_BOOL == value->type) { size = sizeof(CapBoolType); itemType = TWTY_BOOL; } else if (HGCAPVALUE_TYPE_FLOAT == value->type) { size = sizeof(CapFix32Type); itemType = TWTY_FIX32; } else if (HGCAPVALUE_TYPE_STR32 == value->type) { size = sizeof(CapStr32Type); itemType = TWTY_STR32; } else if (HGCAPVALUE_TYPE_STR64 == value->type) { size = sizeof(CapStr64Type); itemType = TWTY_STR64; } else if (HGCAPVALUE_TYPE_STR128 == value->type) { size = sizeof(CapStr128Type); itemType = TWTY_STR128; } else if (HGCAPVALUE_TYPE_STR255 == value->type) { size = sizeof(CapStr255Type); itemType = TWTY_STR255; } twCap.hContainer = GlobalAlloc(GHND, size); if (NULL == twCap.hContainer) { return HGBASE_ERR_FAIL; } void* pVal = GlobalLock(twCap.hContainer); assert(NULL != pVal); if (HGCAPVALUE_TYPE_CHAR == value->type) { ((CapInt8Type*)pVal)->ItemType = itemType; ((CapInt8Type*)pVal)->Value = value->valueChar; } else if (HGCAPVALUE_TYPE_BYTE == value->type) { ((CapUInt8Type*)pVal)->ItemType = itemType; ((CapUInt8Type*)pVal)->Value = value->valueByte; } else if (HGCAPVALUE_TYPE_SHORT == value->type) { ((CapInt16Type*)pVal)->ItemType = itemType; ((CapInt16Type*)pVal)->Value = value->valueShort; } else if (HGCAPVALUE_TYPE_USHORT == value->type) { ((CapUInt16Type*)pVal)->ItemType = itemType; ((CapUInt16Type*)pVal)->Value = value->valueUShort; } else if (HGCAPVALUE_TYPE_INT == value->type) { ((CapInt32Type*)pVal)->ItemType = itemType; ((CapInt32Type*)pVal)->Value = value->valueInt; } else if (HGCAPVALUE_TYPE_UINT == value->type) { ((CapUInt32Type*)pVal)->ItemType = itemType; ((CapUInt32Type*)pVal)->Value = value->valueUInt; } else if (HGCAPVALUE_TYPE_BOOL == value->type) { ((CapBoolType*)pVal)->ItemType = itemType; ((CapBoolType*)pVal)->Value = value->valueBool; } else if (HGCAPVALUE_TYPE_FLOAT == value->type) { ((CapFix32Type*)pVal)->ItemType = itemType; ((CapFix32Type*)pVal)->Value = FloatToFIX32(value->valueFloat); } else if (HGCAPVALUE_TYPE_STR32 == value->type) { assert(NULL != pVal); ((CapStr32Type*)pVal)->ItemType = itemType; if (reset) memset(((CapStr32Type*)pVal)->Value, 0, sizeof(((CapStr32Type*)pVal)->Value)); else strcpy(((CapStr32Type*)pVal)->Value, value->valueStr32); } else if (HGCAPVALUE_TYPE_STR64 == value->type) { assert(NULL != pVal); ((CapStr64Type*)pVal)->ItemType = itemType; if (reset) memset(((CapStr64Type*)pVal)->Value, 0, sizeof(((CapStr64Type*)pVal)->Value)); else strcpy(((CapStr64Type*)pVal)->Value, value->valueStr64); } else if (HGCAPVALUE_TYPE_STR128 == value->type) { assert(NULL != pVal); ((CapStr128Type*)pVal)->ItemType = itemType; if (reset) memset(((CapStr128Type*)pVal)->Value, 0, sizeof(((CapStr128Type*)pVal)->Value)); else strcpy(((CapStr128Type*)pVal)->Value, value->valueStr128); } else if (HGCAPVALUE_TYPE_STR255 == value->type) { assert(NULL != pVal); ((CapStr255Type*)pVal)->ItemType = itemType; if (reset) memset(((CapStr255Type*)pVal)->Value, 0, sizeof(((CapStr255Type*)pVal)->Value)); else strcpy(((CapStr255Type*)pVal)->Value, value->valueStr255); } GlobalUnlock(twCap.hContainer); USHORT ret = m_dsmImpl->m_pDSMProc(&m_dsmImpl->m_AppId, &m_iden, DG_CONTROL, DAT_CAPABILITY, reset ? MSG_RESET : MSG_SET, &twCap); GlobalFree(twCap.hContainer); return (TWRC_SUCCESS == ret) ? HGBASE_ERR_OK : HGTWAIN_ERR_FAIL; } HGResult HGTwainDSImpl::GetCapbility(HGUShort cap, HGCapValue* value) { if (NULL == value) { return HGBASE_ERR_INVALIDARG; } TW_CAPABILITY twCap; twCap.Cap = (TW_UINT16)cap; twCap.ConType = TWON_ONEVALUE; twCap.hContainer = NULL; if (TWRC_SUCCESS != m_dsmImpl->m_pDSMProc(&m_dsmImpl->m_AppId, &m_iden, DG_CONTROL, DAT_CAPABILITY, MSG_GETCURRENT, &twCap)) { return HGTWAIN_ERR_FAIL; } HGResult ret = HGBASE_ERR_FAIL; assert(NULL != twCap.hContainer); void* pVal = GlobalLock(twCap.hContainer); if (NULL != pVal) { TW_UINT16 ItemType = *(TW_UINT16*)pVal; if (ItemType == TWTY_INT8) { value->type = HGCAPVALUE_TYPE_CHAR; value->valueChar = ((CapInt8Type*)pVal)->Value; ret = HGBASE_ERR_OK; } else if (ItemType == TWTY_UINT8) { value->type = HGCAPVALUE_TYPE_BYTE; value->valueByte = ((CapUInt8Type*)pVal)->Value; ret = HGBASE_ERR_OK; } else if (ItemType == TWTY_INT16) { value->type = HGCAPVALUE_TYPE_SHORT; value->valueShort = ((CapInt16Type*)pVal)->Value; ret = HGBASE_ERR_OK; } else if (ItemType == TWTY_UINT16) { value->type = HGCAPVALUE_TYPE_USHORT; value->valueUShort = ((CapUInt16Type*)pVal)->Value; ret = HGBASE_ERR_OK; } else if (ItemType == TWTY_INT32) { value->type = HGCAPVALUE_TYPE_INT; value->valueInt = ((CapInt32Type*)pVal)->Value; ret = HGBASE_ERR_OK; } else if (ItemType == TWTY_UINT32) { value->type = HGCAPVALUE_TYPE_UINT; value->valueUInt = ((CapUInt32Type*)pVal)->Value; ret = HGBASE_ERR_OK; } else if (ItemType == TWTY_BOOL) { value->type = HGCAPVALUE_TYPE_BOOL; value->valueBool = ((CapBoolType*)pVal)->Value; ret = HGBASE_ERR_OK; } else if (ItemType == TWTY_FIX32) { value->type = HGCAPVALUE_TYPE_FLOAT; value->valueFloat = FIX32ToFloat(((CapFix32Type*)pVal)->Value); ret = HGBASE_ERR_OK; } else if (ItemType == TWTY_STR32) { if (32 > strlen(((CapStr32Type*)pVal)->Value)) { value->type = HGCAPVALUE_TYPE_STR32; strcpy(value->valueStr32, ((CapStr32Type*)pVal)->Value); ret = HGBASE_ERR_OK; } else { ret = HGBASE_ERR_INVALIDARG; } } else if (ItemType == TWTY_STR64) { if (64 > strlen(((CapStr64Type*)pVal)->Value)) { value->type = HGCAPVALUE_TYPE_STR64; strcpy(value->valueStr64, ((CapStr64Type*)pVal)->Value); ret = HGBASE_ERR_OK; } else { ret = HGBASE_ERR_INVALIDARG; } } else if (ItemType == TWTY_STR128) { if (128 > strlen(((CapStr128Type*)pVal)->Value)) { value->type = HGCAPVALUE_TYPE_STR128; strcpy(value->valueStr128, ((CapStr128Type*)pVal)->Value); ret = HGBASE_ERR_OK; } else { ret = HGBASE_ERR_INVALIDARG; } } else if (ItemType == TWTY_STR255) { if (255 > strlen(((CapStr255Type*)pVal)->Value)) { value->type = HGCAPVALUE_TYPE_STR255; strcpy(value->valueStr255, ((CapStr255Type*)pVal)->Value); ret = HGBASE_ERR_OK; } else { ret = HGBASE_ERR_INVALIDARG; } } GlobalUnlock(twCap.hContainer); } GlobalFree(twCap.hContainer); return ret; } HGResult HGTwainDSImpl::ImageNativeXfer(HGUInt type, HGUInt origin, HGImage* image) { if (NULL == image) { return HGBASE_ERR_INVALIDARG; } TW_IMAGEINFO info; if (TWRC_SUCCESS != m_dsmImpl->m_pDSMProc(&m_dsmImpl->m_AppId, &m_iden, DG_IMAGE, DAT_IMAGEINFO, MSG_GET, (TW_MEMREF)&info)) { return HGTWAIN_ERR_FAIL; } #ifdef _WIN64 HANDLE hMem = NULL; if (TWRC_XFERDONE != m_dsmImpl->m_pDSMProc(&m_dsmImpl->m_AppId, &m_iden, DG_IMAGE, DAT_IMAGENATIVEXFER, MSG_GET, &hMem)) { return HGTWAIN_ERR_FAIL; } HGStream stream = NULL; HGResult ret = HGBase_CreateDIBStream(hMem, &stream); GlobalFree(hMem); if (HGBASE_ERR_OK != ret) { return ret; } ret = HGBase_CreateImageFromStream(stream, NULL, type, origin, image); HGBase_DestroyStream(stream); #else HGChar tmpFile[260]; HGBase_GetTmpFileName("bmp", tmpFile, 260); TW_SETUPFILEXFER xfer = {0}; strcpy(xfer.FileName, tmpFile); xfer.Format = TWFF_BMP; if (TWRC_SUCCESS != m_dsmImpl->m_pDSMProc(&m_dsmImpl->m_AppId, &m_iden, DG_CONTROL, DAT_SETUPFILEXFER, MSG_SET, &xfer)) { return HGTWAIN_ERR_FAIL; } if (TWRC_XFERDONE != m_dsmImpl->m_pDSMProc(&m_dsmImpl->m_AppId, &m_iden, DG_IMAGE, DAT_IMAGEFILEXFER, MSG_GET, NULL)) { return HGTWAIN_ERR_FAIL; } HGResult ret = HGBase_CreateImageFromFile(tmpFile, NULL, type, origin, image); HGBase_DeleteFile(tmpFile); #endif return ret; } HGResult HGTwainDSImpl::EndXfer(HGUInt* count) { if (NULL == count) { return HGBASE_ERR_INVALIDARG; } TW_PENDINGXFERS twPend; USHORT ret = m_dsmImpl->m_pDSMProc(&m_dsmImpl->m_AppId, &m_iden, DG_CONTROL, DAT_PENDINGXFERS, MSG_ENDXFER, (TW_MEMREF)&twPend); if (TWRC_SUCCESS != ret) { return HGTWAIN_ERR_FAIL; } *count = twPend.Count; return HGBASE_ERR_OK; } HGResult HGTwainDSImpl::Reset() { TW_PENDINGXFERS twPend; USHORT ret = m_dsmImpl->m_pDSMProc(&m_dsmImpl->m_AppId, &m_iden, DG_CONTROL, DAT_PENDINGXFERS, MSG_RESET, (TW_MEMREF)&twPend); if (TWRC_SUCCESS != ret) { return HGTWAIN_ERR_FAIL; } return HGBASE_ERR_OK; } TW_FIX32 HGTwainDSImpl::FloatToFIX32(float i_float) { TW_FIX32 Fix32_value; TW_INT32 value = (TW_INT32)(i_float * 65536.0 + 0.5); Fix32_value.Whole = LOWORD(value >> 16); Fix32_value.Frac = LOWORD(value & 0x0000ffffL); return Fix32_value; } float HGTwainDSImpl::FIX32ToFloat(TW_FIX32 FIX32Value) { TW_INT16 whole = FIX32Value.Whole; TW_UINT16 frac = FIX32Value.Frac; return (float)(whole << 16 | frac) / 65536.0; } void HGAPI HGTwainDSImpl::ThreadFunc(HGThread thread, HGPointer param) { (void)thread; HGTwainDSImpl *p = (HGTwainDSImpl *)param; while (!p->m_stopThread) { HGBase_WaitEvent(p->m_event); if (NULL != p->m_eventFunc) p->m_eventFunc((HGTwainDS)p, HGTWAIN_EVENT_TYPE_WORKING, p->m_eventParam); while (1) { HGImage image = NULL; p->ImageNativeXfer(0, 0, &image); if (NULL != image) { if (NULL != p->m_imageFunc) { HGUInt imgRet = p->m_imageFunc((HGTwainDS)p, image, HGTWAIN_IMAGE_TYPE_NORMAL, p->m_imageParam); assert(HGBASE_ERR_OK == imgRet); } HGBase_DestroyImage(image); } HGUInt count = 0; p->EndXfer(&count); if (0 == count) { break; } } if (NULL != p->m_eventFunc) p->m_eventFunc((HGTwainDS)p, HGTWAIN_EVENT_TYPE_SCANFINISHED, p->m_eventParam); } }