#pragma once #include "scanned_img.h" #include #include #include #include #include #include #define EXTENSION_ID_BASE 0x300 class scanner : public ISaneInvoker, virtual public refer { SANE_Handle handle_; std::string model_; int err_; int ex_id_; int prev_start_result_; int dpi_; int fetch_imgs_ = 0; // count for images has fetched by APP bool is_bIndicator; bool is_show_setting_; unsigned int img_ind_; std::string scanner_name_; std::string tmp_path_; std::string cfg_path_; std::string scan_msg_; bool scan_err_; volatile bool is_ui_wait_img_; volatile bool is_scanning_; volatile bool user_cancel_; twain_xfer xfer_; safe_img_queue images_; size_t max_img_mem_; safe_queue events_; //如果有界面,则全部保存从界面传回的消息;否则只保存开始扫描和结束扫描的事件 int ev_cnt_; SANE_FinalImgFormat img_fmt_; bool twain_set_; SANEAPI sane_api_; std::unique_ptr done_; std::function ui_notify; int(* scanner_ev_handler_)(int, void*); void* evh_param_; HWND app_wnd_; // for MessageBox bool is_show_ui_; typedef struct _sane_opt { int opt_sn; value_type type; value_limit limit; int size; int cap; // sane capability }SANEOPT; std::map sane_opts_; // int transfer_id(int id); // transfer fixed SANE option ID to real id, -1 is none void transport_config_file(void); void update_config(void); void load_config(const wchar_t* file); void save_config(const wchar_t* file); void apply_config(void); void on_ui_event(int uev, void* sender); std::string choose_scanner(const std::vector& scanners); int close(void); int init_options_id(void); char* get_opt_value(int id, int size, bool def_val/*false - current value*/); // call delete[] to free returned value bool get_opt_value(int id, void* buf, bool def_val/*false - current value*/); // call delete[] to free returned value int control_read_string(int io_code, std::string& val); bool get_option_value_with_parent(int sn, set_opt_value setv, void* param); // return true if handled bool set_option_value_with_parent(int sn, void* data, int* err); // return true if handled sn int set_option_value(int sn, SANE_Value_Type type, int size, void* data); int thread_start(void); std::unique_ptr thread_starting_; std::unique_ptr thread_stop_; // stop阻塞到工作线程结束,在结束回调后才返回。为不阻塞界面,在线程中停止 bool scan_working_ = false; // start阻塞到有一张图片才返回,如果第一张出现错误(比如卡纸),则回调先于start返回结束标志。该变量用于协调FINISH事件通知 template bool set_cur_and_def_value(T cur, T def, set_opt_value setv, void* param) { if (cur == def) return setv(&cur, (value_role)(VAL_ROLE_CURRENT | VAL_ROLE_DEFAULT), VAL_LIMIT_NONE, param); else if (setv(&cur, VAL_ROLE_CURRENT, VAL_LIMIT_NONE, param)) return setv(&def, VAL_ROLE_DEFAULT, VAL_LIMIT_NONE, param); return false; } template void set_value_range(S cur, S def, S l, S u, S s, set_opt_value setv, void* param, T(* to_t)(S)) { T v = to_t(cur); while (setv(&v, VAL_ROLE_CURRENT, VAL_LIMIT_RANGE, param)) { v = to_t(def); if (!setv(&v, VAL_ROLE_DEFAULT, VAL_LIMIT_RANGE, param)) break; v = to_t(l); if (!setv(&v, VAL_ROLE_LOWER, VAL_LIMIT_RANGE, param)) break; v = to_t(u); if (!setv(&v, VAL_ROLE_UPPER, VAL_LIMIT_RANGE, param)) break; v = to_t(s); setv(&v, VAL_ROLE_STEP, VAL_LIMIT_RANGE, param); break; } } static int to_int(SANE_Int v); static double to_double(SANE_Fixed v); static void ui_callback(int uev, void* sender, void* param); static bool is_option_float(int sn, void* param); void scan_done(void); int language_id_; public: scanner(const char* model); protected: ~scanner(); public: static void get_scanner_name(const char* model, std::vector& names); static value_type from_sane_type(SANE_Value_Type type); static value_limit from_sane_constraint(SANE_Constraint_Type type); // IRef public: COM_API_OVERRIDE(int32_t, add_ref(void)); COM_API_OVERRIDE(int32_t, release(void)); // ISaneInvoker public: COM_API_OVERRIDE(int, start(void)); COM_API_OVERRIDE(int, stop(void)); COM_API_OVERRIDE(int, get_event(void)); COM_API_OVERRIDE(void, set_event_callback(int(*handle_ev)(int, void*) = nullptr, void* para = nullptr)); COM_API_OVERRIDE(bool, wait_image(DWORD milliseconds = -1)); COM_API_OVERRIDE(int, get_scanned_images(DWORD milliseconds = 0)); COM_API_OVERRIDE(IScanImg*, take_first_image(twain_xfer xfer = TWAIN_XFER_Native)); // call 'release' on returned value, plz COM_API_OVERRIDE(bool, get_first_image_header(SANE_Parameters* header, size_t* bytes = nullptr, int* dpi = nullptr)); COM_API_OVERRIDE(bool, discard_first_image(void)); COM_API_OVERRIDE(int, convert_image(SANE_ImageFormatConvert* conv)); COM_API_OVERRIDE(bool, is_online(void)); COM_API_OVERRIDE(bool, is_paper_on(void)); COM_API_OVERRIDE(int, last_error(void)); COM_API_OVERRIDE(int, image_fetched(IScanImg* tx)); // notify the image 'tx' has fetched by APP // ui ... COM_API_OVERRIDE(bool, ui_is_ok(void)); COM_API_OVERRIDE(bool, ui_show_setting(HWND parent, bool with_scan, bool indicator = true)); COM_API_OVERRIDE(bool, ui_show_progress(HWND parent, bool bIndicator)); COM_API_OVERRIDE(void, ui_hide(void)); // twain COM_API_OVERRIDE(void, twain_set_transfer(twain_xfer xfer)); COM_API_OVERRIDE(void, twain_set_compression(SANE_CompressionType compression, void* detail = nullptr)); COM_API_OVERRIDE(int, twain_get_config(char* buf, size_t* len)); COM_API_OVERRIDE(int, twain_set_config(char* buf, size_t len)); COM_API_OVERRIDE(bool, get_option_info(int sn, value_type* type, value_limit* limit, int* bytes, bool* readonly)); COM_API_OVERRIDE(int, get_fixed_ids(SANE_Bool(*cb)(int id, void* param), void* param)); COM_API_OVERRIDE(bool, get_value(int sn, set_opt_value func, void* param)); // get all values COM_API_OVERRIDE(bool, get_value(int sn, void* data, int* len)); // get current value COM_API_OVERRIDE(int, set_value(int sn, void* val)); // methods: public: int open(void); int handle_device_event(int ev_code, void* data, unsigned int* len); };