tx-gxx-linux/pc/code_twain/sln/usb_tools/DlgScanner.cpp

1548 lines
42 KiB
C++
Raw Permalink Blame History

// DlgScanner.cpp: 实现文件
//
#include "pch.h"
#include "usb_tools.h"
#include "DlgScanner.h"
#include "afxdialogex.h"
#include <direct.h>
#include <file/file_util.h>
#define TIMER_ID_REFRESH_BULK 1001
#include <common/log_util.h>
#include <common/json/gb_json.h>
HMODULE g_my_inst;
namespace sane
{
#define ALIGN_INTEGER(v) ALIGN_INT(v, sizeof(int))
static std::vector<SANE_Option_Descriptor*> g_opts;
SANE_Option_Descriptor g_opt0;
namespace local_utility
{
void* acquire_memory(size_t bytes, const char* msg)
{
char* buf = new char[bytes];
memset(buf, 0, bytes);
return buf;
}
}
static void bzero(void* buf, size_t len)
{
memset(buf, 0, len);
}
SANE_Option_Descriptor* string_option_to_SANE_descriptor(const char* name, const char* title, const char* desc
, const std::vector<std::string>& values)
{
int bytes = sizeof(SANE_Option_Descriptor) + sizeof(char*);
SANE_Option_Descriptor* sod = NULL;
char* str = NULL, ** str_arr = NULL;
bytes += ALIGN_INTEGER(strlen(name) + 1);
bytes += ALIGN_INTEGER(strlen(title) + 1);
bytes += ALIGN_INTEGER(strlen(desc) + 1);
bytes += sizeof(SANE_Option_Descriptor);
bytes += sizeof(char*);
for (size_t i = 0; i < values.size(); ++i)
bytes += ALIGN_INTEGER(values[i].length() + 1);
bytes += sizeof(char*) * (values.size() + 1);
sod = (SANE_Option_Descriptor*)local_utility::acquire_memory(bytes, "string_option_to_SANE_descriptor");
bzero(sod, bytes);
str = (char*)sod;
str += sizeof(SANE_Option_Descriptor);
sod->name = str;
strcpy(str, name);
str += ALIGN_INTEGER(strlen(str) + 1);
sod->title = str;
strcpy(str, title);
str += ALIGN_INTEGER(strlen(str) + 1);
sod->desc = str;
strcpy(str, desc);
str += ALIGN_INTEGER(strlen(str) + 1);
sod->type = SANE_TYPE_STRING;
sod->unit = SANE_UNIT_NONE;
sod->size = values.size();
sod->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT // 软件可设置选项
| SANE_CAP_AUTOMATIC; // 硬件可设置默认<E9BB98>?
if (values.size())
{
sod->constraint_type = SANE_CONSTRAINT_STRING_LIST;
sod->constraint.string_list = (char**)str;
str_arr = (char**)str;
str += (values.size() + 1) * sizeof(char*);
for (size_t i = 0; i < values.size(); ++i)
{
str_arr[i] = str;
strcpy(str, values[i].c_str());
str += ALIGN_INTEGER(values[i].length() + 1);
}
}
//VLOG_MINI_2(LOG_LEVEL_ALL, "Memory usage: %u/%u\n", str - (char*)sod, bytes);
return sod;
}
SANE_Option_Descriptor* number_option_to_SANE_descriptor(const char* name, const char* title, const char* desc
, bool double_val, double* lower, double* upper, double* step)
{
int bytes = sizeof(SANE_Option_Descriptor) + sizeof(SANE_Range);
SANE_Option_Descriptor* sod = NULL;
char* str = NULL;
bytes += ALIGN_INTEGER(strlen(name) + 1);
bytes += ALIGN_INTEGER(strlen(title) + 1);
bytes += ALIGN_INTEGER(strlen(desc) + 1);
bytes += sizeof(SANE_Option_Descriptor);
bytes += sizeof(SANE_Range*) + sizeof(SANE_Range);
sod = (SANE_Option_Descriptor*)local_utility::acquire_memory(bytes, "number_option_to_SANE_descriptor");
bzero(sod, bytes);
str = (char*)sod;
str += sizeof(SANE_Option_Descriptor);
sod->name = str;
strcpy(str, name);
str += ALIGN_INTEGER(strlen(str) + 1);
sod->title = str;
strcpy(str, title);
str += ALIGN_INTEGER(strlen(str) + 1);
sod->desc = str;
strcpy(str, desc);
str += ALIGN_INTEGER(strlen(str) + 1);
sod->type = double_val ? SANE_TYPE_FIXED : SANE_TYPE_INT;
sod->unit = SANE_UNIT_NONE;
sod->size = sizeof(SANE_Word);
sod->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT
| SANE_CAP_AUTOMATIC;
if (lower || upper)
{
sod->size = sizeof(SANE_Range);
sod->constraint_type = SANE_CONSTRAINT_RANGE;
sod->constraint.range = (SANE_Range*)str;
if (lower)
{
if (double_val)
(*(SANE_Range*)str).min = SANE_FIX(*lower);
else
(*(SANE_Range*)str).min = (SANE_Word)*lower;
}
if (upper)
{
if (double_val)
(*(SANE_Range*)str).max = SANE_FIX(*upper);
else
(*(SANE_Range*)str).max = (SANE_Word)*upper;
}
(*(SANE_Range*)str).quant = 0;
if (step)
{
if (double_val)
(*(SANE_Range*)str).quant = SANE_FIX(*step);
else
(*(SANE_Range*)str).quant = (SANE_Word)(*step);
}
str = (char*)((SANE_Range*)str + 1);
}
//VLOG_MINI_2(LOG_LEVEL_ALL, "Memory usage: %u/%u\n", str - (char*)sod, bytes);
return sod;
}
SANE_Option_Descriptor* number_option_to_SANE_descriptor(const char* name, const char* title, const char* desc
, const std::vector<int>& values)
{
int bytes = sizeof(SANE_Option_Descriptor) + sizeof(SANE_Range);
SANE_Option_Descriptor* sod = NULL;
char* str = NULL;
bytes += ALIGN_INTEGER(strlen(name) + 1);
bytes += ALIGN_INTEGER(strlen(title) + 1);
bytes += ALIGN_INTEGER(strlen(desc) + 1);
bytes += sizeof(SANE_Option_Descriptor);
bytes += sizeof(SANE_Word*) + sizeof(SANE_Word) * (values.size() + 1);
sod = (SANE_Option_Descriptor*)local_utility::acquire_memory(bytes, "number_option_to_SANE_descriptor");
bzero(sod, bytes);
str = (char*)sod;
str += sizeof(SANE_Option_Descriptor);
sod->name = str;
strcpy(str, name);
str += ALIGN_INTEGER(strlen(str) + 1);
sod->title = str;
strcpy(str, title);
str += ALIGN_INTEGER(strlen(str) + 1);
sod->desc = str;
strcpy(str, desc);
str += ALIGN_INTEGER(strlen(str) + 1);
sod->type = SANE_TYPE_INT;
sod->unit = SANE_UNIT_NONE;
sod->size = sizeof(SANE_Word);
sod->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT // 软件可设置选项
| SANE_CAP_AUTOMATIC; // 硬件可设置默认<E9BB98>?
if (values.size())
{
SANE_Word* val = (SANE_Word*)str;
sod->constraint.word_list = val;
sod->constraint_type = SANE_CONSTRAINT_WORD_LIST;
*val++ = values.size();
for (size_t i = 0; i < values.size(); ++i)
val[i] = values[i];
str = (char*)(val + values.size());
}
//VLOG_MINI_2(LOG_LEVEL_ALL, "Memory usage: %u/%u\n", str - (char*)sod, bytes);
return sod;
}
SANE_Option_Descriptor* number_option_to_SANE_descriptor(const char* name, const char* title, const char* desc
, const std::vector<double>& values)
{
int bytes = sizeof(SANE_Option_Descriptor) + sizeof(SANE_Range);
SANE_Option_Descriptor* sod = NULL;
char* str = NULL;
bytes += ALIGN_INTEGER(strlen(name) + 1);
bytes += ALIGN_INTEGER(strlen(title) + 1);
bytes += ALIGN_INTEGER(strlen(desc) + 1);
bytes += sizeof(SANE_Option_Descriptor);
bytes += sizeof(SANE_Word*) + sizeof(SANE_Word) * (values.size() + 1);
sod = (SANE_Option_Descriptor*)local_utility::acquire_memory(bytes, "number_option_to_SANE_descriptor");
bzero(sod, bytes);
str = (char*)sod;
str += sizeof(SANE_Option_Descriptor);
sod->name = str;
strcpy(str, name);
str += ALIGN_INTEGER(strlen(str) + 1);
sod->title = str;
strcpy(str, title);
str += ALIGN_INTEGER(strlen(str) + 1);
sod->desc = str;
strcpy(str, desc);
str += ALIGN_INTEGER(strlen(str) + 1);
sod->type = SANE_TYPE_FIXED;
sod->unit = SANE_UNIT_NONE;
sod->size = sizeof(SANE_Word);
sod->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT // 软件可设置选项
| SANE_CAP_AUTOMATIC; // 硬件可设置默认<E9BB98>?
if (values.size())
{
SANE_Word* val = (SANE_Word*)str;
sod->constraint.word_list = val;
sod->constraint_type = SANE_CONSTRAINT_WORD_LIST;
*val++ = values.size();
for (size_t i = 0; i < values.size(); ++i)
val[i] = SANE_FIX(values[i]);
str = (char*)(val + values.size());
}
//VLOG_MINI_2(LOG_LEVEL_ALL, "Memory usage: %u/%u\n", str - (char*)sod, bytes);
return sod;
}
SANE_Option_Descriptor* trans_json_to_opt_desc(gb_json* jsn)
{
std::string title(""),
desc(""),
name(""),
val("");
std::vector<std::string> constraints;
double lower = .0f, upper = .0f, step = .0f;
bool db_val = false;
SANE_Option_Descriptor *ret = NULL;
jsn->get_value("title", title);
jsn->get_value("desc", desc);
name = jsn->key();
if (!jsn->get_value("type", val))
return NULL;
if (val == "string")
{
gb_json* range = NULL, * child = NULL;
jsn->get_value("range", range);
if (range)
{
child = range->first_child();
while (child)
{
if (child->value(val))
constraints.push_back(val);
child->release();
child = range->next_child();
}
range->release();
}
ret = string_option_to_SANE_descriptor(name.c_str(), title.c_str(), desc.c_str()
, constraints);
}
else if (val == "int" || val == "float")
{
gb_json* range = NULL;
jsn->get_value("range", range);
if (range)
{
if (val == "int")
{
int l = 0;
if (range->get_value("min", l))
{
int u = 0, s = 1;
range->get_value("max", u);
range->get_value("step", s);
lower = l;
upper = u;
step = s;
ret = number_option_to_SANE_descriptor(name.c_str(), title.c_str(), desc.c_str()
, false, &lower, &upper, &step);
}
else
{
std::vector<int> constraints;
gb_json* child = range->first_child();
while(child)
{
int val = 0;
if(child->value(val))
constraints.push_back(val);
child->release();
child = range->next_child();
}
ret = number_option_to_SANE_descriptor(name.c_str(), title.c_str(), desc.c_str()
, constraints);
}
}
else
{
if (range->get_value("min", lower))
{
range->get_value("max", upper);
step = (upper - lower) / 10.0f;
range->get_value("step", step);
ret = number_option_to_SANE_descriptor(name.c_str(), title.c_str(), desc.c_str()
, true, &lower, &upper, &step);
}
else
{
std::vector<double> constraints;
gb_json* child = range->first_child();
while(child)
{
double val = .0f;
if(child->value(val))
constraints.push_back(val);
child->release();
child = range->next_child();
}
ret = number_option_to_SANE_descriptor(name.c_str(), title.c_str(), desc.c_str()
, constraints);
}
}
range->release();
}
else
{
ret = number_option_to_SANE_descriptor(name.c_str(), title.c_str(), desc.c_str()
, false, NULL, NULL, NULL);
}
}
else if (val == "bool")
{
ret = number_option_to_SANE_descriptor(name.c_str(), title.c_str(), desc.c_str()
, false, NULL, NULL, NULL);
ret->type = SANE_TYPE_BOOL;
}
else if (val == "button")
{
ret = number_option_to_SANE_descriptor(name.c_str(), title.c_str(), desc.c_str()
, false, NULL, NULL, NULL);
ret->type = SANE_TYPE_BUTTON;
}
else if (val == "group")
{
ret = number_option_to_SANE_descriptor(name.c_str(), title.c_str(), desc.c_str()
, false, NULL, NULL, NULL);
ret->type = SANE_TYPE_GROUP;
}
// fill the 'size' field, for SANE_ACTION_GET action ...
if (ret)
{
int bytes = 0;
bool bv = false;
jsn->get_value("size", bytes);
ret->size = bytes;
if (jsn->get_value("readonly", bv) && bv)
SET_CAP_READONLY(ret->cap)
else if (jsn->get_value("hwonly", bv) && bv)
SET_CAP_DEVICE_SETTABLE(ret->cap, true)
val = "";
jsn->get_value("group", val);
if (val == "advance")
{
ret->cap |= SANE_CAP_ADVANCED;
}
val = "";
if (jsn->get_value("unit", val))
{
if (val == "DPI")
ret->unit = SANE_UNIT_DPI;
else if (val == "pixel")
ret->unit = SANE_UNIT_PIXEL;
else if (val == "mm")
ret->unit = SANE_UNIT_MM;
else if (val == "bit")
ret->unit = SANE_UNIT_BIT;
else if (val == "microsec")
ret->unit = SANE_UNIT_MICROSECOND;
else if (val == "%")
ret->unit = SANE_UNIT_PERCENT;
else
ret->unit = SANE_UNIT_NONE;
}
bool enabled = true;
if (jsn->get_value("enabled", enabled) && !enabled)
ret->cap |= SANE_CAP_INACTIVE;
// 关联<E585B3>?
gb_json* depend = NULL;
}
return ret;
}
void reset_opts(const char* json_txt)
{
for (auto& v : g_opts)
delete[] v;
g_opts.clear();
g_opt0.cap = CAPABILITY_READONLY;
g_opt0.name = "option-count";
g_opt0.title = "";
g_opt0.desc = "Number of options";
g_opt0.type = SANE_TYPE_INT;
g_opt0.size = sizeof(SANE_TYPE_INT);
if (json_txt)
{
gb_json* jsn = new gb_json(), * child = NULL;
if (jsn->attach_text((char*)json_txt))
{
child = jsn->first_child();
if (child)
{
child->release();
while ((child = jsn->next_child()))
{
SANE_Option_Descriptor* desc = trans_json_to_opt_desc(child);
if (desc)
g_opts.push_back(desc);
child->release();
}
}
}
jsn->release();
}
}
SANE_Status sane_get_devices_api(const SANE_Device*** device_list, SANE_Bool local_only)
{
return SANE_STATUS_INVAL;
}
SANE_Status sane_open_api(SANE_String_Const devicename, SANE_Handle* handle)
{
return SANE_STATUS_INVAL;
}
void sane_close_api(SANE_Handle handle)
{}
const SANE_Option_Descriptor* sane_get_option_descriptor_api(SANE_Handle handle, SANE_Int option)
{
if (option == 0)
return &g_opt0;
else if (option <= g_opts.size())
return g_opts[option - 1];
else
return NULL;
}
SANE_Status sane_control_option_api(SANE_Handle handle, SANE_Int option, SANE_Action action, void* value, SANE_Int* info)
{
CDlgScanner* dlg = (CDlgScanner*)handle;
if (action == SANE_ACTION_GET_VALUE && option > 0 && option <= g_opts.size())
{
if (g_opts[option - 1]->type == SANE_TYPE_FIXED)
{
double val = .0f;
dlg->get_option(g_opts[option - 1]->name, &val, sizeof(val));
*(SANE_Fixed*)value = SANE_FIX(val);
}
else
{
dlg->get_option(g_opts[option - 1]->name, value, g_opts[option - 1]->size);
}
return SANE_STATUS_GOOD;
}
else if(action == SANE_ACTION_SET_VALUE && option > 0 && option <= g_opts.size())
{
size_t val_size = 0;
double val = .0f;
void* buf = value;
if (g_opts[option - 1]->type == SANE_TYPE_BOOL)
val_size = sizeof(bool);
else if (g_opts[option - 1]->type == SANE_TYPE_INT)
val_size = sizeof(int);
else if (g_opts[option - 1]->type == SANE_TYPE_FIXED)
{
val_size = sizeof(val);
val = SANE_UNFIX(*(SANE_Int*)value);
buf = &val;
}
else
val_size = strlen((char*)value);
SANE_Int after = 0;
SANE_Status ret = (SANE_Status)dlg->set_option(g_opts[option - 1]->name, buf, g_opts[option - 1]->type, val_size, g_opts[option - 1]->size, (int*)&after);
if (info)
*info = after;
if (buf == &val)
{
*(SANE_Int*)value = SANE_FIX(val);
}
if (after & SANE_INFO_RELOAD_OPTIONS)
{
std::string str("");
if (dlg->get_all_option(str) == 0)
{
reset_opts(str.c_str());
}
}
return ret;
}
return SANE_STATUS_INVAL;
}
SANE_Status sane_get_parameters_api(SANE_Handle handle, SANE_Parameters* params)
{
return SANE_STATUS_INVAL;
}
SANE_Status sane_start_api(SANE_Handle handle)
{
return SANE_STATUS_INVAL;
}
SANE_Status sane_read_api(SANE_Handle handle, SANE_Byte* data, SANE_Int max_length, SANE_Int* length)
{
return SANE_STATUS_INVAL;
}
void sane_cancel_api(SANE_Handle handle)
{}
SANE_Status sane_set_io_mode_api(SANE_Handle handle, SANE_Bool non_blocking)
{
return SANE_STATUS_INVAL;
}
SANE_Status sane_get_select_fd_api(SANE_Handle handle, SANE_Int* fd)
{
return SANE_STATUS_INVAL;
}
SANE_String_Const sane_strstatus_api(SANE_Status status)
{
return "";
}
SANE_Status sane_io_control_api(SANE_Handle h, unsigned long code, void* data, unsigned* len)
{
return SANE_STATUS_INVAL;
}
SANE_Status sane_init_api(SANE_Int* version_code, SANE_Auth_Callback authorize)
{
return SANE_STATUS_INVAL;
}
void sane_exit_api(void)
{}
};
#define RETURN_EQUAL(v, e) \
if(v == e) \
return L###e;
template<typename ... Args>
static int msg_box(HWND owner, UINT type, const wchar_t* title, const wchar_t* fmt, Args ... args)
{
size_t size = _snwprintf(nullptr, 0, fmt, args ...) + 1;
std::unique_ptr<wchar_t[]> buf(new wchar_t[size]);
_snwprintf(buf.get(), size, fmt, args ...);
return ::MessageBoxW(owner, buf.get(), title, type);
}
const wchar_t* peer_bulk_status(int s, wchar_t unk[20])
{
RETURN_EQUAL(s, BULK_STATUS_NOT_START);
RETURN_EQUAL(s, BULK_STATUS_IDLE);
RETURN_EQUAL(s, BULK_STATUS_IO);
RETURN_EQUAL(s, BULK_STATUS_ERROR);
RETURN_EQUAL(s, BULK_STATUS_RESET);
swprintf_s(unk, 18, L"%x", s);
return unk;
}
const wchar_t* scanner_status(int s, wchar_t unk[20])
{
RETURN_EQUAL(s, SCANNER_STATUS_READY);
RETURN_EQUAL(s, SCANNER_STATUS_NOT_OPEN);
RETURN_EQUAL(s, SCANNER_STATUS_LOST_CONNECT);
RETURN_EQUAL(s, SCANNER_STATUS_RESET_BULK);
RETURN_EQUAL(s, SCANNER_STATUS_START_SCANNING);
RETURN_EQUAL(s, SCANNER_STATUS_SCANNING);
RETURN_EQUAL(s, SCANNER_STATUS_SCAN_FINISHED);
RETURN_EQUAL(s, SCANNER_STATUS_BUSY);
RETURN_EQUAL(s, SCANNER_STATUS_COVER_OPENNED);
RETURN_EQUAL(s, SCANNER_STATUS_COVER_CLOSED);
RETURN_EQUAL(s, SCANNER_STATUS_SLEEPING);
RETURN_EQUAL(s, SCANNER_STATUS_WAKED_UP);
RETURN_EQUAL(s, SCANNER_STATUS_COUNT_MODE);
RETURN_EQUAL(s, SCANNER_STATUS_DOUBLE_FEEDED);
RETURN_EQUAL(s, SCANNER_STATUS_PAPER_JAMMED);
RETURN_EQUAL(s, SCANNER_STATUS_PAPER_ASKEW);
RETURN_EQUAL(s, SCANNER_STATUS_FEED_FAILED);
RETURN_EQUAL(s, SCANNER_STATUS_NO_PAPER);
RETURN_EQUAL(s, SCANNER_STATUS_PAPER_ON);
RETURN_EQUAL(s, SCANNER_STATUS_STAPLE_ON);
RETURN_EQUAL(s, SCANNER_STATUS_SIZE_ERR);
RETURN_EQUAL(s, SCANNER_STATUS_DOGEAR);
RETURN_EQUAL(s, SCANNER_STATUS_CFG_CHANGED);
swprintf_s(unk, 18, L"0x%x", s);
return unk;
}
static DWORD thread_open_id_ = 0;
static safe_fifo<std::string> images_;
static DWORD WINAPI thread_open_image(void* lp)
{
while (1)
{
std::string file("");
if (images_.take(file, true))
{
if (file.empty())
break;
ShellExecuteA(NULL, "Open", file.c_str(), NULL, NULL, SW_SHOWNORMAL);
}
}
return 0;
MSG msg = { 0 };
BOOL ret = TRUE;
while ((ret = GetMessage(&msg, NULL, 0, 0)))
{
if ((DWORD)ret == -1)
break;
if (msg.message == WM_USER + 1001)
break;
if (msg.message == WM_USER + 1)
{
std::string* file = (std::string*)msg.lParam;
ShellExecuteA(NULL, "Open", file->c_str(), NULL, NULL, SW_SHOWNORMAL);
delete file;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
// CDlgScanner 对话框
IMPLEMENT_DYNAMIC(CDlgScanner, CDialogEx)
CDlgScanner::CDlgScanner(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_SCANNER, pParent)
, scanner_(NULL), auto_tx_file_(-1), auto_tx_(false)
, setting_ui_(NULL), img_cnt_(0), paper_cnt_(0), max_sent_(0), max_cmd_(0)
{
g_my_inst = GetModuleHandle(NULL);
threads_ = new thread_pool<CDlgScanner>(this);
parent_ = pParent ? pParent->m_hWnd : NULL;
auto_wait_ = CreateEvent(NULL, TRUE, FALSE, NULL);
HANDLE h = CreateThread(NULL, 0, thread_open_image, NULL, 0, &thread_open_id_);
CloseHandle(h);
std::string tj("{\"resolution\":{\"cat\":\"imgp\",\"group\":\"base\",\"title\":\"\\u5206\\u8fa8\\u7387\",\"desc\":\"\\u8bbe\\u7f6e\\u626b\\u63cf\\u56fe\\u50cf\\u7684\\u5206\\u8fa8\\u7387\",\"ver\":1,\"pos\":200,\"type\":\"int\",\"unit\":\"dpi\",\"affect\":6,\"readonly\":false,\"visible\":true,\"enabled\":true,\"size\":4,\"cur\":400,\"default\":200,\"range\":{\"min\":100,\"max\":600,\"step\":50}}}");
gb_json* jsn = new gb_json();
if (jsn->attach_text(&tj[0]))
{
gb_json* child = jsn->first_child();
if (child)
{
bool bv = false, r = false;
int nv = 0;
double dv = .0f;
std::string sv("");
r = child->get_value("cur", bv);
r = child->get_value("cur", nv);
r = child->get_value("cur", dv);
r = child->get_value("cur", sv);
child->release();
}
}
jsn->release();
}
CDlgScanner::~CDlgScanner()
{
::PostThreadMessage(thread_open_id_, WM_USER + 1001, 0, 0);
images_.save("", true);
if (scanner_)
{
scanner_->close();
scanner_->release();
}
}
void CDlgScanner::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
// DDX_Control(pDX, IDC_TAB_OPT, tab_opt_);
DDX_Control(pDX, IDC_TAB_OPER, tab_oper_);
DDX_Control(pDX, IDC_COMBO_BUF_SIZE, buf_);
}
typedef struct _prog_data
{
CDlgScanner* obj;
std::string file;
}PROGD, *LPPROGD;
void CDlgScanner::set_device(usb::LPUSBPNP pnp)
{
if (!pnp)
{
auto_tx_ = false;
SetEvent(auto_wait_);
}
((CButton*)GetDlgItem(IDC_CHECK_REPEAT))->SetCheck(BST_UNCHECKED);
KillTimer(TIMER_ID_REFRESH_BULK);
((CButton*)GetDlgItem(IDC_CHECK_AUTO))->SetCheck(BST_UNCHECKED);
enable_buttons(pnp != NULL);
if (scanner_)
{
scanner_->close();
scanner_->release();
scanner_ = NULL;
}
if (setting_ui_)
{
delete setting_ui_;
setting_ui_ = NULL;
}
auto progresser = [&](uint64_t total, uint64_t cur, uint32_t err, void* user_data) -> int
{
LPPROGD param = (LPPROGD)user_data;
CDlgScanner* dlg = param->obj;
if (cur >= total)
log_cls::log(LOG_LEVEL_DEBUG, "Finished in receiving new image = %d\r\n", err);
if (err)
//::SetDlgItemTextW(m_hWnd, IDC_EDIT_COUNT, (L"Receive image " + std::to_wstring(img_cnt_) + L" error: " + std::to_wstring(err)).c_str());
dlg->set_text(IDC_EDIT_COUNT, (L"Receive image " + (std::to_wstring(dlg->img_cnt_) + L"/" + std::to_wstring(dlg->paper_cnt_)) + L" error: " + std::to_wstring(err)).c_str());
else if (cur >= total)
{
dlg->set_text(IDC_EDIT_COUNT, (std::to_wstring(dlg->img_cnt_) + L"/" + std::to_wstring(dlg->paper_cnt_)).c_str());
if (dlg->is_checked(IDC_CHECK_AUTO_OPEN_IMG))
{
images_.save(param->file, true);
//std::string* file(new std::string(param->file));
//if (!PostThreadMessage(thread_open_id_, WM_USER + 1, NULL, (LPARAM)file))
//{
// delete file;
// ShellExecuteA(dlg->m_hWnd, "Open", param->file.c_str(), NULL, NULL, SW_SHOWNORMAL);
//}
}
delete param;
}
return 0;
};
auto img_keeper = [&](LPPACKIMAGE img, uint64_t size) -> data_holder_ptr
{
if (img == IMG_RECEIVER_FINISHED)
{
// scan stopped ...
wchar_t buf[40] = { 0 };
HWND wnd = GetDlgItem(IDC_EDIT_COUNT)->m_hWnd;
HDC dc = ::GetDC(wnd);
set_text(IDC_BUTTON_SCAN, L"Scan");
::SetTextColor(dc, size ? RGB(255, 0, 0) : RGB(0, 0, 0));
::ReleaseDC(wnd, dc);
log_cls::log(LOG_LEVEL_DEBUG, "Scan stopped with error %s\r\n", usb::u2a(scanner_status(size, buf)).c_str());
set_text(IDC_EDIT_COUNT, (std::to_wstring(img_cnt_) + L"/" + std::to_wstring(paper_cnt_)).c_str());
if (size == 0)
size = SCANNER_STATUS_READY;
::PostMessage(m_hWnd, WM_DEVICE_STATTUS, 0, (LPARAM)size);
return NULL;
}
else if (img == IMG_RECEIVER_PAPER_CNT)
{
set_text(IDC_EDIT_COUNT, (std::to_wstring(img_cnt_) + L"/" + std::to_wstring(++paper_cnt_)).c_str());
return NULL;
}
else
{
file_saver* saver = new file_saver();
std::string root(usb::u2a(img_root_.c_str()));
char name[40] = { 0 };
int err = 0;
std::string ext("jpg");
if (img->format == IMG_FMT_BMP)
ext = "bmp";
else if (img->format == IMG_FMT_GIF)
ext = "gif";
else if (img->format == IMG_FMT_PNG)
ext = "png";
else if (img->format == IMG_FMT_TIFF)
ext = "tiff";
if (paper_cnt_ < img->pos.paper_ind)
paper_cnt_ = img->pos.paper_ind;
++img_cnt_;
sprintf_s(name, _countof(name) - 1, "scan_%04d", (int)img->pos.paper_ind);
root += name;
if (img->pos.paper_side == PAPER_SIDE_FRONT)
root += "F";
else if (img->pos.paper_side == PAPER_SIDE_BACK)
root += "B";
else
root += "C";
sprintf_s(name, _countof(name) - 1, "_%d.%s", (int)img->pos.split_ind, ext.c_str());
root += name;
err = saver->open(root.c_str(), size);
log_cls::log(LOG_LEVEL_DEBUG, "Begin receiving new image (%s + %llu) = %d\r\n", root.c_str(), size, err);
if (err)
{
saver->release();
saver = NULL;
}
else
{
LPPROGD param = new PROGD;
param->file = root;
param->obj = this;
saver->set_progress_notify(progresser, param);
}
return dynamic_cast<data_holder_ptr>(saver);
}
};
auto status_cb = [&](uint32_t status) -> void
{
::PostMessage(m_hWnd, WM_DEVICE_STATTUS, 0, (LPARAM)status);
};
max_cmd_ = max_sent_ = 0;
buf_.SetCurSel(0);
buf_.EnableWindow(pnp != NULL);
if (pnp)
{
int err = 0;
OnDeviceStatus(0, (LPARAM)SCANNER_STATUS_READY);
scanner_ = new scanner_handler();
err = scanner_->open_usb_scanner(pnp->device);
if (err)
{
scanner_->release();
scanner_ = NULL;
msg_box(m_hWnd, MB_OK, L"Error", L"Open %04X:%04X failed with error %d.", pnp->vid, pnp->pid, err);
enable_buttons(false);
buf_.EnableWindow(FALSE);
OnDeviceStatus(0, (LPARAM)SCANNER_STATUS_NOT_OPEN);
}
else
{
wchar_t buf[128] = { 0 };
uint16_t ver = 0;
swprintf_s(buf, _countof(buf) - 1, L"%04X:%04X", pnp->vid, pnp->pid);
::SetWindowTextW(m_hWnd, buf);
err = scanner_->get_protocol_version(&ver);
if (err || ver != PROTOCOL_VER)
{
if(err)
msg_box(m_hWnd, MB_OK, L"Unsupported Scanner", L"Failed to get protocol version with error %d.", err);
else
msg_box(m_hWnd, MB_OK, L"Unsupported Scanner", L"Protocol version is mismatch: expect %u.%u but return %u.%u", HIBYTE(PROTOCOL_VER), LOBYTE(PROTOCOL_VER), HIBYTE(ver), LOBYTE(ver));
if (scanner_)
{
scanner_->release();
scanner_ = NULL;
}
enable_buttons(false);
buf_.EnableWindow(FALSE);
OnDeviceStatus(0, (LPARAM)SCANNER_STATUS_NOT_OPEN);
}
else
{
scanner_->set_image_receiver(img_keeper);
swprintf_s(buf, _countof(buf) - 1, L"%u.%u", HIBYTE(ver), LOBYTE(ver));
SetDlgItemTextW(IDC_EDIT_PROTOCOL_VER, buf);
refresh_bulk_status();
//SetTimer(TIMER_ID_REFRESH_BULK, 1000, NULL);
RECT r = { 0 };
std::string all("");
scanner_->set_status_notifyer(status_cb);
if (scanner_->option_get_all(all) == ETIMEDOUT)
{
// reset it ...
msg_box(m_hWnd, MB_OK, L"Bulk Trouble", L"Bulk communication TIMEOUTED, will try reset bulk ...");
scanner_->reset_message_que();
refresh_bulk_status();
scanner_->option_get_all(all);
}
scanner_handler::reorder_device_config_json(all);
sane::reset_opts(all.c_str());
GetDlgItem(IDC_STATIC_OPTS)->GetWindowRect(&r);
ScreenToClient(&r);
//ClientToScreen(&r);
setting_ui_ = new dlg_setting(m_hWnd, &sane_api_, (SANE_Handle)this, &r);
setting_ui_->show(true);
}
}
}
else
{
OnDeviceStatus(0, (LPARAM)SCANNER_STATUS_LOST_CONNECT);
::SetDlgItemTextW(m_hWnd, IDC_BUTTON_SCAN, L"Scan");
}
GetDlgItem(IDC_CHECK_AUTO)->EnableWindow(scanner_ != NULL);
GetDlgItem(IDC_BUTTON_RESET_BULK)->EnableWindow(scanner_ != NULL);
GetDlgItem(IDC_BUTTON_REFRESH)->EnableWindow(scanner_ != NULL);
}
void CDlgScanner::get_option(const char* name, void* value, size_t size)
{
scanner_->option_value_get(name, value, size);
}
int CDlgScanner::get_all_option(std::string& opts_json)
{
int ret = scanner_->option_get_all(opts_json);
if (ret == 0)
{
scanner_handler::reorder_device_config_json(opts_json);
}
return ret;
}
int CDlgScanner::set_option(const char* name, void* value, int type, size_t len, size_t max_len, int* after)
{
return scanner_->option_value_set(name, type, value, max_len, len, (uint8_t*)after);
}
int CDlgScanner::refresh_bulk_status(void)
{
EP0REPLYSTATUS s = { 0 };
wchar_t buf[128] = { 0 };
int err = scanner_->get_scanner_status(&s);
if (err == 0)
{
SetDlgItemTextW(IDC_EDIT_BUILK_IN, peer_bulk_status(s.in_status, buf));
if (s.in_status == BULK_STATUS_IO)
{
swprintf_s(buf, _countof(buf) - 1, L"BULK_STATUS_IO(Want: %x)", s.bytes_to_sent);
SetDlgItemTextW(IDC_EDIT_BUILK_IN, buf);
}
SetDlgItemTextW(IDC_EDIT_BULK_OUT, peer_bulk_status(s.out_status, buf));
if (s.out_status == BULK_STATUS_IO)
{
swprintf_s(buf, _countof(buf) - 1, L"BULK_STATUS_IO(Need: %x)", s.task_required_bytes);
SetDlgItemTextW(IDC_EDIT_BULK_OUT, buf);
}
if (max_sent_ < s.packets_to_sent)
max_sent_ = s.packets_to_sent;
if (max_cmd_ < s.task_cnt)
max_cmd_ = s.task_cnt;
swprintf_s(buf, _countof(buf) - 1, L"%u (max: %u)", s.packets_to_sent, max_sent_);
SetDlgItemTextW(IDC_EDIT_SENT_QUE, buf);
swprintf_s(buf, _countof(buf) - 1, L"%u (max: %u)", s.task_cnt, max_cmd_);
SetDlgItemTextW(IDC_EDIT_CMD_QUE, buf);
}
return err;
}
void CDlgScanner::thread_auto_tx_file(void)
{
char loc[256] = { 0 },
remt[256] = { 0 };
uint32_t ind = 0, err = 0;
std::string file(""), prev(""), ext("");
::GetDlgItemTextA(m_hWnd, IDC_EDIT_LOCAL, loc, _countof(loc) - 1);
::GetDlgItemTextA(m_hWnd, IDC_EDIT_REMOTE, remt, _countof(remt) - 1);
prev = loc;
ind = prev.rfind('.');
ext = ")" + prev.substr(ind);
prev.erase(ind);
file = loc;
prev += " (";
ind = file.rfind('\\');
file.erase(ind + 1);
file += "tx";
mkdir(file.c_str());
file = loc;
prev.insert(ind, "\\tx");
auto tx_over = [&](uint64_t size, uint64_t cur, uint32_t err_code, void* user_data) -> int
{
err = err_code;
if (cur >= size || err_code)
{
SetEvent(auto_wait_);
log_cls::log(LOG_LEVEL_DEBUG, "File transfer ended with error code %d\r\n", err_code);
}
return 0;
};
ind = 0;
while (auto_tx_)
{
ResetEvent(auto_wait_);
scanner_->file_transfer(file.c_str(), remt, true, tx_over);
if (WaitForSingleObject(auto_wait_, 10 * 60 * 1000) == WAIT_TIMEOUT)
{
msg_box(m_hWnd, MB_OK, L"Send file", L"Wait timeouted!\r\nSend: %s", usb::a2u(file.c_str()).c_str());
// ((CButton*)GetDlgItem(IDC_CHECK_REPEAT))->SetCheck(BST_UNCHECKED);
// OnBnClickedCheckRepeat();
set_check(IDC_CHECK_REPEAT, false);
click_repeat();
break;
}
else if (err)
{
msg_box(m_hWnd, MB_OK | MB_ICONSTOP, L"Send file", L"Failed with error code : %d", err);
set_check(IDC_CHECK_REPEAT, false);
click_repeat();
break;
}
if (!auto_tx_)
break;
Sleep(1000);
ResetEvent(auto_wait_);
// file_util::force_move_file(usb::a2u((file + ".reply").c_str()).c_str(), usb::a2u((prev + std::to_string(++ind) + ext).c_str()).c_str());
file = prev + std::to_string(++ind) + ext;
scanner_->file_transfer(file.c_str(), remt, false, tx_over);
if (WaitForSingleObject(auto_wait_, 10 * 60 * 1000) == WAIT_TIMEOUT)
{
msg_box(m_hWnd, MB_OK, L"Receive file", L"Wait timeouted!\r\nReceive to %s", usb::a2u(file.c_str()).c_str());
set_check(IDC_CHECK_REPEAT, false);
click_repeat();
break;
}
else if (err)
{
msg_box(m_hWnd, MB_OK | MB_ICONSTOP, L"Receive file", L"Failed with error code : %d", err);
set_check(IDC_CHECK_REPEAT, false);
click_repeat();
break;
}
Sleep(1000);
}
set_check(IDC_CHECK_REPEAT, false);
auto_tx_ = false;
//enable_buttons(scanner_ != NULL);
click_repeat(true);
// msg_box(m_hWnd, MB_OK, L"Repeat S/R", L"exited.");
}
void CDlgScanner::enable_buttons(bool enable)
{
//GetDlgItem(IDC_BUTTON_RESET_BULK)->EnableWindow(enable);
//GetDlgItem(IDC_CHECK_AUTO)->EnableWindow(enable);
GetDlgItem(IDC_BUTTON_SCAN)->EnableWindow(enable);
GetDlgItem(IDC_BUTTON_SEND)->EnableWindow(enable);
GetDlgItem(IDC_BUTTON_RECEIVE)->EnableWindow(enable);
GetDlgItem(IDC_CHECK_REPEAT)->EnableWindow(enable);
GetDlgItem(IDC_BUTTON_START_PROG)->EnableWindow(enable);
GetDlgItem(IDC_BUTTON_SEND_EP0)->EnableWindow(enable);
}
void CDlgScanner::set_text(UINT id, const wchar_t* text)
{
std::wstring* str = new std::wstring(text);
if (!::PostMessageW(m_hWnd, WM_SET_TEXT, id, (LPARAM)str))
delete str;
}
bool CDlgScanner::is_checked(UINT id)
{
bool chk = false;
::SendMessage(m_hWnd, WM_IS_BUTTON_CHECKED, id, (LPARAM)&chk);
return chk;
}
void CDlgScanner::set_check(UINT id, bool checked)
{
::PostMessage(m_hWnd, WM_SET_BUTTON_CHECK, id, checked);
}
void CDlgScanner::click_repeat(bool enable_buttons, bool enable)
{
if (enable_buttons)
::PostMessage(m_hWnd, WM_ENABLE_CTRLS, 1, enable);
else
::PostMessage(m_hWnd, WM_ENABLE_CTRLS, 0, enable);
}
BEGIN_MESSAGE_MAP(CDlgScanner, CDialogEx)
ON_NOTIFY(TCN_SELCHANGE, IDC_TAB_OPER, &CDlgScanner::OnTcnSelchangeTabOper)
ON_BN_CLICKED(IDOK, &CDlgScanner::OnBnClickedOk)
ON_BN_CLICKED(IDC_BUTTON_RESET_BULK, &CDlgScanner::OnBnClickedButtonResetBulk)
ON_BN_CLICKED(IDC_BUTTON_BROWSE_IMG_PATH, &CDlgScanner::OnBnClickedButtonBrowseSavingPath)
ON_BN_CLICKED(IDC_BUTTON_SCAN, &CDlgScanner::OnBnClickedButtonScan)
ON_BN_CLICKED(IDC_BUTTON_BROWSE_LOCAL, &CDlgScanner::OnBnClickedButtonBrowseFile)
ON_BN_CLICKED(IDC_BUTTON_SEND, &CDlgScanner::OnBnClickedButtonSendFile)
ON_BN_CLICKED(IDC_BUTTON_RECEIVE, &CDlgScanner::OnBnClickedButtonRecvFile)
ON_BN_CLICKED(IDC_BUTTON_START_PROG, &CDlgScanner::OnBnClickedButtonStartProgram)
ON_BN_CLICKED(IDC_BUTTON_SEND_EP0, &CDlgScanner::OnBnClickedButtonSendEp0)
ON_WM_TIMER()
ON_BN_CLICKED(IDC_CHECK_AUTO, &CDlgScanner::OnBnClickedCheckAuto)
ON_BN_CLICKED(IDC_BUTTON_REFRESH, &CDlgScanner::OnBnClickedButtonRefresh)
ON_BN_CLICKED(IDC_CHECK_REPEAT, &CDlgScanner::OnBnClickedCheckRepeat)
ON_MESSAGE(WM_SET_TEXT, &CDlgScanner::OnSetText)
ON_MESSAGE(WM_IS_BUTTON_CHECKED, &CDlgScanner::OnIsButtonChecked)
ON_MESSAGE(WM_SET_BUTTON_CHECK, &CDlgScanner::OnSetButtonChecked)
ON_MESSAGE(WM_ENABLE_CTRLS, &CDlgScanner::OnEnableCtrls)
ON_MESSAGE(WM_DEVICE_STATTUS, &CDlgScanner::OnDeviceStatus)
ON_CBN_SELCHANGE(IDC_COMBO_BUF_SIZE, &CDlgScanner::OnCbnSelchangeComboBufSize)
END_MESSAGE_MAP()
// CDlgScanner 消息处理程序
BOOL CDlgScanner::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
// TODO: 在此添加额外的初始化代码
int ind = 0;
tab_oper_.InsertItem(ind++, TEXT("Status"));
tab_oper_.InsertItem(ind++, TEXT("Scan"));
tab_oper_.InsertItem(ind++, TEXT("File"));
tab_oper_.InsertItem(ind++, TEXT("Prog"));
tab_oper_.InsertItem(ind++, TEXT("Ctrl"));
tab_oper_.SetCurSel(0);
OnTcnSelchangeTabOper(NULL, (LRESULT*)&ind);
SetDlgItemText(IDC_EDIT_LOCAL, TEXT("D:\\boxroom\\usb-tx-file\\VMwareworkstation.exe"));
SetDlgItemText(IDC_EDIT_REMOTE, TEXT("/root/.scanner/log/VMwareworkstation.exe"));
sane_api_.sane_get_devices_api = &sane::sane_get_devices_api;
sane_api_.sane_open_api = &sane::sane_open_api;
sane_api_.sane_close_api = &sane::sane_close_api;
sane_api_.sane_get_option_descriptor_api = &sane::sane_get_option_descriptor_api;
sane_api_.sane_control_option_api = &sane::sane_control_option_api;
sane_api_.sane_get_parameters_api = &sane::sane_get_parameters_api;
sane_api_.sane_start_api = &sane::sane_start_api;
sane_api_.sane_read_api = &sane::sane_read_api;
sane_api_.sane_cancel_api = &sane::sane_cancel_api;
sane_api_.sane_set_io_mode_api = &sane::sane_set_io_mode_api;
sane_api_.sane_get_select_fd_api = &sane::sane_get_select_fd_api;
sane_api_.sane_strstatus_api = &sane::sane_strstatus_api;
sane_api_.sane_io_control_api = &sane::sane_io_control_api;
sane_api_.sane_init_api = &sane::sane_init_api;
sane_api_.sane_exit_api = &sane::sane_exit_api;
wchar_t path[MAX_PATH] = { 0 };
std::wstring root(L"");
GetModuleFileNameW(NULL, path, _countof(path) - 1);
wcsrchr(path, L'\\')[1] = 0;
root = path;
if (GetPrivateProfileStringW(L"config", L"img-path", L"", path, _countof(path) - 1, (root + L"config.txt").c_str()))
{
img_root_ = path;
}
else
{
img_root_ = root + L"imgs";
}
STR_SIMPLIFY_PATH(img_root_);
file_util::force_create_folder(img_root_.c_str(), NULL, false);
if(img_root_[img_root_.length() - 1] != L'\\')
img_root_ += L"\\";
::SetDlgItemTextW(m_hWnd, IDC_EDIT_IMG_PATH, img_root_.c_str());
buf_.SetCurSel(0);
return FALSE; // 除非将焦点设置到控件,否则返回 TRUE
}
BOOL CDlgScanner::PreTranslateMessage(MSG* pMsg)
{
if (pMsg->message == WM_SHOWWINDOW && pMsg->wParam == 0 && pMsg->lParam == SW_PARENTCLOSING)
return TRUE;
return FALSE;
}
void CDlgScanner::OnTcnSelchangeTabOper(NMHDR* pNMHDR, LRESULT* pResult)
{
// TODO: 在此添加控件通知处理程序代码
UINT statu[] = {IDC_STATIC_BULK_IN, IDC_STATIC_BULK_OUT, IDC_STATIC_CMD_QUE, IDC_STATIC_SENT_QUE
, IDC_EDIT_BUILK_IN, IDC_EDIT_BULK_OUT, IDC_EDIT_CMD_QUE, IDC_EDIT_SENT_QUE
, IDC_BUTTON_RESET_BULK, IDC_CHECK_AUTO, IDC_BUTTON_REFRESH},
scan[] = {IDC_STATIC_IMG_PATH, IDC_STATIC_COUNT, IDC_EDIT_IMG_PATH, IDC_EDIT_COUNT, IDC_BUTTON_BROWSE_IMG_PATH
, IDC_CHECK_AUTO_OPEN_IMG, IDC_BUTTON_SCAN},
file[] = {IDC_STATIC_LOCAL, IDC_STATIC_REMOTE, IDC_EDIT_LOCAL, IDC_EDIT_REMOTE, IDC_BUTTON_BROWSE_LOCAL
, IDC_BUTTON_SEND, IDC_BUTTON_RECEIVE, IDC_CHECK_REPEAT},
prog[] = {IDC_STATIC_CMD, IDC_STATIC_PARAM, IDC_EDIT_CMD, IDC_EDIT_PARAM, IDC_BUTTON_START_PROG},
ctrl[] = {IDC_STATIC_TYPE, IDC_STATIC_REQ, IDC_STATIC_IND, IDC_STATIC_VAL, IDC_STATIC_LEN, IDC_STATIC_DATA
, IDC_EDIT_TYPE, IDC_EDIT_REQ, IDC_EDIT_IND, IDC_EDIT_VAL, IDC_EDIT_LEN, IDC_EDIT_DATA
, IDC_BUTTON_SEND_EP0};
int sel = tab_oper_.GetCurSel(), show = sel-- == 0 ? SW_SHOW : SW_HIDE;
for (auto& v : statu)
GetDlgItem(v)->ShowWindow(show);
show = sel-- == 0 ? SW_SHOW : SW_HIDE;
for (auto& v : scan)
GetDlgItem(v)->ShowWindow(show);
show = sel-- == 0 ? SW_SHOW : SW_HIDE;
for (auto& v : file)
GetDlgItem(v)->ShowWindow(show);
show = sel-- == 0 ? SW_SHOW : SW_HIDE;
for (auto& v : prog)
GetDlgItem(v)->ShowWindow(show);
show = sel-- == 0 ? SW_SHOW : SW_HIDE;
for (auto& v : ctrl)
GetDlgItem(v)->ShowWindow(show);
*pResult = 0;
}
void CDlgScanner::OnBnClickedOk()
{
// TODO: 在此添加控件通知处理程序代码
if (IsWindow(parent_))
::PostMessage(parent_, WM_OPENNING_DLG_CLOSED, 0, (LPARAM)this);
CDialogEx::OnOK();
}
void CDlgScanner::OnBnClickedButtonResetBulk()
{
// TODO: 在此添加控件通知处理程序代码
int err = scanner_->reset_message_que();
msg_box(m_hWnd, MB_OK, L"Reset-Bulk", L"Result = %d", err);
if (err == 0)
{
enable_buttons(true);
auto_tx_ = false;
SetEvent(auto_wait_);
}
}
void CDlgScanner::OnBnClickedButtonBrowseSavingPath()
{
// TODO: 在此添加控件通知处理程序代码
LPITEMIDLIST pidRoot = NULL;
BROWSEINFOW bi = { 0 };
wchar_t path[MAX_PATH] = { 0 };
SHGetSpecialFolderLocation(m_hWnd, CSIDL_DRIVES, &pidRoot);
bi.hwndOwner = m_hWnd;
bi.pidlRoot = pidRoot;
bi.lpszTitle = L"Select folder to save scanning images";
bi.pszDisplayName = path;
bi.ulFlags = BIF_RETURNONLYFSDIRS;
pidRoot = SHBrowseForFolderW(&bi);
if (pidRoot)
{
SHGetPathFromIDListW(pidRoot, path);
img_root_ = path;
img_root_ += L"\\";
STR_SIMPLIFY_PATH(img_root_);
::SetDlgItemTextW(m_hWnd, IDC_EDIT_IMG_PATH, img_root_.c_str());
std::wstring root(L"");
GetModuleFileNameW(NULL, path, _countof(path) - 1);
wcsrchr(path, L'\\')[1] = 0;
root = path;
WritePrivateProfileStringW(L"config", L"img-path", img_root_.c_str(), (root + L"config.txt").c_str());
}
}
void CDlgScanner::OnBnClickedButtonScan()
{
// TODO: 在此添加控件通知处理程序代码
wchar_t title[40] = { 0 };
::GetDlgItemTextW(m_hWnd, IDC_BUTTON_SCAN, title, _countof(title) - 1);
if (wcsicmp(title, L"Scan") == 0)
{
img_cnt_ = 0;
paper_cnt_ = 0;
SetDlgItemInt(IDC_EDIT_COUNT, img_cnt_);
if (scanner_)
{
int err = scanner_->scan_start();
log_cls::log(LOG_LEVEL_DEBUG, "Start to scan = %s\r\n", usb::u2a(scanner_status(err, title)).c_str());
if (err)
msg_box(m_hWnd, MB_OK, L"Error", L"Failed in startin scanning with code %s", scanner_status(err, title));
else
{
::SetDlgItemTextW(m_hWnd, IDC_BUTTON_SCAN, L"Stop");
OnDeviceStatus(0, (LPARAM)SCANNER_STATUS_SCANNING);
}
}
}
else
{
if (scanner_)
{
int err = scanner_->scan_stop();
if (err)
msg_box(m_hWnd, MB_OK, L"Error", L"Failed to stop scanning with code %d", err);
}
}
}
void CDlgScanner::OnBnClickedButtonBrowseFile()
{
// TODO: 在此添加控件通知处理程序代码
}
void CDlgScanner::OnBnClickedButtonSendFile()
{
// TODO: 在此添加控件通知处理程序代码
char l[256] = { 0 },
r[256] = { 0 };
int err = 0;
::GetDlgItemTextA(m_hWnd, IDC_EDIT_LOCAL, l, _countof(l) - 1);
::GetDlgItemTextA(m_hWnd, IDC_EDIT_REMOTE, r, _countof(r) - 1);
err = scanner_->file_transfer(l, r, true);
if(err)
msg_box(m_hWnd, MB_OK, L"Send File", L"Result = %d", err);
}
void CDlgScanner::OnBnClickedButtonRecvFile()
{
// TODO: 在此添加控件通知处理程序代码
char l[256] = { 0 },
r[256] = { 0 };
int err = 0;
::GetDlgItemTextA(m_hWnd, IDC_EDIT_LOCAL, l, _countof(l) - 1);
::GetDlgItemTextA(m_hWnd, IDC_EDIT_REMOTE, r, _countof(r) - 1);
err = scanner_->file_transfer(l, r, false);
if (err)
msg_box(m_hWnd, MB_OK, L"Receive File", L"Result = %d", err);
}
void CDlgScanner::OnBnClickedButtonStartProgram()
{
// TODO: 在此添加控件通知处理程序代码
char key[80] = { 0 }, val[80] = { 0 };
int err = 0;
::GetDlgItemTextA(m_hWnd, IDC_EDIT_CMD, key, _countof(key) - 1);
err = scanner_->option_value_get(key, val, 40);
if (err == 0)
::SetDlgItemTextA(m_hWnd, IDC_EDIT_PARAM, val);
}
void CDlgScanner::OnBnClickedButtonSendEp0()
{
// TODO: 在此添加控件通知处理程序代码
}
void CDlgScanner::OnTimer(UINT_PTR nIDEvent)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
if(nIDEvent == TIMER_ID_REFRESH_BULK)
refresh_bulk_status();
CDialogEx::OnTimer(nIDEvent);
}
void CDlgScanner::OnBnClickedCheckAuto()
{
// TODO: 在此添加控件通知处理程序代码
bool checked = ((CButton*)GetDlgItem(IDC_CHECK_AUTO))->GetCheck() == BST_CHECKED;
GetDlgItem(IDC_BUTTON_REFRESH)->EnableWindow(!checked);
if (checked)
SetTimer(TIMER_ID_REFRESH_BULK, 1000, NULL);
else
KillTimer(TIMER_ID_REFRESH_BULK);
}
void CDlgScanner::OnBnClickedButtonRefresh()
{
// TODO: 在此添加控件通知处理程序代码
refresh_bulk_status();
}
void CDlgScanner::OnBnClickedCheckRepeat()
{
// TODO: 在此添加控件通知处理程序代码
auto_tx_ = ((CButton*)GetDlgItem(IDC_CHECK_REPEAT))->GetCheck() == BST_CHECKED;
enable_buttons(!auto_tx_);
GetDlgItem(IDC_CHECK_REPEAT)->EnableWindow(TRUE);
GetDlgItem(IDC_CHECK_AUTO)->EnableWindow(TRUE);
if (auto_tx_)
{
if (auto_tx_file_ == -1)
auto_tx_file_ = threads_->thread_new(&CDlgScanner::thread_auto_tx_file);
}
else
{
if (auto_tx_file_ != -1)
{
SetEvent(auto_wait_);
threads_->thread_stop(auto_tx_file_);
auto_tx_file_ = -1;
}
}
}
LRESULT CDlgScanner::OnSetText(WPARAM wp, LPARAM lp)
{
std::wstring* str = (std::wstring*)lp;
::SetDlgItemTextW(m_hWnd, wp, str->c_str());
delete str;
return 0;
}
LRESULT CDlgScanner::OnIsButtonChecked(WPARAM wp, LPARAM lp)
{
*(bool*)lp = ((CButton*)GetDlgItem(wp))->GetCheck() == BST_CHECKED;
return 0;
}
LRESULT CDlgScanner::OnSetButtonChecked(WPARAM wp, LPARAM lp)
{
((CButton*)GetDlgItem(wp))->SetCheck(lp ? BST_CHECKED : BST_UNCHECKED);
return 0;
}
LRESULT CDlgScanner::OnEnableCtrls(WPARAM wp, LPARAM lp)
{
if (wp == 0)
OnBnClickedCheckRepeat();
else
enable_buttons(lp);
return 0;
}
LRESULT CDlgScanner::OnDeviceStatus(WPARAM wp, LPARAM lp)
{
wchar_t unk[20] = { 0 };
::SetDlgItemTextW(m_hWnd, IDC_EDIT_STATUS, scanner_status((int)lp, unk));
return 0;
}
void CDlgScanner::OnCbnSelchangeComboBufSize()
{
// TODO: 在此添加控件通知处理程序代码
int sel = buf_.GetCurSel();
sel = 1 << sel;
if (scanner_->set_io_buffer_size(sel))
{
int cur = 0;
sel = scanner_->get_io_buffer_size() >> 1;
while (sel)
{
cur++;
sel >>= 1;
}
buf_.SetCurSel(cur);
}
}