#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; } return GetCapStr255(0x8854, name, maxLen); } HGResult HGTwainDSImpl::GetDeviceCustomInfo(HGTwainDeviceCustomInfo *info) { if (NULL == info) { return HGBASE_ERR_INVALIDARG; } memset(info, 0, sizeof(HGTwainDeviceCustomInfo)); GetCapInt(0x8852, &info->vid); GetCapInt(0x8853, &info->pid); GetCapStr255(0x8856, info->sn, sizeof(info->sn)); GetCapStr255(0x8855, info->type, sizeof(info->type)); GetCapStr255(0x8857, info->fwVer, sizeof(info->fwVer)); GetCapStr255(0x8858, info->ip, sizeof(info->ip)); GetCapStr255(0x8859, info->mac, sizeof(info->mac)); GetCapStr255(0x884A, info->driverVer, sizeof(info->driverVer)); GetCapStr255(0x884B, info->vendor, sizeof(info->vendor)); GetCapStr255(0x884C, info->copyright, sizeof(info->copyright)); GetCapStr255(0x884D, info->comUrl, sizeof(info->comUrl)); GetCapStr255(0x884E, info->comTel, sizeof(info->comTel)); GetCapStr255(0x884F, info->comAddr, sizeof(info->comAddr)); GetCapStr255(0x8850, info->comGps, sizeof(info->comGps)); GetCapInt(0x9902, &info->rollerCount); GetCapInt(0x8849, &info->totalCount); 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() { return ResetCapInt(0x9902, TWTY_INT32); } #pragma pack(push) #pragma pack(1) 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() { return ResetCapStr255(0x9903); } 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() { return ResetCapStr255(0x9904); } 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) { 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) { HGInt oldXferCount = -1; HGResult ret = GetCapInt(CAP_XFERCOUNT, &oldXferCount); if (HGBASE_ERR_OK != ret) { return ret; } ret = SetCapInt(CAP_XFERCOUNT, TWTY_INT16, 1); if (HGBASE_ERR_OK != ret) { 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)) { 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) { SetCapInt(CAP_XFERCOUNT, TWTY_INT16, m_oldXferCount); } 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; } #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; }; #pragma pack(pop) HGResult HGTwainDSImpl::SetCapInt(HGUInt cap, TW_UINT16 itemType, HGInt value) { TW_CAPABILITY twCap; twCap.Cap = (TW_UINT16)cap; twCap.ConType = TWON_ONEVALUE; DWORD size = sizeof(CapInt32Type); if (itemType == TWTY_INT8) size = sizeof(CapInt8Type); else if (itemType == TWTY_INT16) size = sizeof(CapInt16Type); twCap.hContainer = GlobalAlloc(GHND, size); if (NULL == twCap.hContainer) { return HGBASE_ERR_FAIL; } void* pVal = GlobalLock(twCap.hContainer); assert(NULL != pVal); if (itemType == TWTY_INT8) { ((CapInt8Type*)pVal)->ItemType = TWTY_INT8; ((CapInt8Type*)pVal)->Value = (TW_INT8)value; } else if (itemType == TWTY_INT16) { ((CapInt16Type*)pVal)->ItemType = TWTY_INT16; ((CapInt16Type*)pVal)->Value = (TW_INT16)value; } else { ((CapInt32Type*)pVal)->ItemType = TWTY_INT32; ((CapInt32Type*)pVal)->Value = (TW_INT32)value; } 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::ResetCapInt(HGUInt cap, TW_UINT16 itemType) { TW_CAPABILITY twCap; twCap.Cap = (TW_UINT16)cap; twCap.ConType = TWON_ONEVALUE; DWORD size = sizeof(CapInt32Type); if (itemType == TWTY_INT8) size = sizeof(CapInt8Type); else if (itemType == TWTY_INT16) size = sizeof(CapInt16Type); twCap.hContainer = GlobalAlloc(GHND, size); if (NULL == twCap.hContainer) { return HGBASE_ERR_FAIL; } void* pVal = GlobalLock(twCap.hContainer); assert(NULL != pVal); if (itemType == TWTY_INT8) { ((CapInt8Type*)pVal)->ItemType = TWTY_INT8; ((CapInt8Type*)pVal)->Value = 0; } else if (itemType == TWTY_INT16) { ((CapInt16Type*)pVal)->ItemType = TWTY_INT16; ((CapInt16Type*)pVal)->Value = 0; } else { ((CapInt32Type*)pVal)->ItemType = TWTY_INT32; ((CapInt32Type*)pVal)->Value = 0; } GlobalUnlock(twCap.hContainer); USHORT ret = m_dsmImpl->m_pDSMProc(&m_dsmImpl->m_AppId, &m_iden, DG_CONTROL, DAT_CAPABILITY, MSG_RESET, &twCap); GlobalFree(twCap.hContainer); return (TWRC_SUCCESS == ret) ? HGBASE_ERR_OK : HGTWAIN_ERR_FAIL; } HGResult HGTwainDSImpl::GetCapInt(HGUInt cap, HGInt* 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 = ((CapInt8Type*)pVal)->Value; ret = HGBASE_ERR_OK; } else if (ItemType == TWTY_INT16) { *value = ((CapInt16Type*)pVal)->Value; ret = HGBASE_ERR_OK; } else if (ItemType == TWTY_INT32) { *value = ((CapInt32Type*)pVal)->Value; ret = HGBASE_ERR_OK; } GlobalUnlock(twCap.hContainer); } GlobalFree(twCap.hContainer); return ret; } HGResult HGTwainDSImpl::SetCapStr255(HGUInt cap, const HGChar *value) { if (NULL == value || strlen(value) >= sizeof(TW_STR255)) { return HGBASE_ERR_INVALIDARG; } TW_CAPABILITY twCap; twCap.Cap = (TW_UINT16)cap; 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, value); 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::ResetCapStr255(HGUInt cap) { TW_CAPABILITY twCap; twCap.Cap = (TW_UINT16)cap; 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; memset(pVal->Value, 0, sizeof(pVal->Value)); GlobalUnlock(twCap.hContainer); USHORT ret = m_dsmImpl->m_pDSMProc(&m_dsmImpl->m_AppId, &m_iden, DG_CONTROL, DAT_CAPABILITY, MSG_RESET, &twCap); GlobalFree(twCap.hContainer); return (TWRC_SUCCESS == ret) ? HGBASE_ERR_OK : HGTWAIN_ERR_FAIL; } HGResult HGTwainDSImpl::GetCapStr255(HGUInt cap, HGChar *value, HGUInt maxLen) { if (NULL == value || 0 == maxLen) { 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); CapStr255Type* pVal = (CapStr255Type*)GlobalLock(twCap.hContainer); if (NULL != pVal && pVal->ItemType == TWTY_STR255) { if (maxLen > strlen(pVal->Value)) { strcpy(value, 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; } 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); } }