code_twain/sane/scanner.cpp

4141 lines
122 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "scanner.h"
#include <Windows.h>
#include <Shlwapi.h> // for PathFileExistsW
#include "../sdk/hginclude/huagaoxxx_warraper_ex.h"
#include <sane/sane_option_definitions.h>
#include "../../code_device/hgsane/sane_hg_mdw.h"
#include "sane_option_trans.h"
#include <chrono>
#include <mutex>
#include "DlgSetting.h"
#include "gb_json.h"
#include "../../sdk/include/lang/app_language.h"
#include <functional>
#include "DlgIndicator.h"
#include <twainui/twainui.h>
#pragma comment(lib, "Shlwapi.lib")
#define START_SCAN_IN_THREAD
static IMPLEMENT_OPTION_STRING_COMPARE(compare_sane_opt);
#define SET_SANE_OPT_ID(id, id_name, name, val, extension) \
if(strcmp(SANE_STD_OPT_NAME_##name, val) == 0) \
{ \
id_name##_id_ = id; \
sane_ids_[(sane_option_id)SANE_OPT_ID_##name] = id; \
extension(id); \
}
#ifdef EXPORT_SANE_API
__declspec(dllexport)
#else
__declspec(dllimport)
#endif
void __stdcall log_info(const wchar_t* info, int level);
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// callback
extern "C"
{
extern SANE_Status inner_sane_init(SANE_Int* version_code, SANE_Auth_Callback authorize);
extern void inner_sane_exit(void);
extern SANE_Status inner_sane_get_devices(const SANE_Device*** device_list, SANE_Bool local_only);
extern SANE_Status inner_sane_open(SANE_String_Const devicename, SANE_Handle* handle);
extern void inner_sane_close(SANE_Handle handle);
extern const SANE_Option_Descriptor* inner_sane_get_option_descriptor(SANE_Handle handle, SANE_Int option);
extern SANE_Status inner_sane_control_option(SANE_Handle handle, SANE_Int option, SANE_Action action, void* value, SANE_Int* info);
extern SANE_Status inner_sane_get_parameters(SANE_Handle handle, SANE_Parameters* params);
extern SANE_Status inner_sane_start(SANE_Handle handle);
extern SANE_Status inner_sane_read(SANE_Handle handle, SANE_Byte* data, SANE_Int max_length, SANE_Int* length);
extern void inner_sane_cancel(SANE_Handle handle);
extern SANE_Status inner_sane_set_io_mode(SANE_Handle handle, SANE_Bool non_blocking);
extern SANE_Status inner_sane_get_select_fd(SANE_Handle handle, SANE_Int* fd);
extern SANE_String_Const inner_sane_strstatus(SANE_Status status);
extern SANE_Status inner_sane_init_ex(SANE_Int* version_code, sane_callback cb, void* param);
extern SANE_Status inner_sane_io_control(SANE_Handle h, unsigned long code, void* data, unsigned* len);
extern const char* inner_sane_err_desc(SANE_Status err);
}
namespace callback
{
static std::mutex cb_lock_;
typedef struct _scanner_inst
{
SANE_Handle dev;
scanner* invoker;
bool operator==(const SANE_Handle& h)
{
return dev == h;
}
bool operator==(const scanner* obj)
{
return invoker == obj;
}
}SCNINST;
std::vector<SCNINST> g_scanner_instances;
int sane_event_callback( // 婵炲鍔岄崬浠嬪炊閻愬墎娈堕柣銊ュ椤曨喚鎸掗埥鍛闂傚洠鍋撻悷鏇氭缁绘氨鎷犳担绛嬪殙闁搞儳鍋犻惃鐔煎及椤栨凹妯嬬紒鎹愭硶閳昏偐鈧懓顦崣蹇涙<E8B987><E6B699>?
SANE_Handle hdev // 濞存籂鍛櫢濞存粌顑勫▎銏ゆ儍閸曨噮鍟庡璺烘搐瑜扮偤寮?
, int code // 闁搞儳鍋犻惃鐔哥鐎b晜顐藉ù鐙呯悼閻?
, void* data // 闁搞儳鍋犻惃鐔哥鐎晜顐介柡浣哄瀹撲線鏁嶇仦鍓у闁硅鍠曠花銊︾閺堥潧鏁╅柣顔荤劍濠€渚€骞嶉埀顒佺▔瀹ュ懏鍊遍柨娑樿嫰瀵剟鎮¤閸欐寧鎷呴幘鑼殤濞寸姾娉涢悾鐐<E99090><EE8482>?
, unsigned int* len // 闁轰胶澧楀畵渚€姊归崹顔碱唺闁挎稑鐗嗛悺褔鎳為崒锔剧闁挎稑鏈崹銊╂嚀閸楁仸ent_data闁汇劌瀚槐锕傚礃閹绘帒闅橀梻鈧崹顔碱唺闁挎稑鐭侀娑氱磼閸℃凹鍤為柣顏勵儑濞村鎯旈弮鍌涚暠濞存粌顑勫▎銏閿濆洨<E6BF86><E6B4A8>?
, void* param // 闁活潿鍔嶉崺娑㈡嚊椤忓嫮鏆板☉鏂款槹閺嗙喖骞戦鍡欑濞戞挸姘﹂惃鐔兼偨閳虹棏ne_init_ex濞磋偐濮撮崣鍡涘籍閸撲焦鐣卞ǎ鍥ㄧ箖鐎垫梹绋夐埀顒勬<E9A192><E58BAC>?
) // 閺夆晜鏌ㄥú鏍磹闂傚璐╁☉鎾崇Т閹捇鎯冮崟顏嗙殤濞寸姵婀归崬顒勬儘娴hВ鍋撶仦鐣屾毎闁挎稑鐭傞埀顒佽壘閻栬埖绋夌悰鈾€鍋?<3F><>?
{
std::lock_guard<std::mutex> lock(cb_lock_);
std::vector<SCNINST>::iterator it = std::find(g_scanner_instances.begin(), g_scanner_instances.end(), hdev);
if (it != g_scanner_instances.end())
return it->invoker->handle_device_event(code, data, len);
else
{
wchar_t msg[218] = { 0 };
swprintf_s(msg, _countof(msg) - 1, L"Lost device(0x%08X) when event(%u) occurs!\r\n", hdev, code);
log_info(msg, 1);
return 0;
}
}
void reg_callback(SANE_Handle dev, scanner* invoker)
{
std::lock_guard<std::mutex> lock(cb_lock_);
std::vector<SCNINST>::iterator it = std::find(g_scanner_instances.begin(), g_scanner_instances.end(), dev);
if (it == g_scanner_instances.end())
{
SCNINST inst;
inst.dev = dev;
inst.invoker = invoker;
g_scanner_instances.push_back(inst);
}
else
it->invoker = invoker;
}
void unreg_callback(scanner* invoker)
{
std::lock_guard<std::mutex> lock(cb_lock_);
std::vector<SCNINST>::iterator it = std::find(g_scanner_instances.begin(), g_scanner_instances.end(), invoker);
if (it != g_scanner_instances.end())
g_scanner_instances.erase(it);
}
struct
{
const char* name;
const char* title;
}g_opts[] = { {SANE_STD_OPT_NAME_RESTORE , OPTION_TITLE_HFMRSZ}
, {SANE_STD_OPT_NAME_HELP , OPTION_TITLE_BZ}
, {SANE_STD_OPT_NAME_IS_MULTI_OUT , OPTION_TITLE_DLSC}
, {SANE_STD_OPT_NAME_MULTI_OUT_TYPE , OPTION_TITLE_DLSCLX}
, {SANE_STD_OPT_NAME_COLOR_MODE , OPTION_TITLE_YSMS}
, {SANE_STD_OPT_NAME_BINARY_THRESHOLD , OPTION_TITLE_HBTXYZ}
, {SANE_STD_OPT_NAME_REVERSE_01 , OPTION_TITLE_HBTXFSSC}
, {SANE_STD_OPT_NAME_FILTER , OPTION_TITLE_HDHHBTX_CSYZQ}
, {SANE_STD_OPT_NAME_RID_MULTIOUT_RED , OPTION_TITLE_24WCSTX_DLSCCH}
, {SANE_STD_OPT_NAME_RID_ANSWER_SHEET_RED , OPTION_TITLE_24WCSTX_DTKCH}
, {SANE_STD_OPT_NAME_ERASE_BACKGROUND , OPTION_TITLE_BJYC}
, {SANE_STD_OPT_NAME_BKG_COLOR_RANGE , OPTION_TITLE_BJSCFDFW}
, {SANE_STD_OPT_NAME_SHARPEN , OPTION_TITLE_RHYMH}
, {SANE_STD_OPT_NAME_RID_MORR , OPTION_TITLE_QCMW}
, {SANE_STD_OPT_NAME_RID_GRID , OPTION_TITLE_CWW}
, {SANE_STD_OPT_NAME_ERROR_EXTENSION , OPTION_TITLE_CWKS}
, {SANE_STD_OPT_NAME_NOISE_OPTIMIZE , OPTION_TITLE_HBTXZDYH}
, {SANE_STD_OPT_NAME_NOISE_SIZE , OPTION_TITLE_ZDYHCC}
, {SANE_STD_OPT_NAME_PAPER , OPTION_TITLE_ZZCC}
, {SANE_STD_OPT_NAME_CUSTOM_AREA , OPTION_TITLE_ZDYSMQY}
, {SANE_STD_OPT_NAME_CUSTOM_AREA_LEFT , OPTION_TITLE_SMQYZCmm}
, {SANE_STD_OPT_NAME_CUSTOM_AREA_RIGHT , OPTION_TITLE_SMQYYCmm}
, {SANE_STD_OPT_NAME_CUSTOM_AREA_TOP , OPTION_TITLE_SMQYSCmm}
, {SANE_STD_OPT_NAME_CUSTOM_AREA_BOTTOM , OPTION_TITLE_SMQYXCmm}
, {SANE_STD_OPT_NAME_SIZE_CHECK , OPTION_TITLE_CCJC}
, {SANE_STD_OPT_NAME_PAGE , OPTION_TITLE_SMYM}
, {SANE_STD_OPT_NAME_DISCARD_BLANK_SENS , OPTION_TITLE_TGKBYLMD}
, {SANE_STD_OPT_NAME_RESOLUTION , OPTION_TITLE_FBL}
, {SANE_STD_OPT_NAME_TIME_TO_SLEEP , OPTION_TITLE_XMSJ}
, {SANE_STD_OPT_NAME_IMAGE_QUALITY , OPTION_TITLE_HZ}
, {SANE_STD_OPT_NAME_EXCHANGE ,OPTION_TITLE_JHZFM}
, {SANE_STD_OPT_NAME_SPLIT ,OPTION_TITLE_TXCF }
, {SANE_STD_OPT_NAME_ANTI_SKEW , OPTION_TITLE_ZDJP}
, {SANE_STD_OPT_NAME_IS_CUSTOM_GAMMA , OPTION_TITLE_QYSDQX}
, {SANE_STD_OPT_NAME_GAMMA , OPTION_TITLE_JMZ}
, {SANE_STD_OPT_NAME_BRIGHTNESS , OPTION_TITLE_LDZ}
, {SANE_STD_OPT_NAME_CONTRAST , OPTION_TITLE_DBD}
, {SANE_STD_OPT_NAME_IS_PHOTO_MODE , OPTION_TITLE_ZPMS}
, {SANE_STD_OPT_NAME_ERASE_BLACK_FRAME , OPTION_TITLE_XCHK}
, {SANE_STD_OPT_NAME_DARK_SAMPLE , OPTION_TITLE_SSYZ}
, {SANE_STD_OPT_NAME_THRESHOLD , OPTION_TITLE_YZ}
, {SANE_STD_OPT_NAME_ANTI_NOISE_LEVEL , OPTION_TITLE_BJKZDJ}
, {SANE_STD_OPT_NAME_MARGIN , OPTION_TITLE_BYSJ}
, {SANE_STD_OPT_NAME_FILL_BKG_MODE , OPTION_TITLE_BJTCFS}
, {SANE_STD_OPT_NAME_IS_ANTI_PERMEATE , OPTION_TITLE_FZST}
, {SANE_STD_OPT_NAME_ANTI_PERMEATE_LEVEL , OPTION_TITLE_FZSTDJ}
, {SANE_STD_OPT_NAME_RID_HOLE_L , OPTION_TITLE_CKYCZC}
, {SANE_STD_OPT_NAME_SEARCH_HOLE_RANGE_L , OPTION_TITLE_ZCCKSSFWZFMBL}
, {SANE_STD_OPT_NAME_RID_HOLE_R , OPTION_TITLE_CKYCYC}
, {SANE_STD_OPT_NAME_SEARCH_HOLE_RANGE_R , OPTION_TITLE_YCCKSSFWZFMBL}
, {SANE_STD_OPT_NAME_RID_HOLE_T , OPTION_TITLE_CKYCSC}
, {SANE_STD_OPT_NAME_SEARCH_HOLE_RANGE_T , OPTION_TITLE_SCCKSSFWZFMBL}
, {SANE_STD_OPT_NAME_RID_HOLE_B , OPTION_TITLE_CKYCXC}
, {SANE_STD_OPT_NAME_SEARCH_HOLE_RANGE_B , OPTION_TITLE_XCCKSSFWZFMBL}
, {SANE_STD_OPT_NAME_IS_FILL_COLOR , OPTION_TITLE_SCTC}
, {SANE_STD_OPT_NAME_IS_ULTROSONIC_CHECK , OPTION_TITLE_CSBJC}
, {SANE_STD_OPT_NAME_DOUBLE_FEED_HANDLE , OPTION_TITLE_SZTPCL}
, {SANE_STD_OPT_NAME_IS_CHECK_STAPLE , OPTION_TITLE_ZDJC}
, {SANE_STD_OPT_NAME_SCAN_MODE , OPTION_TITLE_SMZS}
, {SANE_STD_OPT_NAME_SCAN_COUNT , OPTION_TITLE_SMSL}
, {SANE_STD_OPT_NAME_TEXT_DIRECTION , OPTION_TITLE_WGFX}
, {SANE_STD_OPT_NAME_IS_ROTATE_BKG_180 , OPTION_TITLE_BMXZ180}
, {SANE_STD_OPT_NAME_IS_CHECK_DOG_EAR , OPTION_TITLE_ZJJC}
, {SANE_STD_OPT_NAME_DOG_EAR_SIZE , OPTION_TITLE_ZJDX}
, {SANE_STD_OPT_NAME_IS_CHECK_ASKEW , OPTION_TITLE_WXJC}
, {SANE_STD_OPT_NAME_ASKEW_RANGE , OPTION_TITLE_WXRRD}
, {SANE_STD_OPT_NAME_FEED_STRENGTH , OPTION_TITLE_FZQD}
, {SANE_STD_OPT_NAME_IS_AUTO_FEED_STRENGTH , OPTION_TITLE_ZDFZQD}
, {SANE_STD_OPT_NAME_FEED_STRENGTH_VALUE , OPTION_TITLE_JZSBL}
, {SANE_STD_OPT_NAME_WAIT_TO_SCAN , OPTION_TITLE_DZSM}
, {SANE_STD_OPT_NAME_FOLD_TYPE , OPTION_TITLE_DZMS}
, {SANE_STD_OPT_NAME_COLOR_CORRECTION , OPTION_TITLE_SPJZ}
, {SANE_STD_OPT_NAME_DISCARDBLANK , OPTION_TITLE_TGKBY}
, {SANE_STD_OPT_NAME_LENS_DIRTY , OPTION_TITLE_JTZWJC}
},
g_discard[] = { {SANE_STD_OPT_NAME_REVERSE_01 , "\351\273\221\347\231\275\345\233\276\345\203\217\345\217\215\350\211\262\350\276\223\345\207\272\357\274\210\346\255\243\345\270\270\351\242\234\350\211\262\344\270\272\357\274\2320-\351\273\221\350\211\262\357\274\2331-\347\231\275\350\211\262\357\274\211"} // 濮掓稒鍨瑰▍褔宕堕幆褍鍓奸柛娆忕Х婢瑰﹥娼忛幘鍐叉瘔闁挎稑鐗婇婊呮暜閹间緡鏉归柤纭呭紦鐠愮喖<E684AE><E59696>?-濮掓稒鍨兼竟濠囨<E6BFA0><E59BA8>?-闁谎冣偓鐔奉棌闁?
, {SANE_STD_OPT_NAME_FILTER , "\347\201\260\345\272\246\346\210\226\351\273\221\347\231\275\345\233\276\345\203\217 - \351\231\244\350\211\262"} // 闁诲繑婢樼€规娊骞嬮弽顓犳嫧闁谎嗘濞存﹢宕?- 闂傚嫨鍊涙竟?
, {SANE_STD_OPT_NAME_IS_AUTO_FEED_STRENGTH , "\350\207\252\345\212\250\346\220\223\347\272\270\345\274\272\345\272\246"} // 闁煎浜滄慨鈺呭箹閹惧墎鍓ㄧ€殿喖鎼€?
, {SANE_STD_OPT_NAME_FEED_STRENGTH_VALUE , "\346\220\223\347\272\270\351\230\210\345\200\274"} // " 闁瑰吋鎸鹃悞濠囨⒓閸績<EE82A3><E7B8BE>?
};
const char* option_title_2_name(const char* title)
{
while (*title == ' ')
title++;
for (size_t i = 0; i < _countof(g_discard); ++i)
{
if (strcmp(title, g_discard[i].title) == 0)
return g_discard[i].name;
}
for (size_t i = 0; i < _countof(g_opts); ++i)
{
if (strcmp(title, g_opts[i].title) == 0)
return g_opts[i].name;
}
return "";
}
const char* __stdcall option_name_2_title(const char* name)
{
for (size_t i = 0; i < _countof(g_opts); ++i)
{
if (strcmp(name, g_opts[i].name) == 0)
return g_opts[i].title;
}
return "";
}
static bool check_wnd_thread_id = false;
static BOOL CALLBACK main_wnd(HWND hwnd, LPARAM param)
{
DWORD pid = 0,
tid = GetWindowThreadProcessId(hwnd, &pid);
if (pid != GetCurrentProcessId())
return TRUE;
if (check_wnd_thread_id && tid != GetCurrentThreadId())
return TRUE;
if (((void**)param)[1] == NULL)
{
HWND parent = GetParent(hwnd);
while (IsWindow(parent))
{
hwnd = parent;
parent = GetParent(hwnd);
}
parent = hwnd;
if (!IsWindowVisible(parent))
return TRUE;
RECT r = { 0 };
GetWindowRect(parent, &r);
if (RECT_H(r) > 50 && RECT_W(r) > 50)
{
*(HWND*)param = parent;
return FALSE;
}
}
else
{
wchar_t val[128] = { 0 };
GetClassNameW(hwnd, val, _countof(val) - 1);
if (wcscmp(val, L"#32770"))
return TRUE;
GetWindowTextW(hwnd, val, _countof(val) - 1);
if (*((std::wstring**)param)[1] == val)
{
*(HWND*)param = hwnd;
return FALSE;
}
}
return TRUE;
}
static HWND find_main_wnd(void)
{
HWND wnd[2] = { NULL };
EnumWindows(main_wnd, (LPARAM)wnd);
{
wchar_t mw[128] = { 0 };
swprintf_s(mw, _countof(mw) - 1, L"find_main_wnd of thread %u = 0x%x\r\n", GetCurrentThreadId(), wnd[0]);
log_info(mw, 1);
}
return wnd[0];
}
static DWORD WINAPI btm(LPVOID para)
{
std::wstring* title[2] = { NULL, (std::wstring*)para };
Sleep(100);
EnumWindows(main_wnd, (LPARAM)title);
if (IsWindow((HWND)title[0]))
{
RECT r = { 0 };
GetWindowRect((HWND)title[0], &r);
SetWindowPos((HWND)title[0], HWND_TOPMOST, r.left, r.top, RECT_W(r), RECT_H(r), SWP_SHOWWINDOW | SWP_NOSENDCHANGING);
SetFocus((HWND)title[0]);
}
delete title[1];
return 0;
}
static void bring_message_box_topmost(const wchar_t* title)
{
DWORD id = 0;
std::wstring* t(new std::wstring(title));
HANDLE h = CreateThread(NULL, 0, btm, t, 0, &id);
if (h)
CloseHandle(h);
else
delete t;
}
static const char* __stdcall language_trans(const char* in, bool from_hz, void* param)
{
if (from_hz)
return from_default_language(in, nullptr);
else
return to_default_language(in, nullptr);
}
// UI ...
//
// events code, see SANE_Event
//
// callback events: SANE_EVENT_UI_CLOSE_CANCEL/SANE_EVENT_UI_CLOSE_NORMAL/SANE_EVENT_UI_SCAN_COMMAND/SANE_EVENT_UI_CLOSE_SETTING
//
// notify events: SANE_EVENT_WORKING - void*: unused, be NULL, flag - unused, be 0
// SANE_EVENT_SCAN_FINISHED - void*: (utf8*)message, flag - error code (0 is success)
// SANE_EVENT_USB_DATA_RECEIVED- void* unused, be NULL, flag - unused, be 0
// SANE_EVENT_IMAGE_OK - void* unused, be NULL, flag - unused, be 0
static HMODULE hui = NULL;
int (*choose_scanner)(const std::vector<DEVQUEUI>& devs) = NULL; // blocked. return selected DEVQUE::id or -1 if user cancelled
char* (*apply_current_config)(const char* dev_name, SANE_Handle device, LPSANEAPI api) = NULL; // 閹煎瓨姊婚弫銈囨媼閹屾У闁汇劌瀚紞瀣礈瀹ュ甯抽柨?
int (*show_setting_ui)(SANE_Handle device, HWND parent, LPSANEAPI api, const char* devname, bool with_scan, std::function<void(ui_result)> callback, std::function<void(int, void*, int)>* notify) = NULL;
int (*show_progress_ui)(HWND parent, std::function<void(ui_result)> callback, std::function<void(int/*event*/, void*/*msg*/, int/*flag*/)>* notify) = NULL;
int (*show_messagebox_ui)(HWND parent, int event, void* msg, int flag) = NULL;
int (*close_ui)(int) = NULL;
int (*apply_given_config)(const char* content, SANE_Handle device, LPSANEAPI api) = NULL; // 閹煎瓨姊婚弫銈夊箰閸パ呮毎闁汇劌瀚伴崢銈囩磾椤曞棛绀塩ontent濞戞挻妞介崢銈囩磾椤旇姤娈堕柟璇″枟<E280B3><E69E9F>?
char* (*get_config_content)(const char* dev_name, const char* name) = NULL;
void (*twain_ui_free)(void* buf) = NULL;
void (*pump_ui_message)(void* reserved) = NULL;
int (*abnormal_image)(SANE_Image* img) = NULL; // return SANE_Abnormal_Image_Treat
static int load_dll(const char* path_dll, HMODULE* dll)
{
HMODULE h = NULL; // LoadLibraryA(path_dll); // 3rd APP like Dynamsoft will treat the exception, so we force to SetDllDirectoryW first and load later
int ret = 0; // GetLastError();
char info[128] = { 0 };
sprintf_s(info, _countof(info) - 1, " = %d\r\n", ret);
OutputDebugStringA(("[TWAIN]Load: " + std::string(path_dll) + info).c_str());
if (!h && (ret == ERROR_MOD_NOT_FOUND || ret == ERROR_BAD_EXE_FORMAT || ret == 0))
{
std::string dir(path_dll);
size_t pos = dir.rfind(L'\\');
wchar_t path[MAX_PATH] = { 0 };
GetDllDirectoryW(_countof(path) - 1, path);
if (pos != std::wstring::npos)
dir.erase(pos);
OutputDebugStringA(("[TWAIN]Load: try change directory to " + dir + "\r\n").c_str());
SetDllDirectoryA(dir.c_str());
h = LoadLibraryA(path_dll);
// h = LoadLibraryExW(path_dll, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
ret = GetLastError();
sprintf_s(info, _countof(info) - 1, " = %d\r\n", ret);
OutputDebugStringA(("[TWAIN]Load: " + std::string(path_dll) + info).c_str());
OutputDebugStringW((L"[TWAIN]Load: restore directory to " + std::wstring(path) + L"\r\n").c_str());
SetDllDirectoryW(path);
}
if (dll)
*dll = h;
return ret;
}
static void init_ui(void)
{
std::string root(hg_sane_middleware::sane_path());
if (hui)
FreeLibrary(hui);
hui = NULL;
root += OEM_SHORT_NAME_E;
root += "TwainUI.dll";
// hui = LoadLibraryExA(root.c_str(), NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
//hui = LoadLibraryA(root.c_str());
load_dll(root.c_str(), &hui);
if (!hui)
{
std::wstring info(L"Load '" + local_trans::a2u(root.c_str(), CP_UTF8));
info += L"' failed: " + std::to_wstring(GetLastError()) + L"\r\n";
log_info(info.c_str(), 1);
}
else
{
#define GET_API(api) \
proc = (FARPROC*)&api; \
*proc = GetProcAddress(hui, #api);
FARPROC* proc = NULL;
GET_API(choose_scanner);
GET_API(apply_current_config);
GET_API(show_setting_ui);
GET_API(show_progress_ui);
GET_API(show_messagebox_ui);
GET_API(close_ui);
GET_API(twain_ui_free);
GET_API(apply_given_config);
GET_API(get_config_content);
GET_API(pump_ui_message);
GET_API(abnormal_image);
}
}
static void unint_ui(void)
{
if (close_ui)
close_ui(UI_UNLOAD_MODULE);
choose_scanner = NULL;
apply_current_config = NULL;
show_setting_ui = NULL;
show_progress_ui = NULL;
show_messagebox_ui = NULL;
close_ui = NULL;
twain_ui_free = NULL;
apply_given_config = NULL;
get_config_content = NULL;
pump_ui_message = NULL;
abnormal_image = NULL;
if (hui)
{
FreeLibrary(hui);
hui = NULL;
}
}
// check thread whether has window
static BOOL WINAPI check_window(HWND hwnd, LPARAM lp)
{
LPDWORD id = (LPDWORD)lp;
if (GetWindowThreadProcessId(hwnd, NULL) == id[0])
{
id[1] = 1;
return FALSE;
}
return TRUE;
}
static bool is_thread_has_window(DWORD thread_id = -1)
{
if (thread_id == -1)
thread_id = GetCurrentThreadId();
DWORD param[] = { thread_id, 0 };
EnumWindows(check_window, (LPARAM)param);
return param[1];
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// class scanner
scanner::scanner(SCANNERID id) : handle_(NULL), id_(id), ex_id_(EXTENSION_ID_BASE), prev_start_result_(SCANNER_ERR_NOT_START)
, dpi_(200), tmp_path_(L""), img_ind_(0)
, scanner_name_(L""), cfg_(NULL), is_ui_wait_img_(false), is_scanning_(false)
, scanner_ev_handler_(NULL), evh_param_(NULL), app_wnd_(NULL), user_cancel_(false)
, max_img_mem_(400), wait_fetch_(60 * 1000), twain_set_(false), ev_cnt_(0), is_bIndicator(false), is_show_setting_(false), is_in_working_thread_(false)
{
ui_notify = std::function<void(int, void*, int)>();
sane_api_.sane_cancel_api = inner_sane_cancel;
sane_api_.sane_close_api = inner_sane_close;
sane_api_.sane_control_option_api = inner_sane_control_option;
sane_api_.sane_get_devices_api = inner_sane_get_devices;
sane_api_.sane_get_option_descriptor_api = inner_sane_get_option_descriptor;
sane_api_.sane_get_parameters_api = inner_sane_get_parameters;
sane_api_.sane_get_select_fd_api = inner_sane_get_select_fd;
sane_api_.sane_io_control_api = inner_sane_io_control;
sane_api_.sane_open_api = inner_sane_open;
sane_api_.sane_read_api = inner_sane_read;
sane_api_.sane_set_io_mode_api = inner_sane_set_io_mode;
sane_api_.sane_start_api = inner_sane_start;
sane_api_.sane_strstatus_api = inner_sane_strstatus;
if (!callback::show_setting_ui)
{
cfg_ = new gb::scanner_cfg();
cfg_->set_language_transform(&callback::language_trans, NULL);
}
tmp_path_ = local_trans::a2u(hg_sane_middleware::sane_path().c_str());
{
char* tmp = getenv("LOCALAPPDATA");
if (tmp)
{
tmp_path_ = local_trans::a2u(tmp) + L"\\";
tmp_path_ += local_trans::a2u(PRODUCT_VENDOR) + L"Scan\\";
CreateDirectoryW(tmp_path_.c_str(), NULL);
}
}
cfg_path_ = tmp_path_ + L"config";
CreateDirectoryW(cfg_path_.c_str(), NULL);
cfg_path_ += L"\\";
tmp_path_ += L"imgs";
CreateDirectoryW(tmp_path_.c_str(), NULL);
tmp_path_ += L"\\";
img_fmt_.img_format = SANE_IMAGE_TYPE_BMP;
img_fmt_.compress.compression = SANE_COMPRESSION_NONE;
int mem_limit = GetPrivateProfileIntW(L"mem", L"max_img", 0, (cfg_path_ + L"debug.cfg").c_str());
if (mem_limit > 0)
{
// this value is same as driver memory limit ...
max_img_mem_ = mem_limit;
}
mem_limit = GetPrivateProfileIntW(L"mem", L"wait", 0, (cfg_path_ + L"debug.cfg").c_str());
if (mem_limit > 0)
{
wait_fetch_ = mem_limit * 1000; // second to millisecond
}
re_enter_msg_ = GetPrivateProfileIntW(L"twain-app", L"ignore-msg", 0, (cfg_path_ + L"debug.cfg").c_str());
re_enter_msg_wp_ = GetPrivateProfileIntW(L"twain-app", L"ignore-msg-wp", 0, (cfg_path_ + L"debug.cfg").c_str());
if (re_enter_msg_ == 0)
{
wchar_t path[MAX_PATH] = { 0 }, * name = NULL;
GetModuleFileNameW(NULL, path, _countof(path) - 1);
name = wcsrchr(path, L'\\');
if (name++ == NULL)
name = path;
if (wcsicmp(name, L"proScanner.exe") == 0)
{
re_enter_msg_ = WM_TIMER;
re_enter_msg_wp_ = 1;
}
}
if(re_enter_msg_)
{
wchar_t info[128] = { 0 };
swprintf_s(info, _countof(info) - 1, L"Ignore message(0x%x) when get images\r\n", re_enter_msg_);
log_info(info, 1);
}
err_ = open();
}
scanner::~scanner()
{
close();
if (thread_starting_.get() && thread_starting_->joinable())
thread_starting_->join();
thread_starting_.reset();
if (start_after_keep_.get() && start_after_keep_->joinable())
start_after_keep_->join();
start_after_keep_.reset();
if (cfg_)
{
cfg_->remove_all_schemes(); // schemes would add_ref on cfg_, so we clear them first. NOTE: do not call save after this !!!
cfg_->release();
cfg_ = NULL;
while (!dlg_base::is_message_thread_exited())
{
MSG msg = { 0 };
PeekMessageW(&msg, NULL, 0, 0, PM_NOREMOVE);
}
}
}
std::string scanner::getDeviceType()
{
std::string cfgPath("");
std::string env("LOCALAPPDATA");
cfgPath = getenv(env.c_str());
cfgPath += "\\";
#ifdef OEM_HANWANG
cfgPath += "HanvonScan";
#elif defined(OEM_LISICHENG)
cfgPath += "LanxumScan";
#elif defined(OEM_CANGTIAN)
cfgPath += "CumTennScan";
#elif defined(OEM_ZHONGJING)
cfgPath += "MicrotekScan";
#elif defined(OEM_ZIGUANG)
cfgPath += "UniScan";
#elif defined(OEM_DELI)
cfgPath += "DeliScan";
#elif defined(OEM_NEUTRAL)
cfgPath += "NeuScan";
#else
cfgPath += "HuaGoScan";
#endif
char devType[256] = { 0 };
cfgPath += "\\config\\debug.cfg";
GetPrivateProfileStringA("devs_name", "name", NULL, devType, 256, cfgPath.c_str());
return devType;
}
bool scanner::is_belong_serial(int vid, int pid, SCANNERID serial)
{
if (vid == PRODUCT_VENDOR_HG)
{
if (GET_SCANNER_VID(serial) == PRODUCT_VENDOR_HG)
{
if (GET_SCANNER_PID(serial) == 0x100)
{
return pid == 0x100 || pid == 0x139;
}
else if (GET_SCANNER_PID(serial) == 0x200)
{
return pid == 0x200 || pid == 0x239;
}
else if (GET_SCANNER_PID(serial) == 0x300)
{
return pid == 0x300 || pid == 0x302 || pid == 0x339 || pid == 0x306;
}
else if (GET_SCANNER_PID(serial) == 0x400)
{
return pid == 0x400 || pid == 0x402 || pid == 0x439;
}
else if (GET_SCANNER_PID(serial) == 0x138 ||
GET_SCANNER_PID(serial) == 0x238 ||
GET_SCANNER_PID(serial) == 0x303 ||
GET_SCANNER_PID(serial) == 0x404) // OEM_CANGTIAN
return true;
}
return false;
}
else if (vid == PRODUCT_VENDOR_HG1)
{
std::string devType = getDeviceType();
int devPid = 0x200;
if (!devType.empty())
{
if (devType == "G300")
devPid = 0x300;
else if (devType == "G400")
devPid = 0x400;
}
int a = GET_SCANNER_VID(serial);
return pid == 0x7823 && GET_SCANNER_VID(serial) == PRODUCT_VENDOR_HG && (GET_SCANNER_PID(serial) == devPid);
}
else if (vid == PRODUCT_VENDOR_HW)
{
return GET_SCANNER_VID(serial) == vid && GET_SCANNER_PID(serial) == pid;
}
else if (vid == PRODUCT_VENDOR_LSC)
{
#if defined (LISICHENG_SPECIAL)
return GET_SCANNER_VID(serial) == vid && GET_SCANNER_PID(serial) == pid;
#else
if (GET_SCANNER_VID(serial) == PRODUCT_VENDOR_LSC)
{
if (GET_SCANNER_PID(serial) == 0x8420)
{
return pid == 0x8200 || pid == 0x8420 || pid == 0x8429;
}
else if (GET_SCANNER_PID(serial) == 0x8520)
{
return pid == 0x8520 || pid == 0x8529;
}
else if (GET_SCANNER_PID(serial) == 0x8620)
{
return pid == 0x8620 || pid == 0x8629;
}
else if (GET_SCANNER_PID(serial) == 0x8730)
{
return pid == 0x8730 || pid == 0x8739;
}
else if (GET_SCANNER_PID(serial) == 0x8630)
{
return pid == 0x8630;
}
}
#endif
return false;
}
else if (vid == PRODUCT_VENDOR_DL)
{
if (GET_SCANNER_PID(serial) == 0x401C)
{
return pid == 0x401C || pid == 0x4020;
}
else
{
return GET_SCANNER_VID(serial) == vid && GET_SCANNER_PID(serial) == pid;
}
}
else if (vid == PRODUCT_VENDOR_ZG)
{
return GET_SCANNER_VID(serial) == vid && GET_SCANNER_PID(serial) == pid;
}
else if (vid == PRODUCT_VENDOR_CTS)
{
return GET_SCANNER_VID(serial) == vid && GET_SCANNER_PID(serial) == pid;
}
else if (vid == PRODUCT_VENDOR_ZJ)
{
return GET_SCANNER_VID(serial) == vid && GET_SCANNER_PID(serial) == pid;
}
return true;
}
void scanner::get_scanner_name(SCANNERID id, std::vector<std::string>& names)
{
ScannerInfo* devs = NULL;
long count = 0;
names.clear();
if (hg_scanner_enum(devs, &count, true) == SCANNER_ERR_INSUFFICIENT_MEMORY)
{
count++;
devs = new ScannerInfo[count];
memset(devs, 0, count * sizeof(*devs));
if (hg_scanner_enum(devs, &count, true) == SCANNER_ERR_OK)
{
for (int i = 0; i < count; ++i)
{
if (scanner::is_belong_serial(devs[i].vid, devs[i].pid, id))
{
names.push_back(devs[i].name);
}
}
}
delete[] devs;
}
}
value_type scanner::from_sane_type(SANE_Value_Type type)
{
if (type == SANE_TYPE_BOOL)
return VAL_TYPE_BOOL;
else if (type == SANE_TYPE_INT)
return VAL_TYPE_INT;
else if (type == SANE_TYPE_FIXED)
return VAL_TYPE_FLOAT;
else if (type == SANE_TYPE_STRING)
return VAL_TYPE_STR;
else
return VAL_TYPE_NONE;
}
value_limit scanner::from_sane_constraint(SANE_Constraint_Type type)
{
if (type == SANE_CONSTRAINT_RANGE)
return VAL_LIMIT_RANGE;
else if (type == SANE_CONSTRAINT_STRING_LIST || type == SANE_CONSTRAINT_WORD_LIST)
return VAL_LIMIT_ENUM;
else
return VAL_LIMIT_NONE;
}
int scanner::control_read_string(SANE_Handle hdev, int code, std::string& str)
{
char* buf = NULL;
unsigned len = 0;
int err = hg_sane_middleware::instance()->io_control(hdev, code, buf, &len);
str = "";
if (err == SANE_STATUS_NO_MEM)
{
len += 4;
buf = new char[len];
memset(buf, 0, len);
err = hg_sane_middleware::instance()->io_control(hdev, code, buf, &len);
if (err == SANE_STATUS_GOOD)
str = buf;
delete[] buf;
}
return err;
}
int __stdcall scanner::to_int(SANE_Int v)
{
return v;
}
float __stdcall scanner::to_float(SANE_Fixed v)
{
return (float)SANE_UNFIX(v);
}
void __stdcall scanner::ui_callback(int uev, void* sender, void* param)
{
((scanner*)param)->on_ui_event(uev, sender);
}
bool scanner::is_option_float(int sn, void* param)
{
SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor((SANE_Handle)param, (const void*)sn);
if (desc)
return desc->type == SANE_TYPE_FIXED;
else
return false;
}
void __stdcall scanner::apply_scheme(gb::sane_config_schm* schm, void* param)
{
((scanner*)param)->apply_scheme(schm);
}
void scanner::scan_done(void)
{
std::string msg(scan_msg_);
// avoid APP do not fetch image ... - 2023-11-30
if (err_ != SCANNER_ERR_USER_CANCELED)
{
int cnt = images_.count(),
wait_total = 1000,
wait_unit = 5,
wait = 0;
while (cnt)
{
std::this_thread::sleep_for(std::chrono::milliseconds(wait_unit));
wait++;
if (wait >= wait_total / wait_unit)
break;
else if (cnt != images_.count())
wait = 0;
cnt = images_.count();
}
}
if (indicator_)
indicator_->notify_scan_over(&msg[0], err_ != SCANNER_ERR_OK);
else if (ui_notify)
ui_notify(SANE_EVENT_SCAN_FINISHED, &msg[0], err_);
else
{
if (err_)
{
if (callback::show_messagebox_ui)
{
callback::show_messagebox_ui(app_wnd_, SANE_EVENT_SCAN_FINISHED, (void*)&msg[0], 0);
}
else // windows message box ...
{
std::wstring text(local_trans::a2u(msg.c_str(), CP_UTF8));
if (!IsWindow(app_wnd_))
callback::bring_message_box_topmost(local_trans::lang_trans_between_hz936(CONST_STRING_ERROR).c_str());
MessageBoxW(app_wnd_, text.c_str(), local_trans::lang_trans_between_hz936(CONST_STRING_ERROR).c_str(), MB_OK);
}
}
on_ui_event(SANE_EVENT_SCAN_FINISHED, (void*)SANE_EVENT_SCAN_FINISHED);
}
is_in_working_thread_ = false;
}
// IRef
COM_API_IMPLEMENT(scanner, long, add_ref(void))
{
return refer::add_ref();
}
COM_API_IMPLEMENT(scanner, long, release(void))
{
return refer::release();
}
int scanner::transfer_id(int id)
{
if (id > SANE_OPT_ID_BASE)
{
if (sane_ids_.count((sane_option_id)id) == 0)
id = -1;
else
id = sane_ids_[(sane_option_id)id];
}
return id;
}
void scanner::transport_config_file(void)
{
size_t pos = scanner_name_.find(L" - ");
std::wstring pid(L"G"), old(L"");
if (pos == std::wstring::npos)
return;
pid += scanner_name_.substr(pos + 3);
if (scanner_name_.find(L"HUAGOSCAN ") != std::wstring::npos)
{
old = local_trans::lang_trans_between_hz936(L"\u534E\u9AD8\u626B\u63CF\u4EEA\u2014");
}
else if (scanner_name_.find(L"LANXUMSCAN ") != std::wstring::npos)
{
old = local_trans::lang_trans_between_hz936(L"\u7ACB\u601D\u8FB0\u626B\u63CF\u4EEA\u2014");
pid += L"S";
}
old += pid;
if (PathFileExistsW((cfg_path_ + old).c_str()))
{
log_info((L"Rename config file '" + old + L"' to '" + scanner_name_.substr(0, pos) + L"'\r\n").c_str(), 1);
MoveFileW((cfg_path_ + old).c_str(), (cfg_path_ + scanner_name_.substr(0, pos)).c_str());
}
}
void scanner::update_config(void)
{
if (!cfg_)
return;
gb::sane_config_schm* schm = cfg_->get_scheme();
std::string notice("");
if (schm)
{
//schm->update(&scanner::is_option_float, handle_, &callback::option_title_2_name, &notice);
//if (notice.length())
//{
// std::wstring msg(local_trans::lang_trans_between_hz936(L"\u4E0B\u5217\u914D\u7F6E\u6570\u636E\u9519\u8BEF\uFF0C\u5DF2\u7ECF\u6062\u590D\u5230\u9ED8\u8BA4\u503C\u3002\u5982\u679C\u9700\u8981\uFF0C\u8BF7\u91CD\u65B0\u8BBE\u7F6E") + L"\r\n\r\n");
// size_t pos = notice.find("\r\n");
//
// while (pos != std::string::npos)
// {
// msg += local_trans::a2u(callback::option_name_2_title(notice.substr(0, pos).c_str()), CP_UTF8) + L"\r\n";
// notice.erase(0, pos + 2);
// pos = notice.find("\r\n");
// }
// if (!IsWindow(app_wnd_))
// callback::bring_message_box_topmost(local_trans::lang_trans_between_hz936(L"\u52A0\u8F7D\u914D\u7F6E").c_str());
// MessageBoxW(app_wnd_, msg.c_str(), local_trans::lang_trans_between_hz936(L"\u52A0\u8F7D\u914D\u7F6E").c_str(), MB_OK | MB_ICONINFORMATION);
//}
schm->release();
}
}
void scanner::load_config(const wchar_t* file)
{
if (cfg_)
{
cfg_->load_file(local_trans::u2a(file).c_str());
update_config();
}
}
void scanner::save_config(const wchar_t* file)
{
if(cfg_)
cfg_->save(local_trans::u2a(file).c_str());
}
void scanner::apply_config(void)
{
if (callback::apply_current_config)
{
char* cfg = callback::apply_current_config(local_trans::u2a(scanner_name_.c_str(), CP_UTF8).c_str(), handle_, &sane_api_);
if (cfg && callback::twain_ui_free)
callback::twain_ui_free(cfg);
}
else if (cfg_)
{
gb::sane_config_schm* schm = cfg_->get_scheme();
if (!schm)
return;
apply_scheme(schm);
schm->release();
}
}
void scanner::on_ui_event(int uev, void* sender)
{
if (uev == SANE_EVENT_UI_CLOSE_SETTING)
{
// setting UI closed ...
is_scanning_ = is_show_setting_ = false;
if (setting_)
setting_->close();
setting_ = NULL;
}
else if (uev == SANE_EVENT_UI_CLOSE_NORMAL)
{
// scan complete
if (indicator_)
indicator_->close();
indicator_ = NULL;
// FIX on 2023-05-30: restore scan finished status, whether close UI is up to APP
//is_scanning_ = is_show_setting_;
is_scanning_ = false;
ui_notify = std::function<void(int, void*, int)>();
}
else if (uev == SANE_EVENT_UI_CLOSE_CANCEL)
{
// scan cancelled
//if (indicator_)
// indicator_->close();
//indicator_ = NULL;
stop(); // nothing to do, the finishing work do in SANE_EVENT_SCAN_FINISHED
}
else if (uev == SANE_EVENT_SCAN_FINISHED)
{
// FIX on 2023-05-30: restore scan finished status, whether close UI is up to APP
//is_scanning_ = is_show_setting_;
is_scanning_ = false;
ui_notify = std::function<void(int, void*, int)>();
}
int(__stdcall * h)(int, void*) = scanner_ev_handler_;
if (h)
{
h(uev, evh_param_);
}
return;
events_.save(uev, sizeof(uev));
}
std::string scanner::choose_scanner(const std::vector<std::string>& scanners)
{
if (scanners.empty())
return "";
std::vector<DEVQUEUI> devs;
std::string sel("");
int id = 1;
for (size_t i = 0; i < scanners.size(); ++i)
{
SANE_Handle h = NULL;
int ret = hg_sane_middleware::instance()->open_device(scanners[i].c_str(), &h);
if (h)
{
std::string sn("");
scanner::control_read_string(h, IO_CTRL_CODE_GET_SERIAL, sn);
if (sn.length())
{
DEVQUEUI dev;
dev.id = id++;
dev.name = scanners[i];
dev.sn = sn;
devs.push_back(dev);
}
hg_sane_middleware::instance()->close_device(h);
}
}
if (devs.size() == 0)
sel = scanners[0];
else if (devs.size() == 1)
sel = devs[0].name;
else if (callback::choose_scanner)
{
id = callback::choose_scanner(devs);
if (id != -1)
{
for (auto& v : devs)
{
if (v.id == id)
{
sel = v.name;
break;
}
}
}
}
else
{
//dlg_choose_dev dlg(NULL, devs);
//dlg.show(true, true);
//sel = dlg.get_selected_device();
}
return sel;
}
int scanner::open(void)
{
int ret = close();
std::vector<std::string> que;
std::string name("");
scanner::get_scanner_name(id_, que);
scanner_name_ = L"";
if (que.empty())
return SCANNER_ERR_DEVICE_NOT_FOUND;
if (que.size() == 1)
name = que[0];
else
{
name = choose_scanner(que);
if (name.empty())
return SCANNER_ERR_USER_CANCELED;
}
ret = hg_sane_middleware::instance()->open_device(name.c_str(), &handle_);
if (ret == SANE_STATUS_GOOD)
{
size_t pid = -1;
transport_config_file();
callback::reg_callback(handle_, this);
scanner_name_ = local_trans::a2u(name.c_str(), CP_UTF8);
pid = scanner_name_.find(L" - ");
if (pid == -1)
pid = scanner_name_.length();
ret = init_options_id();
load_config((cfg_path_ + scanner_name_.substr(0, pid) + L".cfg").c_str());
apply_config();
// check roller life ...
SANE_Int cnt = 0, life = 0;
if (hg_sane_middleware::instance()->get_cur_value(handle_, (void*)SANE_OPT_ID_ROLLER_COUNT, &cnt) &&
hg_sane_middleware::instance()->set_option(handle_, (void*)SANE_OPT_ID_ROLLER_LIFE, SANE_ACTION_GET_VALUE, &life, NULL) == SANE_STATUS_GOOD)
//hg_sane_middleware::instance()->get_cur_value(handle_, (void*)SANE_OPT_ID_ROLLER_LIFE, &life))
{
if (cnt >= life / 100 * 99) // 99%
{
if (callback::show_messagebox_ui)
{
// 缂佺偓鐡曢悿鍡涘箹閹惧墎鍓ㄦ繛鍡忓墲閺嗙喎顔忛懠鍓佇㈤弶鈺佹穿椤旀洜鎷嬮垾鎻掆枏闁活潿鍔忕€垫牠宕舵潏鍓х闁规鍋呭鎸庢交閸モ斁鏌ゅ☉鎿冨幗閹紕鐥粙瑁や杭閻犳劑鍎埀顑跨劍椤掞綁寮┃搴撳亾娴鍋傚鑸佃壘缁卞墎绮垫径濠勭閻㈩垱鎮傞。璺衡枎閳ュ啿璁查柤铏灊缁变即寮版惔銏♀枖濠⒀呭仜椤﹀潡鏁嶅畝鍐惧殲婵炲鍔嶉崜浼村矗婵犲啯顦ф繛鎾虫噺绾俱儵濡存担姝屽珯闁艰鲸姊婚柈瀵告媼閹屾У濞撴碍绋戠花鏌ュ疮閸℃艾鏋犲☉鏃傚濞存盯骞戦姀銏㈠墾閺夌儐鍣<E98DA3><EE889C>?
std::wstring roller_msgw(local_trans::lang_trans_between_hz936(L"\u7EB8\u8F6E\u6413\u7EB8\u6B21\u6570\u5DF2\u8D85\u8FC7\u8BBE\u8BA1\u4F7F\u7528\u8303\u56F4\uFF0C\u626B\u63CF\u8FC7\u7A0B\u4E2D\u6413\u7EB8\u5931\u8D25\u3001\u6B6A\u659C\u3001\u6413\u591A\u5F20\u7B49\u5F02\u5E38\u9891\u6B21\u53EF\u80FD\u4F1A\u660E\u663E\u589E\u591A\uFF0C\u8BF7\u6CE8\u610F\u53CA\u65F6\u6E05\u6D01\u3001\u5E76\u8054\u7CFB\u8BBE\u5907\u4F9B\u5E94\u5546\u8D2D\u4E70\u66FF\u6362\u7EB8\u8F6E\uFF01"));
std::string roller_msg(local_trans::u2a(roller_msgw.c_str(), CP_UTF8));
app_wnd_ = callback::find_main_wnd();
callback::show_messagebox_ui(app_wnd_, ret, (void*)&roller_msg[0], 0);
}
}
}
}
else
{
if (callback::show_messagebox_ui)
{
app_wnd_ = callback::find_main_wnd();
callback::show_messagebox_ui(app_wnd_, ret, (void*)hg_scanner_err_description(ret), 0);
}
else
{
std::wstring msg(local_trans::a2u(hg_scanner_err_description(ret), CP_UTF8));
//if (indicator_.get())
// indicator_->show(false);
if (!IsWindow(app_wnd_))
callback::bring_message_box_topmost(local_trans::lang_trans_between_hz936(CONST_STRING_START_FAILED).c_str());
MessageBoxW(app_wnd_, msg.c_str(), local_trans::lang_trans_between_hz936(CONST_STRING_START_FAILED).c_str(), MB_OK | MB_ICONERROR);
}
}
return ret;
}
int scanner::close(void)
{
images_.clear();
if (done_.get() && done_->joinable())
done_->join();
scanner_ev_handler_ = NULL;
ui_hide();
callback::unreg_callback(this);
if (handle_)
{
hg_sane_middleware::instance()->close_device(handle_);
}
handle_ = NULL;
ex_id_ = EXTENSION_ID_BASE;
return SCANNER_ERR_OK;
}
int scanner::init_options_id(void)
{
SANE_Int op_id = 1;
const SANE_Option_Descriptor* desc = NULL;
int ret = SCANNER_ERR_OK;
#define SET_OPT_ID(var, predef, func) \
SET_SANE_OPT_ID(op_id, var, predef, desc->name, func)
#define INIT_FIXED_IDS(id) \
sane_ids_[SANE_OPT_ID_##id] = SANE_OPT_ID_##id;
INIT_FIXED_IDS(HISTORY_COUNT);
INIT_FIXED_IDS(DRIVER_VERSION);
INIT_FIXED_IDS(MANUFACTURER);
INIT_FIXED_IDS(COPYRIGHT);
INIT_FIXED_IDS(CO_URL);
INIT_FIXED_IDS(CO_TEL);
INIT_FIXED_IDS(CO_ADDR);
INIT_FIXED_IDS(CO_GPS);
INIT_FIXED_IDS(HELP);
INIT_FIXED_IDS(VID);
INIT_FIXED_IDS(PID);
INIT_FIXED_IDS(DEV_NAME);
INIT_FIXED_IDS(DEV_FAMILY);
INIT_FIXED_IDS(LOGIN);
INIT_FIXED_IDS(LOGOUT);
INIT_FIXED_IDS(ROLLER_COUNT);
INIT_FIXED_IDS(DRIVER_LOG);
INIT_FIXED_IDS(DEVICE_LOG);
INIT_FIXED_IDS(ROLLER_LIFE);
INIT_FIXED_IDS(DEVICE_MAC_ADDR);
INIT_FIXED_IDS(CUSTOM_GAMMA);
INIT_FIXED_IDS(MOTOR_VER);
INIT_FIXED_IDS(INITIAL_BOOT_TIME);
INIT_FIXED_IDS(LENS_DIRTY);
while ((desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, (const void*)op_id)))
{
void* val = hg_sane_middleware::instance()->get_def_value(handle_, (void*)op_id, NULL, true);
if (val)
{
size_t len = 0;
switch (desc->type)
{
case SANE_TYPE_BOOL:
len = sizeof(SANE_Bool);
break;
case SANE_TYPE_INT:
len = sizeof(SANE_Int);
break;
case SANE_TYPE_FIXED:
len = sizeof(SANE_Fixed);
break;
case SANE_TYPE_STRING:
len = lstrlenA((char*)val);
break;
default:
break;
}
if (len && cfg_)
{
if (desc->type == SANE_TYPE_STRING)
{
std::string deflan(to_default_language((char*)val, nullptr));
cfg_->set_default_value(op_id, desc->name, desc->title, &deflan[0], deflan.length(), desc->type);
}
else
cfg_->set_default_value(op_id, desc->name, desc->title, (char*)val, len, desc->type);
}
local_utility::free_memory(val);
}
SET_OPT_ID(is_multiout, IS_MULTI_OUT, extension_none)
else SET_OPT_ID(multiout_type, MULTI_OUT_TYPE, extension_multiout_type)
else SET_OPT_ID(color_mode, COLOR_MODE, extension_color_mode)
else SET_OPT_ID(erase_color, FILTER, extension_erase_color)
else SET_OPT_ID(erase_multiout_red, RID_MULTIOUT_RED, extension_none)
else SET_OPT_ID(erase_paper_red, RID_ANSWER_SHEET_RED, extension_none)
else SET_OPT_ID(is_erase_background, ERASE_BACKGROUND, extension_none)
else SET_OPT_ID(background_color_range, BKG_COLOR_RANGE, extension_none)
else SET_OPT_ID(sharpen, SHARPEN, extension_sharpen)
else SET_OPT_ID(erase_morr, RID_MORR, extension_none)
else SET_OPT_ID(erase_grids, RID_GRID, extension_none)
else SET_OPT_ID(error_extend, ERROR_EXTENSION, extension_none)
else SET_OPT_ID(is_noise_modify, NOISE_OPTIMIZE, extension_none)
else SET_OPT_ID(noise_threshold, NOISE_SIZE, extension_none)
else SET_OPT_ID(paper, PAPER, extension_paper)
else SET_OPT_ID(is_custom_area, CUSTOM_AREA, extension_none)
else SET_OPT_ID(curstom_area_l, CUSTOM_AREA_LEFT, extension_none)
else SET_OPT_ID(curstom_area_r, CUSTOM_AREA_RIGHT, extension_none)
else SET_OPT_ID(curstom_area_t, CUSTOM_AREA_TOP, extension_none)
else SET_OPT_ID(curstom_area_b, CUSTOM_AREA_BOTTOM, extension_none)
else SET_OPT_ID(is_size_check, SIZE_CHECK, extension_none)
else SET_OPT_ID(page, PAGE, extension_page)
else SET_OPT_ID(blank_page_threshold, DISCARD_BLANK_SENS, extension_none)
else SET_OPT_ID(resolution, RESOLUTION, extension_none)
else SET_OPT_ID(image_quality, IMAGE_QUALITY, extension_none)
else SET_OPT_ID(is_swap, EXCHANGE, extension_none)
else SET_OPT_ID(is_split, SPLIT, extension_none)
else SET_OPT_ID(is_auto_deskew, ANTI_SKEW, extension_none)
else SET_OPT_ID(is_custom_gamma, IS_CUSTOM_GAMMA, extension_none)
else SET_OPT_ID(bright, BRIGHTNESS, extension_none)
else SET_OPT_ID(contrast, CONTRAST, extension_none)
else SET_OPT_ID(gamma, GAMMA, extension_none)
else SET_OPT_ID(is_erase_black_frame, ERASE_BLACK_FRAME, extension_none)
else SET_OPT_ID(deep_sample, DARK_SAMPLE, extension_none)
else SET_OPT_ID(threshold, THRESHOLD, extension_none)
else SET_OPT_ID(anti_noise, ANTI_NOISE_LEVEL, extension_none)
else SET_OPT_ID(margin, MARGIN, extension_none)
else SET_OPT_ID(fill_background, FILL_BKG_MODE, extension_fill_bkg_method)
else SET_OPT_ID(is_anti_permeate, IS_ANTI_PERMEATE, extension_none)
else SET_OPT_ID(anti_permeate_level, ANTI_PERMEATE_LEVEL, extension_none)
else SET_OPT_ID(is_erase_hole, RID_HOLE, extension_none)
else SET_OPT_ID(search_hole_range, SEARCH_HOLE_RANGE, extension_none)
else SET_OPT_ID(is_filling_color, IS_FILL_COLOR, extension_none)
else SET_OPT_ID(is_ultrasonic_check, IS_ULTROSONIC_CHECK, extension_none)
else SET_OPT_ID(is_check_staple, IS_CHECK_STAPLE, extension_none)
else SET_OPT_ID(scan_mode, SCAN_MODE, extension_none)
else SET_OPT_ID(scan_count, SCAN_COUNT, extension_none)
else SET_OPT_ID(text_direction, TEXT_DIRECTION, extension_text_direction)
else SET_OPT_ID(is_rotate_bkg180, IS_ROTATE_BKG_180, extension_none)
else SET_OPT_ID(is_check_dogear, IS_CHECK_DOG_EAR, extension_none)
else SET_OPT_ID(dogear_size, DOG_EAR_SIZE, extension_none)
else SET_OPT_ID(is_check_skew, IS_CHECK_ASKEW, extension_none)
else SET_OPT_ID(skew_range, ASKEW_RANGE, extension_none)
else SET_OPT_ID(black_white_threshold, BINARY_THRESHOLD, extension_none)
else SET_OPT_ID(is_photo_mode, IS_PHOTO_MODE, extension_none)
else SET_OPT_ID(double_feed_handle, DOUBLE_FEED_HANDLE, extension_none)
else SET_OPT_ID(scan_when_paper_on, WAIT_TO_SCAN, extension_none)
else SET_OPT_ID(feed_strength, FEED_STRENGTH, extension_none)
else SET_OPT_ID(power_scheme, TIME_TO_SLEEP, extension_none)
else SET_OPT_ID(is_auto_strength, IS_AUTO_FEED_STRENGTH, extension_none)
else SET_OPT_ID(feed_strength_value , FEED_STRENGTH_VALUE, extension_none)
else SET_OPT_ID(is_reverse_bw, REVERSE_01, extension_none)
else SET_OPT_ID(is_erase_hole_l, RID_HOLE_L, extension_none)
else SET_OPT_ID(search_hole_range_l, SEARCH_HOLE_RANGE_L, extension_none)
else SET_OPT_ID(is_erase_hole_r, RID_HOLE_R, extension_none)
else SET_OPT_ID(search_hole_range_r, SEARCH_HOLE_RANGE_R, extension_none)
else SET_OPT_ID(is_erase_hole_t, RID_HOLE_T, extension_none)
else SET_OPT_ID(search_hole_range_t, SEARCH_HOLE_RANGE_T, extension_none)
else SET_OPT_ID(is_erase_hole_b, RID_HOLE_B, extension_none)
else SET_OPT_ID(search_hole_range_b, SEARCH_HOLE_RANGE_B, extension_none)
else SET_OPT_ID(fold_direction, FOLD_TYPE, extension_none)
else SET_OPT_ID(color_correction, COLOR_CORRECTION, extension_none)
else SET_OPT_ID(language, LANGUAGE, extension_none)
else SET_OPT_ID(discardblank, DISCARDBLANK, extension_none)
else SET_OPT_ID(lens_dirty, LENS_DIRTY, extension_none)
op_id++;
}
#define EX_APPENDIX_API(name) \
{ \
EXAPI ea; \
ea.ind = ex_##name##_id_ = ex_id_++; \
ea.ex_api = &scanner::handle_ex_##name; \
ea.base_ind = -1; \
ex_opts_.push_back(ea); \
}
EX_APPENDIX_API(final_compression);
EX_APPENDIX_API(final_format);
EX_APPENDIX_API(serial);
EX_APPENDIX_API(to_be_scan);
EX_APPENDIX_API(scan_with_hole);
EX_APPENDIX_API(device_code);
EX_APPENDIX_API(power);
EX_APPENDIX_API(hardware_version);
EX_APPENDIX_API(ip);
if (black_white_threshold_id_ == -1)
black_white_threshold_id_ = 0x8836;
if (is_erase_hole_id_ == -1)
{
// 闁稿繒鍘ч鎰版嚀娴g儤鐣遍梻鍕╁€曢悺鐔虹不濡や胶銆?
EXAPI ea;
ea.ind = is_erase_hole_id_ = ex_id_++;
ea.base_ind = is_erase_hole_l_id_;
ea.ex_api = &scanner::handle_ex_erase_hole;
ex_opts_.push_back(ea);
ea.ind = search_hole_range_id_ = ex_id_++;
ea.base_ind = search_hole_range_l_id_;
ea.ex_api = &scanner::handle_ex_search_hole_range;
ex_opts_.push_back(ea);
}
return ret;
}
int scanner::control_read_string(int code, std::string& ret)
{
return scanner::control_read_string(handle_, code, ret);
}
void scanner::extension_none(int id)
{
}
void scanner::extension_multiout_type(int id)
{
EXAPI ea;
ex_multiout_type_id_ = ex_id_++;
ea.ind = ex_multiout_type_id_;
ea.base_ind = id;
ea.ex_api = &scanner::handle_ex_multiout;
ex_opts_.push_back(ea);
}
void scanner::extension_color_mode(int id)
{
EXAPI ea;
ea.ind = ex_color_mode_id_ = ex_id_++;
ea.base_ind = id;
ea.ex_api = &scanner::handle_ex_color_mode;
ex_opts_.push_back(ea);
ex_auto_color_type_id_ = ex_id_++;
ea.base_ind = id;
ea.ind = ex_auto_color_type_id_;
ea.ex_api = &scanner::handle_ex_auto_color_type;
ex_opts_.push_back(ea);
}
void scanner::extension_sharpen(int id)
{
EXAPI ea;
ex_sharpen_id_ = ex_id_++;
ea.base_ind = id;
ea.ind = ex_sharpen_id_;
ea.ex_api = &scanner::handle_ex_sharpen;
ex_opts_.push_back(ea);
}
void scanner::extension_paper(int id)
{
EXAPI ea;
ea.ind = ex_paper_id_ = ex_id_++;
ea.base_ind = id;
ea.ex_api = &scanner::handle_ex_paper;
ex_opts_.push_back(ea);
ea.ind = ex_paper_lateral_id_ = ex_id_++;
ea.base_ind = id;
ea.ex_api = &scanner::handle_ex_paper_lateral;
ex_opts_.push_back(ea);
ea.ind = ex_auto_paper_size_id_ = ex_id_++;
ea.base_ind = id;
ea.ex_api = &scanner::handle_ex_auto_paper_size;
ex_opts_.push_back(ea);
ea.ind = ex_is_paper_auto_crop_id_ = ex_id_++;
ea.base_ind = id;
ea.ex_api = &scanner::handle_ex_auto_paper_crop;
ex_opts_.push_back(ea);
}
void scanner::extension_fill_bkg_method(int id)
{
EXAPI ea;
ea.ind = ex_fill_background_id_ = ex_id_++;
ea.base_ind = id;
ea.ex_api = &scanner::handle_ex_fill_background;
ex_opts_.push_back(ea);
}
void scanner::extension_text_direction(int id)
{
EXAPI ea;
ea.ind = ex_text_direction_id_ = ex_id_++;
ea.base_ind = id;
ea.ex_api = &scanner::handle_ex_text_direction;
ex_opts_.push_back(ea);
}
void scanner::extension_page(int id)
{
EXAPI ea;
wchar_t msg[128] = { 0 };
ea.ind = ex_duplex_id_ = ex_id_++;
ea.base_ind = id;
ea.ex_api = &scanner::handle_ex_duplex;
ex_opts_.push_back(ea);
{
swprintf_s(msg, _countof(msg) - 1, L"handle_ex_duplex of id: %d\r\n", ea.ind);
log_info(msg, 0);
}
ea.ind = ex_discard_blank_page_id_ = ex_id_++;
ea.base_ind = id;
ea.ex_api = &scanner::handle_ex_discard_blank_page;
ex_opts_.push_back(ea);
{
swprintf_s(msg, _countof(msg) - 1, L"handle_ex_discard_blank_page of id: %d\r\n", ea.ind);
log_info(msg, 0);
}
ea.ind = ex_discard_blank_receipt_id_ = ex_id_++;
ea.base_ind = id;
ea.ex_api = &scanner::handle_ex_discard_blank_receipt;
ex_opts_.push_back(ea);
{
swprintf_s(msg, _countof(msg) - 1, L"handle_ex_discard_blank_receipt of id: %d\r\n", ea.ind);
log_info(msg, 0);
}
ea.ind = ex_is_page_fold_id_ = ex_id_++;
ea.base_ind = id;
ea.ex_api = &scanner::handle_ex_page_fold;
ex_opts_.push_back(ea);
{
swprintf_s(msg, _countof(msg) - 1, L"handle_ex_page_fold of id: %d\r\n", ea.ind);
log_info(msg, 0);
}
}
void scanner::extension_erase_color(int id)
{
EXAPI ea;
ea.ind = ex_color_filter_id_ = ex_id_++;
ea.base_ind = id;
ea.ex_api = &scanner::handle_ex_color_filter;
ex_opts_.push_back(ea);
ea.ind = ex_color_enhance_id_ = ex_id_++;
ea.base_ind = id;
ea.ex_api = &scanner::handle_ex_color_enhance;
ex_opts_.push_back(ea);
}
bool scanner::get_option_value_with_parent(int sn, set_opt_value setv, void* param) // return true if handled
{
bool handled = true;
if (sn == scan_count_id_)
{
SANE_Option_Descriptor* parent = hg_sane_middleware::instance()->get_option_descriptor(handle_, (const void*)scan_mode_id_);
char* buf = new char[parent->size + 4];
memset(buf, 0, parent->size);
hg_sane_middleware::instance()->get_cur_value(handle_, (void*)scan_mode_id_, buf);
handled = compare_sane_opt(local_trans::lang_trans_between_hz936(OPTION_VALUE_SMZS_LXSM, true, nullptr), buf);
delete[] buf;
if (handled)
{
int count = -1;
value_role role = VAL_ROLE_CURRENT;
buf = (char*)hg_sane_middleware::instance()->get_def_value(handle_, (void*)scan_mode_id_);
if (compare_sane_opt(local_trans::lang_trans_between_hz936(OPTION_VALUE_SMZS_LXSM, true, nullptr), buf))
role = value_role(role | VAL_ROLE_DEFAULT);
local_utility::free_memory(buf);
setv(&count, value_role(VAL_ROLE_CURRENT | VAL_ROLE_DEFAULT), VAL_LIMIT_NONE, param);
}
}
else
handled = false;
return handled;
}
bool scanner::set_option_value_with_parent(int sn, void* data, int* err) // return true if handled sn
{
bool handled = false;
if (sn == scan_count_id_)
{
SANE_Option_Descriptor* parent = hg_sane_middleware::instance()->get_option_descriptor(handle_, (void*)scan_mode_id_);
char* val = new char[parent->size + 4];
SANE_Int after = 0;
memset(val, 0, parent->size + 4);
hg_sane_middleware::instance()->get_cur_value(handle_, (void*)scan_mode_id_, val);
if (compare_sane_opt(local_trans::lang_trans_between_hz936(OPTION_VALUE_SMZS_LXSM, true, nullptr), val))
{
if (*(int*)data != -1)
{
strcpy(val, local_trans::lang_trans_between_hz936(OPTION_VALUE_SMZS_SMZDZS, true, nullptr));
*err = hg_sane_middleware::instance()->set_option(handle_, (void*)scan_mode_id_, SANE_ACTION_SET_VALUE, val, &after);
}
}
else if (*(int*)data == -1)
{
strcpy(val, local_trans::lang_trans_between_hz936(OPTION_VALUE_SMZS_LXSM, true, nullptr));
*err = hg_sane_middleware::instance()->set_option(handle_, (void*)scan_mode_id_, SANE_ACTION_SET_VALUE, val, &after);
}
delete[] val;
}
return handled;
}
int scanner::set_option_value(int sn, SANE_Value_Type type, int size, void* data)
{
char* buf = NULL;
SANE_Bool sb = SANE_FALSE;
SANE_Int si = 0, after = 0;
SANE_Fixed sf = 0;
int ret = SCANNER_ERR_OK;
void* val = data;
if (type == SANE_TYPE_BOOL)
{
sb = *(bool*)data ? SANE_TRUE : SANE_FALSE;
val = &sb;
}
else if (type == SANE_TYPE_INT)
{
si = *(int*)data;
val = &si;
}
else if (type == SANE_TYPE_FIXED)
{
sf = SANE_FIX(*(float*)data);
val = &sf;
}
else
{
buf = new char[size + 4];
memset(buf, 0, size + 4);
strcpy(buf, ((std::string*)data)->c_str());
val = buf;
}
ret = hg_sane_middleware::instance()->set_option(handle_, (void*)sn, SANE_ACTION_SET_VALUE, val, &after);
if (type == SANE_TYPE_BOOL)
{
*(bool*)data = sb == SANE_TRUE;
}
else if (type == SANE_TYPE_INT)
{
*(int*)data = si;
}
else if (type == SANE_TYPE_FIXED)
{
*(float*)data = (float)SANE_UNFIX(sf);
}
else if(buf)
{
strcpy((char*)val, buf);
delete[] buf;
}
return ret;
}
int scanner::set_is_multiout(bool enable)
{
int ret = SCANNER_ERR_OK;
if (is_multiout_id_ > 0)
{
SANE_Bool multi = SANE_FALSE;
SANE_Int after = 0;
hg_sane_middleware::instance()->get_cur_value(handle_, (void*)is_multiout_id_, &multi); // parent item ...
if (enable ^ (multi == SANE_TRUE))
{
multi = enable ? SANE_TRUE : SANE_FALSE;
ret = hg_sane_middleware::instance()->set_option(handle_, (void*)is_multiout_id_, SANE_ACTION_SET_VALUE, &multi, &after);
after = 0;
}
}
return ret;
}
int scanner::thread_start(void)
{
is_in_working_thread_ = false;
scan_over_ = false;
double_handle_ = DOUBLE_FEED_NEED_UI;
unsigned int l = sizeof(img_fmt_);
SANE_CompressionType cmprsn = img_fmt_.compress.compression;
if (hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_GET_FINAL_IMAGE_FORMAT, &img_fmt_, &l))
img_fmt_.img_format = SANE_IMAGE_TYPE_BMP;
img_fmt_.compress.compression = cmprsn;
int ret = hg_sane_middleware::instance()->start(handle_, NULL);
// the third-APPs in linux will call 'stop' after every start, but it not happens in windows-apps, so we handle this as following ...
//if (ret == SANE_STATUS_NO_DOCS && prev_start_result_ == SANE_STATUS_GOOD)
// ret = hg_sane_middleware::instance()->start(handle_, NULL);
if (ret == SANE_STATUS_GOOD || ret == SCANNER_ERR_DEVICE_DOUBLE_FEEDING)
{
/*if (indicator_.get() && !IsWindowVisible(indicator_->hwnd()))
indicator_->show(true);*/
}
else
{
err_ = ret;
//startʧ<74>ܻ<EFBFBD><DCBB><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD>Ͳ<EFBFBD><CDB2>ٵ<EFBFBD><D9B5>ûص<C3BB>֪ͨ BUG-814
if (ui_notify)
{
ui_notify(SANE_EVENT_WORKING, NULL, 0);
ui_notify(SANE_EVENT_SCAN_FINISHED, (void*)hg_scanner_err_description(ret), ret);
while (is_scanning_)
std::this_thread::sleep_for(std::chrono::milliseconds(3));
}
else if (callback::show_messagebox_ui)
{
callback::show_messagebox_ui(app_wnd_, ret, (void*)hg_scanner_err_description(ret), 0);
}
else
{
std::wstring msg(local_trans::a2u(hg_scanner_err_description(ret), CP_UTF8));
if (!IsWindow(app_wnd_))
callback::bring_message_box_topmost(local_trans::lang_trans_between_hz936(CONST_STRING_START_FAILED).c_str());
MessageBoxW(app_wnd_, msg.c_str(), local_trans::lang_trans_between_hz936(CONST_STRING_START_FAILED).c_str(), MB_OK | MB_ICONERROR);
}
scan_over_ = true;
is_scanning_ = false;
}
prev_start_result_ = ret;
return ret;
}
int scanner::thread_start_after_keep()
{
is_in_working_thread_ = false;
int ret = hg_sane_middleware::instance()->start(handle_, NULL);
if (ret != SANE_STATUS_GOOD && ret != SCANNER_ERR_DEVICE_DOUBLE_FEEDING)
{
if (callback::show_progress_ui && is_bIndicator && ui_notify)
{
int ev = ret;
if (!is_in_working_thread_)
ui_notify(SANE_EVENT_SCAN_FINISHED, (void*)hg_scanner_err_description(ret), ret);
}
else
{
scan_over_ = true;
if (callback::close_ui)
callback::close_ui(UI_INDICATOR);
if (callback::show_messagebox_ui)
{
callback::show_messagebox_ui(app_wnd_, ret, (void*)hg_scanner_err_description(ret), 0);
}
else
{
std::wstring msg(local_trans::a2u(hg_scanner_err_description(ret), CP_UTF8));
if (!IsWindow(app_wnd_))
callback::bring_message_box_topmost(local_trans::lang_trans_between_hz936(CONST_STRING_START_FAILED).c_str());
MessageBoxW(app_wnd_, msg.c_str(), local_trans::lang_trans_between_hz936(CONST_STRING_START_FAILED).c_str(), MB_OK | MB_ICONERROR);
}
is_scanning_ = false;
}
}
return ret;
}
scanner::EXAPIPOS scanner::find_ex_api(int op_id)
{
return std::find(ex_opts_.begin(), ex_opts_.end(), op_id);
}
void scanner::apply_scheme(gb::sane_config_schm* schm)
{
// restore ...
hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_RESTORE_SETTINGS, nullptr, nullptr);
if (!schm)
return;
std::string n(""), v(""), ver(schm->get_version());
if (schm->first_config(n, v))
{
do
{
int id = schm->id_from_name(n.c_str());
if (id == -1)
{
if (gb::sane_config_schm::is_option_data(n))
{
id = schm->id_from_name(n.c_str());
if (id == is_custom_gamma_id_)
{
if (v.length() == sizeof(SANE_Gamma))
{
unsigned int l = v.length();
hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_SET_CUSTOM_GAMMA, &v[0], &l);
}
else
{
wchar_t info[128] = { 0 };
swprintf_s(info, _countof(info) - 1, L"ERROR: custom gamma data length is %u, but we expect %u.\r\n", v.length(), sizeof(SANE_Gamma));
log_info(info, 1);
}
}
}
}
else
{
v = from_default_language(v.c_str(), nullptr);
void* data = &v[0];
SANE_Fixed fixed = 0;
const SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, (const void*)id);
if (desc)
{
char* buf = NULL;
SANE_Int after = 0;
if (desc->type == SANE_TYPE_STRING)
{
buf = new char[desc->size + 4];
memset(buf, 0, desc->size + 4);
strcpy(buf, v.c_str());
data = buf;
}
hg_sane_middleware::instance()->set_option(handle_, (const void*)id, SANE_ACTION_SET_VALUE, data, &after);
if (buf)
delete[] buf;
}
}
} while (schm->next_config(n, v));
}
}
EX_OPTION_HANDLER_IMPL(multiout)
{
int ret = SCANNER_ERR_OK;
SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, (void*)base_id);
SANE_Bool parent = SANE_FALSE;
hg_sane_middleware::instance()->get_cur_value(handle_, (void*)is_multiout_id_, &parent);
if (setv)
{
char* cur = (char*)hg_sane_middleware::instance()->get_cur_value(handle_, (void*)base_id),
* def = (char*)hg_sane_middleware::instance()->get_def_value(handle_, (void*)base_id);
int now = sane_opt_trans::multiout_value_to_twain(cur),
init = sane_opt_trans::multiout_value_to_twain(def),
val = 0;
local_utility::free_memory(def);
local_utility::free_memory(cur);
{
// parent item ...
if (!parent)
now = MULTI_OUT_NONE;
}
do
{
if (desc->constraint_type == SANE_CONSTRAINT_STRING_LIST)
{
// we have no 'MULTI_OUT_NONE' item in this option, this is used as is_multiout_id_
val = MULTI_OUT_NONE;
value_role role = val == now ? VAL_ROLE_CURRENT : VAL_ROLE_NONE;
if (val == init)
role = (value_role)(role | VAL_ROLE_DEFAULT);
if (!setv(&val, role, VAL_LIMIT_ENUM, data))
break;
for (int i = 0; desc->constraint.string_list[i]; ++i)
{
value_role role = VAL_ROLE_NONE;
val = sane_opt_trans::multiout_value_to_twain(desc->constraint.string_list[i]);
if (val == now)
role = VAL_ROLE_CURRENT;
if (val == init)
role = value_role(role | VAL_ROLE_DEFAULT);
if (!setv(&val, role, VAL_LIMIT_ENUM, data))
break;
}
}
else
set_cur_and_def_value<int>(now, init, setv, data);
} while (0);
}
else
{
char* val = new char[desc->size];
const char* in = sane_opt_trans::multiout_value_from_twain(*(int*)data);
SANE_Int after = 0;
//if (in && strcmp(in, "\346\227\240"))
//{
// ret = set_is_multiout(true);
// if (ret == SANE_STATUS_GOOD)
// {
strcpy(val, in);
ret = hg_sane_middleware::instance()->set_option(handle_, (void*)base_id, SANE_ACTION_SET_VALUE, val, &after);
// }
//}
//else
//{
// // disable multi-out, let multiout type aside
// ret = set_is_multiout(false);
//}
delete[] val;
ret = local_utility::sane_statu_2_scanner_err(ret);
}
return ret;
}
EX_OPTION_HANDLER_IMPL(auto_color_type)
{
int ret = SCANNER_ERR_OK;
SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, (void*)base_id);
int len = desc->size + 4;
char* buf = new char[len];
memset(buf, 0, len);
hg_sane_middleware::instance()->get_cur_value(handle_, (void*)base_id, buf);
if (setv)
{
char* def = (char*)hg_sane_middleware::instance()->get_def_value(handle_, (void*)base_id);
int init = sane_opt_trans::auto_color_type_to_twain(def);
local_utility::free_memory(def);
len = sane_opt_trans::auto_color_type_to_twain(buf);
set_cur_and_def_value<int>(len, init, setv, data);
}
else
{
SANE_Int after = 0;
// ret = set_is_multiout(false);
if (ret == SCANNER_ERR_OK)
{
strcpy(buf, sane_opt_trans::auto_color_type_from_twain(*(int*)data));
ret = hg_sane_middleware::instance()->set_option(handle_, (void*)base_id, SANE_ACTION_SET_VALUE, buf, &after);
}
ret = local_utility::sane_statu_2_scanner_err(ret);
}
delete[] buf;
return ret;
}
EX_OPTION_HANDLER_IMPL(color_mode)
{
int ret = SCANNER_ERR_OK;
SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, (void*)base_id);
if (setv)
{
char* cur = (char*)hg_sane_middleware::instance()->get_cur_value(handle_, (void*)base_id),
* def = (char*)hg_sane_middleware::instance()->get_def_value(handle_, (void*)base_id);
int now = sane_opt_trans::color_mode_to_twain(cur), // sane_opt_trans::multiout_value_to_twain(cur)
init = sane_opt_trans::color_mode_to_twain(def),
val = 0;
local_utility::free_memory(def);
local_utility::free_memory(cur);
do
{
if (desc->constraint_type == SANE_CONSTRAINT_STRING_LIST)
{
for (int i = 0; desc->constraint.string_list[i]; ++i)
{
value_role role = VAL_ROLE_NONE;
val = sane_opt_trans::color_mode_to_twain(desc->constraint.string_list[i]);
if (val == now)
role = VAL_ROLE_CURRENT;
if (val == init)
role = value_role(role | VAL_ROLE_DEFAULT);
if (!setv(&val, role, VAL_LIMIT_ENUM, data))
break;
}
}
else
set_cur_and_def_value<int>(now, init, setv, data);
} while (0);
}
else
{
SANE_Int after = 0;
// ret = set_is_multiout(false);
if (ret == SCANNER_ERR_OK)
{
char* val = new char[desc->size];
const char* in = sane_opt_trans::color_mode_from_twain(*(int*)data);
strcpy(val, in);
ret = hg_sane_middleware::instance()->set_option(handle_, (void*)base_id, SANE_ACTION_SET_VALUE, val, &after);
delete[] val;
}
ret = local_utility::sane_statu_2_scanner_err(ret);
}
return ret;
}
EX_OPTION_HANDLER_IMPL(sharpen)
{
int ret = SCANNER_ERR_OK;
SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, (void*)base_id);
if (setv)
{
char* cur = (char*)hg_sane_middleware::instance()->get_cur_value(handle_, (void*)base_id),
* def = (char*)hg_sane_middleware::instance()->get_def_value(handle_, (void*)base_id);
int now = sane_opt_trans::multiout_value_to_twain(cur),
init = sane_opt_trans::sharpen_to_twain(def),
val = 0;
local_utility::free_memory(def);
local_utility::free_memory(cur);
do
{
if (desc->constraint_type == SANE_CONSTRAINT_STRING_LIST)
{
for (int i = 0; desc->constraint.string_list[i]; ++i)
{
value_role role = VAL_ROLE_NONE;
val = sane_opt_trans::sharpen_to_twain(desc->constraint.string_list[i]);
if (val == now)
role = VAL_ROLE_CURRENT;
if (val == init)
role = value_role(role | VAL_ROLE_DEFAULT);
if (!setv(&val, role, VAL_LIMIT_ENUM, data))
break;
}
}
else
set_cur_and_def_value<int>(now, init, setv, data);
} while (0);
}
else
{
char* val = new char[desc->size];
const char* in = sane_opt_trans::sharpen_from_twain(*(int*)data);
SANE_Int after = 0;
strcpy(val, in);
ret = hg_sane_middleware::instance()->set_option(handle_, (void*)base_id, SANE_ACTION_SET_VALUE, val, &after);
delete[] val;
ret = local_utility::sane_statu_2_scanner_err(ret);
}
return ret;
}
EX_OPTION_HANDLER_IMPL(paper)
{
int ret = SCANNER_ERR_OK;
SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, (void*)base_id);
int len = desc->size + 4;
char* buf = new char[len];
memset(buf, 0, len);
if (setv)
{
hg_sane_middleware::instance()->get_cur_value(handle_, (void*)base_id, buf);
char* def = (char*)hg_sane_middleware::instance()->get_def_value(handle_, (void*)base_id);
int now = sane_opt_trans::paper_to_twain(buf),
init = sane_opt_trans::paper_to_twain(def),
val = 0;
std::vector<int> exists;
local_utility::free_memory(def);
do
{
if (desc->constraint_type == SANE_CONSTRAINT_STRING_LIST)
{
for (int i = 0; desc->constraint.string_list[i]; ++i)
{
value_role role = VAL_ROLE_NONE;
val = sane_opt_trans::paper_to_twain(desc->constraint.string_list[i]);
if (val == -1 || std::find(exists.begin(), exists.end(), val) != exists.end())
continue;
exists.push_back(val);
if (val == now)
role = VAL_ROLE_CURRENT;
if (val == init)
role = value_role(role | VAL_ROLE_DEFAULT);
if (!setv(&val, role, VAL_LIMIT_ENUM, data))
break;
}
}
else
set_cur_and_def_value<int>(now, init, setv, data);
} while (0);
}
else if (sane_opt_trans::paper_from_twain(*(int*)data))
{
SANE_Int after = 0;
strcpy(buf, sane_opt_trans::paper_from_twain(*(int*)data));
ret = hg_sane_middleware::instance()->set_option(handle_, (void*)base_id, SANE_ACTION_SET_VALUE, buf, &after);
}
else
ret = SCANNER_ERR_INVALID_PARAMETER;
delete[] buf;
return ret;
}
EX_OPTION_HANDLER_IMPL(paper_lateral)
{
int ret = SCANNER_ERR_OK;
SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, (void*)base_id);
int len = desc->size + 4;
char* buf = new char[len];
const char* lateral_swap = NULL;
bool lateral = false;
memset(buf, 0, len);
hg_sane_middleware::instance()->get_cur_value(handle_, (void*)base_id, buf);
lateral_swap = sane_opt_trans::switch_paper_lateral(buf);
lateral = sane_opt_trans::is_paper_lateral(buf);
if (setv)
{
set_cur_and_def_value<bool>(lateral, false, setv, data);
}
else if (lateral_swap)
{
SANE_Int after = 0;
if (lateral != *(bool*)data)
{
strcpy(buf, lateral_swap);
ret = hg_sane_middleware::instance()->set_option(handle_, (void*)base_id, SANE_ACTION_SET_VALUE, buf, &after);
ret = local_utility::sane_statu_2_scanner_err(ret);
}
}
else
{
SANE_Int after = 0;
if (*(bool*)data)
{
// set to A4Lateral ...
strcpy(buf, local_trans::lang_trans_between_hz936(OPTION_VALUE_ZZCC_A4HX, true, nullptr));
ret = hg_sane_middleware::instance()->set_option(handle_, (void*)base_id, SANE_ACTION_SET_VALUE, buf, &after);
ret = local_utility::sane_statu_2_scanner_err(ret);
}
//ret = SCANNER_ERR_DEVICE_NOT_SUPPORT;
}
delete[] buf;
return ret;
}
EX_OPTION_HANDLER_IMPL(auto_paper_size)
{
int ret = SCANNER_ERR_OK;
SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, (void*)base_id);
int len = desc->size + 4;
char* buf = new char[len];
memset(buf, 0, len);
hg_sane_middleware::instance()->get_cur_value(handle_, (void*)base_id, buf);
if (setv)
{
char* init = (char*)hg_sane_middleware::instance()->get_def_value(handle_, (void*)base_id);
bool yes = strcmp(buf, local_trans::lang_trans_between_hz936(OPTION_VALUE_ZZCC_PPYSCC, true, nullptr)) == 0,
def = strcmp(init, local_trans::lang_trans_between_hz936(OPTION_VALUE_ZZCC_PPYSCC, true, nullptr)) == 0;
local_utility::free_memory(init);
set_cur_and_def_value<bool>(yes, def, setv, data);
}
else
{
SANE_Int after = 0;
strcpy(buf, *(bool*)data ? local_trans::lang_trans_between_hz936(OPTION_VALUE_ZZCC_PPYSCC, true, nullptr) : local_trans::lang_trans_between_hz936(OPTION_VALUE_ZZCC_A4, true, nullptr));
ret = hg_sane_middleware::instance()->set_option(handle_, (void*)base_id, SANE_ACTION_SET_VALUE, buf, &after);
ret = local_utility::sane_statu_2_scanner_err(ret);
}
delete[] buf;
return ret;
}
EX_OPTION_HANDLER_IMPL(auto_paper_crop)
{
int ret = SCANNER_ERR_OK;
SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, (void*)base_id);
int len = desc->size + 4;
char* buf = new char[len];
memset(buf, 0, len);
hg_sane_middleware::instance()->get_cur_value(handle_, (void*)base_id, buf);
if (setv)
{
char* init = (char*)hg_sane_middleware::instance()->get_def_value(handle_, (void*)base_id);
bool yes = strcmp(buf, local_trans::lang_trans_between_hz936(OPTION_VALUE_ZZCC_ZDSMCCZDCQ, true, nullptr)) == 0,
def = strcmp(init, OPTION_VALUE_ZZCC_ZDSMCCZDCQ) == 0;
local_utility::free_memory(init);
set_cur_and_def_value<bool>(yes, def, setv, data);
}
else
{
SANE_Int after = 0;
strcpy(buf, *(bool*)data ? local_trans::lang_trans_between_hz936(OPTION_VALUE_ZZCC_ZDSMCCZDCQ, true, nullptr) : local_trans::lang_trans_between_hz936(OPTION_VALUE_ZZCC_ZDSMCC, true, nullptr));
ret = hg_sane_middleware::instance()->set_option(handle_, (void*)base_id, SANE_ACTION_SET_VALUE, buf, &after);
ret = local_utility::sane_statu_2_scanner_err(ret);
}
delete[] buf;
return ret;
}
EX_OPTION_HANDLER_IMPL(text_direction)
{
int ret = SCANNER_ERR_OK;
SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, (void*)base_id);
int len = desc->size + 4;
char* buf = new char[len];
memset(buf, 0, len);
if (setv)
{
char* def = (char*)hg_sane_middleware::instance()->get_def_value(handle_, (void*)base_id);
float now = .0f, init = sane_opt_trans::text_direction_to_twain(def), val = .0f;
local_utility::free_memory(def);
hg_sane_middleware::instance()->get_cur_value(handle_, (void*)base_id, buf);
now = sane_opt_trans::text_direction_to_twain(buf);
do
{
if (desc->constraint_type == SANE_CONSTRAINT_STRING_LIST)
{
for (int i = 0; desc->constraint.string_list[i]; ++i)
{
value_role role = VAL_ROLE_NONE;
val = sane_opt_trans::text_direction_to_twain(desc->constraint.string_list[i]);
if (IS_DOUBLE_EQUAL(val, now))
role = VAL_ROLE_CURRENT;
if (IS_DOUBLE_EQUAL(val, init))
role = value_role(role | VAL_ROLE_DEFAULT);
if (!setv(&val, role, VAL_LIMIT_ENUM, data))
break;
}
}
else
set_cur_and_def_value<float>(now, init, setv, data);
} while (0);
}
else
{
SANE_Int after = 0;
strcpy(buf, sane_opt_trans::text_direction_from_twain(*(float*)data));
ret = hg_sane_middleware::instance()->set_option(handle_, (void*)base_id, SANE_ACTION_SET_VALUE, buf, &after);
ret = local_utility::sane_statu_2_scanner_err(ret);
}
delete[] buf;
return ret;
}
EX_OPTION_HANDLER_IMPL(duplex)
{
int ret = SCANNER_ERR_OK;
bool val = *(bool*)data;
SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, (void*)base_id);
unsigned len = desc->size + 4;
char* buf = new char[len];
memset(buf, 0, len);
if (setv)
{
char* init = (char*)hg_sane_middleware::instance()->get_def_value(handle_, (void*)base_id);
hg_sane_middleware::instance()->get_cur_value(handle_, (void*)base_id, buf);
set_cur_and_def_value<bool>(strcmp(buf, local_trans::lang_trans_between_hz936(OPTION_VALUE_SMYM_SM, true, nullptr)) == 0, strcmp(init, local_trans::lang_trans_between_hz936(OPTION_VALUE_SMYM_SM, true, nullptr)) == 0, setv, data);
local_utility::free_memory(init);
}
else
{
strcpy(buf, val ? local_trans::lang_trans_between_hz936(OPTION_VALUE_SMYM_SM, true, nullptr) : local_trans::lang_trans_between_hz936(OPTION_VALUE_SMYM_DM, true, nullptr));
SANE_Int after = 0;
ret = hg_sane_middleware::instance()->set_option(handle_, (void*)base_id, SANE_ACTION_SET_VALUE, buf, &after);
ret = local_utility::sane_statu_2_scanner_err(ret);
}
delete[] buf;
return ret;
}
EX_OPTION_HANDLER_IMPL(fill_background)
{
int ret = SCANNER_ERR_OK;
bool val = *(bool*)data;
SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, (void*)base_id);
unsigned len = desc->size + 4;
char* buf = new char[len];
memset(buf, 0, len);
if (setv)
{
char* init = (char*)hg_sane_middleware::instance()->get_def_value(handle_, (void*)base_id);
hg_sane_middleware::instance()->get_cur_value(handle_, (void*)base_id, buf);
val = strcmp(buf, local_trans::lang_trans_between_hz936(OPTION_VALUE_SMYM_SM, true, nullptr)) == 0;
set_cur_and_def_value<bool>(strcmp(buf, local_trans::lang_trans_between_hz936(OPTION_VALUE_BJTCFS_TDBX, true, nullptr)) == 0, strcmp(init, local_trans::lang_trans_between_hz936(OPTION_VALUE_BJTCFS_TDBX, true, nullptr)) == 0, setv, data);
local_utility::free_memory(init);
}
else
{
strcpy(buf, val ? local_trans::lang_trans_between_hz936(OPTION_VALUE_BJTCFS_TDBX, true, nullptr) : local_trans::lang_trans_between_hz936(OPTION_VALUE_BJTCFS_ADBX, true, nullptr));
SANE_Int after = 0;
ret = hg_sane_middleware::instance()->set_option(handle_, (void*)base_id, SANE_ACTION_SET_VALUE, buf, &after);
ret = local_utility::sane_statu_2_scanner_err(ret);
}
delete[] buf;
return ret;
}
EX_OPTION_HANDLER_IMPL(discard_blank_page)
{
int ret = SCANNER_ERR_OK;
bool val = *(bool*)data;
SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, (void*)base_id);
unsigned len = desc->size + 4;
char* buf = new char[len];
memset(buf, 0, len);
if (setv)
{
char* init = (char*)hg_sane_middleware::instance()->get_def_value(handle_, (void*)base_id);
bool def = strcmp(init, local_trans::lang_trans_between_hz936(OPTION_VALUE_SMYM_TGKBYTY, true, nullptr)) == 0;
local_utility::free_memory(init);
hg_sane_middleware::instance()->get_cur_value(handle_, (void*)base_id, buf);
val = strcmp(buf, local_trans::lang_trans_between_hz936(OPTION_VALUE_SMYM_TGKBYTY, true, nullptr)) == 0;
set_cur_and_def_value<bool>(val, def, setv, data);
}
else
{
if (val)
strcpy(buf, local_trans::lang_trans_between_hz936(OPTION_VALUE_SMYM_TGKBYTY, true, nullptr));
else
{
char* init = (char*)hg_sane_middleware::instance()->get_def_value(handle_, (void*)base_id);
strcpy(buf, init);
local_utility::free_memory(init);
}
SANE_Int after = 0;
ret = hg_sane_middleware::instance()->set_option(handle_, (void*)base_id, SANE_ACTION_SET_VALUE, buf, &after);
ret = local_utility::sane_statu_2_scanner_err(ret);
}
delete[] buf;
return ret;
}
EX_OPTION_HANDLER_IMPL(discard_blank_receipt)
{
int ret = SCANNER_ERR_OK;
bool val = *(bool*)data;
SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, (void*)base_id);
unsigned len = desc->size + 4;
char* buf = new char[len];
memset(buf, 0, len);
if (setv)
{
char* init = (char*)hg_sane_middleware::instance()->get_def_value(handle_, (void*)base_id);
bool def = strcmp(init, local_trans::lang_trans_between_hz936(OPTION_VALUE_SMYM_TGKBYFPZ, true, nullptr)) == 0;
local_utility::free_memory(init);
hg_sane_middleware::instance()->get_cur_value(handle_, (void*)base_id, buf);
val = strcmp(buf, local_trans::lang_trans_between_hz936(OPTION_VALUE_SMYM_TGKBYFPZ, true, nullptr)) == 0;
set_cur_and_def_value<bool>(val, def, setv, data);
}
else
{
if (val)
strcpy(buf, local_trans::lang_trans_between_hz936(OPTION_VALUE_SMYM_TGKBYFPZ, true, nullptr));
else
{
char* init = (char*)hg_sane_middleware::instance()->get_def_value(handle_, (void*)base_id);
strcpy(buf, init);
local_utility::free_memory(init);
}
SANE_Int after = 0;
ret = hg_sane_middleware::instance()->set_option(handle_, (void*)base_id, SANE_ACTION_SET_VALUE, buf, &after);
ret = local_utility::sane_statu_2_scanner_err(ret);
}
delete[] buf;
return ret;
}
EX_OPTION_HANDLER_IMPL(page_fold)
{
int ret = SCANNER_ERR_OK;
bool val = *(bool*)data;
SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, (void*)base_id);
unsigned len = desc->size + 4;
char* buf = new char[len];
memset(buf, 0, len);
if (setv)
{
char* init = (char*)hg_sane_middleware::instance()->get_def_value(handle_, (void*)base_id);
bool def = strcmp(init, local_trans::lang_trans_between_hz936(OPTION_VALUE_SMYM_DZ, true, nullptr)) == 0;
local_utility::free_memory(init);
hg_sane_middleware::instance()->get_cur_value(handle_, (void*)base_id, buf);
val = strcmp(buf, local_trans::lang_trans_between_hz936(OPTION_VALUE_SMYM_DZ, true, nullptr)) == 0;
set_cur_and_def_value<bool>(val, def, setv, data);
}
else
{
if (val)
strcpy(buf, local_trans::lang_trans_between_hz936(OPTION_VALUE_SMYM_DZ, true, nullptr));
else
{
char* init = (char*)hg_sane_middleware::instance()->get_def_value(handle_, (void*)base_id);
strcpy(buf, init);
local_utility::free_memory(init);
}
SANE_Int after = 0;
ret = hg_sane_middleware::instance()->set_option(handle_, (void*)base_id, SANE_ACTION_SET_VALUE, buf, &after);
ret = local_utility::sane_statu_2_scanner_err(ret);
}
delete[] buf;
return ret;
}
EX_OPTION_HANDLER_IMPL(color_filter) // int (filter_value)
{
int ret = SCANNER_ERR_DEVICE_NOT_SUPPORT;
SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, (void*)base_id);
char* buf = NULL;
unsigned int len = 0;
if (desc)
{
len = desc->size + 4;
buf = new char[len];
memset(buf, 0, len);
if (setv)
{
bool filter = false;
int val = FILTER_NONE, now = FILTER_NONE;
hg_sane_middleware::instance()->get_cur_value(handle_, (void*)base_id, buf);
now = sane_opt_trans::filter_enhance_value_to_twain(buf, &filter);
if (!filter)
now = val;
do
{
if (desc->constraint_type == SANE_CONSTRAINT_STRING_LIST)
{
for (int i = 0; desc->constraint.string_list[i]; ++i)
{
value_role role = VAL_ROLE_NONE;
int v = sane_opt_trans::filter_enhance_value_to_twain(desc->constraint.string_list[i], &filter);
if (!filter && v != FILTER_NONE)
continue;
if (v == now)
role = VAL_ROLE_CURRENT;
if (v == val)
role = value_role(role | VAL_ROLE_DEFAULT);
if (!setv(&v, role, VAL_LIMIT_ENUM, data))
break;
}
}
}while (0);
}
else
{
const char* val = sane_opt_trans::filter_enhance_value_from_twain(*((int*)data), true);
SANE_Int after = 0;
strcpy(buf, val);
ret = hg_sane_middleware::instance()->set_option(handle_, (void*)base_id, SANE_ACTION_SET_VALUE, buf, &after);
ret = local_utility::sane_statu_2_scanner_err(ret);
}
delete[] buf;
}
return ret;
}
EX_OPTION_HANDLER_IMPL(color_enhance) // int (enhance_value)
{
int ret = SCANNER_ERR_DEVICE_NOT_SUPPORT;
SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, (void*)base_id);
char* buf = NULL;
unsigned int len = 0;
if (desc)
{
len = desc->size + 4;
buf = new char[len];
memset(buf, 0, len);
if (setv)
{
bool filter = false;
int val = ENHANCE_NONE, now = ENHANCE_NONE;
hg_sane_middleware::instance()->get_cur_value(handle_, (void*)base_id, buf);
now = sane_opt_trans::filter_enhance_value_to_twain(buf, &filter);
if (filter)
now = val;
do
{
if (desc->constraint_type == SANE_CONSTRAINT_STRING_LIST)
{
for (int i = 0; desc->constraint.string_list[i]; ++i)
{
value_role role = VAL_ROLE_NONE;
int v = sane_opt_trans::filter_enhance_value_to_twain(desc->constraint.string_list[i], &filter);
if (filter && v != ENHANCE_NONE)
continue;
if (v == now)
role = VAL_ROLE_CURRENT;
if (v == val)
role = value_role(role | VAL_ROLE_DEFAULT);
if (!setv(&v, role, VAL_LIMIT_ENUM, data))
break;
}
}
} while (0);
}
else
{
const char* val = sane_opt_trans::filter_enhance_value_from_twain(*((int*)data), false);
SANE_Int after = 0;
strcpy(buf, val);
ret = hg_sane_middleware::instance()->set_option(handle_, (void*)base_id, SANE_ACTION_SET_VALUE, buf, &after);
ret = local_utility::sane_statu_2_scanner_err(ret);
}
delete[] buf;
}
return ret;
}
EX_OPTION_HANDLER_IMPL(final_compression)
{
int ret = SCANNER_ERR_OK;
int* compression = (int*)data;
unsigned int len = sizeof(*compression);
if (setv)
{
int val = 0;
ret = hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_GET_FINAL_COMPRESSION, &val, &len);
if (ret == SANE_STATUS_GOOD)
{
int i = SANE_COMPRESSION_FIRST;
for (; i < SANE_COMPRESSION_LAST; ++i)
{
value_role role = VAL_ROLE_NONE;
if (i == val)
role = VAL_ROLE_CURRENT;
if (i == SANE_COMPRESSION_NONE)
role = value_role(role | VAL_ROLE_DEFAULT);
int v = sane_opt_trans::compression_to_twain(i);
if (!setv(&v, role, VAL_LIMIT_ENUM, data))
break;
}
}
}
else
{
int val = sane_opt_trans::compression_from_twain(*(int*)data);
len = sizeof(val);
ret = hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_SET_FINAL_COMPRESSION, &val, &len);
ret = local_utility::sane_statu_2_scanner_err(ret);
}
return ret;
}
EX_OPTION_HANDLER_IMPL(final_format)
{
int ret = SCANNER_ERR_OK;
SANE_FinalImgFormat ff;
unsigned int len = sizeof(ff);
if (setv)
{
ret = hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_GET_FINAL_IMAGE_FORMAT, &ff, &len);
if (ret == SANE_STATUS_GOOD)
{
int now = ff.img_format, init = SANE_IMAGE_TYPE_BMP;
std::vector<int> all(sane_opt_trans::support_image_types());
for (int i = 0; i < (int)all.size(); ++i)
{
value_role role = VAL_ROLE_NONE;
ff.img_format = (SANE_ImageType)all[i];
if (ff.img_format == now)
role = VAL_ROLE_CURRENT;
if (ff.img_format == init)
role = value_role(role | VAL_ROLE_DEFAULT);
if (!setv(&ff, role, VAL_LIMIT_ENUM, data))
break;
}
}
}
else
{
ret = hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_SET_FINAL_IMAGE_FORMAT, data, &len);
ret = local_utility::sane_statu_2_scanner_err(ret);
}
return ret;
}
EX_OPTION_HANDLER_IMPL(serial)
{
int ret = SCANNER_ERR_INVALID_PARAMETER;
if (setv)
{
std::string val("");
ret = control_read_string(IO_CTRL_CODE_GET_SERIAL, val);
if (ret == SANE_STATUS_GOOD)
setv(&val, VAL_ROLE_CURRENT, VAL_LIMIT_NONE, data);
}
return ret;
}
EX_OPTION_HANDLER_IMPL(to_be_scan)
{
int ret = SCANNER_ERR_OK;
SANE_Bool wait_paper = SANE_FALSE;
unsigned int len = sizeof(wait_paper);
if (setv)
{
ret = hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_GET_SCAN_WHEN_PAPER_ON, &wait_paper, &len);
if (ret == SANE_STATUS_GOOD)
{
bool val = wait_paper == SANE_TRUE;
set_cur_and_def_value<bool>(val, false, setv, data);
}
}
else
{
wait_paper = *((bool*)data) ? SANE_TRUE : SANE_FALSE;
ret = hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_SET_SCAN_WHEN_PAPER_ON, &wait_paper, &len);
ret = local_utility::sane_statu_2_scanner_err(ret);
}
return ret;
}
EX_OPTION_HANDLER_IMPL(scan_with_hole)
{
int ret = SCANNER_ERR_OK;
SANE_Bool with_hole = SANE_FALSE;
unsigned int len = sizeof(with_hole);
if (setv)
{
ret = hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_GET_SCAN_WITH_HOLE, &with_hole, &len);
if (ret == SANE_STATUS_GOOD)
{
bool val = with_hole == SANE_TRUE;
set_cur_and_def_value<bool>(val, false, setv, data);
}
}
else
{
with_hole = *((bool*)data) ? SANE_TRUE : SANE_FALSE;
ret = hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_SET_SCAN_WITH_HOLE, &with_hole, &len);
ret = local_utility::sane_statu_2_scanner_err(ret);
}
return ret;
}
EX_OPTION_HANDLER_IMPL(device_code)
{
int ret = SCANNER_ERR_INVALID_PARAMETER;
if (setv)
{
std::string val("");
ret = control_read_string(IO_CTRL_CODE_GET_DEVICE_CODE, val);
if (ret == SANE_STATUS_GOOD)
setv(&val, VAL_ROLE_CURRENT, VAL_LIMIT_NONE, data);
}
return ret;
}
EX_OPTION_HANDLER_IMPL(power)
{
int ret = SCANNER_ERR_OK;
if (setv)
{
SANE_Power now = SANE_POWER_MINUTES_30, init = SANE_POWER_MINUTES_30;
unsigned int len = sizeof(now);
hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_GET_POWER_LEVEL, &now, &len);
for (int i = SANE_POWER_FIRST; i < SANE_POWER_LAST; ++i)
{
value_role role = VAL_ROLE_NONE;
if (i == now)
role = VAL_ROLE_CURRENT;
if (i == init)
role = value_role(role | VAL_ROLE_DEFAULT);
SANE_Power power = (SANE_Power)i;
if (!setv(&power, role, VAL_LIMIT_ENUM, data))
break;
}
}
else
{
SANE_Power power = *((SANE_Power*)data);
unsigned int len = sizeof(power);
ret = hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_SET_POWER_LEVEL, &power, &len);
ret = local_utility::sane_statu_2_scanner_err(ret);
}
return ret;
}
EX_OPTION_HANDLER_IMPL(hardware_version)
{
int ret = SCANNER_ERR_INVALID_PARAMETER;
if (setv)
{
std::string val("");
ret = control_read_string(IO_CTRL_CODE_GET_HARDWARE_VERSION, val);
if (ret == SANE_STATUS_GOOD)
setv(&val, VAL_ROLE_CURRENT, VAL_LIMIT_NONE, data);
}
return ret;
}
EX_OPTION_HANDLER_IMPL(ip)
{
int ret = SCANNER_ERR_INVALID_PARAMETER;
if (setv)
{
std::string val("");
ret = control_read_string(IO_CTRL_CODE_GET_IP, val);
if (ret == SANE_STATUS_GOOD)
setv(&val, VAL_ROLE_CURRENT, VAL_LIMIT_NONE, data);
}
return ret;
}
EX_OPTION_HANDLER_IMPL(erase_hole)
{
int ret = SCANNER_ERR_DEVICE_NOT_SUPPORT;
if (is_erase_hole_l_id_ != -1 || is_erase_hole_r_id_ != -1)
{
SANE_Bool yes = SANE_FALSE, def = SANE_FALSE;
SANE_Int after = 0;
if (setv)
{
if (is_erase_hole_l_id_ != -1)
{
hg_sane_middleware::instance()->get_cur_value(handle_, (void*)is_erase_hole_l_id_, &yes);
hg_sane_middleware::instance()->get_def_value(handle_, (void*)is_erase_hole_l_id_, &def);
}
if (!yes && is_erase_hole_r_id_ != -1)
{
hg_sane_middleware::instance()->get_cur_value(handle_, (void*)is_erase_hole_r_id_, &yes);
hg_sane_middleware::instance()->get_def_value(handle_, (void*)is_erase_hole_r_id_, &def);
}
set_cur_and_def_value<bool>(yes == SANE_TRUE, def == SANE_TRUE, setv, data);
ret = SCANNER_ERR_OK;
}
else
{
yes = *(bool*)data ? SANE_TRUE : SANE_FALSE;
if (is_erase_hole_l_id_ != -1)
ret = hg_sane_middleware::instance()->set_option(handle_, (void*)is_erase_hole_l_id_, SANE_ACTION_SET_VALUE, &yes, &after);
yes = *(bool*)data ? SANE_TRUE : SANE_FALSE;
if (is_erase_hole_r_id_ != -1)
ret = hg_sane_middleware::instance()->set_option(handle_, (void*)is_erase_hole_r_id_, SANE_ACTION_SET_VALUE, &yes, &after);
}
}
return ret;
}
EX_OPTION_HANDLER_IMPL(search_hole_range)
{
int ret = SCANNER_ERR_DEVICE_NOT_SUPPORT;
if (search_hole_range_l_id_ != -1 || search_hole_range_r_id_ != -1)
{
SANE_Fixed val = 0;
SANE_Int after = 0;
double rv = .0f, def = .0f;
if (setv)
{
const SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, (void*)base_id);
void* init = hg_sane_middleware::instance()->get_def_value(handle_, (void*)base_id),
* cur = hg_sane_middleware::instance()->get_cur_value(handle_, (void*)base_id);
float n = SANE_UNFIX(*(SANE_Fixed*)cur),
d = SANE_UNFIX(*(SANE_Fixed*)init);
if (desc->constraint_type == SANE_CONSTRAINT_RANGE)
{
float l = SANE_UNFIX(desc->constraint.range->min),
u = SANE_UNFIX(desc->constraint.range->max),
s = SANE_UNFIX(desc->constraint.range->quant);
set_value_range<SANE_Fixed, float>(*(SANE_Fixed*)cur, *(SANE_Fixed*)init, desc->constraint.range->min, desc->constraint.range->max, desc->constraint.range->quant, setv, data, &scanner::to_float);
}
else
set_cur_and_def_value<float>(n, d, setv, data);
local_utility::free_memory(init);
local_utility::free_memory(cur);
ret = SCANNER_ERR_OK;
}
else
{
rv = (double)*(float*)data;
val = SANE_FIX(rv);
if (search_hole_range_l_id_ != -1)
ret = hg_sane_middleware::instance()->set_option(handle_, (void*)search_hole_range_l_id_, SANE_ACTION_SET_VALUE, &val, &after);
val = SANE_FIX(rv);
if (search_hole_range_r_id_ != -1)
ret = hg_sane_middleware::instance()->set_option(handle_, (void*)search_hole_range_r_id_, SANE_ACTION_SET_VALUE, &val, &after);
}
}
return ret;
}
// ISaneInvoker
COM_API_IMPLEMENT(scanner, int, start(void))
{
int ret = SANE_STATUS_GOOD;
ev_cnt_ = 0;
events_.clear();
images_.clear();
scan_msg_ = "OK";
scan_err_ = false;
user_cancel_ = false;
fetch_imgs_ = 0;
is_scanning_ = true;
err_ = SANE_STATUS_GOOD;
app_wnd_ = setting_ ? setting_->hwnd() : callback::find_main_wnd();
if (thread_starting_.get() && thread_starting_->joinable())
thread_starting_->join();
#ifdef START_SCAN_IN_THREAD
thread_starting_.reset(new std::thread(&scanner::thread_start, this));
ret = get_scanned_images(-1); // block until image arrived or scan finished
ret = ret > 0 ? 0 : err_; // received images, ensure return success. BUG-809
#else
ret = thread_start();
#endif
return ret;
}
COM_API_IMPLEMENT(scanner, int, stop(void))
{
user_cancel_ = true;
return hg_sane_middleware::instance()->stop(handle_);
}
COM_API_IMPLEMENT(scanner, int, get_event(void))
{
return events_.take();
}
COM_API_IMPLEMENT(scanner, void, set_event_callback(int(__stdcall* handle_ev)(int, void*), void* para))
{
scanner_ev_handler_ = handle_ev;
evh_param_ = para;
}
COM_API_IMPLEMENT(scanner, bool, wait_image(DWORD milliseconds))
{
int count = get_scanned_images(milliseconds);
return count > 0;
}
COM_API_IMPLEMENT(scanner, int, get_scanned_images(DWORD milliseconds))
{
size_t count = images_.count();
DWORD elapse = 2;
is_ui_wait_img_ = true;
while (is_scanning_ && count == 0 && milliseconds)
{
MSG msg = { 0 };
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
bool block_msg = false;
if (re_enter_msg_ && re_enter_msg_ == msg.message)
{
if (re_enter_msg_wp_)
{
block_msg = re_enter_msg_wp_ == msg.wParam;
}
else
{
block_msg = true;
}
}
if (!block_msg)
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
}
else
Sleep(elapse);
count = images_.count();
//int ev = get_event();
//
//if (ev == SANE_EVENT_SCAN_FINISHED)
//{
// ui_hide();
// break;
//}
//else if (ev == SANE_EVENT_UI_CLOSE_CANCEL)
//{
// stop();
// ui_hide();
// break;
//}
//else if (ev == SANE_EVENT_UI_CLOSE_NORMAL)
//{
// ui_hide();
// break;
//}
if (milliseconds != -1)
{
if (milliseconds <= elapse)
break;
milliseconds -= elapse;
}
}
is_ui_wait_img_ = false;
count = images_.count();
{
wchar_t msg[128] = { 0 };
swprintf_s(msg, _countof(msg) - 1, L"Wait image count = %d\r\n", count);
log_info(msg, 1);
}
return count;
}
COM_API_IMPLEMENT(scanner, IScanImg*, take_first_image(twain_xfer xfer))
{
scanned_img* img = images_.take(false);
if (img)
{
img->prepare_data_for_transfer(xfer);
img->add_ref();
wchar_t msg[128] = { 0 };
swprintf_s(msg, _countof(msg) - 1, L"Begin transferring image %d of %p\r\n", fetch_imgs_ + 1, img);
log_info(msg, 1);
}
return dynamic_cast<IScanImg*>(img);
}
COM_API_IMPLEMENT(scanner, bool, get_first_image_header(SANE_Parameters* header, size_t* bytes, int* dpi))
{
return images_.get_header(header, bytes, dpi);
}
COM_API_IMPLEMENT(scanner, bool, discard_first_image(void))
{
scanned_img* img = images_.take();
if (img)
{
img->release();
return true;
}
else
{
return false;
}
}
COM_API_IMPLEMENT(scanner, bool, is_online(void))
{
std::string sn("");
return handle_ && control_read_string(IO_CTRL_CODE_GET_SERIAL, sn) != SCANNER_ERR_DEVICE_NOT_FOUND;
}
COM_API_IMPLEMENT(scanner, bool, is_paper_on(void))
{
SANE_Bool on = SANE_FALSE;
unsigned int len = sizeof(on);
if (hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_GET_PAPER_ON, &on, &len) == SANE_STATUS_GOOD)
return on == SANE_TRUE;
else
return false;
}
COM_API_IMPLEMENT(scanner, int, last_error(void))
{
return err_;
}
COM_API_IMPLEMENT(scanner, int, image_fetched(IScanImg* tx))
{
fetch_imgs_++;
if (ui_notify)
ui_notify(SANE_EVENT_IMG_UPLOADED, NULL, fetch_imgs_);
else if (indicator_)
indicator_->notify_data_arrived(false);
{
wchar_t msg[128] = { 0 };
swprintf_s(msg, _countof(msg) - 1, L"Transferring image %d of %p finished.\r\n", fetch_imgs_, tx);
log_info(msg, 1);
}
return 0;
}
COM_API_IMPLEMENT(scanner, bool, get_option_info(int sn, value_type* type, value_limit* limit, int* bytes))
{
#define SIMPLE_STR_INFO(id, rdo) \
if (sn == id) \
{ \
if (type) \
*type = VAL_TYPE_STR; \
if (limit) \
*limit = rdo ? VAL_LIMIT_READONLY : VAL_LIMIT_NONE; \
if (bytes) \
*bytes = 255; \
\
return true; \
}
#define SIMPLE_INT_INFO(id, rdo) \
if (sn == id) \
{ \
if (type) \
*type = VAL_TYPE_INT; \
if (limit) \
*limit = rdo ? VAL_LIMIT_READONLY : VAL_LIMIT_NONE; \
if (bytes) \
*bytes = sizeof(int); \
\
return true; \
}
#define SIMPLE_BOOL_INFO(id, rdo) \
if (sn == id) \
{ \
if (type) \
*type = VAL_TYPE_BOOL; \
if (limit) \
*limit = rdo ? VAL_LIMIT_READONLY : VAL_LIMIT_NONE; \
if (bytes) \
*bytes = sizeof(int); \
\
return true; \
}
SIMPLE_STR_INFO(SANE_OPT_ID_DRIVER_VERSION, true);
SIMPLE_STR_INFO(SANE_OPT_ID_MANUFACTURER, true);
SIMPLE_STR_INFO(SANE_OPT_ID_COPYRIGHT, true);
SIMPLE_STR_INFO(SANE_OPT_ID_CO_URL, true);
SIMPLE_STR_INFO(SANE_OPT_ID_CO_TEL, true);
SIMPLE_STR_INFO(SANE_OPT_ID_CO_ADDR, true);
SIMPLE_STR_INFO(SANE_OPT_ID_CO_GPS, true);
SIMPLE_STR_INFO(SANE_OPT_ID_DEV_NAME, true);
SIMPLE_STR_INFO(SANE_OPT_ID_DEV_FAMILY, true);
SIMPLE_STR_INFO(SANE_OPT_ID_LOGIN, false);
SIMPLE_STR_INFO(SANE_OPT_ID_LOGOUT, false);
SIMPLE_STR_INFO(SANE_OPT_ID_DRIVER_LOG, false);
SIMPLE_STR_INFO(SANE_OPT_ID_DEVICE_LOG, false);
SIMPLE_STR_INFO(SANE_OPT_ID_DEVICE_MAC_ADDR, true);
SIMPLE_STR_INFO(SANE_OPT_ID_MOTOR_VER, true);
SIMPLE_INT_INFO(SANE_OPT_ID_HELP, false);
SIMPLE_INT_INFO(SANE_OPT_ID_HISTORY_COUNT, true);
SIMPLE_INT_INFO(SANE_OPT_ID_ROLLER_COUNT, false);
SIMPLE_INT_INFO(SANE_OPT_ID_VID, true);
SIMPLE_INT_INFO(SANE_OPT_ID_PID, true);
SIMPLE_INT_INFO(SANE_OPT_ID_ROLLER_LIFE, true);
SIMPLE_STR_INFO(SANE_OPT_ID_INITIAL_BOOT_TIME, true);
SIMPLE_BOOL_INFO(SANE_OPT_ID_LENS_DIRTY, false);
sn = transfer_id(sn);
if (sn == -1)
return false;
EXAPIPOS ex = find_ex_api(sn);
SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, ex == ex_opts_.end() ? (void*)sn : (void*)ex->base_ind);
bool ret = false;
if (desc)
{
if (type)
*type = scanner::from_sane_type(desc->type);
if (limit)
{
int lmt = scanner::from_sane_constraint(desc->constraint_type);
if (IS_CAP_READONLY(desc->cap))
lmt |= VAL_LIMIT_READONLY;
*limit = (value_limit)lmt;
}
if (bytes)
*bytes = desc->size;
ret = true;
}
return ret;
}
COM_API_IMPLEMENT(scanner, bool, get_value(int sn, set_opt_value setval, void* param))
{
if (sane_ids_.count((sane_option_id)sn) &&
sane_ids_[(sane_option_id)sn] == sn)
{
char buf[256] = { 0 };
value_type type = VAL_TYPE_NONE;
int ret = hg_sane_middleware::instance()->set_option(handle_, (void*)sn, SANE_ACTION_GET_VALUE, buf, NULL);
if (ret == SANE_STATUS_GOOD)
{
get_option_info(sn, &type, NULL, NULL);
if (type == VAL_TYPE_STR)
{
std::string str(buf);
setval(&str, VAL_ROLE_CURRENT, VAL_LIMIT_NONE, param);
}
else
setval(buf, VAL_ROLE_CURRENT, VAL_LIMIT_NONE, param);
return true;
}
return false;
}
int org_id = sn;
if(sn == 0x102c) // CapType::Language
sn = transfer_id(SANE_OPT_ID_LANGUAGE);
else
sn = transfer_id(sn);
if (sn == -1)
return false;
EXAPIPOS ex = find_ex_api(sn);
int ret = SANE_STATUS_INVAL;
SANE_Int after = 0;
if (ex == ex_opts_.end())
{
if (get_option_value_with_parent(sn, setval, param))
return true;
SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, (void*)sn);
void* init = hg_sane_middleware::instance()->get_def_value(handle_, (void*)sn);
ret = SANE_STATUS_GOOD;
if (desc->type == SANE_TYPE_BOOL)
{
SANE_Bool v = SANE_FALSE;
bool val = false;
hg_sane_middleware::instance()->get_cur_value(handle_, (void*)sn, &v);
val = v == SANE_TRUE;
//set_cur_and_def_value<bool>(val, *(SANE_Bool*)init == SANE_TRUE, setval, param);
{
int role = VAL_ROLE_NONE;
val = false;
if (*(SANE_Bool*)init == SANE_FALSE)
role |= VAL_ROLE_DEFAULT;
if (v == SANE_FALSE)
role |= VAL_ROLE_CURRENT;
setval(&val, (value_role)role, VAL_LIMIT_ENUM, param);
val = true;
role = VAL_ROLE_NONE;
if (*(SANE_Bool*)init == SANE_TRUE)
role |= VAL_ROLE_DEFAULT;
if (v == SANE_TRUE)
role |= VAL_ROLE_CURRENT;
setval(&val, (value_role)role, VAL_LIMIT_ENUM, param);
}
}
else if (desc->type == SANE_TYPE_INT)
{
SANE_Int cur = 0, def = *(SANE_Int*)init;
int val = 0;
hg_sane_middleware::instance()->get_cur_value(handle_, (void*)sn, &cur);
val = cur;
if (sn == resolution_id_)
dpi_ = cur;
do
{
if (desc->constraint_type == SANE_CONSTRAINT_RANGE)
{
set_value_range<SANE_Int, int>(cur, def, desc->constraint.range->min, desc->constraint.range->max, desc->constraint.range->quant, setval, param, scanner::to_int);
}
else if (desc->constraint_type == SANE_CONSTRAINT_WORD_LIST)
{
const SANE_Word* v = desc->constraint.word_list;
for (int i = 0; i < v[0]; ++i)
{
value_role role = VAL_ROLE_NONE;
if (v[i + 1] == cur)
role = value_role(role | VAL_ROLE_CURRENT);
if (v[i + 1] == *(SANE_Int*)init)
role = value_role(role | VAL_ROLE_DEFAULT);
val = v[i + 1];
if (!setval(&val, role, VAL_LIMIT_ENUM, param))
break;
}
}
else
set_cur_and_def_value<int>(val, *(SANE_Int*)init, setval, param);
}while (0);
}
else if (desc->type == SANE_TYPE_FIXED)
{
SANE_Fixed cur = 0, def = *(SANE_Fixed*)init;
float val = .0f;
hg_sane_middleware::instance()->get_cur_value(handle_, (void*)sn, &cur);
if (sn == resolution_id_)
dpi_ = (int)(SANE_UNFIX(cur) + .5f);
do
{
if (desc->constraint_type == SANE_CONSTRAINT_RANGE)
{
set_value_range<SANE_Fixed, float>(cur, def, desc->constraint.range->min, desc->constraint.range->max, desc->constraint.range->quant, setval, param, scanner::to_float);
}
else if (desc->constraint_type == SANE_CONSTRAINT_WORD_LIST)
{
const SANE_Word* v = desc->constraint.word_list;
for (int i = 0; i < v[0]; ++i)
{
value_role role = VAL_ROLE_NONE;
if (v[i + 1] == cur)
role = value_role(role | VAL_ROLE_CURRENT);
if (v[i + 1] == def)
role = value_role(role | VAL_ROLE_DEFAULT);
val = (float)SANE_UNFIX(v[i + 1]);
if (!setval(&val, role, VAL_LIMIT_ENUM, param))
break;
}
}
else
set_cur_and_def_value<float>(val, (float)SANE_UNFIX(*(SANE_Fixed*)init), setval, param);
} while (0);
}
else if (desc->type == SANE_TYPE_STRING)
{
char* buf = new char[desc->size + 4];
std::string val(""), def((char*)init);
memset(buf, 0, desc->size + 4);
hg_sane_middleware::instance()->get_cur_value(handle_, (void*)sn, buf);
val = buf;
do
{
if (desc->constraint_type == SANE_CONSTRAINT_STRING_LIST)
{
for (int i = 0; desc->constraint.string_list[i]; ++i)
{
value_role role = VAL_ROLE_NONE;
if (strcmp(desc->constraint.string_list[i], buf) == 0)
role = value_role(role | VAL_ROLE_CURRENT);
if (strcmp(desc->constraint.string_list[i], (char*)init) == 0)
role = value_role(role | VAL_ROLE_DEFAULT);
val = desc->constraint.string_list[i];
if (org_id == 0x102c)
{
// const char* hz = local_trans::lang_trans_between_hz936(val.c_str(), false, NULL);
int lid = sane_opt_trans::language_to_twain(val.c_str());
if (!setval(&lid, role, VAL_LIMIT_ENUM, param))
break;
}
else if (!setval(&val, role, VAL_LIMIT_ENUM, param))
break;
}
}
else
set_cur_and_def_value<std::string>(val, def, setval, param);
} while (0);
delete[] buf;
}
else
{
ret = SANE_STATUS_INVAL;
}
local_utility::free_memory(init);
}
else
{
ret = (this->*ex->ex_api)(ex->base_ind, param, setval);
}
return ret == SANE_STATUS_GOOD;
}
COM_API_IMPLEMENT(scanner, bool, get_value(int sn, void* data, int* len))
{
if (sn != SANE_OPT_ID_DRIVER_LOG && sn != SANE_OPT_ID_DEVICE_LOG)
return false;
SANE_Status ret = hg_sane_middleware::instance()->set_option(handle_, (const void*)sn, SANE_ACTION_GET_VALUE, data, NULL);
wchar_t msg[128] = { 0 };
swprintf_s(msg, _countof(msg) - 1, L"get log of(%x) = 0x%x\r\n", sn, ret);
log_info(msg, 1);
return ret == SANE_STATUS_GOOD;
}
COM_API_IMPLEMENT(scanner, int, set_value(int sn, void* val))
{
if (sane_ids_.count((sane_option_id)sn) &&
sane_ids_[(sane_option_id)sn] == sn)
{
int ret = hg_sane_middleware::instance()->set_option(handle_, (void*)sn, SANE_ACTION_SET_VALUE, val, NULL);
return ret;
}
int org_id = sn;
if (sn == 0x102c) // CapType::Language
sn = transfer_id(SANE_OPT_ID_LANGUAGE);
else
sn = transfer_id(sn);
if (sn == -1)
return SANE_STATUS_UNSUPPORTED;
EXAPIPOS ex = find_ex_api(sn);
int ret = SANE_STATUS_INVAL;
SANE_Int after = 0;
SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, (void*)sn);
{
wchar_t msg[256] = { 0 };
if (ex == ex_opts_.end())
swprintf_s(msg, _countof(msg) - 1, L"set_value of %s(%s) of ID %d\r\n", local_trans::a2u(desc->name, CP_UTF8).c_str(), local_trans::a2u(hg_sane_middleware::option_value_2_string(desc->type, val).c_str(), CP_UTF8).c_str(), sn);
else if(ex->base_ind != -1)
{
desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, (void*)ex->base_ind);
swprintf_s(msg, _countof(msg) - 1, L"set_value of %s(0x%x) of ID %d, base id = %d)\r\n", local_trans::a2u(desc->name, CP_UTF8).c_str(), *(unsigned*)val, sn, ex->base_ind);
}
log_info(msg, 0);
}
twain_set_ = true;
if (ex == ex_opts_.end())
{
std::string strv("");
void* w = val;
if (org_id == 0x102c)
{
// const char* str = sane_opt_trans::language_from_twain(*(int*)val);
strv = sane_opt_trans::language_from_twain(*(int*)val);
w = &strv;
}
if (!set_option_value_with_parent(sn, w, &ret))
ret = set_option_value(sn, desc->type, desc->size, w);
ret = local_utility::sane_statu_2_scanner_err(ret);
}
else
{
ret = (this->*ex->ex_api)(ex->base_ind, val, NULL);
}
if (sn == resolution_id_)
{
if (desc->type == SANE_TYPE_FIXED)
dpi_ = (int)(*(float*)val + .5f);
else
dpi_ = *(int*)val;
}
return ret;
}
COM_API_IMPLEMENT(scanner, int, convert_image(SANE_ImageFormatConvert* conv))
{
return hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_CONVERT_IMAGE_FORMAT, conv, NULL);
}
COM_API_IMPLEMENT(scanner, void, free_buffer(void* buf, int len))
{
hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_FREE_MEMORY, buf, (unsigned int*)&len);
}
COM_API_IMPLEMENT(scanner, int, get_fixed_ids(bool(__stdcall* cb)(uint32_t id, void* param), void* param))
{
for (auto& v : sane_ids_)
{
if (!cb(v.first, param))
break;
}
return 0;
}
// SANE options ID ...
SANE_OPTION_ID_IMPLEMENT(color_correction)
SANE_OPTION_ID_IMPLEMENT(fold_type)
SANE_OPTION_ID_IMPLEMENT(is_multiout)
SANE_OPTION_ID_IMPLEMENT(multiout_type)
SANE_OPTION_ID_IMPLEMENT(color_mode)
SANE_OPTION_ID_IMPLEMENT(erase_color)
SANE_OPTION_ID_IMPLEMENT(erase_multiout_red)
SANE_OPTION_ID_IMPLEMENT(erase_paper_red)
SANE_OPTION_ID_IMPLEMENT(is_erase_background)
SANE_OPTION_ID_IMPLEMENT(background_color_range)
SANE_OPTION_ID_IMPLEMENT(sharpen)
SANE_OPTION_ID_IMPLEMENT(erase_morr)
SANE_OPTION_ID_IMPLEMENT(erase_grids)
SANE_OPTION_ID_IMPLEMENT(error_extend)
SANE_OPTION_ID_IMPLEMENT(is_noise_modify)
SANE_OPTION_ID_IMPLEMENT(noise_threshold)
SANE_OPTION_ID_IMPLEMENT(paper)
SANE_OPTION_ID_IMPLEMENT(is_custom_area)
SANE_OPTION_ID_IMPLEMENT(curstom_area_l)
SANE_OPTION_ID_IMPLEMENT(curstom_area_r)
SANE_OPTION_ID_IMPLEMENT(curstom_area_t)
SANE_OPTION_ID_IMPLEMENT(curstom_area_b)
SANE_OPTION_ID_IMPLEMENT(is_size_check)
SANE_OPTION_ID_IMPLEMENT(page)
SANE_OPTION_ID_IMPLEMENT(blank_page_threshold)
SANE_OPTION_ID_IMPLEMENT(resolution)
SANE_OPTION_ID_IMPLEMENT(image_quality)
SANE_OPTION_ID_IMPLEMENT(is_swap)
SANE_OPTION_ID_IMPLEMENT(is_split)
SANE_OPTION_ID_IMPLEMENT(is_auto_deskew)
SANE_OPTION_ID_IMPLEMENT(is_custom_gamma)
SANE_OPTION_ID_IMPLEMENT(bright)
SANE_OPTION_ID_IMPLEMENT(contrast)
SANE_OPTION_ID_IMPLEMENT(gamma)
SANE_OPTION_ID_IMPLEMENT(is_erase_black_frame)
SANE_OPTION_ID_IMPLEMENT(deep_sample)
SANE_OPTION_ID_IMPLEMENT(threshold)
SANE_OPTION_ID_IMPLEMENT(anti_noise)
SANE_OPTION_ID_IMPLEMENT(margin)
SANE_OPTION_ID_IMPLEMENT(fill_background)
SANE_OPTION_ID_IMPLEMENT(is_anti_permeate)
SANE_OPTION_ID_IMPLEMENT(anti_permeate_level)
SANE_OPTION_ID_IMPLEMENT(is_erase_hole)
SANE_OPTION_ID_IMPLEMENT(search_hole_range)
SANE_OPTION_ID_IMPLEMENT(is_filling_color)
SANE_OPTION_ID_IMPLEMENT(is_ultrasonic_check)
SANE_OPTION_ID_IMPLEMENT(is_check_staple)
SANE_OPTION_ID_IMPLEMENT(scan_mode)
SANE_OPTION_ID_IMPLEMENT(scan_count)
SANE_OPTION_ID_IMPLEMENT(text_direction)
SANE_OPTION_ID_IMPLEMENT(is_rotate_bkg180)
SANE_OPTION_ID_IMPLEMENT(is_check_dogear)
SANE_OPTION_ID_IMPLEMENT(dogear_size)
SANE_OPTION_ID_IMPLEMENT(is_check_skew)
SANE_OPTION_ID_IMPLEMENT(skew_range)
SANE_OPTION_ID_IMPLEMENT(black_white_threshold)
SANE_OPTION_ID_IMPLEMENT(is_photo_mode)
SANE_OPTION_ID_IMPLEMENT(double_feed_handle)
SANE_OPTION_ID_IMPLEMENT(scan_when_paper_on)
SANE_OPTION_ID_IMPLEMENT(feed_strength)
SANE_OPTION_ID_IMPLEMENT(power_scheme)
SANE_OPTION_ID_IMPLEMENT(is_auto_strength)
SANE_OPTION_ID_IMPLEMENT(feed_strength_value)
SANE_OPTION_ID_IMPLEMENT(is_reverse_bw)
SANE_OPTION_ID_IMPLEMENT(is_erase_hole_l)
SANE_OPTION_ID_IMPLEMENT(search_hole_range_l)
SANE_OPTION_ID_IMPLEMENT(is_erase_hole_r)
SANE_OPTION_ID_IMPLEMENT(search_hole_range_r)
SANE_OPTION_ID_IMPLEMENT(is_erase_hole_t)
SANE_OPTION_ID_IMPLEMENT(search_hole_range_t)
SANE_OPTION_ID_IMPLEMENT(is_erase_hole_b)
SANE_OPTION_ID_IMPLEMENT(search_hole_range_b)
SANE_OPTION_ID_IMPLEMENT(fold_direction)
SANE_OPTION_ID_IMPLEMENT(discardblank)
SANE_OPTION_ID_IMPLEMENT(lens_dirty)
// SANE-ex option ID:
SANE_OPTION_ID_IMPLEMENT(ex_multiout_type)
SANE_OPTION_ID_IMPLEMENT(ex_auto_color_type)
SANE_OPTION_ID_IMPLEMENT(ex_color_mode)
SANE_OPTION_ID_IMPLEMENT(ex_sharpen)
SANE_OPTION_ID_IMPLEMENT(ex_paper)
SANE_OPTION_ID_IMPLEMENT(ex_paper_lateral)
SANE_OPTION_ID_IMPLEMENT(ex_auto_paper_size)
SANE_OPTION_ID_IMPLEMENT(ex_is_paper_auto_crop)
SANE_OPTION_ID_IMPLEMENT(ex_text_direction)
SANE_OPTION_ID_IMPLEMENT(ex_duplex)
SANE_OPTION_ID_IMPLEMENT(ex_fill_background)
SANE_OPTION_ID_IMPLEMENT(ex_discard_blank_page)
SANE_OPTION_ID_IMPLEMENT(ex_discard_blank_receipt)
SANE_OPTION_ID_IMPLEMENT(ex_is_page_fold)
SANE_OPTION_ID_IMPLEMENT(ex_color_filter)
SANE_OPTION_ID_IMPLEMENT(ex_color_enhance)
SANE_OPTION_ID_IMPLEMENT(ex_final_compression)
SANE_OPTION_ID_IMPLEMENT(ex_final_format)
SANE_OPTION_ID_IMPLEMENT(ex_serial)
SANE_OPTION_ID_IMPLEMENT(ex_to_be_scan)
SANE_OPTION_ID_IMPLEMENT(ex_scan_with_hole)
SANE_OPTION_ID_IMPLEMENT(ex_device_code)
SANE_OPTION_ID_IMPLEMENT(ex_power)
SANE_OPTION_ID_IMPLEMENT(ex_hardware_version)
SANE_OPTION_ID_IMPLEMENT(ex_ip)
COM_API_IMPLEMENT(scanner, void, twain_set_transfer(twain_xfer xfer))
{
xfer_ = xfer;
}
COM_API_IMPLEMENT(scanner, void, twain_set_compression(SANE_CompressionType compression, void* detail))
{
img_fmt_.compress.compression = compression;
img_fmt_.compress.detail = detail;
}
COM_API_IMPLEMENT(scanner, int, twain_get_config(char* buf, size_t* len))
{
int ret = SCANNER_ERR_NO_DATA;
if (callback::get_config_content)
{
char* cont = callback::get_config_content(local_trans::u2a(scanner_name_.c_str(), CP_UTF8).c_str(), NULL);
if (cont)
{
if (*len <= strlen(cont))
{
*len = strlen(cont) + 4;
ret = SCANNER_ERR_INSUFFICIENT_MEMORY;
}
else
{
strcpy(buf, cont);
ret = SCANNER_ERR_OK;
*len = strlen(cont);
}
if (callback::twain_ui_free)
callback::twain_ui_free(cont);
}
}
return ret;
}
COM_API_IMPLEMENT(scanner, int, twain_set_config(char* buf, size_t len))
{
if(callback::apply_given_config)
{
if(callback::apply_given_config(buf, handle_, &sane_api_) == 0)
return SCANNER_ERR_OK;
}
return SCANNER_ERR_DATA_DAMAGED;
}
// ui ...
COM_API_IMPLEMENT(scanner, bool, ui_show_main(HWND parent))
{
return false;
}
COM_API_IMPLEMENT(scanner, bool, ui_show_setting(HWND parent, bool with_scan, bool indicator))
{
is_show_ui_ = with_scan;
is_show_setting_ = true;
events_.clear();
ui_notify = std::function<void(int, void*, int)>();
if (!IsWindow(parent) || !IsWindowVisible(parent))
parent = NULL;
if (callback::show_setting_ui)
{
if (with_scan)
{
images_.clear();
scan_msg_ = "OK";
scan_err_ = false;
}
auto ui = [this](ui_result res)
{
int uev = SANE_EVENT_SCAN_FINISHED;
switch (res)
{
case UI_RESULT_FAILED:
break;
case UI_RESULT_OK:
break;
case UI_RESULT_CLOSE_NORMAL:
is_show_ui_ = false;
uev = SANE_EVENT_UI_CLOSE_NORMAL;
on_ui_event(uev, (void*)uev);
break;
case UI_RESULT_CLOSE_CANCEL:
is_show_ui_ = false;
uev = SANE_EVENT_UI_CLOSE_CANCEL;
on_ui_event(uev, (void*)uev);
break;
case UI_RESULT_CLOSE_SETTING:
is_show_setting_ = false;
uev = SANE_EVENT_UI_CLOSE_SETTING;
on_ui_event(uev, (void*)uev);
break;
case UI_RESULT_START_SCAN:
on_ui_event(SANE_EVENT_UI_SCAN_COMMAND, NULL);
break;
default:
break;
}
};
int res = callback::show_setting_ui(handle_, parent, &sane_api_, local_trans::u2a(scanner_name_.c_str(), CP_UTF8).c_str(),with_scan, ui, &ui_notify);
//if (res == ui_result::UI_RESULT_CLOSE_NORMAL)
//{
// int ev = SANE_EVENT_UI_CLOSE_NORMAL;
// on_ui_event(ev, (void*)ev);
//}
//else if (res == ui_result::UI_RESULT_START_SCAN)
//{
// //callback::show_progress_ui(parent, ui_process, &ui_notify);
// //start();
// on_ui_event(SANE_EVENT_UI_SCAN_COMMAND, NULL);
//}
//else if (res == UI_RESULT_CLOSE_CANCEL)
//{
// int ev = SANE_EVENT_UI_CLOSE_CANCEL;
// on_ui_event(ev, (void*)ev);
//}
//on_ui_event(ev, NULL);
}
else if (cfg_)
{
if (with_scan)
{
events_.clear();
images_.clear();
scan_msg_ = "OK";
scan_err_ = false;
}
size_t pid = scanner_name_.find(L" - ");
if (pid == -1)
pid = scanner_name_.length();
if (setting_)
setting_->close();
setting_ = new dlg_setting(parent, &sane_api_, handle_, with_scan, scanner_name_.substr(0, pid).c_str(), true);
setting_->set_ui_event_notify(&scanner::ui_callback, this);
setting_->set_config(cfg_, (cfg_path_ + scanner_name_.substr(0, pid) + L".cfg").c_str(), &scanner::apply_scheme, this, &twain_set_);
//if (indicator)
//{
// indicator_.reset(new dlg_indicator(setting_->hwnd(), false));
// indicator_->set_ui_event_notify(&scanner::ui_callback, this);
//}
setting_->show(true);
}
return true;
}
COM_API_IMPLEMENT(scanner, bool, ui_show_progress(HWND parent, bool bIndicator))
{
is_bIndicator = bIndicator;
if (is_bIndicator)
ui_notify = std::function<void(int, void*, int)>();
if (!IsWindow(parent) || !IsWindowVisible(parent))
parent = NULL;
auto ui_process = [this](ui_result res)
{
int uev = SANE_EVENT_SCAN_FINISHED;
switch (res)
{
case UI_RESULT_CLOSE_NORMAL:
uev = SANE_EVENT_UI_CLOSE_NORMAL;
//if (!is_show_ui_)
{
on_ui_event(uev, (void*)uev);
}
break;
case UI_RESULT_CLOSE_CANCEL:
uev = SANE_EVENT_UI_CLOSE_CANCEL;
//if (!is_show_ui_)
{
on_ui_event(uev, (void*)uev);
}
//else
// stop();
break;
default:
break;
}
};
if (callback::show_progress_ui && bIndicator)
{
callback::show_progress_ui(parent, ui_process,&ui_notify);
}
else if(bIndicator)
{
bool sole_thread = true;
if (setting_ && IsWindowVisible(setting_->hwnd()))
{
parent = setting_->hwnd();
sole_thread = false;
}
else if (!IsWindow(parent))
parent = callback::find_main_wnd();
if (indicator_)
indicator_->close();
indicator_ = new dlg_indicator(parent, sole_thread);
indicator_->set_ui_event_notify(&scanner::ui_callback, this);
indicator_->show(true);
}
return true;
}
COM_API_IMPLEMENT(scanner, void, ui_hide(void))
{
if (indicator_)
indicator_->close();
indicator_ = NULL;
if (setting_)
setting_->close();
setting_ = NULL;
if (callback::close_ui)
callback::close_ui(UI_INDICATOR | UI_SETTING | UI_MSG_BOX);
is_show_setting_ = false;
ui_notify = std::function<void(int, void*, int)>();
}
COM_API_IMPLEMENT(scanner, bool, ui_is_ok(void))
{
return true;
}
// called from device-layer ...
int scanner::handle_device_event(int ev_code, void* data, unsigned int* len)
{
dlg_indicator* prog = indicator_;
if (ev_code == SANE_EVENT_WORKING)
{
is_in_working_thread_ = true;
img_ind_ = 0;
if (prog)
prog->notify_working();
else if (callback::show_progress_ui && is_bIndicator && ui_notify)
ui_notify(ev_code, data, *len);
else if (callback::show_setting_ui && ui_notify)
ui_notify(ev_code, data, *len);
on_ui_event(ev_code, (void*)ev_code);
log_info(L"Scanning ...\r\n", 1);
}
else if (ev_code == SANE_EVENT_IMAGE_OK)
{
SANE_Image* simg = (SANE_Image*)data;
scanned_img* img = NULL;
wchar_t name[40] = { 0 };
if (simg->flag.statu && callback::abnormal_image)
{
if (double_handle_ == DOUBLE_FEED_NEED_UI)
{
if (callback::abnormal_image(simg) == SANE_Abnormal_Image_Discard)
{
wchar_t info[128] = { 0 };
swprintf_s(info, _countof(info) - 1, L"Discard image %d for the status is: %d\r\n", simg->src_id, simg->flag.statu);
log_info(info, LOG_LEVEL_DEBUG_INFO);
double_handle_ = DOUBLE_FEED_DISCARD;
}
else
double_handle_ = DOUBLE_FEED_KEEP;
}
if (double_handle_ == DOUBLE_FEED_DISCARD)
return 0;
}
else
{
double_handle_ = DOUBLE_FEED_NEED_UI;
}
swprintf_s(name, _countof(name) - 1, L"img_%05u.bmp", ++img_ind_);
img = new scanned_img(handle_, simg->header, simg->data, simg->bytes, simg->flag.dpi, (tmp_path_ + name).c_str(), xfer_, &img_fmt_);
if (img->bytes() /*>= simg->bytes*/)
{
size_t bytes = 0;
int times = 0, cnt0 = images_.count(&bytes), cnt = cnt0,
gap = 5, max_wait = wait_fetch_ / gap;
img->set_image_status((SANE_Image_Statu)simg->flag.statu);
bytes /= 1024 * 1024;
while (bytes > max_img_mem_ && !user_cancel_ && times++ < max_wait && cnt >= cnt0) // memory control
{
std::this_thread::sleep_for(std::chrono::milliseconds(gap));
cnt = images_.count(&bytes);
bytes /= 1024 * 1024;
if (times == 1)
{
wchar_t tips[128] = { 0 };
swprintf_s(tips, _countof(tips) - 1, L"Memory usage upto limit! wait up to %u ms ...\r\n", wait_fetch_);
log_info(tips, 1);
}
}
images_.save(img, img->bytes());
}
else
{
img->release();
}
if (prog)
prog->notify_data_arrived(true);
else if (ui_notify)
ui_notify(ev_code, data, img_ind_);
// notifyXferReady <20><>Ϊ<EFBFBD><CEAA>ͼƬ<CDBC><C6AC>֪ͨ<CDA8><D6AA><EFBFBD><EFBFBD>ֹ<EFBFBD><D6B9><EFBFBD><EFBFBD>APP<50><50>imgGetInfo<66>з<EFBFBD><D0B7>ش<EFBFBD><D8B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˳<EFBFBD><CBB3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> - 22023-10-25
if (img_ind_ == 1)
on_ui_event(SANE_EVENT_TWAIN_XFER_READY, nullptr);
{
wchar_t msg[128] = { 0 };
swprintf_s(msg, _countof(msg) - 1, L"New image(%u) received with %u bytes (status: %d)\r\n", img_ind_, simg->bytes, simg->flag.statu);
log_info(msg, 1);
}
}
else if (ev_code == SANE_EVENT_USB_DATA_RECEIVED)
{
//if (prog)
// prog->notify_data_arrived(false);
//else if (ui_notify)
// ui_notify(ev_code, data, 0);
}
else if (ev_code == SANE_EVENT_SCAN_FINISHED)
{
if (double_handle_ == DOUBLE_FEED_KEEP)
{
double_handle_ = DOUBLE_FEED_NEED_UI;
if (start_after_keep_.get() && start_after_keep_->joinable())
start_after_keep_->join();
start_after_keep_.reset(new std::thread(&scanner::thread_start_after_keep, this));
}
else
{
//is_in_working_thread_ = false;
err_ = *len;
scan_over_ = true;
scan_msg_ = data ? (char*)data : "OK";
if (double_handle_ == DOUBLE_FEED_DISCARD)
{
scan_msg_ = "OK";
err_ = 0;
}
if (done_.get() && done_->joinable())
done_->join();
done_.reset(new std::thread(&scanner::scan_done, this));
// scan_done(); // invoking move to the last image fetched
{
wchar_t msg[128] = { 0 };
swprintf_s(msg, _countof(msg) - 1, L"Scan finished with error: %u\r\n", *len);
log_info(msg, 1);
}
}
}
//else if (ev_code == SANE_EVENT_ERROR) // 閻忕偛绻楅弬鈧柨娑樿嫰濠€顏堝磻濠婂嫷鍓鹃柟娈垮亝瀵潡寮捄铏规綌缂佲偓鏉為绻嗛柟?- 2023-05-30
//{
// if (callback::show_messagebox_ui && *len)
// {
// callback::show_messagebox_ui(app_wnd_, ev_code, (void*)data, 0);
// }
// else if (*len) //闂佹寧鐟ㄩ銈咁嚕閻熸澘<E786B8><E6BE98>?
// {
// std::wstring msg(local_trans::a2u((char*)data, CP_UTF8));
// if (!IsWindow(app_wnd_))
// callback::bring_message_box_topmost(local_trans::lang_trans_between_hz936(CONST_STRING_ERROR).c_str());
// MessageBoxW(app_wnd_, msg.c_str(), local_trans::lang_trans_between_hz936(CONST_STRING_ERROR).c_str(), MB_OK);
// }
//// on_ui_event(ev_code, (void*)ev_code);
//}
return 0;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// log ...
#include <direct.h>
std::mutex g_lock_;
std::string g_path_file_("");
FILE* g_file_ = NULL;
static int g_log_level = 1;
static int get_log_level(const char* log_file, std::wstring* firstmsg = NULL)
{
std::string cfg(log_file);
size_t pos = cfg.rfind('\\');
if (firstmsg)
*firstmsg = L"";
cfg.erase(pos);
pos = cfg.rfind('\\');
if (pos != std::string::npos)
{
if (stricmp(cfg.substr(pos).c_str(), "\\log") == 0)
{
cfg.erase(pos);
cfg += "\\config";
}
}
cfg += "\\debug.cfg";
// A+ -> XYBscanner.exe
callback::check_wnd_thread_id = GetPrivateProfileIntA("twain-app", "check-main-wnd-thread-id", 0, cfg.c_str()) == 1;
if (!callback::check_wnd_thread_id)
{
wchar_t pe[MAX_PATH] = { 0 }, * name = NULL;
GetModuleFileNameW(NULL, pe, _countof(pe) - 1);
name = wcsrchr(pe, L'\\');
if (name++ == NULL)
name = pe;
if (wcsicmp(name, L"XYBscanner.exe") == 0)
{
callback::check_wnd_thread_id = true;
if (firstmsg)
*firstmsg = std::wstring(L"check window thread while PE is: '") + pe + L"'\r\n";
}
}
return GetPrivateProfileIntA("log", "twain-level", 1, cfg.c_str());
}
void init_log(void)
{
char* tmp = getenv("LOCALAPPDATA");
if (tmp)
{
std::string path(tmp);
char name[MAX_PATH] = { 0 }, * last = NULL;
path += std::string("\\") + PRODUCT_VENDOR + "Scan\\Log\\";
mkdir(path.c_str());
GetModuleFileNameA(NULL, name, _countof(name) - 1);
last = strrchr(name, '\\');
if (last++ == NULL)
last = name;
path += last;
path += "_twain.log";
g_file_ = fopen(path.c_str(), "a+b");
g_path_file_ = path;
}
else
{
char name[MAX_PATH] = { 0 }, * last = NULL;
std::string path("");
GetModuleFileNameA(NULL, name, _countof(name) - 1);
path = std::string(name) + "_twain.log";
g_file_ = fopen(path.c_str(), "a+b");
g_path_file_ = path;
}
if (g_file_)
{
fseek(g_file_, 0, SEEK_END);
if (ftell(g_file_))
{
std::wstring sep(L"\r\n\r\n\r\n=======================================================\r\n");
fwrite(sep.c_str(), 2, sep.length(), g_file_);
}
else
{
unsigned short bom = 0x0feff;
fwrite(&bom, sizeof(bom), 1, g_file_);
}
wchar_t ts[128] = { 0 }, now[40] = { 0 };
std::wstring msg1(L"");
hg_get_current_time_w(now);
g_log_level = get_log_level(g_path_file_.c_str(), &msg1);
swprintf_s(ts, _countof(ts) - 1, L"==================%s - %d, Proc %d==================\r\n", now, g_log_level, GetCurrentProcessId());
fwrite(ts, 2, lstrlenW(ts), g_file_);
if (msg1.length())
fwrite(msg1.c_str(), 2, msg1.length(), g_file_);
}
}
void close_log(void)
{
if (g_file_)
fclose(g_file_);
g_file_ = NULL;
}
void log(const wchar_t* info)
{
wchar_t clock[40] = { 0 };
hg_get_current_time_w(clock);
if (g_file_)
{
std::lock_guard<std::mutex> lock(g_lock_);
std::wstring text(clock);
text += info;
fwrite(text.c_str(), 2, text.length(), g_file_);
fflush(g_file_);
if (ftell(g_file_) > 10 * 1024 * 1024)
{
fclose(g_file_);
remove(g_path_file_.c_str());
g_file_ = fopen(g_path_file_.c_str(), "wb");
if (g_file_)
{
unsigned short bom = 0x0feff;
wchar_t ts[128] = { 0 }, now[40] = { 0 };
hg_get_current_time_w(now);
swprintf_s(ts, _countof(ts) - 1, L"==================%s (Truncated when size > 10MB) ==================\r\n", now);
fwrite(&bom, sizeof(bom), 1, g_file_);
fwrite(ts, 2, lstrlenW(ts), g_file_);
}
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// exports
extern "C"
{
#ifdef EXPORT_SANE_API
__declspec(dllexport)
#else
__declspec(dllimport)
#endif
int __stdcall initialize(void* reserve)
{
init_log();
callback::init_ui();
hg_sane_middleware::set_callback(callback::sane_event_callback, NULL);
if (hg_sane_middleware::instance()->is_ready())
return SANE_STATUS_GOOD;
else
return SCANNER_ERR_LANG_PAK_LOST;
}
#ifdef EXPORT_SANE_API
__declspec(dllexport)
#else
__declspec(dllimport)
#endif
int __stdcall open_scanner(SCANNERID scanner_id, ISaneInvoker** invoker, bool last_try)
{
if (!invoker)
return SCANNER_ERR_INVALID_PARAMETER;
if (!is_scanner_online(scanner_id))
{
if (last_try)
{
HWND parent = callback::find_main_wnd();
std::string msg(callback::language_trans("\xE6\xB2\xA1\xE6\x9C\x89\xE6\x89\xBE\xE5\x88\xB0\xE6\x89\xAB\xE6\x8F\x8F\xE4\xBB\xAA\xEF\xBC\x81", true, NULL)),
title(callback::language_trans("\xE9\x94\x99\xE8\xAF\xAF", true, NULL));
if (callback::show_messagebox_ui)
callback::show_messagebox_ui(parent, 0, &msg[0], SCANNER_ERR_DEVICE_NOT_FOUND);
else
MessageBoxW(parent, local_trans::a2u(msg.c_str(), CP_UTF8).c_str(), local_trans::a2u(title.c_str(), CP_UTF8).c_str(), MB_OK);
}
return SCANNER_ERR_DEVICE_NOT_FOUND;
}
scanner* scn = new scanner(scanner_id);
if (scn->last_error() == SCANNER_ERR_OK)
{
*invoker = dynamic_cast<ISaneInvoker*>(scn);
return 0;
}
else
{
int ret = scn->last_error();
scn->release();
*invoker = NULL;
if (last_try)
{
HWND parent = callback::find_main_wnd();
std::string msg(callback::language_trans("\xE6\x89\x93\xE5\xBC\x80\xE6\x89\xAB\xE6\x8F\x8F\xE4\xBB\xAA\xE5\xA4\xB1\xE8\xB4\xA5\xE3\x80\x82", true, NULL)),
title(callback::language_trans("\xE9\x94\x99\xE8\xAF\xAF", true, NULL));
if (callback::show_messagebox_ui)
callback::show_messagebox_ui(parent, 0, &msg[0], ret);
else
MessageBoxW(parent, local_trans::a2u(msg.c_str(), CP_UTF8).c_str(), local_trans::a2u(title.c_str(), CP_UTF8).c_str(), MB_OK);
}
return ret;
}
}
#ifdef EXPORT_SANE_API
__declspec(dllexport)
#else
__declspec(dllimport)
#endif
bool __stdcall is_scanner_online(SCANNERID scanner_id)
{
std::vector<std::string> que;
scanner::get_scanner_name(scanner_id, que);
return !que.empty();
}
#ifdef EXPORT_SANE_API
__declspec(dllexport)
#else
__declspec(dllimport)
#endif
int __stdcall uninitialize(void* reserve)
{
hg_sane_middleware::set_callback(NULL, NULL);
hg_sane_middleware::clear();
close_log();
callback::unint_ui();
return 0;
}
#ifdef EXPORT_SANE_API
__declspec(dllexport)
#else
__declspec(dllimport)
#endif
void __stdcall log_info(const wchar_t* info, int level)
{
if(level >= g_log_level)
log(info);
}
}