1335 lines
37 KiB
C++
1335 lines
37 KiB
C++
// 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 <log_util.h>
|
||
#include <json/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(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")
|
||
{
|
||
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")
|
||
{
|
||
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;
|
||
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;
|
||
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("category", val);
|
||
if (val == "advanced")
|
||
{
|
||
ret->cap |= SANE_CAP_ADVANCED;
|
||
}
|
||
|
||
if (strcmp(ret->name, SANE_STD_OPT_NAME_RESOLUTION) == 0)
|
||
{
|
||
ret->unit = SANE_UNIT_DPI;
|
||
}
|
||
else if (strcmp(ret->name, SANE_STD_OPT_NAME_CUSTOM_AREA_LEFT) == 0 ||
|
||
strcmp(ret->name, SANE_STD_OPT_NAME_CUSTOM_AREA_RIGHT) == 0 ||
|
||
strcmp(ret->name, SANE_STD_OPT_NAME_CUSTOM_AREA_TOP) == 0 ||
|
||
strcmp(ret->name, SANE_STD_OPT_NAME_CUSTOM_AREA_BOTTOM) == 0)
|
||
ret->unit = SANE_UNIT_MM;
|
||
|
||
//bool enabled = true;
|
||
//if (jsn->get_value("enable", enabled) && !enabled)
|
||
// ret->cap |= SANE_CAP_INACTIVE;
|
||
|
||
// 关联<E585B3>?
|
||
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)
|
||
{
|
||
json* jsn = new 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())
|
||
{
|
||
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_Status ret = (SANE_Status)dlg->set_option(g_opts[option - 1]->name, value, g_opts[option - 1]->type, val_size, g_opts[option - 1]->size, (int*)info);
|
||
|
||
if (buf == &val)
|
||
{
|
||
*(SANE_Int*)value = SANE_FIX(val);
|
||
}
|
||
|
||
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_SLEEPING);
|
||
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_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;
|
||
}
|
||
// 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)
|
||
{
|
||
g_my_inst = GetModuleHandle(NULL);
|
||
|
||
threads_ = new thread_pool<CDlgScanner>(this);
|
||
parent_ = pParent ? pParent->m_hWnd : NULL;
|
||
auto_wait_ = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||
|
||
char buf[40] = { 0 };
|
||
sscanf(" ether fe:26:f4:f3:29:07 txqueuelen 1000 (Ethernet)", " ether %s", buf);
|
||
}
|
||
|
||
CDlgScanner::~CDlgScanner()
|
||
{
|
||
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_);
|
||
}
|
||
|
||
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);
|
||
GetDlgItem(IDC_CHECK_AUTO)->EnableWindow(pnp != NULL);
|
||
GetDlgItem(IDC_BUTTON_RESET_BULK)->EnableWindow(pnp != NULL);
|
||
GetDlgItem(IDC_BUTTON_REFRESH)->EnableWindow(pnp != NULL);
|
||
|
||
if (scanner_)
|
||
{
|
||
scanner_->close();
|
||
scanner_->release();
|
||
scanner_ = NULL;
|
||
}
|
||
|
||
if (setting_ui_)
|
||
{
|
||
delete setting_ui_;
|
||
setting_ui_ = NULL;
|
||
}
|
||
|
||
static std::string cur_img_file("");
|
||
|
||
auto progresser = [&](uint64_t total, uint64_t cur, uint32_t err, void* user_data) -> int
|
||
{
|
||
CDlgScanner* dlg = (CDlgScanner*)user_data;
|
||
|
||
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(img_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_).c_str());
|
||
|
||
if (dlg->is_checked(IDC_CHECK_AUTO_OPEN_IMG))
|
||
ShellExecuteA(dlg->m_hWnd, "Open", cur_img_file.c_str(), NULL, NULL, SW_SHOWNORMAL);
|
||
}
|
||
|
||
return 0;
|
||
};
|
||
auto img_keeper = [&](LPPACKIMAGE img, uint64_t size) -> data_holder_ptr
|
||
{
|
||
if (img)
|
||
{
|
||
file_saver* saver = new file_saver();
|
||
std::string root(usb::u2a(img_root_.c_str()));
|
||
char name[40] = { 0 };
|
||
int err = 0;
|
||
|
||
sprintf_s(name, _countof(name) - 1, "scan_%04d.jpg", ++img_cnt_);
|
||
err = saver->open((root + name).c_str(), size);
|
||
log_cls::log(LOG_LEVEL_DEBUG, "Begin receiving new image (%s + %llu) = %d\r\n", (root + name).c_str(), size, err);
|
||
if (err)
|
||
{
|
||
saver->release();
|
||
saver = NULL;
|
||
}
|
||
else
|
||
{
|
||
saver->set_progress_notify(progresser, this);
|
||
cur_img_file = root + name;
|
||
}
|
||
|
||
return dynamic_cast<data_holder_ptr>(saver);
|
||
}
|
||
else
|
||
{
|
||
// 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());
|
||
|
||
if (size)
|
||
set_text(IDC_EDIT_COUNT, (std::to_wstring(img_cnt_) + L" (Error: " + scanner_status(size, buf) + L")").c_str());
|
||
else
|
||
set_text(IDC_EDIT_COUNT, (std::to_wstring(img_cnt_) + L" (Good)").c_str());
|
||
return NULL;
|
||
}
|
||
};
|
||
|
||
if (pnp)
|
||
{
|
||
int err = 0;
|
||
|
||
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);
|
||
}
|
||
else
|
||
{
|
||
wchar_t buf[128] = { 0 };
|
||
uint8_t h = 0, l = 0;
|
||
|
||
swprintf_s(buf, _countof(buf) - 1, L"%04X:%04X", pnp->vid, pnp->pid);
|
||
::SetWindowTextW(m_hWnd, buf);
|
||
|
||
err = scanner_->get_protocol_version(&h, &l);
|
||
if (err)
|
||
{
|
||
msg_box(m_hWnd, MB_OK, L"Unsupported Scanner", L"Failed to get protocol version with error %d.", err);
|
||
scanner_->release();
|
||
scanner_ = NULL;
|
||
enable_buttons(false);
|
||
}
|
||
else
|
||
{
|
||
scanner_->set_image_receiver(img_keeper);
|
||
|
||
swprintf_s(buf, _countof(buf) - 1, L"%u.%u", h, l);
|
||
SetDlgItemTextW(IDC_EDIT_PROTOCOL_VER, buf);
|
||
|
||
refresh_bulk_status();
|
||
//SetTimer(TIMER_ID_REFRESH_BULK, 1000, NULL);
|
||
RECT r = { 0 };
|
||
std::string all("");
|
||
|
||
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
|
||
{
|
||
::SetDlgItemTextW(m_hWnd, IDC_BUTTON_SCAN, L"Scan");
|
||
}
|
||
}
|
||
void CDlgScanner::get_option(const char* name, void* value, size_t size)
|
||
{
|
||
scanner_->option_value_get(name, value, size);
|
||
}
|
||
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);
|
||
static uint32_t max_sent = 0, max_cmd = 0;
|
||
|
||
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)
|
||
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());
|
||
|
||
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;
|
||
SetDlgItemInt(IDC_EDIT_COUNT, img_cnt_);
|
||
if (scanner_)
|
||
{
|
||
int err = scanner_->scan_start();
|
||
log_cls::log(LOG_LEVEL_DEBUG, "Start to scan = %d\r\n", err);
|
||
if (err)
|
||
msg_box(m_hWnd, MB_OK, L"Error", L"Failed in startin scanning with code %d", err);
|
||
else
|
||
::SetDlgItemTextW(m_hWnd, IDC_BUTTON_SCAN, L"Stop");
|
||
}
|
||
}
|
||
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;
|
||
}
|