修复IO重叠参数错误;启动失败后进度指示器的隐藏

This commit is contained in:
gb 2022-07-04 16:31:37 +08:00
parent 6cbe8f125c
commit 96f6b45893
3 changed files with 143 additions and 51 deletions

View File

@ -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<std::mutex> 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;
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;
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];

View File

@ -13,6 +13,8 @@
#include <memory>
#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<ovl_cls*> 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_;

View File

@ -246,6 +246,9 @@ void scanner::apply_config(void)
}
void scanner::on_ui_event(int uev, void* sender)
{
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);