#include "scanner.h" #include #include // for PathFileExistsW #include "../sdk/hginclude/huagaoxxx_warraper_ex.h" #include #include "../../code_device/hgsane/sane_hg_mdw.h" #include "sane_option_trans.h" #include #include #include #include "DlgSetting.h" #include "gb_json.h" #include "../../sdk/include/lang/app_language.h" #include #include "DlgIndicator.h" #include #pragma comment(lib, "Shlwapi.lib") 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 g_scanner_instances; int sane_event_callback( // 注册回调的对象,需要保证该回调是多线程安全的 SANE_Handle hdev // 产生事件的设备句柄 , int code // 回调事件代码 , void* data // 回调事件数据,根据事件代码有所不同,参照具体事件定义 , unsigned int* len // 数据长度(字节),或者event_data的缓冲区长度,详细请看相应的事件代码 , void* param // 用户自定义数据,与调用sane_init_ex传入时的保持一致 ) // 返回值依不同的事件代码而定,通常为“0” { std::lock_guard lock(cb_lock_); std::vector::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 lock(cb_lock_); std::vector::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 lock(cb_lock_); std::vector::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} }, 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"} // 黑白图像反色输出(正常颜色为:0-黑色;1-白色) , {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"} // " 搓纸阈值" }; 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 CALLBACK main_wnd(HWND hwnd, LPARAM param) { DWORD pid = 0; GetWindowThreadProcessId(hwnd, &pid); if (pid != GetCurrentProcessId()) 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); 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& devs) = NULL; // blocked. return selected DEVQUE::id or -1 if user cancelled int (*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 callback) = NULL; int (*show_progress_ui)(HWND parent, std::function callback, std::function* notify) = NULL; int (*show_messagebox_ui)(HWND parent, int event, void* msg, int flag) = NULL; int (*close_ui)(int) = NULL; static void init_ui(void) { std::string root(hg_sane_middleware::sane_path()); root += "HGTwainUI.dll"; hui = LoadLibraryExA(root.c_str(), NULL, LOAD_WITH_ALTERED_SEARCH_PATH); 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); } } 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; if (hui) { FreeLibrary(hui); hui = NULL; } } } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // 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_(1 * 1024), twain_set_(false), ev_cnt_(0), is_bIndicator(false), is_show_setting_(false) { ui_notify = std::function(); 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; } err_ = open(); } scanner::~scanner() { close(); if (cfg_) { cfg_->release(); cfg_ = NULL; } } 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; } 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) { return pid == 0x7823 && GET_SCANNER_VID(serial) == PRODUCT_VENDOR_HG && GET_SCANNER_PID(serial) == 0x200; } else if (vid == PRODUCT_VENDOR_HW) { return GET_SCANNER_VID(serial) == vid && GET_SCANNER_PID(serial) == pid; } else if (vid == PRODUCT_VENDOR_LSC) { 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; } } return false; } return true; } void scanner::get_scanner_name(SCANNERID id, std::vector& 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); } // 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, ¬ice); //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) callback::apply_current_config(local_trans::u2a(scanner_name_.c_str(), CP_UTF8).c_str(), handle_, &sane_api_); 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_.get()) setting_.reset(); } else if (uev == SANE_EVENT_UI_CLOSE_NORMAL) { // scan complete if (indicator_.get()) indicator_.reset(); is_scanning_ = is_show_setting_; } else if (uev == SANE_EVENT_UI_CLOSE_CANCEL) { // scan cancelled if (indicator_.get()) indicator_.reset(); stop(); // nothing to do, the finishing work do in SANE_EVENT_SCAN_FINISHED } else if (uev == SANE_EVENT_SCAN_FINISHED) { is_scanning_ = is_show_setting_; } 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& scanners) { if (scanners.empty()) return ""; std::vector 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 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(); } 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 (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) { 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_[id] = id; INIT_FIXED_IDS(SANE_OPT_ID_HISTORY_COUNT); INIT_FIXED_IDS(SANE_OPT_ID_DRIVER_VERSION); INIT_FIXED_IDS(SANE_OPT_ID_MANUFACTURER); INIT_FIXED_IDS(SANE_OPT_ID_COPYRIGHT); INIT_FIXED_IDS(SANE_OPT_ID_CO_URL); INIT_FIXED_IDS(SANE_OPT_ID_CO_TEL); INIT_FIXED_IDS(SANE_OPT_ID_CO_ADDR); INIT_FIXED_IDS(SANE_OPT_ID_CO_GPS); INIT_FIXED_IDS(SANE_OPT_ID_HELP); INIT_FIXED_IDS(SANE_OPT_ID_VID); INIT_FIXED_IDS(SANE_OPT_ID_PID); INIT_FIXED_IDS(SANE_OPT_ID_DEV_NAME); INIT_FIXED_IDS(SANE_OPT_ID_DEV_FAMILY); INIT_FIXED_IDS(SANE_OPT_ID_LOGIN); INIT_FIXED_IDS(SANE_OPT_ID_LOGOUT); INIT_FIXED_IDS(SANE_OPT_ID_ROLLER_COUNT); INIT_FIXED_IDS(SANE_OPT_ID_DRIVER_LOG); INIT_FIXED_IDS(SANE_OPT_ID_DEVICE_LOG); 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) 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) { // 兼容老的除孔算法 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; } 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(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(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(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(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; 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) continue; 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(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(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(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(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(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(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(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(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(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(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 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(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(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(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*)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(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; app_wnd_ = setting_.get() ? setting_->hwnd() : callback::find_main_wnd(); 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) { /*if (indicator_.get() && !IsWindowVisible(indicator_->hwnd())) indicator_->show(true);*/ 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; } //else if (indicator_.get()) //{ // indicator_->notify_scan_over(hg_scanner_err_description(ret), true); //} else { // display error message on progress UI, may be closed immediately by APP, so we hide progress UI and call message_box ... // //if (callback::show_progress_ui && is_bIndicator) //{ // int ev = SANE_EVENT_WORKING; // //// on_ui_event(ev, (void*)ev); // ui_notify(SANE_EVENT_SCAN_FINISHED, (void *)hg_scanner_err_description(ret), ret); //} //else { 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 (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); } } } prev_start_result_ = ret; is_scanning_ = ret == SANE_STATUS_GOOD; return local_utility::sane_statu_2_scanner_err(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)) { 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(); return dynamic_cast(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, 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, bool, get_option_info(int sn, value_type* type, value_limit* limit, int* bytes)) { #define SIMPLE_STR_INFO(id) \ if (sn == id) \ { \ if (type) \ *type = VAL_TYPE_STR; \ if (limit) \ *limit = VAL_LIMIT_NONE; \ if (bytes) \ *bytes = 255; \ \ return true; \ } #define SIMPLE_INT_INFO(id) \ if (sn == id) \ { \ if (type) \ *type = VAL_TYPE_INT; \ if (limit) \ *limit = VAL_LIMIT_NONE; \ if (bytes) \ *bytes = sizeof(int); \ \ return true; \ } SIMPLE_STR_INFO(SANE_OPT_ID_DRIVER_VERSION); SIMPLE_STR_INFO(SANE_OPT_ID_MANUFACTURER); SIMPLE_STR_INFO(SANE_OPT_ID_COPYRIGHT); SIMPLE_STR_INFO(SANE_OPT_ID_CO_URL); SIMPLE_STR_INFO(SANE_OPT_ID_CO_TEL); SIMPLE_STR_INFO(SANE_OPT_ID_CO_ADDR); SIMPLE_STR_INFO(SANE_OPT_ID_CO_GPS); SIMPLE_STR_INFO(SANE_OPT_ID_DEV_NAME); SIMPLE_STR_INFO(SANE_OPT_ID_DEV_FAMILY); SIMPLE_STR_INFO(SANE_OPT_ID_LOGIN); SIMPLE_STR_INFO(SANE_OPT_ID_LOGOUT); SIMPLE_STR_INFO(SANE_OPT_ID_DRIVER_LOG); SIMPLE_STR_INFO(SANE_OPT_ID_DEVICE_LOG); SIMPLE_INT_INFO(SANE_OPT_ID_HELP); SIMPLE_INT_INFO(SANE_OPT_ID_HISTORY_COUNT); SIMPLE_INT_INFO(SANE_OPT_ID_ROLLER_COUNT); SIMPLE_INT_INFO(SANE_OPT_ID_VID); SIMPLE_INT_INFO(SANE_OPT_ID_PID); 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) *limit = scanner::from_sane_constraint(desc->constraint_type); 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; } 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(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(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(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(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(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 (!setval(&val, role, VAL_LIMIT_ENUM, param)) break; } } else set_cur_and_def_value(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; return hg_sane_middleware::instance()->set_option(handle_, (const void*)sn, SANE_ACTION_GET_VALUE, data, NULL) == 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; } 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()) { if (!set_option_value_with_parent(sn, val, &ret)) ret = set_option_value(sn, desc->type, desc->size, val); 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); } // 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-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)) { if (cfg_) { std::string cont(cfg_->to_text_stream()); if (*len < cont.length()) { *len = cont.length() + 4; return SCANNER_ERR_INSUFFICIENT_MEMORY; } strcpy(buf, cont.c_str()); } return SCANNER_ERR_OK; } COM_API_IMPLEMENT(scanner, int, twain_set_config(char* buf, size_t len)) { if(cfg_ && cfg_->load_mem(buf)) { update_config(); apply_config(); 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(); 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); //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(); setting_.reset(new dlg_setting(parent, &sane_api_, handle_, with_scan, scanner_name_.substr(0, pid).c_str())); 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_); indicator_.reset(); if (indicator) { indicator_.reset(new dlg_indicator(setting_->hwnd())); 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; ui_notify = std::function(); 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) { if (setting_.get() && IsWindowVisible(setting_->hwnd())) parent = setting_->hwnd(); else if (!IsWindow(parent)) parent = callback::find_main_wnd(); indicator_.reset(new dlg_indicator(parent)); indicator_->set_ui_event_notify(&scanner::ui_callback, this); indicator_->show(true); } return true; } COM_API_IMPLEMENT(scanner, void, ui_hide(void)) { if (indicator_.get()) indicator_.reset(); if (setting_.get()) setting_.reset(); if (callback::close_ui) callback::close_ui(UI_INDICATOR | UI_SETTING | UI_MSG_BOX); } 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) { if (ev_code == SANE_EVENT_WORKING) { img_ind_ = 0; if (indicator_.get()) indicator_->notify_working(); else if (callback::show_progress_ui && is_bIndicator) 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 }; 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; images_.count(&bytes); img->set_image_status((SANE_Image_Statu)simg->flag.statu); bytes /= 1024 * 1024; while (bytes > max_img_mem_ && !user_cancel_ && times++ < 20) // memory control { std::this_thread::sleep_for(std::chrono::milliseconds(5)); images_.count(&bytes); bytes /= 1024 * 1024; if (times == 1) log_info(L"Memory usage upto limit! wait up to 100 ms ...\r\n", 1); } images_.save(img, img->bytes()); } else { img->release(); } if (indicator_.get()) indicator_->notify_data_arrived(true); else if (ui_notify) ui_notify(ev_code, data, 1); { wchar_t msg[128] = { 0 }; swprintf_s(msg, _countof(msg) - 1, L"New image(%u) received with %u bytes\r\n", img_ind_, simg->bytes); log_info(msg, 1); } } else if (ev_code == SANE_EVENT_USB_DATA_RECEIVED) { if (indicator_.get()) indicator_->notify_data_arrived(false); else if (ui_notify) ui_notify(ev_code, data, 0); } else if (ev_code == SANE_EVENT_SCAN_FINISHED) { err_ = *len; if (indicator_.get()) indicator_->notify_scan_over((char*)data, *len != SCANNER_ERR_OK); else if (ui_notify) ui_notify(ev_code, data, *len); else { if (*len) { if (callback::show_messagebox_ui) { callback::show_messagebox_ui(app_wnd_, ev_code, (void*)data, 0); } else // windows message box ... { 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); } // is_scanning_ = false; { 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) { if (callback::show_messagebox_ui && *len) { callback::show_messagebox_ui(app_wnd_, ev_code, (void*)data, 0); } else if (*len) //错误弹出 { 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 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::string cfg(log_file); size_t pos = cfg.rfind('\\'); 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"; 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 }; hg_get_current_time_w(now); g_log_level = get_log_level(g_path_file_.c_str()); swprintf_s(ts, _countof(ts) - 1, L"==================%s - %d==================\r\n", now, g_log_level); fwrite(ts, 2, lstrlenW(ts), g_file_); } } void close_log(void) { if (g_file_) fclose(g_file_); g_file_ = NULL; } void log(const wchar_t* info) { if (g_file_) { std::lock_guard lock(g_lock_); fwrite(info, 2, lstrlenW(info), 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(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 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); } }