2023-11-10 06:58:17 +00:00
|
|
|
|
|
2023-07-10 07:28:45 +00:00
|
|
|
|
|
|
|
|
|
#include "scanner.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <sane/sane_option_definitions.h>
|
|
|
|
|
#include "sane_option_trans.h"
|
|
|
|
|
#include <chrono>
|
|
|
|
|
#include <mutex>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <functional>
|
|
|
|
|
|
|
|
|
|
#include <twain_user/twainui.h>
|
|
|
|
|
#include <huagao/brand.h>
|
|
|
|
|
#include "sane_helper.h"
|
2023-07-14 03:35:50 +00:00
|
|
|
|
#include "../../sdk/hginclude/utils.h"
|
2023-07-10 07:28:45 +00:00
|
|
|
|
|
|
|
|
|
#define START_SCAN_IN_THREAD
|
|
|
|
|
|
2023-11-10 06:38:12 +00:00
|
|
|
|
#pragma comment(lib, "user32.lib")
|
2023-07-10 07:28:45 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if !defined(WIN32) && !defined(_WIN64)
|
|
|
|
|
template<typename ... Args>
|
|
|
|
|
int sprintf_s(char* buf, size_t len, const char* fmt, Args ... args)
|
|
|
|
|
{
|
|
|
|
|
return sprintf(buf, fmt, args ...);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string g_scanner_path = ""; // hg_log::get_module_full_path((std::string(GET_BACKEND_NAME) + ".so").c_str());
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// callback
|
|
|
|
|
sane_helper* sane_helper_ = nullptr;
|
|
|
|
|
|
|
|
|
|
namespace callback
|
|
|
|
|
{
|
|
|
|
|
static std::mutex cb_lock_;
|
|
|
|
|
typedef struct _scanner_inst
|
|
|
|
|
{
|
|
|
|
|
SANE_Handle dev;
|
|
|
|
|
scanner* invoker;
|
|
|
|
|
|
|
|
|
|
bool operator==(const SANE_Handle& h)
|
|
|
|
|
{
|
|
|
|
|
return dev == h;
|
|
|
|
|
}
|
|
|
|
|
bool operator==(const scanner* obj)
|
|
|
|
|
{
|
|
|
|
|
return invoker == obj;
|
|
|
|
|
}
|
|
|
|
|
}SCNINST;
|
|
|
|
|
std::vector<SCNINST> g_scanner_instances;
|
|
|
|
|
|
|
|
|
|
int sane_event_callback( // 注册回调的对象,需要保证该回调是多线程安全的
|
|
|
|
|
SANE_Handle hdev // 产生事件的设备句柄
|
|
|
|
|
, int code // 回调事件代码
|
|
|
|
|
, void* data // 回调事件数据,根据事件代码有所不同,参照具体事件定义
|
|
|
|
|
, unsigned int* len // 数据长度(字节),或者event_data的缓冲区长度,详细请看相应的事件代码
|
|
|
|
|
, void* param // 用户自定义数据,与调用sane_init_ex传入时的保持一致
|
|
|
|
|
) // 返回值依不同的事件代码而定,通常为“0”
|
|
|
|
|
{
|
|
|
|
|
std::lock_guard<std::mutex> lock(cb_lock_);
|
|
|
|
|
std::vector<SCNINST>::iterator it = std::find(g_scanner_instances.begin(), g_scanner_instances.end(), hdev);
|
|
|
|
|
|
|
|
|
|
if (it != g_scanner_instances.end())
|
|
|
|
|
return it->invoker->handle_device_event(code, data, len);
|
2023-07-15 02:24:25 +00:00
|
|
|
|
else if(code != SANE_EVENT_SCANNER_CLOSED)
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
|
|
|
|
char msg[218] = { 0 };
|
|
|
|
|
sprintf_s(msg, _countof(msg) - 1, "Lost device(0x%08X) when event(%u) occurs!\r\n", hdev, code);
|
2023-07-11 09:13:28 +00:00
|
|
|
|
utils::log_info(msg, (log_level)1);
|
2023-07-10 07:28:45 +00:00
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
void reg_callback(SANE_Handle dev, scanner* invoker)
|
|
|
|
|
{
|
|
|
|
|
std::lock_guard<std::mutex> lock(cb_lock_);
|
|
|
|
|
std::vector<SCNINST>::iterator it = std::find(g_scanner_instances.begin(), g_scanner_instances.end(), dev);
|
|
|
|
|
if (it == g_scanner_instances.end())
|
|
|
|
|
{
|
|
|
|
|
SCNINST inst;
|
|
|
|
|
|
|
|
|
|
inst.dev = dev;
|
|
|
|
|
inst.invoker = invoker;
|
|
|
|
|
g_scanner_instances.push_back(inst);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
it->invoker = invoker;
|
|
|
|
|
}
|
|
|
|
|
void unreg_callback(scanner* invoker)
|
|
|
|
|
{
|
|
|
|
|
std::lock_guard<std::mutex> lock(cb_lock_);
|
|
|
|
|
std::vector<SCNINST>::iterator it = std::find(g_scanner_instances.begin(), g_scanner_instances.end(), invoker);
|
|
|
|
|
if (it != g_scanner_instances.end())
|
|
|
|
|
g_scanner_instances.erase(it);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static HWND find_main_wnd(void)
|
|
|
|
|
{
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static std::string option_value_2_string(SANE_Value_Type type, void* value)
|
|
|
|
|
{
|
|
|
|
|
if(type == SANE_TYPE_BOOL)
|
|
|
|
|
return *(SANE_Bool*)value == SANE_TRUE ? "true" : "false";
|
|
|
|
|
if(type == SANE_TYPE_INT)
|
|
|
|
|
return std::to_string(*(SANE_Int*)value);
|
|
|
|
|
if(type == SANE_TYPE_FIXED)
|
|
|
|
|
return std::to_string(SANE_UNFIX(*(SANE_Int*)value));
|
|
|
|
|
if(type == SANE_TYPE_STRING)
|
|
|
|
|
return (char*)value;
|
|
|
|
|
|
|
|
|
|
return "Unknown";
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-21 03:23:38 +00:00
|
|
|
|
|
|
|
|
|
|
2023-07-10 07:28:45 +00:00
|
|
|
|
// 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 nullptr, 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 nullptr, flag - unused, be 0
|
|
|
|
|
// SANE_EVENT_IMAGE_OK - void* unused, be nullptr, flag - unused, be 0
|
|
|
|
|
static HMODULE hui = nullptr;
|
|
|
|
|
int (*choose_scanner)(const std::vector<DEVQUEUI>& devs) = nullptr; // blocked. return selected DEVQUE::id or -1 if user cancelled
|
|
|
|
|
char* (*apply_current_config)(const char* dev_name, SANE_Handle device, LPSANEAPI api) = nullptr; // 应用设备的当前配<E5898D>?
|
|
|
|
|
int (*show_setting_ui)(SANE_Handle device, HWND parent, LPSANEAPI api, const char* devname, bool with_scan, std::function<void(ui_result)> callback) = nullptr;
|
|
|
|
|
int (*show_progress_ui)(HWND parent, std::function<void(ui_result)> callback, std::function<void(int/*event*/, void* /*msg*/, int/*flag*/)>* notify) = nullptr;
|
|
|
|
|
int (*show_messagebox_ui)(HWND parent, int event, void* msg, int flag) = nullptr;
|
|
|
|
|
int (*close_ui)(int) = nullptr;
|
|
|
|
|
void (*twain_ui_free)(void* buf) = nullptr;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void init_ui(void)
|
|
|
|
|
{
|
2023-10-20 07:21:17 +00:00
|
|
|
|
std::string root(utils::get_module_full_path(MODULE_NAME_SCANNER));
|
2023-07-10 07:28:45 +00:00
|
|
|
|
size_t pos = root.rfind(PATH_SEPARATOR[0]);
|
|
|
|
|
|
2023-07-18 06:13:43 +00:00
|
|
|
|
if(pos != std::string::npos)
|
2023-07-10 07:28:45 +00:00
|
|
|
|
root.erase(pos);
|
2023-07-18 06:13:43 +00:00
|
|
|
|
root = utils::find_file(root.c_str(), "*twainui*", false);
|
|
|
|
|
utils::to_log(LOG_LEVEL_DEBUG, "TwainUI component: %s\n", root.c_str());
|
|
|
|
|
// #if defined(WIN32) || defined(_WIN64)
|
|
|
|
|
// root += OEM_SHORT_NAME_E;
|
|
|
|
|
// #else
|
|
|
|
|
// std::string vnd(OEM_SHORT_NAME_E);
|
|
|
|
|
//
|
|
|
|
|
// std::transform(vnd.begin(), vnd.end(), vnd.begin(), toupper);
|
|
|
|
|
// root += "lib" + vnd;
|
|
|
|
|
// #endif
|
|
|
|
|
// root += "TwainUI.";
|
|
|
|
|
// root += DLL_EXTESION;
|
2023-08-08 08:27:58 +00:00
|
|
|
|
if (hui)
|
|
|
|
|
FreeLibrary(hui);
|
|
|
|
|
|
|
|
|
|
// hui = LoadLibraryExA(root.c_str(), nullptr, LOAD_WITH_ALTERED_SEARCH_PATH);
|
2023-08-22 08:47:28 +00:00
|
|
|
|
hui = utils::load_dll(root.c_str(), LOAD_WITH_ALTERED_SEARCH_PATH);
|
2023-07-10 07:28:45 +00:00
|
|
|
|
if (!hui)
|
|
|
|
|
{
|
|
|
|
|
std::string info("Load '" + root);
|
|
|
|
|
|
|
|
|
|
info += "' failed: " + std::string(strerror(GetLastError())) + "\r\n";
|
|
|
|
|
|
2023-07-21 08:56:28 +00:00
|
|
|
|
|
2023-07-11 09:13:28 +00:00
|
|
|
|
utils::log_info(info.c_str(), LOG_LEVEL_DEBUG);
|
2023-07-10 07:28:45 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
#define GET_API(api) \
|
|
|
|
|
proc = (FARPROC*)&api; \
|
2023-07-11 03:20:11 +00:00
|
|
|
|
*proc = GetProcAddress(hui, #api); \
|
|
|
|
|
if(*proc == nullptr) \
|
|
|
|
|
utils::to_log(LOG_LEVEL_FATAL, "TWAINUI - function '%s' not found!\n", #api);
|
2023-07-10 07:28:45 +00:00
|
|
|
|
|
|
|
|
|
FARPROC* proc = nullptr;
|
|
|
|
|
|
|
|
|
|
GET_API(choose_scanner);
|
|
|
|
|
GET_API(apply_current_config);
|
|
|
|
|
GET_API(show_setting_ui);
|
|
|
|
|
GET_API(show_progress_ui);
|
|
|
|
|
GET_API(show_messagebox_ui);
|
|
|
|
|
GET_API(close_ui);
|
|
|
|
|
GET_API(twain_ui_free);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
static void unint_ui(void)
|
|
|
|
|
{
|
|
|
|
|
if (close_ui)
|
|
|
|
|
close_ui(UI_UNLOAD_MODULE);
|
|
|
|
|
choose_scanner = nullptr;
|
|
|
|
|
apply_current_config = nullptr;
|
|
|
|
|
show_setting_ui = nullptr;
|
|
|
|
|
show_progress_ui = nullptr;
|
|
|
|
|
show_messagebox_ui = nullptr;
|
|
|
|
|
close_ui = nullptr;
|
|
|
|
|
twain_ui_free = nullptr;
|
|
|
|
|
if (hui)
|
|
|
|
|
{
|
|
|
|
|
FreeLibrary(hui);
|
|
|
|
|
hui = nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-09-23 08:07:23 +00:00
|
|
|
|
static SANE_Bool get_invisible_fix_id(int id, void* param)
|
|
|
|
|
{
|
|
|
|
|
((std::vector<int>*)param)->push_back(id);
|
|
|
|
|
|
|
|
|
|
return SANE_TRUE;
|
|
|
|
|
}
|
2023-07-10 07:28:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// class scanner
|
2023-09-21 03:23:38 +00:00
|
|
|
|
scanner::scanner(const char* model) : handle_(nullptr), model_(model), ex_id_(EXTENSION_ID_BASE), prev_start_result_(SCANNER_ERR_NOT_START)
|
2023-09-22 08:26:22 +00:00
|
|
|
|
, dpi_(200), tmp_path_(""), img_ind_(0), err_(SCANNER_ERR_NOT_OPEN)
|
2023-07-10 07:28:45 +00:00
|
|
|
|
, scanner_name_(""), is_ui_wait_img_(false), is_scanning_(false)
|
|
|
|
|
, scanner_ev_handler_(nullptr), evh_param_(nullptr), app_wnd_(nullptr), 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<void(int, void*, int)>();
|
|
|
|
|
|
|
|
|
|
sane_api_.sane_cancel_api = sane_helper_->invoke_sane_cancel;
|
|
|
|
|
sane_api_.sane_close_api = sane_helper_->invoke_sane_close;
|
|
|
|
|
sane_api_.sane_control_option_api = sane_helper_->invoke_sane_control_option;
|
|
|
|
|
sane_api_.sane_get_devices_api = sane_helper_->invoke_sane_get_devices;
|
|
|
|
|
sane_api_.sane_get_option_descriptor_api = sane_helper_->invoke_sane_get_option_descriptor;
|
|
|
|
|
sane_api_.sane_get_parameters_api = sane_helper_->invoke_sane_get_parameters;
|
|
|
|
|
sane_api_.sane_get_select_fd_api = sane_helper_->invoke_sane_get_select_fd;
|
|
|
|
|
sane_api_.sane_io_control_api = nullptr;
|
|
|
|
|
sane_api_.sane_open_api = sane_helper_->invoke_sane_open;
|
|
|
|
|
sane_api_.sane_read_api = sane_helper_->invoke_sane_read;
|
|
|
|
|
sane_api_.sane_set_io_mode_api = sane_helper_->invoke_sane_set_io_mode;
|
|
|
|
|
sane_api_.sane_start_api = sane_helper_->invoke_sane_start;
|
|
|
|
|
sane_api_.sane_strstatus_api = sane_helper_->invoke_sane_strstatus;
|
|
|
|
|
|
|
|
|
|
tmp_path_ = utils::get_local_data_path() + PATH_SEPARATOR;
|
|
|
|
|
cfg_path_ = tmp_path_ + "config";
|
|
|
|
|
utils::create_folder(cfg_path_.c_str());
|
|
|
|
|
cfg_path_ += PATH_SEPARATOR;
|
|
|
|
|
tmp_path_ += "imgs";
|
|
|
|
|
utils::create_folder(tmp_path_.c_str());
|
|
|
|
|
tmp_path_ += PATH_SEPARATOR;
|
|
|
|
|
img_fmt_.img_format = SANE_IMAGE_TYPE_BMP;
|
|
|
|
|
img_fmt_.compress.compression = SANE_COMPRESSION_NONE;
|
|
|
|
|
|
|
|
|
|
int mem_limit = GetPrivateProfileIntA("mem", "max_img", 0, (cfg_path_ + "debug.cfg").c_str());
|
|
|
|
|
if (mem_limit > 0)
|
|
|
|
|
{
|
|
|
|
|
// this value is same as driver memory limit ...
|
|
|
|
|
max_img_mem_ = mem_limit;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
scanner::~scanner()
|
|
|
|
|
{
|
|
|
|
|
close();
|
|
|
|
|
if (thread_starting_.get() && thread_starting_->joinable())
|
|
|
|
|
thread_starting_->join();
|
|
|
|
|
thread_starting_.reset();
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-21 03:23:38 +00:00
|
|
|
|
void scanner::get_scanner_name(const char* model, std::vector<std::string>& names)
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
|
|
|
|
const SANE_Device **devs = nullptr;
|
|
|
|
|
int count = 0;
|
|
|
|
|
|
|
|
|
|
names.clear();
|
|
|
|
|
if (sane_helper_->invoke_sane_get_devices(&devs, SANE_TRUE) == SANE_STATUS_GOOD)
|
|
|
|
|
{
|
|
|
|
|
for(; devs[count]; ++count)
|
|
|
|
|
{
|
2023-09-21 03:23:38 +00:00
|
|
|
|
if (strcmp(devs[count]->model, model) == 0)
|
2023-07-20 09:10:31 +00:00
|
|
|
|
names.push_back(devs[count]->name);
|
2023-07-10 07:28:45 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
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::to_int(SANE_Int v)
|
|
|
|
|
{
|
|
|
|
|
return v;
|
|
|
|
|
}
|
2023-09-21 03:23:38 +00:00
|
|
|
|
double scanner::to_double(SANE_Fixed v)
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
2023-09-21 03:23:38 +00:00
|
|
|
|
return (double)SANE_UNFIX(v);
|
2023-07-10 07:28:45 +00:00
|
|
|
|
}
|
|
|
|
|
void 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)
|
|
|
|
|
{
|
|
|
|
|
const SANE_Option_Descriptor* desc = sane_helper_->invoke_sane_get_option_descriptor((SANE_Handle)param, sn);
|
|
|
|
|
|
|
|
|
|
if (desc)
|
|
|
|
|
return desc->type == SANE_TYPE_FIXED;
|
|
|
|
|
else
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2023-10-31 06:51:14 +00:00
|
|
|
|
void scanner::scan_done(void)
|
|
|
|
|
{
|
|
|
|
|
std::string msg(scan_msg_);
|
|
|
|
|
|
|
|
|
|
while (images_.count())
|
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
|
|
|
|
|
|
|
|
|
if (ui_notify)
|
|
|
|
|
ui_notify(SANE_EVENT_SCAN_FINISHED, &msg[0], err_);
|
|
|
|
|
else
|
|
|
|
|
is_scanning_ = false;
|
|
|
|
|
//else
|
|
|
|
|
//{
|
|
|
|
|
// if (err_)
|
|
|
|
|
// {
|
|
|
|
|
// if (callback::show_messagebox_ui)
|
|
|
|
|
// {
|
|
|
|
|
// callback::show_messagebox_ui(app_wnd_, SANE_EVENT_SCAN_FINISHED, (void*)&msg[0], 0);
|
|
|
|
|
// }
|
|
|
|
|
// else // windows message box ...
|
|
|
|
|
// {
|
|
|
|
|
// std::wstring text(local_trans::a2u(msg.c_str(), CP_UTF8));
|
|
|
|
|
// if (!IsWindow(app_wnd_))
|
|
|
|
|
// callback::bring_message_box_topmost(local_trans::lang_trans_between_hz936(CONST_STRING_ERROR).c_str());
|
|
|
|
|
// MessageBoxW(app_wnd_, text.c_str(), local_trans::lang_trans_between_hz936(CONST_STRING_ERROR).c_str(), MB_OK);
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// on_ui_event(SANE_EVENT_SCAN_FINISHED, (void*)SANE_EVENT_SCAN_FINISHED);
|
|
|
|
|
//}
|
|
|
|
|
// is_scanning_ = false;
|
|
|
|
|
}
|
2023-07-10 07:28:45 +00:00
|
|
|
|
|
|
|
|
|
int scanner::transfer_id(int id)
|
|
|
|
|
{
|
|
|
|
|
if (id > SANE_OPT_ID_BASE)
|
|
|
|
|
{
|
2023-09-21 03:23:38 +00:00
|
|
|
|
if (sane_opts_.count((sane_option_id)id) == 0)
|
2023-07-10 07:28:45 +00:00
|
|
|
|
id = -1;
|
|
|
|
|
else
|
2023-09-21 03:23:38 +00:00
|
|
|
|
id = sane_opts_[(sane_option_id)id].opt_sn;
|
2023-07-10 07:28:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return id;
|
|
|
|
|
}
|
|
|
|
|
void scanner::apply_config(void)
|
|
|
|
|
{
|
2023-10-20 07:21:17 +00:00
|
|
|
|
if (callback::apply_current_config)
|
|
|
|
|
{
|
|
|
|
|
char* cfg = callback::apply_current_config(scanner_name_.c_str(), handle_, &sane_api_);
|
|
|
|
|
if (cfg && callback::twain_ui_free)
|
|
|
|
|
callback::twain_ui_free(cfg);
|
|
|
|
|
}
|
2023-07-10 07:28:45 +00:00
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
else if (uev == SANE_EVENT_UI_CLOSE_NORMAL)
|
|
|
|
|
{
|
|
|
|
|
// scan complete
|
|
|
|
|
|
|
|
|
|
// FIX on 2023-05-30: restore scan finished status, whether close UI is up to APP
|
|
|
|
|
//is_scanning_ = is_show_setting_;
|
|
|
|
|
is_scanning_ = false;
|
|
|
|
|
ui_notify = std::function<void(int, void*, int)>();
|
|
|
|
|
}
|
|
|
|
|
else if (uev == SANE_EVENT_UI_CLOSE_CANCEL)
|
|
|
|
|
{
|
|
|
|
|
// scan cancelled
|
|
|
|
|
|
|
|
|
|
stop(); // nothing to do, the finishing work do in SANE_EVENT_SCAN_FINISHED
|
|
|
|
|
}
|
|
|
|
|
else if (uev == SANE_EVENT_SCAN_FINISHED)
|
|
|
|
|
{
|
|
|
|
|
// FIX on 2023-05-30: restore scan finished status, whether close UI is up to APP
|
|
|
|
|
//is_scanning_ = is_show_setting_;
|
|
|
|
|
is_scanning_ = false;
|
|
|
|
|
ui_notify = std::function<void(int, void*, int)>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int( * h)(int, void*) = scanner_ev_handler_;
|
|
|
|
|
if (h)
|
|
|
|
|
{
|
|
|
|
|
h(uev, evh_param_);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
events_.save(uev, sizeof(uev));
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
std::string scanner::choose_scanner(const std::vector<std::string>& scanners)
|
|
|
|
|
{
|
|
|
|
|
if (scanners.empty())
|
|
|
|
|
return "";
|
|
|
|
|
|
|
|
|
|
std::vector<DEVQUEUI> devs;
|
|
|
|
|
std::string sel("");
|
|
|
|
|
int id = 1;
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < scanners.size(); ++i)
|
|
|
|
|
{
|
|
|
|
|
SANE_Handle h = nullptr;
|
|
|
|
|
int ret = sane_helper_->invoke_sane_open(scanners[i].c_str(), &h);
|
|
|
|
|
|
|
|
|
|
if (h)
|
|
|
|
|
{
|
|
|
|
|
char sn[256] = {0};
|
|
|
|
|
SANE_Int len = sizeof(sn) - 1;
|
|
|
|
|
sane_helper_->invoke_sane_control_option(h, SANE_OPT_ID_DEVICE_SERIAL_NO, SANE_ACTION_GET_VALUE, sn, &len);
|
|
|
|
|
if (sn[0])
|
|
|
|
|
{
|
|
|
|
|
DEVQUEUI dev;
|
|
|
|
|
dev.id = id++;
|
|
|
|
|
dev.name = scanners[i];
|
|
|
|
|
dev.sn = sn;
|
|
|
|
|
devs.push_back(dev);
|
|
|
|
|
}
|
|
|
|
|
sane_helper_->invoke_sane_close(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(nullptr, devs);
|
|
|
|
|
//dlg.show(true, true);
|
|
|
|
|
//sel = dlg.get_selected_device();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return sel;
|
|
|
|
|
}
|
|
|
|
|
int scanner::open(void)
|
|
|
|
|
{
|
|
|
|
|
int ret = close();
|
|
|
|
|
std::vector<std::string> que;
|
|
|
|
|
std::string name("");
|
|
|
|
|
|
2023-09-21 03:23:38 +00:00
|
|
|
|
scanner::get_scanner_name(model_.c_str(), que);
|
2023-07-10 07:28:45 +00:00
|
|
|
|
|
2023-09-22 07:43:53 +00:00
|
|
|
|
init_options_id();
|
2023-07-10 07:28:45 +00:00
|
|
|
|
scanner_name_ = "";
|
|
|
|
|
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 = sane_helper_->invoke_sane_open(name.c_str(), &handle_);
|
|
|
|
|
if (ret == SANE_STATUS_GOOD)
|
|
|
|
|
{
|
|
|
|
|
size_t pid = -1;
|
|
|
|
|
|
|
|
|
|
callback::reg_callback(handle_, this);
|
|
|
|
|
scanner_name_ = name;
|
|
|
|
|
pid = scanner_name_.find(" - ");
|
|
|
|
|
if (pid == -1)
|
|
|
|
|
pid = scanner_name_.length();
|
|
|
|
|
ret = init_options_id();
|
|
|
|
|
apply_config();
|
|
|
|
|
img_fmt_.compress.compression = SANE_CompressionType::SANE_COMPRESSION_NONE;
|
|
|
|
|
img_fmt_.compress.detail = 0;
|
|
|
|
|
img_fmt_.img_format = SANE_IMAGE_TYPE_BMP;
|
|
|
|
|
img_fmt_.detail = 0;
|
|
|
|
|
|
|
|
|
|
// check roller life ...
|
|
|
|
|
SANE_Int cnt = 0, life = 0, after = 0;
|
|
|
|
|
if (sane_helper_->invoke_sane_control_option(handle_, SANE_OPT_ID_ROLLER_COUNT, SANE_ACTION_GET_VALUE, &cnt, &after) == SANE_STATUS_GOOD &&
|
|
|
|
|
sane_helper_->invoke_sane_control_option(handle_, SANE_OPT_ID_ROLLER_LIFE, SANE_ACTION_GET_VALUE, &life, &after) == SANE_STATUS_GOOD)
|
|
|
|
|
{
|
|
|
|
|
if (cnt >= life)
|
|
|
|
|
{
|
|
|
|
|
if (callback::show_messagebox_ui)
|
|
|
|
|
{
|
|
|
|
|
// 纸轮搓纸次数已超过设计使用范围,扫描过程中搓纸失败、歪斜、搓多张等异常频次可能会明显增多,请注意及时清洁、并联系设备供应商购买替换纸轮!
|
|
|
|
|
std::string roller_msg(local_trans::lang_trans_between_hz936("\347\272\270\350\275\256\346\220\223\347\272\270\346\254\241\346\225\260\345\267\262\350\266\205\350\277\207\350\256\276\350\256\241\344\275\277\347\224\250\350\214\203\345\233\264\357\274\214\346\211\253\346\217\217\350\277\207\347\250\213\344\270\255\346\220\223\347\272\270\345\244\261\350\264\245\343\200\201\346\255\252\346\226\234\343\200\201\346\220\223\345\244\232\345\274\240\347\255\211\345\274\202\345\270\270\351\242\221\346\254\241\345\217\257\350\203\275\344\274\232\346\230\216\346\230\276\345\242\236\345\244\232\357\274\214\350\257\267\346\263\250\346\204\217\345\217\212\346\227\266\346\270\205\346\264\201\343\200\201\345\271\266\350\201\224\347\263\273\350\256\276\345\244\207\344\276\233\345\272\224\345\225\206\350\264\255\344\271\260\346\233\277\346\215\242\347\272\270\350\275\256\357\274\201"));
|
|
|
|
|
app_wnd_ = callback::find_main_wnd();
|
|
|
|
|
callback::show_messagebox_ui(app_wnd_, ret, (void*)&roller_msg[0], 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (callback::show_messagebox_ui)
|
|
|
|
|
{
|
|
|
|
|
app_wnd_ = callback::find_main_wnd();
|
|
|
|
|
callback::show_messagebox_ui(app_wnd_, ret, (void*)sane_helper_->invoke_sane_strstatus((SANE_Status)ret), 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
int scanner::close(void)
|
|
|
|
|
{
|
2023-10-31 06:51:14 +00:00
|
|
|
|
images_.clear();
|
|
|
|
|
if (done_.get() && done_->joinable())
|
|
|
|
|
done_->join();
|
|
|
|
|
|
2023-07-10 07:28:45 +00:00
|
|
|
|
scanner_ev_handler_ = nullptr;
|
|
|
|
|
ui_hide();
|
|
|
|
|
callback::unreg_callback(this);
|
|
|
|
|
if (handle_)
|
|
|
|
|
{
|
|
|
|
|
sane_helper_->invoke_sane_close(handle_);
|
|
|
|
|
}
|
|
|
|
|
handle_ = nullptr;
|
|
|
|
|
ex_id_ = EXTENSION_ID_BASE;
|
|
|
|
|
|
|
|
|
|
return SCANNER_ERR_OK;
|
|
|
|
|
}
|
|
|
|
|
int scanner::init_options_id(void)
|
|
|
|
|
{
|
2023-09-21 03:23:38 +00:00
|
|
|
|
SANE_Int op_id = 0, fix_id = 0;
|
|
|
|
|
int ret = SCANNER_ERR_OK;
|
2023-07-10 07:28:45 +00:00
|
|
|
|
const SANE_Option_Descriptor* desc = nullptr;
|
2023-09-21 03:23:38 +00:00
|
|
|
|
|
|
|
|
|
sane_opts_.clear();
|
|
|
|
|
while ((desc = sane_helper_->invoke_sane_get_option_descriptor(handle_, ++op_id)))
|
|
|
|
|
{
|
|
|
|
|
fix_id = -1;
|
|
|
|
|
if (sane_helper_->invoke_sane_control_option(handle_, op_id, (SANE_Action)SANE_ACTION_GET_FIX_ID, &fix_id, nullptr)
|
|
|
|
|
== SANE_STATUS_GOOD)
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
2023-09-21 03:23:38 +00:00
|
|
|
|
SANEOPT opt;
|
|
|
|
|
opt.opt_sn = op_id;
|
|
|
|
|
if (desc->type == SANE_TYPE_BOOL) // bool to enumeration constraint
|
|
|
|
|
opt.limit = VAL_LIMIT_ENUM;
|
|
|
|
|
else
|
|
|
|
|
opt.limit = scanner::from_sane_constraint(desc->constraint_type);
|
|
|
|
|
opt.type = scanner::from_sane_type(desc->type);
|
|
|
|
|
opt.size = desc->size;
|
|
|
|
|
opt.cap = desc->cap;
|
|
|
|
|
sane_opts_[fix_id] = opt;
|
2023-07-10 07:28:45 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-23 08:07:23 +00:00
|
|
|
|
// invisible option in SANE
|
2023-11-01 07:12:11 +00:00
|
|
|
|
if(0)
|
2023-09-23 08:07:23 +00:00
|
|
|
|
{
|
|
|
|
|
std::vector<int> inv;
|
|
|
|
|
struct _fix_id_cb fcb;
|
|
|
|
|
|
|
|
|
|
fcb.cb = callback::get_invisible_fix_id;
|
|
|
|
|
fcb.param = &inv;
|
|
|
|
|
sane_helper_->invoke_sane_control_option(handle_, SANE_OPT_ID_BASE, (SANE_Action)SANE_ACTION_ENUM_INVISIBLE_FIX_ID, &fcb, nullptr);
|
|
|
|
|
for (auto& v : inv)
|
|
|
|
|
{
|
|
|
|
|
desc = sane_helper_->invoke_sane_get_option_descriptor(handle_, v);
|
|
|
|
|
if (desc)
|
|
|
|
|
{
|
|
|
|
|
SANEOPT opt;
|
|
|
|
|
opt.opt_sn = v;
|
|
|
|
|
if (desc->type == SANE_TYPE_BOOL) // bool to enumeration constraint
|
|
|
|
|
opt.limit = VAL_LIMIT_ENUM;
|
|
|
|
|
else
|
|
|
|
|
opt.limit = scanner::from_sane_constraint(desc->constraint_type);
|
|
|
|
|
opt.type = scanner::from_sane_type(desc->type);
|
|
|
|
|
opt.size = desc->size;
|
|
|
|
|
opt.cap = desc->cap;
|
|
|
|
|
sane_opts_[v] = opt;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-10 07:28:45 +00:00
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
char* scanner::get_opt_value(int id, int size, bool def_val)
|
|
|
|
|
{
|
|
|
|
|
char *buf = new char[size + 4];
|
|
|
|
|
SANE_Action act = def_val ? (SANE_Action)SANE_ACTION_GET_DEFAULT_VALUE : SANE_ACTION_GET_VALUE;
|
|
|
|
|
|
|
|
|
|
memset(buf, 0, size + 4);
|
|
|
|
|
if(sane_helper_->invoke_sane_control_option(handle_, id, act, buf, nullptr))
|
|
|
|
|
{
|
|
|
|
|
delete[] buf;
|
|
|
|
|
buf = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
|
}
|
|
|
|
|
bool scanner::get_opt_value(int id, void* buf, bool def_val)
|
|
|
|
|
{
|
|
|
|
|
SANE_Action act = def_val ? (SANE_Action)SANE_ACTION_GET_DEFAULT_VALUE : SANE_ACTION_GET_VALUE;
|
|
|
|
|
|
|
|
|
|
return sane_helper_->invoke_sane_control_option(handle_, id, act, buf, nullptr) == SANE_STATUS_GOOD;
|
|
|
|
|
}
|
|
|
|
|
int scanner::control_read_string(int io_code, std::string& val)
|
|
|
|
|
{
|
|
|
|
|
char buf[256] = {0};
|
|
|
|
|
int ret = SCANNER_ERR_OK, len = sizeof(buf) - 1;
|
|
|
|
|
|
|
|
|
|
if(io_code == IO_CTRL_CODE_GET_SERIAL)
|
|
|
|
|
io_code = SANE_OPT_ID_DEVICE_SERIAL_NO;
|
|
|
|
|
else
|
|
|
|
|
io_code = -1;
|
|
|
|
|
|
|
|
|
|
if(io_code == -1)
|
|
|
|
|
{
|
|
|
|
|
ret = SCANNER_ERR_DEVICE_NOT_SUPPORT;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ret = sane_helper_->invoke_sane_control_option(handle_, io_code, SANE_ACTION_GET_VALUE, buf, &len);
|
|
|
|
|
val = buf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool scanner::get_option_value_with_parent(int sn, set_opt_value setv, void* param) // return true if handled
|
|
|
|
|
{
|
|
|
|
|
bool handled = true;
|
|
|
|
|
|
2023-09-21 03:23:38 +00:00
|
|
|
|
if (sn == SANE_OPT_ID_SCAN_COUNT)
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
2023-09-21 03:23:38 +00:00
|
|
|
|
const SANE_Option_Descriptor* parent = sane_helper_->invoke_sane_get_option_descriptor(handle_, SANE_OPT_ID_SCAN_MODE);
|
|
|
|
|
char* buf = get_opt_value(SANE_OPT_ID_SCAN_MODE, parent->size, false);
|
2023-07-10 07:28:45 +00:00
|
|
|
|
|
2023-09-21 03:23:38 +00:00
|
|
|
|
if (buf)
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
2023-09-21 03:23:38 +00:00
|
|
|
|
handled = strcmp(local_trans::lang_trans_between_hz936(OPTION_VALUE_SMZS_LXSM, true, nullptr), buf) == 0;
|
|
|
|
|
if (handled)
|
|
|
|
|
{
|
|
|
|
|
int count = -1;
|
|
|
|
|
value_role role = VAL_ROLE_CURRENT;
|
|
|
|
|
sane_helper_->invoke_sane_control_option(handle_, SANE_OPT_ID_SCAN_MODE, (SANE_Action)SANE_ACTION_GET_DEFAULT_VALUE, buf, nullptr);
|
|
|
|
|
if (strcmp(local_trans::lang_trans_between_hz936(OPTION_VALUE_SMZS_LXSM, true, nullptr), buf) == 0)
|
|
|
|
|
role = value_role(role | VAL_ROLE_DEFAULT);
|
2023-07-10 07:28:45 +00:00
|
|
|
|
|
2023-09-21 03:23:38 +00:00
|
|
|
|
setv(&count, role, VAL_LIMIT_NONE, param);
|
|
|
|
|
}
|
|
|
|
|
delete[] buf;
|
2023-07-10 07:28:45 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
|
2023-09-21 03:23:38 +00:00
|
|
|
|
if (sn == SANE_OPT_ID_SCAN_COUNT)
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
2023-09-21 03:23:38 +00:00
|
|
|
|
const SANE_Option_Descriptor* parent = sane_helper_->invoke_sane_get_option_descriptor(handle_, SANE_OPT_ID_SCAN_MODE);
|
|
|
|
|
char* val = get_opt_value(SANE_OPT_ID_SCAN_MODE, parent->size, false);
|
2023-07-10 07:28:45 +00:00
|
|
|
|
SANE_Int after = 0;
|
|
|
|
|
|
|
|
|
|
if(val)
|
|
|
|
|
{
|
2023-09-21 03:23:38 +00:00
|
|
|
|
if (strcmp(local_trans::lang_trans_between_hz936(OPTION_VALUE_SMZS_LXSM, true, nullptr), val) == 0)
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
|
|
|
|
if (*(int*)data != -1)
|
|
|
|
|
{
|
|
|
|
|
strcpy(val, local_trans::lang_trans_between_hz936(OPTION_VALUE_SMZS_SMZDZS, true, nullptr));
|
2023-09-21 03:23:38 +00:00
|
|
|
|
*err = sane_helper_->invoke_sane_control_option(handle_, SANE_OPT_ID_SCAN_MODE, SANE_ACTION_SET_VALUE, val, &after);
|
2023-07-10 07:28:45 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (*(int*)data == -1)
|
|
|
|
|
{
|
|
|
|
|
strcpy(val, local_trans::lang_trans_between_hz936(OPTION_VALUE_SMZS_LXSM, true, nullptr));
|
2023-09-21 03:23:38 +00:00
|
|
|
|
*err = sane_helper_->invoke_sane_control_option(handle_, SANE_OPT_ID_SCAN_MODE, SANE_ACTION_SET_VALUE, val, &after);
|
2023-07-10 07:28:45 +00:00
|
|
|
|
}
|
|
|
|
|
delete[] val;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return handled;
|
|
|
|
|
}
|
|
|
|
|
int scanner::set_option_value(int sn, SANE_Value_Type type, int size, void* data)
|
|
|
|
|
{
|
|
|
|
|
char* buf = nullptr;
|
|
|
|
|
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);
|
2023-09-21 08:11:58 +00:00
|
|
|
|
//strcpy(buf, ((std::string*)data)->c_str());
|
|
|
|
|
strcpy(buf, (char*)data);
|
2023-07-10 07:28:45 +00:00
|
|
|
|
val = buf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = sane_helper_->invoke_sane_control_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 = (float)SANE_UNFIX(sf);
|
|
|
|
|
}
|
|
|
|
|
else if(buf)
|
|
|
|
|
{
|
|
|
|
|
strcpy((char*)val, buf);
|
|
|
|
|
delete[] buf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int scanner::thread_start(void)
|
|
|
|
|
{
|
2023-09-21 03:23:38 +00:00
|
|
|
|
SANE_Int dpi = 0;
|
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
|
|
sane_helper_->invoke_sane_control_option(handle_, SANE_OPT_ID_RESOLUTION, SANE_ACTION_GET_VALUE, &dpi, nullptr);
|
|
|
|
|
dpi_ = dpi;
|
|
|
|
|
utils::to_log(LOG_LEVEL_DEBUG, "start scanning with DPI %d\r\n", dpi_);
|
|
|
|
|
|
2023-11-10 06:38:12 +00:00
|
|
|
|
scan_working_ = false;
|
2023-09-21 03:23:38 +00:00
|
|
|
|
ret = sane_helper_->invoke_sane_start(handle_);
|
2023-07-10 07:28:45 +00:00
|
|
|
|
|
|
|
|
|
// the third-APPs in linux will call 'stop' after every start, but it not happens in windows-apps, so we handle this as following ...
|
2023-11-10 06:38:12 +00:00
|
|
|
|
// wait until at least ONE picture returned, so we need not this - 2023-11-07
|
|
|
|
|
//if (ret == SANE_STATUS_NO_DOCS && prev_start_result_ == SANE_STATUS_GOOD)
|
|
|
|
|
// ret = sane_helper_->invoke_sane_start(handle_);
|
2023-07-10 07:28:45 +00:00
|
|
|
|
|
2023-11-10 06:38:12 +00:00
|
|
|
|
if (ret == SANE_STATUS_GOOD || ret == SCANNER_ERR_DEVICE_DOUBLE_FEEDING)
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
|
|
|
|
/*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(sane_helper_->invoke_sane_strstatus((SANE_Status)ret), true);
|
|
|
|
|
//}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// display error message on progress UI, may be closed immediately by APP, so we hide progress UI and call message_box ...
|
|
|
|
|
//
|
|
|
|
|
#ifdef START_SCAN_IN_THREAD
|
2023-11-10 06:38:12 +00:00
|
|
|
|
if (callback::show_progress_ui && is_bIndicator && ui_notify)
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
|
|
|
|
int ev = SANE_EVENT_WORKING;
|
|
|
|
|
|
2023-11-10 06:38:12 +00:00
|
|
|
|
if (!scan_working_) // scan working thread would trigger the finish event, so here check this flag
|
|
|
|
|
{
|
|
|
|
|
ui_notify(SANE_EVENT_SCAN_FINISHED, (void*)sane_helper_->invoke_sane_strstatus((SANE_Status)ret), ret);
|
|
|
|
|
|
|
|
|
|
// block ?
|
|
|
|
|
while (!is_scanning_)
|
|
|
|
|
{
|
2023-11-10 06:58:17 +00:00
|
|
|
|
#ifdef WIN32
|
2023-11-10 06:38:12 +00:00
|
|
|
|
MSG msg = { 0 };
|
|
|
|
|
PeekMessageW(&msg, NULL, 0, 0, PM_NOREMOVE);
|
2023-11-10 06:58:17 +00:00
|
|
|
|
#else
|
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(3));
|
|
|
|
|
#endif
|
2023-11-10 06:38:12 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2023-07-10 07:28:45 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
#endif
|
|
|
|
|
{
|
|
|
|
|
if (callback::close_ui)
|
|
|
|
|
callback::close_ui(UI_INDICATOR);
|
|
|
|
|
|
|
|
|
|
if (callback::show_messagebox_ui)
|
|
|
|
|
{
|
|
|
|
|
callback::show_messagebox_ui(app_wnd_, ret, (void*)sane_helper_->invoke_sane_strstatus((SANE_Status)ret), 0);
|
|
|
|
|
}
|
|
|
|
|
// else
|
|
|
|
|
// {
|
|
|
|
|
// std::string msg(local_trans::a2u(sane_helper_->invoke_sane_strstatus((SANE_Status)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);
|
|
|
|
|
// }
|
|
|
|
|
is_scanning_ = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
prev_start_result_ = ret;
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-21 03:23:38 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// IRef
|
2023-10-20 07:21:17 +00:00
|
|
|
|
COM_API_IMPLEMENT(scanner, int32_t, add_ref(void))
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
2023-09-21 03:23:38 +00:00
|
|
|
|
return refer::add_ref();
|
2023-07-10 07:28:45 +00:00
|
|
|
|
}
|
2023-10-20 07:21:17 +00:00
|
|
|
|
COM_API_IMPLEMENT(scanner, int32_t, release(void))
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
2023-09-21 03:23:38 +00:00
|
|
|
|
return refer::release();
|
|
|
|
|
}
|
2023-07-10 07:28:45 +00:00
|
|
|
|
|
2023-09-21 03:23:38 +00:00
|
|
|
|
// ISaneInvoker
|
|
|
|
|
COM_API_IMPLEMENT(scanner, int, start(void))
|
|
|
|
|
{
|
|
|
|
|
int ret = SANE_STATUS_GOOD;
|
2023-07-10 07:28:45 +00:00
|
|
|
|
|
2023-09-21 03:23:38 +00:00
|
|
|
|
ev_cnt_ = 0;
|
|
|
|
|
events_.clear();
|
|
|
|
|
images_.clear();
|
|
|
|
|
scan_msg_ = "OK";
|
|
|
|
|
scan_err_ = false;
|
|
|
|
|
user_cancel_ = false;
|
|
|
|
|
fetch_imgs_ = 0;
|
|
|
|
|
is_scanning_ = true;
|
|
|
|
|
app_wnd_ = callback::find_main_wnd();
|
2023-07-10 07:28:45 +00:00
|
|
|
|
|
2023-09-21 03:23:38 +00:00
|
|
|
|
if (thread_starting_.get() && thread_starting_->joinable())
|
|
|
|
|
thread_starting_->join();
|
|
|
|
|
#ifdef START_SCAN_IN_THREAD
|
|
|
|
|
thread_starting_.reset(new std::thread(&scanner::thread_start, this));
|
|
|
|
|
#else
|
|
|
|
|
ret = thread_start();
|
|
|
|
|
#endif
|
2023-07-10 07:28:45 +00:00
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
2023-09-21 03:23:38 +00:00
|
|
|
|
COM_API_IMPLEMENT(scanner, int, stop(void))
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
2023-09-21 03:23:38 +00:00
|
|
|
|
user_cancel_ = true;
|
2023-07-10 07:28:45 +00:00
|
|
|
|
|
2023-09-21 03:23:38 +00:00
|
|
|
|
sane_helper_->invoke_sane_cancel(handle_);
|
2023-07-10 07:28:45 +00:00
|
|
|
|
|
2023-09-21 03:23:38 +00:00
|
|
|
|
return SANE_STATUS_GOOD;
|
|
|
|
|
}
|
|
|
|
|
COM_API_IMPLEMENT(scanner, int, get_event(void))
|
|
|
|
|
{
|
|
|
|
|
return events_.take();
|
|
|
|
|
}
|
|
|
|
|
COM_API_IMPLEMENT(scanner, void, set_event_callback(int(* 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);
|
2023-07-10 07:28:45 +00:00
|
|
|
|
|
2023-09-21 03:23:38 +00:00
|
|
|
|
return count > 0;
|
2023-07-10 07:28:45 +00:00
|
|
|
|
}
|
2023-09-21 03:23:38 +00:00
|
|
|
|
COM_API_IMPLEMENT(scanner, int, get_scanned_images(DWORD milliseconds))
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
2023-09-21 03:23:38 +00:00
|
|
|
|
size_t count = images_.count();
|
|
|
|
|
DWORD elapse = 2;
|
2023-07-10 07:28:45 +00:00
|
|
|
|
|
2023-09-21 03:23:38 +00:00
|
|
|
|
is_ui_wait_img_ = true;
|
|
|
|
|
while (is_scanning_ && count == 0 && milliseconds)
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
2023-09-21 03:23:38 +00:00
|
|
|
|
// MSG msg = { 0 };
|
|
|
|
|
// if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
|
|
|
|
|
// {
|
|
|
|
|
// TranslateMessage(&msg);
|
|
|
|
|
// DispatchMessageW(&msg);
|
|
|
|
|
// }
|
|
|
|
|
// else
|
|
|
|
|
Sleep(elapse);
|
2023-07-10 07:28:45 +00:00
|
|
|
|
|
2023-09-21 03:23:38 +00:00
|
|
|
|
count = images_.count();
|
2023-07-10 07:28:45 +00:00
|
|
|
|
|
2023-09-21 03:23:38 +00:00
|
|
|
|
//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)
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
2023-09-21 03:23:38 +00:00
|
|
|
|
if (milliseconds <= elapse)
|
|
|
|
|
break;
|
2023-07-10 07:28:45 +00:00
|
|
|
|
|
2023-09-21 03:23:38 +00:00
|
|
|
|
milliseconds -= elapse;
|
2023-07-10 07:28:45 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2023-09-21 03:23:38 +00:00
|
|
|
|
is_ui_wait_img_ = false;
|
|
|
|
|
count = images_.count();
|
2023-07-10 07:28:45 +00:00
|
|
|
|
|
2023-09-21 03:23:38 +00:00
|
|
|
|
{
|
|
|
|
|
char msg[128] = { 0 };
|
|
|
|
|
sprintf_s(msg, _countof(msg) - 1, "Wait image count = %d\r\n", count);
|
|
|
|
|
utils::log_info(msg, (log_level)1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return count;
|
2023-07-10 07:28:45 +00:00
|
|
|
|
}
|
2023-09-21 03:23:38 +00:00
|
|
|
|
COM_API_IMPLEMENT(scanner, IScanImg*, take_first_image(twain_xfer xfer))
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
2023-09-21 03:23:38 +00:00
|
|
|
|
scanned_img* img = images_.take(false);
|
2023-07-10 07:28:45 +00:00
|
|
|
|
|
2023-09-21 03:23:38 +00:00
|
|
|
|
if (img)
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
2023-09-21 03:23:38 +00:00
|
|
|
|
img->prepare_data_for_transfer(xfer);
|
|
|
|
|
img->add_ref();
|
2023-07-10 07:28:45 +00:00
|
|
|
|
|
2023-09-21 03:23:38 +00:00
|
|
|
|
utils::to_log(LOG_LEVEL_DEBUG, "Begin transferring image %d of %p\r\n", fetch_imgs_ + 1, img);
|
|
|
|
|
}
|
2023-08-03 01:50:51 +00:00
|
|
|
|
|
2023-07-10 07:28:45 +00:00
|
|
|
|
return dynamic_cast<IScanImg*>(img);
|
|
|
|
|
}
|
|
|
|
|
COM_API_IMPLEMENT(scanner, bool, get_first_image_header(SANE_Parameters* header, size_t* bytes, int* dpi))
|
|
|
|
|
{
|
|
|
|
|
return images_.get_header(header, bytes, dpi);
|
|
|
|
|
}
|
2023-08-04 05:13:36 +00:00
|
|
|
|
COM_API_IMPLEMENT(scanner, bool, discard_first_image(void))
|
|
|
|
|
{
|
|
|
|
|
scanned_img* img = images_.take();
|
|
|
|
|
if (img)
|
|
|
|
|
{
|
|
|
|
|
img->release();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-07-10 07:28:45 +00:00
|
|
|
|
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 (get_opt_value(SANE_OPT_ID_PAPER_ON, &on, false) == SANE_STATUS_GOOD)
|
|
|
|
|
return on == SANE_TRUE;
|
|
|
|
|
else
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
COM_API_IMPLEMENT(scanner, int, last_error(void))
|
|
|
|
|
{
|
|
|
|
|
return err_;
|
|
|
|
|
}
|
|
|
|
|
COM_API_IMPLEMENT(scanner, int, image_fetched(IScanImg* tx))
|
|
|
|
|
{
|
|
|
|
|
fetch_imgs_++;
|
|
|
|
|
if (ui_notify)
|
|
|
|
|
ui_notify(SANE_EVENT_IMG_UPLOADED, nullptr, fetch_imgs_);
|
|
|
|
|
|
2023-08-03 01:50:51 +00:00
|
|
|
|
utils::to_log(LOG_LEVEL_DEBUG, "Transferring image %d of %p finished.\r\n", fetch_imgs_, tx);
|
|
|
|
|
|
2023-07-10 07:28:45 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-21 03:23:38 +00:00
|
|
|
|
COM_API_IMPLEMENT(scanner, bool, get_option_info(int sn, value_type* type, value_limit* limit, int* bytes, bool* readonly))
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
2023-09-21 03:23:38 +00:00
|
|
|
|
if (sane_opts_.count(sn))
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
|
|
|
|
if (type)
|
2023-09-21 03:23:38 +00:00
|
|
|
|
*type = sane_opts_[sn].type;
|
2023-07-10 07:28:45 +00:00
|
|
|
|
if (limit)
|
2023-09-21 03:23:38 +00:00
|
|
|
|
*limit = sane_opts_[sn].limit;
|
2023-07-10 07:28:45 +00:00
|
|
|
|
if (bytes)
|
2023-09-21 03:23:38 +00:00
|
|
|
|
*bytes = sane_opts_[sn].size;
|
|
|
|
|
if (readonly)
|
|
|
|
|
*readonly = IS_CAP_READONLY(sane_opts_[sn].cap);
|
2023-07-10 07:28:45 +00:00
|
|
|
|
|
2023-09-21 03:23:38 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return false;
|
2023-07-10 07:28:45 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
COM_API_IMPLEMENT(scanner, bool, get_value(int sn, set_opt_value setval, void* param))
|
|
|
|
|
{
|
2023-09-23 08:07:23 +00:00
|
|
|
|
const SANE_Option_Descriptor* desc = sane_helper_->invoke_sane_get_option_descriptor(handle_, sn);
|
|
|
|
|
if (desc)
|
|
|
|
|
utils::to_log(LOG_LEVEL_DEBUG, "get_value(0x%04X - %s) ...\r\n", sn, desc->name);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
utils::to_log(LOG_LEVEL_WARNING, "get_value(0x%04X, ...), but the option is not found !!!\r\n", sn);
|
|
|
|
|
|
|
|
|
|
return SCANNER_ERR_DEVICE_NOT_SUPPORT;
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-21 03:23:38 +00:00
|
|
|
|
if (get_option_value_with_parent(sn, setval, param))
|
|
|
|
|
return true;
|
2023-07-10 07:28:45 +00:00
|
|
|
|
|
2023-09-21 03:23:38 +00:00
|
|
|
|
char* init = get_opt_value(sn, desc->size, true),
|
|
|
|
|
* now = get_opt_value(sn, desc->size, false);
|
|
|
|
|
int ret = SANE_STATUS_GOOD;
|
2023-07-10 07:28:45 +00:00
|
|
|
|
|
2023-09-21 03:23:38 +00:00
|
|
|
|
if (desc->type == SANE_TYPE_BOOL)
|
|
|
|
|
{
|
|
|
|
|
bool val = false;
|
|
|
|
|
int role = VAL_ROLE_NONE;
|
2023-07-10 07:28:45 +00:00
|
|
|
|
|
2023-09-21 03:23:38 +00:00
|
|
|
|
if (*(SANE_Bool*)init == SANE_FALSE)
|
|
|
|
|
role |= VAL_ROLE_DEFAULT;
|
|
|
|
|
if (*(SANE_Bool*)now == SANE_FALSE)
|
|
|
|
|
role |= VAL_ROLE_CURRENT;
|
|
|
|
|
setval(&val, (value_role)role, VAL_LIMIT_ENUM, param);
|
2023-07-10 07:28:45 +00:00
|
|
|
|
|
2023-09-21 03:23:38 +00:00
|
|
|
|
val = true;
|
|
|
|
|
role = VAL_ROLE_NONE;
|
|
|
|
|
if (*(SANE_Bool*)init == SANE_TRUE)
|
|
|
|
|
role |= VAL_ROLE_DEFAULT;
|
|
|
|
|
if (*(SANE_Bool*)now == SANE_TRUE)
|
|
|
|
|
role |= VAL_ROLE_CURRENT;
|
|
|
|
|
setval(&val, (value_role)role, VAL_LIMIT_ENUM, param);
|
|
|
|
|
}
|
|
|
|
|
else if (desc->type == SANE_TYPE_INT)
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
2023-09-21 03:23:38 +00:00
|
|
|
|
do
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
2023-09-21 03:23:38 +00:00
|
|
|
|
if (desc->constraint_type == SANE_CONSTRAINT_RANGE)
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
2023-09-21 03:23:38 +00:00
|
|
|
|
set_value_range<SANE_Int, int>(*(SANE_Int*)now, *(SANE_Int*)init, desc->constraint.range->min, desc->constraint.range->max, desc->constraint.range->quant, setval, param, scanner::to_int);
|
2023-07-10 07:28:45 +00:00
|
|
|
|
}
|
2023-09-21 03:23:38 +00:00
|
|
|
|
else if (desc->constraint_type == SANE_CONSTRAINT_WORD_LIST)
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
2023-09-21 03:23:38 +00:00
|
|
|
|
const SANE_Word* v = desc->constraint.word_list;
|
|
|
|
|
for (int i = 0; i < v[0]; ++i)
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
2023-09-21 03:23:38 +00:00
|
|
|
|
value_role role = VAL_ROLE_NONE;
|
|
|
|
|
if (v[i + 1] == *(SANE_Int*)now)
|
|
|
|
|
role = value_role(role | VAL_ROLE_CURRENT);
|
|
|
|
|
if (v[i + 1] == *(SANE_Int*)init)
|
|
|
|
|
role = value_role(role | VAL_ROLE_DEFAULT);
|
|
|
|
|
int val = v[i + 1];
|
|
|
|
|
if (!setval(&val, role, VAL_LIMIT_ENUM, param))
|
|
|
|
|
break;
|
2023-07-10 07:28:45 +00:00
|
|
|
|
}
|
2023-09-21 03:23:38 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
set_cur_and_def_value<int>(*(SANE_Int*)now, *(SANE_Int*)init, setval, param);
|
|
|
|
|
}while (0);
|
|
|
|
|
}
|
|
|
|
|
else if (desc->type == SANE_TYPE_FIXED)
|
|
|
|
|
{
|
|
|
|
|
do
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
2023-09-21 03:23:38 +00:00
|
|
|
|
if (desc->constraint_type == SANE_CONSTRAINT_RANGE)
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
2023-09-21 03:23:38 +00:00
|
|
|
|
set_value_range<SANE_Fixed, double>(*(SANE_Fixed*)now, *(SANE_Fixed*)init, desc->constraint.range->min, desc->constraint.range->max, desc->constraint.range->quant, setval, param, scanner::to_double);
|
|
|
|
|
}
|
|
|
|
|
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)
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
2023-09-21 03:23:38 +00:00
|
|
|
|
value_role role = VAL_ROLE_NONE;
|
|
|
|
|
if (v[i + 1] == *(SANE_Fixed*)now)
|
|
|
|
|
role = value_role(role | VAL_ROLE_CURRENT);
|
|
|
|
|
if (v[i + 1] == *(SANE_Fixed*)init)
|
|
|
|
|
role = value_role(role | VAL_ROLE_DEFAULT);
|
|
|
|
|
double val = SANE_UNFIX(v[i + 1]);
|
|
|
|
|
if (!setval(&val, role, VAL_LIMIT_ENUM, param))
|
|
|
|
|
break;
|
2023-07-10 07:28:45 +00:00
|
|
|
|
}
|
2023-09-21 03:23:38 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
set_cur_and_def_value<double>(SANE_UNFIX(*(SANE_Int*)now), SANE_UNFIX(*(SANE_Int*)init), setval, param);
|
|
|
|
|
} while (0);
|
|
|
|
|
}
|
|
|
|
|
else if (desc->type == SANE_TYPE_STRING)
|
|
|
|
|
{
|
|
|
|
|
do
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
2023-09-21 03:23:38 +00:00
|
|
|
|
if (desc->constraint_type == SANE_CONSTRAINT_STRING_LIST)
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
2023-09-21 03:23:38 +00:00
|
|
|
|
for (int i = 0; desc->constraint.string_list[i]; ++i)
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
2023-09-21 03:23:38 +00:00
|
|
|
|
value_role role = VAL_ROLE_NONE;
|
|
|
|
|
if (strcmp(desc->constraint.string_list[i], now) == 0)
|
|
|
|
|
role = value_role(role | VAL_ROLE_CURRENT);
|
|
|
|
|
if (strcmp(desc->constraint.string_list[i], init) == 0)
|
|
|
|
|
role = value_role(role | VAL_ROLE_DEFAULT);
|
|
|
|
|
|
|
|
|
|
std::string val(desc->constraint.string_list[i]);
|
|
|
|
|
if (!setval(&val, role, VAL_LIMIT_ENUM, param))
|
|
|
|
|
break;
|
2023-07-10 07:28:45 +00:00
|
|
|
|
}
|
2023-09-21 03:23:38 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
set_cur_and_def_value<std::string>(now, init, setval, param);
|
|
|
|
|
} while (0);
|
2023-07-10 07:28:45 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2023-09-21 03:23:38 +00:00
|
|
|
|
ret = SANE_STATUS_INVAL;
|
2023-07-10 07:28:45 +00:00
|
|
|
|
}
|
2023-09-21 03:23:38 +00:00
|
|
|
|
delete[] init;
|
|
|
|
|
delete[] now;
|
|
|
|
|
|
2023-07-10 07:28:45 +00:00
|
|
|
|
|
|
|
|
|
return ret == SANE_STATUS_GOOD;
|
|
|
|
|
}
|
|
|
|
|
COM_API_IMPLEMENT(scanner, bool, get_value(int sn, void* data, int* len))
|
|
|
|
|
{
|
|
|
|
|
return sane_helper_->invoke_sane_control_option(handle_, sn, SANE_ACTION_GET_VALUE, data, nullptr) == SANE_STATUS_GOOD;
|
|
|
|
|
}
|
|
|
|
|
COM_API_IMPLEMENT(scanner, int, set_value(int sn, void* val))
|
|
|
|
|
{
|
|
|
|
|
int ret = SANE_STATUS_INVAL;
|
|
|
|
|
SANE_Int after = 0;
|
|
|
|
|
const SANE_Option_Descriptor* desc = sane_helper_->invoke_sane_get_option_descriptor(handle_, sn);
|
|
|
|
|
|
2023-09-23 08:07:23 +00:00
|
|
|
|
if (desc)
|
2023-09-21 03:23:38 +00:00
|
|
|
|
utils::to_log(LOG_LEVEL_DEBUG, "set_value(0x%04X - %s, '%s') ...\r\n", sn, desc->name, callback::option_value_2_string(desc->type, val).c_str());
|
2023-09-23 08:07:23 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
utils::to_log(LOG_LEVEL_WARNING, "set_value(0x%04X, ...), but the option is not found !!!\r\n", sn);
|
2023-07-10 07:28:45 +00:00
|
|
|
|
|
2023-09-23 08:07:23 +00:00
|
|
|
|
return SCANNER_ERR_DEVICE_NOT_SUPPORT;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-10 07:28:45 +00:00
|
|
|
|
twain_set_ = true;
|
2023-09-21 03:23:38 +00:00
|
|
|
|
if (!set_option_value_with_parent(sn, val, &ret))
|
|
|
|
|
ret = set_option_value(sn, desc->type, desc->size, val);
|
2023-07-10 07:28:45 +00:00
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
COM_API_IMPLEMENT(scanner, int, convert_image(SANE_ImageFormatConvert* conv))
|
|
|
|
|
{
|
|
|
|
|
return sane_helper_->invoke_sane_control_option(handle_, SANE_OPT_ID_TRANSFORM_IMAGE_FORMAT, SANE_ACTION_SET_VALUE, conv, nullptr);
|
|
|
|
|
}
|
2023-09-23 08:07:23 +00:00
|
|
|
|
COM_API_IMPLEMENT(scanner, int, get_fixed_ids(SANE_Bool(* cb)(int id, void* param), void* param))
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
2023-09-23 08:07:23 +00:00
|
|
|
|
bool stopped = false;
|
|
|
|
|
|
2023-09-21 03:23:38 +00:00
|
|
|
|
for (auto& v : sane_opts_)
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
2023-09-21 03:23:38 +00:00
|
|
|
|
if (!cb(v.first, param))
|
2023-09-23 08:07:23 +00:00
|
|
|
|
{
|
|
|
|
|
stopped = true;
|
2023-09-21 03:23:38 +00:00
|
|
|
|
break;
|
2023-09-23 08:07:23 +00:00
|
|
|
|
}
|
2023-07-10 07:28:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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))
|
|
|
|
|
{
|
|
|
|
|
return SCANNER_ERR_DEVICE_NOT_SUPPORT;
|
|
|
|
|
}
|
|
|
|
|
COM_API_IMPLEMENT(scanner, int, twain_set_config(char* buf, size_t len))
|
|
|
|
|
{
|
|
|
|
|
return SCANNER_ERR_DEVICE_NOT_SUPPORT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ui ...
|
|
|
|
|
COM_API_IMPLEMENT(scanner, bool, ui_show_setting(HWND parent, bool with_scan, bool indicator))
|
|
|
|
|
{
|
2023-09-21 03:23:38 +00:00
|
|
|
|
bool ret = false;
|
|
|
|
|
|
|
|
|
|
utils::to_log(LOG_LEVEL_ALL, "ui_show_setting(%p, '%s', '%s'), api = %p\r\n", parent, with_scan ? "with scan" : "only ui", indicator ? "has indicator" : "no indicator", callback::show_setting_ui);
|
|
|
|
|
|
2023-07-10 07:28:45 +00:00
|
|
|
|
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, nullptr);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
};
|
2023-09-21 03:23:38 +00:00
|
|
|
|
ret = callback::show_setting_ui(handle_, parent, &sane_api_, scanner_name_.c_str(), with_scan, ui) == ui_result::UI_RESULT_OK;
|
2023-07-10 07:28:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-09-21 03:23:38 +00:00
|
|
|
|
return ret;
|
2023-07-10 07:28:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
COM_API_IMPLEMENT(scanner, bool, ui_show_progress(HWND parent, bool bIndicator))
|
|
|
|
|
{
|
|
|
|
|
is_bIndicator = bIndicator;
|
|
|
|
|
ui_notify = std::function<void(int, void*, int)>();
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
COM_API_IMPLEMENT(scanner, void, ui_hide(void))
|
|
|
|
|
{
|
|
|
|
|
if (callback::close_ui)
|
|
|
|
|
callback::close_ui(UI_INDICATOR | UI_SETTING | UI_MSG_BOX);
|
|
|
|
|
is_show_setting_ = false;
|
|
|
|
|
ui_notify = std::function<void(int, void*, int)>();
|
|
|
|
|
}
|
|
|
|
|
COM_API_IMPLEMENT(scanner, bool, ui_is_ok(void))
|
|
|
|
|
{
|
2023-07-18 06:13:43 +00:00
|
|
|
|
return callback::show_setting_ui != nullptr;
|
2023-07-10 07:28:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// called from device-layer ...
|
|
|
|
|
int scanner::handle_device_event(int ev_code, void* data, unsigned int* len)
|
|
|
|
|
{
|
|
|
|
|
if (ev_code == SANE_EVENT_WORKING)
|
|
|
|
|
{
|
2023-11-10 06:38:12 +00:00
|
|
|
|
scan_working_ = true;
|
2023-07-10 07:28:45 +00:00
|
|
|
|
img_ind_ = 0;
|
|
|
|
|
if (callback::show_progress_ui && is_bIndicator)
|
|
|
|
|
ui_notify(ev_code, data, *len);
|
|
|
|
|
on_ui_event(ev_code, (void*)ev_code);
|
2023-07-11 09:13:28 +00:00
|
|
|
|
utils::log_info("Scanning ...\r\n", LOG_LEVEL_DEBUG);
|
2023-07-10 07:28:45 +00:00
|
|
|
|
}
|
|
|
|
|
else if (ev_code == SANE_EVENT_IMAGE_OK)
|
|
|
|
|
{
|
|
|
|
|
SANE_Image* simg = (SANE_Image*)data;
|
|
|
|
|
scanned_img* img = nullptr;
|
|
|
|
|
char name[40] = { 0 };
|
|
|
|
|
|
|
|
|
|
sprintf_s(name, _countof(name) - 1, "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)
|
2023-07-11 09:13:28 +00:00
|
|
|
|
utils::log_info("Memory usage upto limit! wait up to 100 ms ...\r\n", LOG_LEVEL_DEBUG);
|
2023-07-10 07:28:45 +00:00
|
|
|
|
}
|
|
|
|
|
images_.save(img, img->bytes());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
img->release();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ui_notify)
|
|
|
|
|
ui_notify(ev_code, data, img_ind_);
|
|
|
|
|
|
2023-10-31 06:51:14 +00:00
|
|
|
|
// notifyXferReady 改为有图片才通知,防止部分APP在imgGetInfo中返回错误不能退出的问题 - 22023-10-25
|
|
|
|
|
if (img_ind_ == 1)
|
|
|
|
|
on_ui_event(SANE_EVENT_TWAIN_XFER_READY, nullptr);
|
|
|
|
|
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
|
|
|
|
char msg[128] = { 0 };
|
|
|
|
|
sprintf_s(msg, _countof(msg) - 1, "New image(%u) received with %u bytes\r\n", img_ind_, simg->bytes);
|
2023-07-11 09:13:28 +00:00
|
|
|
|
utils::log_info(msg, (log_level)1);
|
2023-07-10 07:28:45 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
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;
|
2023-10-31 06:51:14 +00:00
|
|
|
|
scan_msg_ = data ? (char*)data : "OK";
|
|
|
|
|
|
|
|
|
|
if (done_.get() && done_->joinable())
|
|
|
|
|
done_->join();
|
|
|
|
|
done_.reset(new std::thread(&scanner::scan_done, this));
|
2023-07-10 07:28:45 +00:00
|
|
|
|
// is_scanning_ = false;
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
char msg[128] = { 0 };
|
|
|
|
|
sprintf_s(msg, _countof(msg) - 1, "Scan finished with error: %u\r\n", *len);
|
2023-07-11 09:13:28 +00:00
|
|
|
|
utils::log_info(msg, (log_level)1);
|
2023-07-10 07:28:45 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
//else if (ev_code == SANE_EVENT_ERROR) // 屏蔽,在停止扫描时展示信息 - 2023-05-30
|
|
|
|
|
//{
|
|
|
|
|
// if (callback::show_messagebox_ui && *len)
|
|
|
|
|
// {
|
|
|
|
|
// callback::show_messagebox_ui(app_wnd_, ev_code, (void*)data, 0);
|
|
|
|
|
// }
|
|
|
|
|
// else if (*len) //错误弹出
|
|
|
|
|
// {
|
|
|
|
|
// std::string 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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// exports
|
|
|
|
|
extern "C"
|
|
|
|
|
{
|
|
|
|
|
int initialize_sane(void* reserve)
|
|
|
|
|
{
|
|
|
|
|
SANE_Int ver = 0;
|
|
|
|
|
|
|
|
|
|
utils::init_log(LOG_TYPE_FILE, LOG_LEVEL_ALL, "_twain");
|
|
|
|
|
sane_helper_ = new sane_helper();
|
2023-10-20 07:21:17 +00:00
|
|
|
|
if(!sane_helper_->load_sane(OEM_SHORT_NAME_E))
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
|
|
|
|
delete sane_helper_;
|
|
|
|
|
sane_helper_ = nullptr;
|
|
|
|
|
|
|
|
|
|
return SCANNER_ERR_NOT_OPEN;
|
|
|
|
|
}
|
|
|
|
|
callback::init_ui();
|
|
|
|
|
|
|
|
|
|
if (sane_helper_->invoke_sane_init_ex(&ver, callback::sane_event_callback, nullptr) == SANE_STATUS_GOOD)
|
|
|
|
|
{
|
2023-10-20 07:21:17 +00:00
|
|
|
|
std::string lang(utils::get_module_full_path(MODULE_NAME_SCANNER));
|
2023-07-10 07:28:45 +00:00
|
|
|
|
size_t pos = lang.rfind(PATH_SEPARATOR[0]);
|
|
|
|
|
if(pos++ == std::string::npos)
|
|
|
|
|
pos = 0;
|
|
|
|
|
lang.erase(pos);
|
2023-10-20 07:21:17 +00:00
|
|
|
|
lang += MODULE_NAME_LANG;
|
2023-07-10 07:28:45 +00:00
|
|
|
|
pos = local_trans::load_lang_pak(lang.c_str());
|
|
|
|
|
utils::to_log(LOG_LEVEL_WARNING, "load language component (%s) = %s\n", lang.c_str(), strerror(pos));
|
|
|
|
|
|
|
|
|
|
return SANE_STATUS_GOOD;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return SCANNER_ERR_LANG_PAK_LOST;
|
|
|
|
|
}
|
2023-09-21 03:23:38 +00:00
|
|
|
|
bool is_scanner_online(const char* model)
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
2023-09-21 03:23:38 +00:00
|
|
|
|
std::vector<std::string> que;
|
2023-07-10 07:28:45 +00:00
|
|
|
|
|
2023-09-21 03:23:38 +00:00
|
|
|
|
scanner::get_scanner_name(model, que);
|
|
|
|
|
|
|
|
|
|
return !que.empty();
|
|
|
|
|
}
|
2023-09-22 08:26:22 +00:00
|
|
|
|
ISaneInvoker* open_scanner(const char* model, int* err)
|
2023-09-21 03:23:38 +00:00
|
|
|
|
{
|
|
|
|
|
if (!sane_helper_)
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
2023-09-21 03:23:38 +00:00
|
|
|
|
int rv = initialize_sane(nullptr);
|
|
|
|
|
if (rv)
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
2023-09-21 03:23:38 +00:00
|
|
|
|
if (err)
|
|
|
|
|
*err = rv;
|
2023-07-10 07:28:45 +00:00
|
|
|
|
|
2023-09-21 03:23:38 +00:00
|
|
|
|
return nullptr;
|
2023-07-10 07:28:45 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-21 03:23:38 +00:00
|
|
|
|
scanner* s = new scanner(model);
|
2023-09-22 08:26:22 +00:00
|
|
|
|
int ret = s->open(), cnt = 0;
|
2023-07-10 07:28:45 +00:00
|
|
|
|
|
2023-09-22 08:26:22 +00:00
|
|
|
|
while (ret)
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
2023-09-22 08:26:22 +00:00
|
|
|
|
if (ret == SCANNER_ERR_OPENED_BY_OTHER_PROCESS)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
|
|
|
|
if (cnt++ > 100)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
ret = s->open();
|
|
|
|
|
}
|
|
|
|
|
if (ret && ret != SCANNER_ERR_OPENED_BY_OTHER_PROCESS) // error SCANNER_ERR_OPENED_BY_OTHER_PROCESS has tipped already
|
|
|
|
|
{
|
|
|
|
|
HWND parent = callback::find_main_wnd();
|
|
|
|
|
std::string msg(local_trans::lang_trans_between_hz936("\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, nullptr)),
|
|
|
|
|
title(local_trans::lang_trans_between_hz936("\xE9\x94\x99\xE8\xAF\xAF", true, nullptr));
|
|
|
|
|
if (callback::show_messagebox_ui)
|
|
|
|
|
callback::show_messagebox_ui(parent, 0, &msg[0], ret);
|
2023-07-10 07:28:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-09-21 03:23:38 +00:00
|
|
|
|
if (err)
|
|
|
|
|
*err = ret;
|
2023-07-10 07:28:45 +00:00
|
|
|
|
|
2023-09-21 03:23:38 +00:00
|
|
|
|
return s ? dynamic_cast<ISaneInvoker*>(s) : nullptr;
|
2023-07-10 07:28:45 +00:00
|
|
|
|
}
|
|
|
|
|
int uninitialize_sane(void* reserve)
|
|
|
|
|
{
|
|
|
|
|
if(sane_helper_ && sane_helper_->invoke_sane_exit)
|
|
|
|
|
sane_helper_->invoke_sane_exit();
|
|
|
|
|
callback::unint_ui();
|
|
|
|
|
if(sane_helper_)
|
|
|
|
|
delete sane_helper_;
|
|
|
|
|
sane_helper_ = nullptr;
|
2023-09-22 09:10:39 +00:00
|
|
|
|
utils::uninit();
|
2023-07-10 07:28:45 +00:00
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|