// DlgScanner.cpp: 实现文件 // #include "pch.h" #include "usb_tools.h" #include "DlgScanner.h" #include "afxdialogex.h" #include #include #define TIMER_ID_REFRESH_BULK 1001 #include #include HMODULE g_my_inst; namespace sane { #define ALIGN_INTEGER(v) ALIGN_INT(v, sizeof(int)) static std::vector 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& 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; // 硬件可设置默认�? 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& 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; // 硬件可设置默认�? 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& 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; // 硬件可设置默认�? 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 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 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 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; // 关联�? 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 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 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 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(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(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); } }