diff --git a/device/win_usb/win_usb.cpp b/device/win_usb/win_usb.cpp index 617953a..3fb149f 100644 --- a/device/win_usb/win_usb.cpp +++ b/device/win_usb/win_usb.cpp @@ -54,6 +54,70 @@ std::string u2utf8(const wchar_t* u) /////*/////////////////////// } +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// OVERLAPPED ... +ovl_cls::ovl_cls() : io_bytes_(0) +{ + memset(&ovl_, 0, sizeof(ovl_)); + ovl_.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); +} +ovl_cls::~ovl_cls() +{ + CloseHandle(ovl_.hEvent); +} + +LPOVERLAPPED ovl_cls::over_lapped(void) +{ + return &ovl_; +} +LPDWORD ovl_cls::io_bytes(void) +{ + return &io_bytes_; +} +void ovl_cls::reset(void) +{ + HANDLE h = ovl_.hEvent; + + memset(&ovl_, 0, sizeof(ovl_)); + ovl_.hEvent = h; + io_bytes_ = 0; +} + +ovl_mgr::ovl_mgr() +{} +ovl_mgr::~ovl_mgr() +{ + for (auto& v : ovls_) + v->release(); +} + +ovl_cls* ovl_mgr::get_ovl(void) +{ + std::lock_guard lock(lock_); + ovl_cls* o = NULL; + + for (auto& v : ovls_) + { + if (WaitForSingleObject(v->over_lapped()->hEvent, 0) == WAIT_OBJECT_0) + { + ResetEvent(v->over_lapped()->hEvent); + o = v; + o->add_ref(); + o->reset(); + break; + } + } + + if (!o) + { + o = new ovl_cls(); + ovls_.push_back(o); + o->add_ref(); + } + + return o; +} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // usb_device ... usb_device::usb_device(const char* name) : ref_(1), name_(name ? name : ""), is_ok_(false) @@ -366,9 +430,6 @@ bool usb_device::init(void) int addr = -1; clear(); - for (size_t i = 0; i < _countof(ovl_); ++i) - ovl_[i].hEvent = CreateEventA(NULL, TRUE, FALSE, NULL); - UuidFromStringA((RPC_CSTR)HG_SCANNER_GUID, &guid); addr = usb_device::get_device_address(name_.c_str(), &guid); //if (addr != -1) @@ -488,9 +549,6 @@ bool usb_device::init(void) void usb_device::clear(void) { close(); - for (size_t i = 0; i < _countof(ovl_); ++i) - CloseHandle(ovl_[i].hEvent); - if (dev_desc_) delete dev_desc_; @@ -595,7 +653,7 @@ int usb_device::open(libusb_device_handle** dev_handle) } } set_timeout(h); - handle_ = (libusb_device_handle*)h; + handle_ = h == INVALID_HANDLE_VALUE ? NULL : (libusb_device_handle*)h; *dev_handle = (libusb_device_handle*)this; return LIBUSB_SUCCESS; @@ -642,27 +700,20 @@ int usb_device::set_timeout(unsigned milliseconds) int usb_device::transfer_bulk(unsigned endpoint, unsigned char* data, int* length, unsigned int timeout) { typedef BOOL(WINAPI* file_io)(HANDLE, LPVOID, DWORD, LPDWORD, LPOVERLAPPED); - int ret = LIBUSB_ERROR_PIPE; + int ret = LIBUSB_ERROR_NOT_SUPPORTED; HANDLE h = find_pipe(endpoint, USBSCAN_PIPE_BULK); file_io fio = (endpoint & BULKIN_FLAG) ? ReadFile : (file_io)WriteFile; - LPOVERLAPPED ovl = (endpoint & BULKIN_FLAG) ? &ovl_[OVL_BULK_IN] : &ovl_[OVL_BULK_OUT]; if (h) { + ovl_cls *oc = ovl_mgr_.get_ovl(); DWORD io = 0; - BOOL result = FALSE; - HANDLE he = ovl->hEvent; + BOOL result = fio(h, data, *length, oc->io_bytes(), oc->over_lapped()); - if (!GetOverlappedResult(h, ovl, &io, FALSE) && GetLastError() == ERROR_IO_INCOMPLETE) - return LIBUSB_ERROR_BUSY; - - memset(ovl, 0, sizeof(*ovl)); - ovl->hEvent = he; - result = fio(h, data, *length, &io, ovl); if (result) { FlushFileBuffers(h); - *length = io; + *length = *oc->io_bytes(); ret = LIBUSB_SUCCESS; } else @@ -670,29 +721,33 @@ int usb_device::transfer_bulk(unsigned endpoint, unsigned char* data, int* lengt io = GetLastError(); if (io == ERROR_IO_PENDING) { - if (WaitForSingleObject(he, timeout) == WAIT_OBJECT_0) + if (WaitForSingleObject(oc->over_lapped()->hEvent, timeout) == WAIT_OBJECT_0) { - GetOverlappedResult(h, ovl, &io, FALSE); + GetOverlappedResult(h, oc->over_lapped(), &io, FALSE); *length = io; ret = LIBUSB_SUCCESS; } + else + ret = LIBUSB_ERROR_TIMEOUT; } + else + ret = LIBUSB_ERROR_PIPE; } + oc->release(); } return ret; } int usb_device::transfer_control(uint8_t type, uint8_t req, uint16_t val, uint16_t ind, unsigned char* data, uint16_t len, unsigned timeout) { - int ret = LIBUSB_ERROR_PIPE; + int ret = LIBUSB_ERROR_NOT_FOUND; _IO_BLOCK_EX irp; if ((HANDLE)handle_ != INVALID_HANDLE_VALUE) { - DWORD io = 0; - LPOVERLAPPED ovl = ovl_ + OVL_CONTROL; + DWORD io = 0; + ovl_cls *oc = ovl_mgr_.get_ovl(); - ResetEvent(ovl->hEvent); irp.bmRequestType = (type >> 5) & 0x03; irp.bRequest = req; irp.fTransferDirectionIn = type >> 7; @@ -700,39 +755,51 @@ int usb_device::transfer_control(uint8_t type, uint8_t req, uint16_t val, uint16 irp.uIndex = ind; irp.uLength = len; irp.uOffset = val; - if (DeviceIoControl((HANDLE)handle_, IOCTL_SEND_USB_REQUEST, &irp, sizeof(irp), data, len, &io, ovl)) + if (DeviceIoControl((HANDLE)handle_, IOCTL_SEND_USB_REQUEST, &irp, sizeof(irp), data, len, oc->io_bytes(), oc->over_lapped())) ret = LIBUSB_SUCCESS; else if (GetLastError() == ERROR_IO_PENDING) { - ret = WaitForSingleObject(ovl->hEvent, timeout) == WAIT_TIMEOUT ? LIBUSB_ERROR_TIMEOUT : LIBUSB_SUCCESS; + ret = WaitForSingleObject(oc->over_lapped()->hEvent, timeout) == WAIT_TIMEOUT ? LIBUSB_ERROR_TIMEOUT : LIBUSB_SUCCESS; } + else + ret = LIBUSB_ERROR_PIPE; + oc->release(); } return ret; } int usb_device::transfer_interrupt(unsigned endpoint, unsigned char* data, int* length, unsigned int timeout) { - int ret = LIBUSB_ERROR_PIPE; + int ret = LIBUSB_ERROR_NOT_SUPPORTED; HANDLE h = find_pipe(endpoint, USBSCAN_PIPE_INTERRUPT); DWORD io = 0; if (h) { - if (DeviceIoControl(h, IOCTL_WAIT_ON_DEVICE_EVENT, NULL, 0, data, *length, &io, &ovl_[OVL_INTERRUPT])) + ovl_cls* oc = ovl_mgr_.get_ovl(); + if (DeviceIoControl(h, IOCTL_WAIT_ON_DEVICE_EVENT, NULL, 0, data, *length, oc->io_bytes(), oc->over_lapped())) { ret = LIBUSB_SUCCESS; - *length = io; + *length = *oc->io_bytes(); } else { io = GetLastError(); if (io == ERROR_IO_PENDING) { - GetOverlappedResult(h, &ovl_[OVL_INTERRUPT], &io, TRUE); - ret = LIBUSB_SUCCESS; - *length = io; + if (WaitForSingleObject(oc->over_lapped()->hEvent, timeout) == WAIT_OBJECT_0) + { + GetOverlappedResult(h, oc->over_lapped(), &io, FALSE); + *length = io; + ret = LIBUSB_SUCCESS; + } + else + ret = LIBUSB_ERROR_TIMEOUT; } + else + ret = LIBUSB_ERROR_PIPE; } + oc->release(); } return ret; @@ -791,10 +858,7 @@ void usb_monitor::notify_usb_event(usb_device*& dev, bool arrive) bool found = false; for(size_t i = 0; i < devices_.size(); ++i) { - if (!(devices_[i]->id() == id)) - continue; - - if (!devices_[i]->is_online() && devices_[i]->is_open()) + if (devices_[i]->id() == id) { dev->release(); dev = devices_[i]; diff --git a/device/win_usb/win_usb.h b/device/win_usb/win_usb.h index cc4d610..9407da4 100644 --- a/device/win_usb/win_usb.h +++ b/device/win_usb/win_usb.h @@ -13,6 +13,8 @@ #include #include "libusb-1.0/libusb.h" +#include "../../../code_device/hgdriver/hgdev/hg_ipc.h" + // HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Class\{6bdd1fc6-810f-11d0-bec7-08002be2092f} #define HG_SCANNER_GUID "6BDD1FC6-810F-11D0-BEC7-08002BE2092F" #define MONITOR_WINDOW_OWNER L"monitor_wnd_owner" @@ -29,6 +31,35 @@ typedef struct _dev_id } }DEVID; +class ovl_cls : public refer +{ + OVERLAPPED ovl_; + DWORD io_bytes_; + +public: + ovl_cls(); + +protected: + ~ovl_cls(); + +public: + LPOVERLAPPED over_lapped(void); + LPDWORD io_bytes(void); + void reset(void); +}; +class ovl_mgr +{ + std::mutex lock_; + std::vector ovls_; + +public: + ovl_mgr(); + ~ovl_mgr(); + +public: + ovl_cls* get_ovl(void); +}; + class usb_device // consider as libusb_device { volatile long ref_; @@ -38,17 +69,7 @@ class usb_device // consider as libusb_device bool is_ok_; bool online_; uint8_t port_; - - enum - { - OVL_BULK_IN, - OVL_BULK_OUT, - OVL_CONTROL, - OVL_INTERRUPT, - - OVL_MAX, - }; - OVERLAPPED ovl_[OVL_MAX]; + ovl_mgr ovl_mgr_; libusb_device_handle *handle_; // as file handle returned by CreateFile libusb_device_descriptor *dev_desc_; diff --git a/sane/scanner.cpp b/sane/scanner.cpp index 84f6fa5..c70fc0b 100644 --- a/sane/scanner.cpp +++ b/sane/scanner.cpp @@ -246,7 +246,10 @@ void scanner::apply_config(void) } void scanner::on_ui_event(int uev, void* sender) { - events_.save(uev); + if (prev_start_result_ != SANE_STATUS_GOOD && sender == indicator_.get()) + indicator_.reset(); + else + events_.save(uev); } int scanner::open(void) { @@ -1548,21 +1551,25 @@ COM_API_IMPLEMENT(scanner, int, start(void)) scan_err_ = false; ret = hg_sane_middleware::instance()->start(handle_, NULL); - if (indicator_.get() && !IsWindowVisible(indicator_->hwnd())) - indicator_->show(true); - // 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) ret = hg_sane_middleware::instance()->start(handle_, NULL); if (ret == SANE_STATUS_GOOD) { + if (indicator_.get() && !IsWindowVisible(indicator_->hwnd())) + indicator_->show(true); + unsigned int l = sizeof(img_fmt_); SANE_CompressionType cmprsn = img_fmt_.compress.compression; if (hg_sane_middleware::instance()->io_control(handle_, IO_CTRL_CODE_GET_FINAL_IMAGE_FORMAT, &img_fmt_, &l)) img_fmt_.img_format = SANE_IMAGE_TYPE_BMP; img_fmt_.compress.compression = cmprsn; } + else if (indicator_.get()) + { + indicator_->notify_scan_over(hg_scanner_err_description(ret), true); + } prev_start_result_ = ret; return local_utility::sane_statu_2_scanner_err(ret);