diff --git a/build_all.bat b/build_all.bat index 985a70f..8ee68f9 100644 --- a/build_all.bat +++ b/build_all.bat @@ -47,47 +47,23 @@ if "%OEM%"=="hw" ( build.bat hw x86 onlytwain 0x8000 nov build.bat hw x86 onlytwain 0x9000 nov ) else if "%OEM%" == "lsc" ( - build.bat lsc x64 0x8200 %NOV% - build.bat lsc x64 onlytwain 0x8420 nov - build.bat lsc x64 onlytwain 0x8429 nov + build.bat lsc x64 0x8420 %NOV% build.bat lsc x64 onlytwain 0x8520 nov - build.bat lsc x64 onlytwain 0x8529 nov build.bat lsc x64 onlytwain 0x8620 nov - build.bat lsc x64 onlytwain 0x8629 nov build.bat lsc x64 onlytwain 0x8730 nov - build.bat lsc x64 onlytwain 0x8739 nov set CPU=x86 - build.bat lsc x86 0x8200 nov - build.bat lsc x86 onlytwain 0x8420 nov - build.bat lsc x86 onlytwain 0x8429 nov + build.bat lsc x86 0x8420 nov build.bat lsc x86 onlytwain 0x8520 nov - build.bat lsc x86 onlytwain 0x8529 nov build.bat lsc x86 onlytwain 0x8620 nov - build.bat lsc x86 onlytwain 0x8629 nov build.bat lsc x86 onlytwain 0x8730 nov - build.bat lsc x86 onlytwain 0x8739 nov ) else ( build.bat x64 0x100 %NOV% - build.bat x64 onlytwain 0x139 nov build.bat x64 onlytwain 0x200 nov - build.bat x64 onlytwain 0x239 nov build.bat x64 onlytwain 0x300 nov - build.bat x64 onlytwain 0x302 nov - build.bat x64 onlytwain 0x339 nov build.bat x64 onlytwain 0x400 nov - build.bat x64 onlytwain 0x402 nov - build.bat x64 onlytwain 0x439 nov - build.bat x64 onlytwain 0x7823 nov set CPU=x86 build.bat x86 0x100 nov - build.bat x86 onlytwain 0x139 nov build.bat x86 onlytwain 0x200 nov - build.bat x86 onlytwain 0x239 nov build.bat x86 onlytwain 0x300 nov - build.bat x86 onlytwain 0x302 nov - build.bat x86 onlytwain 0x339 nov build.bat x86 onlytwain 0x400 nov - build.bat x86 onlytwain 0x402 nov - build.bat x86 onlytwain 0x439 nov - build.bat x86 onlytwain 0x7823 nov ) diff --git a/sane/DlgIndicator.cpp b/sane/DlgIndicator.cpp index b2a4054..c3a4edf 100644 --- a/sane/DlgIndicator.cpp +++ b/sane/DlgIndicator.cpp @@ -5,6 +5,10 @@ #include "resource.h" #include "scanned_img.h" // for local_trans + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/// dlg_choose_dev // CDlgIndicator 对话框 #define WM_SCAN_WORKING WM_USER + 1 // WPARAM: unused; LPARAM: unsed #define WM_USB_PACKET_RECEIVED WM_USER + 2 // WPARAM: unused; LPARAM: unsed @@ -148,3 +152,113 @@ void dlg_indicator::notify_working(void) PostMessage(hwnd_, WM_SCAN_WORKING, 0, 0); } // CDlgIndicator 消息处理程序 + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/// dlg_choose_dev +/// +dlg_choose_dev::dlg_choose_dev(HWND parent, const std::map& devs) : dlg_base(parent, IDD_CHOOSE_DEV), item_(-1) +{ + create(); + + HWND lst = GetDlgItem(hwnd_, IDC_LIST1); + LV_COLUMNW col = { 0 }; + int ind = 0; + + ListView_SetExtendedListViewStyle(lst, ListView_GetExtendedListViewStyle(lst) | LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT); + SetWindowLong(lst, GWL_STYLE, GetWindowLong(lst, GWL_STYLE) | LVS_SINGLESEL); + col.mask = LVCF_TEXT | LVCF_WIDTH; + col.cx = 180; + col.pszText = (wchar_t*)L"\u8BBE\u5907\u540D\u79F0"; + SendMessageW(lst, LVM_INSERTCOLUMN, ind++, (LPARAM)&col); + col.pszText = (wchar_t*)L"\u5E8F\u5217\u53F7"; + SendMessageW(lst, LVM_INSERTCOLUMN, ind++, (LPARAM)&col); + + for (std::map::const_iterator it = devs.begin(); + it != devs.end(); ++it) + { + std::wstring n(local_trans::a2u(it->first.c_str(), CP_UTF8)), + s(local_trans::a2u(it->second.c_str(), CP_UTF8)); + LV_ITEM item = { 0 }; + int ind = 0; + + item.mask = LVIF_TEXT; + item.pszText = &n[0]; + item.iItem = ListView_GetItemCount(lst); + ind = SendMessageW(lst, LVM_INSERTITEMW, 0, (LPARAM)&item); + + item.pszText = &s[0]; + item.iSubItem = 1; + item.iItem = ind; + SendMessageW(lst, LVM_SETITEMTEXTW, ind, (LPARAM)&item); + if (it == devs.begin()) + { + item_ = 0; + ListView_SetItemState(lst, ind, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED); + } + } +} +dlg_choose_dev::~dlg_choose_dev() +{} + +BOOL dlg_choose_dev::handle_message(UINT msg, WPARAM wp, LPARAM lp) +{ + wchar_t text[40] = { 0 }; + BOOL ret = TRUE; + + switch (msg) + { + case WM_COMMAND: + handle_command(HIWORD(wp), LOWORD(wp), (HWND)lp); + break; + case WM_NOTIFY: + handle_notify(wp, (LPNMHDR)lp); + break; + default: + ret = FALSE; + break; + } + + return ret; +} +void dlg_choose_dev::handle_command(WORD code, WORD id, HANDLE ctrl) +{ + if (id == IDOK) + { + HWND lst = GetDlgItem(hwnd_, IDC_LIST1); + if (item_ >= 0 && item_ < ListView_GetItemCount(lst)) + { + wchar_t buf[128] = { 0 }; + + ListView_GetItemText(lst, item_, 0, buf, _countof(buf) - 1); + sel_ = local_trans::u2a(buf, CP_UTF8); + } + id = IDCANCEL; + } + + if (id == IDCANCEL) + { + abandon_hold_ = true; + PostMessage(hwnd_, 0, 0, 0); + } +} +void dlg_choose_dev::handle_notify(UINT id, LPNMHDR pnhdr) +{ + if (pnhdr->hwndFrom == GetDlgItem(hwnd_, IDC_LIST1)) + { + if (pnhdr->code == LVN_ITEMCHANGED) + { + LPNMHEADER h = (LPNMHEADER)pnhdr; + item_ = h->iItem; + } + else if (pnhdr->code == NM_DBLCLK) + { + handle_command(0, IDOK, NULL); + } + } +} + +std::string dlg_choose_dev::get_selected_device(void) +{ + return sel_; +} \ No newline at end of file diff --git a/sane/DlgIndicator.h b/sane/DlgIndicator.h index 8e51841..31cfefd 100644 --- a/sane/DlgIndicator.h +++ b/sane/DlgIndicator.h @@ -2,6 +2,7 @@ #include #include +#include #include "DlgPage.h" @@ -28,3 +29,20 @@ public: void notify_scan_over(const char* msg, bool err); void notify_working(void); }; + +class dlg_choose_dev : public dlg_base +{ + std::string sel_; + int item_; + + BOOL handle_message(UINT msg, WPARAM wp, LPARAM lp) override; + void handle_command(WORD code, WORD id, HANDLE ctrl); + void handle_notify(UINT id, LPNMHDR pnhdr); + +public: + dlg_choose_dev(HWND parent, const std::map& devs); + ~dlg_choose_dev(); + +public: + std::string get_selected_device(void); +}; \ No newline at end of file diff --git a/sane/DlgPage.cpp b/sane/DlgPage.cpp index bf36e48..eaf0f9d 100644 --- a/sane/DlgPage.cpp +++ b/sane/DlgPage.cpp @@ -176,7 +176,7 @@ HWND dlg_base::hwnd(void) { return hwnd_; } -void dlg_base::show(bool visible) +void dlg_base::show(bool visible, bool hold) { UINT cmd = visible ? SW_SHOW : SW_HIDE; DWORD style = GetWindowLong(hwnd_, GWL_STYLE); @@ -187,6 +187,7 @@ void dlg_base::show(bool visible) { RECT r0 = { 0 }, rp = { 0 }, rme = { 0 }; POINT pt = { 0 }; + HWND after = HWND_TOP; if (IsWindow(parent_)) { @@ -202,6 +203,7 @@ void dlg_base::show(bool visible) { GetWindowRect(GetDesktopWindow(), &r0); rp = r0; + after = HWND_TOPMOST; } GetWindowRect(hwnd_, &rme); pt.x = rp.left + (RECT_W(rp) - RECT_W(rme)) / 2; @@ -214,12 +216,28 @@ void dlg_base::show(bool visible) pt.y = r0.bottom - RECT_H(rme); if (pt.y < r0.top) pt.y = r0.top; - SetWindowPos(hwnd_, HWND_TOP, pt.x, pt.y, RECT_W(rme), RECT_H(rme), SWP_NOSIZE); + SetWindowPos(hwnd_, after, pt.x, pt.y, RECT_W(rme), RECT_H(rme), SWP_NOSIZE); UpdateWindow(hwnd_); } EnableWindow(parent_, !visible); } ShowWindow(hwnd_, cmd); + + if (hold) + { + MSG msg = { 0 }; + BOOL ret = FALSE; + + abandon_hold_ = false; + while ((ret = GetMessageW(&msg, NULL, 0, 0))) + { + if (ret == -1 || abandon_hold_) + break; + + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + } } void dlg_base::enable(bool enable) { diff --git a/sane/DlgPage.h b/sane/DlgPage.h index 1d28bdf..fca993b 100644 --- a/sane/DlgPage.h +++ b/sane/DlgPage.h @@ -26,6 +26,7 @@ protected: HWND hwnd_; HWND parent_; UINT idd_; + bool abandon_hold_; void(__stdcall* ui_event_notify_)(int uev, void* sender, void* param); void* ui_notify_param_; static std::wstring prop_name; @@ -50,7 +51,7 @@ public: public: void set_ui_event_notify(void(__stdcall* notify)(int, void*, void*), void* param); HWND hwnd(void); - void show(bool visible); + void show(bool visible, bool hold = false); void enable(bool enable); void screen_2_client(LPRECT r); void client_2_screen(LPRECT r); diff --git a/sane/resource.h b/sane/resource.h index 278e6aa..951fb53 100644 --- a/sane/resource.h +++ b/sane/resource.h @@ -2,11 +2,13 @@ // Microsoft Visual C++ ɵİļ // sane.rc ʹ // +#define IDCANCEL2 3 #define IDD_INDICATOR 101 #define IDD_SETTING 103 #define IDD_PAGE 105 #define IDD_AREA 106 #define IDD_GAMMA 107 +#define IDD_CHOOSE_DEV 108 #define IDC_EDIT_PAPER 1001 #define IDC_EDIT_IMAGE 1002 #define IDC_STATIC_PAPER 1003 @@ -28,6 +30,7 @@ #define IDC_CHANNEL 1017 #define IDC_EDIT_INPUT 1018 #define IDC_EDIT_OUTPUT 1019 +#define IDC_LIST1 1020 // Next default values for new objects // @@ -35,7 +38,7 @@ #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 109 #define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1020 +#define _APS_NEXT_CONTROL_VALUE 1021 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif diff --git a/sane/sane.rc b/sane/sane.rc index e5ec285..8efa736 100644 --- a/sane/sane.rc +++ b/sane/sane.rc @@ -125,6 +125,16 @@ BEGIN EDITTEXT IDC_EDIT_INPUT,33,205,18,12,ES_AUTOHSCROLL | ES_NUMBER END +IDD_CHOOSE_DEV DIALOGEX 0, 0, 267, 96 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION +CAPTION "ѡ豸" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + PUSHBUTTON "ȡ",IDCANCEL,7,77,42,12 + PUSHBUTTON "ȷ",IDOK,218,77,42,12 + CONTROL "",IDC_LIST1,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,253,62 +END + ///////////////////////////////////////////////////////////////////////////// // @@ -173,6 +183,14 @@ BEGIN TOPMARGIN, 7 BOTTOMMARGIN, 217 END + + IDD_CHOOSE_DEV, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 260 + TOPMARGIN, 7 + BOTTOMMARGIN, 89 + END END #endif // APSTUDIO_INVOKED @@ -207,6 +225,11 @@ BEGIN 0 END +IDD_CHOOSE_DEV AFX_DIALOG_LAYOUT +BEGIN + 0 +END + ///////////////////////////////////////////////////////////////////////////// // @@ -248,8 +271,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 4,29,10000,22272 - PRODUCTVERSION 4,29,10000,22272 + FILEVERSION 4,30,10000,22281 + PRODUCTVERSION 4,30,10000,22281 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -266,12 +289,12 @@ BEGIN BEGIN VALUE "CompanyName", "ϢƼ޹˾" VALUE "FileDescription", "ɨӦó" - VALUE "FileVersion", "4.29.10000.22272" + VALUE "FileVersion", "4.30.10000.22281" VALUE "InternalName", "sane.dll" VALUE "LegalCopyright", "Copyright (C) HUAGOScan 2022" VALUE "OriginalFilename", "sane.dll" VALUE "ProductName", "HUAGOScan" - VALUE "ProductVersion", "4.29.10000.22272" + VALUE "ProductVersion", "4.30.10000.22281" END END BLOCK "VarFileInfo" diff --git a/sane/scanner.cpp b/sane/scanner.cpp index aeaf16d..a03be84 100644 --- a/sane/scanner.cpp +++ b/sane/scanner.cpp @@ -267,32 +267,86 @@ scanner::~scanner() delete cfg_; } -std::string scanner::get_scanner_name(SCANNERID id) +bool scanner::is_belong_serial(int vid, int pid, SCANNERID serial) +{ + if (vid == PRODUCT_VENDOR_HG) + { + if (GET_SCANNER_VID(serial) == PRODUCT_VENDOR_HG) + { + if (GET_SCANNER_PID(serial) == 0x100) + { + return pid == 0x100 || pid == 0x139 ; + } + else if (GET_SCANNER_PID(serial) == 0x200) + { + return pid == 0x200 || pid == 0x239; + } + else if (GET_SCANNER_PID(serial) == 0x300) + { + return pid == 0x300 || pid == 0x302 || pid == 0x339; + } + else if (GET_SCANNER_PID(serial) == 0x400) + { + return pid == 0x400 || pid == 0x402 || pid == 0x439; + } + } + } + else if (vid == PRODUCT_VENDOR_HG1) + { + return pid == 0x7823 && GET_SCANNER_VID(serial) == PRODUCT_VENDOR_HG && GET_SCANNER_PID(serial) == 0x200; + } + else if (vid == PRODUCT_VENDOR_HW) + { + return GET_SCANNER_VID(serial) == vid && GET_SCANNER_PID(serial) == pid; + } + else if (vid == PRODUCT_VENDOR_LSC) + { + if (GET_SCANNER_VID(serial) == PRODUCT_VENDOR_LSC) + { + if (GET_SCANNER_PID(serial) == 0x8420) + { + return pid == 0x8200 || pid == 0x8420 || pid == 0x8429; + } + else if (GET_SCANNER_PID(serial) == 0x8520) + { + return pid == 0x8520 || pid == 0x8529; + } + else if (GET_SCANNER_PID(serial) == 0x8620) + { + return pid == 0x8620 || pid == 0x8629; + } + else if (GET_SCANNER_PID(serial) == 0x8730) + { + return pid == 0x8730 || pid == 0x8739; + } + } + } + + return false; +} +void scanner::get_scanner_name(SCANNERID id, std::vector& names) { ScannerInfo* devs = NULL; long count = 0; - std::string name(""); + names.clear(); if (hg_scanner_enum(devs, &count, true) == SCANNER_ERR_INSUFFICIENT_MEMORY) { count++; devs = new ScannerInfo[count]; + memset(devs, 0, count * sizeof(*devs)); if (hg_scanner_enum(devs, &count, true) == SCANNER_ERR_OK) { for (int i = 0; i < count; ++i) { - if (devs[i].vid == GET_SCANNER_VID(id) && - devs[i].pid == GET_SCANNER_PID(id)) + if (scanner::is_belong_serial(devs[i].vid, devs[i].pid, id)) { - name = devs[i].name; - break; + names.push_back(devs[i].name); } } } delete[] devs; } - - return name; } value_type scanner::from_sane_type(SANE_Value_Type type) { @@ -316,6 +370,26 @@ value_limit scanner::from_sane_constraint(SANE_Constraint_Type type) else return VAL_LIMIT_NONE; } +int scanner::control_read_string(SANE_Handle hdev, int code, std::string& str) +{ + char* buf = NULL; + unsigned len = 0; + int err = hg_sane_middleware::instance()->io_control(hdev, code, buf, &len); + + str = ""; + if (err == SANE_STATUS_NO_MEM) + { + len += 4; + buf = new char[len]; + memset(buf, 0, len); + err = hg_sane_middleware::instance()->io_control(hdev, code, buf, &len); + if (err == SANE_STATUS_GOOD) + str = buf; + delete[] buf; + } + + return err; +} int __stdcall scanner::to_int(SANE_Int v) { @@ -457,15 +531,63 @@ void scanner::on_ui_event(int uev, void* sender) events_.save(uev); } } +std::string scanner::choose_scanner(const std::vector& scanners) +{ + if (scanners.empty()) + return ""; + + std::map devs; + std::string sel(""); + + for (size_t i = 0; i < scanners.size(); ++i) + { + SANE_Handle h = NULL; + int ret = hg_sane_middleware::instance()->open_device(scanners[i].c_str(), &h); + + if (h) + { + std::string sn(""); + scanner::control_read_string(h, IO_CTRL_CODE_GET_SERIAL, sn); + if (sn.length()) + devs[scanners[i]] = sn; + hg_sane_middleware::instance()->close_device(h); + } + } + + if (devs.size() == 0) + sel = scanners[0]; + else if (devs.size() == 1) + sel = devs.begin()->first; + else + { + dlg_choose_dev dlg(NULL, devs); + dlg.show(true, true); + sel = dlg.get_selected_device(); + } + + return sel; +} int scanner::open(void) { int ret = close(); - std::string name(scanner::get_scanner_name(id_)); + std::vector que; + std::string name(""); + + scanner::get_scanner_name(id_, que); scanner_name_ = L""; - if (name.empty()) + if (que.empty()) return SCANNER_ERR_DEVICE_NOT_FOUND; + if (que.size() == 1) + name = que[0]; + else + { + name = choose_scanner(que); + if (name.empty()) + return SCANNER_ERR_USER_CANCELED; + } + ret = hg_sane_middleware::instance()->open_device(name.c_str(), &handle_); if (ret == SANE_STATUS_GOOD) { @@ -649,23 +771,7 @@ int scanner::init_options_id(void) } int scanner::control_read_string(int code, std::string& ret) { - char* buf = NULL; - unsigned len = 0; - int err = hg_sane_middleware::instance()->io_control(handle_, code, buf, &len); - - ret = ""; - if (err == SANE_STATUS_NO_MEM) - { - len += 4; - buf = new char[len]; - memset(buf, 0, len); - err = hg_sane_middleware::instance()->io_control(handle_, code, buf, &len); - if (err == SANE_STATUS_GOOD) - ret = buf; - delete[] buf; - } - - return err; + return scanner::control_read_string(handle_, code, ret); } void scanner::extension_none(int id) @@ -2012,7 +2118,9 @@ COM_API_IMPLEMENT(scanner, bool, get_first_image_header(SANE_Parameters* header, } COM_API_IMPLEMENT(scanner, bool, is_online(void)) { - return !scanner::get_scanner_name(id_).empty(); + std::string sn(""); + + return handle_ && control_read_string(IO_CTRL_CODE_GET_SERIAL, sn) != SCANNER_ERR_DEVICE_NOT_FOUND; } COM_API_IMPLEMENT(scanner, bool, is_paper_on(void)) { @@ -2659,7 +2767,11 @@ __declspec(dllimport) #endif bool __stdcall is_scanner_online(SCANNERID scanner_id) { - return !scanner::get_scanner_name(scanner_id).empty(); + std::vector que; + + scanner::get_scanner_name(scanner_id, que); + + return !que.empty(); } #ifdef EXPORT_SANE_API __declspec(dllexport) diff --git a/sane/scanner.h b/sane/scanner.h index a4c86e0..a29e76b 100644 --- a/sane/scanner.h +++ b/sane/scanner.h @@ -59,6 +59,7 @@ class scanner : public ISaneInvoker, virtual public refer void save_config(const wchar_t* file); void apply_config(void); void on_ui_event(int uev, void* sender); + std::string choose_scanner(const std::vector& scanners); int open(void); int close(void); int init_options_id(void); @@ -187,9 +188,11 @@ protected: ~scanner(); public: - static std::string get_scanner_name(SCANNERID id); + static bool is_belong_serial(int vid, int pid, SCANNERID serial); + static void get_scanner_name(SCANNERID id, std::vector& names); static value_type from_sane_type(SANE_Value_Type type); static value_limit from_sane_constraint(SANE_Constraint_Type type); + static int control_read_string(SANE_Handle hdev, int code, std::string& str); // IRef public: