Merge branch 'master' of http://192.168.100.140:8099/sane/code_twain
This commit is contained in:
commit
6994b6718b
|
@ -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"
|
||||
|
|
|
@ -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, ®_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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
713
sane/gb_json.cpp
713
sane/gb_json.cpp
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
124
sane/gb_json.h
124
sane/gb_json.h
|
@ -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);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
188
sane/scanner.cpp
188
sane/scanner.cpp
|
@ -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 };
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue