This commit is contained in:
13038267101 2022-10-28 11:07:10 +08:00
commit 6994b6718b
16 changed files with 1335 additions and 579 deletions

View File

@ -51,8 +51,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 4,32,10000,22287
PRODUCTVERSION 4,32,10000,22287
FILEVERSION 4,33,10000,22297
PRODUCTVERSION 4,33,10000,22297
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -69,12 +69,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "宁波华高信息科技有限公司"
VALUE "FileDescription", "华高扫描仪应用程序"
VALUE "FileVersion", "4.32.10000.22287"
VALUE "FileVersion", "4.33.10000.22297"
VALUE "InternalName", "scanner.dll"
VALUE "LegalCopyright", "Copyright (C) HUAGOScan 2022"
VALUE "OriginalFilename", "scanner.dll"
VALUE "ProductName", "HUAGOScan"
VALUE "ProductVersion", "4.32.10000.22287"
VALUE "ProductVersion", "4.33.10000.22297"
END
END
BLOCK "VarFileInfo"

View File

@ -146,15 +146,10 @@ ovl_cls* ovl_mgr::get_ovl(void)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// usb_device ...
usb_device::usb_device(const char* name) : ref_(1), name_(name ? name : ""), is_ok_(false)
, dev_desc_(NULL), handle_(NULL), online_(true), timout_ms_(1000), reg_key_("")
usb_device::usb_device(const USBDEV& dev) : ref_(1), udev_(dev), is_ok_(false)
, dev_desc_(NULL), handle_(NULL), online_(true), timout_ms_(1000)
{
bzero(&guid_, sizeof(guid_));
id_ = usb_device::vid_pid_from_name(name);
GUID guid;
UuidFromStringA((RPC_CSTR)HG_SCANNER_GUID, &guid);
id_.addr = usb_device::get_device_address(name_.c_str(), &guid);
memset(&guid_, 0, sizeof(guid_));
}
usb_device::~usb_device()
{
@ -202,23 +197,20 @@ int usb_device::set_timeout(HANDLE h)
//SetCommTimeouts(h, &to);
}
DEVID usb_device::vid_pid_from_name(const char* name)
void usb_device::vid_pid_from_name(const char* name, int* vid, int* pid)
{
// name: \\?\usb#vid_3072&pid_0239#01234567aabbccddee#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
DEVID id;
std::string s(name ? name : "");
size_t pos = 0;
std::transform(s.begin(), s.end(), s.begin(), tolower);
pos = s.find("vid_");
if (pos != std::string::npos)
id.vid = usb_device::from_hex_string(s.c_str() + pos + 4);
if (pos != std::string::npos && vid)
*vid = usb_device::from_hex_string(s.c_str() + pos + 4);
pos = s.find("pid_");
if (pos != std::string::npos)
id.pid = usb_device::from_hex_string(s.c_str() + pos + 4);
return id;
if (pos != std::string::npos && pid)
*pid = usb_device::from_hex_string(s.c_str() + pos + 4);
}
DWORD usb_device::from_hex_string(const char* hex_str)
{
@ -242,222 +234,15 @@ DWORD usb_device::from_hex_string(const char* hex_str)
return v;
}
std::string usb_device::driver_key_name(HANDLE file)
std::string usb_device::name_without_guid(const char* name)
{
ULONG nBytes = 0;
USB_HCD_DRIVERKEY_NAME driverKeyName = { 0 };
BOOL success = DeviceIoControl(file, IOCTL_GET_HCD_DRIVERKEY_NAME, &driverKeyName, sizeof(driverKeyName), &driverKeyName, sizeof(driverKeyName), &nBytes, NULL);
std::string ret("");
std::string no_guid(name);
size_t pos = no_guid.find("#{");
if (success && driverKeyName.ActualLength > nBytes)
{
PUSB_HCD_DRIVERKEY_NAME buf = (PUSB_HCD_DRIVERKEY_NAME)GlobalAlloc(GPTR, driverKeyName.ActualLength);
nBytes = driverKeyName.ActualLength;
success = DeviceIoControl(file, IOCTL_GET_HCD_DRIVERKEY_NAME, &buf, nBytes, &buf, nBytes, &nBytes, NULL);
if (success)
{
ret = u2utf8(buf->DriverKeyName);
}
GlobalFree(buf);
}
if (pos != std::string::npos)
no_guid.erase(pos);
return ret;
}
std::string usb_device::parent_hub_path_name(int vid, int pid, int *addr, std::string* reg_key)
{
std::string ret("");
GUID guid = GUID_DEVINTERFACE_USB_HUB;
HDEVINFO dev = SetupDiGetClassDevsW(&guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
int port = addr ? *addr : -1;
if (dev)
{
SP_DEVICE_INTERFACE_DATA id = { 0 };
SP_DEVINFO_DATA did;
int ind = 0;
id.cbSize = sizeof(id);
while (SetupDiEnumDeviceInterfaces(dev, NULL, &guid, ind++, &id))
{
PSP_DEVICE_INTERFACE_DETAIL_DATA_W buf = NULL;
DWORD size = 0;
if (!SetupDiGetDeviceInterfaceDetailW(dev, &id, buf, 0, &size, NULL) &&
GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
int bytes = size + sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) + 40;
buf = (PSP_DEVICE_INTERFACE_DETAIL_DATA_W)new wchar_t[bytes];
memset(buf, 0, bytes * 2);
buf->cbSize = sizeof(*buf);
if (SetupDiGetDeviceInterfaceDetailW(dev, &id, buf, buf->cbSize + size, NULL, NULL))
{
std::string n(u2utf8(buf->DevicePath));
if (find_vid_pid_in_hub(n.c_str(), vid, pid, &port, reg_key))
ret = n;
}
delete[] buf;
if (ret.length())
break;
}
}
SetupDiDestroyDeviceInfoList(dev);
}
if (addr)
*addr = port;
VLOG_MINI_4(LOG_LEVEL_DEBUG_INFO, "Parent hub for %04X:%04X is: %s (+%d)\r\n", vid, pid, ret.c_str(), port);
return ret;
}
bool usb_device::find_vid_pid_in_hub(const char* utf8_hub_path_name, int vid, int pid, int* addr, std::string* reg_key)
{
bool ret = false;
HANDLE h = CreateFileA(utf8_hub_path_name, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (h == INVALID_HANDLE_VALUE)
return ret;
int bytes = sizeof(USB_NODE_CONNECTION_INFORMATION_EX) + (sizeof(USB_PIPE_INFO) * 30);
PUSB_NODE_CONNECTION_INFORMATION_EX connectionInfoEx = (PUSB_NODE_CONNECTION_INFORMATION_EX)new char[bytes];
memset(connectionInfoEx, 0, bytes);
if (addr && *addr != -1)
{
connectionInfoEx->ConnectionIndex = *addr;
DeviceIoControl(h, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, connectionInfoEx,
bytes, connectionInfoEx, bytes, (LPDWORD)&bytes, NULL);
ret = connectionInfoEx->DeviceDescriptor.idVendor == vid && connectionInfoEx->DeviceDescriptor.idProduct == pid;
if (ret && reg_key)
{
char buf[512] = { 0 };
USB_NODE_CONNECTION_DRIVERKEY_NAME* name = (USB_NODE_CONNECTION_DRIVERKEY_NAME*)buf;
name->ConnectionIndex = *addr;
name->ActualLength = (sizeof(buf) - sizeof(*name)) / 2 - 1;
DeviceIoControl(h, IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, name, sizeof(*name), name, name->ActualLength, (LPDWORD)&bytes, NULL);
*reg_key = u2utf8(name->DriverKeyName);
}
}
else
{
for (int i = 1; !ret; ++i)
{
DWORD len = bytes;
connectionInfoEx->ConnectionIndex = i;
if (!DeviceIoControl(h, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, connectionInfoEx,
bytes, connectionInfoEx, bytes, (LPDWORD)&bytes, NULL))
break;
ret = connectionInfoEx->DeviceDescriptor.idVendor == vid && connectionInfoEx->DeviceDescriptor.idProduct == pid;
}
if (ret && addr)
*addr = connectionInfoEx->ConnectionIndex;
}
delete[] connectionInfoEx;
CloseHandle(h);
return ret;
}
int usb_device::get_device_address(const char* device_name, LPGUID lpguid)
{
int addr = -1;
GUID guid = lpguid ? *lpguid : GUID_DEVINTERFACE_USB_DEVICE;
HDEVINFO dev = NULL;
std::string ret(""), src(device_name);
dev = SetupDiGetClassDevsW(&guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (dev)
{
SP_DEVICE_INTERFACE_DATA id = { 0 };
SP_DEVINFO_DATA did;
int ind = 0;
size_t pos = src.find("{");
if (pos != std::string::npos)
src.erase(pos);
id.cbSize = sizeof(id);
while (SetupDiEnumDeviceInterfaces(dev, NULL, &guid, ind++, &id))
{
PSP_DEVICE_INTERFACE_DETAIL_DATA_W buf = NULL;
DWORD size = 0;
ret = "";
if (!SetupDiGetDeviceInterfaceDetailW(dev, &id, buf, 0, &size, NULL) &&
GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
buf = (PSP_DEVICE_INTERFACE_DETAIL_DATA_W)new wchar_t[size + 4];
memset(buf, 0, (size + 4) * 2);
buf->cbSize = sizeof(*buf);
if (SetupDiGetDeviceInterfaceDetailW(dev, &id, buf, buf->cbSize + size, NULL, NULL))
{
wchar_t* l = wcsstr(buf->DevicePath, L"{");
if (l)
*l = 0;
ret = u2utf8(buf->DevicePath);
}
delete buf;
}
if (stricmp(ret.c_str(), src.c_str()))
continue;
SP_DEVINFO_DATA dd = { 0 };
dd.cbSize = sizeof(dd);
// for (int i = 0; SetupDiEnumDeviceInfo(dev_info, i, &dd); ++i)
if (SetupDiEnumDeviceInfo(dev, ind - 1, &dd))
{
SetupDiGetDeviceRegistryPropertyA(dev, &dd, SPDRP_ADDRESS, NULL, (PBYTE)&addr, sizeof(addr), NULL);
}
break;
}
SetupDiDestroyDeviceInfoList(dev);
}
return addr;
}
std::string usb_device::usb_scan_name(DEVID id, const char* guid)
{
// HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{6BDD1FC6-810F-11D0-BEC7-08002BE2092F}
HKEY key = NULL, root = NULL;
std::string path("SYSTEM\\CurrentControlSet\\Control\\Class\\{"), name("");
char val[256] = { 0 };
int ind = 0, err = 0;
path += guid;
path += "}";
err = RegOpenKeyA(HKEY_LOCAL_MACHINE, path.c_str(), &root);
if (root)
{
DWORD index = 0;
while (RegEnumKeyA(root, index++, val, _countof(val) - 1) == ERROR_SUCCESS)
{
RegOpenKeyA(root, val, &key);
if (key)
{
DWORD len = _countof(val) - 1,
type = REG_SZ;
if (RegQueryValueExA(key, "MatchingDeviceId", NULL, &type, (LPBYTE)val, &len) == ERROR_SUCCESS)
{
val[len] = 0;
DEVID cid = usb_device::vid_pid_from_name(val);
if (cid.vid == id.vid && cid.pid == id.pid)
{
len = _countof(val) - 1;
type = REG_SZ;
if (RegQueryValueExA(key, "CreateFileName", NULL, &type, (LPBYTE)val, &len) == ERROR_SUCCESS)
{
val[len] = 0;
name = val;
}
}
}
RegCloseKey(key);
if (!name.empty())
break;
}
memset(val, 0, sizeof(val));
}
RegCloseKey(root);
}
return name;
return no_guid;
}
std::string usb_device::usb_scan_name(const char* reg_key)
{
@ -496,21 +281,6 @@ long usb_device::release(void)
return ref;
}
bool usb_device::operator==(const char* name)
{
return name_ == name;
}
bool usb_device::operator==(const DEVID& id)
{
return id_.vid == id.vid && id_.pid == id.pid;
}
usb_device& usb_device::operator=(const DEVID& id)
{
id_ = id;
return *this;
}
usb_device& usb_device::operator=(const GUID& guid)
{
guid_ = guid;
@ -520,16 +290,16 @@ usb_device& usb_device::operator=(const GUID& guid)
std::string usb_device::name(void)
{
return name_;
return udev_.name;
}
USBDEV& usb_device::dev(void)
{
return udev_;
}
GUID usb_device::guid(void)
{
return guid_;
}
DEVID usb_device::id(void)
{
return id_;
}
bool usb_device::is_ok(void)
{
return is_ok_;
@ -550,29 +320,36 @@ uint8_t usb_device::port(void)
{
if (!dev_desc_)
init();
return port_;
return udev_.port;
}
uint8_t usb_device::address(void)
{
if (!dev_desc_)
init();
return udev_.addr;
}
std::string usb_device::reg_path(void)
{
return udev_.driver_key;
}
bool usb_device::init(void)
{
PUSBDEVICEINFO info = NULL;
GUID guid;
int addr = -1;
clear();
UuidFromStringA((RPC_CSTR)HG_SCANNER_GUID, &guid);
addr = usb_device::get_device_address(name_.c_str(), &guid);
//if (addr != -1)
usb_monitor::enum_usb_device(&usb_monitor::find_parent_hub, &udev_, true);
VLOG_MINI_3(LOG_LEVEL_ALL, "Device '%s' at hub '%s + %d'\r\n", udev_.name.c_str(), udev_.hub.c_str(), udev_.port);
if (!udev_.hub.empty())
{
std::string path(usb_device::parent_hub_path_name(id_.vid, id_.pid, &addr, &reg_key_));
if (!path.empty())
HANDLE h = CreateFileA(udev_.hub.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (h != INVALID_HANDLE_VALUE)
{
HANDLE h = CreateFileA(path.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (h != INVALID_HANDLE_VALUE)
{
info = enumerate_hub_port(h, addr);
CloseHandle(h);
}
info = enumerate_hub_port(h, udev_.port);
CloseHandle(h);
}
}
@ -581,7 +358,7 @@ bool usb_device::init(void)
if (info)
{
port_ = addr;
udev_.addr = info->ConnectionInfo->DeviceAddress;
if (info->ConnectionInfo)
{
dev_desc_ = new libusb_device_descriptor;
@ -675,7 +452,6 @@ bool usb_device::init(void)
free_usb_device_info(info);
}
id_.addr = port_;
return is_ok_;
}
@ -703,10 +479,6 @@ void usb_device::clear(void)
cfg_desc_.clear();
is_ok_ = false;
}
void usb_device::online_statu_changed(bool online)
{
online_ = online;
}
int usb_device::get_descriptor(libusb_device_descriptor* desc)
{
if (dev_desc_)
@ -725,8 +497,8 @@ int usb_device::get_descriptor(libusb_device_descriptor* desc)
desc->bDeviceClass = libusb_class_code::LIBUSB_CLASS_HID;
else
desc->bDeviceClass = libusb_class_code::LIBUSB_CLASS_VENDOR_SPEC;
desc->idVendor = id_.vid;
desc->idProduct = id_.pid;
desc->idVendor = udev_.vid;
desc->idProduct = udev_.pid;
desc->bcdUSB = 0x200; // USB2.0 ?
desc->bcdDevice = 0; // ?
desc->bDescriptorType = libusb_descriptor_type::LIBUSB_DT_DEVICE;
@ -759,7 +531,7 @@ int usb_device::open(libusb_device_handle** dev_handle)
if (!dev_desc_)
init();
HANDLE h = open_usb(name_.c_str());
HANDLE h = open_usb(udev_.name.c_str());
if (h == INVALID_HANDLE_VALUE)
{
*dev_handle = NULL;
@ -769,22 +541,19 @@ int usb_device::open(libusb_device_handle** dev_handle)
USBSCAN_PIPE_CONFIGURATION upc = { 0 };
DWORD cbr = 0;
std::string fmt("\\%d"), root(""); // (usb_device::usb_scan_name(reg_key_.empty() ? id_ : reg_key_.c_str()));
if (reg_key_.length())
root = usb_device::usb_scan_name(reg_key_.c_str());
if (root.empty())
root = usb_device::usb_scan_name(id_);
std::string fmt("\\%d"), root("");
if (udev_.driver_key.length())
root = usb_device::usb_scan_name(udev_.driver_key.c_str());
if (root.empty())
{
VLOG_MINI_1(LOG_LEVEL_WARNING, "Cannot find '\\\\.\\Usbscan' name for '%s', try run in Administrator!\r\n", name_.c_str());
root = name_;
VLOG_MINI_1(LOG_LEVEL_WARNING, "Cannot find '\\\\.\\Usbscan' name for '%s', try run in Administrator!\r\n", udev_.name.c_str());
root = udev_.name;
fmt = "\\%04d";
}
else
{
VLOG_MINI_2(LOG_LEVEL_WARNING, "Nice: '%s' for '%s'.\r\n", root.c_str(), name_.c_str());
VLOG_MINI_2(LOG_LEVEL_WARNING, "Nice: '%s' for '%s'.\r\n", root.c_str(), udev_.name.c_str());
}
if (DeviceIoControl(h, IOCTL_GET_PIPE_CONFIGURATION, NULL, 0, &upc, sizeof(upc), &cbr, NULL))
{
@ -1012,6 +781,121 @@ usb_monitor::~usb_monitor()
quit();
}
int usb_monitor::enum_usb_device(bool(__stdcall* found_usb)(LPUSBDEV dev, void* param), void* param, bool hub)
{
GUID hid = hub ? GUID_DEVINTERFACE_USB_HUB : GUID_DEVINTERFACE_USB_DEVICE;
HDEVINFO dev_info = NULL;
int ind = 0;
SP_DEVICE_INTERFACE_DATA id = { 0 };
SP_DEVINFO_DATA sdd = { 0 };
dev_info = SetupDiGetClassDevsW(&hid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (!dev_info)
return GetLastError();
id.cbSize = sizeof(id);
while (SetupDiEnumDeviceInterfaces(dev_info, NULL, &hid, ind++, &id))
{
PSP_DEVICE_INTERFACE_DETAIL_DATA_W buf = NULL;
DWORD size = 0;
SetupDiGetDeviceInterfaceDetailW(dev_info, &id, buf, 0, &size, NULL);
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
buf = (PSP_DEVICE_INTERFACE_DETAIL_DATA_W)new wchar_t[size + 4];
memset(buf, 0, (size + 4) * 2);
buf->cbSize = sizeof(*buf);
if (SetupDiGetDeviceInterfaceDetailW(dev_info, &id, buf, buf->cbSize + size, NULL, NULL))
{
USBDEV dev;
DWORD len = size;
dev.name = u2utf8(buf->DevicePath);
usb_device::vid_pid_from_name(dev.name.c_str(), &dev.vid, &dev.pid);
sdd.cbSize = sizeof(sdd);
SetupDiEnumDeviceInfo(dev_info, ind - 1, &sdd);
if (SetupDiGetDeviceRegistryPropertyW(dev_info, &sdd, SPDRP_DRIVER, NULL, (PBYTE)buf->DevicePath, len, &len)) // driver key
dev.driver_key = u2utf8(buf->DevicePath);
len = size;
if(SetupDiGetDeviceRegistryPropertyW(dev_info, &sdd, SPDRP_DEVICEDESC, NULL, (PBYTE)buf->DevicePath, len, &len)) // device description
dev.desc = u2utf8(buf->DevicePath);
len = size;
if (SetupDiGetDeviceRegistryPropertyW(dev_info, &sdd, SPDRP_ADDRESS, NULL, (PBYTE)buf->DevicePath, len, &len)) // device description
dev.port = *(int*)buf->DevicePath;
if (!found_usb(&dev, param))
{
delete[](char*)buf;
break;
}
}
delete[](char*)buf;
}
id.cbSize = sizeof(id);
}
SetupDiDestroyDeviceInfoList(dev_info);
return ERROR_SUCCESS;
}
bool __stdcall usb_monitor::find_all_usb_devices(LPUSBDEV dev, void* param/*std::vector<USBDEV>* */)
{
std::vector<USBDEV>* devs = (std::vector<USBDEV>*)param;
devs->push_back(*dev);
return true;
}
bool __stdcall usb_monitor::usb_dev_by_name(LPUSBDEV dev, void* param/*LPUSBDEV*/)
{
LPUSBDEV devt = (LPUSBDEV)param;
if (stricmp(usb_device::name_without_guid(devt->name.c_str()).c_str(), usb_device::name_without_guid(dev->name.c_str()).c_str()) == 0)
{
devt->driver_key = dev->driver_key;
devt->desc = dev->desc;
devt->vid = dev->vid;
devt->pid = dev->pid;
devt->port = dev->port;
return false;
}
return true;
}
bool __stdcall usb_monitor::find_parent_hub(LPUSBDEV hub, void* param/*LPUSBDEV*/)
{
LPUSBDEV t = (LPUSBDEV)param;
if (t->driver_key.empty() || t->port == 0)
return false;
HANDLE h = CreateFileA(hub->name.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
bool go = true;
char buf[512] = { 0 };
DWORD bytes = 0;
if (h == INVALID_HANDLE_VALUE)
return true;
USB_NODE_CONNECTION_DRIVERKEY_NAME* name = (USB_NODE_CONNECTION_DRIVERKEY_NAME*)buf;
name->ConnectionIndex = t->port;
name->ActualLength = (sizeof(buf) - sizeof(*name)) / 2 - 1;
if (DeviceIoControl(h, IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, name, sizeof(*name), name, name->ActualLength, &bytes, NULL))
{
if (u2utf8(name->DriverKeyName) == t->driver_key)
{
t->hub = hub->name;
go = false;
}
}
CloseHandle(h);
return go;
}
bool usb_monitor::is_desired_usb_device(int vid, int pid)
{
return vid == PRODUCT_VID || vid == PRODUCT_VENDOR_HG1;
}
LRESULT CALLBACK usb_monitor::monitor_wnd_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
usb_monitor* monitor = (usb_monitor*)GetPropW(hwnd, MONITOR_WINDOW_OWNER);
@ -1050,29 +934,26 @@ void usb_monitor::notify_usb_event(usb_device*& dev, bool arrive)
{
std::lock_guard<std::mutex> lock(lock_);
int ev = arrive ? LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED : LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT;
DEVID id = dev->id();
if (id.vid != PRODUCT_VID && id.vid != PRODUCT_VENDOR_HG1)
return;
VLOG_MINI_4(LOG_LEVEL_DEBUG_INFO, "WINUSB %04X:%04X(%d) %s\r\n", dev->id().vid, dev->id().pid, dev->id().addr,
arrive ? "Connected" : "Left");
std::string noguid(usb_device::name_without_guid(dev->name().c_str()));
if (arrive)
{
bool found = false;
for(size_t i = 0; i < devices_.size(); ++i)
{
if (devices_[i]->id() == id)
// if (devices_[i]->name() == dev->name())
if (stricmp(usb_device::name_without_guid(devices_[i]->name().c_str()).c_str(), noguid.c_str()) == 0)
{
if (devices_[i]->is_online())
{
VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "%s is already in device queue and received ARRIVE again, discard this event.\n", dev->name().c_str());
dev->release();
// dev->release();
return;
}
else
{
devices_[i]->clear();
devices_[i]->dev() = dev->dev(); // use NEW connection info ...
dev->release();
dev = devices_[i];
dev->add_ref();
@ -1090,31 +971,32 @@ void usb_monitor::notify_usb_event(usb_device*& dev, bool arrive)
}
else
{
bool discard = false;
for (size_t i = 0; i < devices_.size(); ++i)
{
if (!(devices_[i]->id() == id))
continue;
dev->release();
dev = devices_[i];
dev->add_ref();
if (dev->is_open())
// if (devices_[i]->name() == dev->name())
if (stricmp(usb_device::name_without_guid(devices_[i]->name().c_str()).c_str(), noguid.c_str()) == 0)
{
dev->release();
dev = devices_[i];
dev->add_ref();
if (dev->is_online())
{
dev->set_online(false);
discard = false;
}
else
{
VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "%s is already offline and received LEAVE again, discard this event.\n", dev->name().c_str());
dev->release();
return;
discard = true;
}
break;
}
else
{
devices_.erase(devices_.begin() + i);
dev->release();
}
break;
}
if (discard)
{
VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "%s is already offline and received LEAVE again, discard this event.\n", dev->name().c_str());
return;
}
}
@ -1135,67 +1017,54 @@ int usb_monitor::on_usb_pnp(WPARAM wp, LPARAM lp)
return wp == DBT_DEVICEQUERYREMOVE;
}
std::string utf8(u2utf8(dev->dbcc_name));
if (wp == DBT_DEVICEQUERYREMOVE)
return cur_dev_name_ != u2utf8(dev->dbcc_name);
return cur_dev_name_ != utf8;
VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "event '%08x' of device %s\n", wp, u2utf8(dev->dbcc_name).c_str());
VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "event '%08x' of device %s\n", wp, utf8.c_str());
usb_device* ud = new usb_device(u2utf8(dev->dbcc_name).c_str());
int vid = 0,
pid = 0;
usb_device::vid_pid_from_name(utf8.c_str(), &vid, &pid);
if (!usb_monitor::is_desired_usb_device(vid, pid))
return 0;
USBDEV udev;
udev.name = utf8;
usb_monitor::enum_usb_device(&usb_monitor::usb_dev_by_name, &udev);
if (wp == DBT_DEVICEARRIVAL && udev.driver_key.empty())
{
VLOG_MINI_1(LOG_LEVEL_FATAL, "Failed: driver key for '%s' is not found!\r\n", utf8.c_str());
}
usb_device* ud = new usb_device(udev);
*ud = dev->dbcc_classguid;
if (!PostThreadMessageW(handle_msg_id_, MSG_DEVICE_PNP, wp == DBT_DEVICEARRIVAL, (LPARAM)ud))
ud->release();
return ret;
}
void usb_monitor::find_usb(std::vector<std::string>& usb_devs)
{
GUID hid = GUID_DEVINTERFACE_USB_DEVICE; // GUID_DEVINTERFACE_USB_HUB
HDEVINFO dev_info = NULL;
int ind = 0;
SP_DEVICE_INTERFACE_DATA id = { 0 };
// HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\DeviceClasses\{a5dcbf10-6530-11d2-901f-00c04fb951ed}
// HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\USB
// UuidFromStringW((RPC_WSTR)WIN_USB_GUID, &hid);
dev_info = SetupDiGetClassDevsW(&hid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (!dev_info)
return;
id.cbSize = sizeof(id);
while (SetupDiEnumDeviceInterfaces(dev_info, NULL, &hid, ind++, &id))
{
PSP_DEVICE_INTERFACE_DETAIL_DATA_W buf = NULL;
DWORD size = 0;
SetupDiGetDeviceInterfaceDetailW(dev_info, &id, buf, 0, &size, NULL);
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
buf = (PSP_DEVICE_INTERFACE_DETAIL_DATA_W)new wchar_t[size + 4];
memset(buf, 0, (size + 4) * 2);
buf->cbSize = sizeof(*buf);
if (SetupDiGetDeviceInterfaceDetailW(dev_info, &id, buf, buf->cbSize + size, NULL, NULL))
{
usb_devs.push_back(u2utf8(buf->DevicePath));
}
delete[](char*)buf;
}
id.cbSize = sizeof(id);
}
SetupDiDestroyDeviceInfoList(dev_info);
}
void usb_monitor::find_usb_and_trigger_event(void)
{
std::vector<std::string> old(found_usb_devs_);
std::vector<USBDEV> old(found_usb_devs_);
found_usb_devs_.clear();
find_usb(found_usb_devs_);
usb_monitor::enum_usb_device(&usb_monitor::find_all_usb_devices, &found_usb_devs_);
for (size_t i = 0; i < found_usb_devs_.size(); ++i)
{
std::vector<std::string>::iterator it = std::find(old.begin(), old.end(), found_usb_devs_[i]);
if (!usb_monitor::is_desired_usb_device(found_usb_devs_[i].vid, found_usb_devs_[i].pid))
{
found_usb_devs_.erase(found_usb_devs_.begin() + i);
i--;
}
}
for (size_t i = 0; i < found_usb_devs_.size(); ++i)
{
std::vector<USBDEV>::iterator it = std::find(old.begin(), old.end(), found_usb_devs_[i]);
if (it == old.end())
{
usb_device* dev = new usb_device(found_usb_devs_[i].c_str());
usb_device* dev = new usb_device(found_usb_devs_[i]);
notify_usb_event(dev, true);
dev->release();
}
@ -1205,7 +1074,7 @@ void usb_monitor::find_usb_and_trigger_event(void)
for (size_t i = 0; i < old.size(); ++i)
{
usb_device* dev = new usb_device(old[i].c_str());
usb_device* dev = new usb_device(old[i]);
notify_usb_event(dev, false);
dev->release();
}
@ -1258,13 +1127,8 @@ void usb_monitor::thread_run_device_event_wnd(void)
DEV_BROADCAST_HDR dbh = { 0 };
HDEVNOTIFY notify = NULL;
find_usb(found_usb_devs_);
for (size_t i = 0; i < found_usb_devs_.size(); ++i)
{
usb_device* dev = new usb_device(found_usb_devs_[i].c_str());
notify_usb_event(dev, true);
dev->release();
}
// mannual triggered at beginning ...
find_usb_and_trigger_event();
dbh.dbch_size = sizeof(dbh);
dbh.dbch_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
@ -1274,7 +1138,7 @@ void usb_monitor::thread_run_device_event_wnd(void)
DEV_BROADCAST_DEVICEINTERFACE_A di = { 0 };
di.dbcc_size = (sizeof(di) + 3) / 4 * 4;
di.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
UuidFromStringA((RPC_CSTR)HG_SCANNER_GUID, &di.dbcc_classguid);
UuidFromStringA((RPC_CSTR)IMAGE_CLASS_GUID, &di.dbcc_classguid);
notify = RegisterDeviceNotificationA(wnd_monitor_, &di, DEVICE_NOTIFY_WINDOW_HANDLE | DEVICE_NOTIFY_ALL_INTERFACE_CLASSES);
VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "RegisterDeviceNotificationA = 0x%08x, error = %d. di.dbcc_size = %d\n", notify, GetLastError(), di.dbcc_size);
if (!notify)
@ -1587,6 +1451,6 @@ uint8_t LIBUSB_CALL libusb_get_device_address(libusb_device* device)
if(!device)
return 0;
return ((usb_device*)device)->port();
return ((usb_device*)device)->address();
}

View File

@ -15,25 +15,33 @@
// HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Class\{6bdd1fc6-810f-11d0-bec7-08002be2092f}
#define HG_SCANNER_GUID "6BDD1FC6-810F-11D0-BEC7-08002BE2092F"
#define IMAGE_CLASS_GUID "6BDD1FC6-810F-11D0-BEC7-08002BE2092F"
#define MONITOR_WINDOW_OWNER L"monitor_wnd_owner"
typedef struct _dev_id
typedef struct _usb_dev
{
int vid;
int pid;
int addr;
// all members are in utf8
std::string name; // \\?\usb#vid_0bda&pid_0129#20100201396000000#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
std::string driver_key; // {6bdd1fc6-810f-11d0-bec7-08002be2092f}\\0016
std::string desc; // USB Composite Device
std::string hub; // parent hub
int vid;
int pid;
int port; // port on the hub, also be ConnectionIndex
int addr; // connection address
struct _dev_id()
struct _usb_dev()
{
memset(this, 0, sizeof(struct _dev_id));
name = driver_key = desc = hub = "";
vid = pid = port = 0;
addr = -1;
}
bool operator==(const struct _dev_id& r)
bool operator==(const struct _usb_dev& r)
{
return vid == r.vid && pid == r.pid && r.addr == addr;
return name == r.name;
}
}DEVID;
}USBDEV, * LPUSBDEV;
class ovl_cls// : public refer
{
@ -83,12 +91,9 @@ class usb_device // consider as libusb_device
{
volatile long ref_;
GUID guid_;
std::string name_;
std::string reg_key_;
DEVID id_;
USBDEV udev_;
bool is_ok_;
bool online_;
uint8_t port_;
ovl_mgr ovl_mgr_;
libusb_device_handle *handle_; // as file handle returned by CreateFile
@ -108,15 +113,12 @@ class usb_device // consider as libusb_device
int set_timeout(HANDLE h);
public:
usb_device(const char* name);
usb_device(const USBDEV& dev);
static DEVID vid_pid_from_name(const char* name); // device name like '\\?\usb#vid_3072&pid_0239#01234567aabbccddee#{a5dcbf10-6530-11d2-901f-00c04fb951ed}'
static void vid_pid_from_name(const char* name, int *vid, int *pid); // device name like '\\?\usb#vid_3072&pid_0239#01234567aabbccddee#{a5dcbf10-6530-11d2-901f-00c04fb951ed}'
static DWORD from_hex_string(const char* hex_str);
static std::string driver_key_name(HANDLE file);
static std::string parent_hub_path_name(int vid, int pid, int *addr = NULL, std::string* reg_key = NULL);
static std::string name_without_guid(const char* name);
static bool find_vid_pid_in_hub(const char* utf8_hub_path_name, int vid, int pid, int *addr/*if *addr is not -1 or NULL, search the device with vid:pid and set the address in addr if it was not null, or-else chekc the device at *addr is vid:pid or not*/, std::string* reg_key/*{6bdd1fc6-810f-11d0-bec7-08002be2092f}\\0007*/);
static int get_device_address(const char* device_name, LPGUID lpguid);
static std::string usb_scan_name(DEVID id, const char* guid = HG_SCANNER_GUID); // return \\.\Usbscan1 ...
static std::string usb_scan_name(const char* reg_key/*{6bdd1fc6-810f-11d0-bec7-08002be2092f}\\0007*/); // return \\.\Usbscan1 ...
long add_ref(void);
@ -126,24 +128,21 @@ protected:
~usb_device();
public:
bool operator==(const char* name);
bool operator==(const DEVID& id);
usb_device& operator=(const DEVID& id);
usb_device& operator=(const GUID& guid);
std::string name(void);
USBDEV& dev(void);
GUID guid(void);
DEVID id(void);
bool is_ok(void);
bool is_open(void);
bool is_online(void);
void set_online(bool online);
uint8_t port(void);
uint8_t address(void);
std::string reg_path(void);
bool init(void);
void clear(void);
void online_statu_changed(bool online);
int get_descriptor(libusb_device_descriptor* desc);
int get_config_descriptor(int index, libusb_config_descriptor** desc);
int open(libusb_device_handle** dev_handle);
@ -177,14 +176,13 @@ class usb_monitor // consider as libusb_context
HWND wnd_monitor_;
std::string cur_dev_name_;
volatile bool run_;
std::vector<std::string> found_usb_devs_;
std::vector<USBDEV> found_usb_devs_;
static LRESULT CALLBACK monitor_wnd_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp);
static void register_monitor_wnd(const wchar_t* cls);
void notify_usb_event(usb_device*& dev, bool arrive);
int on_usb_pnp(WPARAM wp, LPARAM lp);
void find_usb(std::vector<std::string>& usb_devs);
void find_usb_and_trigger_event(void);
public:
@ -194,6 +192,12 @@ public:
static usb_monitor* usb_monitor_;
static UINT find_usb_timer_; // set when RegisterDeviceNotification failed
static int enum_usb_device(bool(__stdcall* found_usb)(LPUSBDEV dev, void* param), void* param, bool hub = false);
static bool __stdcall find_all_usb_devices(LPUSBDEV dev, void* param/*std::vector<USBDEV>* */);
static bool __stdcall usb_dev_by_name(LPUSBDEV dev, void* param/*LPUSBDEV*/);
static bool __stdcall find_parent_hub(LPUSBDEV hub, void* param/*LPUSBDEV*/);
static bool is_desired_usb_device(int vid, int pid);
public:
usb_callback* reg_callback(libusb_hotplug_callback_fn cb, void* param);
void unreg_callback(usb_callback* cb);

View File

@ -158,9 +158,9 @@ void dlg_base::notify_ui_event(int ev)
if (ui_event_notify_)
ui_event_notify_(ev, this, ui_notify_param_);
}
gb::sane_config* dlg_base::get_config(void)
gb::sane_config_schm* dlg_base::get_config(void)
{
gb::sane_config* cfg = NULL;
gb::sane_config_schm* cfg = NULL;
SendMessage(parent_, WM_GET_CONFIG_OBJ, 0, (LPARAM)&cfg);
@ -796,7 +796,7 @@ void dlg_page::handle_command(WORD code, WORD id, HANDLE ctrl)
{
SANE_Fixed val = SANE_FIX(dlg.x_in_mm());
SANE_Int after = 0;
gb::sane_config* cfg = get_config();
gb::sane_config_schm* cfg = get_config();
sane_.sane_control_option_api(dev_, id_custom_left_, SANE_ACTION_SET_VALUE, &val, &after);
if (cfg)
@ -833,7 +833,7 @@ void dlg_page::handle_command(WORD code, WORD id, HANDLE ctrl)
dlg.get_gamma(&gamma);
sane_.sane_io_control_api(dev_, IO_CTRL_CODE_SET_CUSTOM_GAMMA, &gamma, &len);
gb::sane_config* cfg = get_config();
gb::sane_config_schm* cfg = get_config();
if (cfg)
cfg->config_changed(id_custom_gamma_, (char*)&gamma, sizeof(gamma), true);
}
@ -1077,7 +1077,7 @@ void dlg_page::control_action(HWND wnd)
{
SANE_Int after = 0;
SANE_Status statu = sane_.sane_control_option_api(dev_, id - dlg_page::dyn_id_base, SANE_ACTION_SET_VALUE, val, &after);
gb::sane_config* cfg = get_config();
gb::sane_config_schm* cfg = get_config();
done_ = false;
if (cfg)
{

View File

@ -22,7 +22,7 @@
extern HMODULE g_my_inst;
namespace gb
{
class sane_config;
class sane_config_schm;
}
class dlg_base
@ -41,7 +41,7 @@ protected:
virtual void on_font_changed(void);
void create(void);
void notify_ui_event(int ev);
gb::sane_config* get_config(void);
gb::sane_config_schm* get_config(void);
public:
dlg_base(HWND parent, UINT idd);

View File

@ -58,7 +58,7 @@ BOOL dlg_setting::handle_message(UINT msg, WPARAM wp, LPARAM lp)
refresh_controls((int)wp);
break;
case WM_GET_CONFIG_OBJ:
*((gb::sane_config**)lp) = cfg_;
*((gb::sane_config_schm**)lp) = cfg_;
break;
default:
ret = FALSE;
@ -351,7 +351,7 @@ void dlg_setting::refresh_controls(int src_sn)
}
}
void dlg_setting::set_config(gb::sane_config* cfg, const wchar_t* file)
void dlg_setting::set_config(gb::sane_config_schm* cfg, const wchar_t* file)
{
cfg_ = cfg;
cfg_file_ = file;

View File

@ -17,7 +17,7 @@
namespace gb
{
class sane_config;
class sane_config_schm;
}
class dlg_setting : public dlg_base
{
@ -29,7 +29,7 @@ class dlg_setting : public dlg_base
bool err_;
int id_help_;
int id_restore_;
gb::sane_config* cfg_;
gb::sane_config_schm* cfg_;
std::wstring cfg_file_;
HWND tab_;
@ -55,7 +55,7 @@ public:
~dlg_setting();
public:
void set_config(gb::sane_config* cfg, const wchar_t* file);
void set_config(gb::sane_config_schm* cfg, const wchar_t* file);
HWND window(void);
HWND parent(void);
//void show(void);

View File

@ -30,6 +30,57 @@ namespace gb
return ret;
}
static int load_mini_file(const char* file, std::string& cont)
{
FILE* src = fopen(file, "rb");
if (src)
{
size_t size = 0;
char *buf = NULL;
fseek(src, 0, SEEK_END);
size = ftell(src);
fseek(src, 0, SEEK_SET);
buf = new char[size + 4];
memset(buf, 0, size + 4);
fread(buf, 1, size, src);
fclose(src);
cont = std::string(buf, size);
delete[] buf;
return 0;
}
else
return errno;
}
refer::refer() : ref_(1)
{}
refer::~refer()
{}
long refer::add_ref(void)
{
#if defined(WIN32) || defined(_WIN64)
return InterlockedIncrement(&ref_);
#else
return ++ref_;
#endif
}
long refer::release(void)
{
#if defined(WIN32) || defined(_WIN64)
long ref = InterlockedDecrement(&ref_);
#else
long ref = --ref_;
#endif
if (ref == 0)
delete this;
return ref;
}
json::json(char* json_txt) : obj_(0), cur_child_(0), is_array_(false)
{
@ -325,7 +376,7 @@ namespace gb
val = new json();
if (!val->attach_cjson(obj))
{
delete val;
val->release();
return false;
}
@ -828,22 +879,212 @@ namespace gb
}
}
namespace updater
{
static std::string hg_model_from_pid(const char* pid)
{
if (strcmp(pid, "7823") == 0)
return "G200";
char m[] = { 'G', pid[0], '0', '0', 0};
return std::string(m) + " - " + pid;
}
static std::string hv_model_from_pid(const char* pid)
{
std::string m("");
if (strcmp(pid, "1000") == 0)
m = "HW-1000NS";
else if (strcmp(pid, "1002") == 0)
m = "HW-1000";
else if (strcmp(pid, "7000") == 0)
m = "HW-7000NS";
else if (strcmp(pid, "7002") == 0)
m = "HW-7000";
else if (strcmp(pid, "7039") == 0)
m = "HW-7000NS";
else
m = std::string("HW-") + pid;
return m + " - " + pid;
}
static std::string lsc_model_from_pid(const char* pid)
{
if (strcmp(pid, "8200") == 0)
return "G42S - 8200";
else
{
char m[] = {'G', pid[1], pid[2], 'S', 0};
return std::string(m) + " - " + pid;
}
}
static std::string scanner_chinese_name_2_model(const char* cn)
{
static const char* hg = "\345\215\216\351\253\230",
* hw = "\346\261\211\347\216\213",
* lsc = "\347\253\213\346\200\235\350\276\260",
* smy = "\346\211\253\346\217\217\344\273\252\342\200\224G",
* f = strstr(cn, hg);
std::string model("");
std::string(* model_from_pid)(const char* pid) = nullptr;
if (f == cn)
{
model = "HUAGOSCAN ";
model_from_pid = hg_model_from_pid;;
}
else if (strstr(cn, hw) == cn)
{
model = "Hanvon ";
model_from_pid = hv_model_from_pid;;
}
else if (strstr(cn, lsc) == cn)
{
model = "LANXUMSCAN ";
model_from_pid = lsc_model_from_pid;;
}
else
return "";
f = strstr(cn, smy);
if (!f)
return "";
f += strlen(smy);
model += model_from_pid(f);
return model;
}
static int update_app_config(const char* scanner_name, const char* jsn_txt, const char* path, gb::scanner_cfg::LPUDF lpfunc)
{
std::string scanner(""), jsn_str(jsn_txt);
std::vector<std::string> efiles;
if ((unsigned char)scanner_name[0] > 0x7f)
scanner = scanner_chinese_name_2_model(scanner_name);
else
scanner = scanner_name;
gb::json* jsn = new gb::json();
int cur_sel = -1, ret = 0;
gb::scanner_cfg* cfg = nullptr;
if (!jsn->attach_text(&jsn_str[0]))
{
jsn->release();
return EINVAL;
}
if (jsn->first_child(jsn_str))
{
gb::json* child = new gb::json();
if (child->attach_text(&jsn_str[0]))
{
if (!child->get_value("cur_sel", cur_sel))
ret = EINVAL;
}
if (ret == 0)
{
cfg = new gb::scanner_cfg();
int ind = 0;
while (jsn->next_child(jsn_str))
{
if (!child->attach_text(&jsn_str[0]))
{
ret = EINVAL;
break;
}
std::string schm_name("");
if (!child->get_value("scheme", schm_name))
{
ret = EINVAL;
break;
}
gb::json* items = nullptr;
if (!child->get_value("opts", items) || !items)
{
ret = EINVAL;
break;
}
gb::sane_config_schm* schm = new gb::sane_config_schm();
if (items->first_child(jsn_str))
{
do
{
std::string name(""), val("");
gb::json* item = new gb::json();
if (item->attach_text(&jsn_str[0]))
{
if (item->get_value("name", name) && item->get_value("value", val))
{
name = lpfunc->title2name(name.c_str(), lpfunc->func_param);
lpfunc->trans_number(name.c_str(), val, lpfunc->func_param);
schm->set_value(name.c_str(), val.c_str(), val.length());
val = "";
item->get_value("extra", val);
if (val.length() && gb::load_mini_file(val.c_str(), val) == 0)
{
schm->set_value(name.c_str(), val.c_str(), val.length(), true);
item->get_value("extra", val);
efiles.push_back(val);
}
}
}
item->release();
} while (items->next_child(jsn_str));
}
items->release();
cfg->add_scheme(schm, schm_name.c_str());
schm->release();
if (ind++ == cur_sel)
cfg->select_scheme(schm_name.c_str());
}
}
child->release();
}
jsn->release();
if (cfg)
{
if (ret == 0)
{
cfg->save((path + scanner + ".cfg").c_str());
for (auto& v : efiles)
rename(v.c_str(), (v + "_bk").c_str());
}
cfg->release();
}
return ret;
}
}
namespace gb
{
std::string sane_config::opt_data_appendix_("_data");
std::string sane_config_schm::opt_data_appendix_("_data");
sane_config::sane_config() : jsn_(NULL), bkp_(NULL), in_setting_(false)
sane_config_schm::sane_config_schm(scanner_cfg* scanner) : jsn_(NULL), bkp_(NULL), in_setting_(false), scheme_name_("")
, scanner_(scanner)
{
char empty[8] = { "{}" };
jsn_ = new gb::json();
jsn_->attach_text(empty);
def_val_ = new gb::json();
if (scanner_)
scanner_->add_ref();
}
sane_config::~sane_config()
sane_config_schm::~sane_config_schm()
{
clear();
delete def_val_;
def_val_->release();
if (scanner_)
scanner_->release();
}
bool sane_config::hex(unsigned char ch, unsigned char* val)
bool sane_config_schm::hex(unsigned char ch, unsigned char* val)
{
bool ret = true;
@ -864,15 +1105,15 @@ namespace gb
return ret;
}
bool sane_config::hex_char(const char* data, unsigned char* val)
bool sane_config_schm::hex_char(const char* data, unsigned char* val)
{
unsigned char v = 0;
bool ret = false;
if (sane_config::hex(*data++, &v))
if (sane_config_schm::hex(*data++, &v))
{
v <<= 4;
if (sane_config::hex(*data++, &v))
if (sane_config_schm::hex(*data++, &v))
{
if (val)
*val = v;
@ -883,13 +1124,13 @@ namespace gb
return ret;
}
bool sane_config::is_option_data(std::string& name)
bool sane_config_schm::is_option_data(std::string& name)
{
size_t pos = name.find(sane_config::opt_data_appendix_);
size_t pos = name.find(sane_config_schm::opt_data_appendix_);
if (pos != std::string::npos)
{
if (pos + sane_config::opt_data_appendix_.length() == name.length())
if (pos + sane_config_schm::opt_data_appendix_.length() == name.length())
{
name.erase(pos);
@ -900,17 +1141,17 @@ namespace gb
return false;
}
void sane_config::clear()
void sane_config_schm::clear()
{
if (jsn_)
delete jsn_;
jsn_->release();
jsn_ = NULL;
if (bkp_)
delete bkp_;
bkp_->release();
bkp_ = NULL;
file_ = L"";
// file_ = "";
}
std::string sane_config::to_hex_letter(const char* data, size_t bytes)
std::string sane_config_schm::to_hex_letter(const char* data, size_t bytes)
{
std::string hex("");
const unsigned char* ptr = (const unsigned char*)data;
@ -918,13 +1159,13 @@ namespace gb
for (size_t i = 0; i < bytes; ++i)
{
sprintf_s(buf, _countof(buf) - 1, "%02X", ptr[i]);
sprintf(buf, "%02X", ptr[i]);
hex += buf;
}
return hex;
}
std::string sane_config::from_hex_letter(const char* data, size_t bytes)
std::string sane_config_schm::from_hex_letter(const char* data, size_t bytes)
{
std::string stream("");
@ -932,7 +1173,7 @@ namespace gb
for (size_t i = 0; i < bytes; ++i)
{
unsigned char ch = 0;
if (!sane_config::hex_char(data, &ch))
if (!sane_config_schm::hex_char(data, &ch))
break;
stream.append(1, ch);
data += 2;
@ -940,7 +1181,7 @@ namespace gb
return stream;
}
std::string sane_config::default_value(const char* hex_title)
std::string sane_config_schm::default_value(const char* hex_title)
{
std::string val("");
@ -949,42 +1190,28 @@ namespace gb
return val;
}
bool sane_config::load_from_file(const wchar_t* file)
bool sane_config_schm::load_from_file(const char* file)
{
clear();
bool ret = false;
FILE* src = _wfopen(file, L"rb");
if (src)
{
size_t size = 0;
char* buf = NULL;
gb::base64 b64;
std::string cont("");
fseek(src, 0, SEEK_END);
size = ftell(src);
fseek(src, 0, SEEK_SET);
buf = new char[size + 4];
memset(buf, 0, size + 4);
fread(buf, 1, size, src);
fclose(src);
ret = load_from_mem(buf);
delete[] buf;
}
file_ = file;
if (gb::load_mini_file(file, cont))
return false;
return ret;
return load_from_mem(cont.c_str());
}
bool sane_config::load_from_mem(const char* mem)
bool sane_config_schm::load_from_mem(const char* mem, bool in_b64)
{
gb::base64 b64;
std::string stream(b64.decode(mem, lstrlenA(mem)));
std::string stream(in_b64 ? b64.decode(mem, strlen(mem)) : mem);
clear();
jsn_ = new gb::json();
if (!jsn_->attach_text(&stream[0]))
{
delete jsn_;
jsn_->release();
jsn_ = NULL;
return false;
@ -992,7 +1219,7 @@ namespace gb
return true;
}
bool sane_config::save_to(const wchar_t* file)
bool sane_config_schm::save_to(const char* file)
{
bool ret = false;
std::string encode(to_text_stream());
@ -1002,7 +1229,7 @@ namespace gb
if (encode.length())
{
FILE* dst = _wfopen(file, L"wb");
FILE* dst = fopen(file, "wb");
if (dst)
{
@ -1014,43 +1241,43 @@ namespace gb
return ret;
}
void sane_config::set_default_value(int sn, const char* name, const char* val, size_t bytes)
void sane_config_schm::set_default_value(int sn, const char* name, const char* val, size_t bytes)
{
id_name_[sn] = name;
def_val_->set_value(name, to_hex_letter(val, bytes).c_str());
}
bool sane_config::first_config(std::string& name, std::string& val)
bool sane_config_schm::first_config(std::string& name, std::string& val)
{
bool ret = false;
std::string raw_v("");
if (jsn_ && jsn_->first_child(raw_v, &name))
{
val = sane_config::from_hex_letter(raw_v.c_str(), raw_v.length());
val = sane_config_schm::from_hex_letter(raw_v.c_str(), raw_v.length());
ret = true;
}
return ret;
}
bool sane_config::next_config(std::string& name, std::string& val)
bool sane_config_schm::next_config(std::string& name, std::string& val)
{
bool ret = false;
std::string raw_v("");
if (jsn_ && jsn_->next_child(raw_v, &name))
{
val = sane_config::from_hex_letter(raw_v.c_str(), raw_v.length());
val = sane_config_schm::from_hex_letter(raw_v.c_str(), raw_v.length());
ret = true;
}
return ret;
}
void sane_config::begin_setting(bool restore)
void sane_config_schm::begin_setting(bool restore)
{
if (bkp_)
delete bkp_;
bkp_->release();
bkp_ = jsn_;
in_setting_ = true;
jsn_ = new gb::json();
@ -1061,67 +1288,69 @@ namespace gb
jsn_->attach_text(&stream[0]);
}
}
void sane_config::config_changed(const char* name, const char* val, size_t bytes)
void sane_config_schm::config_changed(const char* name, const char* val, size_t bytes, bool extra)
{
std::string hex_v(to_hex_letter(val, bytes)),
def(default_value(name));
std::string hex_v(to_hex_letter(val, bytes));
if (hex_v == def)
jsn_->remove(name);
if (extra)
{
jsn_->set_value((name + sane_config_schm::opt_data_appendix_).c_str(), hex_v.c_str());
}
else
jsn_->set_value(name, hex_v.c_str());
{
std::string def = default_value(name);
if (hex_v == def)
{
jsn_->remove(name);
jsn_->remove((name + sane_config_schm::opt_data_appendix_).c_str());
}
else
jsn_->set_value(name, hex_v.c_str());
}
}
void sane_config::config_changed(int sn, const char* val, size_t bytes, bool extra)
void sane_config_schm::config_changed(int sn, const char* val, size_t bytes, bool extra)
{
std::string name(""),
hex_v(to_hex_letter(val, bytes)),
def("");
std::string name("");
if (id_name_.count(sn))
{
name = id_name_[sn];
if (extra)
{
name += sane_config::opt_data_appendix_;
jsn_->set_value(name.c_str(), hex_v.c_str());
}
else
{
def = default_value(name.c_str());
if (hex_v == def)
{
jsn_->remove(name.c_str());
jsn_->remove((name + sane_config::opt_data_appendix_).c_str());
}
else
jsn_->set_value(name.c_str(), hex_v.c_str());
}
config_changed(name.c_str(), val, bytes, extra);
}
}
void sane_config::remove_config(const char* name)
void sane_config_schm::remove_config(const char* name)
{
if (jsn_)
jsn_->remove(name);
}
void sane_config::end_setting(bool cancel)
void sane_config_schm::set_value(const char* name, const char* val, size_t bytes, bool extra)
{
std::string hex_v(to_hex_letter(val, bytes));
if (extra)
jsn_->set_value((name + sane_config_schm::opt_data_appendix_).c_str(), hex_v.c_str());
else
jsn_->set_value(name, hex_v.c_str());
}
void sane_config_schm::end_setting(bool cancel)
{
if (in_setting_)
{
if (cancel)
{
delete jsn_;
jsn_->release();
jsn_ = bkp_;
bkp_ = NULL;
}
else if (bkp_)
{
delete bkp_;
bkp_->release();
bkp_ = NULL;
}
}
in_setting_ = false;
}
int sane_config::id_from_name(const char* name)
int sane_config_schm::id_from_name(const char* name)
{
for (const auto& v : id_name_)
{
@ -1131,27 +1360,31 @@ namespace gb
return -1;
}
std::string sane_config::to_text_stream(void)
std::string sane_config_schm::to_text_stream(bool b64, bool with_ver)
{
if (jsn_)
{
if(with_ver)
{
char ver[40] = { 0 };
sprintf_s(ver, "%u.%u", VERSION_MAIN, VERSION_SUB);
sprintf(ver, "%u.%u", VERSION_MAIN, VERSION_SUB);
jsn_->set_value("ver", ver);
}
std::string cont(jsn_->to_string(false)), encode("");
gb::base64 b64;
std::string cont(jsn_->to_string(false));
if (b64)
{
gb::base64 b64;
encode = b64.encode(cont.c_str(), cont.length());
cont = b64.encode(cont.c_str(), cont.length());
}
return encode;
return cont;
}
else
return "";
}
std::string sane_config::get_version(void)
std::string sane_config_schm::get_version(void)
{
std::string ver("");
@ -1160,7 +1393,15 @@ namespace gb
return ver;
}
void sane_config::update(bool(__stdcall* is_float)(int, void*), void* param, const char* (__stdcall* t2n)(const char*), std::string* discard)
std::string sane_config_schm::get_scheme_name(void)
{
return scheme_name_;
}
void sane_config_schm::set_scheme_name(const char* name)
{
scheme_name_ = name ? name : "";
}
void sane_config_schm::update(bool(__stdcall* is_float)(int, void*), void* param, const char* (__stdcall* t2n)(const char*), std::string* discard)
{
if (!jsn_)
return;
@ -1184,7 +1425,7 @@ namespace gb
changed = true;
do
{
jsn_->change_key(name.c_str(), t2n(sane_config::from_hex_letter(name.c_str(), name.length()).c_str()));
jsn_->change_key(name.c_str(), t2n(sane_config_schm::from_hex_letter(name.c_str(), name.length()).c_str()));
} while (jsn_->next_child(val, &name));
}
}
@ -1207,10 +1448,296 @@ namespace gb
} while (jsn_->next_child(val, &name));
}
}
sprintf_s(vs, _countof(vs) - 1, "%u.%u", VERSION_MAIN, VERSION_SUB);
sprintf(vs, "%u.%u", VERSION_MAIN, VERSION_SUB);
jsn_->set_value("ver", vs);
if (changed)
save_to(NULL);
}
///////////////////////////////////////////////////////////////////////////////////
// scanner_cfg
std::string scanner_cfg::global_name_ = "global";
std::string scanner_cfg::cur_sel_ = "cur";
std::string scanner_cfg::default_setting_name_ = "\351\273\230\350\256\244\350\256\276\347\275\256"; // utf-8: 默认设置
scanner_cfg::scanner_cfg() : path_(""), scanner_name_(""), global_(new json())
{
init_version();
init_select();
}
scanner_cfg::~scanner_cfg()
{
clear();
global_->release();
}
bool scanner_cfg::update(const char* file, LPUDF func)
{
std::string cont(""), name(""), path(file);
int ret = gb::load_mini_file(file, cont);
base64 b64;
json *jsn = nullptr;
bool ok = true;
if (ret)
return false;
else if (cont.empty())
return true;
cont = b64.decode(cont.c_str(), cont.length());
jsn = new json();
if (!jsn->attach_text(&cont[0]))
{
jsn->release();
return false;
}
cont = "";
ret = path.rfind(PATH_SYMBOL[0]);
if (ret++ != std::string::npos)
path.erase(ret);
if (jsn->first_child(cont, &name))
{
do
{
ok &= updater::update_app_config(name.c_str(), cont.c_str(), path.c_str(), func) == 0;
} while (jsn->next_child(cont, &name));
}
jsn->release();
if (ok)
rename(file, (std::string(file) + "_bk").c_str());
return true;
}
void scanner_cfg::clear(void)
{
global_->set_value("ver", "");
global_->set_value(scanner_cfg::cur_sel_.c_str(), -1);
for (size_t i = 0; i < schemes_.size(); ++i)
schemes_[i].schm->release();
schemes_.clear();
scanner_name_ = "";
}
void scanner_cfg::init_version(void)
{
char vstr[40] = { 0 };
sprintf(vstr, "%u.%u", VERSION_MAIN, VERSION_SUB);
global_->set_value("ver", vstr);
}
void scanner_cfg::init_select(void)
{
global_->set_value(scanner_cfg::cur_sel_.c_str(), -1);
}
void scanner_cfg::walk_sibling_schemes(cJSON* first)
{
if (!first)
return;
cJSON* next = first->next;
std::string name(first->string ? "" : first->string),
cont("");
CFGSCHM sch;
first->next = nullptr;
cont = json::to_string(first, false);
if (name == scanner_cfg::global_name_)
{
global_->attach_text(&cont[0]);
}
else
{
sch.schm = new sane_config_schm();
if (sch.schm->load_from_mem(cont.c_str(), false))
{
sch.name = sane_config_schm::from_hex_letter(name.c_str(), name.length());
sch.schm->set_scheme_name(sch.name.c_str());
schemes_.push_back(sch);
}
else
sch.schm->release();
}
first->next = next;
walk_sibling_schemes(next);
}
int scanner_cfg::load_file(const char* file)
{
std::string cont("");
int ret = gb::load_mini_file(file, cont);
if (ret == 0)
ret = load_mem(cont.c_str());
if (ret == 0 && scanner_name_.empty())
{
const char* name = strrchr(file, PATH_SYMBOL[0]);
if (name++ == nullptr)
name = file;
scanner_name_ = name;
ret = scanner_name_.rfind('.');
if (ret != std::string::npos)
scanner_name_.erase(ret);
ret = 0;
}
return ret;
}
int scanner_cfg::load_mem(const char* mem)
{
cJSON* root = cJSON_Parse(mem);
if (!root)
return EINVAL;
clear();
walk_sibling_schemes(root->child);
cJSON_Delete(root);
return 0;
}
int scanner_cfg::save(const char* file)
{
if (!file && path_.empty() && scanner_name_.empty())
return EINVAL;
std::string cont("{\"" + scanner_cfg::global_name_ + "\":"),
f(file ? file : path_ + scanner_name_),
v("");
int sel = -1;
if (!global_->get_value("ver", v) || v.empty())
init_version();
if (!global_->get_value(scanner_cfg::cur_sel_.c_str(), sel) || sel >= schemes_.size())
init_select();
cont += global_->to_string(false);
for (auto& v: schemes_)
{
cont += ",\"" + sane_config_schm::to_hex_letter(v.name.c_str(), v.name.length()) + "\":";
cont += v.schm->to_text_stream(false, false);
}
cont += "}";
base64 b64;
FILE* dst = fopen(f.c_str(), "wb");
if (!dst)
return errno;
f = b64.encode(cont.c_str(), cont.length());
fwrite(f.c_str(), 1, f.length(), dst);
fclose(dst);
return 0;
}
void scanner_cfg::get_all_schemes(std::vector<std::string>& schemes)
{
schemes.push_back(scanner_cfg::default_setting_name_);
for (auto& v : schemes_)
schemes.push_back(v.name);
}
sane_config_schm* scanner_cfg::get_scheme(const char* scheme_name)
{
sane_config_schm* found = nullptr;
if (scheme_name)
{
std::vector<CFGSCHM>::iterator it = std::find(schemes_.begin(), schemes_.end(), scheme_name);
if (it != schemes_.end())
found = it->schm;
}
else
{
int ind = -1;
global_->get_value(scanner_cfg::cur_sel_.c_str(), ind);
if (ind >= 0 && ind < schemes_.size())
found = schemes_[ind].schm;
}
if (found)
found->add_ref();
return found;
}
bool scanner_cfg::remove_scheme(const char* scheme_name)
{
std::vector<CFGSCHM>::iterator it = std::find(schemes_.begin(), schemes_.end(), scheme_name);
if (it != schemes_.end())
{
int id = it - schemes_.begin(),
ind = -1;
it->schm->release();
schemes_.erase(it);
global_->get_value(scanner_cfg::cur_sel_.c_str(), ind);
if (ind == id)
global_->set_value(scanner_cfg::cur_sel_.c_str(), -1);
else if (ind > id)
global_->set_value(scanner_cfg::cur_sel_.c_str(), ind - 1);
return true;
}
return false;
}
bool scanner_cfg::select_scheme(const char* scheme_name)
{
std::vector<CFGSCHM>::iterator it = std::find(schemes_.begin(), schemes_.end(), scheme_name);
if (it == schemes_.end())
global_->set_value(scanner_cfg::cur_sel_.c_str(), -1);
else
global_->set_value(scanner_cfg::cur_sel_.c_str(), (int)(it - schemes_.begin()));
return true;
}
sane_config_schm* scanner_cfg::copy_scheme(const char* cp_from_name) // for UI setting, call release() if not use anymore
{
if (!cp_from_name)
return nullptr;
else if (scanner_cfg::default_setting_name_ == cp_from_name)
return new sane_config_schm();
else
{
std::vector<CFGSCHM>::iterator it = std::find(schemes_.begin(), schemes_.end(), cp_from_name);
if (it == schemes_.end())
return nullptr;
std::string cont(it->schm->to_text_stream());
sane_config_schm* schm = new sane_config_schm();
schm->load_from_mem(cont.c_str());
return schm;
}
}
bool scanner_cfg::add_scheme(sane_config_schm* schm, const char* name)
{
if (name && std::find(schemes_.begin(), schemes_.end(), name) != schemes_.end())
return false;
CFGSCHM cs;
cs.name = name ? name : schm->get_scheme_name();
cs.schm = schm;
if (cs.name == scanner_cfg::global_name_)
return false;
schemes_.push_back(cs);
schm->set_scheme_name(cs.name.c_str());
schm->add_ref();
return true;
}
}

View File

@ -2,6 +2,9 @@
#if defined(WIN32) || defined(_WIN64)
#include <Windows.h>
#define PATH_SYMBOL "\\"
#else
#define PATH_SYMBOL "/"
#endif
// #include "cJSON.h"
@ -12,7 +15,22 @@
namespace gb
{
class json
class scanner_cfg;
class refer
{
volatile long ref_;
protected:
refer();
virtual ~refer();
public:
long add_ref(void);
long release(void);
};
class json : public refer
{
cJSON *obj_;
cJSON *cur_child_;
@ -23,9 +41,11 @@ namespace gb
cJSON* find_child(cJSON *parent, std::vector<std::string>& path, bool create, cJSON*** addr = NULL);
cJSON* find(const char* path, bool create = false, cJSON*** addr = NULL);
protected:
~json();
public:
json(char* json_txt = 0);
~json();
static std::string to_string(cJSON* root, bool formatted);
static std::string get_value_as_string(cJSON* root, bool integer = false);
@ -82,44 +102,120 @@ namespace gb
std::string decode(const char* data, size_t bytes);
};
class sane_config
class sane_config_schm : public refer
{
std::wstring file_;
std::string scheme_name_;
scanner_cfg *scanner_;
std::string file_;
json* jsn_;
json* bkp_;
json* def_val_;
bool in_setting_;
std::map<int, std::string> id_name_;
std::map<int, std::string> id_name_; // (id, default-val)
void clear();
std::string to_hex_letter(const char* data, size_t bytes);
std::string from_hex_letter(const char* data, size_t bytes);
std::string default_value(const char* name);
protected:
~sane_config_schm();
public:
sane_config();
~sane_config();
sane_config_schm(scanner_cfg* scanner = nullptr);
static std::string opt_data_appendix_;
static bool hex(unsigned char ch, unsigned char* val);
static bool hex_char(const char* data, unsigned char* val);
static std::string to_hex_letter(const char* data, size_t bytes);
static std::string from_hex_letter(const char* data, size_t bytes);
static bool is_option_data(std::string& name); // reset baase option name into 'name' if name was option data, and return true
public:
bool load_from_file(const wchar_t* file);
bool load_from_mem(const char* mem);
bool save_to(const wchar_t* file);
bool load_from_file(const char* file);
bool load_from_mem(const char* mem, bool in_b64 = true);
bool save_to(const char* file);
void set_default_value(int sn, const char* name, const char* val, size_t bytes);
bool first_config(std::string& name, std::string& val);
bool next_config(std::string& name, std::string& val);
void begin_setting(bool restore = false);
void config_changed(const char* name, const char* val, size_t bytes);
void config_changed(const char* name, const char* val, size_t bytes, bool extra = false);
void config_changed(int sn, const char* val, size_t bytes, bool extra = false);
void remove_config(const char* name);
void set_value(const char* name, const char* val, size_t bytes, bool extra = false);
void end_setting(bool cancel);
int id_from_name(const char* name);
std::string to_text_stream(void);
std::string to_text_stream(bool b64 = true, bool with_ver = true);
std::string get_version(void);
std::string get_scheme_name(void);
void set_scheme_name(const char* name);
void update(bool(__stdcall* is_float)(int, void*), void* param, const char*(__stdcall* t2n)(const char*), std::string* discard = NULL);
};
class scanner_cfg : public refer
{
// format: in base64
//
// {
// "global": {
// "ver": "4.33",
// "cur": -1
// },
// "scheme_1": sane_config_schm*,
// "scheme_2": sane_config_schm*,
// "scheme_3": sane_config_schm*,
// ...
// }
//
std::string path_;
std::string scanner_name_; // scanner type: HUAGOSCAN G100 - 0100
json *global_; // version, current scheme, ...
typedef struct _cfg_schm
{
std::string name;
sane_config_schm* schm;
bool operator==(const char* n)
{
return name == n;
}
}CFGSCHM;
std::vector<CFGSCHM> schemes_;
static std::string global_name_;
static std::string cur_sel_;
static std::string default_setting_name_;
void clear(void);
void init_version(void);
void init_select(void);
void walk_sibling_schemes(cJSON* first);
protected:
~scanner_cfg();
public:
scanner_cfg();
typedef struct _update_func
{
void(__stdcall* trans_number)(const char* name, std::string& val, void* param);
const char* (__stdcall* title2name)(const char* title, void* param);
std::string discard_msg; // update failed items ...
void* func_param;
}UDF, *LPUDF;
static bool update(const char* file, LPUDF func);
public:
int load_file(const char* file);
int load_mem(const char* mem);
int save(const char* file = nullptr);
void get_all_schemes(std::vector<std::string>& schemes); // return all schemes name queue, the first is always be 'Default settings'
sane_config_schm* get_scheme(const char* scheme_name = nullptr/*return current scheme if was null*/); // call sane_config_schm::release() if not use anymore
bool remove_scheme(const char* scheme_name);
bool select_scheme(const char* scheme_name);
sane_config_schm* copy_scheme(const char* cp_from_name); // for UI setting, call release() if not use anymore
bool add_scheme(sane_config_schm* schm, const char* name = nullptr);
};
}

View File

@ -150,6 +150,7 @@ struct __declspec(novtable) ISaneInvoker : public IRef
COM_API_DECLARE(int, start(void));
COM_API_DECLARE(int, stop(void));
COM_API_DECLARE(int, get_event(void));
COM_API_DECLARE(void, set_event_callback(int(__stdcall* handle_ev)(int, void*) = NULL, void* para = NULL));
COM_API_DECLARE(bool, wait_image(DWORD milliseconds = -1));
COM_API_DECLARE(int, get_scanned_images(DWORD milliseconds = 0));
COM_API_DECLARE(IScanImg*, take_first_image(twain_xfer xfer = TWAIN_XFER_Native)); // call 'release' on returned value, plz
@ -244,6 +245,7 @@ struct __declspec(novtable) ISaneInvoker : public IRef
SANE_OPTION_ID_API(search_hole_range_t); // 穿孔搜索范围 - 上
SANE_OPTION_ID_API(is_erase_hole_b); // 穿孔移除 - 下
SANE_OPTION_ID_API(search_hole_range_b); // 穿孔搜索范围 - 下
SANE_OPTION_ID_API(fold_direction); // 对折模式
// SANE-ex option ID:
SANE_OPTION_ID_API_EX(multiout_type); // int

View File

@ -271,8 +271,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 4,32,10000,22287
PRODUCTVERSION 4,32,10000,22287
FILEVERSION 4,33,10000,22297
PRODUCTVERSION 4,33,10000,22297
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -289,12 +289,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "宁波华高信息科技有限公司"
VALUE "FileDescription", "华高扫描仪应用程序"
VALUE "FileVersion", "4.32.10000.22287"
VALUE "FileVersion", "4.33.10000.22297"
VALUE "InternalName", "sane.dll"
VALUE "LegalCopyright", "Copyright (C) HUAGOScan 2022"
VALUE "OriginalFilename", "sane.dll"
VALUE "ProductName", "HUAGOScan"
VALUE "ProductVersion", "4.32.10000.22287"
VALUE "ProductVersion", "4.33.10000.22297"
END
END
BLOCK "VarFileInfo"

View File

@ -15,7 +15,6 @@
#pragma comment(lib, "Shlwapi.lib")
static IMPLEMENT_OPTION_STRING_COMPARE(compare_sane_opt);
#define SET_SANE_OPT_ID(id, id_name, name, val, extension) \
@ -55,6 +54,7 @@ extern "C"
extern SANE_Status inner_sane_init_ex(SANE_Int* version_code, sane_callback cb, void* param);
extern SANE_Status inner_sane_io_control(SANE_Handle h, unsigned long code, void* data, unsigned* len);
extern const char* inner_sane_err_desc(SANE_Status err);
}
namespace callback
@ -229,6 +229,91 @@ namespace callback
return "";
}
static BOOL CALLBACK main_wnd(HWND hwnd, LPARAM param)
{
DWORD pid = 0;
GetWindowThreadProcessId(hwnd, &pid);
if (pid != GetCurrentProcessId())
return TRUE;
if (((void**)param)[1] == NULL)
{
HWND parent = GetParent(hwnd);
while (IsWindow(parent))
{
hwnd = parent;
parent = GetParent(hwnd);
}
parent = hwnd;
if (!IsWindowVisible(parent))
return TRUE;
RECT r = { 0 };
GetWindowRect(parent, &r);
if (RECT_H(r) > 50 && RECT_W(r) > 50)
{
*(HWND*)param = parent;
return FALSE;
}
}
else
{
wchar_t val[128] = { 0 };
GetClassNameW(hwnd, val, _countof(val) - 1);
if (wcscmp(val, L"#32770"))
return TRUE;
GetWindowTextW(hwnd, val, _countof(val) - 1);
if (*((std::wstring**)param)[1] == val)
{
*(HWND*)param = hwnd;
return FALSE;
}
}
return TRUE;
}
static HWND find_main_wnd(void)
{
HWND wnd[2] = { NULL };
EnumWindows(main_wnd, (LPARAM)wnd);
return wnd[0];
}
static DWORD WINAPI btm(LPVOID para)
{
std::wstring* title[2] = { NULL, (std::wstring*)para };
Sleep(100);
EnumWindows(main_wnd, (LPARAM)title);
if (IsWindow((HWND)title[0]))
{
RECT r = { 0 };
GetWindowRect((HWND)title[0], &r);
SetWindowPos((HWND)title[0], HWND_TOPMOST, r.left, r.top, RECT_W(r), RECT_H(r), SWP_SHOWWINDOW | SWP_NOSENDCHANGING);
SetFocus((HWND)title[0]);
}
delete title[1];
return 0;
}
static void bring_message_box_topmost(const wchar_t* title)
{
DWORD id = 0;
std::wstring* t(new std::wstring(title));
HANDLE h = CreateThread(NULL, 0, btm, t, 0, &id);
if (h)
CloseHandle(h);
else
delete t;
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -236,8 +321,9 @@ namespace callback
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)
, scanner_name_(L""), cfg_(NULL), is_ui_wait_img_(false), is_scanning_(false)
, scanner_ev_handler_(NULL), evh_param_(NULL), app_wnd_(NULL)
{
cfg_ = new gb::sane_config();
cfg_ = new gb::sane_config_schm();
tmp_path_ = local_trans::a2u(hg_sane_middleware::sane_path().c_str());
{
char* tmp = getenv("LOCALAPPDATA");
@ -264,7 +350,10 @@ scanner::~scanner()
{
close();
if (cfg_)
delete cfg_;
{
cfg_->release();
cfg_ = NULL;
}
}
bool scanner::is_belong_serial(int vid, int pid, SCANNERID serial)
@ -463,17 +552,19 @@ void scanner::update_config(void)
notice.erase(0, pos + 2);
pos = notice.find("\r\n");
}
MessageBoxW(NULL, msg.c_str(), L"\u52A0\u8F7D\u914D\u7F6E", MB_OK | MB_ICONINFORMATION);
if (!IsWindow(app_wnd_))
callback::bring_message_box_topmost(L"\u52A0\u8F7D\u914D\u7F6E");
MessageBoxW(app_wnd_, msg.c_str(), L"\u52A0\u8F7D\u914D\u7F6E", MB_OK | MB_ICONINFORMATION);
}
}
void scanner::load_config(const wchar_t* file)
{
cfg_->load_from_file(file);
cfg_->load_from_file(local_trans::u2a(file).c_str());
update_config();
}
void scanner::save_config(const wchar_t* file)
{
cfg_->save_to(file);
cfg_->save_to(local_trans::u2a(file).c_str());
}
void scanner::apply_config(void)
{
@ -486,7 +577,7 @@ void scanner::apply_config(void)
int id = cfg_->id_from_name(n.c_str());
if (id == -1)
{
if (gb::sane_config::is_option_data(n))
if (gb::sane_config_schm::is_option_data(n))
{
id = cfg_->id_from_name(n.c_str());
if (id == is_custom_gamma_id_)
@ -534,22 +625,54 @@ void scanner::apply_config(void)
void scanner::on_ui_event(int uev, void* sender)
{
bool indicator = sender == indicator_.get();
if (uev == SANE_EVENT_SCAN_FINISHED || uev == SANE_EVENT_UI_CLOSE_NORMAL || uev == SANE_EVENT_UI_CLOSE_CANCEL)
{
if (indicator)
indicator_.reset();
if (err_ && setting_.get())
{
return;
}
is_scanning_ = false;
}
int(__stdcall * h)(int, void*) = scanner_ev_handler_;
if (h)
{
if (SANE_EVENT_UI_CLOSE_SETTING == uev)
{
is_scanning_ = false;
setting_.reset();
}
h(uev, evh_param_);
return;
}
if (prev_start_result_ != SANE_STATUS_GOOD && indicator)
indicator_.reset();
else
{
if (uev == SANE_EVENT_UI_SCAN_COMMAND)
{
ui_show_progress(NULL);
start();
return;
}
if (/*events_.count() > 5 && !is_ui_wait_img_ &&*/
(uev == SANE_EVENT_UI_CLOSE_CANCEL || uev == SANE_EVENT_UI_CLOSE_NORMAL || uev == SANE_EVENT_UI_CLOSE_SETTING))
{
events_.clear();
ui_hide();
if(indicator)
events_.save(SANE_EVENT_SCAN_FINISHED);
if(indicator || !indicator_.get())
uev = SANE_EVENT_SCAN_FINISHED;
else
events_.save(SANE_EVENT_UI_CLOSE_SETTING);
uev = SANE_EVENT_UI_CLOSE_SETTING;
}
else
events_.save(uev);
events_.save(uev);
}
}
std::string scanner::choose_scanner(const std::vector<std::string>& scanners)
@ -627,13 +750,18 @@ int scanner::open(void)
else
{
std::wstring msg(local_trans::a2u(hg_scanner_err_description(ret), CP_UTF8));
MessageBoxW(NULL, msg.c_str(), L"\u6253\u5F00\u5931\u8D25", MB_OK | MB_ICONERROR);
HWND parent = callback::find_main_wnd();
if (!IsWindow(parent))
callback::bring_message_box_topmost(L"\u6253\u5F00\u5931\u8D25");
MessageBoxW(parent, msg.c_str(), L"\u6253\u5F00\u5931\u8D25", MB_OK | MB_ICONERROR);
}
return ret;
}
int scanner::close(void)
{
scanner_ev_handler_ = NULL;
ui_hide();
callback::unreg_callback(this);
if (handle_)
@ -752,6 +880,7 @@ int scanner::init_options_id(void)
else SET_OPT_ID(search_hole_range_t, SEARCH_HOLE_RANGE_T, extension_none)
else SET_OPT_ID(is_erase_hole_b, RID_HOLE_B, extension_none)
else SET_OPT_ID(search_hole_range_b, SEARCH_HOLE_RANGE_B, extension_none)
else SET_OPT_ID(fold_direction, FOLD_TYPE, extension_none)
op_id++;
}
@ -2028,6 +2157,7 @@ COM_API_IMPLEMENT(scanner, int, start(void))
images_.clear();
scan_msg_ = "OK";
scan_err_ = false;
app_wnd_ = setting_.get() ? setting_->hwnd() : callback::find_main_wnd();
ret = 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 ...
@ -2052,10 +2182,12 @@ COM_API_IMPLEMENT(scanner, int, start(void))
else
{
std::wstring msg(local_trans::a2u(hg_scanner_err_description(ret), CP_UTF8));
HWND parent = setting_.get() ? setting_->hwnd() : NULL;
if (indicator_.get())
indicator_->show(false);
MessageBoxW(parent, msg.c_str(), L"\u542F\u52A8\u5931\u8D25", MB_OK | MB_ICONERROR);
if (!IsWindow(app_wnd_))
callback::bring_message_box_topmost(L"\u542F\u52A8\u5931\u8D25");
MessageBoxW(app_wnd_, msg.c_str(), L"\u542F\u52A8\u5931\u8D25", MB_OK | MB_ICONERROR);
}
prev_start_result_ = ret;
is_scanning_ = ret == SANE_STATUS_GOOD;
@ -2070,6 +2202,11 @@ COM_API_IMPLEMENT(scanner, int, get_event(void))
{
return events_.take();
}
COM_API_IMPLEMENT(scanner, void, set_event_callback(int(__stdcall* handle_ev)(int, void*), void* para))
{
scanner_ev_handler_ = handle_ev;
evh_param_ = para;
}
COM_API_IMPLEMENT(scanner, bool, wait_image(DWORD milliseconds))
{
int count = get_scanned_images(milliseconds);
@ -2427,6 +2564,7 @@ SANE_OPTION_ID_IMPLEMENT(is_erase_hole_t)
SANE_OPTION_ID_IMPLEMENT(search_hole_range_t)
SANE_OPTION_ID_IMPLEMENT(is_erase_hole_b)
SANE_OPTION_ID_IMPLEMENT(search_hole_range_b)
SANE_OPTION_ID_IMPLEMENT(fold_direction)
// SANE-ex option ID:
SANE_OPTION_ID_IMPLEMENT(ex_multiout_type)
@ -2542,8 +2680,10 @@ COM_API_IMPLEMENT(scanner, bool, ui_show_setting(HWND parent, bool with_scan, bo
}
COM_API_IMPLEMENT(scanner, bool, ui_show_progress(HWND parent))
{
if(setting_.get() && IsWindowVisible(setting_->hwnd()))
if (setting_.get() && IsWindowVisible(setting_->hwnd()))
parent = setting_->hwnd();
else if (!IsWindow(parent))
parent = callback::find_main_wnd();
indicator_.reset(new dlg_indicator(parent));
indicator_->set_ui_event_notify(&scanner::ui_callback, this);
@ -2573,7 +2713,7 @@ int scanner::handle_device_event(int ev_code, void* data, unsigned int* len)
if (indicator_.get())
indicator_->notify_working();
else
events_.save(ev_code);
on_ui_event(ev_code, (void*)ev_code);
log_info(L"Scanning ...\r\n", 0);
}
@ -2610,11 +2750,21 @@ int scanner::handle_device_event(int ev_code, void* data, unsigned int* len)
}
else if (ev_code == SANE_EVENT_SCAN_FINISHED)
{
err_ = *len;
if (indicator_.get())
indicator_->notify_scan_over((char*)data, *len != SCANNER_ERR_OK);
else
events_.save(ev_code);
is_scanning_ = false;
{
if (*len)
{
std::wstring msg(local_trans::a2u((char*)data, CP_UTF8));
if(!IsWindow(app_wnd_))
callback::bring_message_box_topmost(L"\u9519\u8BEF");
MessageBoxW(app_wnd_, msg.c_str(), L"\u9519\u8BEF", MB_OK);
}
on_ui_event(ev_code, (void*)ev_code);
}
// is_scanning_ = false;
{
wchar_t msg[128] = { 0 };

View File

@ -26,7 +26,7 @@ class dlg_indicator;
class dlg_setting;
namespace gb
{
class sane_config;
class sane_config_schm;
}
class scanner : public ISaneInvoker, virtual public refer
@ -51,7 +51,11 @@ class scanner : public ISaneInvoker, virtual public refer
SANE_FinalImgFormat img_fmt_;
std::unique_ptr<dlg_indicator> indicator_;
std::unique_ptr<dlg_setting> setting_;
gb::sane_config* cfg_;
gb::sane_config_schm* cfg_;
int(__stdcall* scanner_ev_handler_)(int, void*);
void* evh_param_;
HWND app_wnd_; // for MessageBox
void transport_config_file(void);
void update_config(void);
@ -204,6 +208,7 @@ public:
COM_API_OVERRIDE(int, start(void));
COM_API_OVERRIDE(int, stop(void));
COM_API_OVERRIDE(int, get_event(void));
COM_API_OVERRIDE(void, set_event_callback(int(__stdcall* handle_ev)(int, void*) = NULL, void* para = NULL));
COM_API_OVERRIDE(bool, wait_image(DWORD milliseconds = -1));
COM_API_OVERRIDE(int, get_scanned_images(DWORD milliseconds = 0));
COM_API_OVERRIDE(IScanImg*, take_first_image(twain_xfer xfer = TWAIN_XFER_Native)); // call 'release' on returned value, plz
@ -287,6 +292,7 @@ public:
SANE_OPTION_ID(search_hole_range_t); // 穿孔搜索范围 - 上
SANE_OPTION_ID(is_erase_hole_b); // 穿孔移除 - 下
SANE_OPTION_ID(search_hole_range_b); // 穿孔搜索范围 - 下
SANE_OPTION_ID(fold_direction); // 对折模式
// SANE-ex option ID:
SANE_OPTION_ID(ex_multiout_type); // int

View File

@ -91,20 +91,27 @@ namespace load_sane_util
{
HMODULE h = LoadLibraryW(path_dll);
int ret = GetLastError();
wchar_t info[128] = { 0 };
swprintf_s(info, _countof(info) - 1, L" = %d\r\n", ret);
OutputDebugStringW((L"[TWAIN]Load: " + std::wstring(path_dll) + info).c_str());
if (!h && ret == ERROR_MOD_NOT_FOUND)
{
std::wstring dir(path_dll);
size_t pos = dir.rfind(L'\\');
wchar_t path[MAX_PATH] = { 0 };
GetCurrentDirectoryW(_countof(path) - 1, path);
GetDllDirectoryW(_countof(path) - 1, path);
if (pos != std::wstring::npos)
dir.erase(pos);
SetCurrentDirectoryW(dir.c_str());
OutputDebugStringW((L"[TWAIN]Load: try change directory to " + dir + L"\r\n").c_str());
SetDllDirectoryW(dir.c_str());
h = LoadLibraryW(path_dll);
ret = GetLastError();
SetCurrentDirectoryW(path);
swprintf_s(info, _countof(info) - 1, L" = %d\r\n", ret);
OutputDebugStringW((L"[TWAIN]Load: " + std::wstring(path_dll) + info).c_str());
OutputDebugStringW((L"[TWAIN]Load: restore directory to " + std::wstring(path) + L"\r\n").c_str());
SetDllDirectoryW(path);
}
if (dll)
@ -142,6 +149,13 @@ namespace load_sane_util
}
bool is_ok(void)
{
wchar_t info[128] = { 0 };
swprintf_s(info, _countof(info) - 1, L"[TWAIN]Load: sane_inst: %s, is_on: %s, init: %s, uninit: %s\r\n"
, sane_inst != NULL ? "ok" : "not found"
, is_on != NULL ? "ok" : "not found"
, init != NULL ? "ok" : "not found"
, uninit != NULL ? "ok" : "not found");
return sane_inst != NULL && is_on != NULL && init != NULL && uninit != NULL;
}
bool is_online(SCANNERID guid)

View File

@ -138,7 +138,9 @@ enum CapTypeEx : unsigned short {
CAP_EX_SANE_is_erase_hole_t,
CAP_EX_SANE_search_hole_range_t,
CAP_EX_SANE_is_erase_hole_b,
CAP_EX_SANE_search_hole_range_b, // END for SANE设备层原始设置项透传属性
CAP_EX_SANE_search_hole_range_b,
CAP_EX_SANE_fold_direction,
// END for SANE设备层原始设置项透传属性
/////////////////////////////////////////////////////////////////////////
};
enum // .twain/first.cfg: [twain-app] flow=0
@ -604,7 +606,24 @@ float trans_range(float val, float min_from, float max_from, float min_to, float
return val;
}
static void log_attr_access(int attr, int method)
{
wchar_t msg[128] = { 0 };
const wchar_t* op = L"Unknown Oper";
#define METHOD_DESC(oper) \
if (method == (int)Msg::oper) \
op = L###oper;
METHOD_DESC(Set)
else METHOD_DESC(Reset)
else METHOD_DESC(Get)
else METHOD_DESC(GetCurrent)
else METHOD_DESC(GetDefault)
swprintf_s(msg, _countof(msg) - 1, L"%s %04x\r\n", op, attr);
load_sane_util::log_info(msg, 0);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// huagao_ds ...
@ -654,6 +673,10 @@ void huagao_ds::showmsg(const char* msg, int err)
{
ShellExecuteA(NULL, "open", huagao_ds::get_hidedlg_path().c_str(), msg, NULL, SW_HIDE);
}
int __stdcall huagao_ds::on_scanner_event(int ev, void* param)
{
return ((huagao_ds*)param)->handle_scanner_event(ev);
}
const Identity& huagao_ds::defaultIdentity() noexcept {
// remember, we return a reference, therefore the identity must not be placed on the stack of this method
@ -741,49 +764,17 @@ Result huagao_ds::capabilitySet(const Identity& origin, Capability& data)
}
Result huagao_ds::eventProcess(const Identity&, Event& event)
{
static int count_0 = 0;
const MSG* msg = (const MSG*)event.event();
if (scanner_.get())
{
int ev = scanner_->get_event();
if (ev == 0)
count_0++;
else
{
wchar_t msg[128] = { 0 };
if(count_0)
swprintf_s(msg, _countof(msg) - 1, L"ds::eventProcess(0x0 +%d)\r\nds::eventProcess(0x%x)\r\n", count_0, ev);
else
swprintf_s(msg, _countof(msg) - 1, L"ds::eventProcess(0x%x)\r\n", ev);
load_sane_util::log_info(msg, 0);
count_0 = 0;
}
switch (ev)
{
case SANE_EVENT_WORKING:
notifyXferReady();
break;
case SANE_EVENT_UI_CLOSE_CANCEL:
scanner_->stop();
// notifyEndWithoutImages();
break;
case SANE_EVENT_UI_CLOSE_NORMAL:
scanner_->ui_hide();
case SANE_EVENT_SCAN_FINISHED:
//notifyCloseOk();
//break;
case SANE_EVENT_UI_CLOSE_SETTING:
notifyCloseCancel();
break;
case SANE_EVENT_UI_SCAN_COMMAND:
scanner_->ui_show_progress(NULL);
scanner_->start();
break;
}
if(ev)
handle_scanner_event(ev);
}
// event.setMessage(Msg::Null);
return { ReturnCode::NotDsEvent, ConditionCode::Success };
}
Twpp::Result huagao_ds::deviceEventGet(const Twpp::Identity& origin, Twpp::DeviceEvent& data)
@ -837,6 +828,7 @@ Result huagao_ds::identityOpenDs(const Identity& id)
return { ReturnCode::Failure, huagao_ds::condition_code_from_hg_error(err) };
}
// ui_.reset(new twain_ui(local_utility::reg_get_app_installing_path().c_str()));
scanner_->set_event_callback(&huagao_ds::on_scanner_event, this);
if (get_config_number(L"twain-app", L"flow") == TWAIN_APP_TRANSFER_REVERSE)
{
cur_head_ = new SANE_Parameters;
@ -854,6 +846,7 @@ Result huagao_ds::identityCloseDs(const Identity&)
// ui_.reset();
if (scanner_.get())
{
scanner_->set_event_callback();
scanner_.reset();
}
if (singleton_)
@ -952,8 +945,8 @@ Result huagao_ds::userInterfaceEnable(const Identity&, UserInterface& ui)
}
else
{
if (err == SCANNER_ERR_DEVICE_NO_PAPER)
return { ReturnCode::Failure, ConditionCode::NoMedia };
// if (err == SCANNER_ERR_DEVICE_NO_PAPER)
return { ReturnCode::Failure, huagao_ds::condition_code_from_hg_error(err) };
return bummer();
}
@ -984,7 +977,7 @@ Result huagao_ds::imageInfoGet(const Identity&, ImageInfo& data)
if (!scanner_->wait_image())
{
notifyCloseOk();
return bummer();
return success(); // 好分数需要返回成功
}
ok = scanner_->get_first_image_header(&head);
}
@ -1394,6 +1387,7 @@ void huagao_ds::init_support_caps(void)
m_query[CapType::SupportedCaps] = msgSupportGetAll;
m_caps[CapType::SupportedCaps] = [this](Msg msg, Capability& data) {
log_attr_access((int)CapType::SupportedCaps, (int)msg);
if ((msg == Msg::Get) || (Msg::GetCurrent == msg) || (Msg::GetDefault == msg)) {
data = Capability::createArray<CapType::SupportedCaps>(m_caps.size());
auto arr = data.array<CapType::SupportedCaps>();
@ -1414,6 +1408,7 @@ void huagao_ds::init_support_caps(void)
m_query[CapType::XferCount] = msgSupportGetAllSetReset;
m_caps[CapType::XferCount] = [this](Msg msg, Capability& data) -> Result {
log_attr_access((int)CapType::XferCount, (int)msg);
if (msg == Msg::Set) {
auto item = data.currentItem<Int16>();
if (item > 65535 || item < -1 || item == 0) {
@ -1439,6 +1434,7 @@ void huagao_ds::init_support_caps(void)
m_query[CapType::Indicators] = msgSupportGetAllSetReset;
m_caps[CapType::Indicators] = [this](Msg msg, Capability& data) -> Result {
log_attr_access((int)CapType::Indicators, (int)msg);
if (Msg::Set == msg) {
auto show = data.currentItem<CapType::Indicators>();
m_bIndicator = show;
@ -1451,7 +1447,8 @@ void huagao_ds::init_support_caps(void)
m_query[CapType::DeviceOnline] = msgSupportGetAll;
m_caps[CapType::DeviceOnline] = [this](Msg msg, Capability& data) -> Result {
CapabilityPrintf(msg, enum2str(CapType::DeviceOnline));
log_attr_access((int)CapType::DeviceOnline, (int)msg);
// CapabilityPrintf(msg, enum2str(CapType::DeviceOnline));
switch (msg) {
case Msg::Get:
case Msg::GetCurrent:
@ -1469,6 +1466,7 @@ void huagao_ds::init_support_caps(void)
m_query[CapType::ICompression] = msgSupportGetAllSetReset;
m_caps[CapType::ICompression] = [this](Msg msg, Capability& data)->Result {
log_attr_access((int)CapType::ICompression, (int)msg);
if (!scanner_.get())
return seqError();
if (Msg::Set == msg) {
@ -1518,6 +1516,7 @@ void huagao_ds::init_support_caps(void)
m_query[CapType::IBitDepth] = msgSupportGetAllSetReset;
m_caps[CapType::IBitDepth] = [this](Msg msg, Capability& data) -> Result {
log_attr_access((int)CapType::IBitDepth, (int)msg);
int now = 0, init = 0;
std::vector<int> all;
GET_SANE_OPT(int, scanner_, ex_color_mode, &now, &init, &all, NULL);
@ -1560,6 +1559,7 @@ void huagao_ds::init_support_caps(void)
m_query[CapType::IXResolution] = msgSupportGetAllSetReset;
m_caps[CapType::IXResolution] = [this](Msg msg, Capability& data) {
log_attr_access((int)CapType::IXResolution, (int)msg);
if (!scanner_.get())
return seqError();
std::vector<int> values;
@ -1624,6 +1624,7 @@ void huagao_ds::init_support_caps(void)
m_query[CapType::ISupportedSizes] = msgSupportGetAllSetReset;
m_caps[CapType::ISupportedSizes] = [this](Msg msg, Capability& data) {
log_attr_access((int)CapType::ISupportedSizes, (int)msg);
int now = 0,
init = 0;
std::vector<int> all;
@ -1652,6 +1653,7 @@ void huagao_ds::init_support_caps(void)
m_query[CapType::IPhysicalWidth] = msgSupportGetAll;
m_caps[CapType::IPhysicalWidth] = [this](Msg msg, Capability& data) -> Result {
log_attr_access((int)CapType::IPhysicalWidth, (int)msg);
switch (msg) {
case Msg::Get:
case Msg::GetCurrent:
@ -1673,6 +1675,7 @@ void huagao_ds::init_support_caps(void)
m_query[CapType::IPhysicalHeight] = msgSupportGetAll;
m_caps[CapType::IPhysicalHeight] = [this](Msg msg, Capability& data) -> Result {
log_attr_access((int)CapType::IPhysicalHeight, (int)msg);
switch (msg) {
case Msg::Get:
case Msg::GetCurrent:
@ -1697,6 +1700,7 @@ void huagao_ds::init_support_caps(void)
m_query[CapType::IXferMech] = msgSupportGetAllSetReset;
m_caps[CapType::IXferMech] = [this](Msg msg, Capability& data) -> Result {
log_attr_access((int)CapType::IXferMech, (int)msg);
if (Msg::Set == msg) {
auto mech = data.currentItem<CapType::IXferMech>();
if (mech == XferMech::Native || mech == XferMech::Memory || mech == XferMech::File) {
@ -1718,6 +1722,7 @@ void huagao_ds::init_support_caps(void)
m_query[CapType::IPixelType] = msgSupportGetAllSetReset;
m_caps[CapType::IPixelType] = [this](Msg msg, Capability& data) -> Result {
log_attr_access((int)CapType::IPixelType, (int)msg);
if (!scanner_.get())
return seqError();
std::vector<int> values;
@ -1763,6 +1768,7 @@ void huagao_ds::init_support_caps(void)
m_query[CapType::IAutomaticColorEnabled] = msgSupportGetAllSetReset;
m_caps[CapType::IAutomaticColorEnabled] = [this](Msg msg, Capability& data)->Result {
log_attr_access((int)CapType::IAutomaticColorEnabled, (int)msg);
if (Msg::Set == msg) {
auto mech = data.currentItem<CapType::IAutomaticColorEnabled>();
int ret = SCANNER_ERR_OK, val = mech ? COLOR_AUTO_MATCH : COLOR_RGB;
@ -1778,6 +1784,7 @@ void huagao_ds::init_support_caps(void)
m_query[CapType::IAutomaticColorNonColorPixelType] = msgSupportGetAllSetReset;
m_caps[CapType::IAutomaticColorNonColorPixelType] = [this](Msg msg, Capability& data)->Result {
log_attr_access((int)CapType::IAutomaticColorNonColorPixelType, (int)msg);
if (msg == Msg::Set) {
int mech = (int)data.currentItem<CapType::IAutomaticColorNonColorPixelType>();
//int now = 0;
@ -1802,6 +1809,7 @@ void huagao_ds::init_support_caps(void)
m_query[CapType::IJpegQuality] = msgSupportGetAllSetReset;
m_caps[CapType::IJpegQuality] = [this](Msg msg, Capability& data)->Result {
log_attr_access((int)CapType::IJpegQuality, (int)msg);
SANE_FinalImgFormat fif;
fif.img_format = SANE_IMAGE_TYPE_JPG;
if (Msg::Set == msg) {
@ -1828,6 +1836,7 @@ void huagao_ds::init_support_caps(void)
m_query[CapType::IOrientation] = msgSupportGetAllSetReset;
m_caps[CapType::IOrientation] = [this](Msg msg, Capability& data) -> Result {
log_attr_access((int)CapType::IOrientation, (int)msg);
CapabilityPrintf(msg, enum2str(CapTypeEx::IOrientation), msg == Msg::Set ? to_string((int)data.currentItem<CapType::IOrientation>()) : "");
if (Msg::Set == msg) {
auto mech = data.currentItem<CapType::IOrientation>();
@ -1844,6 +1853,7 @@ void huagao_ds::init_support_caps(void)
m_query[CapType::IRotation] = msgSupportGetAllSetReset;
m_caps[CapType::IRotation] = [this](Msg msg, Capability& data) -> Result {
log_attr_access((int)CapType::IRotation, (int)msg);
if (Msg::Set == msg) {
auto res = data.currentItem<Fix32>();
float angle = res.toFloat();
@ -1875,6 +1885,7 @@ void huagao_ds::init_support_caps(void)
m_query[CapType::FeederEnabled] = msgSupportGetAllSetReset;
m_caps[CapType::FeederEnabled] = [this](Msg msg, Capability& data) -> Result {
log_attr_access((int)CapType::FeederEnabled, (int)msg);
CapabilityPrintf(msg, enum2str(CapType::FeederEnabled), msg == Msg::Set ? to_string((int)data.currentItem<CapType::FeederEnabled>()) : "");
if (Msg::Set == msg) {
auto mech = data.currentItem<CapType::FeederEnabled>();
@ -1889,6 +1900,7 @@ void huagao_ds::init_support_caps(void)
m_query[CapType::DuplexEnabled] = msgSupportGetAllSetReset;
m_caps[CapType::DuplexEnabled] = [this](Msg msg, Capability& data) -> Result {
log_attr_access((int)CapType::DuplexEnabled, (int)msg);
if (Msg::Set == msg) {
bool mech = data.currentItem<CapType::DuplexEnabled>();
int ret = SCANNER_ERR_OK;
@ -1902,6 +1914,7 @@ void huagao_ds::init_support_caps(void)
m_query[CapType::AutoFeed] = msgSupportGetAllSetReset;
m_caps[CapType::AutoFeed] = [this](Msg msg, Capability& data) -> Result {
log_attr_access((int)CapType::AutoFeed, (int)msg);
if (Msg::Set == msg) {
auto mech = data.currentItem<CapType::AutoFeed>();
m_bAutoFeed = mech;
@ -1912,6 +1925,7 @@ void huagao_ds::init_support_caps(void)
m_query[CapType::IImageFileFormat] = msgSupportGetAllSetReset;
m_caps[CapType::IImageFileFormat] = [this](Msg msg, Capability& data) -> Result {
log_attr_access((int)CapType::IImageFileFormat, (int)msg);
SANE_FinalImgFormat now, init;
std::vector<SANE_FinalImgFormat> all;
GET_SANE_OPT(SANE_FinalImgFormat, scanner_, ex_final_format, &now, &init, &all, NULL);
@ -1951,6 +1965,7 @@ void huagao_ds::init_support_caps(void)
m_query[CapType::IAutomaticDeskew] = msgSupportGetAllSetReset;
m_caps[CapType::IAutomaticDeskew] = [this](Msg msg, Capability& data)->Result {
log_attr_access((int)CapType::IAutomaticDeskew, (int)msg);
if (Msg::Set == msg) {
auto atuodsw = data.currentItem<CapType::IAutomaticDeskew>();
int ret = SCANNER_ERR_OK;
@ -1964,6 +1979,7 @@ void huagao_ds::init_support_caps(void)
m_query[CapType::IAutomaticRotate] = msgSupportGetAllSetReset;
m_caps[CapType::IAutomaticRotate] = [this](Msg msg, Capability& data)->Result {
log_attr_access((int)CapType::IAutomaticRotate, (int)msg);
if (Msg::Set == msg) {
auto mech = data.currentItem<CapType::IAutomaticRotate>();
float direction = mech ? AUTO_MATIC_ROTATE : .0f;
@ -1980,6 +1996,7 @@ void huagao_ds::init_support_caps(void)
m_query[CapType::SerialNumber] = msgSupportGetAll;
m_caps[CapType::SerialNumber] = [this](Msg msg, Capability& data)->Result {
log_attr_access((int)CapType::SerialNumber, (int)msg);
Str255 str;
std::string v("");
GET_SANE_OPT(std::string, scanner_, ex_serial, &v, NULL, NULL, NULL);
@ -1989,6 +2006,7 @@ void huagao_ds::init_support_caps(void)
m_query[CapType::AutoScan] = msgSupportGetAllSetReset;
m_caps[CapType::AutoScan] = [this](Msg msg, Capability& data)->Result {
log_attr_access((int)CapType::AutoScan, (int)msg);
if (Msg::Set == msg) {
auto autoscan = data.currentItem<CapType::AutoScan>();
m_autoscan = autoscan;
@ -2001,6 +2019,7 @@ void huagao_ds::init_support_caps(void)
m_query[CapType::IAutoSize] = msgSupportGetAllSetReset;
m_caps[CapType::IAutoSize] = [this](Msg msg, Capability& data)->Result {
log_attr_access((int)CapType::IAutoSize, (int)msg);
CapabilityPrintf(msg, enum2str(CapType::IAutoSize), msg == Msg::Set ? to_string((int)data.currentItem<CapType::IAutoSize>()) : "");
if (Msg::Set == msg) {
auto autosize = data.currentItem<CapType::IAutoSize>();
@ -2017,6 +2036,7 @@ void huagao_ds::init_support_caps(void)
m_query[CapType::IAutomaticBorderDetection] = msgSupportGetAllSetReset;
m_caps[CapType::IAutomaticBorderDetection] = [this](Msg msg, Capability& data)->Result {
log_attr_access((int)CapType::IAutomaticBorderDetection, (int)msg);
if (Msg::Set == msg) {
auto autodetectborder = data.currentItem<CapType::IAutomaticBorderDetection>();
int ret = SCANNER_ERR_OK;
@ -2034,6 +2054,7 @@ void huagao_ds::init_support_caps(void)
m_query[CapType::IAutoDiscardBlankPages] = msgSupportGetAllSetReset;
m_caps[CapType::IAutoDiscardBlankPages] = [this](Msg msg, Capability& data)->Result {
log_attr_access((int)CapType::IAutoDiscardBlankPages, (int)msg);
if (Msg::Set == msg) {
auto mech = data.currentItem<CapType::IAutoDiscardBlankPages>();
bool discard = mech == DiscardBlankPages::Auto;
@ -2049,6 +2070,7 @@ void huagao_ds::init_support_caps(void)
m_query[(CapType)CAP_TYPE_EX_DISCARD_BLANK_RECEIPT] = msgSupportGetAllSetReset;
m_caps[(CapType)CAP_TYPE_EX_DISCARD_BLANK_RECEIPT] = [this](Msg msg, Capability& data)->Result {
log_attr_access((int)CAP_TYPE_EX_DISCARD_BLANK_RECEIPT, (int)msg);
if (Msg::Set == msg) {
auto mech = data.currentItem<DiscardBlankPages>();
bool discard = mech == DiscardBlankPages::Auto;
@ -2065,6 +2087,7 @@ void huagao_ds::init_support_caps(void)
m_query[CapType::IFilter] = msgSupportGetAllSetReset;
m_caps[CapType::IFilter] = [this](Msg msg, Capability& data)->Result {
log_attr_access((int)CapType::IFilter, (int)msg);
if (Msg::Set == msg) {
auto mech = data.currentItem<CapType::IFilter>();
int ret = SCANNER_ERR_OK, val = to_sane_filter((Filter)mech);
@ -2100,6 +2123,7 @@ void huagao_ds::init_support_caps(void)
m_query[CapType::IBrightness] = msgSupportGetAllSetReset;
m_caps[CapType::IBrightness] = [this](Msg msg, Capability& data)->Result {
log_attr_access((int)CapType::IBrightness, (int)msg);
int init = 128, l = 1, u = 255, step = 1, now = 128;
int ret = SCANNER_ERR_OK;
GET_SANE_OPT_RANGE(int, scanner_, bright, &now, &init, &l, &u, &step);
@ -2135,6 +2159,7 @@ void huagao_ds::init_support_caps(void)
m_query[CapType::IContrast] = msgSupportGetAllSetReset;
m_caps[CapType::IContrast] = [this](Msg msg, Capability& data)->Result {
log_attr_access((int)CapType::IContrast, (int)msg);
int init = 4, l = 1, u = 7, step = 1, now = 4;
int ret = SCANNER_ERR_OK;
GET_SANE_OPT_RANGE(int, scanner_, contrast, &now, &init, &l, &u, &step);
@ -2170,6 +2195,7 @@ void huagao_ds::init_support_caps(void)
m_query[(CapType)CapTypeEx::CAP_TYPE_EX_FILL_HOLE_RATIO] = msgSupportGetAllSetReset;
m_caps[(CapType)CapTypeEx::CAP_TYPE_EX_FILL_HOLE_RATIO] = [this](Msg msg, Capability& data)->Result {
log_attr_access((int)CapTypeEx::CAP_TYPE_EX_FILL_HOLE_RATIO, (int)msg);
float init = .0f, l = .0f, u = .0f, step = .0f, now = .0f;
int ret = SCANNER_ERR_OK;
GET_SANE_OPT_RANGE(float, scanner_, search_hole_range, &now, &init, &l, &u, &step);
@ -2206,6 +2232,7 @@ void huagao_ds::init_support_caps(void)
m_query[CapType::IGamma] = msgSupportGetAllSetReset;
m_caps[CapType::IGamma] = [this](Msg msg, Capability& data)->Result {
log_attr_access((int)CapType::IGamma, (int)msg);
float init = .0f, l = .0f, u = .0f, step = .0f, now = .0f;
int ret = SCANNER_ERR_OK;
GET_SANE_OPT_RANGE(float, scanner_, gamma, &now, &init, &l, &u, &step);
@ -2235,11 +2262,13 @@ void huagao_ds::init_support_caps(void)
m_query[CapType::CustomDsData] = msgSupportGetAll;
m_caps[CapType::CustomDsData] = [this](Msg msg, Capability& data) -> Result {
log_attr_access((int)CapType::CustomDsData, (int)msg);
return CapSupGetAll<Bool, Bool, CapType::CustomDsData>(msg, data, Bool(true), Bool(true));
};
m_query[CapType::DoubleFeedDetection] = msgSupportGetAllSetReset;
m_caps[CapType::DoubleFeedDetection] = [this](Msg msg, Capability& data)->Result {
log_attr_access((int)CapType::DoubleFeedDetection, (int)msg);
if (Msg::Set == msg) {
auto atuodsw = data.currentItem<CapType::DoubleFeedDetection>();
int ret = SCANNER_ERR_OK;
@ -2257,6 +2286,7 @@ void huagao_ds::init_support_caps(void)
m_query[CapType::IAutomaticCropUsesFrame] = msgSupportGetAll;
m_caps[CapType::IAutomaticCropUsesFrame] = [this](Msg msg, Capability& data)->Result {
log_attr_access((int)CapType::IAutomaticCropUsesFrame, (int)msg);
bool yes = false;
GET_SANE_OPT(bool, scanner_, ex_is_paper_auto_crop, &yes, NULL, NULL, NULL);
BYTE crop = yes;
@ -2265,12 +2295,14 @@ void huagao_ds::init_support_caps(void)
m_query[CapType::FeederLoaded] = msgSupportGetAll;
m_caps[CapType::FeederLoaded] = [this](Msg msg, Capability& data) -> Result {
log_attr_access((int)CapType::FeederLoaded, (int)msg);
Bool paperon = scanner_->is_paper_on();
return CapSupGetAll<Bool, Bool, CapType::FeederLoaded>(msg, data, paperon, paperon);
};
m_query[CapType(CapTypeEx::CAP_TYPE_EX_FOLD)] = msgSupportGetAllSetReset;
m_caps[CapType(CapTypeEx::CAP_TYPE_EX_FOLD)] = [this](Msg msg, Capability& data)->Result {
log_attr_access((int)CapTypeEx::CAP_TYPE_EX_FOLD, (int)msg);
if (Msg::Set == msg || Msg::Reset == msg) {
auto fold = data.currentItem<Int32>();
if (msg == Msg::Reset)
@ -2287,6 +2319,7 @@ void huagao_ds::init_support_caps(void)
m_query[(CapType)(CapTypeEx::CAP_TYPE_EX_DOGEAR_DIST)] = msgSupportGetAllSetReset;
m_caps[(CapType)(CapTypeEx::CAP_TYPE_EX_DOGEAR_DIST)] = [this](Msg msg, Capability& data)->Result {
log_attr_access((int)CapTypeEx::CAP_TYPE_EX_DOGEAR_DIST, (int)msg);
int now = 10, init = 10, l = 0, u = 100, s = 10;
GET_SANE_OPT_RANGE(int, scanner_, dogear_size, &now, &init, &l, &u, &s);
if (Msg::Set == msg || Msg::Reset == msg) {
@ -2306,6 +2339,7 @@ void huagao_ds::init_support_caps(void)
m_query[(CapType)(CapTypeEx::CAP_TYPE_EX_CROP_MODEL)] = msgSupportGetAllSetReset;
m_caps[(CapType)(CapTypeEx::CAP_TYPE_EX_CROP_MODEL)] = [this](Msg msg, Capability& data)->Result {
log_attr_access((int)CapTypeEx::CAP_TYPE_EX_CROP_MODEL, (int)msg);
bool cur = false, def = false;
GET_SANE_OPT(bool, scanner_, ex_is_paper_auto_crop, &cur, &def, NULL, NULL);
if (Msg::Set == msg || Msg::Reset == msg)
@ -2322,6 +2356,7 @@ void huagao_ds::init_support_caps(void)
m_query[(CapType)CapTypeEx::CAP_TYPE_EX_MULTI_OUT_TYPE] = msgSupportGetAllSetReset;
m_caps[(CapType)CapTypeEx::CAP_TYPE_EX_MULTI_OUT_TYPE] = [this](Msg msg, Capability& data)->Result {
log_attr_access((int)CapTypeEx::CAP_TYPE_EX_MULTI_OUT_TYPE, (int)msg);
int cur = MULTI_OUT_NONE, def = MULTI_OUT_NONE;
std::vector<int> all;
GET_SANE_OPT(int, scanner_, ex_multiout_type, &cur, &def, &all, NULL);
@ -2349,6 +2384,7 @@ void huagao_ds::init_support_caps(void)
m_query[CapType(CapTypeEx::CAP_TYPE_EX_TO_BE_SCAN)] = msgSupportGetAllSetReset;
m_caps[CapType(CapTypeEx::CAP_TYPE_EX_TO_BE_SCAN)] = [this](Msg msg, Capability& data)->Result {
log_attr_access((int)CapTypeEx::CAP_TYPE_EX_TO_BE_SCAN, (int)msg);
if (Msg::Set == msg || Msg::Reset == msg) {
auto tobe = data.currentItem<Int32>();
if (msg == Msg::Reset)
@ -2365,6 +2401,7 @@ void huagao_ds::init_support_caps(void)
m_query[CapType(CapTypeEx::CAP_TYPE_EX_SCAN_WITH_HOLE)] = msgSupportGetAllSetReset;
m_caps[CapType(CapTypeEx::CAP_TYPE_EX_SCAN_WITH_HOLE)] = [this](Msg msg, Capability& data)->Result {
log_attr_access((int)CapTypeEx::CAP_TYPE_EX_SCAN_WITH_HOLE, (int)msg);
if (Msg::Set == msg || Msg::Reset == msg) {
auto tobe = data.currentItem<Int32>();
if (msg == Msg::Reset)
@ -2381,6 +2418,7 @@ void huagao_ds::init_support_caps(void)
m_query[(CapType)(CapTypeEx::CAP_TYPE_EX_ENCODE)] = msgSupportGetAll;
m_caps[(CapType)(CapTypeEx::CAP_TYPE_EX_ENCODE)] = [this](Msg msg, Capability& data)->Result {
log_attr_access((int)CapTypeEx::CAP_TYPE_EX_ENCODE, (int)msg);
std::string code("");
GET_SANE_OPT(std::string, scanner_, ex_device_code, &code, NULL, NULL, NULL);
Str255 str;
@ -2391,6 +2429,7 @@ void huagao_ds::init_support_caps(void)
m_query[(CapType)(CapTypeEx::CAP_TYPE_EX_POWER_LEVEL)] = msgSupportGetAllSetReset;
m_caps[(CapType)(CapTypeEx::CAP_TYPE_EX_POWER_LEVEL)] = [this](Msg msg, Capability& data)->Result {
log_attr_access((int)CapTypeEx::CAP_TYPE_EX_POWER_LEVEL, (int)msg);
int cur = SANE_POWER_MINUTES_30, def = SANE_POWER_MINUTES_30;
std::vector<int> all;
GET_SANE_OPT(int, scanner_, ex_power, &cur, &def, &all, NULL);
@ -2418,6 +2457,7 @@ void huagao_ds::init_support_caps(void)
m_query[(CapType)CapTypeEx::CAP_TYPE_EX_BKG_FILLING_METHOD] = msgSupportGetAllSetReset;
m_caps[(CapType)CapTypeEx::CAP_TYPE_EX_BKG_FILLING_METHOD] = [this](Msg msg, Capability& data)->Result {
log_attr_access((int)CapTypeEx::CAP_TYPE_EX_BKG_FILLING_METHOD, (int)msg);
if (Msg::Set == msg) {
auto convex = data.currentItem<Bool>();
int ret = SCANNER_ERR_OK;
@ -2435,6 +2475,7 @@ void huagao_ds::init_support_caps(void)
m_query[(CapType)CapTypeEx::CAP_TYPE_EX_SHARPEN] = msgSupportGetAllSetReset;
m_caps[(CapType)CapTypeEx::CAP_TYPE_EX_SHARPEN] = [this](Msg msg, Capability& data)->Result {
log_attr_access((int)CapTypeEx::CAP_TYPE_EX_SHARPEN, (int)msg);
int cur = MULTI_OUT_NONE, def = MULTI_OUT_NONE;
std::vector<int> all;
GET_SANE_OPT(int, scanner_, ex_sharpen, &cur, &def, &all, NULL);
@ -2462,6 +2503,7 @@ void huagao_ds::init_support_caps(void)
m_query[(CapType)CapTypeEx::CAP_TYPE_EX_ENHANCE_COLOR] = msgSupportGetAllSetReset;
m_caps[(CapType)CapTypeEx::CAP_TYPE_EX_ENHANCE_COLOR] = [this](Msg msg, Capability& data)->Result {
log_attr_access((int)CapTypeEx::CAP_TYPE_EX_ENHANCE_COLOR, (int)msg);
int cur = FILTER_NONE, def = FILTER_NONE;
std::vector<int> vals;
GET_SANE_OPT(int, scanner_, ex_color_enhance, &cur, &def, &vals, NULL);
@ -2498,6 +2540,7 @@ void huagao_ds::init_support_caps(void)
m_query[(CapType)CapTypeEx::CAP_TYPE_EX_HARDWARE_VERSION] = msgSupportGetAll;
m_caps[(CapType)CapTypeEx::CAP_TYPE_EX_HARDWARE_VERSION] = [this](Msg msg, Capability& data)->Result {
log_attr_access((int)CapTypeEx::CAP_TYPE_EX_HARDWARE_VERSION, (int)msg);
std::string ver("");
GET_SANE_OPT(std::string, scanner_, ex_hardware_version, &ver, NULL, NULL, NULL);
Str255 str;
@ -2508,6 +2551,7 @@ void huagao_ds::init_support_caps(void)
m_query[(CapType)CapTypeEx::CAP_TYPE_EX_IP] = msgSupportGetAll;
m_caps[(CapType)CapTypeEx::CAP_TYPE_EX_IP] = [this](Msg msg, Capability& data)->Result {
log_attr_access((int)CapTypeEx::CAP_TYPE_EX_IP, (int)msg);
std::string ip("");
GET_SANE_OPT(std::string, scanner_, ex_ip, &ip, NULL, NULL, NULL);
Str255 str;
@ -2550,6 +2594,7 @@ void huagao_ds::init_support_caps_ex(void)
#define SET_SANE_CAP_ENUM(ctype, ttype, name) \
m_query[(CapType)CAP_EX_SANE_##name] = msgSupportGetAllSetReset; \
m_caps[(CapType)CAP_EX_SANE_##name] = [this](Msg msg, Capability& data) -> Result { \
log_attr_access((int)CAP_EX_SANE_##name, (int)msg); \
ctype now, init; \
std::vector<ctype> all; \
GET_SANE_OPT(ctype, scanner_, name, &now, &init, &all, NULL); \
@ -2599,6 +2644,7 @@ void huagao_ds::init_support_caps_ex(void)
#define SET_SANE_CAP_RANGE(ctype, ttype, name) \
m_query[(CapType)CAP_EX_SANE_##name] = msgSupportGetAllSetReset; \
m_caps[(CapType)CAP_EX_SANE_##name] = [this](Msg msg, Capability& data) -> Result { \
log_attr_access((int)CAP_EX_SANE_##name, (int)msg); \
ctype now, init, lower, upper, step; \
std::vector<ctype> all; \
GET_SANE_OPT_RANGE(ctype, scanner_, name, &now, &init, &lower, &upper, &step); \
@ -2639,6 +2685,7 @@ void huagao_ds::init_support_caps_ex(void)
#define SET_SANE_CAP(ctype, ttype, name) \
m_query[(CapType)CAP_EX_SANE_##name] = msgSupportGetAllSetReset; \
m_caps[(CapType)CAP_EX_SANE_##name] = [this](Msg msg, Capability& data) -> Result { \
log_attr_access((int)CAP_EX_SANE_##name, (int)msg); \
ctype now, init; \
GET_SANE_OPT(ctype, scanner_, name, &now, &init, NULL, NULL); \
if (msg == Msg::Set || msg == Msg::Reset) \
@ -2797,6 +2844,7 @@ void huagao_ds::init_support_caps_ex(void)
ADD_SANE_CAP(search_hole_range_t); // 穿孔搜索范围 - 上
ADD_SANE_CAP(is_erase_hole_b); // 穿孔移除 - 下
ADD_SANE_CAP(search_hole_range_b); // 穿孔搜索范围 - 下
ADD_SANE_CAP(fold_direction); // 对折方向
}
std::wstring huagao_ds::get_config_file(void)
{
@ -2822,7 +2870,50 @@ DWORD huagao_ds::get_config_number(const wchar_t* sec, const wchar_t* key)
{
return GetPrivateProfileIntW(sec, key, 0, get_config_file().c_str());
}
int huagao_ds::handle_scanner_event(int ev)
{
static int count_0 = 0;
if (ev == 0)
count_0++;
else
{
wchar_t msg[128] = { 0 };
if (count_0)
swprintf_s(msg, _countof(msg) - 1, L"ds::eventProcess(0x0 +%d)\r\nds::eventProcess(0x%x)\r\n", count_0, ev);
else
swprintf_s(msg, _countof(msg) - 1, L"ds::eventProcess(0x%x)\r\n", ev);
load_sane_util::log_info(msg, 0);
count_0 = 0;
}
switch (ev)
{
case SANE_EVENT_WORKING:
notifyXferReady();
break;
case SANE_EVENT_UI_CLOSE_CANCEL:
scanner_->stop();
// notifyEndWithoutImages();
break;
case SANE_EVENT_UI_CLOSE_NORMAL:
scanner_->ui_hide();
case SANE_EVENT_SCAN_FINISHED:
//notifyCloseOk();
//break;
case SANE_EVENT_UI_CLOSE_SETTING:
if(m_bIndicator)
notifyCloseCancel();
else
notifyXferReady(); // 好分数需要再通知 FAINT :( - modified on 2022-10-20
break;
case SANE_EVENT_UI_SCAN_COMMAND:
scanner_->ui_show_progress(NULL);
scanner_->start();
break;
}
return 0;
}

View File

@ -44,6 +44,7 @@ class huagao_ds : public Twpp::SourceFromThis<huagao_ds> {
static std::string get_hidedlg_path(void);
static void showmsg(const char* msg, int err);
static int __stdcall on_scanner_event(int ev, void* param);
void CapabilityPrintf(Twpp::Msg msg, std::string capability, std::string value = "");
Twpp::Result capCommon(const Twpp::Identity& origin, Twpp::Msg msg, Twpp::Capability& data);
@ -53,6 +54,7 @@ class huagao_ds : public Twpp::SourceFromThis<huagao_ds> {
std::wstring get_config_file(void);
std::wstring get_config_value(const wchar_t* sec, const wchar_t* key);
DWORD get_config_number(const wchar_t* sec, const wchar_t* key);
int handle_scanner_event(int ev);
typedef struct _pending_xfer
{