#include "scanner.h" #include #include "../sdk/hginclude/huagaoxxx_warraper_ex.h" #include #include "../../code_device/hgsane/sane_hg_mdw.h" #include "sane_option_trans.h" #include #include #include "DlgIndicator.h" #include "DlgSetting.h" static IMPLEMENT_OPTION_STRING_COMPARE(compare_sane_opt); #define SET_SANE_OPT_ID(id, id_name, title, val, extension) \ if(compare_sane_opt(OPTION_TITLE_##title, val)) \ { \ id_name##_id_ = id; \ extension(id); \ } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // 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); } 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_event(code, data, len); else 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); } } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // 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), cb_invoker_(NULL), cb_param_(NULL), working_(false) , ui_quit_(true), scanner_name_(L"") { tmp_path_ = local_trans::a2u(hg_sane_middleware::sane_path().c_str()); tmp_path_ += L"imgs"; CreateDirectoryW(tmp_path_.c_str(), NULL); tmp_path_ += L"\\"; img_fmt_.img_format = SANE_IMAGE_TYPE_BMP; err_ = open(); } scanner::~scanner() { callback::unreg_callback(this); } std::string scanner::get_scanner_name(SCANNERID id) { ScannerInfo* devs = NULL; long count = 0; std::string name(""); if (hg_scanner_enum(devs, &count, true) == SCANNER_ERR_INSUFFICIENT_MEMORY) { count++; devs = new ScannerInfo[count]; if (hg_scanner_enum(devs, &count, true) == SCANNER_ERR_OK) { for (int i = 0; i < count; ++i) { if (devs[i].vid == GET_SCANNER_VID(id) && devs[i].pid == GET_SCANNER_PID(id)) { name = devs[i].name; break; } } } delete[] devs; } return name; } 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 __stdcall scanner::to_int(SANE_Int v) { return v; } float __stdcall scanner::to_float(SANE_Fixed v) { return SANE_UNFIX(v); } void __stdcall scanner::ui_callback(ui_event uev, void* param) { ((scanner*)param)->on_ui_quit(uev); } // IRef COM_API_IMPLEMENT(scanner, long, add_ref(void)) { return refer::add_ref(); } COM_API_IMPLEMENT(scanner, long, release(void)) { return refer::release(); } void scanner::on_ui_quit(ui_event uev) { if (uev == UI_EVENT_CLOSE_CANCEL) stop(); ui_quit_ = uev != UI_EVENT_BEGIN_SCANNING; if (cb_invoker_) { cb_invoker_(ui_quit_ ? SANE_EVENT_SCAN_FINISHED : SANE_EVENT_WORKING, NULL, NULL, cb_param_); } } int scanner::open(void) { int ret = close(); std::string name(scanner::get_scanner_name(id_)); scanner_name_ = L""; if (name.empty()) return SCANNER_ERR_DEVICE_NOT_FOUND; ret = hg_sane_middleware::instance()->open_device(name.c_str(), &handle_); if (ret == SANE_STATUS_GOOD) { scanner_name_ = local_trans::a2u(name.c_str(), CP_UTF8); callback::reg_callback(handle_, this); ret = init_options_id(); } return ret; } int scanner::close(void) { 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->title, func) while ((desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, op_id))) { SET_OPT_ID(is_multiout, DLSC, extension_none) else SET_OPT_ID(multiout_type, DLSCLX, extension_multiout_type) else SET_OPT_ID(color_mode, YSMS, extension_color_mode) else SET_OPT_ID(erase_color, HDHHBTX_CS, extension_erase_color) else SET_OPT_ID(erase_multiout_red, 24WCSTX_DLSCCH, extension_none) else SET_OPT_ID(erase_paper_red, 24WCSTX_DTKCH, extension_none) else SET_OPT_ID(is_erase_background, BJYC, extension_none) else SET_OPT_ID(background_color_range, BJSCFDFW, extension_none) else SET_OPT_ID(sharpen, RHYMH, extension_sharpen) else SET_OPT_ID(erase_morr, QCMW, extension_none) else SET_OPT_ID(erase_grids, CWW, extension_none) else SET_OPT_ID(error_extend, CWKS, extension_none) else SET_OPT_ID(is_noise_modify, HBTXZDYH, extension_none) else SET_OPT_ID(noise_threshold, ZDYHCC, extension_none) else SET_OPT_ID(paper, ZZCC, extension_paper) else SET_OPT_ID(is_custom_area, ZDYSMQY, extension_none) else SET_OPT_ID(curstom_area_l, SMQYZCmm, extension_none) else SET_OPT_ID(curstom_area_r, SMQYYCmm, extension_none) else SET_OPT_ID(curstom_area_t, SMQYSCmm, extension_none) else SET_OPT_ID(curstom_area_b, SMQYXCmm, extension_none) else SET_OPT_ID(is_size_check, CCJC, extension_none) else SET_OPT_ID(page, SMYM, extension_page) else SET_OPT_ID(blank_page_threshold, TGKBYLMD, extension_none) else SET_OPT_ID(resolution, FBL, extension_none) else SET_OPT_ID(image_quality, HZ, extension_none) else SET_OPT_ID(is_swap, JHZFM, extension_none) else SET_OPT_ID(is_split, TXCF, extension_none) else SET_OPT_ID(is_auto_deskew, ZDJP, extension_none) else SET_OPT_ID(is_custom_gamma, QYSDQX, extension_none) else SET_OPT_ID(bright, LDZ, extension_none) else SET_OPT_ID(contrast, DBD, extension_none) else SET_OPT_ID(gamma, JMZ, extension_none) else SET_OPT_ID(is_erase_black_frame, XCHK, extension_none) else SET_OPT_ID(deep_sample, SSYZ, extension_none) else SET_OPT_ID(threshold, YZ, extension_none) else SET_OPT_ID(anti_noise, BJKZDJ, extension_none) else SET_OPT_ID(margin, BYSJ, extension_none) else SET_OPT_ID(fill_background, BJTCFS, extension_fill_bkg_method) else SET_OPT_ID(is_anti_permeate, FZST, extension_none) else SET_OPT_ID(anti_permeate_level, FZSTDJ, extension_none) else SET_OPT_ID(is_erase_hole, CKYC, extension_none) else SET_OPT_ID(search_hole_range, CKSSFWZFMBL, extension_none) else SET_OPT_ID(is_filling_color, SCTC, extension_none) else SET_OPT_ID(is_ultrasonic_check, CSBJC, extension_none) else SET_OPT_ID(is_check_staple, ZDJC, extension_none) else SET_OPT_ID(scan_mode, SMZS, extension_none) else SET_OPT_ID(scan_count, SMSL, extension_none) else SET_OPT_ID(text_direction, WGFX, extension_text_direction) else SET_OPT_ID(is_rotate_bkg180, BMXZ180, extension_none) else SET_OPT_ID(is_check_dogear, ZJJC, extension_none) else SET_OPT_ID(dogear_size, ZJDX, extension_none) else SET_OPT_ID(is_check_skew, WXJC, extension_none) else SET_OPT_ID(skew_range, WXRRD, 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; \ 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); return ret; } int scanner::control_read_string(int code, std::string& ret) { char* buf = NULL; unsigned len = 0; int err = hg_sane_middleware::instance()->io_control(handle_, code, buf, &len); ret = ""; if (err == SANE_STATUS_NO_MEM) { len += 4; buf = new char[len]; memset(buf, 0, len); err = hg_sane_middleware::instance()->io_control(handle_, code, buf, &len); if (err == SANE_STATUS_GOOD) ret = buf; delete[] buf; } return err; } 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; ea.ind = ex_duplex_id_ = ex_id_++; ea.base_ind = id; ea.ex_api = &scanner::handle_ex_duplex; ex_opts_.push_back(ea); 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); 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); 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); } 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_, scan_mode_id_); char* buf = new char[parent->size + 4]; memset(buf, 0, parent->size); hg_sane_middleware::instance()->get_cur_value(handle_, scan_mode_id_, buf); handled = compare_sane_opt(OPTION_VALUE_SMZS_LXSM, buf); delete[] buf; if (handled) { int count = -1; value_role role = VAL_ROLE_CURRENT; buf = (char*)hg_sane_middleware::instance()->get_def_value(handle_, scan_mode_id_); if (compare_sane_opt(OPTION_VALUE_SMZS_LXSM, buf)) role = value_role(role | VAL_ROLE_DEFAULT); local_utility::free_memory(buf); setv(&count, value_role(VAL_ROLE_CURRENT | VAL_ROLE_DEFAULT), param); } } else handled = false; return handled; } bool scanner::set_option_value_with_parent(int sn, void* data, int* err) // return true if handled { bool handled = true; if (sn == scan_count_id_) { SANE_Option_Descriptor* parent = hg_sane_middleware::instance()->get_option_descriptor(handle_, 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_, scan_mode_id_, val); if (compare_sane_opt(OPTION_VALUE_SMZS_LXSM, val)) { if (*(int*)data != -1) { strcpy(val, OPTION_VALUE_SMZS_SMZDZS); *err = hg_sane_middleware::instance()->set_option(handle_, scan_mode_id_, SANE_ACTION_SET_VALUE, val, &after); } } else if (*(int*)data == -1) { strcpy(val, OPTION_VALUE_SMZS_LXSM); *err = hg_sane_middleware::instance()->set_option(handle_, scan_mode_id_, SANE_ACTION_SET_VALUE, val, &after); } handled = false; } else { handled = false; } 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_, 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 = SANE_UNFIX(sf); } else if(buf) { strcpy((char*)val, buf); delete[] buf; } return ret; } scanner::EXAPIPOS scanner::find_ex_api(int op_id) { return std::find(ex_opts_.begin(), ex_opts_.end(), op_id); } EX_OPTION_HANDLER_IMPL(multiout) { int ret = SCANNER_ERR_OK; SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, base_id); if (setv) { char* cur = new char[desc->size], * def = (char*)hg_sane_middleware::instance()->get_def_value(handle_, base_id); int now = 0, // sane_opt_trans::multiout_value_to_twain(cur) init = sane_opt_trans::multiout_value_to_twain(def), val = 0; local_utility::free_memory(def); memset(cur, 0, desc->size); hg_sane_middleware::instance()->get_cur_value(handle_, base_id, cur); now = sane_opt_trans::multiout_value_to_twain(cur); delete[] cur; { // parent item ... SANE_Bool enable = SANE_TRUE; if (hg_sane_middleware::instance()->get_cur_value(handle_, is_multiout_id_, &enable)) { if (!enable) 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 (!setv(&val, role, 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, 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")) { // enable multi-out ... *((SANE_Bool*)val) = SANE_TRUE; ret = hg_sane_middleware::instance()->set_option(handle_, is_multiout_id_, SANE_ACTION_SET_VALUE, val, &after); strcpy(val, in); } else { // disable multi-out, let multiout type side base_id = is_multiout_id_; *((SANE_Bool*)val) = SANE_FALSE; } if (ret == SANE_STATUS_GOOD) ret = hg_sane_middleware::instance()->set_option(handle_, 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(auto_color_type) { int ret = SCANNER_ERR_OK; SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, base_id); int len = desc->size + 4; char* buf = new char[len]; memset(buf, 0, len); hg_sane_middleware::instance()->get_cur_value(handle_, base_id, buf); if (setv) { len = sane_opt_trans::auto_color_type_to_twain(buf); setv(&len, VAL_ROLE_CURRENT, data); } else { SANE_Int after = 0; strcpy(buf, sane_opt_trans::auto_color_type_from_twain(*(int*)data)); ret = hg_sane_middleware::instance()->set_option(handle_, 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_, base_id); if (setv) { char* cur = new char[desc->size], * def = (char*)hg_sane_middleware::instance()->get_def_value(handle_, base_id); int now = 0, // sane_opt_trans::multiout_value_to_twain(cur) init = sane_opt_trans::color_mode_to_twain(def), val = 0; local_utility::free_memory(def); memset(cur, 0, desc->size); hg_sane_middleware::instance()->get_cur_value(handle_, base_id, cur); now = sane_opt_trans::color_mode_to_twain(cur); delete[] 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, 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::color_mode_from_twain(*(int*)data); SANE_Int after = 0; strcpy(val, in); ret = hg_sane_middleware::instance()->set_option(handle_, 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_, base_id); if (setv) { char* cur = new char[desc->size], * def = (char*)hg_sane_middleware::instance()->get_def_value(handle_, base_id); int now = 0, // sane_opt_trans::multiout_value_to_twain(cur) init = sane_opt_trans::sharpen_to_twain(def), val = 0; local_utility::free_memory(def); memset(cur, 0, desc->size); hg_sane_middleware::instance()->get_cur_value(handle_, base_id, cur); now = sane_opt_trans::sharpen_to_twain(cur); delete[] 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, 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; ret = hg_sane_middleware::instance()->set_option(handle_, 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_, 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_, base_id, buf); char* def = (char*)hg_sane_middleware::instance()->get_def_value(handle_, base_id); int now = sane_opt_trans::paper_to_twain(buf), init = sane_opt_trans::paper_to_twain(def), val = 0; 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, 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_, 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_, 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_, base_id, buf); lateral_swap = sane_opt_trans::switch_paper_lateral(buf); lateral = sane_opt_trans::is_paper_lateral(buf); if (setv) { setv(&lateral, VAL_ROLE_CURRENT, 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_, base_id, SANE_ACTION_SET_VALUE, buf, &after); ret = local_utility::sane_statu_2_scanner_err(ret); } } else 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_, base_id); int len = desc->size + 4; char* buf = new char[len]; memset(buf, 0, len); hg_sane_middleware::instance()->get_cur_value(handle_, base_id, buf); if (setv) { bool yes = strcmp(buf, OPTION_VALUE_ZZCC_PPYSCC) == 0; setv(&yes, VAL_ROLE_CURRENT, data); } else { SANE_Int after = 0; strcpy(buf, *(bool*)data ? OPTION_VALUE_ZZCC_PPYSCC : OPTION_VALUE_ZZCC_A4); ret = hg_sane_middleware::instance()->set_option(handle_, 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_, base_id); int len = desc->size + 4; char* buf = new char[len]; memset(buf, 0, len); hg_sane_middleware::instance()->get_cur_value(handle_, base_id, buf); if (setv) { bool yes = strcmp(buf, OPTION_VALUE_ZZCC_ZDSMCCZDCQ) == 0; setv(&yes, VAL_ROLE_CURRENT, data); } else { SANE_Int after = 0; strcpy(buf, *(bool*)data ? OPTION_VALUE_ZZCC_ZDSMCCZDCQ : OPTION_VALUE_ZZCC_ZDSMCC); ret = hg_sane_middleware::instance()->set_option(handle_, 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_, 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_, 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_, 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, 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_, 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_, base_id); unsigned len = desc->size + 4; char* buf = new char[len]; memset(buf, 0, len); if (setv) { void* init = hg_sane_middleware::instance()->get_def_value(handle_, base_id); hg_sane_middleware::instance()->get_cur_value(handle_, base_id, buf); val = strcmp(buf, OPTION_VALUE_SMYM_SM) == 0; if (val && strcmp((char*)init, OPTION_VALUE_SMYM_SM) == 0 || !val && strcmp((char*)init, OPTION_VALUE_SMYM_DM) == 0) setv(&val, value_role(VAL_ROLE_CURRENT | VAL_ROLE_DEFAULT), data); else if (setv(&val, VAL_ROLE_CURRENT, data)) { if (strcmp((char*)init, OPTION_VALUE_SMYM_SM) == 0) { val = true; setv(&val, VAL_ROLE_DEFAULT, data); } if (strcmp((char*)init, OPTION_VALUE_SMYM_DM) == 0) { val = false; setv(&val, VAL_ROLE_DEFAULT, data); } } } else { strcpy(buf, val ? OPTION_VALUE_SMYM_SM : OPTION_VALUE_SMYM_DM); SANE_Int after = 0; ret = hg_sane_middleware::instance()->set_option(handle_, 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_, 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_, base_id); hg_sane_middleware::instance()->get_cur_value(handle_, base_id, buf); val = strcmp(buf, OPTION_VALUE_SMYM_SM) == 0; set_cur_and_def_value(strcmp(buf, OPTION_VALUE_BJTCFS_TDBX) == 0, strcmp(init, OPTION_VALUE_BJTCFS_TDBX) == 0, setv, data); local_utility::free_memory(init); } else { strcpy(buf, val ? OPTION_VALUE_BJTCFS_TDBX : OPTION_VALUE_BJTCFS_ADBX); SANE_Int after = 0; ret = hg_sane_middleware::instance()->set_option(handle_, 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_, base_id); unsigned len = desc->size + 4; char* buf = new char[len]; memset(buf, 0, len); if (setv) { hg_sane_middleware::instance()->get_cur_value(handle_, base_id, buf); val = strcmp(buf, OPTION_VALUE_SMYM_TGKBYTY) == 0; setv(&val, VAL_ROLE_CURRENT, data); } else { if (val) strcpy(buf, OPTION_VALUE_SMYM_TGKBYTY); else { char* init = (char*)hg_sane_middleware::instance()->get_def_value(handle_, base_id); strcpy(buf, init); local_utility::free_memory(init); } SANE_Int after = 0; ret = hg_sane_middleware::instance()->set_option(handle_, 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_, base_id); unsigned len = desc->size + 4; char* buf = new char[len]; memset(buf, 0, len); if (setv) { hg_sane_middleware::instance()->get_cur_value(handle_, base_id, buf); val = strcmp(buf, OPTION_VALUE_SMYM_TGKBYFPZ) == 0; setv(&val, VAL_ROLE_CURRENT, data); } else { if (val) strcpy(buf, OPTION_VALUE_SMYM_TGKBYFPZ); else { char* init = (char*)hg_sane_middleware::instance()->get_def_value(handle_, base_id); strcpy(buf, init); local_utility::free_memory(init); } SANE_Int after = 0; ret = hg_sane_middleware::instance()->set_option(handle_, 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_, base_id); unsigned len = desc->size + 4; char* buf = new char[len]; memset(buf, 0, len); if (setv) { hg_sane_middleware::instance()->get_cur_value(handle_, base_id, buf); val = strcmp(buf, OPTION_VALUE_SMYM_DZ) == 0; setv(&val, VAL_ROLE_CURRENT, data); } else { if (val) strcpy(buf, OPTION_VALUE_SMYM_DZ); else { char* init = (char*)hg_sane_middleware::instance()->get_def_value(handle_, base_id); strcpy(buf, init); local_utility::free_memory(init); } SANE_Int after = 0; ret = hg_sane_middleware::instance()->set_option(handle_, 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_, 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_, 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, 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_, 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_, 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_, 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, 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_, 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, 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 < 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, 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, 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; setv(&val, VAL_ROLE_CURRENT, 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; setv(&val, VAL_ROLE_CURRENT, 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, 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, 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, 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, data); } return ret; } // ISaneInvoker COM_API_IMPLEMENT(scanner, int, start(void)) { int ret = SANE_STATUS_GOOD; scan_msg_ = "OK"; scan_err_ = false; 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) { unsigned int l = sizeof(img_fmt_); 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; working_ = true; } prev_start_result_ = ret; return local_utility::sane_statu_2_scanner_err(ret); } COM_API_IMPLEMENT(scanner, int, stop(void)) { working_ = false; return hg_sane_middleware::instance()->stop(handle_); } COM_API_IMPLEMENT(scanner, void, set_event_callback(void(*cb)(int ev_type, void* data, unsigned int* len, void* param), void* param)) { cb_invoker_ = cb; cb_param_ = param; } 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(); bool notify = true; while (count == 0 && milliseconds) { MSG msg = { 0 }; if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessageW(&msg); } Sleep(10); if (!working_) { if (notify && indicator_.get()) { notify = false; indicator_->notify_scan_over(scan_msg_.c_str(), scan_err_); // Ending by UI } else if(ui_quit_) break; } count = images_.count(); if (milliseconds != -1) { if (milliseconds <= 10) break; milliseconds -= 10; } } 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)) { return images_.get_header(header); } COM_API_IMPLEMENT(scanner, bool, is_online(void)) { return !scanner::get_scanner_name(id_).empty(); } 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, bool, get_option_info(int sn, value_type* type, value_limit* limit, int* bytes)) { SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, sn); 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)) { 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_, sn); void* init = hg_sane_middleware::instance()->get_def_value(handle_, 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_, sn, &v); val = v == SANE_TRUE; set_cur_and_def_value(val, *(SANE_Bool*)init == SANE_TRUE, setval, 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_, 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, 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_, sn, &cur); if (sn == resolution_id_) dpi_ = 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 = SANE_UNFIX(v[i + 1]); if (!setval(&val, role, param)) break; } } else set_cur_and_def_value(val, 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_, 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, 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, int, set_value(int sn, void* val)) { 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_, sn); 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_ = *(float*)val + .5f; else dpi_ = *(int*)val; } return ret; } // SANE options ID ... 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-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; } // 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)) { SANEAPI api = { NULL }; api.sane_cancel_api = inner_sane_cancel; api.sane_close_api = inner_sane_close; api.sane_control_option_api = inner_sane_control_option; api.sane_get_devices_api = inner_sane_get_devices; api.sane_get_option_descriptor_api = inner_sane_get_option_descriptor; api.sane_get_parameters_api = inner_sane_get_parameters; api.sane_get_select_fd_api = inner_sane_get_select_fd; api.sane_io_control_api = inner_sane_io_control; api.sane_open_api = inner_sane_open; api.sane_read_api = inner_sane_read; api.sane_set_io_mode_api = inner_sane_set_io_mode; api.sane_start_api = inner_sane_start; api.sane_strstatus_api = inner_sane_strstatus; setting_.reset(new dlg_setting(parent, &api, handle_, with_scan, scanner_name_.c_str())); setting_->set_quit_notify(&scanner::ui_callback, this); setting_->show(); ui_quit_ = false; return true; } COM_API_IMPLEMENT(scanner, bool, ui_show_progress(HWND parent)) { indicator_.reset(new dlg_indicator(parent)); indicator_->set_quit_notify(&scanner::ui_callback, this); indicator_->show(); ui_quit_ = false; return true; } COM_API_IMPLEMENT(scanner, void, ui_hide(void)) { if (indicator_.get()) indicator_.reset(); if (setting_.get()) setting_.reset(); } COM_API_IMPLEMENT(scanner, bool, ui_is_ok(void)) { return true; } int scanner::handle_event(int ev_code, void* data, unsigned int* len) { 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(simg->header, simg->data, simg->bytes, dpi_, (tmp_path_ + name).c_str(), xfer_, &img_fmt_); if (img->bytes() >= simg->bytes) { images_.save(img); } else { img->release(); } if (indicator_) indicator_->notify_data_arrived(true); } else if (ev_code == SANE_EVENT_USB_DATA_RECEIVED) { if (indicator_) indicator_->notify_data_arrived(false); } else if (ev_code == SANE_EVENT_SCAN_FINISHED) { if (indicator_.get()) { scan_msg_ = (char*)data; scan_err_ = *len != SCANNER_ERR_OK; } working_ = false; } return 0; } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // exports #ifdef EXPORT_SANE_API __declspec(dllexport) #else __declspec(dllimport) #endif int __stdcall initialize(void* reserve) { hg_sane_middleware::set_callback(callback::sane_event_callback, NULL); hg_sane_middleware::instance(); return SANE_STATUS_GOOD; } #ifdef EXPORT_SANE_API __declspec(dllexport) #else __declspec(dllimport) #endif int __stdcall open_scanner(SCANNERID scanner_id, ISaneInvoker** invoker) { if (!invoker) return SCANNER_ERR_INVALID_PARAMETER; if (!is_scanner_online(scanner_id)) return SCANNER_ERR_DEVICE_NOT_FOUND; scanner* scn = new scanner(scanner_id); *invoker = dynamic_cast(scn); return 0; } #ifdef EXPORT_SANE_API __declspec(dllexport) #else __declspec(dllimport) #endif bool __stdcall is_scanner_online(SCANNERID scanner_id) { return !scanner::get_scanner_name(scanner_id).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(); return 0; }