diff --git a/sane/DlgIndicator.cpp b/sane/DlgIndicator.cpp new file mode 100644 index 0000000..66be786 --- /dev/null +++ b/sane/DlgIndicator.cpp @@ -0,0 +1,244 @@ +// DlgIndicator.cpp: 实现文件 +// + +#include "DlgIndicator.h" +#include "resource.h" +#include "scanned_img.h" // for local_trans + +// CDlgIndicator 对话框 +#define WM_USB_PACKET_RECEIVED WM_USER + 1 +#define WM_IMAGE_RECEIVED WM_USER + 2 +#define WM_SCAN_FINISHED WM_USER + 3 // WPARAM: std::string* msg; LPARAM: boo err + +ATOM dlg_indicator::indicator_class_atom = 0; +std::wstring dlg_indicator::handle_name = L"dlg_indicator_prop_handle"; +std::wstring dlg_indicator::indicator_class_name = L"dlg_indicator_class"; +extern HMODULE g_my_inst; + +dlg_indicator::dlg_indicator() : hwnd_(NULL), papers_(0), images_(0), notify_(NULL), notify_param_(NULL), parent_(NULL), err_(false) +{ + HANDLE wait = CreateEvent(NULL, TRUE, FALSE, NULL); +#ifdef USE_SOLE_WIN_THREAD + thread_.reset(new std::thread(&dlg_indicator::create, this, wait)); +#else + create(wait); +#endif + WaitForSingleObject(wait, INFINITE); + CloseHandle(wait); +} +dlg_indicator::~dlg_indicator() +{ +#ifdef USE_SOLE_WIN_THREAD + if (IsWindow(hwnd_)) + PostMessage(hwnd_, WM_QUIT, 0, 0); + + if (thread_.get() && thread_->joinable()) + thread_->join(); + thread_.reset(); +#else + if (IsWindow(hwnd_)) + DestroyWindow(hwnd_); +#endif +} + +BOOL CALLBACK dlg_indicator::dlg_indicator_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) +{ + if (msg == WM_INITDIALOG) + { + dlg_indicator *obj = (dlg_indicator*)lp; + + SetPropW(hwnd, dlg_indicator::handle_name.c_str(), (HANDLE)obj); + } + + dlg_indicator* obj = (dlg_indicator*)GetPropW(hwnd, dlg_indicator::handle_name.c_str()); + BOOL handled = FALSE, ret = FALSE; + + if (obj) + ret = obj->handle_msg(msg, wp, lp); + + return ret; +} +ATOM dlg_indicator::register_indicator_class(void) +{ + WNDCLASSEXW wcex; + + wcex.cbSize = sizeof(WNDCLASSEXW); + wcex.style = WS_POPUP; + wcex.lpfnWndProc = (WNDPROC)dlg_indicator::dlg_indicator_proc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = g_my_inst; + wcex.hIcon = NULL; + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); + wcex.lpszMenuName = NULL; + wcex.lpszClassName = dlg_indicator::indicator_class_name.c_str(); + wcex.hIconSm = NULL; + + return RegisterClassExW(&wcex); +} + +void dlg_indicator::create(HANDLE wait) +{ + MSG msg = { 0 }; + BOOL ret = TRUE; + + hwnd_ = CreateDialogParamW(g_my_inst, MAKEINTRESOURCE(IDD_INDICATOR), NULL, &dlg_indicator::dlg_indicator_proc, (LPARAM)this); + SetWindowLongW(GetDlgItem(hwnd_, IDC_STATIC_ERR), GWL_STYLE, GetWindowLong(GetDlgItem(hwnd_, IDC_STATIC_ERR), GWL_STYLE) | SS_OWNERDRAW); + SetEvent(wait); + +#ifdef USE_SOLE_WIN_THREAD + while ((ret = GetMessage(&msg, NULL, 0, 0))) + { + if (ret == -1) + break; + + TranslateMessage(&msg); + DispatchMessage(&msg); + } + DestroyWindow(hwnd_); +#endif +} +BOOL dlg_indicator::handle_msg(UINT msg, WPARAM wp, LPARAM lp) +{ + wchar_t text[40] = { 0 }; + BOOL ret = TRUE; + + switch (msg) + { + case WM_INITDIALOG: + swprintf_s(text, _countof(text) - 1, L"%u", papers_); + SetDlgItemTextW(hwnd_, IDC_EDIT_IMAGE, text); + SetDlgItemTextW(hwnd_, IDC_EDIT_PAPER, text); + break; + case WM_USB_PACKET_RECEIVED: + papers_++; + swprintf_s(text, _countof(text) - 1, L"%u", papers_); + SetDlgItemTextW(hwnd_, IDC_EDIT_PAPER, text); + UpdateWindow(hwnd_); + break; + case WM_IMAGE_RECEIVED: + images_++; + swprintf_s(text, _countof(text) - 1, L"%u", images_); + SetDlgItemTextW(hwnd_, IDC_EDIT_IMAGE, text); + UpdateWindow(hwnd_); + break; + case WM_COMMAND: + handle_command(HIWORD(wp), LOWORD(wp), (HWND)lp); + break; + case WM_DRAWITEM: + if (wp == IDC_STATIC_ERR) + { + DRAWITEMSTRUCT* ds = (DRAWITEMSTRUCT*)lp; + wchar_t text[128] = { 0 }; + SetTextColor(ds->hDC, err_ ? RGB(255, 0, 0) : RGB(0, 0, 0)); + SetBkMode(ds->hDC, TRANSPARENT); + GetWindowTextW(ds->hwndItem, text, _countof(text) - 1); + TextOutW(ds->hDC, 0, 0, text, lstrlenW(text)); + } + ret = FALSE; + break; + case WM_SCAN_FINISHED: + if (lp) + { + std::string* str = (std::string*)wp; + std::wstring err(local_trans::a2u(str->c_str(), CP_UTF8)); + + SetDlgItemTextW(hwnd_, IDC_STATIC_ERR, err.c_str()); + delete str; + } + else + { + wchar_t msg[128] = { 0 }; + std::string* str = (std::string*)wp; + swprintf_s(msg, _countof(msg) - 1, L"\u603b\u8ba1\u626b\u63cf\u56fe\u7247\uff1a%u \u5f20", images_); + + SetDlgItemTextW(hwnd_, IDC_STATIC_ERR, msg); + delete str; + SetTimer(hwnd_, 1, 3000, NULL); + } + SetDlgItemTextW(hwnd_, IDCANCEL, L"\u5173\u95ed"); + ShowWindow(GetDlgItem(hwnd_, IDC_STATIC_PAPER), SW_HIDE); + ShowWindow(GetDlgItem(hwnd_, IDC_STATIC_IMAGE), SW_HIDE); + ShowWindow(GetDlgItem(hwnd_, IDC_EDIT_PAPER), SW_HIDE); + ShowWindow(GetDlgItem(hwnd_, IDC_EDIT_IMAGE), SW_HIDE); + ShowWindow(GetDlgItem(hwnd_, IDC_STATIC_ERR), SW_SHOW); + SetWindowTextW(hwnd_, L"\u626b\u63cf\u7ed3\u675f"); + UpdateWindow(hwnd_); + break; + case WM_TIMER: + if (wp == 1) + { + KillTimer(hwnd_, wp); + notify_over(); + break; + } + default: + ret = FALSE; + break; + } + + return ret; +} +void dlg_indicator::handle_command(WORD code, WORD id, HANDLE ctrl) +{ + if (id == IDCANCEL) + { + notify_over(); + } +} +void dlg_indicator::notify_over(void) +{ + if (notify_) + notify_(true, notify_param_); +} + +void dlg_indicator::set_quit_notify(void(__stdcall* notify)(bool, void*), void* param) +{ + notify_ = notify; + notify_param_ = param; +} +HWND dlg_indicator::window(void) +{ + return hwnd_; +} +HWND dlg_indicator::parent(void) +{ + return parent_; +} +void dlg_indicator::show(HWND parent) +{ + RECT rp, r; + + if (IsWindow(parent)) + GetWindowRect(parent, &rp); + else + GetWindowRect(GetDesktopWindow(), &rp); + GetWindowRect(hwnd_, &r); + + parent_ = parent; + rp.left += (rp.right - rp.left - (r.right - r.left)) / 2; + rp.top += (rp.bottom - rp.top - (r.bottom - r.top)) / 2; + SetWindowPos(hwnd_, HWND_TOPMOST, rp.left, rp.top, r.right - r.left, r.bottom - r.top, SWP_NOSIZE | SWP_SHOWWINDOW); + UpdateWindow(hwnd_); +} +void dlg_indicator::hide(void) +{ + ShowWindow(hwnd_, SW_HIDE); +} +void dlg_indicator::notify_data_arrived(bool image) +{ + PostMessage(hwnd_, image ? WM_IMAGE_RECEIVED : WM_USB_PACKET_RECEIVED, 0, 0); +} +void dlg_indicator::notify_scan_over(const char* msg, bool err) +{ + std::string* mstr(new std::string(msg ? msg : "")); + + err_ = err; + if (!PostMessage(hwnd_, WM_SCAN_FINISHED, (WPARAM)mstr, (LPARAM)err)) + { + delete mstr; + notify_over(); + } +} +// CDlgIndicator 消息处理程序 diff --git a/sane/DlgIndicator.h b/sane/DlgIndicator.h new file mode 100644 index 0000000..616849b --- /dev/null +++ b/sane/DlgIndicator.h @@ -0,0 +1,50 @@ +#pragma once + +#include +#include + +// CDlgIndicator 对话框 +//#define USE_SOLE_WIN_THREAD + +#ifdef USE_SOLE_WIN_THREAD +#include +#include +#endif + +class dlg_indicator +{ + HWND hwnd_; + HWND parent_; + unsigned int papers_; + unsigned int images_; + bool err_; +#ifdef USE_SOLE_WIN_THREAD + std::unique_ptr thread_; +#endif + void(__stdcall* notify_)(bool, void*); + void* notify_param_; + + static ATOM indicator_class_atom; + static std::wstring handle_name; + static std::wstring indicator_class_name; + static BOOL CALLBACK dlg_indicator_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp); + static ATOM register_indicator_class(void); + + void create(HANDLE wait); + BOOL handle_msg(UINT msg, WPARAM wp, LPARAM lp); + void handle_command(WORD code, WORD id, HANDLE ctrl); + void notify_over(void); + +public: + dlg_indicator(); + ~dlg_indicator(); + +public: + void set_quit_notify(void(__stdcall* notify)(bool cancel, void*), void* param); + HWND window(void); + HWND parent(void); + void show(HWND parent); + void hide(void); + void notify_data_arrived(bool image); + void notify_scan_over(const char* msg, bool err); +}; diff --git a/sane/resource.h b/sane/resource.h new file mode 100644 index 0000000..c0b8a1d --- /dev/null +++ b/sane/resource.h @@ -0,0 +1,21 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ ɵİļ +// sane.rc ʹ +// +#define IDD_INDICATOR 101 +#define IDC_EDIT_PAPER 1001 +#define IDC_EDIT_IMAGE 1002 +#define IDC_STATIC_PAPER 1003 +#define IDC_STATIC_IMAGE 1004 +#define IDC_STATIC_ERR 1005 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 103 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1006 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/sane/sane.rc b/sane/sane.rc new file mode 100644 index 0000000..53c3c9b --- /dev/null +++ b/sane/sane.rc @@ -0,0 +1,110 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// (壬й) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) +LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED +#pragma code_page(936) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_INDICATOR DIALOGEX 0, 0, 145, 38 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION +CAPTION "ɨ衭" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + PUSHBUTTON "ȡɨ",IDCANCEL,96,19,42,12 + LTEXT "ֽţ",IDC_STATIC_PAPER,7,7,25,8 + LTEXT "ͼƬ",IDC_STATIC_IMAGE,7,21,24,8 + EDITTEXT IDC_EDIT_PAPER,28,5,39,12,ES_AUTOHSCROLL | ES_READONLY + EDITTEXT IDC_EDIT_IMAGE,28,19,39,12,ES_AUTOHSCROLL | ES_READONLY + LTEXT "",IDC_STATIC_ERR,7,7,131,9,NOT WS_VISIBLE +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_INDICATOR, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 138 + TOPMARGIN, 7 + BOTTOMMARGIN, 31 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// AFX_DIALOG_LAYOUT +// + +IDD_INDICATOR AFX_DIALOG_LAYOUT +BEGIN + 0 +END + +#endif // (壬й) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/sane/sane.vcxproj b/sane/sane.vcxproj index cea4c71..e107004 100644 --- a/sane/sane.vcxproj +++ b/sane/sane.vcxproj @@ -197,6 +197,7 @@ move /Y "$(OutDirFullPath)$(ProjectName).pdb" "$(SolutionDir)..\..\sdk\lib\win\$ + @@ -214,6 +215,8 @@ move /Y "$(OutDirFullPath)$(ProjectName).pdb" "$(SolutionDir)..\..\sdk\lib\win\$ + + @@ -225,6 +228,9 @@ move /Y "$(OutDirFullPath)$(ProjectName).pdb" "$(SolutionDir)..\..\sdk\lib\win\$ + + + diff --git a/sane/sane.vcxproj.filters b/sane/sane.vcxproj.filters index 87f970f..b850f0e 100644 --- a/sane/sane.vcxproj.filters +++ b/sane/sane.vcxproj.filters @@ -42,6 +42,9 @@ sane2twain + + 源文件 + @@ -92,6 +95,12 @@ sane2twain + + 头文件 + + + 头文件 + @@ -101,4 +110,9 @@ + + + 资源文件 + + \ No newline at end of file diff --git a/sane/scanner.cpp b/sane/scanner.cpp index 7fd5623..5b62da0 100644 --- a/sane/scanner.cpp +++ b/sane/scanner.cpp @@ -7,7 +7,7 @@ #include "sane_option_trans.h" #include #include - +#include "DlgIndicator.h" static IMPLEMENT_OPTION_STRING_COMPARE(compare_sane_opt); @@ -87,6 +87,7 @@ namespace callback // class scanner scanner::scanner(SCANNERID id) : handle_(NULL), id_(id), ex_id_(EXTENSION_ID_BASE), prev_start_result_(SCANNER_ERR_NOT_START) , dpi_(200), tmp_path_(L""), img_ind_(0), cb_invoker_(NULL), cb_param_(NULL), working_(false) + , ui_quit_(true) { tmp_path_ = local_trans::a2u(hg_sane_middleware::sane_path().c_str()); tmp_path_ += L"imgs"; @@ -158,6 +159,10 @@ float __stdcall scanner::to_float(SANE_Fixed v) { return SANE_UNFIX(v); } +void __stdcall scanner::ui_callback(bool cancel, void* param) +{ + ((scanner*)param)->on_ui_quit(cancel); +} // IRef COM_API_IMPLEMENT(scanner, long, add_ref(void)) @@ -169,6 +174,17 @@ COM_API_IMPLEMENT(scanner, long, release(void)) return refer::release(); } +void scanner::on_ui_quit(bool cancel) +{ + if (cancel) + stop(); + + ui_quit_ = true; + if (cb_invoker_) + { + cb_invoker_(SANE_EVENT_SCAN_FINISHED, NULL, NULL, cb_param_); + } +} int scanner::open(void) { int ret = close(); @@ -1429,7 +1445,11 @@ EX_OPTION_HANDLER_IMPL(ip) // ISaneInvoker COM_API_IMPLEMENT(scanner, int, start(void)) { - int ret = hg_sane_middleware::instance()->start(handle_, NULL); + int ret = SANE_STATUS_GOOD; + + scan_msg_ = "OK"; + scan_err_ = false; + hg_sane_middleware::instance()->start(handle_, NULL); // the third-APPs in linux will call 'stop' after every start, but it not happens in windows-apps, so we handle this as following ... if(ret == SANE_STATUS_NO_DOCS && prev_start_result_ == SANE_STATUS_GOOD) @@ -1465,10 +1485,27 @@ COM_API_IMPLEMENT(scanner, bool, wait_image(DWORD milliseconds)) COM_API_IMPLEMENT(scanner, int, get_scanned_images(DWORD milliseconds)) { size_t count = images_.count(); + bool notify = true; - while (count == 0 && milliseconds && working_) + while (count == 0 && milliseconds) { + MSG msg = { 0 }; + if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } Sleep(10); + if (!working_) + { + if (notify && indicator_.get()) + { + notify = false; + indicator_->notify_scan_over(scan_msg_.c_str(), scan_err_); // Ending by UI + } + else if(ui_quit_) + break; + } count = images_.count(); if (milliseconds != -1) { @@ -1781,14 +1818,26 @@ COM_API_IMPLEMENT(scanner, bool, ui_show_main(HWND parent)) } COM_API_IMPLEMENT(scanner, bool, ui_show_setting(HWND parent, bool with_scan)) { - return false; + indicator_.reset(new dlg_indicator()); + indicator_->set_quit_notify(&scanner::ui_callback, this); + indicator_->show(parent); + ui_quit_ = false; + + return true; } COM_API_IMPLEMENT(scanner, bool, ui_show_progress(HWND parent)) { - return false; + indicator_.reset(new dlg_indicator()); + indicator_->set_quit_notify(&scanner::ui_callback, this); + indicator_->show(parent); + ui_quit_ = false; + + return true; } COM_API_IMPLEMENT(scanner, void, ui_hide(void)) { + if (indicator_.get()) + indicator_.reset(); } COM_API_IMPLEMENT(scanner, bool, ui_is_ok(void)) { @@ -1816,12 +1865,22 @@ int scanner::handle_event(int ev_code, void* data, unsigned int* len) { img->release(); } + if (indicator_) + indicator_->notify_data_arrived(true); + } + else if (ev_code == SANE_EVENT_USB_DATA_RECEIVED) + { + if (indicator_) + indicator_->notify_data_arrived(false); } else if (ev_code == SANE_EVENT_SCAN_FINISHED) { + if (indicator_.get()) + { + scan_msg_ = (char*)data; + scan_err_ = *len != SCANNER_ERR_OK; + } working_ = false; - //if (cb_invoker_) // calling this when UI exited - // cb_invoker_(ev_code, data, len, cb_param_); } return 0; diff --git a/sane/scanner.h b/sane/scanner.h index 73f5c13..525a0dd 100644 --- a/sane/scanner.h +++ b/sane/scanner.h @@ -3,7 +3,7 @@ #include "scanned_img.h" #include #include - +#include #define SANE_OPTION_ID(name) \ SANE_OPTION_ID_OVERRIDE(name); \ @@ -21,6 +21,8 @@ #define EXTENSION_ID_BASE 0x300 + +class dlg_indicator; class scanner : public ISaneInvoker, virtual public refer { SANE_Handle handle_; @@ -33,11 +35,16 @@ class scanner : public ISaneInvoker, virtual public refer int dpi_; unsigned int img_ind_; std::wstring tmp_path_; + std::string scan_msg_; + bool scan_err_; twain_xfer xfer_; safe_img_queue images_; volatile bool working_; + bool ui_quit_; SANE_FinalImgFormat img_fmt_; + std::unique_ptr indicator_; + void on_ui_quit(bool cancel); int open(void); int close(void); int init_options_id(void); @@ -155,6 +162,7 @@ class scanner : public ISaneInvoker, virtual public refer static int __stdcall to_int(SANE_Int v); static float __stdcall to_float(SANE_Fixed v); + static void __stdcall ui_callback(bool cancel, void* param); public: scanner(SCANNERID id); diff --git a/twain/twain/huagaods.cpp b/twain/twain/huagaods.cpp index 932b16f..ba00ed3 100644 --- a/twain/twain/huagaods.cpp +++ b/twain/twain/huagaods.cpp @@ -2471,7 +2471,7 @@ void huagao_ds::on_scan_event(int sane_event, void* data, unsigned int* len) { if (sane_event == SANE_EVENT_SCAN_FINISHED) { - notifyCloseOk(); + notifyCloseCancel(); } } }