commit b047fe3fabc09550ce4f51b325765c70a077734c Author: gb <741021719@qq.com> Date: Tue May 3 16:54:08 2022 +0800 initialize diff --git a/device/device.def b/device/device.def new file mode 100644 index 0000000..c62a1b4 --- /dev/null +++ b/device/device.def @@ -0,0 +1,17 @@ +LIBRARY hgscanner +EXPORTS + hg_scanner_initialize + hg_scanner_uninitialize + hg_scanner_get_version + hg_scanner_enum + hg_scanner_open + hg_scanner_close + hg_scanner_get_parameter + hg_scanner_set_parameter + hg_scanner_start + hg_scanner_stop + hg_scanner_get_img_info + hg_scanner_read_img_data + hg_scanner_get_status + hg_scanner_reset + hg_scanner_control \ No newline at end of file diff --git a/device/hgscanner.vcxproj b/device/hgscanner.vcxproj new file mode 100644 index 0000000..c264d44 --- /dev/null +++ b/device/hgscanner.vcxproj @@ -0,0 +1,325 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {9ed4b425-73e0-423e-9712-455e777481b4} + hgscanner + 10.0 + + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + false + v142 + true + Unicode + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)..\..\device\hgdriver\3rdparty\nick;$(SolutionDir)..\..\device\hgdriver\3rdparty\opencv\include\win;$(SolutionDir)..\..\device\hgdriver\3rdparty\cyusb\inc\;$(SolutionDir)..\..\device\hgdriver\3rdparty\libtiff\include\;$(SolutionDir)..\..\device\hgdriver\3rdparty\log4cplus\include\;$(SolutionDir)..\..\device\sdk\;$(SolutionDir)..\..\device\hgdriver\ImageProcess\;$(SolutionDir)..\..\sdk\include\;$(SolutionDir)..\..\device\hgdriver\hgdev\;$(SolutionDir)..\..\device\hgdriver\wrapper\;$(ProjectDir);$(IncludePath) + $(ProjectDir)lib\$(PlatformTarget)\$(Configuration);$(LibraryPath) + $(SolutionDir)..\..\tmp\$(PlatformTarget)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)..\..\release\win\$(PlatformTarget)\$(Configuration)\ + + + false + $(SolutionDir)..\..\device\hgdriver\3rdparty\nick;$(SolutionDir)..\..\device\hgdriver\3rdparty\opencv\include\win;$(SolutionDir)..\..\device\hgdriver\3rdparty\cyusb\inc\;$(SolutionDir)..\..\device\hgdriver\3rdparty\libtiff\include\;$(SolutionDir)..\..\device\hgdriver\3rdparty\log4cplus\include\;$(SolutionDir)..\..\device\sdk\;$(SolutionDir)..\..\device\hgdriver\ImageProcess\;$(SolutionDir)..\..\sdk\include\;$(SolutionDir)..\..\device\hgdriver\hgdev\;$(SolutionDir)..\..\device\hgdriver\wrapper\;$(ProjectDir);$(IncludePath) + $(ProjectDir)lib\$(PlatformTarget)\$(Configuration);$(LibraryPath) + $(SolutionDir)..\..\tmp\$(PlatformTarget)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)..\..\release\win\$(PlatformTarget)\$(Configuration)\ + + + true + $(SolutionDir)..\..\release\win\$(PlatformTarget)\$(Configuration)\ + $(SolutionDir)..\..\tmp\$(PlatformTarget)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)..\..\device\hgdriver\3rdparty\nick;$(SolutionDir)..\..\device\hgdriver\3rdparty\opencv\include\win;$(SolutionDir)..\..\device\hgdriver\3rdparty\cyusb\inc\;$(SolutionDir)..\..\device\hgdriver\3rdparty\libtiff\include\;$(SolutionDir)..\..\device\hgdriver\3rdparty\log4cplus\include\;$(SolutionDir)..\..\device\sdk\;$(SolutionDir)..\..\device\hgdriver\ImageProcess\;$(SolutionDir)..\..\sdk\include\;$(SolutionDir)..\..\device\hgdriver\hgdev\;$(SolutionDir)..\..\device\hgdriver\wrapper\;$(ProjectDir);$(IncludePath) + $(ProjectDir)lib\$(PlatformTarget)\$(Configuration);$(LibraryPath) + + + false + $(SolutionDir)..\..\release\win\$(PlatformTarget)\$(Configuration)\ + $(SolutionDir)..\..\tmp\$(PlatformTarget)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)..\..\device\hgdriver\3rdparty\nick;$(SolutionDir)..\..\device\hgdriver\3rdparty\opencv\include\win;$(SolutionDir)..\..\device\hgdriver\3rdparty\cyusb\inc\;$(SolutionDir)..\..\device\hgdriver\3rdparty\libtiff\include\;$(SolutionDir)..\..\device\hgdriver\3rdparty\log4cplus\include\;$(SolutionDir)..\..\device\sdk\;$(SolutionDir)..\..\device\hgdriver\ImageProcess\;$(SolutionDir)..\..\sdk\include\;$(SolutionDir)..\..\device\hgdriver\hgdev\;$(SolutionDir)..\..\device\hgdriver\wrapper\;$(ProjectDir);$(IncludePath) + $(ProjectDir)lib\$(PlatformTarget)\$(Configuration);$(LibraryPath) + + + + Level3 + true + WIN32;HGSCANNER_EXPORT;CUSTOM_USBVIEW;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + 4996 + MultiThreadedDebugDLL + stdcpp17 + + + Console + true + opencv_world3414.lib;IlmImf.lib;ittnotify.lib;leptonica.lib;libjasper.lib;libjpeg-turbo.lib;libpng.lib;libtiff.lib;libwebp.lib;log4cplusS.lib;quirc.lib;tiff.lib;zlib.lib;user32.lib + + + $(ProjectDir)device.def + + + + + mkdir $(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration) +move /Y "$(OutDirFullPath)$(ProjectName).exp" "$(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration)" +move /Y "$(OutDirFullPath)$(ProjectName).lib" "$(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration)" +move /Y "$(OutDirFullPath)$(ProjectName).pdb" "$(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration)" + + + + + + Level3 + true + true + true + WIN32;HGSCANNER_EXPORT;CUSTOM_USBVIEW;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + 4996 + stdcpp17 + + + Console + true + true + true + opencv_world3414.lib;IlmImf.lib;ittnotify.lib;leptonica.lib;libjasper.lib;libjpeg-turbo.lib;libpng.lib;libtiff.lib;libwebp.lib;log4cplusS.lib;quirc.lib;tiff.lib;zlib.lib;user32.lib + $(ProjectDir)device.def + + + + + + + mkdir $(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration) +move /Y "$(OutDirFullPath)$(ProjectName).exp" "$(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration)" +move /Y "$(OutDirFullPath)$(ProjectName).lib" "$(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration)" +move /Y "$(OutDirFullPath)$(ProjectName).pdb" "$(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration)" + + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + mkdir $(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration) +move /Y "$(OutDirFullPath)$(ProjectName).exp" "$(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration)" +move /Y "$(OutDirFullPath)$(ProjectName).lib" "$(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration)" +move /Y "$(OutDirFullPath)$(ProjectName).pdb" "$(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration)" + + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + mkdir $(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration) +move /Y "$(OutDirFullPath)$(ProjectName).exp" "$(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration)" +move /Y "$(OutDirFullPath)$(ProjectName).lib" "$(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration)" +move /Y "$(OutDirFullPath)$(ProjectName).pdb" "$(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration)" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/device/hgscanner.vcxproj.filters b/device/hgscanner.vcxproj.filters new file mode 100644 index 0000000..6ea6739 --- /dev/null +++ b/device/hgscanner.vcxproj.filters @@ -0,0 +1,365 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {69bf4790-4420-4dc8-bc81-a63a902ce9c9} + + + {f707cca2-7b0e-41a8-b091-4340f974ff02} + + + {01c7b72c-12be-466b-b93e-9a9c8fea21b4} + + + {06629bf8-5d3e-4855-916b-260169824839} + + + + + 源文件 + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + dev + + + dev + + + dev + + + dev + + + dev + + + dev + + + dev + + + dev + + + dev + + + dev + + + dev + + + dev + + + usb + + + usb\usbview + + + usb\usbview + + + dev + + + dev + + + 源文件 + + + + + 头文件 + + + 头文件 + + + 头文件 + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + image + + + dev + + + dev + + + dev + + + dev + + + dev + + + dev + + + dev + + + dev + + + dev + + + dev + + + dev + + + dev + + + dev + + + dev + + + dev + + + dev + + + dev + + + usb + + + usb\usbview + + + usb\usbview + + + usb\usbview + + + dev + + + dev + + + 头文件 + + + + + 源文件 + + + \ No newline at end of file diff --git a/device/lib/x86/Debug/CyAPI.lib b/device/lib/x86/Debug/CyAPI.lib new file mode 100644 index 0000000..a888ef7 Binary files /dev/null and b/device/lib/x86/Debug/CyAPI.lib differ diff --git a/device/lib/x86/Debug/HG_OCR.lib b/device/lib/x86/Debug/HG_OCR.lib new file mode 100644 index 0000000..a6efaea Binary files /dev/null and b/device/lib/x86/Debug/HG_OCR.lib differ diff --git a/device/lib/x86/Debug/IlmImf.lib b/device/lib/x86/Debug/IlmImf.lib new file mode 100644 index 0000000..5ac1a3c Binary files /dev/null and b/device/lib/x86/Debug/IlmImf.lib differ diff --git a/device/lib/x86/Debug/ittnotify.lib b/device/lib/x86/Debug/ittnotify.lib new file mode 100644 index 0000000..33cb642 Binary files /dev/null and b/device/lib/x86/Debug/ittnotify.lib differ diff --git a/device/lib/x86/Debug/leptonica.lib b/device/lib/x86/Debug/leptonica.lib new file mode 100644 index 0000000..432fce4 Binary files /dev/null and b/device/lib/x86/Debug/leptonica.lib differ diff --git a/device/lib/x86/Debug/libjasper.lib b/device/lib/x86/Debug/libjasper.lib new file mode 100644 index 0000000..104465c Binary files /dev/null and b/device/lib/x86/Debug/libjasper.lib differ diff --git a/device/lib/x86/Debug/libjpeg-turbo.lib b/device/lib/x86/Debug/libjpeg-turbo.lib new file mode 100644 index 0000000..a2322dd Binary files /dev/null and b/device/lib/x86/Debug/libjpeg-turbo.lib differ diff --git a/device/lib/x86/Debug/libpng.lib b/device/lib/x86/Debug/libpng.lib new file mode 100644 index 0000000..8d63e9e Binary files /dev/null and b/device/lib/x86/Debug/libpng.lib differ diff --git a/device/lib/x86/Debug/libtiff.lib b/device/lib/x86/Debug/libtiff.lib new file mode 100644 index 0000000..743bba8 Binary files /dev/null and b/device/lib/x86/Debug/libtiff.lib differ diff --git a/device/lib/x86/Debug/libwebp.lib b/device/lib/x86/Debug/libwebp.lib new file mode 100644 index 0000000..0d5aef7 Binary files /dev/null and b/device/lib/x86/Debug/libwebp.lib differ diff --git a/device/lib/x86/Debug/log4cplusS.lib b/device/lib/x86/Debug/log4cplusS.lib new file mode 100644 index 0000000..d411cf5 Binary files /dev/null and b/device/lib/x86/Debug/log4cplusS.lib differ diff --git a/device/lib/x86/Debug/opencv_world3414.lib b/device/lib/x86/Debug/opencv_world3414.lib new file mode 100644 index 0000000..a867962 Binary files /dev/null and b/device/lib/x86/Debug/opencv_world3414.lib differ diff --git a/device/lib/x86/Debug/quirc.lib b/device/lib/x86/Debug/quirc.lib new file mode 100644 index 0000000..0472624 Binary files /dev/null and b/device/lib/x86/Debug/quirc.lib differ diff --git a/device/lib/x86/Debug/tiff.lib b/device/lib/x86/Debug/tiff.lib new file mode 100644 index 0000000..fff6095 Binary files /dev/null and b/device/lib/x86/Debug/tiff.lib differ diff --git a/device/lib/x86/Debug/zlib.lib b/device/lib/x86/Debug/zlib.lib new file mode 100644 index 0000000..a018c31 Binary files /dev/null and b/device/lib/x86/Debug/zlib.lib differ diff --git a/device/lib/x86/Release/CyAPI.lib b/device/lib/x86/Release/CyAPI.lib new file mode 100644 index 0000000..a888ef7 Binary files /dev/null and b/device/lib/x86/Release/CyAPI.lib differ diff --git a/device/lib/x86/Release/HG_OCR.lib b/device/lib/x86/Release/HG_OCR.lib new file mode 100644 index 0000000..f71a368 Binary files /dev/null and b/device/lib/x86/Release/HG_OCR.lib differ diff --git a/device/lib/x86/Release/IlmImf.lib b/device/lib/x86/Release/IlmImf.lib new file mode 100644 index 0000000..9f812b6 Binary files /dev/null and b/device/lib/x86/Release/IlmImf.lib differ diff --git a/device/lib/x86/Release/ittnotify.lib b/device/lib/x86/Release/ittnotify.lib new file mode 100644 index 0000000..e9e2726 Binary files /dev/null and b/device/lib/x86/Release/ittnotify.lib differ diff --git a/device/lib/x86/Release/leptonica.lib b/device/lib/x86/Release/leptonica.lib new file mode 100644 index 0000000..49e41d2 Binary files /dev/null and b/device/lib/x86/Release/leptonica.lib differ diff --git a/device/lib/x86/Release/libjasper.lib b/device/lib/x86/Release/libjasper.lib new file mode 100644 index 0000000..0e16fa0 Binary files /dev/null and b/device/lib/x86/Release/libjasper.lib differ diff --git a/device/lib/x86/Release/libjpeg-turbo.lib b/device/lib/x86/Release/libjpeg-turbo.lib new file mode 100644 index 0000000..45d949f Binary files /dev/null and b/device/lib/x86/Release/libjpeg-turbo.lib differ diff --git a/device/lib/x86/Release/libpng.lib b/device/lib/x86/Release/libpng.lib new file mode 100644 index 0000000..1c67165 Binary files /dev/null and b/device/lib/x86/Release/libpng.lib differ diff --git a/device/lib/x86/Release/libtiff.lib b/device/lib/x86/Release/libtiff.lib new file mode 100644 index 0000000..3abcdd8 Binary files /dev/null and b/device/lib/x86/Release/libtiff.lib differ diff --git a/device/lib/x86/Release/libwebp.lib b/device/lib/x86/Release/libwebp.lib new file mode 100644 index 0000000..b07abf9 Binary files /dev/null and b/device/lib/x86/Release/libwebp.lib differ diff --git a/device/lib/x86/Release/log4cplusS.lib b/device/lib/x86/Release/log4cplusS.lib new file mode 100644 index 0000000..c6a6163 Binary files /dev/null and b/device/lib/x86/Release/log4cplusS.lib differ diff --git a/device/lib/x86/Release/opencv_world3414.lib b/device/lib/x86/Release/opencv_world3414.lib new file mode 100644 index 0000000..884436b Binary files /dev/null and b/device/lib/x86/Release/opencv_world3414.lib differ diff --git a/device/lib/x86/Release/quirc.lib b/device/lib/x86/Release/quirc.lib new file mode 100644 index 0000000..a84419c Binary files /dev/null and b/device/lib/x86/Release/quirc.lib differ diff --git a/device/lib/x86/Release/tiff.lib b/device/lib/x86/Release/tiff.lib new file mode 100644 index 0000000..5941979 Binary files /dev/null and b/device/lib/x86/Release/tiff.lib differ diff --git a/device/lib/x86/Release/zlib.lib b/device/lib/x86/Release/zlib.lib new file mode 100644 index 0000000..be9c719 Binary files /dev/null and b/device/lib/x86/Release/zlib.lib differ diff --git a/device/win_usb/twain_flow.txt b/device/win_usb/twain_flow.txt new file mode 100644 index 0000000..59af402 --- /dev/null +++ b/device/win_usb/twain_flow.txt @@ -0,0 +1,60 @@ +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_IDENTITY, MSG = MSG_GET, data: 0x02ee50d4, +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_IDENTITY, MSG = MSG_OPENDS, data: 0x02ee6b84, Identity(ID: 0x1b, Ver: 0x1, Proto: 1000d.79736145, Group: 0x6e616353, Manufacturer: EasyScan, ProductFamily: EasyScan, ProductName: EasyScan); +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_CAPABILITY, MSG = MSG_GETCURRENT, data: 0x02ee6b34, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_CAPABILITY, MSG = MSG_SET, data: 0x02ee6b34, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_CAPABILITY, MSG = MSG_GET, data: 0x02ee6b24, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_CAPABILITY, MSG = MSG_GET, data: 0x02ee6b24, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_CAPABILITY, MSG = MSG_GETCURRENT, data: 0x02ee6b24, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_CAPABILITY, MSG = MSG_GETCURRENT, data: 0x02ee6b24, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_CAPABILITY, MSG = MSG_SET, data: 0x02ee6b34, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_CAPABILITY, MSG = MSG_GETCURRENT, data: 0x02ee6b34, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_CAPABILITY, MSG = MSG_SET, data: 0x02ee6b34, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_STATUS, MSG = MSG_GET, data: 0x02ee6b1c, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_CAPABILITY, MSG = MSG_GET, data: 0x02ee6b24, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_CAPABILITY, MSG = MSG_GET, data: 0x02ee6b24, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_CAPABILITY, MSG = MSG_SET, data: 0x02ee6b34, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_CAPABILITY, MSG = MSG_GET, data: 0x02ee6b24, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_CAPABILITY, MSG = MSG_GET, data: 0x02ee6b24, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_CAPABILITY, MSG = MSG_GET, data: 0x02ee6b24, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_CAPABILITY, MSG = MSG_GET, data: 0x02ee6b24, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_CAPABILITY, MSG = MSG_GET, data: 0x02ee6b24, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_CAPABILITY, MSG = MSG_GET, data: 0x02ee6b24, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_CAPABILITY, MSG = MSG_SET, data: 0x02ee6b34, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_CAPABILITY, MSG = MSG_SET, data: 0x02ee6b2c, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_CAPABILITY, MSG = MSG_SET, data: 0x02ee6b2c, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_STATUS, MSG = MSG_GET, data: 0x02ee6b14, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_CAPABILITY, MSG = MSG_SET, data: 0x02ee6b2c, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_CAPABILITY, MSG = MSG_SET, data: 0x02ee6b2c, Identity(same as the latest) +[21164] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_IDENTITY, MSG = MSG_GET, data: 0x0d468504, +[21164] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_IDENTITY, MSG = MSG_OPENDS, data: 0x0d46be54, Identity(ID: 0x1e, Ver: 0x1, Proto: 1000d.79736145, Group: 0x6e616353, Manufacturer: EasyScan, ProductFamily: EasyScan, ProductName: EasyScan); +[21164] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_STATUS, MSG = MSG_GET, data: 0x0d46beb0, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_CAPABILITY, MSG = MSG_SET, data: 0x02ee6b8c, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_CAPABILITY, MSG = MSG_SET, data: 0x02ee6b6c, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_CAPABILITY, MSG = MSG_SET, data: 0x02ee6b6c, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_CAPABILITY, MSG = MSG_SET, data: 0x02ee6b8c, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_CAPABILITY, MSG = MSG_SET, data: 0x02ee6b7c, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_CAPABILITY, MSG = MSG_SET, data: 0x02ee6b8c, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_STATUS, MSG = MSG_GET, data: 0x02ee6b74, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_CAPABILITY, MSG = MSG_SET, data: 0x02ee6b6c, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_CAPABILITY, MSG = MSG_SET, data: 0x02ee6b6c, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_IMAGE, DAT = DAT_IMAGELAYOUT, MSG = MSG_SET, data: 0x02ee6bac, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_STATUS, MSG = MSG_GET, data: 0x02ee6b94, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_IMAGE, DAT = DAT_IMAGELAYOUT, MSG = MSG_RESET, data: 0x02ee6bac, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_CAPABILITY, MSG = MSG_SET, data: 0x02ee6b8c, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_USERINTERFACE, MSG = MSG_ENABLEDS, data: 0x02ee6b80, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_IMAGE, DAT = DAT_IMAGENATIVEXFER, MSG = MSG_GET, data: 0x02ee5518, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_STATUS, MSG = MSG_GET, data: 0x02ee5500, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_PENDINGXFERS, MSG = MSG_ENDXFER, data: 0x02ee5510, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_USERINTERFACE, MSG = MSG_DISABLEDS, data: 0x02ee5674, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_CAPABILITY, MSG = MSG_SET, data: 0x02ee6f84, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_CAPABILITY, MSG = MSG_SET, data: 0x02ee6f64, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_CAPABILITY, MSG = MSG_SET, data: 0x02ee6f64, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_CAPABILITY, MSG = MSG_GETCURRENT, data: 0x02ee6f74, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_CAPABILITY, MSG = MSG_GETCURRENT, data: 0x02ee6f74, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_CAPABILITY, MSG = MSG_SET, data: 0x02ee6f84, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_CAPABILITY, MSG = MSG_SET, data: 0x02ee6f74, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_CAPABILITY, MSG = MSG_SET, data: 0x02ee6f84, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_STATUS, MSG = MSG_GET, data: 0x02ee6f6c, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_CAPABILITY, MSG = MSG_SET, data: 0x02ee6f64, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_CONTROL, DAT = DAT_CAPABILITY, MSG = MSG_SET, data: 0x02ee6f64, Identity(same as the latest) +[22772] [TWAIN-monitor] DG = DG_IMAGE, DAT = DAT_IMAGELAYOUT, MSG = MSG_SET, data: 0x02ee6fa4, Identity(same as the latest) diff --git a/device/win_usb/usbview/devnode.c b/device/win_usb/usbview/devnode.c new file mode 100644 index 0000000..ef81aee --- /dev/null +++ b/device/win_usb/usbview/devnode.c @@ -0,0 +1,336 @@ +/*++ + + Copyright (c) 1998-2011 Microsoft Corporation + + Module Name: + + DEVNODE.C + + --*/ + +/***************************************************************************** + I N C L U D E S + *****************************************************************************/ + +#include "enum.h" + +/***************************************************************************** + + DriverNameToDeviceInst() + + Finds the Device instance of the DevNode with the matching DriverName. + Returns FALSE if the matching DevNode is not found and TRUE if found + + *****************************************************************************/ +BOOL +DriverNameToDeviceInst( + _In_reads_bytes_(cbDriverName) PCHAR DriverName, + _In_ size_t cbDriverName, + _Out_ HDEVINFO *pDevInfo, + _Out_writes_bytes_(sizeof(SP_DEVINFO_DATA)) PSP_DEVINFO_DATA pDevInfoData + ) +{ + HDEVINFO deviceInfo = INVALID_HANDLE_VALUE; + BOOL status = TRUE; + ULONG deviceIndex; + SP_DEVINFO_DATA deviceInfoData; + BOOL bResult = FALSE; + PCHAR pDriverName = NULL; + PSTR buf = NULL; + BOOL done = FALSE; + + if (pDevInfo == NULL) + { + return FALSE; + } + + if (pDevInfoData == NULL) + { + return FALSE; + } + + memset(pDevInfoData, 0, sizeof(SP_DEVINFO_DATA)); + + *pDevInfo = INVALID_HANDLE_VALUE; + + // Use local string to guarantee zero termination + pDriverName = (PCHAR) ALLOC((DWORD) cbDriverName + 1); + if (NULL == pDriverName) + { + status = FALSE; + goto Done; + } + StringCbCopyN(pDriverName, cbDriverName + 1, DriverName, cbDriverName); + + // + // We cannot walk the device tree with CM_Get_Sibling etc. unless we assume + // the device tree will stabilize. Any devnode removal (even outside of USB) + // would force us to retry. Instead we use Setup API to snapshot all + // devices. + // + + // Examine all present devices to see if any match the given DriverName + // + deviceInfo = SetupDiGetClassDevs(NULL, + NULL, + NULL, + DIGCF_ALLCLASSES | DIGCF_PRESENT); + + if (deviceInfo == INVALID_HANDLE_VALUE) + { + status = FALSE; + goto Done; + } + + deviceIndex = 0; + deviceInfoData.cbSize = sizeof(deviceInfoData); + + while (done == FALSE) + { + // + // Get devinst of the next device + // + + status = SetupDiEnumDeviceInfo(deviceInfo, + deviceIndex, + &deviceInfoData); + + deviceIndex++; + + if (!status) + { + // + // This could be an error, or indication that all devices have been + // processed. Either way the desired device was not found. + // + + done = TRUE; + break; + } + + // + // Get the DriverName value + // + + bResult = GetDeviceProperty(deviceInfo, + &deviceInfoData, + SPDRP_DRIVER, + &buf); + + // If the DriverName value matches, return the DeviceInstance + // + if (bResult == TRUE && buf != NULL && _stricmp(pDriverName, buf) == 0) + { + done = TRUE; + *pDevInfo = deviceInfo; + CopyMemory(pDevInfoData, &deviceInfoData, sizeof(deviceInfoData)); + FREE(buf); + break; + } + + if(buf != NULL) + { + FREE(buf); + buf = NULL; + } + } + +Done: + + if (bResult == FALSE) + { + if (deviceInfo != INVALID_HANDLE_VALUE) + { + SetupDiDestroyDeviceInfoList(deviceInfo); + } + } + + if (pDriverName != NULL) + { + FREE(pDriverName); + } + + return status; +} + +/***************************************************************************** + + DriverNameToDeviceProperties() + + Returns the Device properties of the DevNode with the matching DriverName. + Returns NULL if the matching DevNode is not found. + + The caller should free the returned structure using FREE() macro + + *****************************************************************************/ +PUSB_DEVICE_PNP_STRINGS +DriverNameToDeviceProperties( + _In_reads_bytes_(cbDriverName) PCHAR DriverName, + _In_ size_t cbDriverName + ) +{ + HDEVINFO deviceInfo = INVALID_HANDLE_VALUE; + SP_DEVINFO_DATA deviceInfoData = {0}; + ULONG len; + BOOL status; + PUSB_DEVICE_PNP_STRINGS DevProps = NULL; + DWORD lastError; + + // Allocate device propeties structure + DevProps = (PUSB_DEVICE_PNP_STRINGS) ALLOC(sizeof(USB_DEVICE_PNP_STRINGS)); + + if(NULL == DevProps) + { + status = FALSE; + goto Done; + } + + // Get device instance + status = DriverNameToDeviceInst(DriverName, cbDriverName, &deviceInfo, &deviceInfoData); + if (status == FALSE) + { + goto Done; + } + + len = 0; + status = SetupDiGetDeviceInstanceId(deviceInfo, + &deviceInfoData, + NULL, + 0, + &len); + lastError = GetLastError(); + + + if (status != FALSE && lastError != ERROR_INSUFFICIENT_BUFFER) + { + status = FALSE; + goto Done; + } + + // + // An extra byte is required for the terminating character + // + + len++; + DevProps->DeviceId = ALLOC(len); + + if (DevProps->DeviceId == NULL) + { + status = FALSE; + goto Done; + } + + status = SetupDiGetDeviceInstanceId(deviceInfo, + &deviceInfoData, + DevProps->DeviceId, + len, + &len); + if (status == FALSE) + { + goto Done; + } + + status = GetDeviceProperty(deviceInfo, + &deviceInfoData, + SPDRP_DEVICEDESC, + &DevProps->DeviceDesc); + + if (status == FALSE) + { + goto Done; + } + + + // + // We don't fail if the following registry query fails as these fields are additional information only + // + + GetDeviceProperty(deviceInfo, + &deviceInfoData, + SPDRP_HARDWAREID, + &DevProps->HwId); + + GetDeviceProperty(deviceInfo, + &deviceInfoData, + SPDRP_SERVICE, + &DevProps->Service); + + GetDeviceProperty(deviceInfo, + &deviceInfoData, + SPDRP_CLASS, + &DevProps->DeviceClass); +Done: + + if (deviceInfo != INVALID_HANDLE_VALUE) + { + SetupDiDestroyDeviceInfoList(deviceInfo); + } + + if (status == FALSE) + { + if (DevProps != NULL) + { + FreeDeviceProperties(&DevProps); + } + } + return DevProps; +} + +/***************************************************************************** + + FreeDeviceProperties() + + Free the device properties structure + + *****************************************************************************/ +VOID FreeDeviceProperties(_In_ PUSB_DEVICE_PNP_STRINGS *ppDevProps) +{ + if(ppDevProps == NULL) + { + return; + } + + if(*ppDevProps == NULL) + { + return; + } + + if ((*ppDevProps)->DeviceId != NULL) + { + FREE((*ppDevProps)->DeviceId); + } + + if ((*ppDevProps)->DeviceDesc != NULL) + { + FREE((*ppDevProps)->DeviceDesc); + } + + // + // The following are not necessary, but left in case + // in the future there is a later failure where these + // pointer fields would be allocated. + // + + if ((*ppDevProps)->HwId != NULL) + { + FREE((*ppDevProps)->HwId); + } + + if ((*ppDevProps)->Service != NULL) + { + FREE((*ppDevProps)->Service); + } + + if ((*ppDevProps)->DeviceClass != NULL) + { + FREE((*ppDevProps)->DeviceClass); + } + + if ((*ppDevProps)->PowerState != NULL) + { + FREE((*ppDevProps)->PowerState); + } + + FREE(*ppDevProps); + *ppDevProps = NULL; +} diff --git a/device/win_usb/usbview/enum.c b/device/win_usb/usbview/enum.c new file mode 100644 index 0000000..dc4dfbe --- /dev/null +++ b/device/win_usb/usbview/enum.c @@ -0,0 +1,3857 @@ +/*++ + +Copyright (c) 1997-2011 Microsoft Corporation + +Module Name: + + ENUM.C + +Abstract: + + This source file contains the routines which enumerate the USB bus + and populate the TreeView control. + + The enumeration process goes like this: + + (1) Enumerate Host Controllers and Root Hubs + EnumerateHostControllers() + EnumerateHostController() + Host controllers currently have symbolic link names of the form HCDx, + where x starts at 0. Use CreateFile() to open each host controller + symbolic link. Create a node in the TreeView to represent each host + controller. + + GetRootHubName() + After a host controller has been opened, send the host controller an + IOCTL_USB_GET_ROOT_HUB_NAME request to get the symbolic link name of + the root hub that is part of the host controller. + + (2) Enumerate Hubs (Root Hubs and External Hubs) + EnumerateHub() + Given the name of a hub, use CreateFile() to map the hub. Send the + hub an IOCTL_USB_GET_NODE_INFORMATION request to get info about the + hub, such as the number of downstream ports. Create a node in the + TreeView to represent each hub. + + (3) Enumerate Downstream Ports + EnumerateHubPorts() + Given an handle to an open hub and the number of downstream ports on + the hub, send the hub an IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX + request for each downstream port of the hub to get info about the + device (if any) attached to each port. If there is a device attached + to a port, send the hub an IOCTL_USB_GET_NODE_CONNECTION_NAME request + to get the symbolic link name of the hub attached to the downstream + port. If there is a hub attached to the downstream port, recurse to + step (2). + + GetAllStringDescriptors() + GetConfigDescriptor() + Create a node in the TreeView to represent each hub port + and attached device. + + +Environment: + + user mode + +Revision History: + + 04-25-97 : created + +--*/ + +//***************************************************************************** +// I N C L U D E S +//***************************************************************************** + +#include "enum.h" + +//***************************************************************************** +// D E F I N E S +//***************************************************************************** + +#define NUM_STRING_DESC_TO_GET 32 + +//***************************************************************************** +// L O C A L F U N C T I O N P R O T O T Y P E S +//***************************************************************************** + +VOID +EnumerateHostControllers ( + HTREEITEM hTreeParent, + ULONG *DevicesConnected +); + +VOID +EnumerateHostController ( + HTREEITEM hTreeParent, + HANDLE hHCDev, + _Inout_ PCHAR leafName, + _In_ HANDLE deviceInfo, + _In_ PSP_DEVINFO_DATA deviceInfoData +); + +VOID +EnumerateHub ( + HTREEITEM hTreeParent, + _In_reads_(cbHubName) PCHAR HubName, + _In_ size_t cbHubName, + _In_opt_ PUSB_NODE_CONNECTION_INFORMATION_EX ConnectionInfo, + _In_opt_ PUSB_NODE_CONNECTION_INFORMATION_EX_V2 ConnectionInfoV2, + _In_opt_ PUSB_PORT_CONNECTOR_PROPERTIES PortConnectorProps, + _In_opt_ PUSB_DESCRIPTOR_REQUEST ConfigDesc, + _In_opt_ PUSB_DESCRIPTOR_REQUEST BosDesc, + _In_opt_ PSTRING_DESCRIPTOR_NODE StringDescs, + _In_opt_ PUSB_DEVICE_PNP_STRINGS DevProps +); + +VOID +EnumerateHubPorts ( + HTREEITEM hTreeParent, + HANDLE hHubDevice, + ULONG NumPorts +); + +PCHAR GetRootHubName ( + HANDLE HostController +); + +PCHAR GetExternalHubName ( + HANDLE Hub, + ULONG ConnectionIndex +); + +PCHAR GetHCDDriverKeyName ( + HANDLE HCD +); + +PCHAR GetDriverKeyName ( + HANDLE Hub, + ULONG ConnectionIndex +); + +PUSB_DESCRIPTOR_REQUEST +GetConfigDescriptor ( + HANDLE hHubDevice, + ULONG ConnectionIndex, + UCHAR DescriptorIndex + ); + +PUSB_DESCRIPTOR_REQUEST +GetBOSDescriptor ( + HANDLE hHubDevice, + ULONG ConnectionIndex + ); + +DWORD +GetHostControllerPowerMap( + HANDLE hHCDev, + PUSBHOSTCONTROLLERINFO hcInfo); + +DWORD +GetHostControllerInfo( + HANDLE hHCDev, + PUSBHOSTCONTROLLERINFO hcInfo); + +PCHAR WideStrToMultiStr ( + _In_reads_bytes_(cbWideStr) PWCHAR WideStr, + _In_ size_t cbWideStr + ); + +BOOL +AreThereStringDescriptors ( + PUSB_DEVICE_DESCRIPTOR DeviceDesc, + PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc +); + +PSTRING_DESCRIPTOR_NODE +GetAllStringDescriptors ( + HANDLE hHubDevice, + ULONG ConnectionIndex, + PUSB_DEVICE_DESCRIPTOR DeviceDesc, + PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc +); + +PSTRING_DESCRIPTOR_NODE +GetStringDescriptor ( + HANDLE hHubDevice, + ULONG ConnectionIndex, + UCHAR DescriptorIndex, + USHORT LanguageID +); + +HRESULT +GetStringDescriptors ( + _In_ HANDLE hHubDevice, + _In_ ULONG ConnectionIndex, + _In_ UCHAR DescriptorIndex, + _In_ ULONG NumLanguageIDs, + _In_reads_(NumLanguageIDs) USHORT *LanguageIDs, + _In_ PSTRING_DESCRIPTOR_NODE StringDescNodeHead +); + +void +EnumerateAllDevices(); + + +void +EnumerateAllDevicesWithGuid( + PDEVICE_GUID_LIST DeviceList, + LPGUID Guid + ); + +void +FreeDeviceInfoNode( + _In_ PDEVICE_INFO_NODE *ppNode + ); + +PDEVICE_INFO_NODE +FindMatchingDeviceNodeForDriverName( + _In_ PSTR DriverKeyName, + _In_ BOOLEAN IsHub + ); + + +//***************************************************************************** +// G L O B A L S +//***************************************************************************** + +// List of enumerated host controllers. +// +LIST_ENTRY EnumeratedHCListHead = +{ + &EnumeratedHCListHead, + &EnumeratedHCListHead +}; + +DEVICE_GUID_LIST gHubList; +DEVICE_GUID_LIST gDeviceList; + + +//***************************************************************************** +// G L O B A L S P R I V A T E T O T H I S F I L E +//***************************************************************************** + +PCHAR ConnectionStatuses[] = +{ + "", // 0 - NoDeviceConnected + "", // 1 - DeviceConnected + "FailedEnumeration", // 2 - DeviceFailedEnumeration + "GeneralFailure", // 3 - DeviceGeneralFailure + "Overcurrent", // 4 - DeviceCausedOvercurrent + "NotEnoughPower", // 5 - DeviceNotEnoughPower + "NotEnoughBandwidth", // 6 - DeviceNotEnoughBandwidth + "HubNestedTooDeeply", // 7 - DeviceHubNestedTooDeeply + "InLegacyHub", // 8 - DeviceInLegacyHub + "Enumerating", // 9 - DeviceEnumerating + "Reset" // 10 - DeviceReset +}; + +ULONG TotalDevicesConnected; + + +//***************************************************************************** +// +// EnumerateHostControllers() +// +// hTreeParent - Handle of the TreeView item under which host controllers +// should be added. +// +//***************************************************************************** + +VOID +EnumerateHostControllers ( + HTREEITEM hTreeParent, + ULONG *DevicesConnected +) +{ + HANDLE hHCDev = NULL; + HDEVINFO deviceInfo = NULL; + SP_DEVINFO_DATA deviceInfoData; + SP_DEVICE_INTERFACE_DATA deviceInterfaceData; + PSP_DEVICE_INTERFACE_DETAIL_DATA deviceDetailData = NULL; + ULONG index = 0; + ULONG requiredLength = 0; + BOOL success; + + TotalDevicesConnected = 0; + TotalHubs = 0; + + EnumerateAllDevices(); + + // Iterate over host controllers using the new GUID based interface + // + deviceInfo = SetupDiGetClassDevs((LPGUID)&GUID_CLASS_USB_HOST_CONTROLLER, + NULL, + NULL, + (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE)); + + deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA); + + for (index=0; + SetupDiEnumDeviceInfo(deviceInfo, + index, + &deviceInfoData); + index++) + { + deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + + success = SetupDiEnumDeviceInterfaces(deviceInfo, + 0, + (LPGUID)&GUID_CLASS_USB_HOST_CONTROLLER, + index, + &deviceInterfaceData); + + if (!success) + { + OOPS(); + break; + } + + success = SetupDiGetDeviceInterfaceDetail(deviceInfo, + &deviceInterfaceData, + NULL, + 0, + &requiredLength, + NULL); + + if (!success && GetLastError() != ERROR_INSUFFICIENT_BUFFER) + { + OOPS(); + break; + } + + deviceDetailData = ALLOC(requiredLength); + if (deviceDetailData == NULL) + { + OOPS(); + break; + } + + deviceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); + + success = SetupDiGetDeviceInterfaceDetail(deviceInfo, + &deviceInterfaceData, + deviceDetailData, + requiredLength, + &requiredLength, + NULL); + + if (!success) + { + OOPS(); + break; + } + + hHCDev = CreateFile(deviceDetailData->DevicePath, + GENERIC_WRITE, + FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL); + + // If the handle is valid, then we've successfully opened a Host + // Controller. Display some info about the Host Controller itself, + // then enumerate the Root Hub attached to the Host Controller. + // + if (hHCDev != INVALID_HANDLE_VALUE) + { + EnumerateHostController(hTreeParent, + hHCDev, + deviceDetailData->DevicePath, + deviceInfo, + &deviceInfoData); + + CloseHandle(hHCDev); + } + + FREE(deviceDetailData); + } + + SetupDiDestroyDeviceInfoList(deviceInfo); + + *DevicesConnected = TotalDevicesConnected; + + return; +} + +//***************************************************************************** +// +// EnumerateHostController() +// +// hTreeParent - Handle of the TreeView item under which host controllers +// should be added. +// +//***************************************************************************** + +VOID +EnumerateHostController ( + HTREEITEM hTreeParent, + HANDLE hHCDev, _Inout_ PCHAR leafName, + _In_ HANDLE deviceInfo, + _In_ PSP_DEVINFO_DATA deviceInfoData +) +{ + PCHAR driverKeyName = NULL; + HTREEITEM hHCItem = NULL; + PCHAR rootHubName = NULL; + PLIST_ENTRY listEntry = NULL; + PUSBHOSTCONTROLLERINFO hcInfo = NULL; + PUSBHOSTCONTROLLERINFO hcInfoInList = NULL; + DWORD dwSuccess; + BOOL success = FALSE; + ULONG deviceAndFunction = 0; + PUSB_DEVICE_PNP_STRINGS DevProps = NULL; + + + // Allocate a structure to hold information about this host controller. + // + hcInfo = (PUSBHOSTCONTROLLERINFO)ALLOC(sizeof(USBHOSTCONTROLLERINFO)); + + // just return if could not alloc memory + if (NULL == hcInfo) + return; + + hcInfo->DeviceInfoType = HostControllerInfo; + + // Obtain the driver key name for this host controller. + // + driverKeyName = GetHCDDriverKeyName(hHCDev); + + if (NULL == driverKeyName) + { + // Failure obtaining driver key name. + OOPS(); + FREE(hcInfo); + return; + } + + // Don't enumerate this host controller again if it already + // on the list of enumerated host controllers. + // + listEntry = EnumeratedHCListHead.Flink; + + while (listEntry != &EnumeratedHCListHead) + { + hcInfoInList = CONTAINING_RECORD(listEntry, + USBHOSTCONTROLLERINFO, + ListEntry); + + if (strcmp(driverKeyName, hcInfoInList->DriverKey) == 0) + { + // Already on the list, exit + // + FREE(driverKeyName); + FREE(hcInfo); + return; + } + + listEntry = listEntry->Flink; + } + + // Obtain host controller device properties + { + size_t cbDriverName = 0; + HRESULT hr = S_OK; + + hr = StringCbLength(driverKeyName, MAX_DRIVER_KEY_NAME, &cbDriverName); + if (SUCCEEDED(hr)) + { + DevProps = DriverNameToDeviceProperties(driverKeyName, cbDriverName); + } + } + + hcInfo->DriverKey = driverKeyName; + + if (DevProps) + { + ULONG ven, dev, subsys, rev; + ven = dev = subsys = rev = 0; + + if (sscanf_s(DevProps->DeviceId, + "PCI\\VEN_%x&DEV_%x&SUBSYS_%x&REV_%x", + &ven, &dev, &subsys, &rev) != 4) + { + OOPS(); + } + + hcInfo->VendorID = ven; + hcInfo->DeviceID = dev; + hcInfo->SubSysID = subsys; + hcInfo->Revision = rev; + hcInfo->UsbDeviceProperties = DevProps; + } + else + { + OOPS(); + } + + if (DevProps != NULL && DevProps->DeviceDesc != NULL) + { + leafName = DevProps->DeviceDesc; + } + else + { + OOPS(); + } + + // Get the USB Host Controller power map + dwSuccess = GetHostControllerPowerMap(hHCDev, hcInfo); + + if (ERROR_SUCCESS != dwSuccess) + { + OOPS(); + } + + + // Get bus, device, and function + // + hcInfo->BusDeviceFunctionValid = FALSE; + + success = SetupDiGetDeviceRegistryProperty(deviceInfo, + deviceInfoData, + SPDRP_BUSNUMBER, + NULL, + (PBYTE)&hcInfo->BusNumber, + sizeof(hcInfo->BusNumber), + NULL); + + if (success) + { + success = SetupDiGetDeviceRegistryProperty(deviceInfo, + deviceInfoData, + SPDRP_ADDRESS, + NULL, + (PBYTE)&deviceAndFunction, + sizeof(deviceAndFunction), + NULL); + } + + if (success) + { + hcInfo->BusDevice = deviceAndFunction >> 16; + hcInfo->BusFunction = deviceAndFunction & 0xffff; + hcInfo->BusDeviceFunctionValid = TRUE; + } + + // Get the USB Host Controller info + dwSuccess = GetHostControllerInfo(hHCDev, hcInfo); + + if (ERROR_SUCCESS != dwSuccess) + { + OOPS(); + } + + // Add this host controller to the USB device tree view. + // + //hHCItem = AddLeaf(hTreeParent, + // (LPARAM)hcInfo, + // leafName, + // hcInfo->Revision == UsbSuperSpeed ? GoodSsDeviceIcon : GoodDeviceIcon); + + //if (NULL == hHCItem) + //{ + // // Failure adding host controller to USB device tree + // // view. + + // OOPS(); + // FREE(driverKeyName); + // FREE(hcInfo); + // return; + //} + + // Add this host controller to the list of enumerated + // host controllers. + // + InsertTailList(&EnumeratedHCListHead, + &hcInfo->ListEntry); + + // Get the name of the root hub for this host + // controller and then enumerate the root hub. + // + rootHubName = GetRootHubName(hHCDev); + + if (rootHubName != NULL) + { + size_t cbHubName = 0; + HRESULT hr = S_OK; + + hr = StringCbLength(rootHubName, MAX_DRIVER_KEY_NAME, &cbHubName); + if (SUCCEEDED(hr)) + { + EnumerateHub(hHCItem, + rootHubName, + cbHubName, + NULL, // ConnectionInfo + NULL, // ConnectionInfoV2 + NULL, // PortConnectorProps + NULL, // ConfigDesc + NULL, // BosDesc + NULL, // StringDescs + NULL); // We do not pass DevProps for RootHub + } + } + else + { + // Failure obtaining root hub name. + + OOPS(); + } + + return; +} + + +//***************************************************************************** +// +// EnumerateHub() +// +// hTreeParent - Handle of the TreeView item under which this hub should be +// added. +// +// HubName - Name of this hub. This pointer is kept so the caller can neither +// free nor reuse this memory. +// +// ConnectionInfo - NULL if this is a root hub, else this is the connection +// info for an external hub. This pointer is kept so the caller can neither +// free nor reuse this memory. +// +// ConfigDesc - NULL if this is a root hub, else this is the Configuration +// Descriptor for an external hub. This pointer is kept so the caller can +// neither free nor reuse this memory. +// +// StringDescs - NULL if this is a root hub. +// +// DevProps - Device properties of the hub +// +//***************************************************************************** + +VOID +EnumerateHub ( + HTREEITEM hTreeParent, + _In_reads_(cbHubName) PCHAR HubName, + _In_ size_t cbHubName, + _In_opt_ PUSB_NODE_CONNECTION_INFORMATION_EX ConnectionInfo, + _In_opt_ PUSB_NODE_CONNECTION_INFORMATION_EX_V2 ConnectionInfoV2, + _In_opt_ PUSB_PORT_CONNECTOR_PROPERTIES PortConnectorProps, + _In_opt_ PUSB_DESCRIPTOR_REQUEST ConfigDesc, + _In_opt_ PUSB_DESCRIPTOR_REQUEST BosDesc, + _In_opt_ PSTRING_DESCRIPTOR_NODE StringDescs, + _In_opt_ PUSB_DEVICE_PNP_STRINGS DevProps + ) +{ + // Initialize locals to not allocated state so the error cleanup routine + // only tries to cleanup things that were successfully allocated. + // + PUSB_NODE_INFORMATION hubInfo = NULL; + PUSB_HUB_INFORMATION_EX hubInfoEx = NULL; + PUSB_HUB_CAPABILITIES_EX hubCapabilityEx = NULL; + HANDLE hHubDevice = INVALID_HANDLE_VALUE; + HTREEITEM hItem = NULL; + PVOID info = NULL; + PCHAR deviceName = NULL; + ULONG nBytes = 0; + BOOL success = 0; + DWORD dwSizeOfLeafName = 0; + CHAR leafName[512] = {0}; + HRESULT hr = S_OK; + size_t cchHeader = 0; + size_t cchFullHubName = 0; + + // Allocate some space for a USBDEVICEINFO structure to hold the + // hub info, hub name, and connection info pointers. GPTR zero + // initializes the structure for us. + // + info = ALLOC(sizeof(USBEXTERNALHUBINFO)); + if (info == NULL) + { + OOPS(); + goto EnumerateHubError; + } + + // Allocate some space for a USB_NODE_INFORMATION structure for this Hub + // + hubInfo = (PUSB_NODE_INFORMATION)ALLOC(sizeof(USB_NODE_INFORMATION)); + if (hubInfo == NULL) + { + OOPS(); + goto EnumerateHubError; + } + + hubInfoEx = (PUSB_HUB_INFORMATION_EX)ALLOC(sizeof(USB_HUB_INFORMATION_EX)); + if (hubInfoEx == NULL) + { + OOPS(); + goto EnumerateHubError; + } + + hubCapabilityEx = (PUSB_HUB_CAPABILITIES_EX)ALLOC(sizeof(USB_HUB_CAPABILITIES_EX)); + if(hubCapabilityEx == NULL) + { + OOPS(); + goto EnumerateHubError; + } + + // Keep copies of the Hub Name, Connection Info, and Configuration + // Descriptor pointers + // + ((PUSBROOTHUBINFO)info)->HubInfo = hubInfo; + ((PUSBROOTHUBINFO)info)->HubName = HubName; + + if (ConnectionInfo != NULL) + { + ((PUSBEXTERNALHUBINFO)info)->DeviceInfoType = ExternalHubInfo; + ((PUSBEXTERNALHUBINFO)info)->ConnectionInfo = ConnectionInfo; + ((PUSBEXTERNALHUBINFO)info)->ConfigDesc = ConfigDesc; + ((PUSBEXTERNALHUBINFO)info)->StringDescs = StringDescs; + ((PUSBEXTERNALHUBINFO)info)->PortConnectorProps = PortConnectorProps; + ((PUSBEXTERNALHUBINFO)info)->HubInfoEx = hubInfoEx; + ((PUSBEXTERNALHUBINFO)info)->HubCapabilityEx = hubCapabilityEx; + ((PUSBEXTERNALHUBINFO)info)->BosDesc = BosDesc; + ((PUSBEXTERNALHUBINFO)info)->ConnectionInfoV2 = ConnectionInfoV2; + ((PUSBEXTERNALHUBINFO)info)->UsbDeviceProperties = DevProps; + } + else + { + ((PUSBROOTHUBINFO)info)->DeviceInfoType = RootHubInfo; + ((PUSBROOTHUBINFO)info)->HubInfoEx = hubInfoEx; + ((PUSBROOTHUBINFO)info)->HubCapabilityEx = hubCapabilityEx; + ((PUSBROOTHUBINFO)info)->PortConnectorProps = PortConnectorProps; + ((PUSBROOTHUBINFO)info)->UsbDeviceProperties = DevProps; + } + + // Allocate a temp buffer for the full hub device name. + // + hr = StringCbLength("\\\\.\\", MAX_DEVICE_PROP, &cchHeader); + if (FAILED(hr)) + { + goto EnumerateHubError; + } + cchFullHubName = cchHeader + cbHubName + 1; + deviceName = (PCHAR)ALLOC((DWORD) cchFullHubName); + if (deviceName == NULL) + { + OOPS(); + goto EnumerateHubError; + } + + // Create the full hub device name + // + hr = StringCchCopyN(deviceName, cchFullHubName, "\\\\.\\", cchHeader); + if (FAILED(hr)) + { + goto EnumerateHubError; + } + hr = StringCchCatN(deviceName, cchFullHubName, HubName, cbHubName); + if (FAILED(hr)) + { + goto EnumerateHubError; + } + + // Try to hub the open device + // + hHubDevice = CreateFile(deviceName, + GENERIC_WRITE, + FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL); + + // Done with temp buffer for full hub device name + // + FREE(deviceName); + + if (hHubDevice == INVALID_HANDLE_VALUE) + { + OOPS(); + goto EnumerateHubError; + } + + // + // Now query USBHUB for the USB_NODE_INFORMATION structure for this hub. + // This will tell us the number of downstream ports to enumerate, among + // other things. + // + success = DeviceIoControl(hHubDevice, + IOCTL_USB_GET_NODE_INFORMATION, + hubInfo, + sizeof(USB_NODE_INFORMATION), + hubInfo, + sizeof(USB_NODE_INFORMATION), + &nBytes, + NULL); + + if (!success) + { + OOPS(); + goto EnumerateHubError; + } + + success = DeviceIoControl(hHubDevice, + IOCTL_USB_GET_HUB_INFORMATION_EX, + hubInfoEx, + sizeof(USB_HUB_INFORMATION_EX), + hubInfoEx, + sizeof(USB_HUB_INFORMATION_EX), + &nBytes, + NULL); + + // + // Fail gracefully for downlevel OS's from Win8 + // + if (!success || nBytes < sizeof(USB_HUB_INFORMATION_EX)) + { + FREE(hubInfoEx); + hubInfoEx = NULL; + if (ConnectionInfo != NULL) + { + ((PUSBEXTERNALHUBINFO)info)->HubInfoEx = NULL; + } + else + { + ((PUSBROOTHUBINFO)info)->HubInfoEx = NULL; + } + } + + // + // Obtain Hub Capabilities + // + success = DeviceIoControl(hHubDevice, + IOCTL_USB_GET_HUB_CAPABILITIES_EX, + hubCapabilityEx, + sizeof(USB_HUB_CAPABILITIES_EX), + hubCapabilityEx, + sizeof(USB_HUB_CAPABILITIES_EX), + &nBytes, + NULL); + + // + // Fail gracefully + // + if (!success || nBytes < sizeof(USB_HUB_CAPABILITIES_EX)) + { + FREE(hubCapabilityEx); + hubCapabilityEx = NULL; + if (ConnectionInfo != NULL) + { + ((PUSBEXTERNALHUBINFO)info)->HubCapabilityEx = NULL; + } + else + { + ((PUSBROOTHUBINFO)info)->HubCapabilityEx = NULL; + } + } + + // Build the leaf name from the port number and the device description + // + dwSizeOfLeafName = sizeof(leafName); + if (ConnectionInfo) + { + StringCchPrintf(leafName, dwSizeOfLeafName, "[Port%d] ", ConnectionInfo->ConnectionIndex); + StringCchCat(leafName, + dwSizeOfLeafName, + ConnectionStatuses[ConnectionInfo->ConnectionStatus]); + StringCchCatN(leafName, + dwSizeOfLeafName, + " : ", + sizeof(" : ")); + } + + if (DevProps) + { + size_t cbDeviceDesc = 0; + hr = StringCbLength(DevProps->DeviceDesc, MAX_DRIVER_KEY_NAME, &cbDeviceDesc); + if(SUCCEEDED(hr)) + { + StringCchCatN(leafName, + dwSizeOfLeafName, + DevProps->DeviceDesc, + cbDeviceDesc); + } + } + else + { + if(ConnectionInfo != NULL) + { + // External hub + StringCchCatN(leafName, + dwSizeOfLeafName, + HubName, + cbHubName); + } + else + { + // Root hub + StringCchCatN(leafName, + dwSizeOfLeafName, + "RootHub", + sizeof("RootHub")); + } + } + + // Now add an item to the TreeView with the PUSBDEVICEINFO pointer info + // as the LPARAM reference value containing everything we know about the + // hub. + // + //hItem = AddLeaf(hTreeParent, + // (LPARAM)info, + // leafName, + // HubIcon); + + //if (hItem == NULL) + //{ + // OOPS(); + // goto EnumerateHubError; + //} + + // Now recursively enumerate the ports of this hub. + // + EnumerateHubPorts( + hItem, + hHubDevice, + hubInfo->u.HubInformation.HubDescriptor.bNumberOfPorts + ); + + + CloseHandle(hHubDevice); + return; + +EnumerateHubError: + // + // Clean up any stuff that got allocated + // + + if (hHubDevice != INVALID_HANDLE_VALUE) + { + CloseHandle(hHubDevice); + hHubDevice = INVALID_HANDLE_VALUE; + } + + if (hubInfo) + { + FREE(hubInfo); + } + + if (hubInfoEx) + { + FREE(hubInfoEx); + } + + if (info) + { + FREE(info); + } + + if (HubName) + { + FREE(HubName); + } + + if (ConnectionInfo) + { + FREE(ConnectionInfo); + } + + if (ConfigDesc) + { + FREE(ConfigDesc); + } + + if (BosDesc) + { + FREE(BosDesc); + } + + if (StringDescs != NULL) + { + PSTRING_DESCRIPTOR_NODE Next; + + do { + + Next = StringDescs->Next; + FREE(StringDescs); + StringDescs = Next; + + } while (StringDescs != NULL); + } +} + +//***************************************************************************** +// +// EnumerateHubPorts() +// +// hTreeParent - Handle of the TreeView item under which the hub port should +// be added. +// +// hHubDevice - Handle of the hub device to enumerate. +// +// NumPorts - Number of ports on the hub. +// +//***************************************************************************** + +VOID +EnumerateHubPorts ( + HTREEITEM hTreeParent, + HANDLE hHubDevice, + ULONG NumPorts +) +{ + ULONG index = 0; + BOOL success = 0; + HRESULT hr = S_OK; + PCHAR driverKeyName = NULL; + PUSB_DEVICE_PNP_STRINGS DevProps; + DWORD dwSizeOfLeafName = 0; + CHAR leafName[512]; + int icon = 0; + + PUSB_NODE_CONNECTION_INFORMATION_EX connectionInfoEx; + PUSB_PORT_CONNECTOR_PROPERTIES pPortConnectorProps; + USB_PORT_CONNECTOR_PROPERTIES portConnectorProps; + PUSB_DESCRIPTOR_REQUEST configDesc; + PUSB_DESCRIPTOR_REQUEST bosDesc; + PSTRING_DESCRIPTOR_NODE stringDescs; + PUSBDEVICEINFO info; + PUSB_NODE_CONNECTION_INFORMATION_EX_V2 connectionInfoExV2; + PDEVICE_INFO_NODE pNode; + + // Loop over all ports of the hub. + // + // Port indices are 1 based, not 0 based. + // + for (index = 1; index <= NumPorts; index++) + { + ULONG nBytesEx; + ULONG nBytes = 0; + + connectionInfoEx = NULL; + pPortConnectorProps = NULL; + ZeroMemory(&portConnectorProps, sizeof(portConnectorProps)); + configDesc = NULL; + bosDesc = NULL; + stringDescs = NULL; + info = NULL; + connectionInfoExV2 = NULL; + pNode = NULL; + DevProps = NULL; + ZeroMemory(leafName, sizeof(leafName)); + + // + // Allocate space to hold the connection info for this port. + // For now, allocate it big enough to hold info for 30 pipes. + // + // Endpoint numbers are 0-15. Endpoint number 0 is the standard + // control endpoint which is not explicitly listed in the Configuration + // Descriptor. There can be an IN endpoint and an OUT endpoint at + // endpoint numbers 1-15 so there can be a maximum of 30 endpoints + // per device configuration. + // + // Should probably size this dynamically at some point. + // + + nBytesEx = sizeof(USB_NODE_CONNECTION_INFORMATION_EX) + + (sizeof(USB_PIPE_INFO) * 30); + + connectionInfoEx = (PUSB_NODE_CONNECTION_INFORMATION_EX)ALLOC(nBytesEx); + + if (connectionInfoEx == NULL) + { + OOPS(); + break; + } + + connectionInfoExV2 = (PUSB_NODE_CONNECTION_INFORMATION_EX_V2) + ALLOC(sizeof(USB_NODE_CONNECTION_INFORMATION_EX_V2)); + + if (connectionInfoExV2 == NULL) + { + OOPS(); + FREE(connectionInfoEx); + break; + } + + // + // Now query USBHUB for the structures + // for this port. This will tell us if a device is attached to this + // port, among other things. + // The fault tolerate code is executed first. + // + + portConnectorProps.ConnectionIndex = index; + + success = DeviceIoControl(hHubDevice, + IOCTL_USB_GET_PORT_CONNECTOR_PROPERTIES, + &portConnectorProps, + sizeof(USB_PORT_CONNECTOR_PROPERTIES), + &portConnectorProps, + sizeof(USB_PORT_CONNECTOR_PROPERTIES), + &nBytes, + NULL); + + if (success && nBytes == sizeof(USB_PORT_CONNECTOR_PROPERTIES)) + { + pPortConnectorProps = (PUSB_PORT_CONNECTOR_PROPERTIES) + ALLOC(portConnectorProps.ActualLength); + + if (pPortConnectorProps != NULL) + { + pPortConnectorProps->ConnectionIndex = index; + + success = DeviceIoControl(hHubDevice, + IOCTL_USB_GET_PORT_CONNECTOR_PROPERTIES, + pPortConnectorProps, + portConnectorProps.ActualLength, + pPortConnectorProps, + portConnectorProps.ActualLength, + &nBytes, + NULL); + + if (!success || nBytes < portConnectorProps.ActualLength) + { + FREE(pPortConnectorProps); + pPortConnectorProps = NULL; + } + } + } + + connectionInfoExV2->ConnectionIndex = index; + connectionInfoExV2->Length = sizeof(USB_NODE_CONNECTION_INFORMATION_EX_V2); + connectionInfoExV2->SupportedUsbProtocols.Usb300 = 1; + + success = DeviceIoControl(hHubDevice, + IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX_V2, + connectionInfoExV2, + sizeof(USB_NODE_CONNECTION_INFORMATION_EX_V2), + connectionInfoExV2, + sizeof(USB_NODE_CONNECTION_INFORMATION_EX_V2), + &nBytes, + NULL); + + if (!success || nBytes < sizeof(USB_NODE_CONNECTION_INFORMATION_EX_V2)) + { + FREE(connectionInfoExV2); + connectionInfoExV2 = NULL; + } + + connectionInfoEx->ConnectionIndex = index; + + success = DeviceIoControl(hHubDevice, + IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, + connectionInfoEx, + nBytesEx, + connectionInfoEx, + nBytesEx, + &nBytesEx, + NULL); + + if (success) + { + // + // Since the USB_NODE_CONNECTION_INFORMATION_EX is used to display + // the device speed, but the hub driver doesn't support indication + // of superspeed, we overwrite the value if the super speed + // data structures are available and indicate the device is operating + // at SuperSpeed. + // + + if (connectionInfoEx->Speed == UsbHighSpeed + && connectionInfoExV2 != NULL + && (connectionInfoExV2->Flags.DeviceIsOperatingAtSuperSpeedOrHigher || + connectionInfoExV2->Flags.DeviceIsOperatingAtSuperSpeedPlusOrHigher)) + { + connectionInfoEx->Speed = UsbSuperSpeed; + } + } + else + { + PUSB_NODE_CONNECTION_INFORMATION connectionInfo = NULL; + + // Try using IOCTL_USB_GET_NODE_CONNECTION_INFORMATION + // instead of IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX + // + + nBytes = sizeof(USB_NODE_CONNECTION_INFORMATION) + + sizeof(USB_PIPE_INFO) * 30; + + connectionInfo = (PUSB_NODE_CONNECTION_INFORMATION)ALLOC(nBytes); + + if (connectionInfo == NULL) + { + OOPS(); + + FREE(connectionInfoEx); + if (pPortConnectorProps != NULL) + { + FREE(pPortConnectorProps); + } + if (connectionInfoExV2 != NULL) + { + FREE(connectionInfoExV2); + } + continue; + } + + connectionInfo->ConnectionIndex = index; + + success = DeviceIoControl(hHubDevice, + IOCTL_USB_GET_NODE_CONNECTION_INFORMATION, + connectionInfo, + nBytes, + connectionInfo, + nBytes, + &nBytes, + NULL); + + if (!success) + { + OOPS(); + + FREE(connectionInfo); + FREE(connectionInfoEx); + if (pPortConnectorProps != NULL) + { + FREE(pPortConnectorProps); + } + if (connectionInfoExV2 != NULL) + { + FREE(connectionInfoExV2); + } + continue; + } + + // Copy IOCTL_USB_GET_NODE_CONNECTION_INFORMATION into + // IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX structure. + // + connectionInfoEx->ConnectionIndex = connectionInfo->ConnectionIndex; + connectionInfoEx->DeviceDescriptor = connectionInfo->DeviceDescriptor; + connectionInfoEx->CurrentConfigurationValue = connectionInfo->CurrentConfigurationValue; + connectionInfoEx->Speed = connectionInfo->LowSpeed ? UsbLowSpeed : UsbFullSpeed; + connectionInfoEx->DeviceIsHub = connectionInfo->DeviceIsHub; + connectionInfoEx->DeviceAddress = connectionInfo->DeviceAddress; + connectionInfoEx->NumberOfOpenPipes = connectionInfo->NumberOfOpenPipes; + connectionInfoEx->ConnectionStatus = connectionInfo->ConnectionStatus; + + memcpy(&connectionInfoEx->PipeList[0], + &connectionInfo->PipeList[0], + sizeof(USB_PIPE_INFO) * 30); + + FREE(connectionInfo); + } + + // Update the count of connected devices + // + if (connectionInfoEx->ConnectionStatus == DeviceConnected) + { + TotalDevicesConnected++; + } + + if (connectionInfoEx->DeviceIsHub) + { + TotalHubs++; + } + + // If there is a device connected, get the Device Description + // + if (connectionInfoEx->ConnectionStatus != NoDeviceConnected) + { + driverKeyName = GetDriverKeyName(hHubDevice, index); + + if (driverKeyName) + { + size_t cbDriverName = 0; + + hr = StringCbLength(driverKeyName, MAX_DRIVER_KEY_NAME, &cbDriverName); + if (SUCCEEDED(hr)) + { + DevProps = DriverNameToDeviceProperties(driverKeyName, cbDriverName); + pNode = FindMatchingDeviceNodeForDriverName(driverKeyName, connectionInfoEx->DeviceIsHub); + } + FREE(driverKeyName); + } + + } + + // If there is a device connected to the port, try to retrieve the + // Configuration Descriptor from the device. + // + if (gDoConfigDesc && + connectionInfoEx->ConnectionStatus == DeviceConnected) + { + configDesc = GetConfigDescriptor(hHubDevice, + index, + 0); + } + else + { + configDesc = NULL; + } + + if (configDesc != NULL && + connectionInfoEx->DeviceDescriptor.bcdUSB > 0x0200) + { + bosDesc = GetBOSDescriptor(hHubDevice, + index); + } + else + { + bosDesc = NULL; + } + + if (configDesc != NULL && + AreThereStringDescriptors(&connectionInfoEx->DeviceDescriptor, + (PUSB_CONFIGURATION_DESCRIPTOR)(configDesc+1))) + { + stringDescs = GetAllStringDescriptors ( + hHubDevice, + index, + &connectionInfoEx->DeviceDescriptor, + (PUSB_CONFIGURATION_DESCRIPTOR)(configDesc+1)); + } + else + { + stringDescs = NULL; + } + + // If the device connected to the port is an external hub, get the + // name of the external hub and recursively enumerate it. + // + if (connectionInfoEx->DeviceIsHub) + { + PCHAR extHubName; + size_t cbHubName = 0; + + extHubName = GetExternalHubName(hHubDevice, index); + if (extHubName != NULL) + { + hr = StringCbLength(extHubName, MAX_DRIVER_KEY_NAME, &cbHubName); + if (SUCCEEDED(hr)) + { + EnumerateHub(hTreeParent, //hPortItem, + extHubName, + cbHubName, + connectionInfoEx, + connectionInfoExV2, + pPortConnectorProps, + configDesc, + bosDesc, + stringDescs, + DevProps); + } + } + } + else + { + // Allocate some space for a USBDEVICEINFO structure to hold the + // hub info, hub name, and connection info pointers. GPTR zero + // initializes the structure for us. + // + info = (PUSBDEVICEINFO) ALLOC(sizeof(USBDEVICEINFO)); + + if (info == NULL) + { + OOPS(); + if (configDesc != NULL) + { + FREE(configDesc); + } + if (bosDesc != NULL) + { + FREE(bosDesc); + } + FREE(connectionInfoEx); + + if (pPortConnectorProps != NULL) + { + FREE(pPortConnectorProps); + } + if (connectionInfoExV2 != NULL) + { + FREE(connectionInfoExV2); + } + break; + } + + info->DeviceInfoType = DeviceInfo; + info->ConnectionInfo = connectionInfoEx; + info->PortConnectorProps = pPortConnectorProps; + info->ConfigDesc = configDesc; + info->StringDescs = stringDescs; + info->BosDesc = bosDesc; + info->ConnectionInfoV2 = connectionInfoExV2; + info->UsbDeviceProperties = DevProps; + info->DeviceInfoNode = pNode; + + StringCchPrintf(leafName, sizeof(leafName), "[Port%d] ", index); + + // Add error description if ConnectionStatus is other than NoDeviceConnected / DeviceConnected + StringCchCat(leafName, + sizeof(leafName), + ConnectionStatuses[connectionInfoEx->ConnectionStatus]); + + if (DevProps) + { + size_t cchDeviceDesc = 0; + + hr = StringCbLength(DevProps->DeviceDesc, MAX_DEVICE_PROP, &cchDeviceDesc); + if (FAILED(hr)) + { + OOPS(); + } + dwSizeOfLeafName = sizeof(leafName); + StringCchCatN(leafName, + dwSizeOfLeafName - 1, + " : ", + sizeof(" : ")); + StringCchCatN(leafName, + dwSizeOfLeafName - 1, + DevProps->DeviceDesc, + cchDeviceDesc ); + } + + if (connectionInfoEx->ConnectionStatus == NoDeviceConnected) + { + if (connectionInfoExV2 != NULL && + connectionInfoExV2->SupportedUsbProtocols.Usb300 == 1) + { + icon = NoSsDeviceIcon; + } + else + { + icon = NoDeviceIcon; + } + } + else if (connectionInfoEx->CurrentConfigurationValue) + { + if (connectionInfoEx->Speed == UsbSuperSpeed) + { + icon = GoodSsDeviceIcon; + } + else + { + icon = GoodDeviceIcon; + } + } + else + { + icon = BadDeviceIcon; + } + + //AddLeaf(hTreeParent, //hPortItem, + // (LPARAM)info, + // leafName, + // icon); + } + } // for +} + + +//***************************************************************************** +// +// WideStrToMultiStr() +// +//***************************************************************************** + +PCHAR WideStrToMultiStr ( + _In_reads_bytes_(cbWideStr) PWCHAR WideStr, + _In_ size_t cbWideStr + ) +{ + ULONG nBytes = 0; + PCHAR MultiStr = NULL; + PWCHAR pWideStr = NULL; + + // Use local string to guarantee zero termination + pWideStr = (PWCHAR) ALLOC((DWORD) cbWideStr + sizeof(WCHAR)); + if (NULL == pWideStr) + { + return NULL; + } + memset(pWideStr, 0, cbWideStr + sizeof(WCHAR)); + memcpy(pWideStr, WideStr, cbWideStr); + + // Get the length of the converted string + // + nBytes = WideCharToMultiByte( + CP_ACP, + WC_NO_BEST_FIT_CHARS, + pWideStr, + -1, + NULL, + 0, + NULL, + NULL); + + if (nBytes == 0) + { + FREE(pWideStr); + return NULL; + } + + // Allocate space to hold the converted string + // + MultiStr = ALLOC(nBytes); + if (MultiStr == NULL) + { + FREE(pWideStr); + return NULL; + } + + // Convert the string + // + nBytes = WideCharToMultiByte( + CP_ACP, + WC_NO_BEST_FIT_CHARS, + pWideStr, + -1, + MultiStr, + nBytes, + NULL, + NULL); + + if (nBytes == 0) + { + FREE(MultiStr); + FREE(pWideStr); + return NULL; + } + + FREE(pWideStr); + return MultiStr; +} + +//***************************************************************************** +// +// GetRootHubName() +// +//***************************************************************************** + +PCHAR GetRootHubName ( + HANDLE HostController +) +{ + BOOL success = 0; + ULONG nBytes = 0; + USB_ROOT_HUB_NAME rootHubName; + PUSB_ROOT_HUB_NAME rootHubNameW = NULL; + PCHAR rootHubNameA = NULL; + + // Get the length of the name of the Root Hub attached to the + // Host Controller + // + success = DeviceIoControl(HostController, + IOCTL_USB_GET_ROOT_HUB_NAME, + 0, + 0, + &rootHubName, + sizeof(rootHubName), + &nBytes, + NULL); + + if (!success) + { + OOPS(); + goto GetRootHubNameError; + } + + // Allocate space to hold the Root Hub name + // + nBytes = rootHubName.ActualLength; + + rootHubNameW = ALLOC(nBytes); + if (rootHubNameW == NULL) + { + OOPS(); + goto GetRootHubNameError; + } + + // Get the name of the Root Hub attached to the Host Controller + // + success = DeviceIoControl(HostController, + IOCTL_USB_GET_ROOT_HUB_NAME, + NULL, + 0, + rootHubNameW, + nBytes, + &nBytes, + NULL); + if (!success) + { + OOPS(); + goto GetRootHubNameError; + } + + // Convert the Root Hub name + // + rootHubNameA = WideStrToMultiStr(rootHubNameW->RootHubName, nBytes - sizeof(USB_ROOT_HUB_NAME) + sizeof(WCHAR)); + + // All done, free the uncoverted Root Hub name and return the + // converted Root Hub name + // + FREE(rootHubNameW); + + return rootHubNameA; + +GetRootHubNameError: + // There was an error, free anything that was allocated + // + if (rootHubNameW != NULL) + { + FREE(rootHubNameW); + rootHubNameW = NULL; + } + return NULL; +} + + +//***************************************************************************** +// +// GetExternalHubName() +// +//***************************************************************************** + +PCHAR GetExternalHubName ( + HANDLE Hub, + ULONG ConnectionIndex +) +{ + BOOL success = 0; + ULONG nBytes = 0; + USB_NODE_CONNECTION_NAME extHubName; + PUSB_NODE_CONNECTION_NAME extHubNameW = NULL; + PCHAR extHubNameA = NULL; + + // Get the length of the name of the external hub attached to the + // specified port. + // + extHubName.ConnectionIndex = ConnectionIndex; + + success = DeviceIoControl(Hub, + IOCTL_USB_GET_NODE_CONNECTION_NAME, + &extHubName, + sizeof(extHubName), + &extHubName, + sizeof(extHubName), + &nBytes, + NULL); + + if (!success) + { + OOPS(); + goto GetExternalHubNameError; + } + + // Allocate space to hold the external hub name + // + nBytes = extHubName.ActualLength; + + if (nBytes <= sizeof(extHubName)) + { + OOPS(); + goto GetExternalHubNameError; + } + + extHubNameW = ALLOC(nBytes); + + if (extHubNameW == NULL) + { + OOPS(); + goto GetExternalHubNameError; + } + + // Get the name of the external hub attached to the specified port + // + extHubNameW->ConnectionIndex = ConnectionIndex; + + success = DeviceIoControl(Hub, + IOCTL_USB_GET_NODE_CONNECTION_NAME, + extHubNameW, + nBytes, + extHubNameW, + nBytes, + &nBytes, + NULL); + + if (!success) + { + OOPS(); + goto GetExternalHubNameError; + } + + // Convert the External Hub name + // + extHubNameA = WideStrToMultiStr(extHubNameW->NodeName, nBytes - sizeof(USB_NODE_CONNECTION_NAME) + sizeof(WCHAR)); + + // All done, free the uncoverted external hub name and return the + // converted external hub name + // + FREE(extHubNameW); + + return extHubNameA; + + +GetExternalHubNameError: + // There was an error, free anything that was allocated + // + if (extHubNameW != NULL) + { + FREE(extHubNameW); + extHubNameW = NULL; + } + + return NULL; +} + + +//***************************************************************************** +// +// GetDriverKeyName() +// +//***************************************************************************** + +PCHAR GetDriverKeyName ( + HANDLE Hub, + ULONG ConnectionIndex +) +{ + BOOL success = 0; + ULONG nBytes = 0; + USB_NODE_CONNECTION_DRIVERKEY_NAME driverKeyName; + PUSB_NODE_CONNECTION_DRIVERKEY_NAME driverKeyNameW = NULL; + PCHAR driverKeyNameA = NULL; + + // Get the length of the name of the driver key of the device attached to + // the specified port. + // + driverKeyName.ConnectionIndex = ConnectionIndex; + + success = DeviceIoControl(Hub, + IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, + &driverKeyName, + sizeof(driverKeyName), + &driverKeyName, + sizeof(driverKeyName), + &nBytes, + NULL); + + if (!success) + { + OOPS(); + goto GetDriverKeyNameError; + } + + // Allocate space to hold the driver key name + // + nBytes = driverKeyName.ActualLength; + + if (nBytes <= sizeof(driverKeyName)) + { + OOPS(); + goto GetDriverKeyNameError; + } + + driverKeyNameW = ALLOC(nBytes); + if (driverKeyNameW == NULL) + { + OOPS(); + goto GetDriverKeyNameError; + } + + // Get the name of the driver key of the device attached to + // the specified port. + // + driverKeyNameW->ConnectionIndex = ConnectionIndex; + + success = DeviceIoControl(Hub, + IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, + driverKeyNameW, + nBytes, + driverKeyNameW, + nBytes, + &nBytes, + NULL); + + if (!success) + { + OOPS(); + goto GetDriverKeyNameError; + } + + // Convert the driver key name + // + driverKeyNameA = WideStrToMultiStr(driverKeyNameW->DriverKeyName, nBytes - sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME) + sizeof(WCHAR)); + + // All done, free the uncoverted driver key name and return the + // converted driver key name + // + FREE(driverKeyNameW); + + return driverKeyNameA; + + +GetDriverKeyNameError: + // There was an error, free anything that was allocated + // + if (driverKeyNameW != NULL) + { + FREE(driverKeyNameW); + driverKeyNameW = NULL; + } + + return NULL; +} + + +//***************************************************************************** +// +// GetHCDDriverKeyName() +// +//***************************************************************************** + +PCHAR GetHCDDriverKeyName ( + HANDLE HCD +) +{ + BOOL success = 0; + ULONG nBytes = 0; + USB_HCD_DRIVERKEY_NAME driverKeyName = {0}; + PUSB_HCD_DRIVERKEY_NAME driverKeyNameW = NULL; + PCHAR driverKeyNameA = NULL; + + ZeroMemory(&driverKeyName, sizeof(driverKeyName)); + + // Get the length of the name of the driver key of the HCD + // + success = DeviceIoControl(HCD, + IOCTL_GET_HCD_DRIVERKEY_NAME, + &driverKeyName, + sizeof(driverKeyName), + &driverKeyName, + sizeof(driverKeyName), + &nBytes, + NULL); + + if (!success) + { + OOPS(); + goto GetHCDDriverKeyNameError; + } + + // Allocate space to hold the driver key name + // + nBytes = driverKeyName.ActualLength; + if (nBytes <= sizeof(driverKeyName)) + { + OOPS(); + goto GetHCDDriverKeyNameError; + } + + driverKeyNameW = ALLOC(nBytes); + if (driverKeyNameW == NULL) + { + OOPS(); + goto GetHCDDriverKeyNameError; + } + + // Get the name of the driver key of the device attached to + // the specified port. + // + + success = DeviceIoControl(HCD, + IOCTL_GET_HCD_DRIVERKEY_NAME, + driverKeyNameW, + nBytes, + driverKeyNameW, + nBytes, + &nBytes, + NULL); + if (!success) + { + OOPS(); + goto GetHCDDriverKeyNameError; + } + + // + // Convert the driver key name + // Pass the length of the DriverKeyName string + // + + driverKeyNameA = WideStrToMultiStr(driverKeyNameW->DriverKeyName, nBytes - sizeof(USB_HCD_DRIVERKEY_NAME) + sizeof(WCHAR)); + + // All done, free the uncoverted driver key name and return the + // converted driver key name + // + FREE(driverKeyNameW); + + return driverKeyNameA; + +GetHCDDriverKeyNameError: + // There was an error, free anything that was allocated + // + if (driverKeyNameW != NULL) + { + FREE(driverKeyNameW); + driverKeyNameW = NULL; + } + + return NULL; +} + + +//***************************************************************************** +// +// GetConfigDescriptor() +// +// hHubDevice - Handle of the hub device containing the port from which the +// Configuration Descriptor will be requested. +// +// ConnectionIndex - Identifies the port on the hub to which a device is +// attached from which the Configuration Descriptor will be requested. +// +// DescriptorIndex - Configuration Descriptor index, zero based. +// +//***************************************************************************** + +PUSB_DESCRIPTOR_REQUEST +GetConfigDescriptor ( + HANDLE hHubDevice, + ULONG ConnectionIndex, + UCHAR DescriptorIndex +) +{ + BOOL success = 0; + ULONG nBytes = 0; + ULONG nBytesReturned = 0; + + UCHAR configDescReqBuf[sizeof(USB_DESCRIPTOR_REQUEST) + + sizeof(USB_CONFIGURATION_DESCRIPTOR)]; + + PUSB_DESCRIPTOR_REQUEST configDescReq = NULL; + PUSB_CONFIGURATION_DESCRIPTOR configDesc = NULL; + + + // Request the Configuration Descriptor the first time using our + // local buffer, which is just big enough for the Cofiguration + // Descriptor itself. + // + nBytes = sizeof(configDescReqBuf); + + configDescReq = (PUSB_DESCRIPTOR_REQUEST)configDescReqBuf; + configDesc = (PUSB_CONFIGURATION_DESCRIPTOR)(configDescReq+1); + + // Zero fill the entire request structure + // + memset(configDescReq, 0, nBytes); + + // Indicate the port from which the descriptor will be requested + // + configDescReq->ConnectionIndex = ConnectionIndex; + + // + // USBHUB uses URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE to process this + // IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION request. + // + // USBD will automatically initialize these fields: + // bmRequest = 0x80 + // bRequest = 0x06 + // + // We must inititialize these fields: + // wValue = Descriptor Type (high) and Descriptor Index (low byte) + // wIndex = Zero (or Language ID for String Descriptors) + // wLength = Length of descriptor buffer + // + configDescReq->SetupPacket.wValue = (USB_CONFIGURATION_DESCRIPTOR_TYPE << 8) + | DescriptorIndex; + + configDescReq->SetupPacket.wLength = (USHORT)(nBytes - sizeof(USB_DESCRIPTOR_REQUEST)); + + // Now issue the get descriptor request. + // + success = DeviceIoControl(hHubDevice, + IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, + configDescReq, + nBytes, + configDescReq, + nBytes, + &nBytesReturned, + NULL); + + if (!success) + { + OOPS(); + return NULL; + } + + if (nBytes != nBytesReturned) + { + OOPS(); + return NULL; + } + + if (configDesc->wTotalLength < sizeof(USB_CONFIGURATION_DESCRIPTOR)) + { + OOPS(); + return NULL; + } + + // Now request the entire Configuration Descriptor using a dynamically + // allocated buffer which is sized big enough to hold the entire descriptor + // + nBytes = sizeof(USB_DESCRIPTOR_REQUEST) + configDesc->wTotalLength; + + configDescReq = (PUSB_DESCRIPTOR_REQUEST)ALLOC(nBytes); + + if (configDescReq == NULL) + { + OOPS(); + return NULL; + } + + configDesc = (PUSB_CONFIGURATION_DESCRIPTOR)(configDescReq+1); + + // Indicate the port from which the descriptor will be requested + // + configDescReq->ConnectionIndex = ConnectionIndex; + + // + // USBHUB uses URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE to process this + // IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION request. + // + // USBD will automatically initialize these fields: + // bmRequest = 0x80 + // bRequest = 0x06 + // + // We must inititialize these fields: + // wValue = Descriptor Type (high) and Descriptor Index (low byte) + // wIndex = Zero (or Language ID for String Descriptors) + // wLength = Length of descriptor buffer + // + configDescReq->SetupPacket.wValue = (USB_CONFIGURATION_DESCRIPTOR_TYPE << 8) + | DescriptorIndex; + + configDescReq->SetupPacket.wLength = (USHORT)(nBytes - sizeof(USB_DESCRIPTOR_REQUEST)); + + // Now issue the get descriptor request. + // + + success = DeviceIoControl(hHubDevice, + IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, + configDescReq, + nBytes, + configDescReq, + nBytes, + &nBytesReturned, + NULL); + + if (!success) + { + OOPS(); + FREE(configDescReq); + return NULL; + } + + if (nBytes != nBytesReturned) + { + OOPS(); + FREE(configDescReq); + return NULL; + } + + if (configDesc->wTotalLength != (nBytes - sizeof(USB_DESCRIPTOR_REQUEST))) + { + OOPS(); + FREE(configDescReq); + return NULL; + } + + return configDescReq; +} + + + +//***************************************************************************** +// +// GetBOSDescriptor() +// +// hHubDevice - Handle of the hub device containing the port from which the +// Configuration Descriptor will be requested. +// +// ConnectionIndex - Identifies the port on the hub to which a device is +// attached from which the BOS Descriptor will be requested. +// +//***************************************************************************** + +PUSB_DESCRIPTOR_REQUEST +GetBOSDescriptor ( + HANDLE hHubDevice, + ULONG ConnectionIndex +) +{ + BOOL success = 0; + ULONG nBytes = 0; + ULONG nBytesReturned = 0; + + UCHAR bosDescReqBuf[sizeof(USB_DESCRIPTOR_REQUEST) + + sizeof(USB_BOS_DESCRIPTOR)]; + + PUSB_DESCRIPTOR_REQUEST bosDescReq = NULL; + PUSB_BOS_DESCRIPTOR bosDesc = NULL; + + + // Request the BOS Descriptor the first time using our + // local buffer, which is just big enough for the BOS + // Descriptor itself. + // + nBytes = sizeof(bosDescReqBuf); + + bosDescReq = (PUSB_DESCRIPTOR_REQUEST)bosDescReqBuf; + bosDesc = (PUSB_BOS_DESCRIPTOR)(bosDescReq+1); + + // Zero fill the entire request structure + // + memset(bosDescReq, 0, nBytes); + + // Indicate the port from which the descriptor will be requested + // + bosDescReq->ConnectionIndex = ConnectionIndex; + + // + // USBHUB uses URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE to process this + // IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION request. + // + // USBD will automatically initialize these fields: + // bmRequest = 0x80 + // bRequest = 0x06 + // + // We must inititialize these fields: + // wValue = Descriptor Type (high) and Descriptor Index (low byte) + // wIndex = Zero (or Language ID for String Descriptors) + // wLength = Length of descriptor buffer + // + bosDescReq->SetupPacket.wValue = (USB_BOS_DESCRIPTOR_TYPE << 8); + + bosDescReq->SetupPacket.wLength = (USHORT)(nBytes - sizeof(USB_DESCRIPTOR_REQUEST)); + + // Now issue the get descriptor request. + // + success = DeviceIoControl(hHubDevice, + IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, + bosDescReq, + nBytes, + bosDescReq, + nBytes, + &nBytesReturned, + NULL); + + if (!success) + { + OOPS(); + return NULL; + } + + if (nBytes != nBytesReturned) + { + OOPS(); + return NULL; + } + + if (bosDesc->wTotalLength < sizeof(USB_BOS_DESCRIPTOR)) + { + OOPS(); + return NULL; + } + + // Now request the entire BOS Descriptor using a dynamically + // allocated buffer which is sized big enough to hold the entire descriptor + // + nBytes = sizeof(USB_DESCRIPTOR_REQUEST) + bosDesc->wTotalLength; + + bosDescReq = (PUSB_DESCRIPTOR_REQUEST)ALLOC(nBytes); + + if (bosDescReq == NULL) + { + OOPS(); + return NULL; + } + + bosDesc = (PUSB_BOS_DESCRIPTOR)(bosDescReq+1); + + // Indicate the port from which the descriptor will be requested + // + bosDescReq->ConnectionIndex = ConnectionIndex; + + // + // USBHUB uses URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE to process this + // IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION request. + // + // USBD will automatically initialize these fields: + // bmRequest = 0x80 + // bRequest = 0x06 + // + // We must inititialize these fields: + // wValue = Descriptor Type (high) and Descriptor Index (low byte) + // wIndex = Zero (or Language ID for String Descriptors) + // wLength = Length of descriptor buffer + // + bosDescReq->SetupPacket.wValue = (USB_BOS_DESCRIPTOR_TYPE << 8); + + bosDescReq->SetupPacket.wLength = (USHORT)(nBytes - sizeof(USB_DESCRIPTOR_REQUEST)); + + // Now issue the get descriptor request. + // + + success = DeviceIoControl(hHubDevice, + IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, + bosDescReq, + nBytes, + bosDescReq, + nBytes, + &nBytesReturned, + NULL); + + if (!success) + { + OOPS(); + FREE(bosDescReq); + return NULL; + } + + if (nBytes != nBytesReturned) + { + OOPS(); + FREE(bosDescReq); + return NULL; + } + + if (bosDesc->wTotalLength != (nBytes - sizeof(USB_DESCRIPTOR_REQUEST))) + { + OOPS(); + FREE(bosDescReq); + return NULL; + } + + return bosDescReq; +} + + +//***************************************************************************** +// +// AreThereStringDescriptors() +// +// DeviceDesc - Device Descriptor for which String Descriptors should be +// checked. +// +// ConfigDesc - Configuration Descriptor (also containing Interface Descriptor) +// for which String Descriptors should be checked. +// +//***************************************************************************** + +BOOL +AreThereStringDescriptors ( + PUSB_DEVICE_DESCRIPTOR DeviceDesc, + PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc +) +{ + PUCHAR descEnd = NULL; + PUSB_COMMON_DESCRIPTOR commonDesc = NULL; + + // + // Check Device Descriptor strings + // + + if (DeviceDesc->iManufacturer || + DeviceDesc->iProduct || + DeviceDesc->iSerialNumber + ) + { + return TRUE; + } + + + // + // Check the Configuration and Interface Descriptor strings + // + + descEnd = (PUCHAR)ConfigDesc + ConfigDesc->wTotalLength; + + commonDesc = (PUSB_COMMON_DESCRIPTOR)ConfigDesc; + + while ((PUCHAR)commonDesc + sizeof(USB_COMMON_DESCRIPTOR) < descEnd && + (PUCHAR)commonDesc + commonDesc->bLength <= descEnd) + { + switch (commonDesc->bDescriptorType) + { + case USB_CONFIGURATION_DESCRIPTOR_TYPE: + case USB_OTHER_SPEED_CONFIGURATION_DESCRIPTOR_TYPE: + if (commonDesc->bLength != sizeof(USB_CONFIGURATION_DESCRIPTOR)) + { + OOPS(); + break; + } + if (((PUSB_CONFIGURATION_DESCRIPTOR)commonDesc)->iConfiguration) + { + return TRUE; + } + commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength); + continue; + + case USB_INTERFACE_DESCRIPTOR_TYPE: + if (commonDesc->bLength != sizeof(USB_INTERFACE_DESCRIPTOR) && + commonDesc->bLength != sizeof(USB_INTERFACE_DESCRIPTOR2)) + { + OOPS(); + break; + } + if (((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->iInterface) + { + return TRUE; + } + commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength); + continue; + + default: + commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength); + continue; + } + break; + } + + return FALSE; +} + + +//***************************************************************************** +// +// GetAllStringDescriptors() +// +// hHubDevice - Handle of the hub device containing the port from which the +// String Descriptors will be requested. +// +// ConnectionIndex - Identifies the port on the hub to which a device is +// attached from which the String Descriptors will be requested. +// +// DeviceDesc - Device Descriptor for which String Descriptors should be +// requested. +// +// ConfigDesc - Configuration Descriptor (also containing Interface Descriptor) +// for which String Descriptors should be requested. +// +//***************************************************************************** + +PSTRING_DESCRIPTOR_NODE +GetAllStringDescriptors ( + HANDLE hHubDevice, + ULONG ConnectionIndex, + PUSB_DEVICE_DESCRIPTOR DeviceDesc, + PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc +) +{ + PSTRING_DESCRIPTOR_NODE supportedLanguagesString = NULL; + ULONG numLanguageIDs = 0; + USHORT *languageIDs = NULL; + + PUCHAR descEnd = NULL; + PUSB_COMMON_DESCRIPTOR commonDesc = NULL; + UCHAR uIndex = 1; + UCHAR bInterfaceClass = 0; + BOOL getMoreStrings = FALSE; + HRESULT hr = S_OK; + + // + // Get the array of supported Language IDs, which is returned + // in String Descriptor 0 + // + supportedLanguagesString = GetStringDescriptor(hHubDevice, + ConnectionIndex, + 0, + 0); + + if (supportedLanguagesString == NULL) + { + return NULL; + } + + numLanguageIDs = (supportedLanguagesString->StringDescriptor->bLength - 2) / 2; + + languageIDs = &supportedLanguagesString->StringDescriptor->bString[0]; + + // + // Get the Device Descriptor strings + // + + if (DeviceDesc->iManufacturer) + { + GetStringDescriptors(hHubDevice, + ConnectionIndex, + DeviceDesc->iManufacturer, + numLanguageIDs, + languageIDs, + supportedLanguagesString); + } + + if (DeviceDesc->iProduct) + { + GetStringDescriptors(hHubDevice, + ConnectionIndex, + DeviceDesc->iProduct, + numLanguageIDs, + languageIDs, + supportedLanguagesString); + } + + if (DeviceDesc->iSerialNumber) + { + GetStringDescriptors(hHubDevice, + ConnectionIndex, + DeviceDesc->iSerialNumber, + numLanguageIDs, + languageIDs, + supportedLanguagesString); + } + + // + // Get the Configuration and Interface Descriptor strings + // + + descEnd = (PUCHAR)ConfigDesc + ConfigDesc->wTotalLength; + + commonDesc = (PUSB_COMMON_DESCRIPTOR)ConfigDesc; + + while ((PUCHAR)commonDesc + sizeof(USB_COMMON_DESCRIPTOR) < descEnd && + (PUCHAR)commonDesc + commonDesc->bLength <= descEnd) + { + switch (commonDesc->bDescriptorType) + { + case USB_CONFIGURATION_DESCRIPTOR_TYPE: + if (commonDesc->bLength != sizeof(USB_CONFIGURATION_DESCRIPTOR)) + { + OOPS(); + break; + } + if (((PUSB_CONFIGURATION_DESCRIPTOR)commonDesc)->iConfiguration) + { + GetStringDescriptors(hHubDevice, + ConnectionIndex, + ((PUSB_CONFIGURATION_DESCRIPTOR)commonDesc)->iConfiguration, + numLanguageIDs, + languageIDs, + supportedLanguagesString); + } + commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength); + continue; + + case USB_IAD_DESCRIPTOR_TYPE: + if (commonDesc->bLength < sizeof(USB_IAD_DESCRIPTOR)) + { + OOPS(); + break; + } + if (((PUSB_IAD_DESCRIPTOR)commonDesc)->iFunction) + { + GetStringDescriptors(hHubDevice, + ConnectionIndex, + ((PUSB_IAD_DESCRIPTOR)commonDesc)->iFunction, + numLanguageIDs, + languageIDs, + supportedLanguagesString); + } + commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength); + continue; + + case USB_INTERFACE_DESCRIPTOR_TYPE: + if (commonDesc->bLength != sizeof(USB_INTERFACE_DESCRIPTOR) && + commonDesc->bLength != sizeof(USB_INTERFACE_DESCRIPTOR2)) + { + OOPS(); + break; + } + if (((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->iInterface) + { + GetStringDescriptors(hHubDevice, + ConnectionIndex, + ((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->iInterface, + numLanguageIDs, + languageIDs, + supportedLanguagesString); + } + + // + // We need to display more string descriptors for the following + // interface classes + // + bInterfaceClass = ((PUSB_INTERFACE_DESCRIPTOR)commonDesc)->bInterfaceClass; + if (bInterfaceClass == USB_DEVICE_CLASS_VIDEO) + { + getMoreStrings = TRUE; + } + commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength); + continue; + + default: + commonDesc = (PUSB_COMMON_DESCRIPTOR) ((PUCHAR) commonDesc + commonDesc->bLength); + continue; + } + break; + } + + if (getMoreStrings) + { + // + // We might need to display strings later that are referenced only in + // class-specific descriptors. Get String Descriptors 1 through 32 (an + // arbitrary upper limit for Strings needed due to "bad devices" + // returning an infinite repeat of Strings 0 through 4) until one is not + // found. + // + // There are also "bad devices" that have issues even querying 1-32, but + // historically USBView made this query, so the query should be safe for + // video devices. + // + for (uIndex = 1; SUCCEEDED(hr) && (uIndex < NUM_STRING_DESC_TO_GET); uIndex++) + { + hr = GetStringDescriptors(hHubDevice, + ConnectionIndex, + uIndex, + numLanguageIDs, + languageIDs, + supportedLanguagesString); + } + } + + return supportedLanguagesString; +} + + + +//***************************************************************************** +// +// GetStringDescriptor() +// +// hHubDevice - Handle of the hub device containing the port from which the +// String Descriptor will be requested. +// +// ConnectionIndex - Identifies the port on the hub to which a device is +// attached from which the String Descriptor will be requested. +// +// DescriptorIndex - String Descriptor index. +// +// LanguageID - Language in which the string should be requested. +// +//***************************************************************************** + +PSTRING_DESCRIPTOR_NODE +GetStringDescriptor ( + HANDLE hHubDevice, + ULONG ConnectionIndex, + UCHAR DescriptorIndex, + USHORT LanguageID +) +{ + BOOL success = 0; + ULONG nBytes = 0; + ULONG nBytesReturned = 0; + + UCHAR stringDescReqBuf[sizeof(USB_DESCRIPTOR_REQUEST) + + MAXIMUM_USB_STRING_LENGTH]; + + PUSB_DESCRIPTOR_REQUEST stringDescReq = NULL; + PUSB_STRING_DESCRIPTOR stringDesc = NULL; + PSTRING_DESCRIPTOR_NODE stringDescNode = NULL; + + nBytes = sizeof(stringDescReqBuf); + + stringDescReq = (PUSB_DESCRIPTOR_REQUEST)stringDescReqBuf; + stringDesc = (PUSB_STRING_DESCRIPTOR)(stringDescReq+1); + + // Zero fill the entire request structure + // + memset(stringDescReq, 0, nBytes); + + // Indicate the port from which the descriptor will be requested + // + stringDescReq->ConnectionIndex = ConnectionIndex; + + // + // USBHUB uses URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE to process this + // IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION request. + // + // USBD will automatically initialize these fields: + // bmRequest = 0x80 + // bRequest = 0x06 + // + // We must inititialize these fields: + // wValue = Descriptor Type (high) and Descriptor Index (low byte) + // wIndex = Zero (or Language ID for String Descriptors) + // wLength = Length of descriptor buffer + // + stringDescReq->SetupPacket.wValue = (USB_STRING_DESCRIPTOR_TYPE << 8) + | DescriptorIndex; + + stringDescReq->SetupPacket.wIndex = LanguageID; + + stringDescReq->SetupPacket.wLength = (USHORT)(nBytes - sizeof(USB_DESCRIPTOR_REQUEST)); + + // Now issue the get descriptor request. + // + success = DeviceIoControl(hHubDevice, + IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, + stringDescReq, + nBytes, + stringDescReq, + nBytes, + &nBytesReturned, + NULL); + + // + // Do some sanity checks on the return from the get descriptor request. + // + + if (!success) + { + OOPS(); + return NULL; + } + + if (nBytesReturned < 2) + { + OOPS(); + return NULL; + } + + if (stringDesc->bDescriptorType != USB_STRING_DESCRIPTOR_TYPE) + { + OOPS(); + return NULL; + } + + if (stringDesc->bLength != nBytesReturned - sizeof(USB_DESCRIPTOR_REQUEST)) + { + OOPS(); + return NULL; + } + + if (stringDesc->bLength % 2 != 0) + { + OOPS(); + return NULL; + } + + // + // Looks good, allocate some (zero filled) space for the string descriptor + // node and copy the string descriptor to it. + // + + stringDescNode = (PSTRING_DESCRIPTOR_NODE)ALLOC(sizeof(STRING_DESCRIPTOR_NODE) + + stringDesc->bLength); + + if (stringDescNode == NULL) + { + OOPS(); + return NULL; + } + + stringDescNode->DescriptorIndex = DescriptorIndex; + stringDescNode->LanguageID = LanguageID; + + memcpy(stringDescNode->StringDescriptor, + stringDesc, + stringDesc->bLength); + + return stringDescNode; +} + + +//***************************************************************************** +// +// GetStringDescriptors() +// +// hHubDevice - Handle of the hub device containing the port from which the +// String Descriptor will be requested. +// +// ConnectionIndex - Identifies the port on the hub to which a device is +// attached from which the String Descriptor will be requested. +// +// DescriptorIndex - String Descriptor index. +// +// NumLanguageIDs - Number of languages in which the string should be +// requested. +// +// LanguageIDs - Languages in which the string should be requested. +// +// StringDescNodeHead - First node in linked list of device's string descriptors +// +// Return Value: HRESULT indicating whether the string is on the list +// +//***************************************************************************** + +HRESULT +GetStringDescriptors ( + _In_ HANDLE hHubDevice, + _In_ ULONG ConnectionIndex, + _In_ UCHAR DescriptorIndex, + _In_ ULONG NumLanguageIDs, + _In_reads_(NumLanguageIDs) USHORT *LanguageIDs, + _In_ PSTRING_DESCRIPTOR_NODE StringDescNodeHead +) +{ + PSTRING_DESCRIPTOR_NODE tail = NULL; + PSTRING_DESCRIPTOR_NODE trailing = NULL; + ULONG i = 0; + + // + // Go to the end of the linked list, searching for the requested index to + // see if we've already retrieved it + // + for (tail = StringDescNodeHead; tail != NULL; tail = tail->Next) + { + if (tail->DescriptorIndex == DescriptorIndex) + { + return S_OK; + } + + trailing = tail; + } + + tail = trailing; + + // + // Get the next String Descriptor. If this is NULL, then we're done (return) + // Otherwise, loop through all Language IDs + // + for (i = 0; (tail != NULL) && (i < NumLanguageIDs); i++) + { + tail->Next = GetStringDescriptor(hHubDevice, + ConnectionIndex, + DescriptorIndex, + LanguageIDs[i]); + + tail = tail->Next; + } + + if (tail == NULL) + { + return E_FAIL; + } else { + return S_OK; + } +} + + +//***************************************************************************** +// +// CleanupItem() +// +//***************************************************************************** + +VOID +CleanupItem ( + HWND hTreeWnd, + HTREEITEM hTreeItem, + PVOID pContext +) +{ + TV_ITEM tvi; + PVOID info = NULL; + + UNREFERENCED_PARAMETER(pContext); + + tvi.mask = TVIF_HANDLE | TVIF_PARAM; + tvi.hItem = hTreeItem; + + TreeView_GetItem(hTreeWnd, + &tvi); + + info = (PVOID)tvi.lParam; + + if (info) + { + PCHAR DriverKey = NULL; + PUSB_NODE_INFORMATION HubInfo = NULL; + PCHAR HubName = NULL; + PUSB_NODE_CONNECTION_INFORMATION_EX ConnectionInfoEx = NULL; + PUSB_DESCRIPTOR_REQUEST ConfigDesc = NULL; + PUSB_DESCRIPTOR_REQUEST BosDesc = NULL; + PSTRING_DESCRIPTOR_NODE StringDescs = NULL; + PUSB_HUB_INFORMATION_EX HubInfoEx = NULL; + PUSB_PORT_CONNECTOR_PROPERTIES PortConnectorProps = NULL; + PUSB_NODE_CONNECTION_INFORMATION_EX_V2 ConnectionInfoV2 = NULL; + PUSB_HUB_CAPABILITIES_EX HubCapabilityEx = NULL; + PUSB_DEVICE_PNP_STRINGS UsbDeviceProperties = NULL; + PUSB_CONTROLLER_INFO_0 ControllerInfo = NULL; + + // + // All structures except DEVICE_INFO_NODE are free'd up here. DEVICE_INFO_NODE structures are free'd while + // destroying device info lists (ClearDeviceList()) + // + switch (*(PUSBDEVICEINFOTYPE)info) + { + case HostControllerInfo: + // + // Remove this host controller from the list of enumerated + // host controllers. + // + RemoveEntryList(&((PUSBHOSTCONTROLLERINFO)info)->ListEntry); + DriverKey = ((PUSBHOSTCONTROLLERINFO)info)->DriverKey; + ControllerInfo = ((PUSBHOSTCONTROLLERINFO)info)->ControllerInfo; + UsbDeviceProperties = ((PUSBHOSTCONTROLLERINFO)info)->UsbDeviceProperties; + break; + + case RootHubInfo: + HubInfo = ((PUSBROOTHUBINFO)info)->HubInfo; + HubInfoEx = ((PUSBROOTHUBINFO)info)->HubInfoEx; + HubName = ((PUSBROOTHUBINFO)info)->HubName; + PortConnectorProps = ((PUSBROOTHUBINFO)info)->PortConnectorProps; + UsbDeviceProperties = ((PUSBROOTHUBINFO)info)->UsbDeviceProperties; + HubCapabilityEx = ((PUSBROOTHUBINFO)info)->HubCapabilityEx; + break; + + case ExternalHubInfo: + HubInfo = ((PUSBEXTERNALHUBINFO)info)->HubInfo; + HubInfoEx = ((PUSBEXTERNALHUBINFO)info)->HubInfoEx; + HubName = ((PUSBEXTERNALHUBINFO)info)->HubName; + ConnectionInfoEx = ((PUSBEXTERNALHUBINFO)info)->ConnectionInfo; + PortConnectorProps = ((PUSBEXTERNALHUBINFO)info)->PortConnectorProps; + ConfigDesc = ((PUSBEXTERNALHUBINFO)info)->ConfigDesc; + BosDesc = ((PUSBEXTERNALHUBINFO)info)->BosDesc; + StringDescs = ((PUSBEXTERNALHUBINFO)info)->StringDescs; + ConnectionInfoV2 = ((PUSBEXTERNALHUBINFO)info)->ConnectionInfoV2; + UsbDeviceProperties = ((PUSBEXTERNALHUBINFO)info)->UsbDeviceProperties; + HubCapabilityEx = ((PUSBEXTERNALHUBINFO)info)->HubCapabilityEx; + break; + + case DeviceInfo: + ConnectionInfoEx = ((PUSBDEVICEINFO)info)->ConnectionInfo; + PortConnectorProps = ((PUSBDEVICEINFO)info)->PortConnectorProps; + ConfigDesc = ((PUSBDEVICEINFO)info)->ConfigDesc; + BosDesc = ((PUSBDEVICEINFO)info)->BosDesc; + StringDescs = ((PUSBDEVICEINFO)info)->StringDescs; + ConnectionInfoV2 = ((PUSBDEVICEINFO)info)->ConnectionInfoV2; + UsbDeviceProperties = ((PUSBDEVICEINFO)info)->UsbDeviceProperties; + break; + } + + if(UsbDeviceProperties) + { + FreeDeviceProperties(&UsbDeviceProperties); + } + + if(ControllerInfo) + { + FREE(ControllerInfo); + } + + if(HubCapabilityEx) + { + FREE(HubCapabilityEx); + } + + if (DriverKey) + { + FREE(DriverKey); + } + + if (HubInfo) + { + FREE(HubInfo); + } + + if (HubName) + { + FREE(HubName); + } + + if (ConfigDesc) + { + FREE(ConfigDesc); + } + + if (BosDesc) + { + FREE(BosDesc); + } + + if (StringDescs) + { + PSTRING_DESCRIPTOR_NODE Next; + + do { + + Next = StringDescs->Next; + FREE(StringDescs); + StringDescs = Next; + + } while (StringDescs); + } + + if (ConnectionInfoEx) + { + FREE(ConnectionInfoEx); + } + + if (HubInfoEx) + { + FREE(HubInfoEx); + } + + if (PortConnectorProps) + { + FREE(PortConnectorProps); + } + + if (ConnectionInfoV2) + { + FREE(ConnectionInfoV2); + } + + FREE(info); + } +} + +//***************************************************************************** +// +// GetHostControllerPowerMap() +// +// HANDLE hHCDev +// - handle to USB Host Controller +// +// PUSBHOSTCONTROLLERINFO hcInfo +// - data structure to receive the Power Map Info +// +// return DWORD dwError +// - return ERROR_SUCCESS or last error +// +//***************************************************************************** + +DWORD +GetHostControllerPowerMap( + HANDLE hHCDev, + PUSBHOSTCONTROLLERINFO hcInfo) +{ + USBUSER_POWER_INFO_REQUEST UsbPowerInfoRequest; + PUSB_POWER_INFO pUPI = &UsbPowerInfoRequest.PowerInformation ; + DWORD dwError = 0; + DWORD dwBytes = 0; + BOOL bSuccess = FALSE; + int nIndex = 0; + int nPowerState = WdmUsbPowerSystemWorking; + + for ( ; nPowerState <= WdmUsbPowerSystemShutdown; nIndex++, nPowerState++) + { + // zero initialize our request + memset(&UsbPowerInfoRequest, 0, sizeof(UsbPowerInfoRequest)); + + // set the header and request sizes + UsbPowerInfoRequest.Header.UsbUserRequest = USBUSER_GET_POWER_STATE_MAP; + UsbPowerInfoRequest.Header.RequestBufferLength = sizeof(UsbPowerInfoRequest); + UsbPowerInfoRequest.PowerInformation.SystemState = nPowerState; + + // + // Now query USBHUB for the USB_POWER_INFO structure for this hub. + // For Selective Suspend support + // + bSuccess = DeviceIoControl(hHCDev, + IOCTL_USB_USER_REQUEST, + &UsbPowerInfoRequest, + sizeof(UsbPowerInfoRequest), + &UsbPowerInfoRequest, + sizeof(UsbPowerInfoRequest), + &dwBytes, + NULL); + + if (!bSuccess) + { + dwError = GetLastError(); + OOPS(); + } + else + { + // copy the data into our USB Host Controller's info structure + memcpy( &(hcInfo->USBPowerInfo[nIndex]), pUPI, sizeof(USB_POWER_INFO)); + } + } + + return dwError; +} + +void +EnumerateAllDevices() +{ + EnumerateAllDevicesWithGuid(&gDeviceList, + (LPGUID)&GUID_DEVINTERFACE_USB_DEVICE); + + EnumerateAllDevicesWithGuid(&gHubList, + (LPGUID)&GUID_DEVINTERFACE_USB_HUB); +} + + +//***************************************************************************** +// +// GetHostControllerInfo() +// +// HANDLE hHCDev +// - handle to USB Host Controller +// +// PUSBHOSTCONTROLLERINFO hcInfo +// - data structure to receive the Power Map Info +// +// return DWORD dwError +// - return ERROR_SUCCESS or last error +// +//***************************************************************************** + +DWORD +GetHostControllerInfo( + HANDLE hHCDev, + PUSBHOSTCONTROLLERINFO hcInfo) +{ + USBUSER_CONTROLLER_INFO_0 UsbControllerInfo; + DWORD dwError = 0; + DWORD dwBytes = 0; + BOOL bSuccess = FALSE; + + memset(&UsbControllerInfo, 0, sizeof(UsbControllerInfo)); + + // set the header and request sizes + UsbControllerInfo.Header.UsbUserRequest = USBUSER_GET_CONTROLLER_INFO_0; + UsbControllerInfo.Header.RequestBufferLength = sizeof(UsbControllerInfo); + + // + // Query for the USB_CONTROLLER_INFO_0 structure + // + bSuccess = DeviceIoControl(hHCDev, + IOCTL_USB_USER_REQUEST, + &UsbControllerInfo, + sizeof(UsbControllerInfo), + &UsbControllerInfo, + sizeof(UsbControllerInfo), + &dwBytes, + NULL); + + if (!bSuccess) + { + dwError = GetLastError(); + OOPS(); + } + else + { + hcInfo->ControllerInfo = (PUSB_CONTROLLER_INFO_0) ALLOC(sizeof(USB_CONTROLLER_INFO_0)); + if(NULL == hcInfo->ControllerInfo) + { + dwError = GetLastError(); + OOPS(); + } + else + { + // copy the data into our USB Host Controller's info structure + memcpy(hcInfo->ControllerInfo, &UsbControllerInfo.Info0, sizeof(USB_CONTROLLER_INFO_0)); + } + } + return dwError; +} + +_Success_(return == TRUE) +BOOL +GetDeviceProperty( + _In_ HDEVINFO DeviceInfoSet, + _In_ PSP_DEVINFO_DATA DeviceInfoData, + _In_ DWORD Property, + _Outptr_ LPTSTR *ppBuffer + ) +{ + BOOL bResult; + DWORD requiredLength = 0; + DWORD lastError; + + if (ppBuffer == NULL) + { + return FALSE; + } + + *ppBuffer = NULL; + + bResult = SetupDiGetDeviceRegistryPropertyA(DeviceInfoSet, + DeviceInfoData, + Property , + NULL, + NULL, + 0, + &requiredLength); + lastError = GetLastError(); + + if ((requiredLength == 0) || (bResult != FALSE && lastError != ERROR_INSUFFICIENT_BUFFER)) + { + return FALSE; + } + + requiredLength *= 4; + *ppBuffer = ALLOC(requiredLength); + + if (*ppBuffer == NULL) + { + return FALSE; + } + + bResult = SetupDiGetDeviceRegistryPropertyA(DeviceInfoSet, + DeviceInfoData, + Property , + NULL, + (PBYTE) *ppBuffer, + requiredLength, + &requiredLength); + if(bResult == FALSE) + { + FREE(*ppBuffer); + *ppBuffer = NULL; + return FALSE; + } + + return TRUE; +} + + +void +EnumerateAllDevicesWithGuid( + PDEVICE_GUID_LIST DeviceList, + LPGUID Guid + ) +{ + if (DeviceList->DeviceInfo != INVALID_HANDLE_VALUE) + { + ClearDeviceList(DeviceList); + } + + DeviceList->DeviceInfo = SetupDiGetClassDevs(Guid, + NULL, + NULL, + (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE)); + + if (DeviceList->DeviceInfo != INVALID_HANDLE_VALUE) + { + ULONG index; + DWORD error; + + error = 0; + index = 0; + + while (error != ERROR_NO_MORE_ITEMS) + { + BOOL success; + PDEVICE_INFO_NODE pNode; + + pNode = ALLOC(sizeof(DEVICE_INFO_NODE)); + if (pNode == NULL) + { + OOPS(); + break; + } + pNode->DeviceInfo = DeviceList->DeviceInfo; + pNode->DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + pNode->DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA); + + success = SetupDiEnumDeviceInfo(DeviceList->DeviceInfo, + index, + &pNode->DeviceInfoData); + + index++; + + if (success == FALSE) + { + error = GetLastError(); + + if (error != ERROR_NO_MORE_ITEMS) + { + OOPS(); + } + + FreeDeviceInfoNode(&pNode); + } + else + { + BOOL bResult; + ULONG requiredLength; + + bResult = GetDeviceProperty(DeviceList->DeviceInfo, + &pNode->DeviceInfoData, + SPDRP_DEVICEDESC, + &pNode->DeviceDescName); + if (bResult == FALSE) + { + FreeDeviceInfoNode(&pNode); + OOPS(); + break; + } + + bResult = GetDeviceProperty(DeviceList->DeviceInfo, + &pNode->DeviceInfoData, + SPDRP_DRIVER, + &pNode->DeviceDriverName); + if (bResult == FALSE) + { + FreeDeviceInfoNode(&pNode); + OOPS(); + break; + } + + pNode->DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + + success = SetupDiEnumDeviceInterfaces(DeviceList->DeviceInfo, + 0, + Guid, + index-1, + &pNode->DeviceInterfaceData); + if (!success) + { + FreeDeviceInfoNode(&pNode); + OOPS(); + break; + } + + success = SetupDiGetDeviceInterfaceDetail(DeviceList->DeviceInfo, + &pNode->DeviceInterfaceData, + NULL, + 0, + &requiredLength, + NULL); + + error = GetLastError(); + + if (!success && error != ERROR_INSUFFICIENT_BUFFER) + { + FreeDeviceInfoNode(&pNode); + OOPS(); + break; + } + + pNode->DeviceDetailData = ALLOC(requiredLength); + + if (pNode->DeviceDetailData == NULL) + { + FreeDeviceInfoNode(&pNode); + OOPS(); + break; + } + + pNode->DeviceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); + + success = SetupDiGetDeviceInterfaceDetail(DeviceList->DeviceInfo, + &pNode->DeviceInterfaceData, + pNode->DeviceDetailData, + requiredLength, + &requiredLength, + NULL); + if (!success) + { + FreeDeviceInfoNode(&pNode); + OOPS(); + break; + } + + InsertTailList(&DeviceList->ListHead, &pNode->ListEntry); + } + } + } +} + +DEVICE_POWER_STATE +AcquireDevicePowerState( + _Inout_ PDEVICE_INFO_NODE pNode + ) +{ + CM_POWER_DATA cmPowerData = {0}; + BOOL bResult; + + bResult = SetupDiGetDeviceRegistryProperty(pNode->DeviceInfo, + &pNode->DeviceInfoData, + SPDRP_DEVICE_POWER_DATA, + NULL, + (PBYTE)&cmPowerData, + sizeof(cmPowerData), + NULL); + + pNode->LatestDevicePowerState = bResult ? cmPowerData.PD_MostRecentPowerState : PowerDeviceUnspecified; + + return pNode->LatestDevicePowerState; +} + + +void +ClearDeviceList( + PDEVICE_GUID_LIST DeviceList + ) +{ + if (DeviceList->DeviceInfo != INVALID_HANDLE_VALUE) + { + SetupDiDestroyDeviceInfoList(DeviceList->DeviceInfo); + DeviceList->DeviceInfo = INVALID_HANDLE_VALUE; + } + + while (!IsListEmpty(&DeviceList->ListHead)) + { + PDEVICE_INFO_NODE pNode = NULL; + PLIST_ENTRY pEntry; + + pEntry = RemoveHeadList(&DeviceList->ListHead); + + pNode = CONTAINING_RECORD(pEntry, + DEVICE_INFO_NODE, + ListEntry); + + FreeDeviceInfoNode(&pNode); + } +} + +VOID +FreeDeviceInfoNode( + _In_ PDEVICE_INFO_NODE *ppNode + ) +{ + if (ppNode == NULL) + { + return; + } + + if (*ppNode == NULL) + { + return; + } + + if ((*ppNode)->DeviceDetailData != NULL) + { + FREE((*ppNode)->DeviceDetailData); + } + + if ((*ppNode)->DeviceDescName != NULL) + { + FREE((*ppNode)->DeviceDescName); + } + + if ((*ppNode)->DeviceDriverName != NULL) + { + FREE((*ppNode)->DeviceDriverName); + } + + FREE(*ppNode); + *ppNode = NULL; +} + +PDEVICE_INFO_NODE +FindMatchingDeviceNodeForDriverName( + _In_ PSTR DriverKeyName, + _In_ BOOLEAN IsHub + ) +{ + PDEVICE_INFO_NODE pNode = NULL; + PDEVICE_GUID_LIST pList = NULL; + PLIST_ENTRY pEntry = NULL; + + pList = IsHub ? &gHubList : &gDeviceList; + + pEntry = pList->ListHead.Flink; + + while (pEntry && pEntry != &pList->ListHead) + { + pNode = CONTAINING_RECORD(pEntry, + DEVICE_INFO_NODE, + ListEntry); + if (_stricmp(DriverKeyName, pNode->DeviceDriverName) == 0) + { + return pNode; + } + + pEntry = pEntry->Flink; + } + + return NULL; +} + +#ifdef CUSTOM_USBVIEW + +PUSBDEVICEINFO +enumerate_hub_port(HANDLE hHubDevice, ULONG port_index) +{ + ULONG index = port_index; + BOOL success = 0; + HRESULT hr = S_OK; + PCHAR driverKeyName = NULL; + PUSB_DEVICE_PNP_STRINGS DevProps; + DWORD dwSizeOfLeafName = 0; + CHAR leafName[512]; + int icon = 0; + + PUSB_NODE_CONNECTION_INFORMATION_EX connectionInfoEx; + PUSB_PORT_CONNECTOR_PROPERTIES pPortConnectorProps; + USB_PORT_CONNECTOR_PROPERTIES portConnectorProps; + PUSB_DESCRIPTOR_REQUEST configDesc; + PUSB_DESCRIPTOR_REQUEST bosDesc; + PSTRING_DESCRIPTOR_NODE stringDescs; + PUSBDEVICEINFO info; + PUSB_NODE_CONNECTION_INFORMATION_EX_V2 connectionInfoExV2; + PDEVICE_INFO_NODE pNode; + + // Loop over all ports of the hub. + // + // Port indices are 1 based, not 0 based. + // + //for (index = 1; index <= NumPorts; index++) + { + ULONG nBytesEx; + ULONG nBytes = 0; + + connectionInfoEx = NULL; + pPortConnectorProps = NULL; + ZeroMemory(&portConnectorProps, sizeof(portConnectorProps)); + configDesc = NULL; + bosDesc = NULL; + stringDescs = NULL; + info = NULL; + connectionInfoExV2 = NULL; + pNode = NULL; + DevProps = NULL; + ZeroMemory(leafName, sizeof(leafName)); + + // + // Allocate space to hold the connection info for this port. + // For now, allocate it big enough to hold info for 30 pipes. + // + // Endpoint numbers are 0-15. Endpoint number 0 is the standard + // control endpoint which is not explicitly listed in the Configuration + // Descriptor. There can be an IN endpoint and an OUT endpoint at + // endpoint numbers 1-15 so there can be a maximum of 30 endpoints + // per device configuration. + // + // Should probably size this dynamically at some point. + // + + nBytesEx = sizeof(USB_NODE_CONNECTION_INFORMATION_EX) + + (sizeof(USB_PIPE_INFO) * 30); + + connectionInfoEx = (PUSB_NODE_CONNECTION_INFORMATION_EX)ALLOC(nBytesEx); + + if (connectionInfoEx == NULL) + { + OOPS(); + + return NULL; + } + + connectionInfoExV2 = (PUSB_NODE_CONNECTION_INFORMATION_EX_V2) + ALLOC(sizeof(USB_NODE_CONNECTION_INFORMATION_EX_V2)); + + if (connectionInfoExV2 == NULL) + { + OOPS(); + FREE(connectionInfoEx); + return NULL; + } + + // + // Now query USBHUB for the structures + // for this port. This will tell us if a device is attached to this + // port, among other things. + // The fault tolerate code is executed first. + // + + portConnectorProps.ConnectionIndex = index; + + success = DeviceIoControl(hHubDevice, + IOCTL_USB_GET_PORT_CONNECTOR_PROPERTIES, + &portConnectorProps, + sizeof(USB_PORT_CONNECTOR_PROPERTIES), + &portConnectorProps, + sizeof(USB_PORT_CONNECTOR_PROPERTIES), + &nBytes, + NULL); + + if (success && nBytes == sizeof(USB_PORT_CONNECTOR_PROPERTIES)) + { + pPortConnectorProps = (PUSB_PORT_CONNECTOR_PROPERTIES) + ALLOC(portConnectorProps.ActualLength); + + if (pPortConnectorProps != NULL) + { + pPortConnectorProps->ConnectionIndex = index; + + success = DeviceIoControl(hHubDevice, + IOCTL_USB_GET_PORT_CONNECTOR_PROPERTIES, + pPortConnectorProps, + portConnectorProps.ActualLength, + pPortConnectorProps, + portConnectorProps.ActualLength, + &nBytes, + NULL); + + if (!success || nBytes < portConnectorProps.ActualLength) + { + FREE(pPortConnectorProps); + pPortConnectorProps = NULL; + } + } + } + + connectionInfoExV2->ConnectionIndex = index; + connectionInfoExV2->Length = sizeof(USB_NODE_CONNECTION_INFORMATION_EX_V2); + connectionInfoExV2->SupportedUsbProtocols.Usb300 = 1; + + success = DeviceIoControl(hHubDevice, + IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX_V2, + connectionInfoExV2, + sizeof(USB_NODE_CONNECTION_INFORMATION_EX_V2), + connectionInfoExV2, + sizeof(USB_NODE_CONNECTION_INFORMATION_EX_V2), + &nBytes, + NULL); + + if (!success || nBytes < sizeof(USB_NODE_CONNECTION_INFORMATION_EX_V2)) + { + FREE(connectionInfoExV2); + connectionInfoExV2 = NULL; + } + + connectionInfoEx->ConnectionIndex = index; + + success = DeviceIoControl(hHubDevice, + IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, + connectionInfoEx, + nBytesEx, + connectionInfoEx, + nBytesEx, + &nBytesEx, + NULL); + + if (success) + { + // + // Since the USB_NODE_CONNECTION_INFORMATION_EX is used to display + // the device speed, but the hub driver doesn't support indication + // of superspeed, we overwrite the value if the super speed + // data structures are available and indicate the device is operating + // at SuperSpeed. + // + + if (connectionInfoEx->Speed == UsbHighSpeed + && connectionInfoExV2 != NULL + && (connectionInfoExV2->Flags.DeviceIsOperatingAtSuperSpeedOrHigher || + connectionInfoExV2->Flags.DeviceIsOperatingAtSuperSpeedPlusOrHigher)) + { + connectionInfoEx->Speed = UsbSuperSpeed; + } + } + else + { + PUSB_NODE_CONNECTION_INFORMATION connectionInfo = NULL; + + // Try using IOCTL_USB_GET_NODE_CONNECTION_INFORMATION + // instead of IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX + // + + nBytes = sizeof(USB_NODE_CONNECTION_INFORMATION) + + sizeof(USB_PIPE_INFO) * 30; + + connectionInfo = (PUSB_NODE_CONNECTION_INFORMATION)ALLOC(nBytes); + + if (connectionInfo == NULL) + { + OOPS(); + + FREE(connectionInfoEx); + if (pPortConnectorProps != NULL) + { + FREE(pPortConnectorProps); + } + if (connectionInfoExV2 != NULL) + { + FREE(connectionInfoExV2); + } + + return NULL; + } + + connectionInfo->ConnectionIndex = index; + + success = DeviceIoControl(hHubDevice, + IOCTL_USB_GET_NODE_CONNECTION_INFORMATION, + connectionInfo, + nBytes, + connectionInfo, + nBytes, + &nBytes, + NULL); + + if (!success) + { + OOPS(); + + FREE(connectionInfo); + FREE(connectionInfoEx); + if (pPortConnectorProps != NULL) + { + FREE(pPortConnectorProps); + } + if (connectionInfoExV2 != NULL) + { + FREE(connectionInfoExV2); + } + + return NULL; + } + + // Copy IOCTL_USB_GET_NODE_CONNECTION_INFORMATION into + // IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX structure. + // + connectionInfoEx->ConnectionIndex = connectionInfo->ConnectionIndex; + connectionInfoEx->DeviceDescriptor = connectionInfo->DeviceDescriptor; + connectionInfoEx->CurrentConfigurationValue = connectionInfo->CurrentConfigurationValue; + connectionInfoEx->Speed = connectionInfo->LowSpeed ? UsbLowSpeed : UsbFullSpeed; + connectionInfoEx->DeviceIsHub = connectionInfo->DeviceIsHub; + connectionInfoEx->DeviceAddress = connectionInfo->DeviceAddress; + connectionInfoEx->NumberOfOpenPipes = connectionInfo->NumberOfOpenPipes; + connectionInfoEx->ConnectionStatus = connectionInfo->ConnectionStatus; + + memcpy(&connectionInfoEx->PipeList[0], + &connectionInfo->PipeList[0], + sizeof(USB_PIPE_INFO) * 30); + + FREE(connectionInfo); + } + + // If there is a device connected, get the Device Description + // + if (connectionInfoEx->ConnectionStatus != NoDeviceConnected) + { + driverKeyName = GetDriverKeyName(hHubDevice, index); + + if (driverKeyName) + { + size_t cbDriverName = 0; + + hr = StringCbLength(driverKeyName, MAX_DRIVER_KEY_NAME, &cbDriverName); + if (SUCCEEDED(hr)) + { + DevProps = DriverNameToDeviceProperties(driverKeyName, cbDriverName); + pNode = FindMatchingDeviceNodeForDriverName(driverKeyName, connectionInfoEx->DeviceIsHub); + } + FREE(driverKeyName); + } + + } + + // If there is a device connected to the port, try to retrieve the + // Configuration Descriptor from the device. + // + if (/*gDoConfigDesc &&*/ + connectionInfoEx->ConnectionStatus == DeviceConnected) + { + configDesc = GetConfigDescriptor(hHubDevice, + index, + 0); + } + else + { + configDesc = NULL; + } + + if (configDesc != NULL && + connectionInfoEx->DeviceDescriptor.bcdUSB > 0x0200) + { + bosDesc = GetBOSDescriptor(hHubDevice, + index); + } + else + { + bosDesc = NULL; + } + + if (configDesc != NULL && + AreThereStringDescriptors(&connectionInfoEx->DeviceDescriptor, + (PUSB_CONFIGURATION_DESCRIPTOR)(configDesc + 1))) + { + stringDescs = GetAllStringDescriptors( + hHubDevice, + index, + &connectionInfoEx->DeviceDescriptor, + (PUSB_CONFIGURATION_DESCRIPTOR)(configDesc + 1)); + } + else + { + stringDescs = NULL; + } + + // If the device connected to the port is an external hub, get the + // name of the external hub and recursively enumerate it. + // + if (connectionInfoEx->DeviceIsHub) + { + OOPS(); + if (configDesc != NULL) + { + FREE(configDesc); + } + if (bosDesc != NULL) + { + FREE(bosDesc); + } + FREE(connectionInfoEx); + + if (pPortConnectorProps != NULL) + { + FREE(pPortConnectorProps); + } + if (connectionInfoExV2 != NULL) + { + FREE(connectionInfoExV2); + } + + return NULL; + } + else + { + // Allocate some space for a USBDEVICEINFO structure to hold the + // hub info, hub name, and connection info pointers. GPTR zero + // initializes the structure for us. + // + info = (PUSBDEVICEINFO)ALLOC(sizeof(USBDEVICEINFO)); + + if (info == NULL) + { + OOPS(); + if (configDesc != NULL) + { + FREE(configDesc); + } + if (bosDesc != NULL) + { + FREE(bosDesc); + } + FREE(connectionInfoEx); + + if (pPortConnectorProps != NULL) + { + FREE(pPortConnectorProps); + } + if (connectionInfoExV2 != NULL) + { + FREE(connectionInfoExV2); + } + + return NULL; + } + + info->DeviceInfoType = DeviceInfo; + info->ConnectionInfo = connectionInfoEx; + info->PortConnectorProps = pPortConnectorProps; + info->ConfigDesc = configDesc; + info->StringDescs = stringDescs; + info->BosDesc = bosDesc; + info->ConnectionInfoV2 = connectionInfoExV2; + info->UsbDeviceProperties = DevProps; + info->DeviceInfoNode = pNode; + + StringCchPrintf(leafName, sizeof(leafName), "[Port%d] ", index); + + // Add error description if ConnectionStatus is other than NoDeviceConnected / DeviceConnected + StringCchCat(leafName, + sizeof(leafName), + ConnectionStatuses[connectionInfoEx->ConnectionStatus]); + + if (DevProps) + { + size_t cchDeviceDesc = 0; + + hr = StringCbLength(DevProps->DeviceDesc, MAX_DEVICE_PROP, &cchDeviceDesc); + if (FAILED(hr)) + { + OOPS(); + } + dwSizeOfLeafName = sizeof(leafName); + StringCchCatN(leafName, + dwSizeOfLeafName - 1, + " : ", + sizeof(" : ")); + StringCchCatN(leafName, + dwSizeOfLeafName - 1, + DevProps->DeviceDesc, + cchDeviceDesc); + } + + if (connectionInfoEx->ConnectionStatus == NoDeviceConnected) + { + if (connectionInfoExV2 != NULL && + connectionInfoExV2->SupportedUsbProtocols.Usb300 == 1) + { + icon = NoSsDeviceIcon; + } + else + { + icon = NoDeviceIcon; + } + } + else if (connectionInfoEx->CurrentConfigurationValue) + { + if (connectionInfoEx->Speed == UsbSuperSpeed) + { + icon = GoodSsDeviceIcon; + } + else + { + icon = GoodDeviceIcon; + } + } + else + { + icon = BadDeviceIcon; + } + } + } // for + + return info; +} +PUSBDEVICEINFO get_usb_device_info(const char* device_name) +{ + PUSBDEVICEINFO info = NULL; + HANDLE hub = NULL; + ULONG port = -1; + DWORD bytes = 0; + BOOL ret = FALSE; + HDEVINFO dev = SetupDiGetClassDevsW(&GUID_DEVINTERFACE_USB_HUB, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); + + if (dev) + { + SetupDiDestroyDeviceInfoList(dev); + } + + if (hub) + { + info = enumerate_hub_port(hub, port); + CloseHandle(hub); + } + + return info; +} +void free_usb_device_info(PUSBDEVICEINFO pudi) +{ + if (pudi) + { + if (pudi->ConnectionInfo) + FREE(pudi->ConnectionInfo); + if (pudi->PortConnectorProps) + FREE(pudi->PortConnectorProps); + if (pudi->ConfigDesc) + FREE(pudi->ConfigDesc); + if (pudi->StringDescs) + FREE(pudi->StringDescs); + if (pudi->BosDesc) + FREE(pudi->BosDesc); + if (pudi->ConnectionInfoV2) + FREE(pudi->ConnectionInfoV2); + if (pudi->UsbDeviceProperties) + FREE(pudi->UsbDeviceProperties); + if (pudi->DeviceInfoNode) + FREE(pudi->DeviceInfoNode); + + FREE(pudi); + } +} + + +#endif diff --git a/device/win_usb/usbview/enum.h b/device/win_usb/usbview/enum.h new file mode 100644 index 0000000..3b37763 --- /dev/null +++ b/device/win_usb/usbview/enum.h @@ -0,0 +1,682 @@ +/*++ + +Copyright (c) 1997-2008 Microsoft Corporation + +Module Name: + + UVCVIEW.H + +Abstract: + + This is the header file for UVCVIEW + +Environment: + + user mode + +Revision History: + + 04-25-97 : created + 04/13/2005 : major bug fixing + +--*/ + +/***************************************************************************** + I N C L U D E S +*****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// This is mostly a private USB Audio descriptor header +#include "usbdesc.h" + +// This is the inbox USBVideo driver descriptor header (copied locally) +#include "uvcdesc.h" + +/***************************************************************************** + P R A G M A S +*****************************************************************************/ + +#pragma once + +/***************************************************************************** + D E F I N E S +*****************************************************************************/ + +// define H264_SUPPORT to add H.264 support to uvcview.exe +#define H264_SUPPORT + +#define TEXT_ITEM_LENGTH 64 + +#ifdef DEBUG +#undef DBG +#define DBG 1 +#endif + +#if DBG +#define OOPS() Oops(__FILE__, __LINE__) +#else +#define OOPS() +#endif + +#if DBG + +#define ALLOC(dwBytes) MyAlloc(__FILE__, __LINE__, (dwBytes)) + +#define REALLOC(hMem, dwBytes) MyReAlloc((hMem), (dwBytes)) + +#define FREE(hMem) MyFree((hMem)) + +#define CHECKFORLEAKS() MyCheckForLeaks() + +#else + +#define ALLOC(dwBytes) GlobalAlloc(GPTR,(dwBytes)) + +#define REALLOC(hMem, dwBytes) GlobalReAlloc((hMem), (dwBytes), (GMEM_MOVEABLE|GMEM_ZEROINIT)) + +#define FREE(hMem) GlobalFree((hMem)) + +#define CHECKFORLEAKS() + +#endif + +#define DEVICE_CONFIGURATION_TEXT_LENGTH 10240 + +#define STR_INVALID_POWER_STATE "(invalid state) " +#define STR_UNKNOWN_CONTROLLER_FLAVOR "Unknown" + +FORCEINLINE +VOID +InitializeListHead( + _Out_ PLIST_ENTRY ListHead + ) +{ + ListHead->Flink = ListHead->Blink = ListHead; +} + +// +// BOOLEAN +// IsListEmpty( +// PLIST_ENTRY ListHead +// ); +// + +#define IsListEmpty(ListHead) \ + ((ListHead)->Flink == (ListHead)) + +// +// PLIST_ENTRY +// RemoveHeadList( +// PLIST_ENTRY ListHead +// ); +// + +#define RemoveHeadList(ListHead) \ + (ListHead)->Flink;\ + {RemoveEntryList((ListHead)->Flink)} + +// +// VOID +// RemoveEntryList( +// PLIST_ENTRY Entry +// ); +// + +#define RemoveEntryList(Entry) {\ + PLIST_ENTRY _EX_Blink;\ + PLIST_ENTRY _EX_Flink;\ + _EX_Flink = (Entry)->Flink;\ + _EX_Blink = (Entry)->Blink;\ + _EX_Blink->Flink = _EX_Flink;\ + _EX_Flink->Blink = _EX_Blink;\ + } + +// +// VOID +// InsertTailList( +// PLIST_ENTRY ListHead, +// PLIST_ENTRY Entry +// ); +// + +#define InsertTailList(ListHead,Entry) {\ + PLIST_ENTRY _EX_Blink;\ + PLIST_ENTRY _EX_ListHead;\ + _EX_ListHead = (ListHead);\ + _EX_Blink = _EX_ListHead->Blink;\ + (Entry)->Flink = _EX_ListHead;\ + (Entry)->Blink = _EX_Blink;\ + _EX_Blink->Flink = (Entry);\ + _EX_ListHead->Blink = (Entry);\ + } + +// global version for USB Video Class spec version (pre-release) +#define BCDVDC 0x0083 + +// A.2 Video Interface Subclass Codes +#define SC_VIDEO_INTERFACE_COLLECTION 0x03 + +// A.3 Video Interface Protocol Codes +#define PC_PROTOCOL_UNDEFINED 0x00 + +// USB Video Class spec version +#define NOT_UVC 0x0 +#define UVC10 0x100 +#define UVC11 0x110 + +#ifdef H264_SUPPORT +#define UVC15 0x150 +#endif + +#define OUTPUT_MESSAGE_MAX_LENGTH 1024 +#define MAX_DEVICE_PROP 200 +#define MAX_DRIVER_KEY_NAME 256 + +/***************************************************************************** + T Y P E D E F S +*****************************************************************************/ + +typedef enum _TREEICON +{ + ComputerIcon, + HubIcon, + NoDeviceIcon, + GoodDeviceIcon, + BadDeviceIcon, + GoodSsDeviceIcon, + NoSsDeviceIcon +} TREEICON; + +// Callback function for walking TreeView items +// +typedef VOID +(*LPFNTREECALLBACK)( + HWND hTreeWnd, + HTREEITEM hTreeItem, + PVOID pContext +); + + +// Callback notification function called at end of every tree depth +typedef VOID +(*LPFNTREENOTIFYCALLBACK)(PVOID pContext); + +// +// Structure used to build a linked list of String Descriptors +// retrieved from a device. +// + +typedef struct _STRING_DESCRIPTOR_NODE +{ + struct _STRING_DESCRIPTOR_NODE *Next; + UCHAR DescriptorIndex; + USHORT LanguageID; + USB_STRING_DESCRIPTOR StringDescriptor[1]; +} STRING_DESCRIPTOR_NODE, *PSTRING_DESCRIPTOR_NODE; + +// +// A collection of device properties. The device can be hub, host controller or usb device +// +typedef struct _USB_DEVICE_PNP_STRINGS +{ + PCHAR DeviceId; + PCHAR DeviceDesc; + PCHAR HwId; + PCHAR Service; + PCHAR DeviceClass; + PCHAR PowerState; +} USB_DEVICE_PNP_STRINGS, *PUSB_DEVICE_PNP_STRINGS; + +typedef struct _DEVICE_INFO_NODE { + HDEVINFO DeviceInfo; + LIST_ENTRY ListEntry; + SP_DEVINFO_DATA DeviceInfoData; + SP_DEVICE_INTERFACE_DATA DeviceInterfaceData; + PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceDetailData; + PSTR DeviceDescName; + ULONG DeviceDescNameLength; + PSTR DeviceDriverName; + ULONG DeviceDriverNameLength; + DEVICE_POWER_STATE LatestDevicePowerState; +} DEVICE_INFO_NODE, *PDEVICE_INFO_NODE; + +// +// Structures assocated with TreeView items through the lParam. When an item +// is selected, the lParam is retrieved and the structure it which it points +// is used to display information in the edit control. +// + +typedef enum _USBDEVICEINFOTYPE +{ + HostControllerInfo, + RootHubInfo, + ExternalHubInfo, + DeviceInfo +} USBDEVICEINFOTYPE, *PUSBDEVICEINFOTYPE; + +typedef struct _USBHOSTCONTROLLERINFO +{ + USBDEVICEINFOTYPE DeviceInfoType; + LIST_ENTRY ListEntry; + PCHAR DriverKey; + ULONG VendorID; + ULONG DeviceID; + ULONG SubSysID; + ULONG Revision; + USB_POWER_INFO USBPowerInfo[6]; + BOOL BusDeviceFunctionValid; + ULONG BusNumber; + USHORT BusDevice; + USHORT BusFunction; + PUSB_CONTROLLER_INFO_0 ControllerInfo; + PUSB_DEVICE_PNP_STRINGS UsbDeviceProperties; +} USBHOSTCONTROLLERINFO, *PUSBHOSTCONTROLLERINFO; + +typedef struct _USBROOTHUBINFO +{ + USBDEVICEINFOTYPE DeviceInfoType; + PUSB_NODE_INFORMATION HubInfo; + PUSB_HUB_INFORMATION_EX HubInfoEx; + PCHAR HubName; + PUSB_PORT_CONNECTOR_PROPERTIES PortConnectorProps; + PUSB_DEVICE_PNP_STRINGS UsbDeviceProperties; + PDEVICE_INFO_NODE DeviceInfoNode; + PUSB_HUB_CAPABILITIES_EX HubCapabilityEx; + +} USBROOTHUBINFO, *PUSBROOTHUBINFO; + +typedef struct _USBEXTERNALHUBINFO +{ + USBDEVICEINFOTYPE DeviceInfoType; + PUSB_NODE_INFORMATION HubInfo; + PUSB_HUB_INFORMATION_EX HubInfoEx; + PCHAR HubName; + PUSB_NODE_CONNECTION_INFORMATION_EX ConnectionInfo; + PUSB_PORT_CONNECTOR_PROPERTIES PortConnectorProps; + PUSB_DESCRIPTOR_REQUEST ConfigDesc; + PUSB_DESCRIPTOR_REQUEST BosDesc; + PSTRING_DESCRIPTOR_NODE StringDescs; + PUSB_NODE_CONNECTION_INFORMATION_EX_V2 ConnectionInfoV2; // NULL if root HUB + PUSB_DEVICE_PNP_STRINGS UsbDeviceProperties; + PDEVICE_INFO_NODE DeviceInfoNode; + PUSB_HUB_CAPABILITIES_EX HubCapabilityEx; +} USBEXTERNALHUBINFO, *PUSBEXTERNALHUBINFO; + + +// HubInfo, HubName may be in USBDEVICEINFOTYPE, so they can be removed +typedef struct +{ + USBDEVICEINFOTYPE DeviceInfoType; + PUSB_NODE_INFORMATION HubInfo; // NULL if not a HUB + PUSB_HUB_INFORMATION_EX HubInfoEx; // NULL if not a HUB + PCHAR HubName; // NULL if not a HUB + PUSB_NODE_CONNECTION_INFORMATION_EX ConnectionInfo; // NULL if root HUB + PUSB_PORT_CONNECTOR_PROPERTIES PortConnectorProps; + PUSB_DESCRIPTOR_REQUEST ConfigDesc; // NULL if root HUB + PUSB_DESCRIPTOR_REQUEST BosDesc; // NULL if root HUB + PSTRING_DESCRIPTOR_NODE StringDescs; + PUSB_NODE_CONNECTION_INFORMATION_EX_V2 ConnectionInfoV2; // NULL if root HUB + PUSB_DEVICE_PNP_STRINGS UsbDeviceProperties; + PDEVICE_INFO_NODE DeviceInfoNode; + PUSB_HUB_CAPABILITIES_EX HubCapabilityEx; // NULL if not a HUB +} USBDEVICEINFO, *PUSBDEVICEINFO; + +typedef struct _STRINGLIST +{ +#ifdef H264_SUPPORT + ULONGLONG ulFlag; +#else + ULONG ulFlag; +#endif + PCHAR pszString; + PCHAR pszModifier; + +} STRINGLIST, * PSTRINGLIST; + +typedef struct _DEVICE_GUID_LIST { + HDEVINFO DeviceInfo; + LIST_ENTRY ListHead; +} DEVICE_GUID_LIST, *PDEVICE_GUID_LIST; + + +/***************************************************************************** + G L O B A L S +*****************************************************************************/ + +// +// USBVIEW.C +// + +BOOL gDoConfigDesc; +BOOL gDoAnnotation; +BOOL gLogDebug; +int TotalHubs; + +// +// ENUM.C +// + +PCHAR ConnectionStatuses[]; + +// +// DISPVID.C +// +DEFINE_GUID(YUY2_Format,0x32595559L,0x0000,0x0010,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71); +DEFINE_GUID(NV12_Format,0x3231564EL,0x0000,0x0010,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71); + +#ifdef H264_SUPPORT +DEFINE_GUID(H264_Format,0x34363248, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); +#endif + +// The following flags/variables are all initialized in Display.c InitializePerDeviceSettings() +// +// Save the default frame from the MJPEG, Uncompressed, Vendor and Frame Based Format descriptor +// Check for this when processing the individual Frame descriptors +UCHAR g_chMJPEGFrameDefault; +UCHAR g_chUNCFrameDefault; +UCHAR g_chVendorFrameDefault; +UCHAR g_chFrameBasedFrameDefault; + +// Spec version of UVC device +UINT g_chUVCversion; + +// Base address of the USBDEVICEINFO for device we're parsing +PUSBDEVICEINFO CurrentUSBDeviceInfo; + +// Base address of the Configuration descriptor we're parsing +PUSB_CONFIGURATION_DESCRIPTOR CurrentConfigDesc; + +// Length of the current configuration descriptor +DWORD dwConfigLength; +// Our current position from the beginning of the config descriptor +DWORD dwConfigIndex; + +// +// DISPLAY.C +// +int gDeviceSpeed; + +// Save the current Configuration starting and ending addresses +// Used in ValidateDescAddress() +// +PUSB_CONFIGURATION_DESCRIPTOR g_pConfigDesc; +PSTRING_DESCRIPTOR_NODE g_pStringDescs; +PUCHAR g_descEnd; + +/***************************************************************************** + F U N C T I O N P R O T O T Y P E S +*****************************************************************************/ + +// +// USBVIEW.C +// + +HTREEITEM +AddLeaf ( + HTREEITEM hTreeParent, + LPARAM lParam, + _In_ LPTSTR lpszText, + TREEICON TreeIcon +); + +VOID +Oops +( + _In_ PCHAR File, + ULONG Line +); + +// +// DISPLAY.C +// + +EXTERN_C UINT IsIADDevice (PUSBDEVICEINFO info); +EXTERN_C UINT IsUVCDevice (PUSBDEVICEINFO info); +EXTERN_C PCHAR GetVendorString(USHORT idVendor); +EXTERN_C PCHAR GetLangIDString(USHORT idLang); +EXTERN_C UINT GetConfigurationSize (PUSBDEVICEINFO info); +EXTERN_C PUSB_COMMON_DESCRIPTOR +GetNextDescriptor( + _In_reads_bytes_(TotalLength) + PUSB_COMMON_DESCRIPTOR FirstDescriptor, + _In_ + ULONG TotalLength, + _In_ + PUSB_COMMON_DESCRIPTOR StartDescriptor, + _In_ long + DescriptorType + ); + +HRESULT +UpdateTreeItemDeviceInfo( + HWND hTreeWnd, + HTREEITEM hTreeItem + ); + +PCHAR +GetTextBuffer( +); + +BOOL +ResetTextBuffer( +); + +BOOL +CreateTextBuffer ( +); + +VOID +DestroyTextBuffer ( +); + +UINT +GetTextBufferPos ( +); + +VOID +UpdateEditControl ( + HWND hEditWnd, + HWND hTreeWnd, + HTREEITEM hTreeItem +); + + +VOID __cdecl +AppendBuffer ( + LPCTSTR lpFormat, + ... +); + +VOID __cdecl +AppendTextBuffer ( + LPCTSTR lpFormat, + ... +); + +VOID +DisplayStringDescriptor ( + UCHAR Index, + PSTRING_DESCRIPTOR_NODE StringDescs, + DEVICE_POWER_STATE LatestDevicePowerState +); + +PCHAR +GetStringFromList( + PSTRINGLIST slPowerState, + ULONG ulNumElements, + +#ifdef H264_SUPPORT + ULONGLONG ulFlag, +#else + ULONG ulFlag, +#endif + _In_ PCHAR szDefault + ); + +EXTERN_C PCHAR GetPowerStateString( + WDMUSB_POWER_STATE powerState + ); + +EXTERN_C PCHAR GetControllerFlavorString( + USB_CONTROLLER_FLAVOR flavor + ); + +EXTERN_C ULONG GetEhciDebugPort( + ULONG vendorId, + ULONG deviceId + ); + +VOID +WalkTreeTopDown( + _In_ HTREEITEM hTreeItem, + _In_ LPFNTREECALLBACK lpfnTreeCallback, + _In_opt_ PVOID pContext, + _In_opt_ LPFNTREENOTIFYCALLBACK lpfnTreeNotifyCallback + ); + +VOID RefreshTree (VOID); + +// +// ENUM.C +// + +VOID +EnumerateHostControllers ( + HTREEITEM hTreeParent, + ULONG *DevicesConnected + ); + + +VOID +CleanupItem ( + HWND hTreeWnd, + HTREEITEM hTreeItem, + PVOID pContext + ); + +DEVICE_POWER_STATE +AcquireDevicePowerState( + _Inout_ PDEVICE_INFO_NODE pNode + ); + +_Success_(return == TRUE) +BOOL +GetDeviceProperty( + _In_ HDEVINFO DeviceInfoSet, + _In_ PSP_DEVINFO_DATA DeviceInfoData, + _In_ DWORD Property, + _Outptr_ LPTSTR *ppBuffer + ); + +void +ClearDeviceList( + PDEVICE_GUID_LIST DeviceList + ); + +// +// DEBUG.C +// + +_Success_(return != NULL) +_Post_writable_byte_size_(dwBytes) +HGLOBAL +MyAlloc ( + _In_ PCHAR File, + ULONG Line, + DWORD dwBytes + ); + +_Success_(return != NULL) +_Post_writable_byte_size_(dwBytes) +HGLOBAL +MyReAlloc ( + HGLOBAL hMem, + DWORD dwBytes + ); + +HGLOBAL +MyFree ( + HGLOBAL hMem + ); + +VOID +MyCheckForLeaks ( + VOID + ); + +// +// DEVNODE.C +// + + +PUSB_DEVICE_PNP_STRINGS +DriverNameToDeviceProperties( + _In_reads_bytes_(cbDriverName) PCHAR DriverName, + _In_ size_t cbDriverName + ); + +VOID FreeDeviceProperties( + _In_ PUSB_DEVICE_PNP_STRINGS *ppDevProps + ); +// +// DISPAUD.C +// + +BOOL +DisplayAudioDescriptor ( + PUSB_AUDIO_COMMON_DESCRIPTOR CommonDesc, + UCHAR bInterfaceSubClass + ); + +// +// DISPVID.C +// + +BOOL +DisplayVideoDescriptor ( + PVIDEO_SPECIFIC VidCommonDesc, + UCHAR bInterfaceSubClass, + PSTRING_DESCRIPTOR_NODE StringDescs, + DEVICE_POWER_STATE LatestDevicePowerState + ); + +// +// DISPLAY.C +// + +BOOL +ValidateDescAddress ( + PUSB_COMMON_DESCRIPTOR commonDesc + ); + +#ifdef CUSTOM_USBVIEW +EXTERN_C PUSBDEVICEINFO enumerate_hub_port(HANDLE hHubDevice, ULONG port_index); +EXTERN_C PUSBDEVICEINFO get_usb_device_info(const char* device_name/*\\\\.\\USB..*/); +EXTERN_C void free_usb_device_info(PUSBDEVICEINFO pudi); +#endif \ No newline at end of file diff --git a/device/win_usb/usbview/usbdesc.h b/device/win_usb/usbview/usbdesc.h new file mode 100644 index 0000000..23420cf --- /dev/null +++ b/device/win_usb/usbview/usbdesc.h @@ -0,0 +1,394 @@ +/*++ + +Copyright (c) 1997-2008 Microsoft Corporation + +Module Name: + + USBDESC.H + +Abstract: + + This is a header file for USB descriptors which are not yet in + a standard system header file. + +Environment: + + user mode + +Revision History: + + 03-06-1998 : created + 03-28-2003 : minor changes to support UVC and USB200 + +--*/ + +#pragma pack(push, 1) + +/***************************************************************************** + D E F I N E S +*****************************************************************************/ + +// +//Device Descriptor bDeviceClass values +// +#define USB_INTERFACE_CLASS_DEVICE 0x00 +#define USB_COMMUNICATION_DEVICE 0x02 +#define USB_HUB_DEVICE 0x09 +#define USB_DEVICE_CLASS_BILLBOARD 0x11 +#define USB_DIAGNOSTIC_DEVICE 0xDC +#define USB_WIRELESS_CONTROLLER_DEVICE 0xE0 +#define USB_MISCELLANEOUS_DEVICE 0xEF +#define USB_VENDOR_SPECIFIC_DEVICE 0xFF + +// +//Device Descriptor bDeviceSubClass values +// +#define USB_COMMON_SUB_CLASS 0x02 + +// +//Interface Descriptor bInterfaceClass values: +// +//#define USB_AUDIO_INTERFACE 0x01 +//#define USB_CDC_CONTROL_INTERFACE 0x02 +//#define USB_HID_INTERFACE 0x03 +//#define USB_PHYSICAL_INTERFACE 0x05 +//#define USB_IMAGE_INTERFACE 0x06 +//#define USB_PRINTER_INTERFACE 0x07 +//#define USB_MASS_STORAGE_INTERFACE 0x08 +//#define USB_HUB_INTERFACE 0x09 +#define USB_CDC_DATA_INTERFACE 0x0A +#define USB_CHIP_SMART_CARD_INTERFACE 0x0B +#define USB_CONTENT_SECURITY_INTERFACE 0x0D +#define USB_DIAGNOSTIC_DEVICE_INTERFACE 0xDC +#define USB_WIRELESS_CONTROLLER_INTERFACE 0xE0 +#define USB_APPLICATION_SPECIFIC_INTERFACE 0xFE +//#define USB_VENDOR_SPECIFIC_INTERFACE 0xFF +#define USB_HID_DESCRIPTOR_TYPE 0x21 + +// +//IAD protocol values +// +#define USB_IAD_PROTOCOL 0x01 + +// +//Device class specific values +// +#define BILLBOARD_MAX_NUM_ALT_MODE 0x34 + +// +//USB 2.0 Specification Changes - New Descriptors +// +#define USB_OTHER_SPEED_CONFIGURATION_DESCRIPTOR_TYPE 0x07 +#define USB_INTERFACE_POWER_DESCRIPTOR_TYPE 0x08 +#define USB_OTG_DESCRIPTOR_TYPE 0x09 +#define USB_DEBUG_DESCRIPTOR_TYPE 0x0A +#define USB_IAD_DESCRIPTOR_TYPE 0x0B + +// +// USB Device Class Definition for Audio Devices +// Appendix A. Audio Device Class Codes +// + +// A.2 Audio Interface Subclass Codes +// +#define USB_AUDIO_SUBCLASS_UNDEFINED 0x00 +#define USB_AUDIO_SUBCLASS_AUDIOCONTROL 0x01 +#define USB_AUDIO_SUBCLASS_AUDIOSTREAMING 0x02 +#define USB_AUDIO_SUBCLASS_MIDISTREAMING 0x03 + +// A.4 Audio Class-Specific Descriptor Types +// +#define USB_AUDIO_CS_UNDEFINED 0x20 +#define USB_AUDIO_CS_DEVICE 0x21 +#define USB_AUDIO_CS_CONFIGURATION 0x22 +#define USB_AUDIO_CS_STRING 0x23 +#define USB_AUDIO_CS_INTERFACE 0x24 +#define USB_AUDIO_CS_ENDPOINT 0x25 + +// A.5 Audio Class-Specific AC (Audio Control) Interface Descriptor Subtypes +// +#define USB_AUDIO_AC_UNDEFINED 0x00 +#define USB_AUDIO_AC_HEADER 0x01 +#define USB_AUDIO_AC_INPUT_TERMINAL 0x02 +#define USB_AUDIO_AC_OUTPUT_TERMINAL 0x03 +#define USB_AUDIO_AC_MIXER_UNIT 0x04 +#define USB_AUDIO_AC_SELECTOR_UNIT 0x05 +#define USB_AUDIO_AC_FEATURE_UNIT 0x06 +#define USB_AUDIO_AC_PROCESSING_UNIT 0x07 +#define USB_AUDIO_AC_EXTENSION_UNIT 0x08 + +// A.6 Audio Class-Specific AS (Audio Streaming) Interface Descriptor Subtypes +// +#define USB_AUDIO_AS_UNDEFINED 0x00 +#define USB_AUDIO_AS_GENERAL 0x01 +#define USB_AUDIO_AS_FORMAT_TYPE 0x02 +#define USB_AUDIO_AS_FORMAT_SPECIFIC 0x03 + +// A.7 Processing Unit Process Types +// +#define USB_AUDIO_PROCESS_UNDEFINED 0x00 +#define USB_AUDIO_PROCESS_UPDOWNMIX 0x01 +#define USB_AUDIO_PROCESS_DOLBYPROLOGIC 0x02 +#define USB_AUDIO_PROCESS_3DSTEREOEXTENDER 0x03 +#define USB_AUDIO_PROCESS_REVERBERATION 0x04 +#define USB_AUDIO_PROCESS_CHORUS 0x05 +#define USB_AUDIO_PROCESS_DYNRANGECOMP 0x06 + + +/***************************************************************************** + T Y P E D E F S +*****************************************************************************/ + +// HID Class HID Descriptor +// +typedef struct _USB_HID_DESCRIPTOR +{ + UCHAR bLength; + UCHAR bDescriptorType; + USHORT bcdHID; + UCHAR bCountryCode; + UCHAR bNumDescriptors; + struct + { + UCHAR bDescriptorType; + USHORT wDescriptorLength; + } OptionalDescriptors[1]; +} USB_HID_DESCRIPTOR, *PUSB_HID_DESCRIPTOR; + + +// OTG Descriptor +// +typedef struct _USB_OTG_DESCRIPTOR +{ + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bmAttributes; +} USB_OTG_DESCRIPTOR, *PUSB_OTG_DESCRIPTOR; + +// IAD Descriptor +// +typedef struct _USB_IAD_DESCRIPTOR +{ + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bFirstInterface; + UCHAR bInterfaceCount; + UCHAR bFunctionClass; + UCHAR bFunctionSubClass; + UCHAR bFunctionProtocol; + UCHAR iFunction; +} USB_IAD_DESCRIPTOR, *PUSB_IAD_DESCRIPTOR; + + +// Common Class Endpoint Descriptor +// +typedef struct _USB_ENDPOINT_DESCRIPTOR2 { + UCHAR bLength; // offset 0, size 1 + UCHAR bDescriptorType; // offset 1, size 1 + UCHAR bEndpointAddress; // offset 2, size 1 + UCHAR bmAttributes; // offset 3, size 1 + USHORT wMaxPacketSize; // offset 4, size 2 + USHORT wInterval; // offset 6, size 2 + UCHAR bSyncAddress; // offset 8, size 1 +} USB_ENDPOINT_DESCRIPTOR2, *PUSB_ENDPOINT_DESCRIPTOR2; + +// Common Class Interface Descriptor +// +typedef struct _USB_INTERFACE_DESCRIPTOR2 { + UCHAR bLength; // offset 0, size 1 + UCHAR bDescriptorType; // offset 1, size 1 + UCHAR bInterfaceNumber; // offset 2, size 1 + UCHAR bAlternateSetting; // offset 3, size 1 + UCHAR bNumEndpoints; // offset 4, size 1 + UCHAR bInterfaceClass; // offset 5, size 1 + UCHAR bInterfaceSubClass; // offset 6, size 1 + UCHAR bInterfaceProtocol; // offset 7, size 1 + UCHAR iInterface; // offset 8, size 1 + USHORT wNumClasses; // offset 9, size 2 +} USB_INTERFACE_DESCRIPTOR2, *PUSB_INTERFACE_DESCRIPTOR2; + + +// +// USB Device Class Definition for Audio Devices +// + +typedef struct _USB_AUDIO_COMMON_DESCRIPTOR { + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; +} USB_AUDIO_COMMON_DESCRIPTOR, +*PUSB_AUDIO_COMMON_DESCRIPTOR; + +// 4.3.2 Class-Specific AC (Audio Control) Interface Descriptor +// +typedef struct _USB_AUDIO_AC_INTERFACE_HEADER_DESCRIPTOR { + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + USHORT bcdADC; + USHORT wTotalLength; + UCHAR bInCollection; + UCHAR baInterfaceNr[1]; +} USB_AUDIO_AC_INTERFACE_HEADER_DESCRIPTOR, +*PUSB_AUDIO_AC_INTERFACE_HEADER_DESCRIPTOR; + +// 4.3.2.1 Input Terminal Descriptor +// +typedef struct _USB_AUDIO_INPUT_TERMINAL_DESCRIPTOR { + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bTerminalID; + USHORT wTerminalType; + UCHAR bAssocTerminal; + UCHAR bNrChannels; + USHORT wChannelConfig; + UCHAR iChannelNames; + UCHAR iTerminal; +} USB_AUDIO_INPUT_TERMINAL_DESCRIPTOR, +*PUSB_AUDIO_INPUT_TERMINAL_DESCRIPTOR; + +// 4.3.2.2 Output Terminal Descriptor +// +typedef struct _USB_AUDIO_OUTPUT_TERMINAL_DESCRIPTOR { + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bTerminalID; + USHORT wTerminalType; + UCHAR bAssocTerminal; + UCHAR bSourceID; + UCHAR iTerminal; +} USB_AUDIO_OUTPUT_TERMINAL_DESCRIPTOR, +*PUSB_AUDIO_OUTPUT_TERMINAL_DESCRIPTOR; + +// 4.3.2.3 Mixer Unit Descriptor +// +typedef struct _USB_AUDIO_MIXER_UNIT_DESCRIPTOR { + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bUnitID; + UCHAR bNrInPins; + UCHAR baSourceID[1]; +} USB_AUDIO_MIXER_UNIT_DESCRIPTOR, +*PUSB_AUDIO_MIXER_UNIT_DESCRIPTOR; + +// 4.3.2.4 Selector Unit Descriptor +// +typedef struct _USB_AUDIO_SELECTOR_UNIT_DESCRIPTOR { + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bUnitID; + UCHAR bNrInPins; + UCHAR baSourceID[1]; +} USB_AUDIO_SELECTOR_UNIT_DESCRIPTOR, +*PUSB_AUDIO_SELECTOR_UNIT_DESCRIPTOR; + +// 4.3.2.5 Feature Unit Descriptor +// +typedef struct _USB_AUDIO_FEATURE_UNIT_DESCRIPTOR { + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bUnitID; + UCHAR bSourceID; + UCHAR bControlSize; + UCHAR bmaControls[1]; +} USB_AUDIO_FEATURE_UNIT_DESCRIPTOR, +*PUSB_AUDIO_FEATURE_UNIT_DESCRIPTOR; + +// 4.3.2.6 Processing Unit Descriptor +// +typedef struct _USB_AUDIO_PROCESSING_UNIT_DESCRIPTOR { + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bUnitID; + USHORT wProcessType; + UCHAR bNrInPins; + UCHAR baSourceID[1]; +} USB_AUDIO_PROCESSING_UNIT_DESCRIPTOR, +*PUSB_AUDIO_PROCESSING_UNIT_DESCRIPTOR; + +// 4.3.2.7 Extension Unit Descriptor +// +typedef struct _USB_AUDIO_EXTENSION_UNIT_DESCRIPTOR { + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bUnitID; + USHORT wExtensionCode; + UCHAR bNrInPins; + UCHAR baSourceID[1]; +} USB_AUDIO_EXTENSION_UNIT_DESCRIPTOR, +*PUSB_AUDIO_EXTENSION_UNIT_DESCRIPTOR; + +// 4.5.2 Class-Specific AS Interface Descriptor +// +typedef struct _USB_AUDIO_GENERAL_DESCRIPTOR { + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bTerminalLink; + UCHAR bDelay; + USHORT wFormatTag; +} USB_AUDIO_GENERAL_DESCRIPTOR, +*PUSB_AUDIO_GENERAL_DESCRIPTOR; + +// 4.6.1.2 Class-Specific AS Endpoint Descriptor +// +typedef struct _USB_AUDIO_ENDPOINT_DESCRIPTOR { + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bmAttributes; + UCHAR bLockDelayUnits; + USHORT wLockDelay; +} USB_AUDIO_ENDPOINT_DESCRIPTOR, +*PUSB_AUDIO_ENDPOINT_DESCRIPTOR; + +// +// USB Device Class Definition for Audio Data Formats +// + +typedef struct _USB_AUDIO_COMMON_FORMAT_DESCRIPTOR { + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bFormatType; +} USB_AUDIO_COMMON_FORMAT_DESCRIPTOR, +*PUSB_AUDIO_COMMON_FORMAT_DESCRIPTOR; + + +// 2.1.5 Type I Format Type Descriptor +// 2.3.1 Type III Format Type Descriptor +// +typedef struct _USB_AUDIO_TYPE_I_OR_III_FORMAT_DESCRIPTOR { + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bFormatType; + UCHAR bNrChannels; + UCHAR bSubframeSize; + UCHAR bBitResolution; + UCHAR bSamFreqType; +} USB_AUDIO_TYPE_I_OR_III_FORMAT_DESCRIPTOR, +*PUSB_AUDIO_TYPE_I_OR_III_FORMAT_DESCRIPTOR; + + +// 2.2.6 Type II Format Type Descriptor +// +typedef struct _USB_AUDIO_TYPE_II_FORMAT_DESCRIPTOR { + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bFormatType; + USHORT wMaxBitRate; + USHORT wSamplesPerFrame; + UCHAR bSamFreqType; +} USB_AUDIO_TYPE_II_FORMAT_DESCRIPTOR, +*PUSB_AUDIO_TYPE_II_FORMAT_DESCRIPTOR; + +#pragma pack(pop) diff --git a/device/win_usb/usbview/uvcdesc.h b/device/win_usb/usbview/uvcdesc.h new file mode 100644 index 0000000..b1d197a --- /dev/null +++ b/device/win_usb/usbview/uvcdesc.h @@ -0,0 +1,1106 @@ +//+------------------------------------------------------------------------- +// +// Microsoft Windows +// +// Copyright (C) Microsoft Corporation, 1999 - 2008 +// +// File: uvcdesc.h +// +// This header is from the UVC 1.1 USBVideo driver +// +//-------------------------------------------------------------------------- + +#ifndef ___UVCDESC_H___ +#define ___UVCDESC_H___ + + +// USB Video Device Class Code +#define USB_DEVICE_CLASS_VIDEO 0x0E + +// Video sub-classes +#define SUBCLASS_UNDEFINED 0x00 +#define VIDEO_SUBCLASS_CONTROL 0x01 +#define VIDEO_SUBCLASS_STREAMING 0x02 + +// Video Class-Specific Descriptor Types +#define CS_UNDEFINED 0x20 +#define CS_DEVICE 0x21 +#define CS_CONFIGURATION 0x22 +#define CS_STRING 0x23 +#define CS_INTERFACE 0x24 +#define CS_ENDPOINT 0x25 + +// Video Class-Specific VC Interface Descriptor Subtypes +#define VC_HEADER 0x01 +#define INPUT_TERMINAL 0x02 +#define OUTPUT_TERMINAL 0x03 +#define SELECTOR_UNIT 0x04 +#define PROCESSING_UNIT 0x05 +#define EXTENSION_UNIT 0x06 +#define MAX_TYPE_UNIT 0x07 + +// Video Class-Specific VS Interface Descriptor Subtypes +#define VS_DESCRIPTOR_UNDEFINED 0x00 +#define VS_INPUT_HEADER 0x01 +#define VS_OUTPUT_HEADER 0x02 +#define VS_STILL_IMAGE_FRAME 0x03 +#define VS_FORMAT_UNCOMPRESSED 0x04 +#define VS_FRAME_UNCOMPRESSED 0x05 +#define VS_FORMAT_MJPEG 0x06 +#define VS_FRAME_MJPEG 0x07 +#define VS_FORMAT_MPEG1 0x08 +#define VS_FORMAT_MPEG2PS 0x09 +#define VS_FORMAT_MPEG2TS 0x0A +#define VS_FORMAT_MPEG4SL 0x0B +#define VS_FORMAT_DV 0x0C +#define VS_COLORFORMAT 0x0D +#define VS_FORMAT_VENDOR 0x0E +#define VS_FRAME_VENDOR 0x0F + +// Video Class-Specific Endpoint Descriptor Subtypes +#define EP_UNDEFINED 0x00 +#define EP_GENERAL 0x01 +#define EP_ENDPOINT 0x02 +#define EP_INTERRUPT 0x03 + +// Video Class-Specific Terminal Types +#define TERMINAL_TYPE_VENDOR_SPECIFIC 0x0100 +#define TERMINAL_TYPE_USB_STREAMING 0x0101 +#define TERMINAL_TYPE_INPUT_MASK 0x0200 +#define TERMINAL_TYPE_INPUT_VENDOR_SPECIFIC 0x0200 +#define TERMINAL_TYPE_INPUT_CAMERA 0x0201 +#define TERMINAL_TYPE_INPUT_MEDIA_TRANSPORT 0x0202 +#define TERMINAL_TYPE_OUTPUT_MASK 0x0300 +#define TERMINAL_TYPE_OUTPUT_VENDOR_SPECIFIC 0x0300 +#define TERMINAL_TYPE_OUTPUT_DISPLAY 0x0301 +#define TERMINAL_TYPE_OUTPUT_MEDIA_TRANSPORT 0x0302 +#define TERMINAL_TYPE_EXTERNAL_VENDOR_SPECIFIC 0x0400 +#define TERMINAL_TYPE_EXTERNAL_UNDEFINED 0x0400 +#define TERMINAL_TYPE_EXTERNAL_COMPOSITE 0x0401 +#define TERMINAL_TYPE_EXTERNAL_SVIDEO 0x0402 +#define TERMINAL_TYPE_EXTERNAL_COMPONENT 0x0403 + + +// Controls for error checking only +#define DEV_SPECIFIC_CONTROL 0x1001 + +// Map KSNODE_TYPE GUIDs to Indexes +#define NODE_TYPE_NONE 0 +#define NODE_TYPE_STREAMING 1 +#define NODE_TYPE_INPUT_TERMINAL 2 +#define NODE_TYPE_OUTPUT_TERMINAL 3 +#define NODE_TYPE_SELECTOR 4 +#define NODE_TYPE_PROCESSING 5 +#define NODE_TYPE_CAMERA_TERMINAL 6 +#define NODE_TYPE_INPUT_MTT 7 +#define NODE_TYPE_OUTPUT_MTT 8 +#define NODE_TYPE_DEV_SPEC 9 +#define NODE_TYPE_MAX 9 + +// USB bmRequestType values +#define USBVIDEO_INTERFACE_SET 0x21 +#define USBVIDEO_ENDPOINT_SET 0x22 +#define USBVIDEO_INTERFACE_GET 0xA1 +#define USBVIDEO_ENDPOINT_GET 0xA2 + +// Video Class-specific specific requests +#define CLASS_SPECIFIC_GET_MASK 0x80 + +#define RC_UNDEFINED 0x00 +#define SET_CUR 0x01 +#define GET_CUR 0x81 +#define GET_MIN 0x82 +#define GET_MAX 0x83 +#define GET_RES 0x84 +#define GET_LEN 0x85 +#define GET_INFO 0x86 +#define GET_DEF 0x87 + +// Power Mode Control constants +#define POWER_MODE_CONTROL_FULL 0x0 +#define POWER_MODE_CONTROL_DEV_DEPENDENT 0x1 + +// Video Class-specific Processing Unit Controls +#define PU_CONTROL_UNDEFINED 0x00 +#define PU_BACKLIGHT_COMPENSATION_CONTROL 0x01 +#define PU_BRIGHTNESS_CONTROL 0x02 +#define PU_CONTRAST_CONTROL 0x03 +#define PU_GAIN_CONTROL 0x04 +#define PU_POWER_LINE_FREQUENCY_CONTROL 0x05 +#define PU_HUE_CONTROL 0x06 +#define PU_SATURATION_CONTROL 0x07 +#define PU_SHARPNESS_CONTROL 0x08 +#define PU_GAMMA_CONTROL 0x09 +#define PU_WHITE_BALANCE_TEMPERATURE_CONTROL 0x0A +#define PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL 0x0B +#define PU_WHITE_BALANCE_COMPONENT_CONTROL 0x0C +#define PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL 0x0D +#define PU_DIGITAL_MULTIPLIER_CONTROL 0x0E +#define PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL 0x0F +#define PU_HUE_AUTO_CONTROL 0x10 +#define PU_ANALOG_VIDEO_STANDARD_CONTROL 0x11 +#define PU_ANALOG_LOCK_STATUS_CONTROL 0x12 + +// Video Class-specific Camera Terminal Controls +#define CT_CONTROL_UNDEFINED 0x00 +#define CT_SCANNING_MODE_CONTROL 0x01 +#define CT_AE_MODE_CONTROL 0x02 +#define CT_AE_PRIORITY_CONTROL 0x03 +#define CT_EXPOSURE_TIME_ABSOLUTE_CONTROL 0x04 +#define CT_EXPOSURE_TIME_RELATIVE_CONTROL 0x05 +#define CT_FOCUS_ABSOLUTE_CONTROL 0x06 +#define CT_FOCUS_RELATIVE_CONTROL 0x07 +#define CT_FOCUS_AUTO_CONTROL 0x08 +#define CT_IRIS_ABSOLUTE_CONTROL 0x09 +#define CT_IRIS_RELATIVE_CONTROL 0x0A +#define CT_ZOOM_ABSOLUTE_CONTROL 0x0B +#define CT_ZOOM_RELATIVE_CONTROL 0x0C +#define CT_PANTILT_ABSOLUTE_CONTROL 0x0D +#define CT_PANTILT_RELATIVE_CONTROL 0x0E +#define CT_ROLL_ABSOLUTE_CONTROL 0x0F +#define CT_ROLL_RELATIVE_CONTROL 0x10 +#define CT_PRIVACY_CONTROL 0x11 + +#define CT_RELATIVE_INCREASE 0x01 +#define CT_RELATIVE_DECREASE 0xff +#define CT_RELATIVE_STOP 0x00 + +// Selector Unit Control Selector +#define SU_INPUT_SELECT_CONTROL 0x01 + +// Media Tape Transport Control Selector +#define MTT_CONTROL_UNDEFINED 0x00 +#define MTT_TRANSPORT_CONTROL 0x01 +#define MTT_ATN_INFORMATION_CONTROL 0x02 +#define MTT_MEDIA_INFORMATION_CONTROL 0x03 +#define MTT_TIME_CODE_INFORMATION_CONTROL 0x04 + +// Media Transport Terminal States +#define MTT_STATE_PLAY_NEXT_FRAME 0x00 +#define MTT_STATE_PLAY_FWD_SLOWEST 0x01 +#define MTT_STATE_PLAY_SLOW_FWD_4 0x02 +#define MTT_STATE_PLAY_SLOW_FWD_3 0x03 +#define MTT_STATE_PLAY_SLOW_FWD_2 0x04 +#define MTT_STATE_PLAY_SLOW_FWD_1 0x05 +#define MTT_STATE_PLAY_X1 0x06 +#define MTT_STATE_PLAY_FAST_FWD_1 0x07 +#define MTT_STATE_PLAY_FAST_FWD_2 0x08 +#define MTT_STATE_PLAY_FAST_FWD_3 0x09 +#define MTT_STATE_PLAY_FAST_FWD_4 0x0A +#define MTT_STATE_PLAY_FASTEST_FWD 0x0B +#define MTT_STATE_PLAY_PREV_FRAME 0x0C +#define MTT_STATE_PLAY_SLOWEST_REV 0x0D +#define MTT_STATE_PLAY_SLOW_REV_4 0x0E +#define MTT_STATE_PLAY_SLOW_REV_3 0x0F +#define MTT_STATE_PLAY_SLOW_REV_2 0x10 +#define MTT_STATE_PLAY_SLOW_REV_1 0x11 +#define MTT_STATE_PLAY_REV 0x12 +#define MTT_STATE_PLAY_FAST_REV_1 0x13 +#define MTT_STATE_PLAY_FAST_REV_2 0x14 +#define MTT_STATE_PLAY_FAST_REV_3 0x15 +#define MTT_STATE_PLAY_FAST_REV_4 0x16 +#define MTT_STATE_PLAY_FASTEST_REV 0x17 +#define MTT_STATE_PLAY 0x18 +#define MTT_STATE_PAUSE 0x19 +#define MTT_STATE_PLAY_REVERSE_PAUSE 0x1A + + +#define MTT_STATE_STOP 0x40 +#define MTT_STATE_FAST_FORWARD 0x41 +#define MTT_STATE_REWIND 0x42 +#define MTT_STATE_HIGH_SPEED_REWIND 0x43 + +#define MTT_STATE_RECORD_START 0x50 +#define MTT_STATE_RECORD_PAUSE 0x51 + +#define MTT_STATE_EJECT 0x60 + +#define MTT_STATE_PLAY_SLOW_FWD_X 0x70 +#define MTT_STATE_PLAY_FAST_FWD_X 0x71 +#define MTT_STATE_PLAY_SLOW_REV_X 0x72 +#define MTT_STATE_PLAY_FAST_REV_X 0x73 +#define MTT_STATE_STOP_START 0x74 +#define MTT_STATE_STOP_END 0x75 +#define MTT_STATE_STOP_EMERGENCY 0x76 +#define MTT_STATE_STOP_CONDENSATION 0x77 +#define MTT_STATE_UNSPECIFIED 0x7F + +// Video Control Interface Control Selectors +#define VC_UNDEFINED_CONTROL 0x00 +#define VC_VIDEO_POWER_MODE_CONTROL 0x01 +#define VC_REQUEST_ERROR_CODE_CONTROL 0x02 + +// VideoStreaming Interface Control Selectors +#define VS_CONTROL_UNDEFINED 0x00 +#define VS_PROBE_CONTROL 0x01 +#define VS_COMMIT_CONTROL 0x02 +#define VS_STILL_PROBE_CONTROL 0x03 +#define VS_STILL_COMMIT_CONTROL 0x04 +#define VS_STILL_IMAGE_TRIGGER_CONTROL 0x05 +#define VS_STREAM_ERROR_CODE_CONTROL 0x06 +#define VS_GENERATE_KEY_FRAME_CONTROL 0x07 +#define VS_UPDATE_FRAME_SEGMENT_CONTROL 0x08 +#define VS_SYNC_DELAY_CONTROL 0x09 + +// Probe commit bitmap framing info +#define VS_PROBE_COMMIT_BIT_FID 0x01 +#define VS_PROBE_COMMIT_BIT_EOF 0x02 + +// Stream payload header Bit Field Header bits +#define BFH_FID 0x01 // Frame ID bit +#define BFH_EOF 0x02 // End of Frame bit +#define BFH_PTS 0x04 // Presentation Time Stamp bit +#define BFH_SCR 0x08 // Source Clock Reference bit +#define BFH_RES 0x10 // Reserved bit +#define BFH_STI 0x20 // Still image bit +#define BFH_ERR 0x40 // Error bit +#define BFH_EOH 0x80 // End of header bit + +#define HDR_LENGTH 1 // Length of header length field in bytes +#define BFH_LENGTH 1 // Length of BFH field in bytes +#define PTS_LENGTH 4 // Length of PTS field in bytes +#define SCR_LENGTH 6 // Length of SCR field in bytes + +// USB Video Status Codes (Request Error Code Control) +#define USBVIDEO_RE_STATUS_NOERROR 0x00 +#define USBVIDEO_RE_STATUS_NOT_READY 0x01 +#define USBVIDEO_RE_STATUS_WRONG_STATE 0x02 +#define USBVIDEO_RE_STATUS_POWER 0x03 +#define USBVIDEO_RE_STATUS_OUT_OF_RANGE 0x04 +#define USBVIDEO_RE_STATUS_INVALID_UNIT 0x05 +#define USBVIDEO_RE_STATUS_INVALID_CONTROL 0x06 +#define USBVIDEO_RE_STATUS_UNKNOWN 0x07 + +// USB Video Device Status Codes (Stream Error Code Control) +#define USBVIDEO_SE_STATUS_NOERROR 0x00 +#define USBVIDEO_SE_STATUS_PROTECTED_CONTENT 0x01 +#define USBVIDEO_SE_STATUS_INPUT_BUFFER_UNDERRUN 0x02 +#define USBVIDEO_SE_STATUS_DATA_DICONTINUITY 0x03 +#define USBVIDEO_SE_STATUS_OUTPUT_BUFFER_UNDERRUN 0x04 +#define USBVIDEO_SE_STATUS_OUTPUT_BUFFER_OVERRUN 0x05 +#define USBVIDEO_SE_STATUS_FORMAT_CHANGE 0x06 +#define USBVIDEO_SE_STATUS_STILL_IMAGE_ERROR 0x07 +#define USBVIDEO_SE_STATUS_UNKNOWN 0x08 + +// Status Interrupt Types +#define STATUS_INTERRUPT_VC 1 +#define STATUS_INTERRUPT_VS 2 + +// Status Interrupt Attributes +#define STATUS_INTERRUPT_ATTRIBUTE_VALUE 0x00 +#define STATUS_INTERRUPT_ATTRIBUTE_INFO 0x01 +#define STATUS_INTERRUPT_ATTRIBUTE_FAILURE 0x02 + +// VideoStreaming interface interrupt types +#define VS_INTERRUPT_EVENT_BUTTON_PRESS 0x00 +#define VS_INTERRUPT_VALUE_BUTTON_RELEASE 0x00 +#define VS_INTERRUPT_VALUE_BUTTON_PRESS 0x01 + +// Get Info Values +#define USBVIDEO_ASYNC_CONTROL 0x10 +#define USBVIDEO_SETTABLE_CONTROL 0x2 + +#define MAX_INTERRUPT_PACKET_VALUE_SIZE 8 + +// Frame descriptor frame interval array offsets +#define MIN_FRAME_INTERVAL_OFFSET 0 +#define MAX_FRAME_INTERVAL_OFFSET 1 +#define FRAME_INTERVAL_STEP_OFFSET 2 + +// Still image capture methods +#define STILL_CAPTURE_METHOD_NONE 0 +#define STILL_CAPTURE_METHOD_1 1 +#define STILL_CAPTURE_METHOD_2 2 +#define STILL_CAPTURE_METHOD_3 3 + +// Still image trigger control states +#define STILL_IMAGE_TRIGGER_NORMAL 0 +#define STILL_IMAGE_TRIGGER_TRANSMIT 1 +#define STILL_IMAGE_TRIGGER_TRANSMIT_BULK 2 +#define STILL_IMAGE_TRIGGER_TRANSMIT_ABORT 3 + +// Endpoint descriptor masks +#define EP_DESCRIPTOR_TRANSACTION_SIZE_MASK 0x07ff +#define EP_DESCRIPTOR_NUM_TRANSACTION_MASK 0x1800 +#define EP_DESCRIPTOR_NUM_TRANSACTION_OFFSET 11 + + +// Copy protection flag defined in the Uncompressed Payload Spec +#define USB_VIDEO_UNCOMPRESSED_RESTRICT_DUPLICATION 1 + +// Interlace flags +#define INTERLACE_FLAGS_SUPPORTED_MASK 0x01 +#define INTERLACE_FLAGS_FIELDS_PER_FRAME_MASK 0x02 +#define INTERLACE_FLAGS_FIELDS_PER_FRAME_2 0x00 +#define INTERLACE_FLAGS_FIELDS_PER_FRAME_1 0x02 +#define INTERLACE_FLAGS_FIELD_1_FIRST_MASK 0x04 +#define INTERLACE_FLAGS_FIELD_PATTERN_MASK 0x30 +#define INTERLACE_FLAGS_FIELD_PATTERN_FIELD1 0x00 +#define INTERLACE_FLAGS_FIELD_PATTERN_FIELD2 0x10 +#define INTERLACE_FLAGS_FIELD_PATTERN_REGULAR 0x20 +#define INTERLACE_FLAGS_FIELD_PATTERN_RANDOM 0x30 +#define INTERLACE_FLAGS_DISPLAY_MODE_MASK 0xC0 +#define INTERLACE_FLAGS_DISPLAY_MODE_BOB 0x00 +#define INTERLACE_FLAGS_DISPLAY_MODE_WEAVE 0x40 +#define INTERLACE_FLAGS_DISPLAY_MODE_BOB_WEAVE 0x80 + +// Color Matching Flags +#define UVC_PRIMARIES_UNKNOWN 0x0 +#define UVC_PRIMARIES_BT709 0x1 +#define UVC_PRIMARIES_BT470_2M 0x2 +#define UVC_PRIMARIES_BT470_2BG 0x3 +#define UVC_PRIMARIES_SMPTE_170M 0x4 +#define UVC_PRIMARIES_SMPTE_240M 0x5 + +#define UVC_GAMMA_UNKNOWN 0x0 +#define UVC_GAMMA_BT709 0x1 +#define UVC_GAMMA_BT470_2M 0x2 +#define UVC_GAMMA_BT470_2BG 0x3 +#define UVC_GAMMA_SMPTE_170M 0x4 +#define UVC_GAMMA_SMPTE_240M 0x5 +#define UVC_GAMMA_LINEAR 0x6 +#define UVC_GAMMA_sRGB 0x7 + +#define UVC_TRANSFER_MATRIX_UNKNOWN 0x0 +#define UVC_TRANSFER_MATRIX_BT709 0x1 +#define UVC_TRANSFER_MATRIX_FCC 0x2 +#define UVC_TRANSFER_MATRIX_BT470_2BG 0x3 +#define UVC_TRANSFER_MATRIX_BT601 0x4 +#define UVC_TRANSFER_MATRIX_SMPTE_240M 0x5 + +// +// BEGIN - VDC Descriptor and Control Structures +// +#pragma warning( disable : 4200 ) // Allow zero-sized arrays at end of structs +#pragma pack( push, vdc_descriptor_structs, 1) + +// Video Specific Descriptor +typedef struct { + UCHAR bLength; // Size of this descriptor in bytes + UCHAR bDescriptorType; // CS_INTERFACE descriptor type + UCHAR bDescriptorSubtype; // descriptor subtype +} VIDEO_SPECIFIC, *PVIDEO_SPECIFIC; + +#define SIZEOF_VIDEO_SPECIFIC(pDesc) sizeof(VIDEO_SPECIFIC) + + +// Video Unit Descriptor +typedef struct { + UCHAR bLength; // Size of this descriptor in bytes + UCHAR bDescriptorType; // CS_INTERFACE descriptor type + UCHAR bDescriptorSubtype; // descriptor subtype + UCHAR bUnitID; // Constant uniquely identifying the Unit +} VIDEO_UNIT, *PVIDEO_UNIT; + +#define SIZEOF_VIDEO_UNIT(pDesc) sizeof(VIDEO_UNIT) + +// VideoControl Header Descriptor +typedef struct { + UCHAR bLength; // Size of this descriptor in bytes + UCHAR bDescriptorType; // CS_INTERFACE descriptor type + UCHAR bDescriptorSubtype; // VC_HEADER descriptor subtype + USHORT bcdVideoSpec; // USB video class spec revision number + USHORT wTotalLength; // Total length, including all units and terminals + ULONG dwClockFreq; // Device clock frequency in Hz + UCHAR bInCollection; // number of video streaming interfaces + UCHAR baInterfaceNr[]; // interface number array +} VIDEO_CONTROL_HEADER_UNIT, *PVIDEO_CONTROL_HEADER_UNIT; + +#define SIZEOF_VIDEO_CONTROL_HEADER_UNIT(pDesc) \ + ((sizeof(VIDEO_CONTROL_HEADER_UNIT) + (pDesc)->bInCollection)) + + +// VideoControl Input Terminal Descriptor +typedef struct { + UCHAR bLength; // Size of this descriptor in bytes + UCHAR bDescriptorType; // CS_INTERFACE descriptor type + UCHAR bDescriptorSubtype; // INPUT_TERMINAL descriptor subtype + UCHAR bTerminalID; // Constant uniquely identifying the Terminal + USHORT wTerminalType; // Constant characterizing the terminal type + UCHAR bAssocTerminal; // ID of associated output terminal + UCHAR iTerminal; // Index of string descriptor +} VIDEO_INPUT_TERMINAL, *PVIDEO_INPUT_TERMINAL; + +#define SIZEOF_VIDEO_INPUT_TERMINAL(pDesc) sizeof(VIDEO_INPUT_TERMINAL) + + +// VideoControl Output Terminal Descriptor +typedef struct { + UCHAR bLength; // Size of this descriptor in bytes + UCHAR bDescriptorType; // CS_INTERFACE descriptor type + UCHAR bDescriptorSubtype; // OUTPUT_TERMINAL descriptor subtype + UCHAR bTerminalID; // Constant uniquely identifying the Terminal + USHORT wTerminalType; // Constant characterizing the terminal type + UCHAR bAssocTerminal; // ID of associated input terminal + UCHAR bSourceID; // ID of source unit/terminal + UCHAR iTerminal; // Index of string descriptor +} VIDEO_OUTPUT_TERMINAL, *PVIDEO_OUTPUT_TERMINAL; + +#define SIZEOF_VIDEO_OUTPUT_TERMINAL(pDesc) sizeof(VIDEO_OUTPUT_TERMINAL) + + +// VideoControl Camera Terminal Descriptor +typedef struct { + UCHAR bLength; // Size of this descriptor in bytes + UCHAR bDescriptorType; // CS_INTERFACE descriptor type + UCHAR bDescriptorSubtype; // INPUT_TERMINAL descriptor subtype + UCHAR bTerminalID; // Constant uniquely identifying the Terminal + USHORT wTerminalType; // Sensor type + UCHAR bAssocTerminal; // ID of associated output terminal + UCHAR iTerminal; // Index of string descriptor + USHORT wObjectiveFocalLengthMin; // Min focal length for zoom + USHORT wObjectiveFocalLengthMax; // Max focal length for zoom + USHORT wOcularFocalLength; // Ocular focal length for zoom + UCHAR bControlSize; // Size of bmControls field + UCHAR bmControls[]; // Bitmap of controls supported +} VIDEO_CAMERA_TERMINAL, *PVIDEO_CAMERA_TERMINAL; + +#define SIZEOF_VIDEO_CAMERA_TERMINAL(pDesc) \ + (sizeof(VIDEO_CAMERA_TERMINAL) + (pDesc)->bControlSize) + + +// Media Transport Input Terminal Descriptor +typedef struct { + UCHAR bLength; // Size of this descriptor in bytes + UCHAR bDescriptorType; // CS_INTERFACE descriptor type + UCHAR bDescriptorSubtype; // INPUT_TERMINAL descriptor subtype + UCHAR bTerminalID; // Constant uniquely identifying the Terminal + USHORT wTerminalType; // Media Transport type + UCHAR bAssocTerminal; // ID of associated output terminal + UCHAR iTerminal; // Index of string descriptor + UCHAR bControlSize; // Size of bmControls field + UCHAR bmControls[]; // Bitmap of controls supported +} VIDEO_INPUT_MTT, *PVIDEO_INPUT_MTT; + + +__inline size_t SizeOfVideoInputMTT(_In_ PVIDEO_INPUT_MTT pDesc) +{ + UCHAR bTransportModeSize; + PUCHAR pbCurr; + + pbCurr = pDesc->bmControls + pDesc->bControlSize; + bTransportModeSize = *pbCurr; + + return sizeof(VIDEO_INPUT_MTT) + pDesc->bControlSize + 1 + bTransportModeSize; +} + +#define SIZEOF_VIDEO_INPUT_MTT(pDesc) SizeOfVideoInputMTT(pDesc) + + +// Media Transport Output Terminal Descriptor +typedef struct { + UCHAR bLength; // Size of this descriptor in bytes + UCHAR bDescriptorType; // CS_INTERFACE descriptor type + UCHAR bDescriptorSubtype; // OUTPUT_TERMINAL descriptor subtype + UCHAR bTerminalID; // Constant uniquely identifying the Terminal + USHORT wTerminalType; // Media Transport type + UCHAR bAssocTerminal; // ID of associated output terminal + UCHAR bSourceID; // ID of source unit/terminal + UCHAR iTerminal; // Index of string descriptor + UCHAR bControlSize; // Size of bmControls field + UCHAR bmControls[]; // Bitmap of controls supported +} VIDEO_OUTPUT_MTT, *PVIDEO_OUTPUT_MTT; + + +__inline size_t SizeOfVideoOutputMTT(_In_ PVIDEO_OUTPUT_MTT pDesc) +{ + UCHAR bTransportModeSize; + PUCHAR pbCurr; + + pbCurr = pDesc->bmControls + pDesc->bControlSize; + bTransportModeSize = *pbCurr; + + return sizeof(VIDEO_OUTPUT_MTT) + pDesc->bControlSize + 1+ bTransportModeSize; +} + +#define SIZEOF_VIDEO_OUTPUT_MTT(pDesc) SizeOfVideoOutputMTT(pDesc) + + +// VideoControl Selector Unit Descriptor +typedef struct { + UCHAR bLength; // Size of this descriptor in bytes + UCHAR bDescriptorType; // CS_INTERFACE descriptor type + UCHAR bDescriptorSubtype; // SELECTOR_UNIT descriptor subtype + UCHAR bUnitID; // Constant uniquely identifying the Unit + UCHAR bNrInPins; // Number of input pins + UCHAR baSourceID[]; // IDs of connected units/terminals +} VIDEO_SELECTOR_UNIT, *PVIDEO_SELECTOR_UNIT; + +#define SIZEOF_VIDEO_SELECTOR_UNIT(pDesc) \ + (sizeof(VIDEO_SELECTOR_UNIT) + (pDesc)->bNrInPins + 1) + + +// VideoControl Processing Unit Descriptor +typedef struct { + UCHAR bLength; // Size of this descriptor in bytes + UCHAR bDescriptorType; // CS_INTERFACE descriptor type + UCHAR bDescriptorSubtype; // PROCESSING_UNIT descriptor subtype + UCHAR bUnitID; // Constant uniquely identifying the Unit + UCHAR bSourceID; // ID of connected unit/terminal + USHORT wMaxMultiplier; // Maximum digital magnification + UCHAR bControlSize; // Size of bmControls field + UCHAR bmControls[]; // Bitmap of controls supported +} VIDEO_PROCESSING_UNIT, *PVIDEO_PROCESSING_UNIT; + +#define SIZEOF_VIDEO_PROCESSING_UNIT(pDesc) \ + (sizeof(VIDEO_PROCESSING_UNIT) + 1 + (pDesc)->bControlSize) + + +// VideoControl Extension Unit Descriptor +typedef struct { + UCHAR bLength; // Size of this descriptor in bytes + UCHAR bDescriptorType; // CS_INTERFACE descriptor type + UCHAR bDescriptorSubtype; // EXTENSION_UNIT descriptor subtype + UCHAR bUnitID; // Constant uniquely identifying the Unit + GUID guidExtensionCode; // Vendor-specific code identifying extension unit + UCHAR bNumControls; // Number of controls in Extension Unit + UCHAR bNrInPins; // Number of input pins + UCHAR baSourceID[]; // IDs of connected units/terminals +} VIDEO_EXTENSION_UNIT, *PVIDEO_EXTENSION_UNIT; +// this is followed by bControlSize, bmControls and iExtension (1 byte) + +__inline size_t SizeOfVideoExtensionUnit(PVIDEO_EXTENSION_UNIT pDesc) +{ + UCHAR bControlSize; + PUCHAR pbCurr; + + // baSourceID is an array, and hence understood to be an address + pbCurr = pDesc->baSourceID + pDesc->bNrInPins; + if (((ULONG_PTR) pbCurr < (ULONG_PTR) pDesc->baSourceID) || + (ULONG_PTR) pbCurr >= (ULONG_PTR)((UCHAR *) pDesc + pDesc->bLength)) + return 0; + + bControlSize = *pbCurr; + return 24 + pDesc->bNrInPins + bControlSize; +} + +#define SIZEOF_VIDEO_EXTENSION_UNIT(pDesc) SizeOfVideoExtensionUnit(pDesc) + + +// Class-specific Interrupt Endpoint Descriptor +typedef struct { + UCHAR bLength; // Size of this descriptor in bytes + UCHAR bDescriptorType; // CS_ENDPOINT descriptor type + UCHAR bDescriptorSubtype; // EP_INTERRUPT descriptor subtype + USHORT wMaxTransferSize; // Max interrupt payload size +} VIDEO_CS_INTERRUPT, *PVIDEO_CS_INTERRUPT; + +#define SIZEOF_VIDEO_CS_INTERRUPT(pDesc) sizeof(VIDEO_CS_INTERRUPT) + + +// VideoStreaming Input Header Descriptor +typedef struct _VIDEO_STREAMING_INPUT_HEADER +{ + UCHAR bLength; // Size of this descriptor in bytes + UCHAR bDescriptorType; // CS_INTERFACE descriptor type + UCHAR bDescriptorSubtype; // VS_INPUT_HEADER descriptor subtype + UCHAR bNumFormats; + USHORT wTotalLength; + UCHAR bEndpointAddress; + UCHAR bmInfo; + UCHAR bTerminalLink; + UCHAR bStillCaptureMethod; + UCHAR bTriggerSupport; + UCHAR bTriggerUsage; + UCHAR bControlSize; + UCHAR bmaControls[]; +} VIDEO_STREAMING_INPUT_HEADER, *PVIDEO_STREAMING_INPUT_HEADER; + +#define SIZEOF_VIDEO_STREAMING_INPUT_HEADER(pDesc) \ + (sizeof(VIDEO_STREAMING_INPUT_HEADER) + (pDesc->bNumFormats * pDesc->bControlSize)) + + +// VideoStreaming Output Header Descriptor +typedef struct _VIDEO_STREAMING_OUTPUT_HEADER +{ + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bNumFormats; + USHORT wTotalLength; + UCHAR bEndpointAddress; + UCHAR bTerminalLink; +} VIDEO_STREAMING_OUTPUT_HEADER, *PVIDEO_STREAMING_OUTPUT_HEADER; + +#define SIZEOF_VIDEO_STREAMING_OUTPUT_HEADER(pDesc) sizeof(VIDEO_STREAMING_OUTPUT_HEADER) + + +typedef struct _VIDEO_STILL_IMAGE_RECT +{ + USHORT wWidth; + USHORT wHeight; +} VIDEO_STILL_IMAGE_RECT; + +// VideoStreaming Still Image Frame Descriptor +typedef struct _VIDEO_STILL_IMAGE_FRAME +{ + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bEndpointAddress; + UCHAR bNumImageSizePatterns; + VIDEO_STILL_IMAGE_RECT aStillRect[]; +} VIDEO_STILL_IMAGE_FRAME, *PVIDEO_STILL_IMAGE_FRAME; + +__inline size_t SizeOfVideoStillImageFrame(PVIDEO_STILL_IMAGE_FRAME pDesc) +{ + UCHAR bNumCompressionPatterns; + PUCHAR pbCurr; + + pbCurr = (PUCHAR) pDesc->aStillRect + (sizeof(VIDEO_STILL_IMAGE_RECT) * pDesc->bNumImageSizePatterns); + bNumCompressionPatterns = *pbCurr; + + return (sizeof(VIDEO_STILL_IMAGE_FRAME) + + (sizeof(VIDEO_STILL_IMAGE_RECT) * pDesc->bNumImageSizePatterns) + + 1 + bNumCompressionPatterns); +} + +#define SIZEOF_VIDEO_STILL_IMAGE_FRAME(pDesc) SizeOfVideoStillImageFrame(pDesc) + + +// VideoStreaming Color Matching Descriptor +typedef struct _VIDEO_COLORFORMAT +{ + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bColorPrimaries; + UCHAR bTransferCharacteristics; + UCHAR bMatrixCoefficients; +} VIDEO_COLORFORMAT, *PVIDEO_COLORFORMAT; + +#define SIZEOF_VIDEO_COLORFORMAT(pDesc) sizeof(VIDEO_COLORFORMAT) + + +// VideoStreaming Uncompressed Format Descriptor +typedef struct _VIDEO_FORMAT_UNCOMPRESSED +{ + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bFormatIndex; + UCHAR bNumFrameDescriptors; + GUID guidFormat; + UCHAR bBitsPerPixel; + UCHAR bDefaultFrameIndex; + UCHAR bAspectRatioX; + UCHAR bAspectRatioY; + UCHAR bmInterlaceFlags; + UCHAR bCopyProtect; +} VIDEO_FORMAT_UNCOMPRESSED, *PVIDEO_FORMAT_UNCOMPRESSED; + +#define SIZEOF_VIDEO_FORMAT_UNCOMPRESSED(pDesc) sizeof(VIDEO_FORMAT_UNCOMPRESSED) + + +// VideoStreaming Uncompressed Frame Descriptor +typedef struct _VIDEO_FRAME_UNCOMPRESSED +{ + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bFrameIndex; + UCHAR bmCapabilities; + USHORT wWidth; + USHORT wHeight; + ULONG dwMinBitRate; + ULONG dwMaxBitRate; + ULONG dwMaxVideoFrameBufferSize; + ULONG dwDefaultFrameInterval; + UCHAR bFrameIntervalType; + ULONG adwFrameInterval[]; +} VIDEO_FRAME_UNCOMPRESSED, *PVIDEO_FRAME_UNCOMPRESSED; + + +__inline size_t SizeOfVideoFrameUncompressed(_In_ PVIDEO_FRAME_UNCOMPRESSED pDesc) +{ + if (pDesc->bFrameIntervalType == 0) { // Continuous + return sizeof(VIDEO_FRAME_UNCOMPRESSED) + (3 * sizeof(ULONG)); + } + else { // Discrete + return sizeof(VIDEO_FRAME_UNCOMPRESSED) + (pDesc->bFrameIntervalType * sizeof(ULONG)); + } +} + +#define SIZEOF_VIDEO_FRAME_UNCOMPRESSED(pDesc) SizeOfVideoFrameUncompressed(pDesc) + + +// VideoStreaming MJPEG Format Descriptor +typedef struct _VIDEO_FORMAT_MJPEG +{ + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bFormatIndex; + UCHAR bNumFrameDescriptors; + UCHAR bmFlags; + UCHAR bDefaultFrameIndex; + UCHAR bAspectRatioX; + UCHAR bAspectRatioY; + UCHAR bmInterlaceFlags; + UCHAR bCopyProtect; +} VIDEO_FORMAT_MJPEG, *PVIDEO_FORMAT_MJPEG; + +#define SIZEOF_VIDEO_FORMAT_MJPEG(pDesc) sizeof(VIDEO_FORMAT_MJPEG) + + +// VideoStreaming MJPEG Frame Descriptor +typedef struct _VIDEO_FRAME_MJPEG +{ + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bFrameIndex; + UCHAR bmCapabilities; + USHORT wWidth; + USHORT wHeight; + ULONG dwMinBitRate; + ULONG dwMaxBitRate; + ULONG dwMaxVideoFrameBufferSize; + ULONG dwDefaultFrameInterval; + UCHAR bFrameIntervalType; + ULONG adwFrameInterval[]; +} VIDEO_FRAME_MJPEG, *PVIDEO_FRAME_MJPEG; + + +__inline size_t SizeOfVideoFrameMjpeg(_In_ PVIDEO_FRAME_MJPEG pDesc) +{ + if (pDesc->bFrameIntervalType == 0) { // Continuous + return sizeof(VIDEO_FRAME_MJPEG) + (3 * sizeof(ULONG)); + } + else { // Discrete + return sizeof(VIDEO_FRAME_MJPEG) + (pDesc->bFrameIntervalType * sizeof(ULONG)); + } +} + +#define SIZEOF_VIDEO_FRAME_MJPEG(pDesc) SizeOfVideoFrameMjpeg(pDesc) + + +// VideoStreaming Vendor Format Descriptor +typedef struct _VIDEO_FORMAT_VENDOR +{ + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bFormatIndex; + UCHAR bNumFrameDescriptors; + GUID guidMajorFormat; + GUID guidSubFormat; + GUID guidSpecifier; + UCHAR bPayloadClass; + UCHAR bDefaultFrameIndex; + UCHAR bCopyProtect; +} VIDEO_FORMAT_VENDOR, *PVIDEO_FORMAT_VENDOR; + +#define SIZEOF_VIDEO_FORMAT_VENDOR(pDesc) sizeof(VIDEO_FORMAT_VENDOR) + + +// VideoStreaming Vendor Frame Descriptor +typedef struct _VIDEO_FRAME_VENDOR +{ + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bFrameIndex; + UCHAR bmCapabilities; + USHORT wWidth; + USHORT wHeight; + ULONG dwMinBitRate; + ULONG dwMaxBitRate; + ULONG dwMaxVideoFrameBufferSize; + ULONG dwDefaultFrameInterval; + UCHAR bFrameIntervalType; + DWORD adwFrameInterval[]; +} VIDEO_FRAME_VENDOR, *PVIDEO_FRAME_VENDOR; + +__inline size_t SizeOfVideoFrameVendor(_In_ PVIDEO_FRAME_VENDOR pDesc) +{ + if (pDesc->bFrameIntervalType == 0) { // Continuous + return sizeof(VIDEO_FRAME_VENDOR) + (3 * sizeof(ULONG)); + } + else { // Discrete + return sizeof(VIDEO_FRAME_VENDOR) + (pDesc->bFrameIntervalType * sizeof(ULONG)); + } +} + +#define SIZEOF_VIDEO_FRAME_VENDOR(pDesc) SizeOfVideoFrameVendor(pDesc) + + +// VideoStreaming DV Format Descriptor +typedef struct _VIDEO_FORMAT_DV +{ + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bFormatIndex; + ULONG dwMaxVideoFrameBufferSize; + UCHAR bFormatType; +} VIDEO_FORMAT_DV, *PVIDEO_FORMAT_DV; + +#define SIZEOF_VIDEO_FORMAT_DV(pDesc) sizeof(VIDEO_FORMAT_DV) + + +// VideoStreaming MPEG2-TS Format Descriptor +typedef struct _VIDEO_FORMAT_MPEG2TS +{ + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bFormatIndex; + UCHAR bDataOffset; + UCHAR bPacketLength; + UCHAR bStrideLength; +} VIDEO_FORMAT_MPEG2TS, *PVIDEO_FORMAT_MPEG2TS; + +#define SIZEOF_VIDEO_FORMAT_MPEG2TS(pDesc) sizeof(VIDEO_FORMAT_MPEG2TS) + + +// VideoStreaming MPEG1 System Stream Format Descriptor +typedef struct _VIDEO_FORMAT_MPEG1SS +{ + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bFormatIndex; + UCHAR bPacketLength; + UCHAR bPackLength; + UCHAR bPackDataType; +} VIDEO_FORMAT_MPEG1SS, *PVIDEO_FORMAT_MPEG1SS; + +#define SIZEOF_VIDEO_FORMAT_MPEG1SS(pDesc) sizeof(VIDEO_FORMAT_MPEG1SS) + + +// VideoStreaming MPEG2-PS Format Descriptor +typedef struct _VIDEO_FORMAT_MPEG2PS +{ + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bFormatIndex; + UCHAR bPacketLength; + UCHAR bPackLength; + UCHAR bPackDataType; +} VIDEO_FORMAT_MPEG2PS, *PVIDEO_FORMAT_MPEG2PS; + +#define SIZEOF_VIDEO_FORMAT_MPEG2PS(pDesc) sizeof(VIDEO_FORMAT_MPEG2PS) + + +// VideoStreaming MPEG4-SL Format Descriptor +typedef struct _VIDEO_FORMAT_MPEG4SL +{ + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bFormatIndex; + UCHAR bPacketLength; +} VIDEO_FORMAT_MPEG4SL, *PVIDEO_FORMAT_MPEG4SL; + +#define SIZEOF_VIDEO_FORMAT_MPEG4SL(pDesc) sizeof(VIDEO_FORMAT_MPEG4SL) + +// VideoStreaming Probe/Commit Control +typedef struct _VS_PROBE_COMMIT_CONTROL +{ + USHORT bmHint; + UCHAR bFormatIndex; + UCHAR bFrameIndex; + ULONG dwFrameInterval; + USHORT wKeyFrameRate; + USHORT wPFrameRate; + USHORT wCompQuality; + USHORT wCompWindowSize; + USHORT wDelay; + ULONG dwMaxVideoFrameSize; + ULONG dwMaxPayloadTransferSize; +} VS_PROBE_COMMIT_CONTROL, *PVS_PROBE_COMMIT_CONTROL; + +// VideoStreaming Still Probe/Commit Control +typedef struct _VS_STILL_PROBE_COMMIT_CONTROL +{ + UCHAR bFormatIndex; + UCHAR bFrameIndex; + UCHAR bCompressionIndex; + ULONG dwMaxVideoFrameSize; + ULONG dwMaxPayloadTransferSize; +} VS_STILL_PROBE_COMMIT_CONTROL, *PVS_STILL_PROBE_COMMIT_CONTROL; + + +// Status Interrupt Packet (Video Control) +typedef struct _VC_INTERRUPT_PACKET +{ + UCHAR bStatusType; + UCHAR bOriginator; + UCHAR bEvent; + UCHAR bSelector; + UCHAR bAttribute; + UCHAR bValue[1]; +} VC_INTERRUPT_PACKET, *PVC_INTERRUPT_PACKET; + +// Status Interrupt Packet (Video Control) +typedef struct _VC_INTERRUPT_PACKET_EX +{ + UCHAR bStatusType; + UCHAR bOriginator; + UCHAR bEvent; + UCHAR bSelector; + UCHAR bAttribute; + UCHAR bValue[MAX_INTERRUPT_PACKET_VALUE_SIZE]; +} VC_INTERRUPT_PACKET_EX, *PVC_INTERRUPT_PACKET_EX; + +// Status Interrupt Packet (Video Streaming) +typedef struct _VS_INTERRUPT_PACKET +{ + UCHAR bStatusType; + UCHAR bOriginator; + UCHAR bEvent; + UCHAR bValue[1]; +} VS_INTERRUPT_PACKET, *PVS_INTERRUPT_PACKET; + +// Status Interrupt Packet (Generic) +typedef struct _VIDEO_INTERRUPT_PACKET +{ + UCHAR bStatusType; + UCHAR bOriginator; +} VIDEO_INTERRUPT_PACKET, *PVIDEO_INTERRUPT_PACKET; + + +// Relative property struct +typedef struct _VIDEO_RELATIVE_PROPERTY +{ + UCHAR bValue; + UCHAR bSpeed; +} VIDEO_RELATIVE_PROPERTY, *PVIDEO_RELATIVE_PROPERTY; + +// Relative Zoom control struct +typedef struct _ZOOM_RELATIVE_PROPERTY +{ + UCHAR bZoom; + UCHAR bDigitalZoom; + UCHAR bSpeed; +} ZOOM_RELATIVE_PROPERTY, *PZOOM_RELATIVE_PROPERTY; + +// Relative pan-tilt struct +typedef struct _PANTILT_RELATIVE_PROPERTY +{ + UCHAR bPanRelative; + UCHAR bPanSpeed; + UCHAR bTiltRelative; + UCHAR bTiltSpeed; +} PANTILT_RELATIVE_PROPERTY, *PPANTILT_RELATIVE_PROPERTY; + +typedef struct _MEDIA_INFORMATION_CONTROL +{ + UCHAR bmMediaType; + UCHAR bmWriteProtect; +} MEDIA_INFORMATION_CONTROL, *PMEDIA_INFORMATION_CONTROL; + +typedef struct _TIME_CODE_INFORMATION_CONTROL +{ + UCHAR bcdFrame; + UCHAR bcdSecond; + UCHAR bcdMinute; + UCHAR bcdHour; +} TIME_CODE_INFORMATION_CONTROL, *PTIME_CODE_INFORMATION_CONTROL; + +typedef struct _ATN_INFORMATION_CONTROL +{ + UCHAR bmMediaType; + DWORD dwATN_Data; +} ATN_INFORMATION_CONTROL, *PATN_INFORMATION_CONTROL; + +#define VS_FORMAT_FRAME_BASED 0x10 +#define VS_FRAME_FRAME_BASED 0x11 +#define VS_FORMAT_STREAM_BASED 0x12 + +// Format Descriptor for UVC 1.1 frame based format +typedef struct _VIDEO_FORMAT_FRAME +{ + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bFormatIndex; + UCHAR bNumFrameDescriptors; + GUID guidFormat; + UCHAR bBitsPerPixel; + UCHAR bDefaultFrameIndex; + UCHAR bAspectRatioX; + UCHAR bAspectRatioY; + UCHAR bmInterlaceFlags; + UCHAR bCopyProtect; + UCHAR bVariableSize; +} VIDEO_FORMAT_FRAME, *PVIDEO_FORMAT_FRAME; + +#define SIZEOF_VIDEO_FORMAT_FRAME(pDesc) sizeof(VIDEO_FORMAT_FRAME) + + +// Frame Descriptor for UVC 1.1 frame based format +typedef struct _VIDEO_FRAME_FRAME +{ + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bFrameIndex; + UCHAR bmCapabilities; + USHORT wWidth; + USHORT wHeight; + ULONG dwMinBitRate; + ULONG dwMaxBitRate; + ULONG dwDefaultFrameInterval; + UCHAR bFrameIntervalType; + ULONG dwBytesPerLine; + ULONG adwFrameInterval[]; +} VIDEO_FRAME_FRAME, *PVIDEO_FRAME_FRAME; + +__inline size_t SizeOfVideoFrameFrame(_In_ PVIDEO_FRAME_FRAME pDesc) +{ + if (pDesc->bFrameIntervalType == 0) { // Continuous + return sizeof(VIDEO_FRAME_FRAME) + (3 * sizeof(ULONG)); + } + else { // Discrete + return sizeof(VIDEO_FRAME_FRAME) + (pDesc->bFrameIntervalType * sizeof(ULONG)); + } +} + +#define SIZEOF_VIDEO_FRAME_FRAME(pDesc) SizeOfVideoFrameFrame(pDesc) + +// VideoStreaming Stream Based Format Descriptor +typedef struct _VIDEO_FORMAT_STREAM +{ + UCHAR bLength; + UCHAR bDescriptorType; + UCHAR bDescriptorSubtype; + UCHAR bFormatIndex; + GUID guidFormat; + ULONG dwPacketLength; +} VIDEO_FORMAT_STREAM, *PVIDEO_FORMAT_STREAM; + +#define SIZEOF_VIDEO_FORMAT_STREAM(pDesc) sizeof(VIDEO_FORMAT_STREAM) + +// VideoStreaming Probe/Commit Control +typedef struct _VS_PROBE_COMMIT_CONTROL2 +{ + USHORT bmHint; + UCHAR bFormatIndex; + UCHAR bFrameIndex; + ULONG dwFrameInterval; + USHORT wKeyFrameRate; + USHORT wPFrameRate; + USHORT wCompQuality; + USHORT wCompWindowSize; + USHORT wDelay; + ULONG dwMaxVideoFrameSize; + ULONG dwMaxPayloadTransferSize; + ULONG dwClockFrequency; + UCHAR bmFramingInfo; + UCHAR bPreferredVersion; + UCHAR bMinVersion; + UCHAR bMaxVersion; +} VS_PROBE_COMMIT_CONTROL2, *PVS_PROBE_COMMIT_CONTROL2; + +#pragma pack( pop, vdc_descriptor_structs ) +#pragma warning( default : 4200 ) + + +// +// END - VDC Descriptor and Control Structures +// + +#endif // ___UVCDESC_H___ diff --git a/device/win_usb/win_usb.cpp b/device/win_usb/win_usb.cpp new file mode 100644 index 0000000..e872ed4 --- /dev/null +++ b/device/win_usb/win_usb.cpp @@ -0,0 +1,1268 @@ +#include "win_usb.h" + +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include + +#pragma comment(lib, "setupapi.lib") +#pragma comment(lib, "hid.lib") +#pragma comment(lib, "winusb.lib") +#pragma comment(lib, "rpcrt4.lib") + +#include "hginclude/hg_log.h" +#include "scanner_manager.h" // for hg_scanner_mgr::ui_default_callback +#include "usbview/enum.h" + +#define MSG_DEVICE_PNP WM_USER + 1 // wParam: (bool)arrive; lParam: usb_device* +#define bzero(a, l) memset(a, 0, l) + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// usb_callback ... +usb_callback::usb_callback(libusb_hotplug_callback_fn cb + , void* param) + : usb_cb_(cb), usb_cb_param_(param) +{} +usb_callback::~usb_callback() +{} + +void usb_callback::notify(libusb_context* ctx, usb_device* dev, int ev) +{ + usb_cb_(ctx, (libusb_device*)dev, (libusb_hotplug_event)ev, usb_cb_param_); +} +std::string u2utf8(const wchar_t* u) +{ + //* + return hg_log::u2utf8(u); + /*/ + int len = WideCharToMultiByte(CP_UTF8, 0, u, lstrlenW(u), NULL, 0, NULL, NULL); + char *ansi = new char[len + 4]; + + len = WideCharToMultiByte(CP_UTF8, 0, u, lstrlenW(u), ansi, len, NULL, NULL); + ansi[len--] = 0; + + std::string utf8(ansi); + delete[] ansi; + + return utf8; + /////*/////////////////////// +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// 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) +{ + bzero(&guid_, sizeof(guid_)); + id_ = usb_device::vid_pid_from_name(name); +} +usb_device::~usb_device() +{ + clear(); +} + +HANDLE usb_device::find_pipe(UCHAR addr, int type) +{ + for (size_t i = 0; i < pipes_.size(); ++i) + { + if (pipes_[i].address == addr && pipes_[i].type == type) + return pipes_[i].pipe; + } + + return NULL; +} +int usb_device::set_timeout(HANDLE h) +{ + USBSCAN_TIMEOUT uto = { 0 }; + DWORD cbr = 0; + + uto.TimeoutEvent = uto.TimeoutRead = uto.TimeoutWrite = (timout_ms_ + 500) / 1000; + + return DeviceIoControl(h, IOCTL_SET_TIMEOUT, &uto, sizeof(uto), NULL, 0, &cbr, NULL) ? LIBUSB_SUCCESS : LIBUSB_ERROR_IO; +} + +DEVID usb_device::vid_pid_from_name(const char* name) +{ + // name: \\?\usb#vid_3072&pid_0239#01234567aabbccddee#{a5dcbf10-6530-11d2-901f-00c04fb951ed} + DEVID id = { 0 }; + 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); + + pos = s.find("pid_"); + if (pos != std::string::npos) + id.pid = usb_device::from_hex_string(s.c_str() + pos + 4); + + return id; +} +DWORD usb_device::from_hex_string(const char* hex_str) +{ + DWORD v = 0; + + for (int i = 0; hex_str[i]; ++i) + { + DWORD now = 0; + if (hex_str[i] >= '0' && hex_str[i] <= '9') + now = hex_str[i] - '0'; + else if (hex_str[i] >= 'a' && hex_str[i] <= 'f') + now = hex_str[i] - 'a' + 10; + else if (hex_str[i] >= 'A' && hex_str[i] <= 'F') + now = hex_str[i] - 'A' + 10; + else + break; + + v <<= 4; + v += now; + } + + return v; +} +std::string usb_device::driver_key_name(HANDLE file) +{ + 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(""); + + 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); + } + + return ret; +} +std::string usb_device::parent_hub_path_name(int vid, int pid, int *addr) +{ + 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)) + ret = n; + } + delete[] buf; + if (ret.length()) + break; + } + } + SetupDiDestroyDeviceInfoList(dev); + } + if (addr) + *addr = port; + HG_VLOG_MINI_4(HG_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) +{ + 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; + } + 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; +} + +long usb_device::add_ref(void) +{ + return InterlockedIncrement(&ref_); +} +long usb_device::release(void) +{ + long ref = InterlockedDecrement(&ref_); + + if (ref == 0) + delete this; + + 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; + + return *this; +} + +std::string usb_device::name(void) +{ + return name_; +} +GUID usb_device::guid(void) +{ + return guid_; +} +DEVID usb_device::id(void) +{ + return id_; +} +bool usb_device::is_ok(void) +{ + return is_ok_; +} +bool usb_device::is_open(void) +{ + return handle_ != NULL; +} +bool usb_device::is_online(void) +{ + return online_; +} +void usb_device::set_online(bool online) +{ + online_ = online; +} +uint8_t usb_device::port(void) +{ + if (!dev_desc_) + init(); + return port_; +} + +bool usb_device::init(void) +{ + PUSBDEVICEINFO info = NULL; + GUID guid; + int addr = -1; + + clear(); + for (size_t i = 0; i < _countof(ovl_); ++i) + ovl_[i].hEvent = CreateEventA(NULL, TRUE, FALSE, NULL); + + UuidFromStringA((RPC_CSTR)HG_SCANNER_GUID, &guid); + addr = usb_device::get_device_address(name_.c_str(), &guid); + //if (addr != -1) + { + std::string path(usb_device::parent_hub_path_name(id_.vid, id_.pid, &addr)); + if (!path.empty()) + { + 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); + } + } + } + +#define COPY_MEMBER(d, s, m) \ + (d)->m = (s)->m + + if (info) + { + port_ = addr; + if (info->ConnectionInfo) + { + dev_desc_ = new libusb_device_descriptor; + COPY_MEMBER(dev_desc_, &info->ConnectionInfo->DeviceDescriptor, bLength); + COPY_MEMBER(dev_desc_, &info->ConnectionInfo->DeviceDescriptor, bDescriptorType); + COPY_MEMBER(dev_desc_, &info->ConnectionInfo->DeviceDescriptor, bcdUSB); + COPY_MEMBER(dev_desc_, &info->ConnectionInfo->DeviceDescriptor, bDeviceClass); + COPY_MEMBER(dev_desc_, &info->ConnectionInfo->DeviceDescriptor, bDeviceSubClass); + COPY_MEMBER(dev_desc_, &info->ConnectionInfo->DeviceDescriptor, bDeviceProtocol); + COPY_MEMBER(dev_desc_, &info->ConnectionInfo->DeviceDescriptor, bMaxPacketSize0); + COPY_MEMBER(dev_desc_, &info->ConnectionInfo->DeviceDescriptor, idVendor); + COPY_MEMBER(dev_desc_, &info->ConnectionInfo->DeviceDescriptor, idProduct); + COPY_MEMBER(dev_desc_, &info->ConnectionInfo->DeviceDescriptor, bcdDevice); + COPY_MEMBER(dev_desc_, &info->ConnectionInfo->DeviceDescriptor, iManufacturer); + COPY_MEMBER(dev_desc_, &info->ConnectionInfo->DeviceDescriptor, iProduct); + COPY_MEMBER(dev_desc_, &info->ConnectionInfo->DeviceDescriptor, iSerialNumber); + COPY_MEMBER(dev_desc_, &info->ConnectionInfo->DeviceDescriptor, bNumConfigurations); + } + if (info->ConfigDesc) + { + libusb_config_descriptor* desc = NULL; + PUSB_COMMON_DESCRIPTOR cmn = (PUSB_COMMON_DESCRIPTOR)(info->ConfigDesc + 1); + int if_ind = 0, ep_ind = 0; + + while (cmn->bLength) + { + if (USB_CONFIGURATION_DESCRIPTOR_TYPE == cmn->bDescriptorType) + { + PUSB_CONFIGURATION_DESCRIPTOR conf = (PUSB_CONFIGURATION_DESCRIPTOR)cmn; + if (desc) + cfg_desc_.push_back(desc); + + desc = new libusb_config_descriptor; + memset(desc, 0, sizeof(*desc)); + COPY_MEMBER(desc, conf, bLength); + COPY_MEMBER(desc, conf, bDescriptorType); + COPY_MEMBER(desc, conf, wTotalLength); + COPY_MEMBER(desc, conf, bNumInterfaces); + COPY_MEMBER(desc, conf, bConfigurationValue); + COPY_MEMBER(desc, conf, iConfiguration); + COPY_MEMBER(desc, conf, bmAttributes); + COPY_MEMBER(desc, conf, MaxPower); + desc->usb_if = new libusb_interface[desc->bNumInterfaces]; + memset(desc->usb_if, 0, desc->bNumInterfaces * sizeof(desc->usb_if[0])); + ep_ind = if_ind = 0; + } + else if (USB_INTERFACE_DESCRIPTOR_TYPE == cmn->bDescriptorType) + { + PUSB_INTERFACE_DESCRIPTOR ifd = (PUSB_INTERFACE_DESCRIPTOR)cmn; + libusb_interface_descriptor* uid = NULL; + + desc->usb_if[if_ind].num_altsetting = 1; + desc->usb_if[if_ind].altsetting = uid = new libusb_interface_descriptor; + COPY_MEMBER(uid, ifd, bLength); + COPY_MEMBER(uid, ifd, bDescriptorType); + COPY_MEMBER(uid, ifd, bInterfaceNumber); + COPY_MEMBER(uid, ifd, bAlternateSetting); + COPY_MEMBER(uid, ifd, bNumEndpoints); + COPY_MEMBER(uid, ifd, bInterfaceClass); + COPY_MEMBER(uid, ifd, bInterfaceSubClass); + COPY_MEMBER(uid, ifd, bInterfaceProtocol); + COPY_MEMBER(uid, ifd, iInterface); + uid->endpoint = new libusb_endpoint_descriptor[desc->usb_if[if_ind].altsetting->bNumEndpoints]; + if_ind++; + ep_ind = 0; + } + else if (USB_ENDPOINT_DESCRIPTOR_TYPE == cmn->bDescriptorType) + { + PUSB_ENDPOINT_DESCRIPTOR endp = (PUSB_ENDPOINT_DESCRIPTOR)cmn; + libusb_endpoint_descriptor* uep = (libusb_endpoint_descriptor*)((void*)&desc->usb_if[if_ind - 1].altsetting->endpoint[ep_ind]); + + COPY_MEMBER(uep, endp, bLength); + COPY_MEMBER(uep, endp, bDescriptorType); + COPY_MEMBER(uep, endp, bEndpointAddress); + COPY_MEMBER(uep, endp, bmAttributes); + COPY_MEMBER(uep, endp, wMaxPacketSize); + COPY_MEMBER(uep, endp, bInterval); + uep->extra = NULL; + ep_ind++; + } + cmn = (PUSB_COMMON_DESCRIPTOR)((PCHAR)cmn + cmn->bLength); + } + + if (desc) + cfg_desc_.push_back(desc); + + is_ok_ = !cfg_desc_.empty(); + } + + free_usb_device_info(info); + } + + return is_ok_; +} +void usb_device::clear(void) +{ + close(); + for (size_t i = 0; i < _countof(ovl_); ++i) + CloseHandle(ovl_[i].hEvent); + + + if (dev_desc_) + delete dev_desc_; + dev_desc_ = NULL; + + for (size_t i = 0; i < cfg_desc_.size(); ++i) + { + if (cfg_desc_[i]->usb_if) + { + for (size_t j = 0; j < cfg_desc_[i]->bNumInterfaces; ++j) + { + if (cfg_desc_[i]->usb_if[j].altsetting->endpoint) + delete[] cfg_desc_[i]->usb_if[j].altsetting->endpoint; + } + delete[] cfg_desc_[i]->usb_if; + } + delete cfg_desc_[i]; + } + 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_) + memcpy(desc, dev_desc_, sizeof(*desc)); + else + { + char cls[128] = { 0 }; + + SetupDiGetClassDescriptionA(&guid_, cls, _countof(cls) - 1, NULL); + std::transform(cls, cls + lstrlenA(cls), cls, tolower); + if (strcmp(cls, "usb") == 0) + desc->bDeviceClass = libusb_class_code::LIBUSB_CLASS_HUB; + else if (strcmp(cls, "image") == 0) + desc->bDeviceClass = libusb_class_code::LIBUSB_CLASS_IMAGE; + else if (strcmp(cls, "hidclass") == 0) + 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->bcdUSB = 0x200; // USB2.0 ? + desc->bcdDevice = 0; // ? + desc->bDescriptorType = libusb_descriptor_type::LIBUSB_DT_DEVICE; + desc->bDeviceProtocol = 0; + desc->bDeviceSubClass = libusb_class_code::LIBUSB_CLASS_IMAGE; + desc->bLength = sizeof(*desc); + desc->bMaxPacketSize0 = 512; + desc->bNumConfigurations = 1; // ? + desc->iManufacturer = 0; + desc->iSerialNumber = 0; + desc->iProduct = 0; + } + + return LIBUSB_SUCCESS; +} +int usb_device::get_config_descriptor(int index, libusb_config_descriptor** desc) +{ + if (index >= 0 && index < cfg_desc_.size()) + *desc = cfg_desc_[index]; + else + return LIBUSB_ERROR_INVALID_PARAM; + + return LIBUSB_SUCCESS; +} +int usb_device::open(libusb_device_handle** dev_handle) +{ + if (handle_) + return LIBUSB_ERROR_BUSY; + + if (!dev_desc_) + init(); + HANDLE h = CreateFileA(name_.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); + if (h == INVALID_HANDLE_VALUE) + { + *dev_handle = NULL; + + return online_ ? LIBUSB_ERROR_IO : LIBUSB_ERROR_NO_DEVICE; + } + + USBSCAN_PIPE_CONFIGURATION upc = { 0 }; + DWORD cbr = 0; + if (DeviceIoControl(h, IOCTL_GET_PIPE_CONFIGURATION, NULL, 0, &upc, sizeof(upc), &cbr, NULL)) + { + for (int i = 0; i < upc.NumberOfPipes; ++i) + { + USBPIPE up = { 0 }; + char ind[20] = { 0 }; + up.address = upc.PipeInfo[i].EndpointAddress; + up.type = upc.PipeInfo[i].PipeType; + sprintf_s(ind, _countof(ind) - 1, "\\%04d", i); + up.pipe = CreateFileA((name_ + ind).c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); + if (up.pipe != INVALID_HANDLE_VALUE) + { + set_timeout(up.pipe); + pipes_.push_back(up); + } + } + } + set_timeout(h); + handle_ = (libusb_device_handle*)h; + *dev_handle = (libusb_device_handle*)this; + + return LIBUSB_SUCCESS; +} +int usb_device::close(void) +{ + for (size_t i = 0; i < pipes_.size(); ++i) + { + CancelIo(pipes_[i].pipe); + CloseHandle(pipes_[i].pipe); + } + pipes_.clear(); + + if (handle_) + { + OVERLAPPED ovl = { 0 }; + PIPE_TYPE type = ALL_PIPE; + DWORD cbr = 0; + + ovl.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL); + DeviceIoControl(handle_, IOCTL_CANCEL_IO, &type, sizeof(type), NULL, 0, &cbr, &ovl); + WaitForSingleObject(ovl.hEvent, 1000); + CloseHandle(ovl.hEvent); + + CancelIo(handle_); + CloseHandle((HANDLE)handle_); + handle_ = NULL; + } + + return LIBUSB_SUCCESS; +} +int usb_device::set_timeout(unsigned milliseconds) +{ + timout_ms_ = milliseconds; + for (size_t i = 0; i < pipes_.size(); ++i) + { + set_timeout(pipes_[i].pipe); + } + if (handle_) + set_timeout(handle_); + + return LIBUSB_SUCCESS; +} +int usb_device::transfer_bulk(unsigned endpoint, unsigned char* data, int* length, unsigned int timeout) +{ + typedef BOOL(WINAPI* file_io)(HANDLE, LPVOID, DWORD, LPDWORD, LPOVERLAPPED); + int ret = LIBUSB_ERROR_PIPE; + HANDLE h = find_pipe(endpoint, USBSCAN_PIPE_BULK); + file_io fio = (endpoint & BULKIN_FLAG) ? ReadFile : (file_io)WriteFile; + LPOVERLAPPED ovl = (endpoint & BULKIN_FLAG) ? &ovl_[OVL_BULK_IN] : &ovl_[OVL_BULK_OUT]; + + if (h) + { + DWORD io = 0; + BOOL result = FALSE; + HANDLE he = ovl->hEvent; + + memset(ovl, 0, sizeof(*ovl)); + ovl->hEvent = he; + result = fio(h, data, *length, &io, ovl); + if (result) + { + FlushFileBuffers(h); + *length = io; + ret = LIBUSB_SUCCESS; + } + else + { + io = GetLastError(); + if (io == ERROR_IO_PENDING) + { + WaitForSingleObject(he, 500); + GetOverlappedResult(h, &ovl_[OVL_BULK_IN], &io, FALSE); + *length = io; + ret = LIBUSB_SUCCESS; + } + } + } + + return ret; +} +int usb_device::transfer_control(uint8_t type, uint8_t req, uint16_t val, uint16_t ind, unsigned char* data, uint16_t len, unsigned timeout) +{ + int ret = LIBUSB_ERROR_PIPE; + _IO_BLOCK_EX irp; + + if ((HANDLE)handle_ != INVALID_HANDLE_VALUE) + { + DWORD io = 0; + LPOVERLAPPED ovl = ovl_ + OVL_CONTROL; + + ResetEvent(ovl->hEvent); + irp.bmRequestType = (type >> 5) & 0x03; + irp.bRequest = req; + irp.fTransferDirectionIn = type >> 7; + irp.pbyData = data; + irp.uIndex = ind; + irp.uLength = len; + irp.uOffset = val; + if (DeviceIoControl((HANDLE)handle_, IOCTL_SEND_USB_REQUEST, &irp, sizeof(irp), data, len, &io, ovl)) + ret = LIBUSB_SUCCESS; + else if (GetLastError() == ERROR_IO_PENDING) + { + ret = WaitForSingleObject(ovl->hEvent, timeout) == WAIT_TIMEOUT ? LIBUSB_ERROR_TIMEOUT : LIBUSB_SUCCESS; + } + } + + return ret; +} +int usb_device::transfer_interrupt(unsigned endpoint, unsigned char* data, int* length, unsigned int timeout) +{ + int ret = LIBUSB_ERROR_PIPE; + HANDLE h = find_pipe(endpoint, USBSCAN_PIPE_INTERRUPT); + DWORD io = 0; + + if (h) + { + if (DeviceIoControl(h, IOCTL_WAIT_ON_DEVICE_EVENT, NULL, 0, data, *length, &io, &ovl_[OVL_INTERRUPT])) + { + ret = LIBUSB_SUCCESS; + *length = io; + } + else + { + io = GetLastError(); + if (io == ERROR_IO_PENDING) + { + GetOverlappedResult(h, &ovl_[OVL_INTERRUPT], &io, TRUE); + ret = LIBUSB_SUCCESS; + *length = io; + } + } + } + + return ret; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// usb_monitor ... + +usb_monitor* usb_monitor::usb_monitor_ = NULL; + +usb_monitor::usb_monitor() : wnd_monitor_(NULL), handle_msg_id_(0), run_(true) +{ + handle_msg_.reset(new std::thread(&usb_monitor::thread_handle_device_change_msg, this)); +} +usb_monitor::~usb_monitor() +{ + quit(); +} + +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); + + if (msg == WM_CREATE) + { + LPCREATESTRUCTW data = (LPCREATESTRUCTW)lp; + + SetPropW(hwnd, MONITOR_WINDOW_OWNER, (HANDLE)data->lpCreateParams); + + return 0; + } + else if (!monitor || msg != WM_DEVICECHANGE) + return DefWindowProcW(hwnd, msg, wp, lp); + + return monitor->on_usb_pnp(wp, lp); +} +void usb_monitor::register_monitor_wnd(const wchar_t* cls) +{ + WNDCLASSW wc = { 0 }; + + wc.lpfnWndProc = &usb_monitor::monitor_wnd_proc; + wc.lpszClassName = cls; + wc.hInstance = GetModuleHandleW(NULL); + + RegisterClassW(&wc); +} + +void usb_monitor::notify_usb_event(usb_device*& dev, bool arrive) +{ + std::lock_guard lock(lock_); + int ev = arrive ? LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED : LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT; + DEVID id = dev->id(); + + if (arrive) + { + bool found = false; + for(size_t i = 0; i < devices_.size(); ++i) + { + if (!(devices_[i]->id() == id)) + continue; + + if (!devices_[i]->is_online() && devices_[i]->is_open()) + { + dev->release(); + dev = devices_[i]; + dev->add_ref(); + dev->set_online(true); + found = true; + break; + } + } + if (!found) + { + devices_.push_back(dev); + dev->add_ref(); + } + } + else + { + 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()) + { + dev->set_online(false); + } + else + { + devices_.erase(devices_.begin() + i); + dev->release(); + } + break; + } + } + + for (size_t i = 0; i < cbs_.size(); ++i) + cbs_[i]->notify((libusb_context*)this, dev, ev); +} +int usb_monitor::on_usb_pnp(WPARAM wp, LPARAM lp) +{ + int ret = 0; + DEV_BROADCAST_HDR* dbt = (DEV_BROADCAST_HDR*)lp; + + if (!dbt || dbt->dbch_devicetype != DBT_DEVTYP_DEVICEINTERFACE) + return wp == DBT_DEVICEQUERYREMOVE; + + PDEV_BROADCAST_DEVICEINTERFACE_W dev = (PDEV_BROADCAST_DEVICEINTERFACE_W)lp; + if (dev->dbcc_classguid == GUID_DEVINTERFACE_USB_DEVICE) + { + return wp == DBT_DEVICEQUERYREMOVE; + } + + if (wp == DBT_DEVICEQUERYREMOVE) + return cur_dev_name_ != u2utf8(dev->dbcc_name); + + usb_device* ud = new usb_device(u2utf8(dev->dbcc_name).c_str()); + *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& 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); +} + +usb_callback* usb_monitor::reg_callback(libusb_hotplug_callback_fn cb, void* param) +{ + usb_callback* obj = new usb_callback(cb, param); + + { + std::lock_guard lock(lock_); + cbs_.push_back(obj); + } + + return obj; +} +void usb_monitor::unreg_callback(usb_callback* cb) +{ + std::lock_guard lock(lock_); + + for (int i = 0; i < cbs_.size(); ++i) + { + if (cbs_[i] == cb) + { + cbs_.erase(cbs_.begin() + i); + delete cb; + break; + } + } +} + +void usb_monitor::thread_run_device_event_wnd(void) +{ + MSG msg = { 0 }; + const wchar_t* cls = L"usb_pnp_wnd"; + + register_monitor_wnd(cls); + wnd_monitor_ = CreateWindowW(cls, L"usb", WS_POPUP, 0, 0, 0, 0, NULL, NULL, GetModuleHandleW(NULL), this); + if (!IsWindow(wnd_monitor_)) + { + // HG_VLOG_MINI_1(HG_LOG_LEVEL_FATAL, "create monitor window failed: %d\n", GetLastError()); + if(run_) + Sleep(1000); + + return; + } + + if (run_) + { + BOOL ret = TRUE; + DEV_BROADCAST_HDR dbh = { 0 }; + HDEVNOTIFY notify = NULL; + + std::vector first; + find_usb(first); + for (size_t i = 0; i < first.size(); ++i) + { + usb_device* dev = new usb_device(first[i].c_str()); + notify_usb_event(dev, true); + dev->release(); + } + + dbh.dbch_size = sizeof(dbh); + dbh.dbch_devicetype = DBT_DEVTYP_DEVICEINTERFACE; + notify = RegisterDeviceNotificationW(wnd_monitor_, &dbh, DEVICE_NOTIFY_WINDOW_HANDLE | DEVICE_NOTIFY_ALL_INTERFACE_CLASSES); + ret = GetLastError(); + // find_usb(); + while (run_ && (ret = GetMessageW(&msg, wnd_monitor_, 0, 0))) + { + if (ret == -1) + { + // HG_VLOG_MINI_1(HG_LOG_LEVEL_FATAL, "GetMessageW returned -1 with error: %d\n", GetLastError()); + break; + } + + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + UnregisterDeviceNotification(notify); + } + + DestroyWindow(wnd_monitor_); + UnregisterClassW(cls, GetModuleHandleW(NULL)); +} +void usb_monitor::thread_handle_device_change_msg(void) +{ + MSG msg = { 0 }; + BOOL ret = FALSE; + + handle_msg_id_ = GetCurrentThreadId(); + while ((ret = GetMessageW(&msg, NULL, 0, 0))) + { + if (ret == -1) + break; + + if (msg.message == MSG_DEVICE_PNP) + { + char buf[40] = { 0 }; + usb_device* dev = (usb_device*)msg.lParam; + //if(msg.wParam) + // dev->init(); + notify_usb_event(dev, msg.wParam); + + // dev->release ? + dev->release(); + } + else + { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + } +} +void usb_monitor::quit(void) +{ + run_ = false; + if (handle_msg_.get()) + { + PostThreadMessageW(handle_msg_id_, WM_QUIT, 0, 0); + if (handle_msg_->joinable()) + handle_msg_->join(); + handle_msg_.reset(); + } + + if (IsWindow(wnd_monitor_)) + { + PostMessage(wnd_monitor_, WM_QUIT, 0, 0); + } +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// libusb APIs ... +int LIBUSB_CALL libusb_init(libusb_context** ctx) +{ + if (ctx) + *ctx = (libusb_context*)new usb_monitor(); + else if(!usb_monitor::usb_monitor_) + usb_monitor::usb_monitor_ = new usb_monitor(); + + return LIBUSB_SUCCESS; +} +void LIBUSB_CALL libusb_exit(libusb_context* ctx) +{ + usb_monitor* usb = (usb_monitor*)ctx; + if (usb) + { + usb->quit(); + delete usb; + } +} +int LIBUSB_CALL libusb_hotplug_register_callback(libusb_context* ctx, + libusb_hotplug_event events, + libusb_hotplug_flag flags, + int vendor_id, int product_id, + int dev_class, + libusb_hotplug_callback_fn cb_fn, + void* user_data, + libusb_hotplug_callback_handle* callback_handle) +{ + if (ctx) + *callback_handle = (libusb_hotplug_callback_handle)((usb_monitor*)ctx)->reg_callback(cb_fn, user_data); + else if (usb_monitor::usb_monitor_) + *callback_handle = (libusb_hotplug_callback_handle)usb_monitor::usb_monitor_->reg_callback(cb_fn, user_data); + + return LIBUSB_SUCCESS; +} +void LIBUSB_CALL libusb_hotplug_deregister_callback(libusb_context* ctx, libusb_hotplug_callback_handle callback_handle) +{ + if (ctx) + ((usb_monitor*)ctx)->unreg_callback((usb_callback*)callback_handle); + else if (usb_monitor::usb_monitor_) + usb_monitor::usb_monitor_->unreg_callback((usb_callback*)callback_handle); +} +int LIBUSB_CALL libusb_handle_events_timeout(libusb_context* ctx, struct timeval* tv) +{ + // NOTE: for the caller is in a separate thread, this call will blocked while process exited, or libusb_exit called + ((usb_monitor*)ctx)->thread_run_device_event_wnd(); + + return LIBUSB_SUCCESS; +} +libusb_device* LIBUSB_CALL libusb_ref_device(libusb_device* dev) +{ + if (dev) + ((usb_device*)dev)->add_ref(); + + return dev; +} +void LIBUSB_CALL libusb_unref_device(libusb_device* dev) +{ + if (dev) + ((usb_device*)dev)->release(); +} +int LIBUSB_CALL libusb_get_device_descriptor(libusb_device* dev, struct libusb_device_descriptor* desc) +{ + if (!dev) + return LIBUSB_ERROR_INVALID_PARAM; + + return ((usb_device*)dev)->get_descriptor(desc); +} +int LIBUSB_CALL libusb_get_config_descriptor(libusb_device* dev, uint8_t config_index, struct libusb_config_descriptor** config) +{ + if (!dev) + return LIBUSB_ERROR_INVALID_PARAM; + + return ((usb_device*)dev)->get_config_descriptor(config_index, config); +} +void LIBUSB_CALL libusb_free_config_descriptor(struct libusb_config_descriptor* config) +{ + // because the configuration descriptor is member of device, nothing to do here ... +} + +int LIBUSB_CALL libusb_reset_device(libusb_device_handle* dev_handle) +{ + // to be implemented later ... + + return LIBUSB_SUCCESS; +} +ssize_t LIBUSB_CALL libusb_get_device_list(libusb_context* ctx, libusb_device*** list) +{ + // to be implemented later ... + + return 0; +} +void LIBUSB_CALL libusb_free_device_list(libusb_device** list, int unref_devices) +{ + // to be implemented later ... + +} +int LIBUSB_CALL libusb_set_auto_detach_kernel_driver(libusb_device_handle* dev_handle, int enable) +{ + // to be implemented later ... + + return LIBUSB_SUCCESS; +} +int LIBUSB_CALL libusb_claim_interface(libusb_device_handle* dev_handle, int interface_number) +{ + // to be implemented later ... + + return LIBUSB_SUCCESS; +} +int LIBUSB_CALL libusb_release_interface(libusb_device_handle* dev_handle, int interface_number) +{ + // to be implemented later ... + + return LIBUSB_SUCCESS; +} +int LIBUSB_CALL libusb_set_configuration(libusb_device_handle* dev_handle, int configuration) +{ + // to be implemented later ... + + return LIBUSB_SUCCESS; +} +int LIBUSB_CALL libusb_kernel_driver_active(libusb_device_handle* dev_handle, int interface_number) +{ + // to be implemented later ... + + return LIBUSB_SUCCESS; +} +int LIBUSB_CALL libusb_detach_kernel_driver(libusb_device_handle* dev_handle, int interface_number) +{ + // to be implemented later ... + + return LIBUSB_SUCCESS; +} +int LIBUSB_CALL libusb_attach_kernel_driver(libusb_device_handle* dev_handle, int interface_number) +{ + // to be implemented later ... + + return LIBUSB_SUCCESS; +} +libusb_device_handle* LIBUSB_CALL libusb_open_device_with_vid_pid(libusb_context* ctx, uint16_t vendor_id, uint16_t product_id) +{ + // to be implemented later ... + + return NULL; +} +int LIBUSB_CALL libusb_clear_halt(libusb_device_handle* dev_handle, unsigned char endpoint) +{ + // to be implemented later ... + + return LIBUSB_SUCCESS; +} +const char* LIBUSB_CALL libusb_error_name(int errcode) +{ +#define RETURN_IF(e) \ + if(errcode == e) \ + return #e; + + RETURN_IF(LIBUSB_SUCCESS); + RETURN_IF(LIBUSB_ERROR_IO); + RETURN_IF(LIBUSB_ERROR_INVALID_PARAM); + RETURN_IF(LIBUSB_ERROR_ACCESS); + RETURN_IF(LIBUSB_ERROR_NO_DEVICE); + RETURN_IF(LIBUSB_ERROR_NOT_FOUND); + RETURN_IF(LIBUSB_ERROR_BUSY); + RETURN_IF(LIBUSB_ERROR_TIMEOUT); + RETURN_IF(LIBUSB_ERROR_OVERFLOW); + RETURN_IF(LIBUSB_ERROR_PIPE); + RETURN_IF(LIBUSB_ERROR_INTERRUPTED); + RETURN_IF(LIBUSB_ERROR_NO_MEM); + RETURN_IF(LIBUSB_ERROR_NOT_SUPPORTED); + RETURN_IF(LIBUSB_ERROR_OTHER); + + return "Unknown error"; +} + +int LIBUSB_CALL libusb_open(libusb_device* dev, libusb_device_handle** dev_handle) +{ + if (!dev) + return LIBUSB_ERROR_INVALID_PARAM; + + return ((usb_device*)dev)->open(dev_handle); +} +void LIBUSB_CALL libusb_close(libusb_device_handle* dev_handle) +{ + if (dev_handle) + { + ((usb_device*)dev_handle)->close(); + } +} +int LIBUSB_CALL libusb_control_transfer(libusb_device_handle* dev_handle, + uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, + unsigned char* data, uint16_t wLength, unsigned int timeout) +{ + if (!dev_handle) + return LIBUSB_ERROR_INVALID_PARAM; + + return ((usb_device*)dev_handle)->transfer_control(request_type, bRequest, wValue, wIndex, data, wLength, timeout); +} +int LIBUSB_CALL libusb_bulk_transfer(libusb_device_handle* dev_handle, + unsigned char endpoint, unsigned char* data, int length, + int* actual_length, unsigned int timeout) +{ + if (!dev_handle) + return LIBUSB_ERROR_INVALID_PARAM; + + if (actual_length) + *actual_length = length; + else + actual_length = &length; + + return ((usb_device*)dev_handle)->transfer_bulk(endpoint, data, actual_length, timeout); +} +int LIBUSB_CALL libusb_interrupt_transfer(libusb_device_handle* dev_handle, + unsigned char endpoint, unsigned char* data, int length, + int* actual_length, unsigned int timeout) +{ + if (!dev_handle) + return LIBUSB_ERROR_INVALID_PARAM; + + if (actual_length) + *actual_length = length; + else + actual_length = &length; + + return ((usb_device*)dev_handle)->transfer_interrupt(endpoint, data, actual_length, timeout); +} + +int LIBUSB_CALL libusb_set_timeout(libusb_device_handle* h, unsigned int milliseconds) +{ + if (!h) + return LIBUSB_ERROR_INVALID_PARAM; + + return ((usb_device*)h)->set_timeout(milliseconds); +} +void LIBUSB_CALL libusb_quit(libusb_context* ctx) +{ + if (ctx) + ((usb_monitor*)ctx)->quit(); +} +uint8_t LIBUSB_CALL libusb_get_device_address(libusb_device* device) +{ + if(!device) + return 0; + + return ((usb_device*)device)->port(); +} + diff --git a/device/win_usb/win_usb.h b/device/win_usb/win_usb.h new file mode 100644 index 0000000..cc4d610 --- /dev/null +++ b/device/win_usb/win_usb.h @@ -0,0 +1,234 @@ +#pragma once + +// implements USB as libusb on windows +// +// Date: 2022-04-01 + +#include +#include +#include +#include +#include +#include +#include +#include "libusb-1.0/libusb.h" + +// HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Class\{6bdd1fc6-810f-11d0-bec7-08002be2092f} +#define HG_SCANNER_GUID "6BDD1FC6-810F-11D0-BEC7-08002BE2092F" +#define MONITOR_WINDOW_OWNER L"monitor_wnd_owner" + + +typedef struct _dev_id +{ + int vid; + int pid; + + bool operator==(const struct _dev_id& r) + { + return vid == r.vid && pid == r.pid; + } +}DEVID; + +class usb_device // consider as libusb_device +{ + volatile long ref_; + GUID guid_; + std::string name_; + DEVID id_; + bool is_ok_; + bool online_; + uint8_t port_; + + enum + { + OVL_BULK_IN, + OVL_BULK_OUT, + OVL_CONTROL, + OVL_INTERRUPT, + + OVL_MAX, + }; + OVERLAPPED ovl_[OVL_MAX]; + + libusb_device_handle *handle_; // as file handle returned by CreateFile + libusb_device_descriptor *dev_desc_; + std::vector cfg_desc_; + + typedef struct _usb_pipe + { + UCHAR address; + int type; + HANDLE pipe; + }USBPIPE; + std::vector pipes_; + DWORD timout_ms_; + HANDLE find_pipe(UCHAR addr, int type); + int set_timeout(HANDLE h); + +public: + usb_device(const char* name); + + static DEVID vid_pid_from_name(const char* name); // 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); + 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*/); + static int get_device_address(const char* device_name, LPGUID lpguid); + + long add_ref(void); + long release(void); + +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); + 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); + + 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); + int close(void); + int set_timeout(unsigned milliseconds); + + int transfer_bulk(unsigned endpoint, unsigned char* data, int* length, unsigned int timeout); + int transfer_control(uint8_t type, uint8_t req, uint16_t val, uint16_t ind, unsigned char* data, uint16_t len, unsigned timeout); + int transfer_interrupt(unsigned endpoint, unsigned char* data, int* length, unsigned int timeout); +}; +class usb_callback +{ + libusb_hotplug_callback_fn usb_cb_; + void* usb_cb_param_; + +public: + usb_callback(libusb_hotplug_callback_fn cb, void* param); + ~usb_callback(); + +public: + void notify(libusb_context* ctx, usb_device* dev, int ev); +}; +class usb_monitor // consider as libusb_context +{ + std::vector cbs_; + std::mutex lock_; + std::vector devices_; + std::shared_ptr handle_msg_; + DWORD handle_msg_id_; + std::string cur_dev_name_; + volatile bool run_; + + HWND wnd_monitor_; + 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& usb_devs); + +public: + usb_monitor(); + ~usb_monitor(); + + static usb_monitor* usb_monitor_; + +public: + usb_callback* reg_callback(libusb_hotplug_callback_fn cb, void* param); + void unreg_callback(usb_callback* cb); + + void thread_run_device_event_wnd(void); // called in a seperate thread from libusb + void thread_handle_device_change_msg(void); // a seperate thread for WM_DEVICECHANGE cannot be blocked + + void quit(void); +}; + +//1: \\?\usb#vid_0bda&pid_0129#20100201396000000#{a5dcbf10-6530-11d2-901f-00c04fb951ed} +// DeviceIoControl error: 31 +// USB\VID_0BDA&PID_0129\20100201396000000 +// class: USB +// desc: Realtek USB 2.0 Card Reader +// HID: USB\VID_0BDA&PID_0129&REV_3960 +// name: \Device\USBPDO-3 +// bus : 1 +// addr: 9 +// guid: {36fc9e60-c465-11cf-8056-444553540000} +// path: PCIROOT(0)#PCI(1400)#USBROOT(0)#USB(9) +// +//2: \\?\usb#vid_06cb&pid_00ea#9bec419959f6#{a5dcbf10-6530-11d2-901f-00c04fb951ed} +// Open error: 5 +// USB\VID_06CB&PID_00EA\9BEC419959F6 +// class: Biometric +// desc: Synaptics UWP WBDI +// HID: USB\VID_06CB&PID_00EA&REV_0000 +// name: \Device\USBPDO-5 +// bus : 1 +// addr: 12 +// guid: {53d29ef7-377c-4d14-864b-eb3a85769359} +// path: PCIROOT(0)#PCI(1400)#USBROOT(0)#USB(12) +// +//3: \\?\usb#vid_3072&pid_0239#01234567aabbccddee#{a5dcbf10-6530-11d2-901f-00c04fb951ed} +// VID: 3072 +// PID: 0239 +// USB: 4.4 +// USB\VID_3072&PID_0239\01234567AABBCCDDEE +// class: Image +// desc: HUAGOSCAN G200 TWAIN +// HID: USB\VID_3072&PID_0239&REV_0404 +// name: \Device\USBPDO-7 +// bus : 1 +// addr: 8 +// guid: {6bdd1fc6-810f-11d0-bec7-08002be2092f} +// path: PCIROOT(0)#PCI(1400)#USBROOT(0)#USB(8) +// +//4: \\?\usb#vid_17ef&pid_6100#5&4adfeed&0&6#{a5dcbf10-6530-11d2-901f-00c04fb951ed} +// VID: 0000 +// PID: 0000 +// USB: 0.0 +// USB\VID_17EF&PID_6100\5&4ADFEED&0&6 +// class: USB +// desc: USB Composite Device +// HID: USB\VID_17EF&PID_6100&REV_0201 +// name: \Device\USBPDO-1 +// bus : 1 +// addr: 6 +// guid: {36fc9e60-c465-11cf-8056-444553540000} +// path: PCIROOT(0)#PCI(1400)#USBROOT(0)#USB(6) +// +//5: \\?\usb#vid_8087&pid_0026#5&4adfeed&0&14#{a5dcbf10-6530-11d2-901f-00c04fb951ed} +// DeviceIoControl error: 50 +// USB\VID_8087&PID_0026\5&4ADFEED&0&14 +// class: Bluetooth +// desc: 英特尔(R) 无线 Bluetooth(R) +// HID: USB\VID_8087&PID_0026&REV_0002 +// name: \Device\USBPDO-4 +// bus : 1 +// addr: 14 +// guid: {e0cbf06c-cd8b-4647-bb8a-263b43f0f974} +// path: PCIROOT(0)#PCI(1400)#USBROOT(0)#USB(14) +// +//6: \\?\usb#vid_17ef&pid_608d#5&4adfeed&0&7#{a5dcbf10-6530-11d2-901f-00c04fb951ed} +// Open error: 31 +// USB\VID_17EF&PID_608D\5&4ADFEED&0&7 +// class: HIDClass +// desc: USB 输入设备 +// HID: USB\VID_17EF&PID_608D&REV_0100 +// name: \Device\USBPDO-2 +// bus : 1 +// addr: 7 +// guid: {745a17a0-74d3-11d0-b6fe-00a0c90f57da} +// path: PCIROOT(0)#PCI(1400)#USBROOT(0)#USB(7) +// diff --git a/huagaotwain/dllmain.cpp b/huagaotwain/dllmain.cpp new file mode 100644 index 0000000..ae98183 --- /dev/null +++ b/huagaotwain/dllmain.cpp @@ -0,0 +1,22 @@ +#include "pch.h" +#include "huagaotwain.h" + +HMODULE me_ = NULL; + +BOOL APIENTRY DllMain(HMODULE hModule , DWORD ul_reason_for_call, LPVOID /* lpReserved */) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + //sane_invoker::initialize(hModule); + me_ = hModule; + break; + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + break; + case DLL_PROCESS_DETACH: + //sane_invoker::uninitialize(); + break; + } + return TRUE; +} diff --git a/huagaotwain/huagaotwain.cpp b/huagaotwain/huagaotwain.cpp new file mode 100644 index 0000000..876d9ae --- /dev/null +++ b/huagaotwain/huagaotwain.cpp @@ -0,0 +1,2189 @@ +#include "pch.h" +#include "huagaotwain.h" +#include "huagao/hgscanner_error.h" +#include "./twain/twain_2.4.h" +#include "../../device/sdk/hginclude/hg_log.h" + +#define STR(s) #s +#define PASTE_STR(a, b) STR(a##b) +#define SANE_API(api) PASTE_STR(sane_hgsane_, api) +#define API_ELEM(api) {SANE_API(api), (FARPROC*)&real_sane_##api##_} +#ifdef VLOG_OK +#define vlog_debug_info sane_invoker::log_debug_info +#else +#define vlog_debug_info +#endif + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// utilities ... +namespace local_utility +{ + std::wstring reg_read(HKEY root, const wchar_t* path, const wchar_t* name) + { + HKEY key = NULL; + + RegOpenKeyW(root, path, &key); + if (!key) + return L""; + + wchar_t* buf = NULL; + DWORD len = 0; + DWORD type = REG_SZ; + std::wstring ret(L""); + + RegQueryValueExW(key, name, NULL, &type, (LPBYTE)buf, &len); + if(len) + { + buf = new wchar_t[len + 4]; + memset(buf, 0, (len + 4) * sizeof(*buf)); + RegQueryValueExW(key, name, NULL, &type, (LPBYTE)buf, &len); + ret = buf; + delete[] buf; + } + RegCloseKey(key); + + return ret; + } + std::wstring reg_get_app_installing_path(void) + { + return reg_read(HKEY_LOCAL_MACHINE, L"SOFTWARE\\HuaGoScan", L"AppDirectory"); + } +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// scanned image ... +scanned_img::scanned_img(SANE_Image* img, SANE_FinalImgFormat* header) : param_(img->header) +{ + // PBITMAPINFOHEADER + size_t bytes = line_bytes() * height(); + std::string h(file_header(header, bytes)); + unsigned char *src = img->data + img->bytes - param_.bytes_per_line, + *dst = NULL; + + data_.resize(bytes + h.length()); + memcpy(&data_[0], h.c_str(), h.length()); + dst = (unsigned char*)&data_[0] + h.length(); + + if (param_.format == SANE_FRAME_RGB) + { + for (int i = 0; i < height(); ++i) + { + for (int j = 0; j < param_.pixels_per_line; ++j) + { + dst[j * 3 + 0] = src[j * 3 + 2]; + dst[j * 3 + 1] = src[j * 3 + 1]; + dst[j * 3 + 2] = src[j * 3 + 0]; + } + src -= param_.bytes_per_line; + dst += line_bytes(); + } + } + else + { + for (int i = 0; i < height(); ++i, dst += line_bytes(), src -= param_.bytes_per_line) + memcpy(dst, src, param_.bytes_per_line); + } +} +scanned_img::~scanned_img() +{} + +std::string scanned_img::file_header(SANE_FinalImgFormat* header, float resolution) +{ + std::string h(""); + + if (header->img_format == SANE_IMAGE_TYPE_BMP) + { + BITMAPINFOHEADER bih = { 0 }; + + bih.biSize = sizeof(bih); + bih.biWidth = width(); + bih.biBitCount = depth(); + bih.biSizeImage = line_bytes() * height(); + bih.biPlanes = 1; + bih.biHeight = height(); + bih.biCompression = BI_RGB; + bih.biXPelsPerMeter = bih.biYPelsPerMeter = resolution * 39.37f + .5f; + + h = std::string((char*)&bih, sizeof(bih)); + } + + return h; +} + +int scanned_img::width(void) +{ + return param_.pixels_per_line; +} +int scanned_img::line_bytes(void) +{ + return (param_.bytes_per_line + 3) / 4 * 4; +} +int scanned_img::height(void) +{ + return param_.lines; +} +int scanned_img::depth(void) +{ + if (param_.format == SANE_FRAME_RGB) + return param_.depth * 3; + else + return param_.depth; +} +int scanned_img::channel(void) +{ + return param_.format == SANE_FRAME_RGB ? 3 : 1; +} +SANE_Frame scanned_img::type(void) +{ + return param_.format; +} +unsigned int scanned_img::bytes(void) +{ + return data_.size(); +} +unsigned char* scanned_img::bits(void) +{ + return &data_[0]; +} +void scanned_img::copy_header(SANE_Parameters* head) +{ + *head = param_; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// sane_invoker ... + +sane_invoker* sane_invoker::inst_ = NULL; +sane_invoker::sane_invoker(const wchar_t* path) : ok_(false), ver_(0), sane_(NULL), first_cb_(NULL) +{ + memset(&sane_api_, 0, sizeof(sane_api_)); + cfg_file_ = std::wstring(path) + L"config.txt"; + if (load_sane()) + { + first_cb_ = CreateEventA(NULL, FALSE, FALSE, NULL); + real_sane_init_ex_(&ver_, &sane_invoker::sane_callback_handler, this); + + char msg[128] = { 0 }; + sprintf_s(msg, _countof(msg) - 1, "Wait sane first callback = %d\r\n", WaitForSingleObject(first_cb_, 1000)); + sane_invoker::log_debug_info(msg); + } +} +sane_invoker::~sane_invoker() +{ + if (sane_) + { + if(real_sane_exit_) + real_sane_exit_(); + FreeLibrary(sane_); + sane_ = NULL; + } + if (first_cb_) + CloseHandle(first_cb_); +} + +bool sane_invoker::load_sane() +{ + //sane_hgsane_init + //sane_hgsane_exit + //sane_hgsane_get_devices + //sane_hgsane_open + //sane_hgsane_close + //sane_hgsane_get_option_descriptor + //sane_hgsane_control_option + //sane_hgsane_get_parameters + //sane_hgsane_start + //sane_hgsane_read + //sane_hgsane_cancel + //sane_hgsane_set_io_mode + //sane_hgsane_get_select_fd + //sane_hgsane_strstatus + //sane_hgsane_init_ex + //sane_hgsane_io_control + struct { + std::string name; + FARPROC* api; + }apis[] = { API_ELEM(init), + API_ELEM(exit), + API_ELEM(get_devices), + API_ELEM(open), + API_ELEM(close), + API_ELEM(get_option_descriptor), + API_ELEM(control_option), + API_ELEM(get_parameters), + API_ELEM(start), + API_ELEM(read), + API_ELEM(cancel), + API_ELEM(set_io_mode), + API_ELEM(get_select_fd), + API_ELEM(strstatus), + API_ELEM(io_control), + API_ELEM(init_ex) + }; + + wchar_t sane_path[MAX_PATH] = { 0 }; + DWORD size = _countof(sane_path); + + log_ = &sane_invoker::no_log; + for (int i = 0; i < _countof(apis); ++i) + *apis[i].api = NULL; + + ok_ = false; +#ifdef USE_LOCAL_CONFIG + if (GetPrivateProfileStringW(L"sane", L"pe", L"", sane_path, size - 1, cfg_file_.c_str())) +#else + std::wstring reg(local_utility::reg_get_app_installing_path()); + wcscpy_s(sane_path, size - 1, reg.c_str()); + if(reg.length()) +#endif + { + wcscat(sane_path, L"\\hgsane.dll"); + size = sane_invoker::load_dll(sane_path, &sane_); + if (sane_) + { + ok_ = true; + *((FARPROC*)&log_) = GetProcAddress(sane_, "hg_debug_log"); + if (!log_) + log_ = &sane_invoker::no_log; + for (int i = 0; i < _countof(apis); ++i) + { + *apis[i].api = GetProcAddress(sane_, apis[i].name.c_str()); + if (!(*apis[i].api)) + { + vlog_debug_info(1024, "GetProcAddress(\"sane.dll\", \"%s\") failed with error: %d\r\n", apis[i].name.c_str(), GetLastError()); + ok_ = false; + } + } + if (ok_) + { + vlog_debug_info(1024, "sane component load success, path = \"%s\"\r\n", sane_invoker::u2ansi(sane_path).c_str()); + for (int i = 0; i < sizeof(sane_api_) / sizeof(sane_api_.sane_cancel_api); ++i) + ((FARPROC*)&sane_api_)[i] = *apis[i + 2].api; + } + } + else + { + vlog_debug_info(1024, "LoadLibraryW(\"%s\") failed with error: %d\r\n", sane_invoker::u2ansi(sane_path).c_str(), GetLastError()); + } + } + else + { + vlog_debug_info(1024, "GetPrivateProfileStringW(\"sane\", \"pe\", \"%s\") failed\r\n", sane_invoker::u2ansi(cfg_file_.c_str()).c_str()); + } + + return ok_; +} +int sane_invoker::handle_sane_event(SANE_Handle hdev, int code, void* data, unsigned int* len) +{ + SetEvent(first_cb_); + if (code == SANE_EVENT_DEVICE_ARRIVED) + { + SANE_Device* sdev = (SANE_Device*)data; + SANEDEV dev; + std::lock_guard lock(lock_dev_); + std::vector::iterator it = std::find(devices_.begin(), devices_.end(), sdev->name); + + if (it == devices_.end()) + { + dev.name = sdev->name; + dev.type = sdev->model; + dev.product = sdev->type; + dev.vendor = sdev->vendor; + devices_.push_back(dev); + } + else if (it->scanner) + it->scanner->set_online(true); + } + else if (code == SANE_EVENT_DEVICE_LEFT) + { + SANE_Device* sdev = (SANE_Device*)data; + std::lock_guard lock(lock_dev_); + std::vector::iterator it = std::find(devices_.begin(), devices_.end(), sdev->name); + if (it != devices_.end()) + { + if (it->scanner) + it->scanner->set_online(false); + else + devices_.erase(it); + } + } + else if (code == SANE_EVENT_IMAGE_OK) + { + scanner* dev = find_scanner(hdev); + if (dev) + { + dev->put_image((SANE_Image*)data, len); + dev->release(); + } + } + else if (code == SANE_EVENT_SCAN_FINISHED) + { + scanner* dev = find_scanner(hdev); + if (dev) + { + dev->scan_finished((char*)data, *len); + } + } + else if (code == SANE_EVENT_ERROR) + { + std::wstring msg(sane_invoker::utf82u((char*)data)); + MessageBoxW(NULL, msg.c_str(), L"Error", MB_OK); + } + + return HG_ERR_OK; +} +void sane_invoker::get_online_devices(std::vector& devs) +{ + std::lock_guard lock(lock_dev_); + + devs = devices_; +} +int sane_invoker::get_online_device_count(void) +{ + std::lock_guard lock(lock_dev_); + + return devices_.size(); +} +scanner* sane_invoker::find_scanner(SANE_Handle hdev) +{ + std::lock_guard lock(lock_dev_); + std::vector::iterator it = std::find(devices_.begin(), devices_.end(), hdev); + + if (it == devices_.end()) + return NULL; + else + { + it->scanner->add_ref(); + + return it->scanner; + } +} +scanner* sane_invoker::open(const char* name, int* err) +{ + std::lock_guard lock(lock_dev_); + std::vector::iterator it = std::find(devices_.begin(), devices_.end(), name); + + if (it == devices_.end()) + { + if (err) + *err = HG_ERR_DEVICE_NOT_FOUND; + + return NULL; + } + + scanner *s = new scanner(this, *it); + if (s->last_error() != SANE_STATUS_GOOD) + { + if (err) + *err = s->last_error(); + s->release(); + s = NULL; + } + + return s; +} + +void sane_invoker::no_log(int, const char* info) +{ + OutputDebugStringA(info); +} +int sane_invoker::sane_callback_handler(SANE_Handle hdev, int code, void* data, unsigned int* len, void* param) +{ + return ((sane_invoker*)param)->handle_sane_event(hdev, code, data, len); +} + +int sane_invoker::load_dll(const wchar_t* path_dll, HMODULE* dll) +{ + HMODULE h = LoadLibraryW(path_dll); + int ret = 0; + + if (!h && GetLastError() == 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); + if (pos != std::wstring::npos) + dir.erase(pos); + SetCurrentDirectoryW(dir.c_str()); + h = LoadLibraryW(path_dll); + ret = GetLastError(); + SetCurrentDirectoryW(path); + } + else + ret = GetLastError(); + + if (dll) + *dll = h; + + return ret; +} +bool sane_invoker::initialize(HMODULE me) +{ + if (sane_invoker::inst_) + return false; + else + { + wchar_t path[MAX_PATH] = { 0 }, * last = NULL; + + GetModuleFileNameW(me, path, _countof(path) - 1); + last = wcsrchr(path, L'\\'); + if (last++) + *last = 0; + sane_invoker::inst_ = new sane_invoker(path); + + return true; + } +} +void sane_invoker::uninitialize(void) +{ + if (sane_invoker::inst_) + delete sane_invoker::inst_; + sane_invoker::inst_ = NULL; +} +std::string sane_invoker::u2m(const wchar_t* u, int page) +{ + char *ansi = NULL; + int len = 0; + std::string mb(""); + + len = WideCharToMultiByte(page, 0, u, lstrlenW(u), NULL, 0, NULL, NULL); + ansi = new char[len + 2]; + len = WideCharToMultiByte(page, 0, u, lstrlenW(u), ansi, len, NULL, NULL); + ansi[len--] = 0; + mb = ansi; + delete[] ansi; + + return mb; +} +std::wstring sane_invoker::m2u(const char* m, int page) +{ + wchar_t *unic = NULL; + int len = 0; + std::wstring u(L""); + + len = MultiByteToWideChar(page, 0, m, lstrlenA(m), NULL, 0); + unic = new wchar_t[len + 2]; + len = MultiByteToWideChar(page, 0, m, lstrlenA(m), unic, len); + unic[len--] = 0; + u = unic; + delete[] unic; + + return u; +} +std::string sane_invoker::u2ansi(const wchar_t* u) +{ + return sane_invoker::u2m(u, CP_ACP); +} +std::string sane_invoker::u2utf8(const wchar_t* u) +{ + return sane_invoker::u2m(u, CP_UTF8); +} +std::string sane_invoker::utf82ansi(const char* utf8) +{ + return sane_invoker::u2m(sane_invoker::m2u(utf8, CP_UTF8).c_str(), CP_ACP); +} +std::string sane_invoker::ansi2utf8(const char* ansi) +{ + return sane_invoker::u2m(sane_invoker::m2u(ansi, CP_ACP).c_str(), CP_UTF8); +} +std::wstring sane_invoker::utf82u(const char* utf8) +{ + return sane_invoker::m2u(utf8, CP_UTF8); +} +std::wstring sane_invoker::ansi2u(const char* ansi) +{ + return sane_invoker::m2u(ansi, CP_ACP); +} +void sane_invoker::log_debug_info(const char* info) +{ + if (sane_invoker::inst_) + sane_invoker::inst_->log_(HG_LOG_LEVEL_DEBUG_INFO, info); + else + OutputDebugStringA(info); +} +#ifdef VLOG_OK +void __cdecl sane_invoker::log_debug_info(int bytes, const char* fmt, ...) +{ + std::string str(bytes + 20, 0); + + va_list args; + + va_start(args, fmt); + sprintf_s(&str[0], bytes, fmt, args); + va_end(args); + + vlog_debug_info(str.c_str()); +} +#endif + +SANE_Status sane_invoker::invoke_sane_init(SANE_Int* version_code, SANE_Auth_Callback authorize) +{ + if (!sane_invoker::inst_) + return (SANE_Status)HG_ERR_NOT_OPEN; + + if (!sane_invoker::inst_->real_sane_init_) + return SANE_STATUS_UNSUPPORTED; + + return sane_invoker::inst_->real_sane_init_(version_code, authorize); +} +void sane_invoker::invoke_sane_exit(void) +{ + if (sane_invoker::inst_ && sane_invoker::inst_->real_sane_exit_) + sane_invoker::inst_->real_sane_exit_(); +} +SANE_Status sane_invoker::invoke_sane_get_devices(const SANE_Device*** device_list, SANE_Bool local_only) +{ + if (!sane_invoker::inst_) + return (SANE_Status)HG_ERR_NOT_OPEN; + + if (!sane_invoker::inst_->real_sane_get_devices_) + return SANE_STATUS_UNSUPPORTED; + + return sane_invoker::inst_->real_sane_get_devices_(device_list, local_only); +} +SANE_Status sane_invoker::invoke_sane_open(SANE_String_Const devicename, SANE_Handle* handle) +{ + if (!sane_invoker::inst_) + return (SANE_Status)HG_ERR_NOT_OPEN; + + if (!sane_invoker::inst_->real_sane_open_) + return SANE_STATUS_UNSUPPORTED; + + return sane_invoker::inst_->real_sane_open_(devicename, handle); +} +void sane_invoker::invoke_sane_close(SANE_Handle handle) +{ + if (sane_invoker::inst_ && sane_invoker::inst_->real_sane_close_) + sane_invoker::inst_->real_sane_close_(handle); +} +const SANE_Option_Descriptor* sane_invoker::invoke_sane_get_option_descriptor(SANE_Handle handle, SANE_Int option) +{ + if (!sane_invoker::inst_) + return NULL; + + if (!sane_invoker::inst_->real_sane_get_option_descriptor_) + return NULL; + + return sane_invoker::inst_->real_sane_get_option_descriptor_(handle, option); +} +SANE_Status sane_invoker::invoke_sane_control_option(SANE_Handle handle, SANE_Int option, SANE_Action action, void* value, SANE_Int* info) +{ + if (!sane_invoker::inst_) + return (SANE_Status)HG_ERR_NOT_OPEN; + + if (!sane_invoker::inst_->real_sane_control_option_) + return SANE_STATUS_UNSUPPORTED; + + return sane_invoker::inst_->real_sane_control_option_(handle, option, action, value, info); +} +SANE_Status sane_invoker::invoke_sane_get_parameters(SANE_Handle handle, SANE_Parameters* params) +{ + if (!sane_invoker::inst_) + return (SANE_Status)HG_ERR_NOT_OPEN; + + if (!sane_invoker::inst_->real_sane_get_parameters_) + return SANE_STATUS_UNSUPPORTED; + + return sane_invoker::inst_->real_sane_get_parameters_(handle, params); +} +SANE_Status sane_invoker::invoke_sane_start(SANE_Handle handle) +{ + if (!sane_invoker::inst_) + return (SANE_Status)HG_ERR_NOT_OPEN; + + if (!sane_invoker::inst_->real_sane_start_) + return SANE_STATUS_UNSUPPORTED; + + return sane_invoker::inst_->real_sane_start_(handle); +} +SANE_Status sane_invoker::invoke_sane_read(SANE_Handle handle, SANE_Byte* data, SANE_Int max_length, SANE_Int* length) +{ + if (!sane_invoker::inst_) + return (SANE_Status)HG_ERR_NOT_OPEN; + + if (!sane_invoker::inst_->real_sane_read_) + return SANE_STATUS_UNSUPPORTED; + + return sane_invoker::inst_->real_sane_read_(handle, data, max_length, length); +} +void sane_invoker::invoke_sane_cancel(SANE_Handle handle) +{ + if (sane_invoker::inst_ && sane_invoker::inst_->real_sane_cancel_) + sane_invoker::inst_->invoke_sane_cancel(handle); +} +SANE_Status sane_invoker::invoke_sane_set_io_mode(SANE_Handle handle, SANE_Bool non_blocking) +{ + if (!sane_invoker::inst_) + return (SANE_Status)HG_ERR_NOT_OPEN; + + if (!sane_invoker::inst_->real_sane_set_io_mode_) + return SANE_STATUS_UNSUPPORTED; + + return sane_invoker::inst_->real_sane_set_io_mode_(handle, non_blocking); +} +SANE_Status sane_invoker::invoke_sane_get_select_fd(SANE_Handle handle, SANE_Int* fd) +{ + if (!sane_invoker::inst_) + return (SANE_Status)HG_ERR_NOT_OPEN; + + if (!sane_invoker::inst_->real_sane_get_select_fd_) + return SANE_STATUS_UNSUPPORTED; + + return sane_invoker::inst_->real_sane_get_select_fd_(handle, fd); +} +SANE_String_Const sane_invoker::invoke_sane_strstatus(SANE_Status status) +{ + if (sane_invoker::inst_ && sane_invoker::inst_->real_sane_strstatus_) + return sane_invoker::inst_->real_sane_strstatus_(status); + else + return ""; +} +SANE_Status sane_invoker::invoke_sane_init_ex(SANE_Int* version_code, sane_callback cb, void* param) +{ + if (!sane_invoker::inst_) + return (SANE_Status)HG_ERR_NOT_OPEN; + + if (!sane_invoker::inst_->real_sane_init_ex_) + return SANE_STATUS_UNSUPPORTED; + + return sane_invoker::inst_->real_sane_init_ex_(version_code, cb, param); +} +SANE_Status sane_invoker::invoke_sane_io_control(SANE_Handle h, unsigned long code, void* data, unsigned* len) +{ + if (!sane_invoker::inst_) + return (SANE_Status)HG_ERR_NOT_OPEN; + + if (!sane_invoker::inst_->real_sane_io_control_) + return SANE_STATUS_UNSUPPORTED; + + return sane_invoker::inst_->real_sane_io_control_(h, code, data, len); +} + +LPSANEAPI sane_invoker::get_api(void) +{ + if (sane_invoker::inst_) + return &sane_invoker::inst_->sane_api_; + else + return NULL; +} + +bool sane_invoker::is_ok(void) +{ + if (sane_invoker::inst_) + return sane_invoker::inst_->ok_; + else + return false; +} +std::string sane_invoker::version(LPDWORD v) +{ + char vs[40] = { 0 }; + DWORD ver = 0; + + if (sane_invoker::inst_) + ver = sane_invoker::inst_->ver_; + + sprintf_s(vs, _countof(vs) - 1, "%u.%u.%u", (ver >> 24) & 0x0ff, (ver >> 16) & 0x0ff, ver & 0x0ffff); + if (v) + *v = ver; + + return vs; +} +void sane_invoker::get_devices(std::vector& devs) +{ + if (sane_invoker::inst_) + sane_invoker::inst_->get_online_devices(devs); +} +scanner* sane_invoker::open_scanner(const char* name, int* err) +{ + if (!sane_invoker::inst_) + { + if (err) + *err = HG_ERR_NOT_OPEN; + + return NULL; + } + + return sane_invoker::inst_->open(name, err); +} +int sane_invoker::online_devices(void) +{ + if (sane_invoker::inst_) + sane_invoker::inst_->get_online_device_count(); + else + return 0; +} + + + + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// scanner ... +#define FIND_OPTION(opt) \ + std::vector::iterator it = std::find(options_.begin(), options_.end(), opt); + +scanner::scanner(sane_invoker* host, struct _dev& dev) : host_(host), hdev_(NULL), dpi_(200.0f), option_count_(0), event_cb_(NULL) + , name_(dev.name), type_(dev.type), vendor_(dev.vendor), product_(dev.product), cb_param_(NULL) + , scanning_(false), wait_img_(CreateEventA(NULL, TRUE, FALSE, NULL)), fmt_(NULL) + , opt_ind_dpi_(-1), opt_ind_color_mode_(-1), opt_ind_paper_(-1), opt_ind_scann_count_(-1) + , jpeg_quality_(80), opt_ind_text_direction_(-1), opt_ind_page_(-1), img_fmt_(SANE_IMAGE_TYPE_BMP) + , opt_ind_auto_descrew_(-1), opt_ind_erase_black_frame_(-1), opt_ind_filter_(-1), opt_ind_bright_(-1) + , opt_ind_contrast_(-1), opt_ind_gamma_(-1), opt_ind_ultrasonic_(-1), err_(HG_ERR_OK), desc_("") + , compression_(SANE_COMPRESSION_NONE), opt_ind_flip_(-1), auto_crop_(false), opt_ind_rotate_bkg_(-1) + , opt_ind_fill_blank_bkg_(-1), opt_ind_edge_ident_(-1), opt_ind_threshold_(-1), opt_ind_bkg_filling_method_(-1) + , opt_ind_fill_hole_(-1), opt_ind_fill_hole_ratio_(-1), opt_ind_noise_(-1), opt_ind_noise_threshold_(-1) + , opt_ind_rid_red_hsv_(-1), opt_ind_rid_red_(-1), opt_ind_sharpen_(-1), opt_ind_screw_detect_(-1), opt_ind_screw_detect_level_(-1) + , opt_ind_staple_(-1), opt_ind_dogear_(-1), opt_ind_dark_sample_(-1), opt_ind_split_(-1), opt_ind_fade_bkg_(-1) + , opt_ind_fade_bkg_val_(-1), opt_ind_size_detect_(-1), opt_ind_multi_out_(-1) +{ + dev.scanner = this; + + SANE_Status statu = sane_invoker::invoke_sane_open(name_.c_str(), &hdev_); + online_ = statu == SANE_STATUS_GOOD; + { + vlog_debug_info(128, "scanner(0x%x) generated, open '%s' = %d\r\n", this, name_.c_str(), statu); + } + if (online_) + load_options(); + init_image_format(); + err_ = statu; +} +scanner::~scanner() +{ + if (fmt_) + delete[](char*)fmt_; + for (auto& v : options_) + { + if (v.desc->type == SANE_Value_Type::SANE_TYPE_STRING) + delete v.val.sv; + } + + vlog_debug_info(128, "scanner(0x%x) destroyed\r\n", this); +} + +std::string scanner::type(SANE_Value_Type st) +{ + switch (st) + { + case SANE_Value_Type::SANE_TYPE_BOOL: + return "bool"; + case SANE_Value_Type::SANE_TYPE_BUTTON: + return "button"; + case SANE_Value_Type::SANE_TYPE_FIXED: + return "float"; + case SANE_Value_Type::SANE_TYPE_INT: + return "int"; + case SANE_Value_Type::SANE_TYPE_STRING: + return "string"; + default: + return ""; + } +} +value_limit scanner::limit(SANE_Constraint_Type st) +{ + switch (st) + { + case SANE_Constraint_Type::SANE_CONSTRAINT_RANGE: + return VAL_LIMIT_RANGE; + case SANE_Constraint_Type::SANE_CONSTRAINT_STRING_LIST: + case SANE_Constraint_Type::SANE_CONSTRAINT_WORD_LIST: + return VAL_LIMIT_ENUM; + default: + return VAL_LIMIT_NONE; + } +} + +void scanner::load_options(void) +{ + SANE_Int count = 0, afterdo = 0; + SANE_Status statu = sane_invoker::invoke_sane_control_option(hdev_, 0, SANE_ACTION_GET_VALUE, &count, &afterdo); + + option_count_ = 0; + if (statu != SANE_STATUS_GOOD) + { + vlog_debug_info(128, "get option count failed with error: %d\r\n", statu); + return; + } + else + vlog_debug_info(128, "\"%s\" has %d options.\r\n", count); + + option_count_ = count; + for (int i = 1; i < option_count_; ++i) + { + const SANE_Option_Descriptor* desc = sane_invoker::invoke_sane_get_option_descriptor(hdev_, i); + SANEOPTION op; + + op.ind = i; + op.desc = desc; + if (desc->type == SANE_Value_Type::SANE_TYPE_BOOL) + op.val.bv = get_boolean(i); + else if (desc->type == SANE_Value_Type::SANE_TYPE_FIXED) + op.val.dv = get_double(i); + else if (desc->type == SANE_Value_Type::SANE_TYPE_INT) + op.val.iv = get_integer(i); + else if (desc->type == SANE_Value_Type::SANE_TYPE_STRING) + op.val.sv = new std::string(get_string(i, desc->size)); + options_.push_back(op); + if (color_mode::is_me(desc->title)) + opt_ind_color_mode_ = i; + else if (dpi::is_me(desc->title)) + opt_ind_dpi_ = i; + else if (paper::is_me(desc->title)) + opt_ind_paper_ = i; + else if (scan_count::is_me(desc->title)) + opt_ind_scann_count_ = MAKELPARAM(i, HIWORD(opt_ind_scann_count_)); + else if (scan_count::is_parent(desc->title)) + opt_ind_scann_count_ = MAKELPARAM(LOWORD(opt_ind_scann_count_), i); + else if (text_direction::is_me(desc->title)) + opt_ind_text_direction_ = i; + else if (page::is_me(desc->title)) + opt_ind_page_ = i; + else if (auto_descrew::is_me(desc->title)) + opt_ind_auto_descrew_ = i; + else if (erase_black_frame::is_me(desc->title)) + opt_ind_erase_black_frame_ = i; + else if (filter::is_me(desc->title)) + opt_ind_filter_ = i; + else if (bright::is_me(desc->title)) + opt_ind_bright_ = i; + else if (contrast::is_me(desc->title)) + opt_ind_contrast_ = i; + else if (gamma::is_me(desc->title)) + opt_ind_gamma_ = i; + else if (ultrasonic::is_me(desc->title)) + opt_ind_ultrasonic_ = i; + else if (flip::is_me(desc->title)) + opt_ind_flip_ = i; + else if (rotate_bg::is_me(desc->title)) + opt_ind_rotate_bkg_ = i; + else if (fill_black_border::is_me(desc->title)) + opt_ind_fill_blank_bkg_ = i; + else if (edge_ident::is_me(desc->title)) + opt_ind_edge_ident_ = i; + else if (threshold::is_me(desc->title)) + opt_ind_threshold_ = i; + else if (bkg_filling_method::is_me(desc->title)) + opt_ind_bkg_filling_method_ = i; + else if (fill_hole::is_me(desc->title)) + opt_ind_fill_hole_ = i; + else if (fill_hole::is_ratio(desc->title)) + opt_ind_fill_hole_ratio_ = i; + else if (noise::is_me(desc->title)) + opt_ind_noise_ = i; + else if (noise::is_threshold(desc->title)) + opt_ind_noise_threshold_ = i; + else if (rid_red::is_me(desc->title, false)) + opt_ind_rid_red_ = i; + else if (rid_red::is_me(desc->title, true)) + opt_ind_rid_red_hsv_ = i; + else if (sharpen::is_me(desc->title)) + opt_ind_sharpen_ = i; + else if (screw::is_me(desc->title)) + opt_ind_screw_detect_ = i; + else if (screw::is_level(desc->title)) + opt_ind_screw_detect_level_ = i; + else if (staple::is_me(desc->title)) + opt_ind_staple_ = i; + else if (dogear::is_me(desc->title)) + opt_ind_dogear_ = i; + else if (sample::is_me(desc->title)) + opt_ind_dark_sample_ = i; + else if (split::is_me(desc->title)) + opt_ind_split_ = i; + else if (fade_bkg::is_me(desc->title)) + opt_ind_fade_bkg_ = i; + else if (fade_bkg::is_value(desc->title)) + opt_ind_fade_bkg_val_ = i; + else if (size_detect::is_me(desc->title)) + opt_ind_size_detect_ = i; + else if (multi_out::is_me(desc->title)) + opt_ind_multi_out_ = i; + } +} +void scanner::init_image_format(void) +{ + if (fmt_) + delete[](char*)fmt_; + + int len = sizeof(SANE_FinalImgFormat) + sizeof(BITMAPINFOHEADER); + PBITMAPINFOHEADER pbi = NULL; + + fmt_ = (SANE_FinalImgFormat*)new char[len]; + memset(fmt_, 0, len); + fmt_->img_format = SANE_IMAGE_TYPE_BMP; + pbi = (PBITMAPINFOHEADER)fmt_->detail; +} +std::string scanner::get_string(int opt, int bytes) +{ + std::string ret(""); + char* v = new char[bytes + 4]; + SANE_Int afterdo = 0; + + memset(v, 0, bytes + 4); + sane_invoker::invoke_sane_control_option(hdev_, opt, SANE_ACTION_GET_VALUE, v, &afterdo); + ret = v; + delete[] v; + + return ret; +} +bool scanner::get_boolean(int opt) +{ + SANE_Int afterdo = 0; + SANE_Bool v = 0; + + sane_invoker::invoke_sane_control_option(hdev_, opt, SANE_ACTION_GET_VALUE, &v, &afterdo); + + return v; +} +int scanner::get_integer(int opt) +{ + SANE_Int afterdo = 0; + SANE_Int v = 0; + + sane_invoker::invoke_sane_control_option(hdev_, opt, SANE_ACTION_GET_VALUE, &v, &afterdo); + + return v; +} +double scanner::get_double(int opt) +{ + SANE_Int afterdo = 0; + SANE_Fixed f = 0; + + sane_invoker::invoke_sane_control_option(hdev_, opt, SANE_ACTION_GET_VALUE, &f, &afterdo); + + return SANE_UNFIX(f); +} +int scanner::set_string(int opt, std::string& val, int size, SANE_Int* afterdo) +{ + SANE_Int after = 0; + char* buf = new char[size + 20]; + int ret = 0; + + memset(buf, 0, size + 20); + strcpy(buf, val.c_str()); + ret = sane_invoker::invoke_sane_control_option(hdev_, opt, SANE_ACTION_SET_VALUE, buf, &after); + val = buf; + delete[] buf; + if (afterdo) + *afterdo = after; + + return ret; +} + +int scanner::close(void) +{ + if (hdev_) + { + sane_invoker::invoke_sane_close(hdev_); + hdev_ = NULL; + } + + return HG_ERR_OK; +} +int scanner::start(void) +{ + int ret = HG_ERR_NOT_OPEN; + + ResetEvent(wait_img_); + if (hdev_) + ret = sane_invoker::invoke_sane_start(hdev_); + scanning_ = ret == SANE_STATUS_GOOD; + + return ret; +} +int scanner::stop(void) +{ + scanning_ = false; + if (hdev_) + sane_invoker::invoke_sane_cancel(hdev_); + + return HG_ERR_OK; +} +void scanner::set_event_callback(void(*cb)(int, void*, unsigned int*, void*), void* param) +{ + cb_param_ = param; + event_cb_ = cb; +} +bool scanner::wait_image(DWORD milliseconds) +{ + { + std::lock_guard lock(lock_img_); + if (img_.size()) + return true; + } + + if (!scanning_) + { + if (err_) + { + std::wstring tips(sane_invoker::utf82u(desc_.c_str())); + MessageBoxW(NULL, tips.c_str(), L"\u9519\u8bef", MB_OK); + } + return false; + } + + WaitForSingleObject(wait_img_, milliseconds); + + return img_.size() > 0; +} +int scanner::get_scanned_images(DWORD milliseconds) +{ + if (milliseconds && !wait_image(milliseconds)) + return 0; + else + { + std::lock_guard lock(lock_img_); + + return img_.size(); + } +} +scanned_img* scanner::take_first_image(void) // delete returned value, plz +{ + std::lock_guard lock(lock_img_); + scanned_img* img = NULL; + + if (img_.size()) + { + img = img_[0]; + img_.erase(img_.begin()); + ResetEvent(wait_img_); + } + + return img; +} +bool scanner::get_first_image_header(SANE_Parameters* header) +{ + std::lock_guard lock(lock_img_); + if (img_.size()) + { + img_[0]->copy_header(header); + header->bytes_per_line = img_[0]->line_bytes(); + if (header->format == SANE_FRAME_RGB) + header->depth *= 3; + + return true; + } + + return false; +} +int scanner::last_error(void) +{ + return err_; +} + +SANE_Handle scanner::handle(void) +{ + return hdev_; +} +bool scanner::is_online(void) +{ + return online_; +} +void scanner::set_online(bool online) +{ + online_ = online; +} + + +void scanner::put_image(SANE_Image* img, unsigned int* len) +{ + std::lock_guard lock(lock_img_); + img_.push_back(new scanned_img(img, fmt_)); + SetEvent(wait_img_); + if (event_cb_) + event_cb_(SANE_EVENT_IMAGE_OK, (void*)img, len, cb_param_); +} +void scanner::scan_finished(const char* desc, int err) +{ + desc_ = desc ? desc : "OK"; + err_ = err; + scanning_ = false; + SetEvent(wait_img_); + if (event_cb_) + event_cb_(SANE_EVENT_SCAN_FINISHED, (void*)desc, (unsigned int*)&err, cb_param_); +} + +// up to sane, we set the CAP_xxx according to settings display in UI ... +bool scanner::get_value_info(int sn, std::string& type, value_limit& limit) +{ + if (sn <= 0 || sn >= option_count_) + return false; + + FIND_OPTION(sn); + if (it == options_.end()) + return false; + + type = scanner::type(it->desc->type); + limit = scanner::limit(it->desc->constraint_type); + + return true; +} +bool scanner::get_value(int sn, std::list& values, std::string& now, std::string& init) +{ + if (sn <= 0 || sn >= option_count_) + return false; + + FIND_OPTION(sn); + if (it == options_.end()) + return false; + + if (scanner::type(it->desc->type) != "string" || + scanner::limit(it->desc->constraint_type) != VAL_LIMIT_ENUM) + return false; + + sane_trans::get_value_list(it->desc, &values); + init = *it->val.sv; + now = get_string(sn, it->desc->size); + + return true; +} +bool scanner::get_value(int sn, std::list& values, float& now, float& init) +{ + if (sn <= 0 || sn >= option_count_) + return false; + + FIND_OPTION(sn); + if (it == options_.end()) + return false; + + if (scanner::type(it->desc->type) != "float" || + scanner::limit(it->desc->constraint_type) != VAL_LIMIT_ENUM) + return false; + + std::list vals; + sane_trans::get_value_list(it->desc, &vals); + for(const auto& v : vals) + values.push_back(v); + + init = it->val.dv; + now = get_double(sn); + + return true; +} +bool scanner::get_value(int sn, std::list& values, bool& now, bool& init) +{ + if (sn <= 0 || sn >= option_count_) + return false; + + FIND_OPTION(sn); + if (it == options_.end()) + return false; + + values.push_back(false); + values.push_back(true); + now = get_boolean(sn); + init = it->val.bv; + + return true; +} +bool scanner::get_value(int sn, int& now, int& init, int* lower, int* upper, int* step) +{ + if (sn <= 0 || sn >= option_count_) + return false; + + FIND_OPTION(sn); + if (it == options_.end()) + return false; + + if (scanner::type(it->desc->type) != "int") + return false; + + bool ret = true; + now = get_integer(sn); + init = it->val.iv; + if (lower && upper && step) + { + *lower = *upper = *step = 0; + if (scanner::limit(it->desc->constraint_type) == VAL_LIMIT_RANGE) + { + *lower = it->desc->constraint.range->min; + *upper = it->desc->constraint.range->max; + *step = it->desc->constraint.range->quant; + } + else + ret = false; + } + + return ret; +} +bool scanner::get_value(int sn, float& now, float& init, float* lower, float* upper, float* step) +{ + if (sn <= 0 || sn >= option_count_) + return false; + + std::vector::iterator it = std::find(options_.begin(), options_.end(), sn); + if (it == options_.end()) + return false; + + if (scanner::type(it->desc->type) != "float") + return false; + + bool ret = true; + double ratio = sn == opt_ind_fill_hole_ratio_ ? 100.0f : 1.0f; + now = get_double(sn) * ratio; + init = it->val.dv * ratio; + if (lower && upper && step) + { + *lower = *upper = *step = 0; + if (scanner::limit(it->desc->constraint_type) == VAL_LIMIT_RANGE) + { + *lower = SANE_UNFIX(it->desc->constraint.range->min) * ratio; + *upper = SANE_UNFIX(it->desc->constraint.range->max) * ratio; + *step = SANE_UNFIX(it->desc->constraint.range->quant) * ratio; + } + else + ret = false; + } + + return ret; +} + +int scanner::set_value(int sn, std::string val) +{ + if (sn <= 0 || sn >= option_count_) + return HG_ERR_OUT_OF_RANGE; + + std::vector::iterator it = std::find(options_.begin(), options_.end(), sn); + if (it == options_.end()) + return HG_ERR_NO_DATA; + + if (scanner::type(it->desc->type) != "string" || + val.length() > it->desc->size) + return HG_ERR_INVALID_PARAMETER; + + char* buf = new char[it->desc->size + 20]; + int ret = HG_ERR_OK; + SANE_Int afterdo = 0; + + memset(buf, 0, it->desc->size + 20); + strcpy(buf, val.c_str()); + ret = sane_invoker::invoke_sane_control_option(hdev_, sn, SANE_ACTION_SET_VALUE, buf, &afterdo); + if (sn == opt_ind_paper_ && (ret == HG_ERR_OK || ret == HG_ERR_NOT_EXACT)) + { + auto_crop_ = paper::is_auto_crop(buf); + } + delete[] buf; + + return ret; +} +int scanner::set_value(int sn, bool val) +{ + if (sn <= 0 || sn >= option_count_) + return HG_ERR_OUT_OF_RANGE; + + std::vector::iterator it = std::find(options_.begin(), options_.end(), sn); + if (it == options_.end()) + return HG_ERR_NO_DATA; + + if (scanner::type(it->desc->type) != "bool" && + scanner::type(it->desc->type) != "button") + return HG_ERR_INVALID_PARAMETER; + + int ret = HG_ERR_OK; + SANE_Int afterdo = 0; + SANE_Bool v = val; + + ret = sane_invoker::invoke_sane_control_option(hdev_, sn, SANE_ACTION_SET_VALUE, &v, &afterdo); + + return ret; +} +int scanner::set_value(int sn, int val) +{ + if (sn <= 0 || sn >= option_count_) + return HG_ERR_OUT_OF_RANGE; + + std::vector::iterator it = std::find(options_.begin(), options_.end(), sn); + if (it == options_.end()) + return HG_ERR_NO_DATA; + + if (scanner::type(it->desc->type) != "int") + return HG_ERR_INVALID_PARAMETER; + + int ret = HG_ERR_OK; + SANE_Int afterdo = 0; + SANE_Int v = val; + + ret = sane_invoker::invoke_sane_control_option(hdev_, sn, SANE_ACTION_SET_VALUE, &v, &afterdo); + + return ret; +} +int scanner::set_value(int sn, double val) +{ + if (sn <= 0 || sn >= option_count_) + return HG_ERR_OUT_OF_RANGE; + + std::vector::iterator it = std::find(options_.begin(), options_.end(), sn); + if (it == options_.end()) + return HG_ERR_NO_DATA; + + if (scanner::type(it->desc->type) != "float") + return HG_ERR_INVALID_PARAMETER; + + if (sn == opt_ind_fill_hole_ratio_) + val /= 100.0f; + + int ret = HG_ERR_OK; + SANE_Int afterdo = 0; + SANE_Fixed v = SANE_FIX(val); + + ret = sane_invoker::invoke_sane_control_option(hdev_, sn, SANE_ACTION_SET_VALUE, &v, &afterdo); + + return ret; +} + +int scanner::twain_set_resolution(float dpi) +{ + float l = .0f, u = .0f, n = .0f, i = .0f; + + if(opt_ind_dpi_ == -1 || + !get_value(opt_ind_dpi_, n, i, &l, &u)) + return dpi >= 200.0f && dpi <= 600.0f ? HG_ERR_OK : HG_ERR_INVALID_PARAMETER; + + if (dpi <= l || dpi >= u) + return HG_ERR_INVALID_PARAMETER; + + std::vector::iterator it = std::find(options_.begin(), options_.end(), opt_ind_dpi_); + SANE_Fixed v = it->desc->type == SANE_TYPE_FIXED ? SANE_FIX(dpi) : dpi; + SANE_Int afterdo = 0; + int ret = sane_invoker::invoke_sane_control_option(hdev_, opt_ind_dpi_, SANE_ACTION_SET_VALUE, &v, &afterdo); + + dpi_ = it->desc->type == SANE_TYPE_FIXED ? SANE_UNFIX(v) : v; + + return ret; +} +float scanner::twain_get_resolution(float* init, std::vector* values, value_limit* limit) +{ + if (opt_ind_dpi_ != -1) + { + std::vector< SANEOPTION>::iterator it = std::find(options_.begin(), options_.end(), opt_ind_dpi_); + if (it != options_.end()) + { + if(init) + *init = it->val.dv; + + if (limit) + *limit = scanner::limit(it->desc->constraint_type); + if (values && (it->desc->type == SANE_TYPE_FIXED || it->desc->type == SANE_TYPE_INT)) + { + if (it->desc->constraint_type == SANE_CONSTRAINT_WORD_LIST) + { + const SANE_Word* val = it->desc->constraint.word_list; + for (SANE_Word i = 1; i < val[0]; ++i) + values->push_back(it->desc->type == SANE_TYPE_FIXED ? SANE_UNFIX(val[i]) : val[i]); + } + else if (it->desc->constraint_type == SANE_CONSTRAINT_RANGE) + { + const SANE_Range* r = it->desc->constraint.range; + values->push_back(it->desc->type == SANE_TYPE_FIXED ? SANE_UNFIX(r->min) : r->min); + values->push_back(it->desc->type == SANE_TYPE_FIXED ? SANE_UNFIX(r->max) : r->max); + } + } + } + } + if (values && values->empty()) + { + values->push_back(100.0f); + values->push_back(600.0f); + if (limit) + *limit = VAL_LIMIT_RANGE; + } + + return dpi_; +} + +int scanner::twain_set_color_mode(int twain_pixel_type) +{ + int ret = HG_ERR_DEVICE_NOT_SUPPORT; + + for (const auto& v : options_) + { + if (v.ind != opt_ind_color_mode_) + continue; + + std::string val(color_mode::from_twain_pixel_type(twain_pixel_type)); + char* buf = new char[v.desc->size + 8]; + SANE_Int afterdo = 0; + + memset(buf, 0, v.desc->size + 8); + strcpy(buf, val.c_str()); + ret = sane_invoker::invoke_sane_control_option(hdev_, v.ind, SANE_ACTION_SET_VALUE, buf, &afterdo); + delete buf; + break; + } + + return HG_ERR_OK; +} +int scanner::twain_get_color_mode(int* init, std::vector* values, value_limit* limit) +{ + int tw_pixel_type = TWPT_RGB; + + for(const auto& v : options_) + { + if (v.ind != opt_ind_color_mode_) + continue; + + if (v.desc->type == SANE_Value_Type::SANE_TYPE_STRING) + { + SANE_Int afterdo = 0; + char* now = new char[v.desc->size + 8]; + + memset(now, 0, v.desc->size + 8); + sane_invoker::invoke_sane_control_option(hdev_, v.ind, SANE_ACTION_GET_VALUE, now, &afterdo); + tw_pixel_type = color_mode::to_twain_pixel_type(now); + if (init) + *init = color_mode::to_twain_pixel_type(v.val.sv->c_str()); + if (values && limit) + { + std::list vals; + if (sane_trans::get_value_list(v.desc, &vals)) + { + *limit = VAL_LIMIT_ENUM; + for (const auto& var : vals) + values->push_back(color_mode::to_twain_pixel_type(var.c_str())); + } + } + + delete[] now; + } + break; + } + + if (values && values->empty()) + { + values->push_back(TWPT_BW); + values->push_back(TWPT_GRAY); + values->push_back(TWPT_RGB); + if (limit) + *limit = VAL_LIMIT_ENUM; + } + return tw_pixel_type; +} +int scanner::twain_set_auto_color_type(int type) +{ + unsigned int len = sizeof(type); + + return sane_invoker::invoke_sane_io_control(hdev_, IO_CTRL_CODE_SET_AUTO_COLOR_TYPE, &type, &len); +} + +int scanner::twain_get_paper_ind(void) +{ + return opt_ind_paper_; +} +int scanner::twain_set_paper_lateral(bool lateral) +{ + FIND_OPTION(opt_ind_paper_); + if (it == options_.end()) + return HG_ERR_INVALID_PARAMETER; + + std::list vals; + std::string now(get_string(opt_ind_paper_, it->desc->size)); + size_t pos = now.find(paper::lateral_title()); + int ret = HG_ERR_OK; + + if (lateral) + { + if (!paper::is_lateral(now.c_str())) + { + now += paper::lateral_title(); + sane_trans::get_value_list(it->desc, &vals); + if (std::find(vals.begin(), vals.end(), now) == vals.end()) + ret = HG_ERR_INVALID_PARAMETER; + else + { + ret = set_string(opt_ind_paper_, now, it->desc->size); + } + } + } + else + { + if (paper::is_lateral(now.c_str())) + { + size_t pos = now.find(paper::lateral_title()); + + if (pos != std::string::npos) + { + now.erase(pos); + ret = set_string(opt_ind_paper_, now, it->desc->size); + } + } + } + + return ret; +} +bool scanner::twain_is_paper_lateral(void) +{ + FIND_OPTION(opt_ind_paper_); + if (it == options_.end()) + return false; + + std::string now(get_string(opt_ind_paper_, it->desc->size)); + + return paper::is_lateral(now.c_str()); +} +int scanner::twain_set_paper_auto_match_size(bool match) +{ + FIND_OPTION(opt_ind_paper_); + if (it == options_.end()) + return HG_ERR_NOT_OPEN; + + std::string val(match ? paper::auto_size_title() : *it->val.sv); + + return set_string(opt_ind_paper_, val, it->desc->size); +} +bool scanner::twain_is_paper_auto_match_size(void) +{ + FIND_OPTION(opt_ind_paper_); + if (it == options_.end()) + return false; + + std::string now(get_string(opt_ind_paper_, it->desc->size)); + + return paper::is_auto_size(now.c_str()); +} + +int scanner::twain_set_scan_count(int count) +{ + int ret = HG_ERR_DEVICE_NOT_SUPPORT; + + if (opt_ind_scann_count_ != -1) + { + SANE_Int afterdo = 0; + char buf[80] = { 0 }; + + strcpy(buf, scan_count::scan_continous_val().c_str()); + if (count == -1) + { + ret = sane_invoker::invoke_sane_control_option(hdev_, HIWORD(opt_ind_scann_count_), SANE_ACTION_SET_VALUE, buf, &afterdo); + } + else + { + std::list vals; + std::string now(""), init(""); + + get_value(HIWORD(opt_ind_scann_count_), vals, now, init); + for (const auto& v : vals) + { + if (v != buf) + { + init = v; + break; + } + } + strcpy(buf, init.c_str()); + ret = sane_invoker::invoke_sane_control_option(hdev_, HIWORD(opt_ind_scann_count_), SANE_ACTION_SET_VALUE, buf, &afterdo); + if (ret == SANE_STATUS_GOOD) + { + SANE_Int v = count; + ret = sane_invoker::invoke_sane_control_option(hdev_, LOWORD(opt_ind_scann_count_), SANE_ACTION_SET_VALUE, &v, &afterdo); + } + } + } + + return ret; +} +int scanner::twain_get_scan_count(void) +{ + int ret = -1; + + if (opt_ind_scann_count_ != -1) + { + char buf[80] = { 0 }; + SANE_Int afterdo = 0, count = -1; + + ret = sane_invoker::invoke_sane_control_option(hdev_, HIWORD(opt_ind_scann_count_), SANE_ACTION_GET_VALUE, buf, &afterdo); + if (scan_count::scan_continous_val() == buf) + ret = -1; + else + { + sane_invoker::invoke_sane_control_option(hdev_, LOWORD(opt_ind_scann_count_), SANE_ACTION_GET_VALUE, &count, &afterdo); + ret = count; + } + } + + return ret; +} + +int scanner::twain_set_final_format(SANE_ImageType type, void* param) +{ + SANE_FinalImgFormat fmt; + unsigned int len = sizeof(fmt); + int ret = HG_ERR_OK; + + fmt.img_format = type; + fmt.detail = param; + ret = sane_invoker::invoke_sane_io_control(hdev_, IO_CTRL_CODE_SET_FINAL_IMAGE_FORMAT, &fmt, &len); + if (ret == HG_ERR_OK) + { + if (type == SANE_IMAGE_TYPE_JPG) + jpeg_quality_ = (int)param; + img_fmt_ = type; + } + + return ret; +} +int scanner::twain_get_jpeg_quality(void) +{ + return jpeg_quality_; +} +SANE_ImageType scanner::get_final_format(void) +{ + return img_fmt_; +} + +int scanner::twain_set_final_compression(int compression) +{ + SANE_Compression compr; + unsigned int len = sizeof(compr); + int ret = HG_ERR_OK; + + compr.compression = (SANE_CompressionType)compression; + compr.detail = NULL; + + ret = sane_invoker::invoke_sane_io_control(hdev_, IO_CTRL_CODE_SET_FINAL_COMPRESSION, &compr, &len); + if (ret == HG_ERR_OK || ret == HG_ERR_NOT_EXACT) + compression_ = compr.compression; + + return ret; +} +int scanner::twain_get_final_compression(int* init, std::vector* values) +{ + if (init || values) + { + SANE_Int vals[80] = { 0 }; + unsigned int len = _countof(vals) - 4; + int ret = sane_invoker::invoke_sane_io_control(hdev_, IO_CTRL_CODE_GET_FINAL_COMPRESSION, vals, &len); + + if (ret == HG_ERR_OK) + { + if (init) + *init = vals[1]; + if (values) + { + for (int i = 0; i < vals[0]; ++i) + values->push_back(vals[3 + i]); + } + } + compression_ = (SANE_CompressionType)vals[2]; + } + + return compression_; +} + +int scanner::twain_set_text_direction(double degree) +{ + int ret = HG_ERR_INVALID_PARAMETER; + std::string val(text_direction::from_twain_angle(degree)); + + if (val.length()) + { + FIND_OPTION(opt_ind_text_direction_); + if (it != options_.end()) + { + ret = set_string(opt_ind_text_direction_, val, it->desc->size); + } + } + + return ret; +} +double scanner::twain_get_text_direction(double* init, std::list* vals, value_limit* limit) +{ + double dir = .0f; + FIND_OPTION(opt_ind_text_direction_); + + if (it != options_.end()) + { + if (init) + *init = text_direction::to_twain_angle(it->val.sv->c_str()); + + if (vals) + { + std::list values; + sane_trans::get_value_list(it->desc, &values); + for (const auto& v : values) + vals->push_back(text_direction::to_twain_angle(v.c_str())); + + if (limit) + *limit = scanner::limit(it->desc->constraint_type); + } + + dir = text_direction::to_twain_angle(get_string(opt_ind_text_direction_, it->desc->size).c_str()); + } + + return dir; +} +int scanner::twain_set_text_auto_matic(bool am) +{ + FIND_OPTION(opt_ind_text_direction_); + if (it == options_.end()) + return HG_ERR_NOT_OPEN; + + std::string val(am ? text_direction::auto_val() : text_direction::from_twain_angle(0)); + + return set_string(opt_ind_text_direction_, val, it->desc->size); +} +bool scanner::twain_is_text_auto_matic(void) +{ + FIND_OPTION(opt_ind_text_direction_); + if (it == options_.end()) + return false; + + return text_direction::is_auto(get_string(opt_ind_text_direction_, it->desc->size).c_str()); +} + +int scanner::twain_set_page_duplex(bool dup) +{ + std::string val(page::from_duplex(dup)); + FIND_OPTION(opt_ind_page_); + + if (it == options_.end()) + return HG_ERR_NOT_OPEN; + + return set_string(opt_ind_page_, val, it->desc->size); +} +bool scanner::twain_is_page_duplex(void) +{ + FIND_OPTION(opt_ind_page_); + if (it == options_.end()) + return true; + + std::string now(get_string(opt_ind_page_, it->desc->size)); + + return page::is_duplex(now.c_str()); +} +int scanner::twain_set_page_discarding_blank_page(bool discard, bool receipt) +{ + std::string val(discard ? page::discard_blank_page_title(receipt) : page::from_duplex(true)); + FIND_OPTION(opt_ind_page_); + + if (it == options_.end()) + return HG_ERR_NOT_OPEN; + + return set_string(opt_ind_page_, val, it->desc->size); +} +bool scanner::twain_is_page_discarding_blank_page(bool receipt) +{ + FIND_OPTION(opt_ind_page_); + if (it == options_.end()) + return true; + + std::string now(get_string(opt_ind_page_, it->desc->size)); + + return page::is_discard_blank_page(now.c_str(), receipt); +} +int scanner::twain_set_page_fold(bool fold) +{ + std::string val(page::fold_page_title()); + FIND_OPTION(opt_ind_page_); + + if (it == options_.end()) + return HG_ERR_NOT_OPEN; + + return set_string(opt_ind_page_, val, it->desc->size); +} +bool scanner::twain_is_page_fold(void) +{ + FIND_OPTION(opt_ind_page_); + if (it == options_.end()) + return true; + + std::string now(get_string(opt_ind_page_, it->desc->size)); + + return page::is_fold(now.c_str()); +} + +int scanner::twain_set_auto_descrew(bool enable) +{ + FIND_OPTION(opt_ind_auto_descrew_); + if (it == options_.end()) + return HG_ERR_NOT_OPEN; + + SANE_Bool v = enable; + SANE_Int after = 0; + + return sane_invoker::invoke_sane_control_option(hdev_, opt_ind_auto_descrew_, SANE_ACTION_SET_VALUE, &v, &after); +} +bool scanner::twain_is_auto_descrew(void) +{ + return get_boolean(opt_ind_auto_descrew_); +} + +int scanner::twain_set_erase_black_frame(bool erase) +{ + FIND_OPTION(opt_ind_erase_black_frame_); + if (it == options_.end()) + return HG_ERR_NOT_OPEN; + + SANE_Bool v = erase; + SANE_Int after = 0; + + return sane_invoker::invoke_sane_control_option(hdev_, opt_ind_erase_black_frame_, SANE_ACTION_SET_VALUE, &v, &after); +} +bool scanner::twain_is_erase_black_frame(bool* init) +{ + FIND_OPTION(opt_ind_erase_black_frame_); + if (it == options_.end()) + return false; + + if (init) + *init = it->val.bv; + + return get_boolean(opt_ind_erase_black_frame_); +} + +int scanner::twain_set_filter(int tw_filter, bool enhance) +{ + FIND_OPTION(opt_ind_filter_); + if (it == options_.end()) + return HG_ERR_NOT_OPEN; + + std::string val(filter::from_filter_type(tw_filter, enhance)); + + return set_string(opt_ind_filter_, val, it->desc->size); +} +int scanner::twain_get_filter(bool enhance) +{ + FIND_OPTION(opt_ind_filter_); + if (it == options_.end()) + return HG_ERR_NOT_OPEN; + + std::string val(get_string(opt_ind_filter_, it->desc->size)); + + return filter::to_filter_type(val.c_str(), enhance); +} + +int scanner::twain_set_bright(double bright) +{ + FIND_OPTION(opt_ind_bright_); + if (it == options_.end()) + return HG_ERR_NOT_OPEN; + + SANE_Fixed v = SANE_FIX(bright); + SANE_Int after = 0; + + return sane_invoker::invoke_sane_control_option(hdev_, opt_ind_bright_, SANE_ACTION_SET_VALUE, &v, &after); +} +double scanner::twain_get_bright(double* init, double* lower, double* upper, double* step) +{ + FIND_OPTION(opt_ind_bright_); + if (it == options_.end()) + return .0f; + + if(lower && upper) + sane_trans::get_value_range(it->desc, lower, upper); + if (init) + *init = it->val.dv; + if (step) + *step = 1.0f; + + return get_double(opt_ind_bright_); +} + +int scanner::twain_set_contrast(double bright) +{ + FIND_OPTION(opt_ind_contrast_); + if (it == options_.end()) + return HG_ERR_NOT_OPEN; + + SANE_Fixed v = SANE_FIX(bright); + SANE_Int after = 0; + + return sane_invoker::invoke_sane_control_option(hdev_, opt_ind_contrast_, SANE_ACTION_SET_VALUE, &v, &after); +} +double scanner::twain_get_contrast(double* init, double* lower, double* upper, double* step) +{ + FIND_OPTION(opt_ind_contrast_); + if (it == options_.end()) + return .0f; + + if (lower && upper) + sane_trans::get_value_range(it->desc, lower, upper); + if (init) + *init = it->val.dv; + if (step) + *step = 1.0f; + + return get_double(opt_ind_contrast_); +} + +int scanner::twain_set_gamma(double bright) +{ + FIND_OPTION(opt_ind_gamma_); + if (it == options_.end()) + return HG_ERR_NOT_OPEN; + + SANE_Fixed v = SANE_FIX(bright); + SANE_Int after = 0; + + return sane_invoker::invoke_sane_control_option(hdev_, opt_ind_gamma_, SANE_ACTION_SET_VALUE, &v, &after); +} +double scanner::twain_get_gamma(double* init, double* lower, double* upper, double* step) +{ + FIND_OPTION(opt_ind_gamma_); + if (it == options_.end()) + return .0f; + + if (lower && upper) + sane_trans::get_value_range(it->desc, lower, upper); + if (init) + *init = it->val.dv; + if (step) + *step = 1.0f; + + return get_double(opt_ind_gamma_); +} + +int scanner::twain_set_ultrasonic_check(bool check) +{ + FIND_OPTION(opt_ind_ultrasonic_); + if (it == options_.end()) + return HG_ERR_NOT_OPEN; + + SANE_Bool v = check; + SANE_Int after = 0; + + return sane_invoker::invoke_sane_control_option(hdev_, opt_ind_ultrasonic_, SANE_ACTION_SET_VALUE, &v, &after); +} +bool scanner::twain_is_ultrasonic_check(bool* init) +{ + FIND_OPTION(opt_ind_ultrasonic_); + if (it == options_.end()) + return false; + + if (init) + *init = it->val.bv; + + return get_boolean(opt_ind_ultrasonic_); +} + +bool scanner::twain_is_auto_crop(void) +{ + return auto_crop_; +} +bool scanner::twain_is_paper_on(void) +{ + SANE_Bool on = false; + unsigned int len = sizeof(on); + + sane_invoker::invoke_sane_io_control(hdev_, IO_CTRL_CODE_GET_PAPER_ON, &on, &len); + + return on; +} +int scanner::twain_get_device_code(char* buf, unsigned int len) +{ + return sane_invoker::invoke_sane_io_control(hdev_, IO_CTRL_CODE_GET_DEVICE_CODE, buf, &len); +} + +int scanner::twain_set_sharpen(int sharpen) +{ + std::string val(sharpen::from_type(sharpen)); + FIND_OPTION(opt_ind_sharpen_); + if (it == options_.end()) + return HG_ERR_NOT_OPEN; + + return set_string(opt_ind_sharpen_, val, it->desc->size); +} +int scanner::twain_get_sharpen(void) +{ + FIND_OPTION(opt_ind_sharpen_); + if (it == options_.end()) + return SHARPEN_NONE; + + std::string now(get_string(opt_ind_sharpen_, it->desc->size)); + + return sharpen::to_type(now.c_str()); +} + +int scanner::twain_get_serial_num(char buf[]) +{ + unsigned int len = 240; + + return sane_invoker::invoke_sane_io_control(hdev_, IO_CTRL_CODE_GET_SERIAL, buf, &len); +} +int scanner::twain_get_hareware_version(char buf[]) +{ + unsigned int len = 240; + + return sane_invoker::invoke_sane_io_control(hdev_, IO_CTRL_CODE_GET_HARDWARE_VERSION, buf, &len); +} +int scanner::twain_get_ip(char buf[]) +{ + unsigned int len = 240; + + return sane_invoker::invoke_sane_io_control(hdev_, IO_CTRL_CODE_GET_IP, buf, &len); +} + +int scanner::twain_get_dogear_distance(void) +{ + SANE_Int v = 0; + unsigned int len = sizeof(v); + + sane_invoker::invoke_sane_io_control(hdev_, IO_CTRL_CODE_GET_DOGEAR_DISTANCE, &v, &len); + + return v; +} +int scanner::twain_set_dogear_distance(int dist) +{ + SANE_Int v = dist; + unsigned int len = sizeof(v); + + return sane_invoker::invoke_sane_io_control(hdev_, IO_CTRL_CODE_SET_DOGEAR_DISTANCE, &v, &len); +} + +int scanner::twain_set_power_level(int level) +{ + SANE_Power v = (SANE_Power)level; + unsigned int len = sizeof(v); + + return sane_invoker::invoke_sane_io_control(hdev_, IO_CTRL_CODE_SET_POWER_LEVEL, &v, &len); +} +int scanner::twain_get_power_level(void) +{ + SANE_Power v = SANE_POWER_NONE; + unsigned int len = sizeof(v); + + sane_invoker::invoke_sane_io_control(hdev_, IO_CTRL_CODE_GET_POWER_LEVEL, &v, &len); + + return v; +} + +int scanner::twain_set_to_be_scan(bool yes) +{ + SANE_Bool v = yes; + unsigned int len = sizeof(v); + + return sane_invoker::invoke_sane_io_control(hdev_, IO_CTRL_CODE_SET_SCAN_WHEN_PAPER_ON, &v, &len); +} +bool scanner::twain_get_to_be_scan(void) +{ + SANE_Bool v = 0; + unsigned int len = sizeof(v); + + sane_invoker::invoke_sane_io_control(hdev_, IO_CTRL_CODE_GET_SCAN_WHEN_PAPER_ON, &v, &len); + + return v; +} + +int scanner::twain_set_scan_with_hole(bool yes) +{ + SANE_Bool v = yes; + unsigned int len = sizeof(v); + + return sane_invoker::invoke_sane_io_control(hdev_, IO_CTRL_CODE_SET_SCAN_WITH_HOLE, &v, &len); +} +bool scanner::twain_get_scan_with_hole(void) +{ + SANE_Bool v = 0; + unsigned int len = sizeof(v); + + sane_invoker::invoke_sane_io_control(hdev_, IO_CTRL_CODE_GET_SCAN_WITH_HOLE, &v, &len); + + return v; +} + +int scanner::twain_set_multioutput_type(int type) +{ + FIND_OPTION(opt_ind_multi_out_); + if (it == options_.end()) + return HG_ERR_NOT_OPEN; + + std::string val(multi_out::from_twain_type(type)); + + return set_string(opt_ind_multi_out_, val, it->desc->size); +} +int scanner::twain_get_multioutput_type(void) +{ + FIND_OPTION(opt_ind_multi_out_); + if (it == options_.end()) + return MULTI_OUT_NONE; + + std::string now(get_string(opt_ind_multi_out_, it->desc->size)); + + return multi_out::to_twain_type(now.c_str()); +} + +int scanner::twain_get_flip_ind(void) +{ + return opt_ind_flip_; +} +int scanner::twain_get_rotate_bkg_ind(void) +{ + return opt_ind_rotate_bkg_; +} +int scanner::twain_get_fill_black_bkg_ind(void) +{ + return opt_ind_fill_blank_bkg_; +} +int scanner::twain_get_edge_ident_ind(void) +{ + return opt_ind_edge_ident_; +} +int scanner::twain_get_threshold_ind(void) +{ + return opt_ind_threshold_; +} +int scanner::twain_bkg_filling_method_ind(void) +{ + return opt_ind_bkg_filling_method_; +} +int scanner::twain_fill_hole_ind(void) +{ + return opt_ind_fill_hole_; +} +int scanner::twain_fill_hole_ratio_ind(void) +{ + return opt_ind_fill_hole_ratio_; +} +int scanner::twain_detach_noise_ind(void) +{ + return opt_ind_noise_; +} +int scanner::twain_detach_noise_threshold_ind(void) +{ + return opt_ind_noise_threshold_; +} +int scanner::twain_rid_red_ind(void) +{ + return opt_ind_rid_red_; +} +int scanner::twain_rid_red_hsv_ind(void) +{ + return opt_ind_rid_red_hsv_; +} +int scanner::twain_screw_detect_ind(void) +{ + return opt_ind_screw_detect_; +} +int scanner::twain_screw_detect_level_ind(void) +{ + return opt_ind_screw_detect_level_; +} +int scanner::twain_staple_detect_ind(void) +{ + return opt_ind_staple_; +} +int scanner::twain_dogear_detect_ind(void) +{ + return opt_ind_dogear_; +} +int scanner::twain_dark_sample_ind(void) +{ + return opt_ind_dark_sample_; +} +int scanner::twain_image_split_ind(void) +{ + return opt_ind_split_; +} +int scanner::twain_fade_bkground_ind(void) +{ + return opt_ind_fade_bkg_; +} +int scanner::twain_fade_bkground_val_ind(void) +{ + return opt_ind_fade_bkg_val_; +} +int scanner::twain_size_detect_ind(void) +{ + return opt_ind_size_detect_; +} + + diff --git a/huagaotwain/huagaotwain.h b/huagaotwain/huagaotwain.h new file mode 100644 index 0000000..0e25600 --- /dev/null +++ b/huagaotwain/huagaotwain.h @@ -0,0 +1,446 @@ +#pragma once +#include "huagao/hgscanner_error.h" +#include +#include +#include +#include +#include "sane_option_trans.h" + + +class sane_invoker; +class scanner; +struct _dev; + + +class refer +{ + volatile long ref_; + +public: + refer() : ref_(1) + {} +protected: + virtual ~refer() + {} + +public: + long add_ref(void) + { + return InterlockedIncrement(&ref_); + } + long release(void) + { + long ref = InterlockedDecrement(&ref_); + + if (ref <= 0) + delete this; + + return ref; + } +}; + +class scanned_img +{ + SANE_Parameters param_; + std::vector data_; + + std::string file_header(SANE_FinalImgFormat* header, float resolution); + +public: + scanned_img(SANE_Image* img, SANE_FinalImgFormat* header); + ~scanned_img(); + +public: + int width(void); + int line_bytes(void); + int height(void); + int depth(void); + int channel(void); + SANE_Frame type(void); + unsigned int bytes(void); + unsigned char* bits(void); + void copy_header(SANE_Parameters* head); +}; + +extern HMODULE me_; +namespace local_utility +{ + std::wstring reg_read(HKEY root, const wchar_t* path, const wchar_t* name); + std::wstring reg_get_app_installing_path(void); +} + +class scanner : public refer +{ + SANE_Handle hdev_; + sane_invoker* host_; + std::string name_; + std::string type_; + std::string vendor_; + std::string product_; + bool online_; + int option_count_; + std::mutex lock_img_; + std::vector img_; + SANE_FinalImgFormat *fmt_; + + typedef struct _sane_option + { + int ind; + const SANE_Option_Descriptor* desc; + union + { + bool bv; + int iv; + double dv; + std::string* sv; + }val; + bool operator==(int id) + { + return ind == id; + } + }SANEOPTION; + std::vector options_; + + float dpi_; + HANDLE wait_img_; + volatile bool scanning_; + int err_; + std::string desc_; + + void load_options(void); + void init_image_format(void); + std::string get_string(int opt, int bytes); + bool get_boolean(int opt); + int get_integer(int opt); + double get_double(int opt); + int set_string(int opt, std::string& val, int size, SANE_Int* afterdo = NULL); + + enum twain_essential + { + TWAIN_RESOLUTION, + TWAIN_PAPER_SIZE, + }; + + int opt_ind_dpi_; + int opt_ind_color_mode_; + int opt_ind_paper_; + int opt_ind_scann_count_; // MAKELONG(count, scan_continue) + int opt_ind_text_direction_; + int opt_ind_page_; + int opt_ind_auto_descrew_; + int opt_ind_erase_black_frame_; + int opt_ind_filter_; + int opt_ind_bright_; + int opt_ind_contrast_; + int opt_ind_gamma_; + int opt_ind_ultrasonic_; + int opt_ind_flip_; + int opt_ind_rotate_bkg_; + int opt_ind_fill_blank_bkg_; + int opt_ind_edge_ident_; + int opt_ind_threshold_; + int opt_ind_bkg_filling_method_; + int opt_ind_fill_hole_; + int opt_ind_fill_hole_ratio_; + int opt_ind_noise_; + int opt_ind_noise_threshold_; + int opt_ind_rid_red_; + int opt_ind_rid_red_hsv_; + int opt_ind_sharpen_; + int opt_ind_screw_detect_; + int opt_ind_screw_detect_level_; + int opt_ind_staple_; + int opt_ind_dogear_; + int opt_ind_dark_sample_; + int opt_ind_split_; + int opt_ind_fade_bkg_; + int opt_ind_fade_bkg_val_; + int opt_ind_size_detect_; + int opt_ind_multi_out_; + + SANE_ImageType img_fmt_; + int jpeg_quality_; + + SANE_CompressionType compression_; + bool auto_crop_; + + void(*event_cb_)(int, void*, unsigned int*, void*); + void* cb_param_; + +public: + scanner(sane_invoker* host, struct _dev& dev); + + static std::string type(SANE_Value_Type st); + static value_limit limit(SANE_Constraint_Type st); + +protected: + ~scanner(); + +public: + int close(void); + int start(void); + int stop(void); + void set_event_callback(void(*cb)(int, void*, unsigned int*, void*), void* param); + bool wait_image(DWORD milliseconds = -1); + int get_scanned_images(DWORD milliseconds = 0); + scanned_img* take_first_image(void); // delete returned value, plz + bool get_first_image_header(SANE_Parameters* header); + int last_error(void); + + SANE_Handle handle(void); + bool is_online(void); + void set_online(bool online); + + void put_image(SANE_Image* img, unsigned int* len); + void scan_finished(const char* desc, int err); + + // up to sane, we set the CAP_xxx according to settings display in UI ... + bool get_value_info(int sn, std::string& type, value_limit& limit); + bool get_value(int sn, std::list& values, std::string& now, std::string& init); + bool get_value(int sn, std::list& values, float& now, float& init); + bool get_value(int sn, std::list& values, bool& now, bool& init); + bool get_value(int sn, int& now, int& init, int* lower = NULL, int* upper = NULL, int* step = NULL); + bool get_value(int sn, float& now, float& init, float* lower = NULL, float* upper = NULL, float* step = NULL); + + int set_value(int sn, std::string val); + int set_value(int sn, bool val); + int set_value(int sn, int val); + int set_value(int sn, double val); + + // attribute for twain ... +public: + int twain_set_resolution(float dpi); + float twain_get_resolution(float* init = NULL, std::vector* values = NULL, value_limit* limit = NULL); + + int twain_set_color_mode(int twain_pixel_type); + int twain_get_color_mode(int* init = NULL, std::vector* values = NULL, value_limit* limit = NULL); + int twain_set_auto_color_type(int type); + + int twain_get_paper_ind(void); + int twain_set_paper_lateral(bool lateral); + bool twain_is_paper_lateral(void); + int twain_set_paper_auto_match_size(bool match); + bool twain_is_paper_auto_match_size(void); + + int twain_set_scan_count(int count); + int twain_get_scan_count(void); + + int twain_set_final_format(SANE_ImageType type, void* param); + int twain_get_jpeg_quality(void); + SANE_ImageType get_final_format(void); + + int twain_set_final_compression(int compression); + int twain_get_final_compression(int *init = NULL, std::vector* values = NULL); + + int twain_set_text_direction(double degree); + double twain_get_text_direction(double* init = NULL, std::list* vals = NULL, value_limit* limit = NULL); + int twain_set_text_auto_matic(bool am); + bool twain_is_text_auto_matic(void); + + int twain_set_page_duplex(bool dup); + bool twain_is_page_duplex(void); + int twain_set_page_discarding_blank_page(bool discard, bool receipt); + bool twain_is_page_discarding_blank_page(bool receipt); + int twain_set_page_fold(bool fold); + bool twain_is_page_fold(void); + + int twain_set_auto_descrew(bool enable); + bool twain_is_auto_descrew(void); + + int twain_set_erase_black_frame(bool erase); + bool twain_is_erase_black_frame(bool* init); + + int twain_set_filter(int tw_filter, bool enhance); + int twain_get_filter(bool enhance); + + int twain_set_bright(double bright); + double twain_get_bright(double* init = NULL, double* lower = NULL, double* upper = NULL, double* step = NULL); + + int twain_set_contrast(double bright); + double twain_get_contrast(double* init = NULL, double* lower = NULL, double* upper = NULL, double* step = NULL); + + int twain_set_gamma(double bright); + double twain_get_gamma(double* init = NULL, double* lower = NULL, double* upper = NULL, double* step = NULL); + + int twain_set_ultrasonic_check(bool check); + bool twain_is_ultrasonic_check(bool* init = NULL); + + bool twain_is_auto_crop(void); + bool twain_is_paper_on(void); + int twain_get_device_code(char* buf, unsigned int len); + + int twain_set_sharpen(int sharpen); + int twain_get_sharpen(void); + + int twain_get_serial_num(char buf[256]); + int twain_get_hareware_version(char buf[256]); + int twain_get_ip(char buf[256]); + + int twain_get_dogear_distance(void); + int twain_set_dogear_distance(int dist); + + int twain_set_power_level(int level); + int twain_get_power_level(void); + + int twain_set_to_be_scan(bool yes); + bool twain_get_to_be_scan(void); + + int twain_set_scan_with_hole(bool yes); + bool twain_get_scan_with_hole(void); + + int twain_set_multioutput_type(int type); + int twain_get_multioutput_type(void); + + int twain_get_flip_ind(void); + int twain_get_rotate_bkg_ind(void); + int twain_get_fill_black_bkg_ind(void); + int twain_get_edge_ident_ind(void); + int twain_get_threshold_ind(void); + int twain_bkg_filling_method_ind(void); + int twain_fill_hole_ind(void); + int twain_fill_hole_ratio_ind(void); + int twain_detach_noise_ind(void); + int twain_detach_noise_threshold_ind(void); + int twain_rid_red_ind(void); + int twain_rid_red_hsv_ind(void); + int twain_screw_detect_ind(void); + int twain_screw_detect_level_ind(void); + int twain_staple_detect_ind(void); + int twain_dogear_detect_ind(void); + int twain_dark_sample_ind(void); + int twain_image_split_ind(void); + int twain_fade_bkground_ind(void); + int twain_fade_bkground_val_ind(void); + int twain_size_detect_ind(void); +}; +struct delete_scanner +{ + void operator()(scanner* p) + { + p->release(); + } +}; +typedef struct _dev +{ + scanner* scanner; + std::string name; + std::string type; + std::string vendor; + std::string product; + + struct _dev() + { + scanner = NULL; + name = type = vendor = product = ""; + } + bool operator==(const char* n) + { + return name == n; + } + bool operator==(SANE_Handle h) + { + return scanner && scanner->handle() == h; + } +}SANEDEV; + + + + +class sane_invoker +{ + bool ok_; + std::wstring cfg_file_; + SANE_Int ver_; + HMODULE sane_; + HANDLE first_cb_; + SANEAPI sane_api_; + + std::mutex lock_dev_; + std::vector devices_; + + SANE_Status (*real_sane_init_)(SANE_Int* version_code, SANE_Auth_Callback authorize); + void (*real_sane_exit_)(void); + SANE_Status(*real_sane_get_devices_)(const SANE_Device*** device_list, SANE_Bool local_only); + SANE_Status(*real_sane_open_)(SANE_String_Const devicename, SANE_Handle* handle); + void (*real_sane_close_)(SANE_Handle handle); + const SANE_Option_Descriptor* (*real_sane_get_option_descriptor_)(SANE_Handle handle, SANE_Int option); + SANE_Status(*real_sane_control_option_)(SANE_Handle handle, SANE_Int option, SANE_Action action, void* value, SANE_Int* info); + SANE_Status(*real_sane_get_parameters_)(SANE_Handle handle, SANE_Parameters* params); + SANE_Status(*real_sane_start_)(SANE_Handle handle); + SANE_Status(*real_sane_read_)(SANE_Handle handle, SANE_Byte* data, SANE_Int max_length, SANE_Int* length); + void (*real_sane_cancel_)(SANE_Handle handle); + SANE_Status(*real_sane_set_io_mode_)(SANE_Handle handle, SANE_Bool non_blocking); + SANE_Status(*real_sane_get_select_fd_)(SANE_Handle handle, SANE_Int* fd); + SANE_String_Const(*real_sane_strstatus_)(SANE_Status status); + SANE_Status(*real_sane_init_ex_)(SANE_Int* version_code, sane_callback cb, void* param); + SANE_Status(*real_sane_io_control_)(SANE_Handle h, unsigned long code, void* data, unsigned* len); + + void(*log_)(int, const char*); + + bool load_sane(void); + int handle_sane_event(SANE_Handle hdev, int code, void* data, unsigned int* len); + void get_online_devices(std::vector& devs); + int get_online_device_count(void); + scanner* find_scanner(SANE_Handle hdev); + scanner* open(const char* name, int* err); + + static void no_log(int, const char*); + static int sane_callback_handler( // 注册回调的对象,需要保证该回调是多线程安全的 + SANE_Handle hdev // 产生事件的设备句柄 + , int code // 回调事件代码 + , void* data // 回调事件数据,根据事件代码有所不同,参照具体事件定义 + , unsigned int* len // 数据长度(字节),或者event_data的缓冲区长度,详细请看相应的事件代码 + , void* param // 用户自定义数据,与调用sane_init_ex传入时的保持一致 + ); // 返回值依不同的事件代码而定,通常为“0” + + static sane_invoker* inst_; + +protected: + sane_invoker(const wchar_t* path); + ~sane_invoker(); + +public: + static int load_dll(const wchar_t* path_dll, HMODULE* dll); + static bool initialize(HMODULE me); + static void uninitialize(void); + static std::string u2m(const wchar_t* u, int page = CP_ACP); + static std::wstring m2u(const char* m, int page = CP_ACP); + static std::string u2ansi(const wchar_t* u); + static std::string u2utf8(const wchar_t* u); + static std::string utf82ansi(const char* utf8); + static std::string ansi2utf8(const char* ansi); + static std::wstring utf82u(const char* utf8); + static std::wstring ansi2u(const char* ansi); + static void log_debug_info(const char* info); +#ifdef VLOG_OK + static void __cdecl log_debug_info(int bytes, const char* fmt, ...); +#endif + + static SANE_Status invoke_sane_init(SANE_Int* version_code, SANE_Auth_Callback authorize); + static void invoke_sane_exit(void); + static SANE_Status invoke_sane_get_devices(const SANE_Device*** device_list, SANE_Bool local_only); + static SANE_Status invoke_sane_open(SANE_String_Const devicename, SANE_Handle* handle); + static void invoke_sane_close(SANE_Handle handle); + static const SANE_Option_Descriptor* invoke_sane_get_option_descriptor(SANE_Handle handle, SANE_Int option); + static SANE_Status invoke_sane_control_option(SANE_Handle handle, SANE_Int option, SANE_Action action, void* value, SANE_Int* info); + static SANE_Status invoke_sane_get_parameters(SANE_Handle handle, SANE_Parameters* params); + static SANE_Status invoke_sane_start(SANE_Handle handle); + static SANE_Status invoke_sane_read(SANE_Handle handle, SANE_Byte* data, SANE_Int max_length, SANE_Int* length); + static void invoke_sane_cancel(SANE_Handle handle); + static SANE_Status invoke_sane_set_io_mode(SANE_Handle handle, SANE_Bool non_blocking); + static SANE_Status invoke_sane_get_select_fd(SANE_Handle handle, SANE_Int* fd); + static SANE_String_Const invoke_sane_strstatus(SANE_Status status); + static SANE_Status invoke_sane_init_ex(SANE_Int* version_code, sane_callback cb, void* param); + static SANE_Status invoke_sane_io_control(SANE_Handle h, unsigned long code, void* data, unsigned* len); + + static LPSANEAPI get_api(void); + +public: + static bool is_ok(void); + static std::string version(LPDWORD v = NULL); + static void get_devices(std::vector& devs); + static scanner* open_scanner(const char* name, int* err); + static int online_devices(void); +}; + + diff --git a/huagaotwain/huagaotwain.rc b/huagaotwain/huagaotwain.rc new file mode 100644 index 0000000..a3d184e --- /dev/null +++ b/huagaotwain/huagaotwain.rc @@ -0,0 +1,61 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// (壬й) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) +LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED +#pragma code_page(936) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // (壬й) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/huagaotwain/huagaotwain.vcxproj b/huagaotwain/huagaotwain.vcxproj new file mode 100644 index 0000000..67b80f6 --- /dev/null +++ b/huagaotwain/huagaotwain.vcxproj @@ -0,0 +1,184 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {c3b47ce2-27ce-4509-ab59-3c0f194f0fce} + DynamicLibrary + huagaotwain + Win32Proj + 10.0 + + + + DynamicLibrary + true + v142 + Unicode + Static + + + DynamicLibrary + false + true + v142 + Unicode + Static + + + + + + + + + + + + + true + $(SolutionDir)..\..\sdk\include\;$(IncludePath) + $(SolutionDir)..\..\release\win\$(PlatformTarget)\$(Configuration)\ + $(SolutionDir)..\..\tmp\$(PlatformTarget)\$(Configuration)\$(ProjectName)\ + + + false + $(SolutionDir)..\..\sdk\include\;$(IncludePath) + $(SolutionDir)..\..\release\win\$(PlatformTarget)\$(Configuration)\ + $(SolutionDir)..\..\tmp\$(PlatformTarget)\$(Configuration)\$(ProjectName)\ + + + + Use + Level3 + Disabled + TWPP_NO_NOTES;TWPP_IS_DS;HGSCANNER_EXPORT;CUSTOM_USBVIEW;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + true + 4996 + pch.h + + + Console + true + $(ProjectDir)twain.def + + + mkdir $(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration) +move /Y "$(OutDirFullPath)$(ProjectName).exp" "$(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration)" +move /Y "$(OutDirFullPath)$(ProjectName).lib" "$(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration)" +move /Y "$(OutDirFullPath)$(ProjectName).pdb" "$(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration)" +copy $(TargetPath) $(WinDir)\twain_32\HuaGoScan\$(ProjectName).ds /y + + + + + Level3 + Use + MaxSpeed + true + true + TWPP_NO_NOTES;TWPP_IS_DS;HGSCANNER_EXPORT;CUSTOM_USBVIEW;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + true + 4996 + pch.h + + + Console + true + true + true + $(ProjectDir)twain.def + + + mkdir $(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration) +move /Y "$(OutDirFullPath)$(ProjectName).exp" "$(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration)" +move /Y "$(OutDirFullPath)$(ProjectName).lib" "$(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration)" +move /Y "$(OutDirFullPath)$(ProjectName).pdb" "$(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration)" +copy $(TargetPath) $(WinDir)\twain_32\HuaGoScan\$(ProjectName).ds /y + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create + Create + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + + + + + + + + + + + \ No newline at end of file diff --git a/huagaotwain/huagaotwain.vcxproj.filters b/huagaotwain/huagaotwain.vcxproj.filters new file mode 100644 index 0000000..e82d13b --- /dev/null +++ b/huagaotwain/huagaotwain.vcxproj.filters @@ -0,0 +1,165 @@ + + + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms + + + {668e9513-f6db-4f9d-9e0e-76cb8b5b7882} + + + {df21031b-938a-4a08-ae64-e869e2586201} + + + + + + + + twain + + + + + + + + + + twain + + + twain\twpp + + + twain\twpp + + + twain\twpp + + + twain\twpp + + + twain\twpp + + + twain\twpp + + + twain\twpp + + + twain\twpp + + + twain\twpp + + + twain\twpp + + + twain\twpp + + + twain\twpp + + + twain\twpp + + + twain\twpp + + + twain\twpp + + + twain\twpp + + + twain\twpp + + + twain\twpp + + + twain\twpp + + + twain\twpp + + + twain\twpp + + + twain\twpp + + + twain\twpp + + + twain\twpp + + + twain\twpp + + + twain\twpp + + + twain\twpp + + + twain\twpp + + + twain\twpp + + + twain\twpp + + + twain\twpp + + + twain\twpp + + + twain\twpp + + + twain\twpp + + + twain\twpp + + + twain\twpp + + + twain\twpp + + + twain\twpp + + + twain + + + twain + + + + + + + + + + + + Resource Files + + + \ No newline at end of file diff --git a/huagaotwain/pch.cpp b/huagaotwain/pch.cpp new file mode 100644 index 0000000..bcb5590 --- /dev/null +++ b/huagaotwain/pch.cpp @@ -0,0 +1 @@ +#include "pch.h" diff --git a/huagaotwain/pch.h b/huagaotwain/pch.h new file mode 100644 index 0000000..529bbb1 --- /dev/null +++ b/huagaotwain/pch.h @@ -0,0 +1,9 @@ +#pragma once + +#include "targetver.h" + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif + +#include diff --git a/huagaotwain/resource.h b/huagaotwain/resource.h new file mode 100644 index 0000000..477d3de --- /dev/null +++ b/huagaotwain/resource.h @@ -0,0 +1,15 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ ɵİļ +// huagaotwain.rc ʹ +// + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 103 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/huagaotwain/sane_option_trans.cpp b/huagaotwain/sane_option_trans.cpp new file mode 100644 index 0000000..1216bff --- /dev/null +++ b/huagaotwain/sane_option_trans.cpp @@ -0,0 +1,630 @@ +#include "sane_option_trans.h" +#include +#include "./twain/twain_2.4.h" + + +namespace sane_trans +{ + bool get_value_list(const SANE_Option_Descriptor* desc, std::list* values) + { + if (desc->type != SANE_TYPE_STRING) + return false; + if (desc->constraint_type != SANE_CONSTRAINT_STRING_LIST) + return false; + + const SANE_String_Const* str = desc->constraint.string_list; + int ind = 0; + while (str[ind]) + values->push_back(str[ind++]); + + return true; + } + bool get_value_list(const SANE_Option_Descriptor* desc, std::list* values) + { + if (desc->type != SANE_TYPE_INT && desc->type != SANE_TYPE_FIXED) + return false; + if (desc->constraint_type != SANE_CONSTRAINT_WORD_LIST) + return false; + + const SANE_Word* val = desc->constraint.word_list; + if (desc->type == SANE_TYPE_FIXED) + { + for (int i = 0; i < val[0]; ++i) + values->push_back(SANE_UNFIX(val[i + 1])); + } + else + { + for (int i = 0; i < val[0]; ++i) + values->push_back(val[i + 1]); + } + + return true; + } + bool get_value_range(const SANE_Option_Descriptor* desc, double* lower, double* upper) + { + if (desc->type != SANE_TYPE_INT && desc->type != SANE_TYPE_FIXED) + return false; + if (desc->constraint_type != SANE_CONSTRAINT_RANGE) + return false; + + if (desc->type == SANE_TYPE_FIXED) + { + *lower = SANE_UNFIX(desc->constraint.range->min); + *upper = SANE_UNFIX(desc->constraint.range->max); + } + else + { + *lower = desc->constraint.range->min; + *upper = desc->constraint.range->max; + } + + return true; + } +} + + +namespace color_mode +{ + static char g_name[] = { "\351\242\234\350\211\262\346\250\241\345\274\217" }; // 颜色模式 + bool is_me(const char* desc_title) + { + return strcmp(g_name, desc_title) == 0; + } + + struct + { + int tw_pixel; + char op_val[80]; + }g_ops[] = { {TWPT_BW, { "\351\273\221\347\231\275" }}, // 黑白 + {TWPT_GRAY, { "256\347\272\247\347\201\260\345\272\246" }}, // 256级灰度 + {TWPT_RGB, { "24\344\275\215\345\275\251\350\211\262" }}, // 24位彩色 + {TWPT_AUTOMATIC_COLOR, {"\351\242\234\350\211\262\350\207\252\345\212\250\350\257\206\345\210\253"}} // 颜色自动识别 + }; + int to_twain_pixel_type(const char* op_val) + { + for (size_t i = 0; i < _countof(g_ops); ++i) + { + if (strcmp(g_ops[i].op_val, op_val) == 0) + return g_ops[i].tw_pixel; + } + + return TWPT_RGB; + } + std::string from_twain_pixel_type(int twpt) + { + for (size_t i = 0; i < _countof(g_ops); ++i) + { + if (g_ops[i].tw_pixel == twpt) + return g_ops[i].op_val; + } + + return g_ops[_countof(g_ops) - 1].op_val; + } +} + +namespace dpi +{ + static char g_name[] = { "\345\210\206\350\276\250\347\216\207" }; // 分辨率 + bool is_me(const char* desc_title) + { + return strcmp(g_name, desc_title) == 0; + } +} + +namespace paper +{ + static char g_name[] = { "\347\272\270\345\274\240\345\260\272\345\257\270" }; // 纸张尺寸 + bool is_me(const char* desc_title) + { + return strcmp(g_name, desc_title) == 0; + } + + static char g_lateral[] = { "\346\250\252\345\220\221" }; + bool is_lateral(const char* paper_val) + { + return strstr(paper_val, g_lateral) != NULL; + } + std::string lateral_title(void) + { + return g_lateral; + } + + static char g_auto_size[] = { "\345\214\271\351\205\215\345\216\237\345\247\213\345\260\272\345\257\270" }; // 匹配原始尺寸 + bool is_auto_size(const char* paper_val) + { + return strstr(paper_val, g_auto_size) != NULL; + } + std::string auto_size_title(void) + { + return g_auto_size; + } + + static char g_auto_crop[] = { "\346\234\200\345\244\247\346\211\253\346\217\217\345\260\272\345\257\270\350\207\252\345\212\250\350\243\201\345\210\207" }; // 最大扫描尺寸自动裁切 + bool is_auto_crop(const char* paper_val) + { + return strstr(paper_val, g_auto_crop) != NULL; + } +} + +namespace scan_count +{ + static char g_parent[] = { "\346\211\253\346\217\217\345\274\240\346\225\260" };// 扫描张数 + bool is_parent(const char* desc_title) + { + return strcmp(g_parent, desc_title) == 0; + } + static char g_name[] = { "\346\211\253\346\217\217\346\225\260\351\207\217" }; // 扫描数量 + bool is_me(const char* desc_title) + { + return strstr(desc_title, g_name); + } + std::string scan_continous_val(void) + { + return "\350\277\236\347\273\255\346\211\253\346\217\217"; // 连续扫描 + } +} + +namespace text_direction +{ + static char g_direction[] = { "\346\226\207\347\250\277\346\226\271\345\220\221" }; // 文稿方向 + bool is_me(const char* desc_title) + { + return strcmp(desc_title, g_direction) == 0; + } + struct + { + double angle; + std::string op_val; + }g_ops[] = { {.0f, "0\302\260"} + , {90.0f, "90\302\260"} + , {180.0f, "180\302\260"} + , {270.0f, "270\302\260"} + }; + static char g_auto_dir[] = { "\350\207\252\345\212\250\346\226\207\346\234\254\346\226\271\345\220\221\350\257\206\345\210\253\302\260" }; // 自动文本方向识别° + double to_twain_angle(const char* opt_val) + { + for (size_t i = 0; i < _countof(g_ops); ++i) + { + if (g_ops[i].op_val == opt_val) + return g_ops[i].angle; + } + + return g_ops[0].angle; + } + std::string from_twain_angle(double angle) + { + for (size_t i = 0; i < _countof(g_ops); ++i) + { + if (IS_DOUBLE_EQUAL(g_ops[i].angle, angle)) + return g_ops[i].op_val; + } + + return g_ops[0].op_val; + } + bool is_auto(const char* opt_val) + { + return strcmp(opt_val, g_auto_dir) == 0; + } + std::string auto_val(void) + { + return g_auto_dir; + } +} + +namespace page +{ + static char g_name[] = { "\346\211\253\346\217\217\351\241\265\351\235\242" }; // 扫描页面 + bool is_me(const char* desc_title) + { + return strcmp(g_name, desc_title) == 0; + } + + static char g_not_duplex[] = { "\345\215\225\351\235\242" }; // 单面 + static char g_duplex[] = { "\345\217\214\351\235\242" }; // 双面 + bool is_duplex(const char* opval) + { + return strcmp(opval, g_duplex) == 0; + } + std::string from_duplex(bool duplex) + { + return duplex ? g_duplex : g_not_duplex; + } + + static char g_discard_blank[] = { "\350\267\263\350\277\207\347\251\272\347\231\275\351\241\265\357\274\210\351\200\232\347\224\250\357\274\211" }; // 跳过空白页(通用) + static char g_discard_blank_receipt[] = { "\350\267\263\350\277\207\347\251\272\347\231\275\351\241\265\357\274\210\345\217\221\347\245\250\347\272\270\357\274\211" }; // 跳过空白页(发票纸) + bool is_discard_blank_page(const char* opval, bool receipt) + { + return receipt ? strcmp(g_discard_blank_receipt, opval) == 0 : + strcmp(g_discard_blank, opval) == 0; + } + std::string discard_blank_page_title(bool receipt) + { + return receipt ? g_discard_blank_receipt : g_discard_blank; + } + + static char g_fold[] = { "\345\257\271\346\212\230" }; // 对折 + bool is_fold(const char* opval) + { + return strcmp(g_fold, opval) == 0; + } + std::string fold_page_title(void) + { + return g_fold; + } + +} + +namespace auto_descrew +{ + static char g_name[] = { "\350\207\252\345\212\250\347\272\240\345\201\217" }; // 自动纠偏 + bool is_me(const char* desc_title) + { + return strcmp(g_name, desc_title) == 0; + } +} + +namespace erase_black_frame +{ + static char g_name[] = { "\346\266\210\351\231\244\351\273\221\346\241\206" }; // 消除黑框 + bool is_me(const char* desc_title) + { + return strcmp(g_name, desc_title) == 0; + } +} + +namespace filter +{ + static char g_name[] = { "\347\201\260\345\272\246\346\210\226\351\273\221\347\231\275\345\233\276\345\203\217 - \351\231\244\350\211\262" }; // 灰度或黑白图像 - 除色 + bool is_me(const char* desc_title) + { + return strcmp(g_name, desc_title) == 0; + } + + struct + { + int twfilter; + std::string opt_val; + }g_ops[] = { {TWFT_RED, "\351\231\244\347\272\242\350\211\262"} // 除红色 + , {TWFT_GREEN, "\351\231\244\347\273\277\350\211\262"} // 除绿色 + , {TWFT_BLUE, "\351\231\244\350\223\235\350\211\262"} // 除蓝色 + , {TWFT_NONE, "\344\270\215\351\231\244\350\211\262"} // 不除色 + + // 颜色增强 + // , {ENHANCE_COLOR_NONE, "\351\231\244\347\273\277\350\211\262"} // 不增强 + , {ENHANCE_COLOR_RED, "\347\272\242\350\211\262\345\242\236\345\274\272"} // 红色增强 + , {ENHANCE_COLOR_GREEN,"\347\273\277\350\211\262\345\242\236\345\274\272"} // 绿色增强 + , {ENHANCE_COLOR_BLUE, "\350\223\235\350\211\262\345\242\236\345\274\272"} // 蓝色增强 + }; + static int g_enhance_base = 4; + int to_filter_type(const char* opt_val, bool enhance) + { + if (enhance) + { + for (size_t i = g_enhance_base; i < _countof(g_ops); ++i) + { + if (g_ops[i].opt_val == opt_val) + return g_ops[i].twfilter; + } + + return ENHANCE_COLOR_NONE; + } + + for (size_t i = 0; i < g_enhance_base; ++i) + { + if (g_ops[i].opt_val == opt_val) + return g_ops[i].twfilter; + } + + return TWFT_NONE; + } + std::string from_filter_type(int filter, bool enhance) + { + if (enhance) + { + for (size_t i = g_enhance_base; i < _countof(g_ops); ++i) + { + if (g_ops[i].twfilter == filter) + return g_ops[i].opt_val; + } + } + else + { + for (size_t i = 0; i < g_enhance_base; ++i) + { + if (g_ops[i].twfilter == filter) + return g_ops[i].opt_val; + } + } + + return g_ops[g_enhance_base - 1].opt_val; + } +} + +namespace bright +{ + static char g_name[] = { "\344\272\256\345\272\246" }; // 亮度 + bool is_me(const char* desc_title) + { + return strcmp(g_name, desc_title) == 0; + } +} +namespace contrast +{ + static char g_name[] = { "\345\257\271\346\257\224\345\272\246" }; // 对比度 + bool is_me(const char* desc_title) + { + return strcmp(g_name, desc_title) == 0; + } +} +namespace gamma +{ + static char g_name[] = { "\344\274\275\347\216\233" }; // 伽玛 + bool is_me(const char* desc_title) + { + return strcmp(g_name, desc_title) == 0; + } +} + +namespace ultrasonic +{ + static char g_name[] = { "\350\266\205\345\243\260\346\263\242\346\243\200\346\265\213" }; // 超声波检测 + bool is_me(const char* desc_title) + { + return strcmp(g_name, desc_title) == 0; + } +} + +namespace flip +{ + static char g_name[] = { "\344\272\244\346\215\242\346\255\243\345\217\215\351\235\242" }; // 交换正反面 + bool is_me(const char* desc_title) + { + return strcmp(g_name, desc_title) == 0; + } +} + +namespace rotate_bg +{ + static char g_name[] = { "\350\203\214\351\235\242\346\227\213\350\275\254180\302\260" }; // 背面旋转180° + bool is_me(const char* desc_title) + { + return strcmp(g_name, desc_title) == 0; + } +} + +namespace fill_black_border +{ + static char g_name[] = { "\346\266\210\351\231\244\351\273\221\346\241\206" }; // 消除黑框 + bool is_me(const char* desc_title) + { + return strcmp(g_name, desc_title) == 0; + } +} + +namespace edge_ident +{ + static char g_name[] = { "\350\276\271\347\274\230\347\274\251\350\277\233" }; // 边缘缩进 + bool is_me(const char* desc_title) + { + return strcmp(g_name, desc_title) == 0; + } +} + +namespace threshold +{ + static char g_name[] = { "\351\230\210\345\200\274" }; // 阈值 + bool is_me(const char* desc_title) + { + return strcmp(g_name, desc_title) == 0; + } +} + +namespace bkg_filling_method +{ + static char g_name[] = { "\350\203\214\346\231\257\345\241\253\345\205\205\346\226\271\345\274\217" }; // 背景填充方式 + bool is_me(const char* desc_title) + { + return strcmp(g_name, desc_title) == 0; + } + + static char g_convex[] = { "\345\207\270\345\244\232\350\276\271\345\275\242" };// 凸多边形 + bool is_convex(const char* opval) + { + return strcmp(opval, g_convex) == 0; + } +} + +namespace fill_hole +{ + static char g_name[] = { "\347\251\277\345\255\224\347\247\273\351\231\244" }; // 穿孔移除 + bool is_me(const char* desc_title) + { + return strcmp(g_name, desc_title) == 0; + } + + static char g_ratio[] = { "\347\251\277\345\255\224\346\220\234\347\264\242\350\214\203\345\233\264\345\215\240\345\271\205\351\235\242\346\257\224\344\276\213" }; // 穿孔搜索范围占幅面比例 + bool is_ratio(const char* desc_title) + { + return strstr(desc_title, g_ratio) != NULL; + } +} + +namespace noise +{ + static char g_name[] = { "\351\273\221\347\231\275\345\233\276\345\203\217\345\231\252\347\202\271\344\274\230\345\214\226" }; // 黑白图像噪点优化 + bool is_me(const char* desc_title) + { + return strcmp(g_name, desc_title) == 0; + } + + static char g_threshold[] = { "\345\231\252\347\202\271\344\274\230\345\214\226\345\260\272\345\257\270" }; // 噪点优化尺寸 + bool is_threshold(const char* desc_title) + { + return strstr(desc_title, g_threshold) != NULL; + } +} + +namespace rid_red +{ + static char g_name[] = { "24\344\275\215\345\275\251\350\211\262\345\233\276\345\203\217 - \345\244\232\346\265\201\350\276\223\345\207\272\351\231\244\347\272\242" }; // 24位彩色图像 - 多流输出除红 + static char g_hsv[] = { "24\344\275\215\345\275\251\350\211\262\345\233\276\345\203\217 - \347\255\224\351\242\230\345\215\241\351\231\244\347\272\242" }; // 24位彩色图像 - 答题卡除红 + bool is_me(const char* desc_title, bool hsv) + { + return strcmp(hsv ? g_hsv : g_name, desc_title) == 0; + } +} + +namespace sharpen +{ + static char g_name[] = { "\351\224\220\345\214\226\344\270\216\346\250\241\347\263\212" }; // 锐化与模糊 + bool is_me(const char* desc_title) + { + return strcmp(g_name, desc_title) == 0; + } + + struct + { + int type; + std::string op_val; + }g_ops[] = { {SHARPEN_NONE, "\346\227\240"} // 无 + , {SHARPEN_NORMAL, "\351\224\220\345\214\226"} // 锐化 + , {SHARPEN_MORE, "\350\277\233\344\270\200\346\255\245\351\224\220\345\214\226"} // 进一步锐化 + , {SHARPEN_BLUR, "\346\250\241\347\263\212"} // 模糊 + , {SHARPEN_BLUR_MORE, "\350\277\233\344\270\200\346\255\245\346\250\241\347\263\212"} // 进一步模糊 + }; + int to_type(const char* opval) + { + for (size_t i = 0; i < _countof(g_ops); ++i) + { + if (g_ops[i].op_val == opval) + return g_ops[i].type; + } + + return SHARPEN_NONE; + } + std::string from_type(int type) + { + for (size_t i = 0; i < _countof(g_ops); ++i) + { + if (g_ops[i].type == type) + return g_ops[i].op_val; + } + + return g_ops[0].op_val; + } +} + +namespace screw +{ + static char g_name[] = { "\346\255\252\346\226\234\346\243\200\346\265\213" }; // 歪斜检测 + bool is_me(const char* desc_title) + { + return strcmp(g_name, desc_title) == 0; + } + + static char g_level[] = { "\346\255\252\346\226\234\346\243\200\346\265\213\345\244\215\346\235\202\345\272\246" }; // 歪斜检测复杂度 + bool is_level(const char* desc_title) + { + return strstr(desc_title, g_level) != NULL; + } +} + +namespace staple +{ + static char g_name[] = { "\350\243\205\350\256\242\346\243\200\346\265\213" }; // 装订检测 + bool is_me(const char* desc_title) + { + return strcmp(g_name, desc_title) == 0; + } +} + +namespace dogear +{ + static char g_name[] = { "\346\212\230\350\247\222\346\243\200\346\265\213" }; // 折角检测 + bool is_me(const char* desc_title) + { + return strcmp(g_name, desc_title) == 0; + } +} + +namespace sample +{ + static char g_name[] = { "\346\267\261\350\211\262\346\240\267\345\274\240" }; // 深色样张 + bool is_me(const char* desc_title) + { + return strcmp(g_name, desc_title) == 0; + } +} + +namespace split +{ + static char g_name[] = { "\345\233\276\345\203\217\346\213\206\345\210\206" }; // 图像拆分 + bool is_me(const char* desc_title) + { + return strcmp(g_name, desc_title) == 0; + } +} + +namespace fade_bkg +{ + static char g_name[] = { "\350\203\214\346\231\257\347\247\273\351\231\244" }; // 背景移除 + bool is_me(const char* desc_title) + { + return strcmp(g_name, desc_title) == 0; + } + + static char g_val[] = { "\350\203\214\346\231\257\350\211\262\345\275\251\346\265\256\345\212\250\350\214\203\345\233\264" }; // 背景色彩浮动范围 + bool is_value(const char* desc_title) + { + return strstr(desc_title, g_val) != NULL; + } +} + +namespace size_detect +{ + static char g_name[] = { "\345\260\272\345\257\270\346\243\200\346\265\213" }; // 尺寸检测 + bool is_me(const char* desc_title) + { + return strcmp(g_name, desc_title) == 0; + } +} + +namespace multi_out +{ + static char g_name[] = { "24\344\275\215\345\275\251\350\211\262\345\233\276\345\203\217-\345\244\232\346\265\201\350\276\223\345\207\272" }; // 24位彩色图像-多流输出 + bool is_me(const char* desc_title) + { + return strcmp(g_name, desc_title) == 0; + } + + struct + { + int type; + std::string op_val; + }g_ops[] = { {MULTI_OUT_NONE, "\344\270\215\351\200\211\346\213\251\350\276\223\345\207\272\346\250\241\345\274\217"} // 不选择输出模式 + , {MULTI_OUT_ALL, "\345\275\251\350\211\262+\347\201\260\345\272\246+\351\273\221\347\231\275"} // 彩色+灰度+黑白 + , {MULTI_OUT_COLOR_GRAY, "\345\275\251\350\211\262+\347\201\260\345\272\246"} // 彩色+灰度 + , {MULTI_OUT_COLOR_BW, "\345\275\251\350\211\262+\351\273\221\347\231\275"} // 彩色+黑白 + , {MULTI_OUT_GRAY_BW, "\347\201\260\345\272\246+\351\273\221\347\231\275"} // 灰度+黑白 + }; + int to_twain_type(const char* opval) + { + for (int i = 0; i < _countof(g_ops); ++i) + { + if (g_ops[i].op_val == opval) + return g_ops[i].type; + } + + return MULTI_OUT_NONE; + } + std::string from_twain_type(int type) + { + for (int i = 0; i < _countof(g_ops); ++i) + { + if (g_ops[i].type == type) + return g_ops[i].op_val; + } + + return g_ops[0].op_val; + } +} diff --git a/huagaotwain/sane_option_trans.h b/huagaotwain/sane_option_trans.h new file mode 100644 index 0000000..e551fa2 --- /dev/null +++ b/huagaotwain/sane_option_trans.h @@ -0,0 +1,230 @@ +// utilities for transfroming options between TWAIN and sane ... +// +// Date: 2022-04-14 +// + +#pragma once + +#include "sane/sane_ex.h" +#include +#include +#include + +#define TWPT_AUTOMATIC_COLOR 0x0a0c +#define IS_DOUBLE_EQUAL(a, b) fabs((a) - (b)) < .000001 + +#define ENHANCE_COLOR_NONE 0 +#define ENHANCE_COLOR_RED 1 +#define ENHANCE_COLOR_GREEN 2 +#define ENHANCE_COLOR_BLUE 3 + +#define SHARPEN_NONE 0 +#define SHARPEN_NORMAL 1 +#define SHARPEN_MORE 2 +#define SHARPEN_BLUR 3 +#define SHARPEN_BLUR_MORE 4 + +#define MULTI_OUT_NONE -1 +#define MULTI_OUT_ALL 0 +#define MULTI_OUT_COLOR_GRAY 1 +#define MULTI_OUT_COLOR_BW 2 +#define MULTI_OUT_GRAY_BW 3 + +enum value_limit +{ + VAL_LIMIT_NONE = 0, // + VAL_LIMIT_ENUM, // + VAL_LIMIT_RANGE, // +}; + +namespace sane_trans +{ + bool get_value_list(const SANE_Option_Descriptor* desc, std::list* values); + bool get_value_list(const SANE_Option_Descriptor* desc, std::list* values); + bool get_value_range(const SANE_Option_Descriptor* desc, double* lower, double* upper); +} + + +namespace color_mode +{ + bool is_me(const char* desc_title); + int to_twain_pixel_type(const char* op_val); + std::string from_twain_pixel_type(int twpt); +} + +namespace dpi +{ + bool is_me(const char* desc_title); +} + +namespace paper +{ + bool is_me(const char* desc_title); + bool is_lateral(const char* paper_val); + std::string lateral_title(void); + bool is_auto_size(const char* paper_val); + std::string auto_size_title(void); + bool is_auto_crop(const char* paper_val); +} + +namespace scan_count +{ + bool is_parent(const char* desc_title); + bool is_me(const char* desc_title); + std::string scan_continous_val(void); +} + +namespace text_direction +{ + bool is_me(const char* desc_title); + double to_twain_angle(const char* opt_val); + std::string from_twain_angle(double angle); + + bool is_auto(const char* opt_val); + std::string auto_val(void); +} + +namespace page +{ + bool is_me(const char* desc_title); + bool is_duplex(const char* opval); + std::string from_duplex(bool duplex); + bool is_discard_blank_page(const char* opval, bool receipt); + std::string discard_blank_page_title(bool receipt); + bool is_fold(const char* opval); + std::string fold_page_title(void); +} + +namespace auto_descrew +{ + bool is_me(const char* desc_title); +} + +namespace erase_black_frame +{ + bool is_me(const char* desc_title); +} + +namespace filter +{ + bool is_me(const char* desc_title); + int to_filter_type(const char* opt_val, bool enhance); + std::string from_filter_type(int filter, bool enhance); +} + +namespace bright +{ + bool is_me(const char* desc_title); +} +namespace contrast +{ + bool is_me(const char* desc_title); +} +namespace gamma +{ + bool is_me(const char* desc_title); +} + +namespace ultrasonic +{ + bool is_me(const char* desc_title); +} + +namespace flip +{ + bool is_me(const char* desc_title); +} + +namespace rotate_bg +{ + bool is_me(const char* desc_title); +} + +namespace fill_black_border +{ + bool is_me(const char* desc_title); +} + +namespace edge_ident +{ + bool is_me(const char* desc_title); +} + +namespace threshold +{ + bool is_me(const char* desc_title); +} + +namespace bkg_filling_method +{ + bool is_me(const char* desc_title); + bool is_convex(const char* opval); +} + +namespace fill_hole +{ + bool is_me(const char* desc_title); + bool is_ratio(const char* desc_title); +} + +namespace noise +{ + bool is_me(const char* desc_title); + bool is_threshold(const char* desc_title); +} + +namespace rid_red +{ + bool is_me(const char* desc_title, bool hsv/*是否为答题卡除红*/); +} + +namespace sharpen +{ + bool is_me(const char* desc_title); + int to_type(const char* opval); + std::string from_type(int type); +} + +namespace screw +{ + bool is_me(const char* desc_title); + bool is_level(const char* desc_title); +} + +namespace staple +{ + bool is_me(const char* desc_title); +} + +namespace dogear +{ + bool is_me(const char* desc_title); +} + +namespace sample +{ + bool is_me(const char* desc_title); +} + +namespace split +{ + bool is_me(const char* desc_title); +} + +namespace fade_bkg +{ + bool is_me(const char* desc_title); + bool is_value(const char* desc_title); +} + +namespace size_detect +{ + bool is_me(const char* desc_title); +} + +namespace multi_out +{ + bool is_me(const char* desc_title); + int to_twain_type(const char* opval); + std::string from_twain_type(int type); +} diff --git a/huagaotwain/targetver.h b/huagaotwain/targetver.h new file mode 100644 index 0000000..79934a3 --- /dev/null +++ b/huagaotwain/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// 包括 SDKDDKVer.h 将定义可用的最高版本的 Windows 平台。 + +//如果要为以前的 Windows 平台生成应用程序,请包括 WinSDKVer.h,并 +// 将 _WIN32_WINNT 宏设置为要支持的平台,然后再包括 SDKDDKVer.h。 + +#include diff --git a/huagaotwain/twain.def b/huagaotwain/twain.def new file mode 100644 index 0000000..f7da6af --- /dev/null +++ b/huagaotwain/twain.def @@ -0,0 +1,3 @@ +LIBRARY huagaotwain +EXPORTS + DS_Entry \ No newline at end of file diff --git a/huagaotwain/twain/huagaods.cpp b/huagaotwain/twain/huagaods.cpp new file mode 100644 index 0000000..b5339f1 --- /dev/null +++ b/huagaotwain/twain/huagaods.cpp @@ -0,0 +1,2026 @@ +#ifdef max +#undef max +#endif +#ifdef min +#undef min +#endif + +#include +#include "huagaods.hpp" +//#include "twpp/twglue.hpp" +#include +#include +#ifdef WIN32 +#include +#include +#include +#define mktemp _mktemp +#endif // WIN32 +using namespace std; + +#include "../huagaotwain.h" +#include "../ui.h" + +#define enum2str(R) #R + + +using namespace Twpp; +using namespace std::placeholders; + + +//custom define caps enum +enum CapTypeEx : unsigned short { + CAP_TYPE_EX_FILL_BLACK_BKG = 0x8004, + CAP_TYPE_EX_ROTATE_BKG_180 = 0x8005, + CAP_TYPE_EX_SCREW_DETECT = 0x8006, + CAP_TYPE_EX_ENHANCE_COLOR = 0x8007, + CAP_TYPE_EX_FILL_HOLE = 0x8018, + CAP_TYPE_EX_SCREW_DETECT_LEVEL = 0x8021, + CAP_TYPE_EX_SHARPEN = 0x8022, + CAP_TYPE_EX_HARDWARE_VERSION = 0x8025, + CAP_TYPE_EX_RID_RED = 0x8026, + CAP_TYPE_EX_FOLD = 0x8037, + CAP_TYPE_EX_STAPLE_DETECT = 0x8090, + CAP_TYPE_EX_DISCARD_BLANK_RECEIPT = 0x8091, + CAP_TYPE_EX_FILL_HOLE_RATIO = 0x8092, + CAP_TYPE_EX_FLIP = 0x8094, // switch front back + CAP_TYPE_EX_RID_RED_HSV = 0x8095, + CAP_TYPE_EX_DOGEAR_DETECT = 0x8096, + CAP_TYPE_EX_BKG_FILLING_METHOD = 0x8097, + CAP_TYPE_EX_EDGE_IDENT = 0x8098, + CAP_TYPE_EX_THRESHOLD = 0x8099, + CAP_TYPE_EX_THRESHOLD_1 = 0x8100, + CAP_TYPE_EX_DETACH_NOISE = 0x8101, + CAP_TYPE_EX_DETACH_NOISE_THRESHOLD = 0x8102, + CAP_TYPE_EX_SIZE_DETECT = 0x8103, + CAP_TYPE_EX_POWER_LEVEL = 0x8104, + CAP_TYPE_EX_ENCODE = 0x8105, + CAP_TYPE_EX_DARK_SAMPLE = 0x8016, + CAP_TYPE_EX_DOGEAR_DIST = 0x8107, + CAP_TYPE_EX_IMAGE_SPLIT = 0x8108, + CAP_TYPE_EX_FADE_BKG = 0x8109, + CAP_TYPE_EX_FADE_BKG_VALUE = 0x8110, + CAP_TYPE_EX_TO_BE_SCAN = 0x8111, + CAP_TYPE_EX_MULTI_OUT = 0x8112, + CAP_TYPE_EX_MULTI_OUT_TYPE = 0x8113, + CAP_TYPE_EX_SCAN_WITH_HOLE = 0x8114, + CAP_TYPE_EX_IP = 0x8200, + + CAP_TYPE_EX_0 = (int)CapType::CustomBase + 0x800, + CAP_TYPE_EX_1, + CAP_TYPE_EX_2, + CAP_TYPE_EX_3, + CAP_TYPE_EX_4, + CAP_TYPE_EX_5, + CAP_TYPE_EX_6, + CAP_TYPE_EX_7, + CAP_TYPE_EX_8, + CAP_TYPE_EX_9, + CAP_TYPE_EX_10, + CAP_TYPE_EX_11, + CAP_TYPE_EX_12, + CAP_TYPE_EX_13, + CAP_TYPE_EX_14, + CAP_TYPE_EX_15, + CAP_TYPE_EX_16, + CAP_TYPE_EX_17, + CAP_TYPE_EX_18, + CAP_TYPE_EX_19, + CAP_TYPE_EX_20, + CAP_TYPE_EX_21, + CAP_TYPE_EX_22, + CAP_TYPE_EX_23, + CAP_TYPE_EX_24, + CAP_TYPE_EX_25, + CAP_TYPE_EX_26, + CAP_TYPE_EX_27, + CAP_TYPE_EX_28, + CAP_TYPE_EX_29, + CAP_TYPE_EX_30, + CAP_TYPE_EX_31, + CAP_TYPE_EX_32, + CAP_TYPE_EX_33, + CAP_TYPE_EX_34, + CAP_TYPE_EX_35, + CAP_TYPE_EX_36, + CAP_TYPE_EX_37, + CAP_TYPE_EX_38, + CAP_TYPE_EX_39, + CAP_TYPE_EX_40, + CAP_TYPE_EX_41, + CAP_TYPE_EX_42, + CAP_TYPE_EX_43, + CAP_TYPE_EX_44, + CAP_TYPE_EX_45, + CAP_TYPE_EX_46, + CAP_TYPE_EX_47, + CAP_TYPE_EX_48, + CAP_TYPE_EX_49, + CAP_TYPE_EX_50, + CAP_TYPE_EX_51, + CAP_TYPE_EX_52, + CAP_TYPE_EX_53, + CAP_TYPE_EX_54, + CAP_TYPE_EX_55, + CAP_TYPE_EX_56, + CAP_TYPE_EX_57, + CAP_TYPE_EX_58, + CAP_TYPE_EX_59, + CAP_TYPE_EX_60, + CAP_TYPE_EX_61, + CAP_TYPE_EX_62, + CAP_TYPE_EX_63, + CAP_TYPE_EX_64, + CAP_TYPE_EX_65, + CAP_TYPE_EX_66, + CAP_TYPE_EX_67, + CAP_TYPE_EX_68, + CAP_TYPE_EX_69, + CAP_TYPE_EX_70, + CAP_TYPE_EX_71, + CAP_TYPE_EX_72, + CAP_TYPE_EX_73, + CAP_TYPE_EX_74, + CAP_TYPE_EX_75, + CAP_TYPE_EX_76, + CAP_TYPE_EX_77, + CAP_TYPE_EX_78, + CAP_TYPE_EX_79, + CAP_TYPE_EX_80, +}; + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// entry ... +TWPP_ENTRY(huagao_ds) + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// utilites ... +// some helper functions to handle capability stuff +template +static Result oneValGet(Msg msg, Capability& data, const T& value) { + switch (msg) { + case Msg::Get: + case Msg::GetCurrent: + case Msg::GetDefault: + data = Capability::createOneValue(data.type(), value); + return {}; + + default: + return { ReturnCode::Failure, ConditionCode::CapBadOperation }; + } +} + +static Result oneValGetString(Msg msg, Capability& data, std::string value) { + Str255 str; + str.setData(value.c_str(), value.size()); + return oneValGet(msg, data, str); +} + +template +static Result enmGet(Msg msg, Capability& data, const T& value) { + switch (msg) { + case Msg::Get: + data = Capability::createEnumeration(data.type(), { value }); + return {}; + case Msg::GetCurrent: + case Msg::GetDefault: + data = Capability::createOneValue(data.type(), value); + return {}; + + default: + return { ReturnCode::Failure, ConditionCode::CapBadOperation }; + } +} + +template +static Result oneValGetSet(Msg msg, Capability& data, T& value, const T& def) { + switch (msg) { + case Msg::Reset: + value = def; + // fallthrough + case Msg::Get: + case Msg::GetCurrent: + data = Capability::createOneValue(data.type(), value); + return {}; + + case Msg::GetDefault: + data = Capability::createOneValue(data.type(), def); + return {}; + + case Msg::Set: + value = data.currentItem(); + return {}; + + default: + return { ReturnCode::Failure, ConditionCode::CapBadOperation }; + } +} + +template +static Result oneValGetSetConst(Msg msg, Capability& data, const T& def) { + switch (msg) { + case Msg::Get: + case Msg::GetCurrent: + case Msg::GetDefault: + case Msg::Reset: + data = Capability::createOneValue(data.type(), def); + return {}; + + case Msg::Set: + return data.currentItem() == def ? + Result() : Result(ReturnCode::Failure, ConditionCode::BadValue); + + default: + return { ReturnCode::Failure, ConditionCode::CapBadOperation }; + } +} + +template +static Result enmGetSetConst(Msg msg, Capability& data, const T& def) { + switch (msg) { + case Msg::Get: + data = Capability::createEnumeration(data.type(), { def }); + return {}; + + case Msg::GetCurrent: + case Msg::GetDefault: + case Msg::Reset: + data = Capability::createOneValue(data.type(), def); + return {}; + + case Msg::Set: + return data.currentItem() == def ? + Result() : Result(ReturnCode::Failure, ConditionCode::BadValue); + + default: + return { ReturnCode::Failure, ConditionCode::CapBadOperation }; + } +} + +template +Result CapSupGetAllReset(Msg msg, Capability& data, std::initializer_list values, T1& currvalue, T2 defaultvalue, UInt32 currindex, UInt32 defaultindex) { + switch (msg) { + case Msg::Get: + data = Capability::createEnumeration(values, currindex, defaultindex); + return { ReturnCode::Success, ConditionCode::Success }; + case Msg::GetCurrent: + data = Capability::createOneValue((T2)currvalue); + return { ReturnCode::Success, ConditionCode::Success }; + case Msg::Reset: + case Msg::GetDefault: + currvalue = (T1)defaultvalue; + data = Capability::createOneValue(defaultvalue); + return { ReturnCode::Success, ConditionCode::Success }; + default: + return { ReturnCode::Failure, ConditionCode::CapBadOperation }; + } +} +template +Result CapSupGetAllResetEx(Msg msg, Capability& data, std::initializer_list values, T1& currvalue, T2 defaultvalue, UInt32 currindex, UInt32 defaultindex) { + switch (msg) { + case Msg::Get: + data = Capability::createEnumeration(cap, values, currindex, defaultindex); + return { ReturnCode::Success, ConditionCode::Success }; + case Msg::GetCurrent: + data = Capability::createOneValue(cap, (T2)currvalue); + return { ReturnCode::Success, ConditionCode::Success }; + case Msg::Reset: + case Msg::GetDefault: + currvalue = (T1)defaultvalue; + data = Capability::createOneValue(cap, defaultvalue); + return { ReturnCode::Success, ConditionCode::Success }; + default: + return { ReturnCode::Failure, ConditionCode::CapBadOperation }; + } +} + +template +Result CapSupGetAllReset(Msg msg, Capability& data, T1& currvalue, T2 defaultvalue) { + switch (msg) { + case Msg::Get: + case Msg::GetCurrent: + data = Capability::createOneValue((T2)currvalue); + return { ReturnCode::Success, ConditionCode::Success }; + case Msg::Reset: + case Msg::GetDefault: + currvalue = (T1)defaultvalue; + data = Capability::createOneValue(defaultvalue); + return { ReturnCode::Success, ConditionCode::Success }; + default: + return { ReturnCode::Failure, ConditionCode::CapBadOperation }; + } +} +template +Result CapSupGetAllResetEx(Msg msg, Capability& data, T1& currvalue, T2 defaultvalue) { + switch (msg) { + case Msg::Get: + case Msg::GetCurrent: + data = Capability::createOneValue(cap, (T2)currvalue); + return { ReturnCode::Success, ConditionCode::Success }; + case Msg::Reset: + case Msg::GetDefault: + currvalue = (T1)defaultvalue; + data = Capability::createOneValue(cap, defaultvalue); + return { ReturnCode::Success, ConditionCode::Success }; + default: + return { ReturnCode::Failure, ConditionCode::CapBadOperation }; + } +} + +template +Result cap_get_enum_values(Msg msg, Capability& data, std::list values, T& cur, T& def, UInt32 cur_ind, UInt32 def_ind) +{ + switch (msg) + { + case Msg::Get: + data = Capability::createEnumeration(cap, values.size(), cur_ind, def_ind); + //data = Capability::createArray(cap, values.size()); + { + auto arr = data.enumeration(); + int i = 0; + for (const auto& v : values) + arr[i++] = v; + } + return { ReturnCode::Success, ConditionCode::Success }; + case Msg::GetCurrent: + data = Capability::createOneValue(cap, cur); + return { ReturnCode::Success, ConditionCode::Success }; + case Msg::Reset: + case Msg::GetDefault: + data = Capability::createOneValue(cap, def); + return { ReturnCode::Success, ConditionCode::Success }; + default: + return { ReturnCode::Failure, ConditionCode::CapBadOperation }; + } +} +template +Result cap_get_one_value(Msg msg, Capability& data, T& cur, T& def, T* lower, T* upper, T* step) +{ + switch (msg) + { + case Msg::Get: + if (lower && upper && step) + { + data = Capability::createRange(cap, *lower, *upper, *step, cur, def); + return { ReturnCode::Success, ConditionCode::Success }; + } + case Msg::GetCurrent: + data = Capability::createOneValue(cap, cur); + return { ReturnCode::Success, ConditionCode::Success }; + case Msg::Reset: + case Msg::GetDefault: + data = Capability::createOneValue(cap, def); + return { ReturnCode::Success, ConditionCode::Success }; + default: + return { ReturnCode::Failure, ConditionCode::CapBadOperation }; + } +} + +template +Result CapSupGetAll(Msg msg, Capability& data, T1& currvalue, T2 defaultvalue) { + switch (msg) { + case Msg::Get: + case Msg::GetCurrent: + case Msg::GetDefault: + data = Capability::createOneValue((T2)defaultvalue); + return { ReturnCode::Success, ConditionCode::Success }; + default: + return { ReturnCode::Failure, ConditionCode::CapBadOperation }; + } +} +template +Result CapSupGetAllEx(Msg msg, Capability& data, T1& currvalue, T2 defaultvalue) { + switch (msg) { + case Msg::Get: + case Msg::GetCurrent: + case Msg::GetDefault: + data = Capability::createOneValue(defaultvalue); + return { ReturnCode::Success, ConditionCode::Success }; + default: + return { ReturnCode::Failure, ConditionCode::CapBadOperation }; + } +} + +static void copy_type(Bool& to, bool from) +{ + to = from; +} +static void copy_type(bool& to, Bool from) +{ + to = (bool)from; +} +static void copy_type(UInt32& to, int from) +{ + to = from; +} +static void copy_type(Fix32& to, double from) +{ + to = from; +} +static void copy_type(Fix32& to, float from) +{ + to = from; +} +static void copy_type(Str255& to, std::string from) +{ + to.setData(sane_invoker::utf82ansi(from.c_str()).c_str()); +} +static void copy_type(std::string& to, Str255 from) +{ + to = sane_invoker::ansi2utf8(from.data()); +} +static void copy_type(Str64& to, std::string from) +{ + to.setData(sane_invoker::utf82ansi(from.c_str()).c_str()); +} +static void copy_type(std::string& to, Str64 from) +{ + to = sane_invoker::ansi2utf8(from.data()); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// huagao_ds ... +static Identity* srcIdent = new Identity( + Version(3, 3, Language::English, Country::China, "v3.3.5.6"), + DataGroup::Image, "HUAGO", "HUAGAO Series", "Huagao scanner series"); + + +static std::once_flag oc; +huagao_ds::huagao_ds() +{ + //std::call_once(oc, [&]() { log4cplus::Initializer(); }); +} +huagao_ds::~huagao_ds() +{ + if (memoryinfo.get()) { + m_memoryfalg = false; + if (memoryinfo->joinable()) + memoryinfo->join(); + } +} + +std::string huagao_ds::get_hidedlg_path(void) +{ + char szIniFile[MAX_PATH] = { 0 }; + SHGetSpecialFolderPathA(NULL, szIniFile, CSIDL_WINDOWS, TRUE); +#ifdef MAKEHUAGAO + strcat(szIniFile, "\\twain_32\\HuaGoScan\\hidedlg.exe"); +#elif defined AUGE + strcat(szIniFile, "\\twain_32\\AuGeScan\\hidedlg.exe"); +#elif defined HANVON + strcat(szIniFile, "\\twain_32\\HanvonScan\\hidedlg.exe"); +#elif defined LANXUM + strcat(szIniFile, "\\twain_32\\LANXUMSCAN\\hidedlg.exe"); +#else // MAKEHUAGAO + strcat(szIniFile, "\\twain_32\\ZhibenScan\\hidedlg.exe"); +#endif + + return szIniFile; +} +void huagao_ds::showmsg(const char* msg, int err) +{ + ShellExecuteA(NULL, "open", huagao_ds::get_hidedlg_path().c_str(), msg, NULL, SW_HIDE); +} +void huagao_ds::scan_event(int sane_event, void* data, unsigned int* len, void* param) +{ + ((huagao_ds*)param)->on_scan_event(sane_event, data, len); +} + +const Identity& huagao_ds::defaultIdentity() noexcept { + // remember, we return a reference, therefore the identity must not be placed on the stack of this method + if (sane_invoker::is_ok()) + { + DWORD ver = 0; + std::string v(sane_invoker::version(&ver)), + n("HUAGO"), t("Huagao scanner series"), m("HUAGAO Series"); + std::vector devs; + char v32[32] = { 0 }, n32[32] = { 0 }, t32[32] = { 0 }, m32[32] = { 0 }; + + sane_invoker::get_devices(devs); + if (devs.size()) + { + n = devs[0].vendor; + t = devs[0].name; + m = devs[0].product; + } + if (ver == 0) + { + ver = MAKELPARAM(56, 0x303); + v = "v3.3.56"; + } + else + v.insert(0, "v"); + + delete srcIdent; +#define COPY_32(a) strcpy_s(v##32, _countof(v##32), v##.c_str()) + COPY_32(v); + COPY_32(n); + COPY_32(t); + COPY_32(m); + srcIdent = new Twpp::Identity(Twpp::Version((ver >> 24) & 0x0ff, (ver >> 16) & 0x0ff, Language::English, Country::China, v32), + DataGroup::Image, n32, m32, t32); + } + + return *srcIdent; +} +Result huagao_ds::selectIdentity(Twpp::Identity& ident) noexcept { + // remember, we return a reference, therefore the identity must not be placed on the stack of this method + if (sane_invoker::is_ok()) + { + DWORD ver = 0; + std::vector devs; + Version twver; + char v32[32] = { 0 }, n32[32] = { 0 }, t32[32] = { 0 }, m32[32] = { 0 }; + + sane_invoker::get_devices(devs); + if (devs.size()) + { + strcpy(m32, devs[0].type.c_str()); + strcpy(n32, devs[0].product.c_str()); + strcpy(t32, devs[0].name.c_str()); + ident = Identity(twver, DataGroup::Image, n32, m32, t32); + + return success(); + } + // show dialog to select the devices listed in devs here ... + //if (dlg.DoModal() == IDOK) + //{ + // ident = Identity(twver, DataGroup::Image, n32, m32, t32); + // return success(); + //} + //else + { + return { ReturnCode::Failure, ConditionCode::Bummer }; + } + } + + return { ReturnCode::Failure, ConditionCode::NoDs }; +} +Twpp::ConditionCode huagao_ds::condition_code_from_hg_error(int hgerr) +{ + if (hgerr == HG_ERR_OK) + return Twpp::ConditionCode::Success; + if (hgerr == HG_ERR_DEVICE_NOT_FOUND) + return Twpp::ConditionCode::CheckDeviceOnline; + if (hgerr == HG_ERR_IO) + return Twpp::ConditionCode::OperationError; + if(hgerr == HG_ERR_OUT_OF_RANGE) + return Twpp::ConditionCode::BadCap; + if(hgerr == HG_ERR_DEVICE_NOT_SUPPORT) + return Twpp::ConditionCode::BadProtocol; + if(hgerr == HG_ERR_INVALID_PARAMETER) + return Twpp::ConditionCode::BadValue; + if(hgerr == HG_ERR_ACCESS_DENIED) + return Twpp::ConditionCode::Denied; + if(hgerr == HG_ERR_OPEN_FILE_FAILED) + return Twpp::ConditionCode::FileNotFound; + if (hgerr == HG_ERR_DEVICE_PAPER_JAMMED) + return Twpp::ConditionCode::PaperJam; + if (hgerr == HG_ERR_DEVICE_DOUBLE_FEEDING) + return Twpp::ConditionCode::PaperDoubleFeed; + if (hgerr == HG_ERR_WRITE_FILE_FAILED) + return Twpp::ConditionCode::FileWriteError; + if (hgerr == HG_ERR_DEVICE_DOGEAR) + return Twpp::ConditionCode::DamagedCorner; + if (hgerr == HG_ERR_DEVICE_NO_PAPER) + return Twpp::ConditionCode::NoMedia; + + return (Twpp::ConditionCode)((int)Twpp::ConditionCode::CustomBase + hgerr); +} + +Result huagao_ds::capabilityGet(const Identity& origin, Capability& data) +{ + return capCommon(origin, Msg::Get, data); +} +Result huagao_ds::capabilityGetCurrent(const Identity& origin, Capability& data) +{ + return capCommon(origin, Msg::GetCurrent, data); +} +Result huagao_ds::capabilityGetDefault(const Identity& origin, Capability& data) +{ + return capCommon(origin, Msg::GetDefault, data); +} +Result huagao_ds::capabilityQuerySupport(const Identity&, Capability& data) +{ + auto it = m_query.find(data.type()); + MsgSupport sup = it != m_query.end() ? it->second : msgSupportEmpty; + data = Capability::createOneValue(data.type(), sup); + return success(); +} +Result huagao_ds::capabilityReset(const Identity& origin, Capability& data) +{ + return capCommon(origin, Msg::Reset, data); +} +Result huagao_ds::capabilityResetAll(const Identity& origin) +{ + for (auto& pair : m_query) { + if ((pair.second & MsgSupport::Reset) != msgSupportEmpty) { + Capability dummyCap(pair.first); + capCommon(origin, Msg::Reset, dummyCap); + } + } + + return success(); +} +Result huagao_ds::capabilitySet(const Identity& origin, Capability& data) +{ + return capCommon(origin, Msg::Set, data); +} +Result huagao_ds::eventProcess(const Identity&, Event& event) +{ + return { ReturnCode::NotDsEvent, ConditionCode::Success }; +} +Twpp::Result huagao_ds::deviceEventGet(const Twpp::Identity& origin, Twpp::DeviceEvent& data) +{ + // data = DeviceEvent::simple(sane_invoker::take_event(), "HUAGAO"); + // return success(); + + return seqError(); +} +Result huagao_ds::identityOpenDs(const Identity& id) +{ + //singleton_ = CreateMutexA(NULL, FALSE, "LookitApp"); + //if (GetLastError() == ERROR_ALREADY_EXISTS) { //ѾͬMutexõ. + // CloseHandle(singleton_); + // singleton_ = NULL; + // showmsg("ʾ", 202); + // + // return { ReturnCode::Failure, ConditionCode::CapBadOperation }; + //} + if (!sane_invoker::is_ok()) + sane_invoker::initialize(me_); + if (!sane_invoker::is_ok()) + { + CloseHandle(singleton_); + singleton_ = NULL; + return bummer(); + } + + Identity target(id); + Result result = huagao_ds::selectIdentity(target); + if (scanner_.get()) + scanner_.reset(); + + if (result.returnCode() != ReturnCode::Success) + { + CloseHandle(singleton_); + singleton_ = NULL; + sane_invoker::uninitialize(); + return result; + } + + int err = 0; + scanner_.reset(sane_invoker::open_scanner(target.productName().begin(), &err)); + if (!scanner_.get()) + { + //CloseHandle(singleton_); + //singleton_ = NULL; + + sane_invoker::uninitialize(); + 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::scan_event, this); + init_support_caps(); + + return success(); +} +Result huagao_ds::identityCloseDs(const Identity&) +{ + ui_.reset(); + if (scanner_.get()) + { + scanner_.reset(); + } + if (singleton_) + { + CloseHandle(singleton_); + singleton_ = NULL; + } + sane_invoker::uninitialize(); + + return success(); +} +Result huagao_ds::pendingXfersGet(const Identity&, PendingXfers& data) +{ + if (!scanner_.get()) + return seqError(); + + data.setCount(scanner_->get_scanned_images(-1)); + return success(); +} +Result huagao_ds::pendingXfersEnd(const Identity& id, PendingXfers& data) +{ + return pendingXfersGet(id, data); +} +Result huagao_ds::pendingXfersReset(const Identity&, PendingXfers& data) +{ + data.setCount(0); + if (scanner_.get()) + scanner_->stop(); + + //if (scanner.get()) + //{ + // scanner->Stop_scan(); + // scanner->reset(); + // scanner->ResetScanner(); + //} + + return success(); +} +Result huagao_ds::setupMemXferGet(const Identity&, SetupMemXfer& data) +{ + SANE_Parameters head; + + if (!scanner_.get() || scanner_->get_scanned_images() == 0) + return seqError(); + + if (scanner_->get_first_image_header(&head)) + { + data.setMinSize(head.bytes_per_line); + data.setPreferredSize(head.bytes_per_line * head.lines); + data.setMaxSize(head.bytes_per_line * head.lines); + + return success(); + } + else + return badValue(); +} +Result huagao_ds::userInterfaceDisable(const Identity&, UserInterface& ui) +{ + ui_->hide_ui(); + + return success(); +} +Result huagao_ds::userInterfaceEnable(const Identity&, UserInterface& ui) +{ + if (!ui.showUi()) + { + if (m_bIndicator) + ui_->show_main_ui(sane_invoker::get_api()); + return scanner_->start() == HG_ERR_OK ? success() : seqError(); + } + + return showTwainUI(ui); +} +Result huagao_ds::userInterfaceEnableUiOnly(const Identity&, UserInterface& ui) +{ + // as a minimal source, we do not support GUI that just saves settings + return showTwainUI(ui, true); +} +Result huagao_ds::imageInfoGet(const Identity&, ImageInfo& data) +{ + SANE_Parameters head; + + if (!scanner_.get()) + return seqError(); + if (!scanner_->wait_image()) + return bummer(); + + if (scanner_->get_first_image_header(&head)) + { + data.setBitsPerPixel(head.depth); + data.setHeight(head.lines); + data.setPixelType(head.depth == 24 ? PixelType::Rgb : PixelType::Gray); + data.setPlanar(false); + data.setWidth(head.pixels_per_line); + data.setXResolution(scanner_->twain_get_resolution()); + data.setYResolution(scanner_->twain_get_resolution()); + data.compression(Compression::None); + } + + return success(); +} +Result huagao_ds::imageLayoutGet(const Identity&, ImageLayout& data) +{ + SANE_Parameters head = { 0 }; + + if (!scanner_.get() || scanner_->get_scanned_images() == 0) + return seqError(); + + scanner_->get_first_image_header(&head); + data.setDocumentNumber(1); + data.setFrameNumber(1); + data.setPageNumber(1); + data.setFrame(Frame(0, 0, static_cast(head.pixels_per_line) / scanner_->twain_get_resolution(), static_cast(head.lines) / scanner_->twain_get_resolution())); + + return success(); +} +Result huagao_ds::imageLayoutGetDefault(const Identity& origin, ImageLayout& data) +{ + return imageLayoutGet(origin, data); +} +Result huagao_ds::imageLayoutSet(const Identity& origin, ImageLayout& lay) +{ + // we dont support setting image frame + + ImageLayout def; + imageLayoutGetDefault(origin, def); + + return lay.frame() == def.frame() ? success() : badValue(); +} +Result huagao_ds::imageLayoutReset(const Identity& origin, ImageLayout& data) +{ + return imageLayoutGet(origin, data); +} +Result huagao_ds::imageMemXferGet(const Identity& origin, ImageMemXfer& data) +{ + if (!scanner_.get() || scanner_->get_scanned_images() == 0) + return seqError(); + + scanned_img *img = scanner_->take_first_image(); + unsigned char *src = img->bits() + img->bytes() - img->line_bytes(), + *dst = NULL; + + data.setBytesPerRow(img->line_bytes()); + data.setColumns(img->width()); + data.setRows(img->height()); + data.setBytesWritten(img->bytes()); + data.setXOffset(0); + data.setYOffset(0); + data.setCompression(Compression::None); + dst = (unsigned char*)data.memory().data().data(); + for (int i = 0; i < img->height(); ++i, src -= img->line_bytes(), dst += img->line_bytes()) + std::copy(src, src + img->line_bytes(), dst); + delete img; + + return success(); +} +Result huagao_ds::imageNativeXferGet(const Identity& id, ImageNativeXfer& data) +{ + if (!scanner_.get() || scanner_->get_scanned_images() == 0) + return seqError(); + + scanned_img* img = scanner_->take_first_image(); + + if (!img) + return seqError(); + if (data) + data.release(); + data = ImageNativeXfer(img->bytes()); + std::copy(img->bits(), img->bits() + img->bytes(), data.data().data()); + delete img; + + return { ReturnCode::XferDone, ConditionCode::Success }; +} +Twpp::Result huagao_ds::pendingXfersStopFeeder(const Identity& origin, PendingXfers& data) +{ + // sane_invoker::invoke_sane_cancel(); + + return success(); +} +Twpp::Result huagao_ds::imageFileXferGet(const Twpp::Identity& origin) +{ + // assume that the file format has set before start-scanning, so we write-down the image content to file directly here ... + if (!scanner_.get() || scanner_->get_scanned_images() == 0) + return seqError(); + + scanned_img *img = scanner_->take_first_image(); + Twpp::Result ret = seqError(); + FILE* dst = NULL; + + if (img) + { + dst = fopen(m_fileXfer.filePath().string().c_str(), "wb"); + ret = { ReturnCode::Failure, ConditionCode::FileWriteError }; + if (dst) + { + if(fwrite(img->bits(), 1, img->bytes(), dst) == img->bytes()) + ret = Result(ReturnCode::XferDone, ConditionCode::Success); + + fclose(dst); + } + + delete img; + } + + return ret; +} +Twpp::Result huagao_ds::setupFileXferGet(const Twpp::Identity& origin, Twpp::SetupFileXfer& data) +{ + data.setFilePath(m_fileXfer.filePath()); + data.setFormat(m_fileXfer.format()); + return success(); +} +Twpp::Result huagao_ds::setupFileXferGetDefault(const Twpp::Identity& origin, Twpp::SetupFileXfer& data) +{ + Str255 str("HGTwain.bmp"); + data.setFilePath(str); + data.setFormat(ImageFileFormat::Bmp); + return success(); +} +Twpp::Result huagao_ds::setupFileXferSet(const Twpp::Identity& origin, Twpp::SetupFileXfer& data) +{ + m_fileXfer.setFilePath(data.filePath()); + m_fileXfer.setFormat(data.format()); + return success(); +} +Twpp::Result huagao_ds::setupFileXferReset(const Twpp::Identity& origin, Twpp::SetupFileXfer& data) +{ + m_fileXfer.setFormat(Twpp::ImageFileFormat::Bmp); + std::string templateName = "HG"; + char* tempPath = mktemp((char*)templateName.c_str()); + if (tempPath) { + Str255 str; + str.setData(tempPath, strlen(tempPath)); + m_fileXfer.setFilePath(str); + return success(); + } + + return badProtocol(); +} +Result huagao_ds::call(const Identity& origin, DataGroup dg, Dat dat, Msg msg, void* data) { + try { + // we can override almost anything from SourceFromThis, even the top-most source instance call + //FileTools::write_log("D:\\1.txt", "call:datagroup-"+to_string((int)dg)+"dat-"+to_string(int(dat))+"msg-"+to_string(int(msg))); + return Base::call(origin, dg, dat, msg, data); + } + catch (const CapabilityException& e) { + //FileTools::writelog(log_ERROR, e.what()); + return badValue(); + } +} +Result huagao_ds::customDataGet(const Twpp::Identity& origin, Twpp::CustomData& data) +{ + // get user setting from local file ... + + return success(); +} +Result huagao_ds::customDataSet(const Twpp::Identity& origin, Twpp::CustomData& data) +{ + // write user setting to local file ... + + return success(); +} + +void huagao_ds::CapabilityPrintf(Twpp::Msg msg, std::string capability, std::string value) +{ + +} +Result huagao_ds::capCommon(const Identity&, Msg msg, Capability& data) { + auto it = m_caps.find(data.type()); + if (it != m_caps.end()) { + return (it->second)(msg, data); + } + + return capUnsupported(); +} +Twpp::Result huagao_ds::showTwainUI(Twpp::UserInterface& data, bool bUiOnly) +{ + // display user UI ... (setting UI, can we show my own main window here ?) + LPSANEAPI api = sane_invoker::get_api(); + + if (bUiOnly) + ui_->show_setting_ui(api, false); + else + ui_->show_main_ui(api); + + return success(); +} +void huagao_ds::init_support_caps(void) +{ + m_query.clear(); + m_caps.clear(); + + m_query[CapType::SupportedCaps] = msgSupportGetAll; + m_caps[CapType::SupportedCaps] = [this](Msg msg, Capability& data) { + if ((msg == Msg::Get) || (Msg::GetCurrent == msg) || (Msg::GetDefault == msg)) { + data = Capability::createArray(m_caps.size()); + auto arr = data.array(); + UInt32 i = 0; + for (const auto& kv : m_caps) { + arr[i] = kv.first; + i++; + } + return success(); + } + else + return capBadOperation(); + }; + + m_query[CapType::XferCount] = msgSupportGetAllSetReset; + m_caps[CapType::XferCount] = [this](Msg msg, Capability& data) -> Result { + if (msg == Msg::Set) { + auto item = data.currentItem(); + if (item > 65535 || item < -1 || item == 0) { + return badValue(); + } + return scanner_->twain_set_scan_count(item) == HG_ERR_OK ? success() : badValue(); + } + Int16 tmp_count = scanner_->twain_get_scan_count(); + return oneValGetSet(msg, data, tmp_count, -1); + }; + + if (ui_->is_ok()) + { + m_query[CapType::UiControllable] = msgSupportGetAll; + m_caps[CapType::UiControllable] = std::bind(oneValGet, _1, _2, Bool(true)); + } + + m_query[CapType::DeviceOnline] = msgSupportGetAll; + m_caps[CapType::DeviceOnline] = [this](Msg msg, Capability& data) -> Result { + CapabilityPrintf(msg, enum2str(CapType::DeviceOnline)); + switch (msg) { + case Msg::Get: + case Msg::GetCurrent: + case Msg::GetDefault: + if(scanner_.get()) + data = Capability::createOneValue((Twpp::Bool)scanner_->is_online()); + else + data = Capability::createOneValue((Twpp::Bool)(sane_invoker::online_devices() > 0)); + return success(); + + default: + return { ReturnCode::Failure, ConditionCode::CapBadOperation }; + } + }; + + m_query[CapType::ICompression] = msgSupportGetAllSetReset; + m_caps[CapType::ICompression] = [this](Msg msg, Capability& data)->Result { + if (!scanner_.get()) + return seqError(); + if (msg == Msg::Set || msg == Msg::Reset) + { + int mech = (int)data.currentItem(); + if (msg == Msg::Reset) + scanner_->twain_get_final_compression(&mech); + return scanner_->twain_set_final_compression(mech) == HG_ERR_OK ? success() : badValue(); + } + std::vector values; + std::list vals; + Compression Now, Init; + UInt32 ni = 0, ii = 0; + int init = 0, now = scanner_->twain_get_final_compression(&init, &values); + Now = (Compression)now; + Init = (Compression)init; + for (const auto& v : values) + vals.push_back((Compression)v); + ni = std::distance(values.begin(), std::find(values.begin(), values.end(), now)); + ii = std::distance(values.begin(), std::find(values.begin(), values.end(), init)); + return cap_get_enum_values(msg, data, vals, Now, Init, ni, ii); + }; + + m_query[CapType::IUnits] = msgSupportGetAllSetReset; + m_caps[CapType::IUnits] = std::bind(enmGetSetConst, _1, _2, Unit::Inches); + + m_query[CapType::IBitDepth] = msgSupportGetAllSetReset; + m_caps[CapType::IBitDepth] = [this](Msg msg, Capability& data) -> Result { + if (Msg::Set == msg) { + auto mech = data.currentItem(); + int ret = HG_ERR_INVALID_PARAMETER; + if (mech == 1) + ret = scanner_->twain_set_color_mode((int)PixelType::BlackWhite); + else if(mech == 8) + ret = scanner_->twain_set_color_mode((int)PixelType::Gray); + else if(mech == 24) + ret = scanner_->twain_set_color_mode((int)PixelType::Rgb); + return ret == HG_ERR_OK ? success() : badValue(); + } + UINT16 twpt = scanner_->twain_get_color_mode(); + if (twpt == (int)PixelType::BlackWhite) + twpt = 1; + else if (twpt == (int)PixelType::Gray) + twpt = 8; + else + twpt = 24; + + return CapSupGetAllReset(msg, data, twpt, 24); + }; + + m_query[CapType::IBitOrder] = msgSupportGetAllSetReset; + m_caps[CapType::IBitOrder] = std::bind(oneValGetSetConst, _1, _2, BitOrder::MsbFirst); + + m_query[CapType::IPlanarChunky] = msgSupportGetAllSetReset; + m_caps[CapType::IPlanarChunky] = std::bind(enmGetSetConst, _1, _2, PlanarChunky::Chunky); + + m_query[CapType::IXResolution] = msgSupportGetAllSetReset; + m_caps[CapType::IXResolution] = [this](Msg msg, Capability& data) { + if (!scanner_.get()) + return seqError(); + std::vector values; + value_limit limit = VAL_LIMIT_NONE; + float init = .0f, now = .0f; + switch (msg) { + case Msg::Get: + now = scanner_->twain_get_resolution(&init, &values, &limit); + if (limit == VAL_LIMIT_RANGE) + { + data = Capability::createRange(Fix32(values[0]), Fix32(values[1]), Fix32(50.0f), Fix32(now), Fix32(init)); + return success(); + } + else if (limit == VAL_LIMIT_ENUM) + { + std::list vals; + Fix32 Now, Init; + UInt32 ni, ii; + for (const auto& v : values) + { + Fix32 f; + copy_type(f, v); + vals.push_back(f); + } + copy_type(Now, now); + copy_type(Init, init); + ni = std::distance(vals.begin(), std::find(vals.begin(), vals.end(), Now)); + ii = std::distance(vals.begin(), std::find(vals.begin(), vals.end(), Init)); + return cap_get_enum_values(msg, data, vals, Now, Init, ni, ii); + } + case Msg::GetCurrent: + now = scanner_->twain_get_resolution(); + data = Capability::createOneValue(Fix32(now)); + return success(); + case Msg::GetDefault: + now = scanner_->twain_get_resolution(&init); + data = Capability::createOneValue(Fix32(init)); + return success(); + case Msg::Reset: + now = scanner_->twain_get_resolution(&init); + data = Capability::createOneValue(Fix32(init)); + case Msg::Set: { + auto mech = data.currentItem(); + return scanner_->twain_set_resolution((float)mech) == HG_ERR_OK ? success() : badValue(); + } + default: + return capBadOperation(); + } + }; + + m_query[CapType::IYResolution] = msgSupportGetAllSetReset; + m_caps[CapType::IYResolution] = m_caps[CapType::IXResolution]; + + m_query[CapType::IXNativeResolution] = msgSupportGetAll; + m_caps[CapType::IXNativeResolution] = std::bind(enmGet, _1, _2, Fix32(200.0)); + + m_query[CapType::IYNativeResolution] = msgSupportGetAll; + m_caps[CapType::IYNativeResolution] = m_caps[CapType::IXNativeResolution]; + + m_query[CapType::IPhysicalWidth] = msgSupportGetAll; + m_caps[CapType::IPhysicalWidth] = [this](Msg msg, Capability& data) -> Result { + switch (msg) { + case Msg::Get: + case Msg::GetCurrent: + case Msg::GetDefault: + { + float init = 10.0f; + SANE_Parameters param = { 0 }; + if (scanner_.get() && scanner_->get_first_image_header(¶m)) + init = param.bytes_per_line / scanner_->twain_get_resolution(); + data = Capability::createOneValue(data.type(), Fix32(init)); + return success(); + } + default: + return { ReturnCode::Failure, ConditionCode::CapBadOperation }; + } + }; + + m_query[CapType::IPhysicalHeight] = msgSupportGetAll; + m_caps[CapType::IPhysicalHeight] = [this](Msg msg, Capability& data) -> Result { + switch (msg) { + case Msg::Get: + case Msg::GetCurrent: + case Msg::GetDefault: + { + float init = 10.0f; + SANE_Parameters param = { 0 }; + if (scanner_.get() && scanner_->get_first_image_header(¶m)) + init = param.lines / scanner_->twain_get_resolution(); + data = Capability::createOneValue(data.type(), Fix32(init)); + return success(); + } + default: + return { ReturnCode::Failure, ConditionCode::CapBadOperation }; + } + }; + + m_query[CapType::IPixelFlavor] = msgSupportGetAllSetReset; + m_caps[CapType::IPixelFlavor] = std::bind(enmGetSetConst, _1, _2, PixelFlavor::Chocolate); + + m_query[CapType::IXferMech] = msgSupportGetAllSetReset; + m_caps[CapType::IXferMech] = [this](Msg msg, Capability& data) -> Result { + if (Msg::Set == msg) { + auto mech = data.currentItem(); + if (mech == XferMech::Native || mech == XferMech::Memory || mech == XferMech::File) { + m_capXferMech = mech; + return success(); + } + else { + return badValue(); + } + } + return CapSupGetAllReset(msg, data, { XferMech::Native, XferMech::File, XferMech::Memory }, m_capXferMech, XferMech::Native, (int)m_capXferMech, 0); + }; + + m_query[CapType::IPixelType] = msgSupportGetAllSetReset; + m_caps[CapType::IPixelType] = [this](Msg msg, Capability& data) -> Result { + if (!scanner_.get()) + return seqError(); + if (Msg::Reset == msg) + { + int init = 0; + scanner_->twain_get_color_mode(&init); + data = Capability::createOneValue((Twpp::PixelType)init); + msg = Msg::Set; + } + if (Msg::Set == msg) { + auto mech = data.currentItem(); + return scanner_->twain_set_color_mode((int)mech) == HG_ERR_OK ? success() : badValue(); + } + std::vector values; + value_limit limit = VAL_LIMIT_NONE; + int init = 0, now = 0; + switch (msg) { + case Msg::Get: + now = scanner_->twain_get_color_mode(&init, &values, &limit); + //if (limit == VAL_LIMIT_RANGE) + //{ + // data = Capability::createRange((Twpp::PixelType)(values[0]), (Twpp::PixelType)(values[1]), (Twpp::PixelType)(1), (Twpp::PixelType)(now), (Twpp::PixelType)(init)); + // return success(); + //} + if (limit == VAL_LIMIT_ENUM) + { + std::list vals; + UInt32 ni, ii; + Twpp::PixelType Init = (Twpp::PixelType)init, Now = (Twpp::PixelType)now; + for (const auto& v : values) + vals.push_back((Twpp::PixelType)v); + ni = std::distance(vals.begin(), std::find(vals.begin(), vals.end(), (Twpp::PixelType)now)); + ii = std::distance(vals.begin(), std::find(vals.begin(), vals.end(), (Twpp::PixelType)init)); + return cap_get_enum_values(msg, data, vals, Now, Init, ni, ii); + } + case Msg::GetCurrent: + now = scanner_->twain_get_color_mode(); + data = Capability::createOneValue((Twpp::PixelType)now); + return success(); + case Msg::GetDefault: + now = scanner_->twain_get_color_mode(&init); + data = Capability::createOneValue((Twpp::PixelType)init); + return success(); + } + return capBadOperation(); + }; + + m_query[CapType::IAutomaticColorEnabled] = msgSupportGetAllSetReset; + m_caps[CapType::IAutomaticColorEnabled] = [this](Msg msg, Capability& data)->Result { + if (Msg::Set == msg) { + auto mech = data.currentItem(); + scanner_->twain_set_color_mode(mech ? TWPT_AUTOMATIC_COLOR : (int)PixelType::Rgb); + return success(); + } + int twpt = scanner_->twain_get_color_mode() == TWPT_AUTOMATIC_COLOR ? 1 : 0; + return CapSupGetAllReset(msg, data, { FALSE,TRUE }, twpt, false, twpt ? 1 : 0, 0); + }; + + m_query[CapType::IAutomaticColorNonColorPixelType] = msgSupportGetAllSetReset; + m_caps[CapType::IAutomaticColorNonColorPixelType] = [this](Msg msg, Capability& data)->Result { + if (msg == Msg::Set) { + auto mech = data.currentItem(); + if (scanner_->twain_get_color_mode() == TWPT_AUTOMATIC_COLOR) { + if ((UInt16)mech == 0 || (UInt16)mech == 1) { + if (scanner_->twain_set_auto_color_type((int)mech) == HG_ERR_OK) + { + automaticcolortype_ = (UInt16)mech; + return success(); + } + } + } + return seqError(); + } + return CapSupGetAllReset(msg, data, { PixelType::BlackWhite, PixelType::Gray }, automaticcolortype_, PixelType::Gray, automaticcolortype_, 1); + }; + + m_query[CapType::IJpegQuality] = msgSupportGetAllSetReset; + m_caps[CapType::IJpegQuality] = [this](Msg msg, Capability& data)->Result { + if (Msg::Set == msg) { + auto mech = data.currentItem(); + if ((int)mech <= 0 || (int)mech > 100) + return badValue(); + return scanner_->twain_set_final_format(SANE_IMAGE_TYPE_JPG, (void*)mech) == HG_ERR_OK ? success() : badValue(); + } + unsigned short q = scanner_->twain_get_jpeg_quality(); + return CapSupGetAllResetEx(msg, data, q, 80); + }; + + m_query[CapType::IOrientation] = msgSupportGetAllSetReset; + m_caps[CapType::IOrientation] = [this](Msg msg, Capability& data) -> Result { + CapabilityPrintf(msg, enum2str(CapTypeEx::IOrientation), msg == Msg::Set ? to_string((int)data.currentItem()) : ""); + if (Msg::Set == msg) { + auto mech = data.currentItem(); + return scanner_->twain_set_paper_lateral(mech == Orientation::Landscape) ? success() : badValue(); + } + int lateral = scanner_->twain_is_paper_lateral() ? (int)Orientation::Landscape : (int)Orientation::Portrait; + return CapSupGetAllReset(msg, data, { Orientation::Portrait, Orientation::Landscape }, lateral, Orientation::Portrait, lateral == 0 ? 0 : 1, 0); + }; + + m_query[CapType::IRotation] = msgSupportGetAllSetReset; + m_caps[CapType::IRotation] = [this](Msg msg, Capability& data) -> Result { + if (Msg::Set == msg) { + auto res = data.currentItem(); + return scanner_->twain_set_text_direction(res.toFloat()) == HG_ERR_OK ? success() : badValue(); + } + double init = .0f, now = .0f; + std::list values; + value_limit limit = VAL_LIMIT_NONE; + now = scanner_->twain_get_text_direction(&init, &values, &limit); + + Fix32 Init = Fix32(init), Now = Fix32(now); + std::list vls; + UInt32 i = 0, n = 0; + for (const auto& v : values) + vls.push_back(Fix32(v)); + i = std::distance(vls.begin(), std::find(vls.begin(), vls.end(), Init)); + n = std::distance(vls.begin(), std::find(vls.begin(), vls.end(), Now)); + + return cap_get_enum_values(msg, data, vls, Now, Init, n, i); + }; + + m_query[CapType::EnableDsUiOnly] = msgSupportGetAll; + m_caps[CapType::EnableDsUiOnly] = std::bind(enmGet, _1, _2, Bool(true)); + + m_query[CapType::PaperDetectable] = msgSupportGetAll; + m_caps[CapType::PaperDetectable] = std::bind(oneValGet, _1, _2, Bool(true)); + + m_query[CapType::FeederEnabled] = msgSupportGetAllSetReset; + m_caps[CapType::FeederEnabled] = [this](Msg msg, Capability& data) -> Result { + CapabilityPrintf(msg, enum2str(CapType::FeederEnabled), msg == Msg::Set ? to_string((int)data.currentItem()) : ""); + if (Msg::Set == msg) { + auto mech = data.currentItem(); + m_bFeederEnabled = mech; + return success(); + } + return CapSupGetAllReset(msg, data, m_bFeederEnabled, Bool(true)); + }; + + m_query[CapType::Duplex] = msgSupportGetAll; + m_caps[CapType::Duplex] = std::bind(oneValGet, _1, _2, Duplex::OnePass); + + m_query[CapType::DuplexEnabled] = msgSupportGetAllSetReset; + m_caps[CapType::DuplexEnabled] = [this](Msg msg, Capability& data) -> Result { + if (Msg::Set == msg) { + bool mech = data.currentItem(); + return scanner_->twain_set_page_duplex(mech) == HG_ERR_OK ? success() : badValue(); + } + BYTE dup = scanner_->twain_is_page_duplex(); + return CapSupGetAllReset(msg, data, dup, Bool(true)); + }; + + m_query[CapType::AutoFeed] = msgSupportGetAllSetReset; + m_caps[CapType::AutoFeed] = [this](Msg msg, Capability& data) -> Result { + if (Msg::Set == msg) { + auto mech = data.currentItem(); + m_bAutoFeed = mech; + return success(); + } + return CapSupGetAllReset(msg, data, { false,true }, m_bAutoFeed, true, m_bAutoFeed ? 1 : 0, 1); + }; + + m_query[CapType::IImageFileFormat] = msgSupportGetAllSetReset; + m_caps[CapType::IImageFileFormat] = [this](Msg msg, Capability& data) -> Result { + CapabilityPrintf(msg, enum2str(CapType::IImageFileFormat), msg == Msg::Set ? to_string((int)data.currentItem()) : ""); + if (Msg::Set == msg) { + auto mech = data.currentItem(); + SANE_ImageType type = SANE_IMAGE_TYPE_BMP; + if (mech == ImageFileFormat::Bmp) + type = SANE_IMAGE_TYPE_BMP; + else if(mech == ImageFileFormat::Tiff) + type = SANE_IMAGE_TYPE_TIFF; + else if(mech == ImageFileFormat::Jfif) + type = SANE_IMAGE_TYPE_JFIF; + else + return badValue(); + return scanner_->twain_set_final_format(type, NULL) == HG_ERR_OK ? success() : badValue(); + } + ImageFileFormat fmt = ImageFileFormat::Bmp; + SANE_ImageType type = scanner_->get_final_format(); + if (type == SANE_IMAGE_TYPE_TIFF) + fmt = ImageFileFormat::Tiff; + else if(type == SANE_IMAGE_TYPE_JFIF) + fmt = ImageFileFormat::Jfif; + return CapSupGetAllReset < ImageFileFormat, ImageFileFormat, CapType::IImageFileFormat>(msg, data, { ImageFileFormat::Bmp, ImageFileFormat::Tiff,ImageFileFormat::Jfif }, + fmt, ImageFileFormat::Bmp, fmt == ImageFileFormat::Bmp ? 0 : (fmt == ImageFileFormat::Tiff ? 1 : 2), 0); + }; + + m_query[CapType::IAutomaticDeskew] = msgSupportGetAllSetReset; + m_caps[CapType::IAutomaticDeskew] = [this](Msg msg, Capability& data)->Result { + if (Msg::Set == msg) { + auto atuodsw = data.currentItem(); + return scanner_->twain_set_auto_descrew((bool)atuodsw) == HG_ERR_OK ? success() : seqError(); + } + BYTE ato = scanner_->twain_is_auto_descrew(); + return CapSupGetAllReset(msg, data, ato, true); + }; + + m_query[CapType::IAutomaticRotate] = msgSupportGetAllSetReset; + m_caps[CapType::IAutomaticRotate] = [this](Msg msg, Capability& data)->Result { + if (Msg::Set == msg) { + auto mech = data.currentItem(); + return scanner_->twain_set_text_auto_matic(mech) == HG_ERR_OK ? success() : badValue(); + } + BYTE am = scanner_->twain_is_text_auto_matic(); + return CapSupGetAllReset(msg, data, am, false); + }; + + m_query[CapType::SerialNumber] = msgSupportGetAll; + m_caps[CapType::SerialNumber] = [this](Msg msg, Capability& data)->Result { + Str255 str; + scanner_->twain_get_serial_num(str.data()); + return CapSupGetAll(msg, data, str, str); + }; + + m_query[CapType::AutoScan] = msgSupportGetAllSetReset; + m_caps[CapType::AutoScan] = [this](Msg msg, Capability& data)->Result { + if (Msg::Set == msg) { + auto autoscan = data.currentItem(); + m_autoscan = autoscan; + return success(); + } + return CapSupGetAllReset(msg, data, m_autoscan, FALSE); + }; + + m_query[CapType::IAutoSize] = msgSupportGetAllSetReset; + m_caps[CapType::IAutoSize] = [this](Msg msg, Capability& data)->Result { + CapabilityPrintf(msg, enum2str(CapType::IAutoSize), msg == Msg::Set ? to_string((int)data.currentItem()) : ""); + if (Msg::Set == msg) { + auto autosize = data.currentItem(); + return scanner_->twain_set_paper_auto_match_size(autosize == AutoSize::Auto) == HG_ERR_OK ? success() : badValue(); + } + UInt16 size = scanner_->twain_is_paper_auto_match_size() ? (UInt16)AutoSize::Auto : (UInt16)AutoSize::None; + return CapSupGetAllReset(msg, data, { AutoSize::None, AutoSize::Auto }, size, AutoSize::None, (size == (UInt16)AutoSize::Auto) ? 1 : 0, 0); + }; + + m_query[CapType::IAutomaticBorderDetection] = msgSupportGetAllSetReset; + m_caps[CapType::IAutomaticBorderDetection] = [this](Msg msg, Capability& data)->Result { + if (Msg::Set == msg) { + auto autodetectborder = data.currentItem(); + return scanner_->twain_set_erase_black_frame((bool)autodetectborder) == HG_ERR_OK ? success() : badValue(); + } + bool val = false; + Bool init = false, + erase = scanner_->twain_is_erase_black_frame(&val); + init = val; + return CapSupGetAllReset(msg, data, { false,true }, erase, init, erase ? 1 : 0, 0); + }; + + m_query[CapType::IAutoDiscardBlankPages] = msgSupportGetAllSetReset; + m_caps[CapType::IAutoDiscardBlankPages] = [this](Msg msg, Capability& data)->Result { + if (Msg::Set == msg) { + auto mech = data.currentItem(); + return scanner_->twain_set_page_discarding_blank_page(mech == DiscardBlankPages::Auto, false) == HG_ERR_OK ? success() : badValue(); + } + DiscardBlankPages autodiscradblank = scanner_->twain_is_page_discarding_blank_page(false) ? + DiscardBlankPages::Auto : DiscardBlankPages::Disabled; + return CapSupGetAllReset(msg, data, autodiscradblank, DiscardBlankPages::Disabled); + }; + + 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 { + if (Msg::Set == msg) { + auto mech = data.currentItem(); + return scanner_->twain_set_page_discarding_blank_page(mech == DiscardBlankPages::Auto, true) == HG_ERR_OK ? success() : badValue(); + } + DiscardBlankPages autodiscradblank = scanner_->twain_is_page_discarding_blank_page(true) ? + DiscardBlankPages::Auto : DiscardBlankPages::Disabled; + return CapSupGetAllResetEx(msg, data, autodiscradblank, DiscardBlankPages::Disabled); + }; + + m_query[CapType::IFilter] = msgSupportGetAllSetReset; + m_caps[CapType::IFilter] = [this](Msg msg, Capability& data)->Result { + if (Msg::Set == msg) { + auto mech = data.currentItem(); + return scanner_->twain_set_filter((int)mech, false) == HG_ERR_OK ? success() : badValue(); + } + BYTE f = (BYTE)scanner_->twain_get_filter(false); + UInt32 ind = 3; + if (f == (BYTE)Filter::Red) + ind = 0; + else if (f == (BYTE)Filter::Green) + ind = 1; + else if (f == (BYTE)Filter::Blue) + ind = 2; + return CapSupGetAllReset(msg, data, { Filter::Red, Filter::Green,Filter::Blue,Filter::None }, f, Filter::None, ind, 3); + }; + + 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 { + if (Msg::Set == msg) { + auto mech = data.currentItem(); + return scanner_->twain_set_filter((int)mech, true) == HG_ERR_OK ? success() : badValue(); + } + BYTE f = (BYTE)scanner_->twain_get_filter(true); + UInt32 ind = 3; + if (f == ENHANCE_COLOR_RED) + ind = 0; + else if (f == ENHANCE_COLOR_GREEN) + ind = 1; + else if (f == ENHANCE_COLOR_BLUE) + ind = 2; + return CapSupGetAllResetEx(msg, data, { Filter::Red, Filter::Green,Filter::Blue,Filter::None }, f, Filter::None, ind, 3); + }; + + m_query[CapType::IBrightness] = msgSupportGetAllSetReset; + m_caps[CapType::IBrightness] = [this](Msg msg, Capability& data)->Result { + double init = .0f, l = .0f, u = .0f, step = .0f, + now = scanner_->twain_get_bright(&init, &l, &u, &step); + switch (msg) { + case Msg::Get: + data = Capability::createRange(Fix32(l), Fix32(u), Fix32(step), Fix32(now), Fix32(init)); + return success(); + case Msg::GetCurrent: + data = Capability::createOneValue(Fix32(now)); + return success(); + case Msg::GetDefault: + case Msg::Reset: + data = Capability::createOneValue(Fix32(init)); + return success(); + case Msg::Set: { + auto mech = data.currentItem(); + if (mech > u || mech < -l) + return badValue(); + return scanner_->twain_set_bright(mech.toFloat()) == HG_ERR_OK ? success() : badValue(); + } + default: + return capBadOperation(); + } + }; + + m_query[CapType::IContrast] = msgSupportGetAllSetReset; + m_caps[CapType::IContrast] = [this](Msg msg, Capability& data)->Result { + double init = .0f, l = .0f, u = .0f, step = .0f, + now = scanner_->twain_get_contrast(&init, &l, &u, &step); + switch (msg) { + case Msg::Get: + data = Capability::createRange(Fix32(l), Fix32(u), Fix32(step), Fix32(now), Fix32(init)); + return success(); + case Msg::GetCurrent: + data = Capability::createOneValue(Fix32(now)); + return success(); + case Msg::GetDefault: + case Msg::Reset: + data = Capability::createOneValue(Fix32(init)); + return success(); + case Msg::Set: { + auto mech = data.currentItem(); + if (mech > u || mech < -l) + return badValue(); + return scanner_->twain_set_contrast(mech.toFloat()) == HG_ERR_OK ? success() : badValue(); + } + default: + return capBadOperation(); + } + }; + + m_query[CapType::IGamma] = msgSupportGetAllSetReset; + m_caps[CapType::IGamma] = [this](Msg msg, Capability& data)->Result { + double init = .0f, l = .0f, u = .0f, step = .0f, + now = scanner_->twain_get_gamma(&init, &l, &u, &step); + switch (msg) { + case Msg::Get: + data = Capability::createRange(Fix32(l), Fix32(u), Fix32(step), Fix32(now), Fix32(init)); + return success(); + case Msg::GetCurrent: + data = Capability::createOneValue(Fix32(now)); + return success(); + case Msg::GetDefault: + case Msg::Reset: + data = Capability::createOneValue(Fix32(init)); + return success(); + case Msg::Set: { + auto mech = data.currentItem(); + if (mech > u || mech < l) + return badValue(); + return scanner_->twain_set_gamma(mech.toFloat()) == HG_ERR_OK ? success() : badValue(); + } + default: + return capBadOperation(); + } + }; + + m_query[CapType::CustomDsData] = msgSupportGetAll; + m_caps[CapType::CustomDsData] = [this](Msg msg, Capability& data) -> Result { + return CapSupGetAll(msg, data, Bool(true), Bool(true)); + }; + + m_query[CapType::DoubleFeedDetection] = msgSupportGetAllSetReset; + m_caps[CapType::DoubleFeedDetection] = [this](Msg msg, Capability& data)->Result { + if (Msg::Set == msg) { + auto atuodsw = data.currentItem(); + return scanner_->twain_set_ultrasonic_check((bool)atuodsw) == HG_ERR_OK ? success() : seqError(); + } + DoubleFeedDetection init = DoubleFeedDetection::Ultrasonic; + BYTE ato = scanner_->twain_is_ultrasonic_check(); + return CapSupGetAllReset(msg, data, ato, init); + }; + + m_query[CapType::IAutomaticCropUsesFrame] = msgSupportGetAll; + m_caps[CapType::IAutomaticCropUsesFrame] = [this](Msg msg, Capability& data)->Result { + BYTE crop = scanner_->twain_is_auto_crop(); + return CapSupGetAll(msg, data, crop, false); + }; + + m_query[CapType::FeederLoaded] = msgSupportGetAll; + m_caps[CapType::FeederLoaded] = [this](Msg msg, Capability& data) -> Result { + Bool paperon = scanner_->twain_is_paper_on(); + return CapSupGetAll(msg, data, paperon, paperon); + }; + + m_query[CapType::Indicators] = msgSupportGetAllSetReset; + m_caps[CapType::Indicators] = [this](Msg msg, Capability& data) -> Result { + if (Msg::Set == msg) { + auto show = data.currentItem(); + m_bIndicator = show; + return success(); + } + return CapSupGetAllReset(msg, data, { FALSE,TRUE }, m_bIndicator, TRUE, m_bIndicator ? 1 : 0, 1); + }; + + m_query[CapType(CapTypeEx::CAP_TYPE_EX_FOLD)] = msgSupportGetAllSetReset; + m_caps[CapType(CapTypeEx::CAP_TYPE_EX_FOLD)] = [this](Msg msg, Capability& data)->Result { + if (Msg::Set == msg || Msg::Reset == msg) { + auto fold = data.currentItem(); + if (msg == Msg::Reset) + fold = false; + return scanner_->twain_set_page_fold(fold) == HG_ERR_OK ? success() : badValue(); + } + BYTE fold = scanner_->twain_is_page_fold(); + return CapSupGetAllResetEx(msg, data, fold, 0); + }; + + m_query[(CapType)CapTypeEx::CAP_TYPE_EX_SHARPEN] = msgSupportGetAllSetReset; + m_caps[(CapType)CapTypeEx::CAP_TYPE_EX_SHARPEN] = [this](Msg msg, Capability& data)->Result { + if (Msg::Set == msg) { + auto mech = data.currentItem(); + return scanner_->twain_set_sharpen((int)mech) == HG_ERR_OK ? success() : badValue(); + } + BYTE f = (BYTE)scanner_->twain_get_sharpen(); + return CapSupGetAllResetEx(msg, data, { 0, 1, 2, 3, 4}, f, 0, f, 0); + }; + + 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 { + if (Msg::Set == msg) { + auto mech = data.currentItem(); + if (mech < 10 || mech > 300) + return badValue(); + return scanner_->twain_set_dogear_distance(mech) == HG_ERR_OK ? success() : badValue(); + } + UInt32 init = 50, + now = scanner_->twain_get_dogear_distance(); + + return CapSupGetAllResetEx(msg, data, now, init); + }; + + m_query[CapType(CapTypeEx::CAP_TYPE_EX_MULTI_OUT)] = msgSupportGetAllSetReset; + m_caps[CapType(CapTypeEx::CAP_TYPE_EX_MULTI_OUT)] = [this](Msg msg, Capability& data)->Result { + if (Msg::Set == msg || Msg::Reset == msg) { + auto multi = data.currentItem(); + if (msg == Msg::Reset) + multi = false; + multi_out_ = multi; + return success(); + } + BYTE multi = multi_out_; + return CapSupGetAllResetEx(msg, data, multi, 0); + }; + + 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 { + if (Msg::Set == msg || Msg::Reset == msg) { + auto mech = data.currentItem(); + if (msg == Msg::Reset) + mech = -1; + return scanner_->twain_set_multioutput_type((int)mech) == HG_ERR_OK ? success() : badValue(); + } + UInt32 f = (UInt32)scanner_->twain_get_multioutput_type(); + return CapSupGetAllResetEx(msg, data, { (UInt32)-1, 0, 1, 2, 3 }, f, -1, 0, 0); + }; + + 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 { + if (Msg::Set == msg || Msg::Reset == msg) { + auto tobe = data.currentItem(); + if (msg == Msg::Reset) + tobe = false; + return scanner_->twain_set_to_be_scan(tobe) == HG_ERR_OK ? success() : seqError(); + } + BYTE tobe = scanner_->twain_get_to_be_scan(); + return CapSupGetAllResetEx(msg, data, tobe, 0); + }; + + 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 { + if (Msg::Set == msg || Msg::Reset == msg) { + auto tobe = data.currentItem(); + if (msg == Msg::Reset) + tobe = false; + return scanner_->twain_set_scan_with_hole(tobe) == HG_ERR_OK ? success() : seqError(); + } + BYTE tobe = scanner_->twain_get_scan_with_hole(); + return CapSupGetAllResetEx(msg, data, tobe, 0); + }; + + char code[256] = { 0 }; + unsigned int len = _countof(code); + if (scanner_->twain_get_device_code(code, len) == HG_ERR_OK) + { + m_query[(CapType)(CapTypeEx::CAP_TYPE_EX_ENCODE)] = msgSupportGetAll; + m_caps[(CapType)(CapTypeEx::CAP_TYPE_EX_ENCODE)] = [this](Msg msg, Capability& data)->Result { + char code[256] = { 0 }; + unsigned int len = _countof(code); + Str255 str; + scanner_->twain_get_device_code(code, len); + str.setData(code, 32); + data = Capability::createOneValue((CapType)CapTypeEx::CAP_TYPE_EX_ENCODE, str); + return success(); + }; + } + + 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 { + UInt32 init = 4; + if (Msg::Set == msg || Msg::Reset == msg) { + if(msg == Msg::Set) + init = data.currentItem(); + scanner_->twain_set_power_level(init); + return success(); + } + UInt32 level = scanner_->twain_get_power_level(); + return CapSupGetAllResetEx(msg, data, level, init); + }; + + init_support_caps_ex(); + + 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 { + Str255 str; + scanner_->twain_get_hareware_version(str.data()); + data = Capability::createOneValue((CapType)CapTypeEx::CAP_TYPE_EX_HARDWARE_VERSION, str); + return success(); // CapSupGetAllEx(msg, data, str, str); + }; + + m_query[(CapType)CapTypeEx::CAP_TYPE_EX_IP] = msgSupportGetAll; + m_caps[(CapType)CapTypeEx::CAP_TYPE_EX_IP] = [this](Msg msg, Capability& data)->Result { + Str255 str; + scanner_->twain_get_ip(str.data()); + data = Capability::createOneValue((CapType)CapTypeEx::CAP_TYPE_EX_IP, str); + return success(); // CapSupGetAll(msg, data, str, str); + }; + +#define SET_EXISTING_EXTENSION(scan_ind, cap) \ + op_ind = scanner_->##scan_ind(); \ + if(op_ind != -1) \ + { \ + m_query[(CapType)cap] = msgSupportGetAllSetReset; \ + m_caps[(CapType)cap] = m_caps[CapType((int)CAP_TYPE_EX_0 + op_ind)]; \ + } + int op_ind = -1; + + SET_EXISTING_EXTENSION(twain_get_paper_ind, CapType::ISupportedSizes); + SET_EXISTING_EXTENSION(twain_get_flip_ind, CapTypeEx::CAP_TYPE_EX_FLIP); + SET_EXISTING_EXTENSION(twain_get_rotate_bkg_ind, CapTypeEx::CAP_TYPE_EX_ROTATE_BKG_180); + SET_EXISTING_EXTENSION(twain_get_fill_black_bkg_ind, CapTypeEx::CAP_TYPE_EX_FILL_BLACK_BKG); + SET_EXISTING_EXTENSION(twain_get_edge_ident_ind, CapTypeEx::CAP_TYPE_EX_EDGE_IDENT); + SET_EXISTING_EXTENSION(twain_get_threshold_ind, CapTypeEx::CAP_TYPE_EX_THRESHOLD); + SET_EXISTING_EXTENSION(twain_get_threshold_ind, CapTypeEx::CAP_TYPE_EX_THRESHOLD_1); + SET_EXISTING_EXTENSION(twain_bkg_filling_method_ind, CapTypeEx::CAP_TYPE_EX_BKG_FILLING_METHOD); + SET_EXISTING_EXTENSION(twain_fill_hole_ind, CapTypeEx::CAP_TYPE_EX_FILL_HOLE); + SET_EXISTING_EXTENSION(twain_fill_hole_ratio_ind, CapTypeEx::CAP_TYPE_EX_FILL_HOLE_RATIO); + SET_EXISTING_EXTENSION(twain_detach_noise_ind, CapTypeEx::CAP_TYPE_EX_DETACH_NOISE); + SET_EXISTING_EXTENSION(twain_detach_noise_threshold_ind, CapTypeEx::CAP_TYPE_EX_DETACH_NOISE_THRESHOLD); + SET_EXISTING_EXTENSION(twain_rid_red_ind, CapTypeEx::CAP_TYPE_EX_RID_RED); + SET_EXISTING_EXTENSION(twain_rid_red_hsv_ind, CapTypeEx::CAP_TYPE_EX_RID_RED_HSV); + SET_EXISTING_EXTENSION(twain_screw_detect_ind, CapTypeEx::CAP_TYPE_EX_SCREW_DETECT); + SET_EXISTING_EXTENSION(twain_screw_detect_level_ind, CapTypeEx::CAP_TYPE_EX_SCREW_DETECT_LEVEL); + SET_EXISTING_EXTENSION(twain_staple_detect_ind, CapTypeEx::CAP_TYPE_EX_STAPLE_DETECT); + SET_EXISTING_EXTENSION(twain_dogear_detect_ind, CapTypeEx::CAP_TYPE_EX_DOGEAR_DETECT); + SET_EXISTING_EXTENSION(twain_dark_sample_ind, CapTypeEx::CAP_TYPE_EX_DARK_SAMPLE); + SET_EXISTING_EXTENSION(twain_image_split_ind, CapTypeEx::CAP_TYPE_EX_IMAGE_SPLIT); + SET_EXISTING_EXTENSION(twain_fade_bkground_ind, CapTypeEx::CAP_TYPE_EX_FADE_BKG); + SET_EXISTING_EXTENSION(twain_fade_bkground_val_ind, CapTypeEx::CAP_TYPE_EX_FADE_BKG_VALUE); + SET_EXISTING_EXTENSION(twain_size_detect_ind, CapTypeEx::CAP_TYPE_EX_SIZE_DETECT); +} +void huagao_ds::init_support_caps_ex(void) +{ +#define SET_CAP_ENUM(sn, ctype, ttype, cap) \ + m_query[(CapType)cap] = msgSupportGetAllSetReset; \ + m_caps[(CapType)cap] = [this](Msg msg, Capability& data) -> Result { \ + if (!scanner_.get()) \ + return seqError(); \ + if(msg == Msg::Set) { \ + ctype item; \ + copy_type(item, data.currentItem()); \ + return scanner_->set_value(sn, item) == HG_ERR_OK ? success() : badValue(); \ + } \ + std::list org; \ + ctype now, init; \ + std::list vals; \ + ttype Now, Init; \ + UInt32 ni, ii; \ + scanner_->get_value(sn, org, now, init); \ + ni = std::distance(org.begin(), std::find(org.begin(), org.end(), now)); \ + ii = std::distance(org.begin(), std::find(org.begin(), org.end(), init)); \ + copy_type(Now, now); \ + for(const auto& v: org) \ + { \ + copy_type(Init, v); \ + vals.push_back(Init); \ + } \ + copy_type(Init, init); \ + return cap_get_enum_values(msg, data, vals, Now, Init, ni, ii); \ + }; +#define SET_CAP_RANGE(sn, ctype, ttype, cap) \ + m_query[(CapType)cap] = msgSupportGetAllSetReset; \ + m_caps[(CapType)cap] = [this](Msg msg, Capability& data) -> Result { \ + if (!scanner_.get()) \ + return seqError(); \ + if(msg == Msg::Set) { \ + ctype item = (ctype)data.currentItem(); \ + return scanner_->set_value(sn, item) == HG_ERR_OK ? success() : badValue(); \ + } \ + ctype now, init, lower, upper, step; \ + ttype Now, Init, Lower, Upper, Step; \ + scanner_->get_value(sn, now, init, &lower, &upper, &step); \ + copy_type(Now, now); \ + copy_type(Init, init); \ + copy_type(Lower, lower); \ + copy_type(Upper, upper); \ + copy_type(Step, step); \ + return cap_get_one_value(msg, data, Now, Init, &Lower, &Upper, &Step); \ + }; +#define SET_BOOL(sn, cap) \ + m_query[(CapType)cap] = msgSupportGetAllSetReset; \ + m_caps[(CapType)cap] = [this](Msg msg, Capability& data) -> Result { \ + if (!scanner_.get()) \ + return seqError(); \ + if(msg == Msg::Set) { \ + auto item = data.currentItem(); \ + return scanner_->set_value(sn, (bool)item) == HG_ERR_OK ? success() : badValue(); \ + } \ + bool init = false, now = false; \ + std::list vals; \ + scanner_->get_value(sn, vals, now, init); \ + BYTE v = now; \ + return CapSupGetAllResetEx(msg, data, v, init); \ + }; + +#define SET_CAP(sn, ctype, ttype, cap) \ + m_query[(CapType)cap] = msgSupportGetAllSetReset; \ + m_caps[(CapType)cap] = [this](Msg msg, Capability& data) -> Result { \ + if (!scanner_.get()) \ + return seqError(); \ + if(msg == Msg::Set) { \ + ctype item = (ctype)data.currentItem(); \ + return scanner_->set_value(sn, item) == HG_ERR_OK ? success() : badValue(); \ + } \ + ctype now, init; \ + ttype Now, Init; \ + scanner_->get_value(sn, now, init); \ + copy_type(Now, now); \ + copy_type(Init, init); \ + return cap_get_one_value(msg, data, Now, Init, NULL, NULL, NULL); \ + }; + +#define ADD_CAP(sn) \ +{ \ + std::string data_type(""); \ + value_limit vl = VAL_LIMIT_NONE; \ + if(!scanner_->get_value_info(sn, data_type, vl)) \ + return; \ + if(data_type == "bool") \ + { \ + SET_BOOL(sn, CAP_TYPE_EX_##sn); \ + } \ + else if(data_type == "int") \ + { \ + if(vl == VAL_LIMIT_RANGE) \ + { SET_CAP_RANGE(sn, int, UInt32, CAP_TYPE_EX_##sn); } \ + else \ + { SET_CAP(sn, int, UInt32, CAP_TYPE_EX_##sn); } \ + } \ + else if(data_type == "float") \ + { \ + if(vl == VAL_LIMIT_RANGE) \ + { SET_CAP_RANGE(sn, float, Fix32, CAP_TYPE_EX_##sn); } \ + else \ + { SET_CAP(sn, float, Fix32, CAP_TYPE_EX_##sn); } \ + } \ + else if(data_type == "string") \ + { \ + if(vl == VAL_LIMIT_ENUM) \ + { SET_CAP_ENUM(sn, std::string, Twpp::Str64, CAP_TYPE_EX_##sn); } \ + } \ + else if(data_type == "button") \ + { \ + m_query[(CapType)CAP_TYPE_EX_##sn] = MsgSupport::Set | MsgSupport::Reset; \ + m_caps[(CapType)CAP_TYPE_EX_##sn] = [this](Msg msg, Capability& data) -> Result { \ + if (!scanner_.get()) \ + return seqError(); \ + if(msg == Msg::Set) { \ + scanner_->set_value(sn, false); \ + return success(); \ + } \ + return enmGet(msg, data, true); \ + }; \ + } \ +} + + // setting items ... + + ADD_CAP(1); + ADD_CAP(2); + ADD_CAP(3); + ADD_CAP(4); + ADD_CAP(5); + ADD_CAP(6); + ADD_CAP(7); + ADD_CAP(8); + ADD_CAP(9); + ADD_CAP(10); + ADD_CAP(11); + ADD_CAP(12); + ADD_CAP(13); + ADD_CAP(14); + ADD_CAP(15); + ADD_CAP(16); + ADD_CAP(17); + ADD_CAP(18); + ADD_CAP(19); + ADD_CAP(20); + ADD_CAP(21); + ADD_CAP(22); + ADD_CAP(23); + ADD_CAP(24); + ADD_CAP(25); + ADD_CAP(26); + ADD_CAP(27); + ADD_CAP(28); + ADD_CAP(29); + ADD_CAP(30); + ADD_CAP(31); + ADD_CAP(32); + ADD_CAP(33); + ADD_CAP(34); + ADD_CAP(35); + ADD_CAP(36); + ADD_CAP(37); + ADD_CAP(38); + ADD_CAP(39); + ADD_CAP(40); + ADD_CAP(41); + ADD_CAP(42); + ADD_CAP(43); + ADD_CAP(44); + ADD_CAP(45); + ADD_CAP(46); + ADD_CAP(47); + ADD_CAP(48); + ADD_CAP(49); + ADD_CAP(50); + ADD_CAP(51); + ADD_CAP(52); + ADD_CAP(53); + ADD_CAP(54); + ADD_CAP(55); + ADD_CAP(56); + ADD_CAP(57); + ADD_CAP(58); + ADD_CAP(59); + ADD_CAP(60); + ADD_CAP(61); + ADD_CAP(62); + ADD_CAP(63); + ADD_CAP(64); + ADD_CAP(65); + ADD_CAP(66); + ADD_CAP(67); + ADD_CAP(68); + ADD_CAP(69); + ADD_CAP(70); + ADD_CAP(71); + ADD_CAP(72); + ADD_CAP(73); + ADD_CAP(74); + ADD_CAP(75); + ADD_CAP(76); + ADD_CAP(77); + ADD_CAP(78); + ADD_CAP(79); + ADD_CAP(80); +} +void huagao_ds::on_scan_event(int sane_event, void* data, unsigned int* len) +{ + if (ui_.get()) + { + ui_->handle_sane_event(sane_event, data, len); + if (sane_event == SANE_EVENT_SCAN_FINISHED) + { + if (ui_->is_progress_ui_showing()) + ui_->hide_ui(); + else if (!scanner_->twain_get_to_be_scan()) + ui_->hide_ui(); + } + } +} + + + + diff --git a/huagaotwain/twain/huagaods.hpp b/huagaotwain/twain/huagaods.hpp new file mode 100644 index 0000000..8ae8354 --- /dev/null +++ b/huagaotwain/twain/huagaods.hpp @@ -0,0 +1,105 @@ +#ifndef SIMPLEDS_HPP +#define SIMPLEDS_HPP + +#include +#include +#include +#include +#include +#include +#include "twpp.hpp" +#include "../huagaotwain.h" + +namespace std { + + template<> + struct hash { + size_t operator()(Twpp::CapType cap) const { + return hash()(static_cast(cap)); + } + }; + +} + +class twain_ui; + +class huagao_ds : public Twpp::SourceFromThis { + std::unordered_map> m_caps; + std::unordered_map m_query; + std::unique_ptr scanner_; + Twpp::SetupFileXfer m_fileXfer; + Twpp::XferMech m_capXferMech = Twpp::XferMech::Native; + std::unique_ptr memoryinfo; + std::unique_ptr ui_; + bool m_memoryfalg = true; + bool m_bFeederEnabled = true; + bool m_bAutoFeed = true; + HANDLE singleton_ = NULL; + Twpp::Bool m_autoscan = true; + int automaticcolortype_ = 0; + bool multi_out_ = false; + bool m_bIndicator = true; + + static std::string get_hidedlg_path(void); + static void showmsg(const char* msg, int err); + static void scan_event(int sane_event, void* data, unsigned int* len, 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); + Twpp::Result showTwainUI(Twpp::UserInterface& data, bool bUiOnly = false); + void init_support_caps(void); + void init_support_caps_ex(void); + void on_scan_event(int sane_event, void* data, unsigned int* len); + +public: + huagao_ds(); + virtual ~huagao_ds(); + + static const Twpp::Identity& defaultIdentity() noexcept; + static Twpp::Result selectIdentity(Twpp::Identity& ident) noexcept; + static Twpp::ConditionCode condition_code_from_hg_error(int hgerr); + + // SourceFromThis interface +protected: + typedef Twpp::SourceFromThis Base; + + virtual Twpp::Result capabilityGet(const Twpp::Identity& origin, Twpp::Capability& data) override; + virtual Twpp::Result capabilityGetCurrent(const Twpp::Identity& origin, Twpp::Capability& data) override; + virtual Twpp::Result capabilityGetDefault(const Twpp::Identity& origin, Twpp::Capability& data) override; + virtual Twpp::Result capabilityQuerySupport(const Twpp::Identity& origin, Twpp::Capability& data) override; + virtual Twpp::Result capabilityReset(const Twpp::Identity& origin, Twpp::Capability& data) override; + virtual Twpp::Result capabilityResetAll(const Twpp::Identity& origin) override; + virtual Twpp::Result capabilitySet(const Twpp::Identity& origin, Twpp::Capability& data) override; + virtual Twpp::Result eventProcess(const Twpp::Identity& origin, Twpp::Event& data) override; + virtual Twpp::Result deviceEventGet(const Twpp::Identity& origin, Twpp::DeviceEvent& data) override; + virtual Twpp::Result identityOpenDs(const Twpp::Identity& origin) override; + virtual Twpp::Result identityCloseDs(const Twpp::Identity& origin) override; + virtual Twpp::Result pendingXfersGet(const Twpp::Identity& origin, Twpp::PendingXfers& data) override; + virtual Twpp::Result pendingXfersEnd(const Twpp::Identity& origin, Twpp::PendingXfers& data) override; + virtual Twpp::Result pendingXfersReset(const Twpp::Identity& origin, Twpp::PendingXfers& data) override; + virtual Twpp::Result setupMemXferGet(const Twpp::Identity& origin, Twpp::SetupMemXfer& data) override; + virtual Twpp::Result userInterfaceDisable(const Twpp::Identity& origin, Twpp::UserInterface& data) override; + virtual Twpp::Result userInterfaceEnable(const Twpp::Identity& origin, Twpp::UserInterface& data) override; + virtual Twpp::Result userInterfaceEnableUiOnly(const Twpp::Identity& origin, Twpp::UserInterface& data) override; + virtual Twpp::Result imageInfoGet(const Twpp::Identity& origin, Twpp::ImageInfo& data) override; + virtual Twpp::Result imageLayoutGet(const Twpp::Identity& origin, Twpp::ImageLayout& data) override; + virtual Twpp::Result imageLayoutGetDefault(const Twpp::Identity& origin, Twpp::ImageLayout& data) override; + virtual Twpp::Result imageLayoutSet(const Twpp::Identity& origin, Twpp::ImageLayout& data) override; + virtual Twpp::Result imageLayoutReset(const Twpp::Identity& origin, Twpp::ImageLayout& data) override; + virtual Twpp::Result imageMemXferGet(const Twpp::Identity& origin, Twpp::ImageMemXfer& data) override; + virtual Twpp::Result imageNativeXferGet(const Twpp::Identity& origin, Twpp::ImageNativeXfer& data) override; + virtual Twpp::Result pendingXfersStopFeeder(const Twpp::Identity& origin, Twpp::PendingXfers& data) override; + virtual Twpp::Result imageFileXferGet(const Twpp::Identity& origin) override; + virtual Twpp::Result setupFileXferGet(const Twpp::Identity& origin, Twpp::SetupFileXfer& data) override; + virtual Twpp::Result setupFileXferGetDefault(const Twpp::Identity& origin, Twpp::SetupFileXfer& data) override; + virtual Twpp::Result setupFileXferSet(const Twpp::Identity& origin, Twpp::SetupFileXfer& data) override; + virtual Twpp::Result setupFileXferReset(const Twpp::Identity& origin, Twpp::SetupFileXfer& data) override; + virtual Twpp::Result call(const Twpp::Identity& origin, Twpp::DataGroup dg, Twpp::Dat dat, Twpp::Msg msg, void* data) override; + virtual Twpp::Result customDataGet(const Twpp::Identity& origin, Twpp::CustomData& data) override; + virtual Twpp::Result customDataSet(const Twpp::Identity& origin, Twpp::CustomData& data) override; + +public: + void SetResoluton(const char* path, int resolution); +}; + +#endif // SIMPLEDS_HPP diff --git a/huagaotwain/twain/twain_2.4.h b/huagaotwain/twain/twain_2.4.h new file mode 100644 index 0000000..0d1ce92 --- /dev/null +++ b/huagaotwain/twain/twain_2.4.h @@ -0,0 +1,2265 @@ +/* ======================================================================== *\ + + Copyright (C) 2007 TWAIN Working Group: Adobe Systems Incorporated, + AnyDoc Software Inc., Eastman Kodak Company, Fujitsu Computer Products + of America, JFL Peripheral Solutions Inc., Ricoh Corporation, and + Xerox Corporation. All rights reserved. + + Copyright (C) 1991, 1992 TWAIN Working Group: Aldus, Caere, Eastman-Kodak, + Hewlett-Packard and Logitech Corporations. All rights reserved. + + Copyright (C) 1997 TWAIN Working Group: Bell+Howell, Canon, DocuMagix, + Fujitsu, Genoa Technology, Hewlett-Packard, Kofax Imaging Products, and + Ricoh Corporation. All rights reserved. + + Copyright (C) 1998 TWAIN Working Group: Adobe Systems Incorporated, + Canon Information Systems, Eastman Kodak Company, + Fujitsu Computer Products of America, Genoa Technology, + Hewlett-Packard Company, Intel Corporation, Kofax Image Products, + JFL Peripheral Solutions Inc., Ricoh Corporation, and Xerox Corporation. + All rights reserved. + + Copyright (C) 2000 TWAIN Working Group: Adobe Systems Incorporated, + Canon Information Systems, Digimarc Corporation, Eastman Kodak Company, + Fujitsu Computer Products of America, Hewlett-Packard Company, + JFL Peripheral Solutions Inc., Ricoh Corporation, and Xerox Corporation. + All rights reserved. + + + TWAIN.h - This is the definitive include file for applications and + data sources written to the TWAIN specification. + It defines constants, data structures, messages etc. + for the public interface to TWAIN. + + Revision History: + version 1.0, March 6, 1992. TWAIN 1.0. + version 1.1, January 1993. Tech Notes 1.1 + version 1.5, June 1993. Specification Update 1.5 + Change DC to TW + Change filename from DC.H to TWAIN.H + version 1.5, July 1993. Remove spaces from country identifiers + + version 1.7, July 1997 Added Capabilities and data structure for + document imaging and digital cameras. + KHL. + version 1.7, July 1997 Inserted Borland compatibile structure packing + directives provided by Mentor. JMH + version 1.7, Aug 1997 Expanded file tabs to spaces. + NOTE: future authors should be sure to have + their editors set to automatically expand tabs + to spaces (original tab setting was 4 spaces). + version 1.7, Sept 1997 Added job control values + Added return codes + version 1.7, Sept 1997 changed definition of pRGBRESPONSE to + pTW_RGBRESPONSE + version 1.7 Aug 1998 Added missing TWEI_BARCODEROTATION values + TWBCOR_ types JMH + version 1.8 August 1998 Added new types and definitions required + for 1.8 Specification JMH + version 1.8 January 1999 Changed search mode from SRCH_ to TWBD_ as + in 1.8 Specification, added TWBT_MAXICODE JMH + version 1.8 January 1999 Removed undocumented duplicate AUTO JMH + version 1.8 March 1999 Removed undocumented 1.8 caps: + CAP_FILESYSTEM + CAP_PAPERBINDING + CAP_PASSTHRU + CAP_POWERDOWNTIME + ICAP_AUTODISCARDBLANKPAGES + * CAP_PAGEMULTIPLEACQUIRE - is CAP_REACQUIREALLOWED, + requires spec change. JMH + Added Mac structure packing modifications JMH + version 1.9 March 2000 Added new types and definations required + for 1.9 Specification MLM + version 1.9 March 2000 Added ICAP_JPEGQUALITY, TWJQ_ values, + updated TWON_PROTOCOLMINOR for Release v1.9 MN + version 1.91 August 2007 Added new types and definitions required + for 1.91 Specification MLM + version 2.0 Sept 2007 Added new types and definitions required + for 2.0 Specification FHH + version 2.0 Mar 2008 Depreciated ICAP_PIXELTYPEs TWPT_SRGB64, TWPT_BGR, + TWPT_CIELAB, TWPT_CIELUV, and TWPT_YCBCR JMW + version 2.0 Mar 2008 Added missing new 2.0 CAP_ definitions JMW + version 2.0 Dec 2008 Updated TW_INFO structure for 64bit JMW + version 2.1 Mar 2009 Added new types and definitions required + for 2.1 Specification JMW + version 2.2 Nov 2010 Added new types and definitions required + for 2.2 Specification MSM + version 2.3 Feb 2013 Added new types and definitions required + for 2.3 Specification MLM + version 2.3a Apr 2015 Errata fixes to TWCY_ANDORRA and TWCY_CUBA + version 2.4 Aug 2015 Added new types and definitions required + for 2.4 Specification MLM + version 2.4a June 2016 Added TW_INT32 and TW_UINT32 fixes for Linux, + (I just added this comment today) + version 2.4b March 2017 Missing changeset from 2.3 verion (2013/06/20) + + +\* ======================================================================== */ + +#ifndef TWAIN +#define TWAIN + +/**************************************************************************** + * TWAIN Version * + ****************************************************************************/ +#define TWON_PROTOCOLMINOR 4 /* Changed for Version 2.4 */ +#define TWON_PROTOCOLMAJOR 2 + +/**************************************************************************** + * Platform Dependent Definitions and Typedefs * + ****************************************************************************/ + +/* Microsoft C/C++ Compiler */ +#if defined(WIN32) || defined(WIN64) || defined (_WINDOWS) + #define TWH_CMP_MSC + #if defined(_WIN64) || defined(WIN64) + #define TWH_64BIT + #elif defined(WIN32) || defined(_WIN32) + #define TWH_32BIT + #endif + +/* GNU C/C++ Compiler */ +#elif defined(__GNUC__) + #define TWH_CMP_GNU + #if defined(__alpha__)\ + ||defined(__ia64__)\ + ||defined(__ppc64__)\ + ||defined(__s390x__)\ + ||defined(__x86_64__) + #define TWH_64BIT + #else + #define TWH_32BIT + #endif + + +/* Borland C/C++ Compiler */ +#elif defined(__BORLAND__) + #define TWH_CMP_BORLAND + #define TWH_32BIT +/* Unrecognized */ +#else + #error Unrecognized compiler +#endif + +/* Apple Compiler (which is GNU now) */ +#if defined(__APPLE__) + #define TWH_CMP_XCODE + #ifdef __MWERKS__ + #include + #else + #include + #endif +#endif + +/* Win32 and Win64 systems */ +#if defined(TWH_CMP_MSC) | defined(TWH_CMP_BORLAND) + typedef HANDLE TW_HANDLE; + typedef LPVOID TW_MEMREF; + typedef UINT_PTR TW_UINTPTR; + +/* MacOS/X... */ +#elif defined(TWH_CMP_XCODE) + #define PASCAL pascal + #define FAR + typedef Handle TW_HANDLE; + typedef char *TW_MEMREF; + typedef unsigned char BYTE; + + #ifdef TWH_32BIT + //32 bit GNU + typedef unsigned long TW_UINTPTR; + #else + //64 bit GNU + typedef unsigned long long TW_UINTPTR; + #endif + +/* Everything else... */ +#else + #define PASCAL + #define FAR + typedef void* TW_HANDLE; + typedef void* TW_MEMREF; + typedef unsigned char BYTE; + + #ifdef TWH_32BIT + //32 bit GNU + typedef unsigned long TW_UINTPTR; + #else + //64 bit GNU + typedef unsigned long long TW_UINTPTR; + #endif +#endif + + +/* Set the packing: this occurs before any structures are defined */ +#ifdef TWH_CMP_MSC + #pragma pack (push, before_twain) + #pragma pack (2) +#elif defined(TWH_CMP_GNU) + #if defined(__APPLE__) /* cf: Mac version of TWAIN.h */ + #pragma options align = power + #else + #pragma pack (push, before_twain) + #pragma pack (2) + #endif +#elif defined(TWH_CMP_BORLAND) + #pragma option -a2 +#endif + + +/**************************************************************************** + * Type Definitions * + ****************************************************************************/ + +/* String types. These include room for the strings and a NULL char, * + * or, on the Mac, a length byte followed by the string. * + * TW_STR255 must hold less than 256 chars so length fits in first byte. */ +#if defined(__APPLE__)/* cf: Mac version of TWAIN.h */ + typedef unsigned char TW_STR32[34], FAR *pTW_STR32; + typedef unsigned char TW_STR64[66], FAR *pTW_STR64; + typedef unsigned char TW_STR128[130], FAR *pTW_STR128; + typedef unsigned char TW_STR255[256], FAR *pTW_STR255; +#else + typedef char TW_STR32[34], FAR *pTW_STR32; + typedef char TW_STR64[66], FAR *pTW_STR64; + typedef char TW_STR128[130], FAR *pTW_STR128; + typedef char TW_STR255[256], FAR *pTW_STR255; +#endif + +/* Numeric types. */ +typedef char TW_INT8, FAR *pTW_INT8; +typedef short TW_INT16, FAR *pTW_INT16; +#if defined(_WIN32) + typedef long TW_INT32, FAR *pTW_INT32; +#else + typedef int TW_INT32, FAR *pTW_INT32; +#endif +typedef unsigned char TW_UINT8, FAR *pTW_UINT8; +typedef unsigned short TW_UINT16, FAR *pTW_UINT16; +#if defined(_WIN32) + typedef unsigned long TW_UINT32, FAR *pTW_UINT32; +#else + typedef unsigned int TW_UINT32, FAR *pTW_UINT32; +#endif +typedef unsigned short TW_BOOL, FAR *pTW_BOOL; + + +/**************************************************************************** + * Structure Definitions * + ****************************************************************************/ + +/* Fixed point structure type. */ +typedef struct { + TW_INT16 Whole; + TW_UINT16 Frac; +} TW_FIX32, FAR *pTW_FIX32; + +/* Defines a frame rectangle in ICAP_UNITS coordinates. */ +typedef struct { + TW_FIX32 Left; + TW_FIX32 Top; + TW_FIX32 Right; + TW_FIX32 Bottom; +} TW_FRAME, FAR * pTW_FRAME; + +/* Defines the parameters used for channel-specific transformation. */ +typedef struct { + TW_FIX32 StartIn; + TW_FIX32 BreakIn; + TW_FIX32 EndIn; + TW_FIX32 StartOut; + TW_FIX32 BreakOut; + TW_FIX32 EndOut; + TW_FIX32 Gamma; + TW_FIX32 SampleCount; +} TW_DECODEFUNCTION, FAR * pTW_DECODEFUNCTION; + +/* Stores a Fixed point number in two parts, a whole and a fractional part. */ +typedef struct { + TW_DECODEFUNCTION Decode[3]; + TW_FIX32 Mix[3][3]; +} TW_TRANSFORMSTAGE, FAR * pTW_TRANSFORMSTAGE; + +/* Container for array of values */ +typedef struct { + TW_UINT16 ItemType; + TW_UINT32 NumItems; + TW_UINT8 ItemList[1]; +} TW_ARRAY, FAR * pTW_ARRAY; + +/* Information about audio data */ +typedef struct { + TW_STR255 Name; + TW_UINT32 Reserved; +} TW_AUDIOINFO, FAR * pTW_AUDIOINFO; + +/* Used to register callbacks. */ +typedef struct { + TW_MEMREF CallBackProc; + #if defined(__APPLE__) /* cf: Mac version of TWAIN.h */ + TW_MEMREF RefCon; + #else + TW_UINT32 RefCon; + #endif + TW_INT16 Message; +} TW_CALLBACK, FAR * pTW_CALLBACK; + +/* Used to register callbacks. */ +typedef struct { + TW_MEMREF CallBackProc; + TW_UINTPTR RefCon; + TW_INT16 Message; +} TW_CALLBACK2, FAR * pTW_CALLBACK2; + +/* Used by application to get/set capability from/in a data source. */ +typedef struct { + TW_UINT16 Cap; + TW_UINT16 ConType; + TW_HANDLE hContainer; +} TW_CAPABILITY, FAR * pTW_CAPABILITY; + +/* Defines a CIE XYZ space tri-stimulus value. */ +typedef struct { + TW_FIX32 X; + TW_FIX32 Y; + TW_FIX32 Z; +} TW_CIEPOINT, FAR * pTW_CIEPOINT; + +/* Defines the mapping from an RGB color space device into CIE 1931 (XYZ) color space. */ +typedef struct { + TW_UINT16 ColorSpace; + TW_INT16 LowEndian; + TW_INT16 DeviceDependent; + TW_INT32 VersionNumber; + TW_TRANSFORMSTAGE StageABC; + TW_TRANSFORMSTAGE StageLMN; + TW_CIEPOINT WhitePoint; + TW_CIEPOINT BlackPoint; + TW_CIEPOINT WhitePaper; + TW_CIEPOINT BlackInk; + TW_FIX32 Samples[1]; +} TW_CIECOLOR, FAR * pTW_CIECOLOR; + +/* Allows for a data source and application to pass custom data to each other. */ +typedef struct { + TW_UINT32 InfoLength; + TW_HANDLE hData; +}TW_CUSTOMDSDATA, FAR *pTW_CUSTOMDSDATA; + +/* Provides information about the Event that was raised by the Source */ +typedef struct { + TW_UINT32 Event; + TW_STR255 DeviceName; + TW_UINT32 BatteryMinutes; + TW_INT16 BatteryPercentage; + TW_INT32 PowerSupply; + TW_FIX32 XResolution; + TW_FIX32 YResolution; + TW_UINT32 FlashUsed2; + TW_UINT32 AutomaticCapture; + TW_UINT32 TimeBeforeFirstCapture; + TW_UINT32 TimeBetweenCaptures; +} TW_DEVICEEVENT, FAR * pTW_DEVICEEVENT; + +/* This structure holds the tri-stimulus color palette information for TW_PALETTE8 structures.*/ +typedef struct { + TW_UINT8 Index; + TW_UINT8 Channel1; + TW_UINT8 Channel2; + TW_UINT8 Channel3; +} TW_ELEMENT8, FAR * pTW_ELEMENT8; + +/* Stores a group of individual values describing a capability. */ +typedef struct { + TW_UINT16 ItemType; + TW_UINT32 NumItems; + TW_UINT32 CurrentIndex; + TW_UINT32 DefaultIndex; + TW_UINT8 ItemList[1]; +} TW_ENUMERATION, FAR * pTW_ENUMERATION; + +/* Used to pass application events/messages from the application to the Source. */ +typedef struct { + TW_MEMREF pEvent; + TW_UINT16 TWMessage; +} TW_EVENT, FAR * pTW_EVENT; + +/* This structure is used to pass specific information between the data source and the application. */ +typedef struct { + TW_UINT16 InfoID; + TW_UINT16 ItemType; + TW_UINT16 NumItems; + union { + TW_UINT16 ReturnCode; + TW_UINT16 CondCode; // Deprecated, do not use + }; + TW_UINTPTR Item; +}TW_INFO, FAR* pTW_INFO; + +typedef struct { + TW_UINT32 NumInfos; + TW_INFO Info[1]; +}TW_EXTIMAGEINFO, FAR* pTW_EXTIMAGEINFO; + +/* Provides information about the currently selected device */ +typedef struct { + TW_STR255 InputName; + TW_STR255 OutputName; + TW_MEMREF Context; + union { + int Recursive; + TW_BOOL Subdirectories; + }; + union { + TW_INT32 FileType; + TW_UINT32 FileSystemType; + }; + TW_UINT32 Size; + TW_STR32 CreateTimeDate; + TW_STR32 ModifiedTimeDate; + TW_UINT32 FreeSpace; + TW_INT32 NewImageSize; + TW_UINT32 NumberOfFiles; + TW_UINT32 NumberOfSnippets; + TW_UINT32 DeviceGroupMask; + TW_INT8 Reserved[508]; +} TW_FILESYSTEM, FAR * pTW_FILESYSTEM; + +/* This structure is used by the application to specify a set of mapping values to be applied to grayscale data. */ +typedef struct { + TW_ELEMENT8 Response[1]; +} TW_GRAYRESPONSE, FAR * pTW_GRAYRESPONSE; + +/* A general way to describe the version of software that is running. */ +typedef struct { + TW_UINT16 MajorNum; + TW_UINT16 MinorNum; + TW_UINT16 Language; + TW_UINT16 Country; + TW_STR32 Info; +} TW_VERSION, FAR * pTW_VERSION; + +/* Provides identification information about a TWAIN entity.*/ +typedef struct { + #if defined(__APPLE__) /* cf: Mac version of TWAIN.h */ + TW_MEMREF Id; + #else + TW_UINT32 Id; + #endif + TW_VERSION Version; + TW_UINT16 ProtocolMajor; + TW_UINT16 ProtocolMinor; + TW_UINT32 SupportedGroups; + TW_STR32 Manufacturer; + TW_STR32 ProductFamily; + TW_STR32 ProductName; +} TW_IDENTITY, FAR * pTW_IDENTITY; + +/* Describes the "real" image data, that is, the complete image being transferred between the Source and application. */ +typedef struct { + TW_FIX32 XResolution; + TW_FIX32 YResolution; + TW_INT32 ImageWidth; + TW_INT32 ImageLength; + TW_INT16 SamplesPerPixel; + TW_INT16 BitsPerSample[8]; + TW_INT16 BitsPerPixel; + TW_BOOL Planar; + TW_INT16 PixelType; + TW_UINT16 Compression; +} TW_IMAGEINFO, FAR * pTW_IMAGEINFO; + +/* Involves information about the original size of the acquired image. */ +typedef struct { + TW_FRAME Frame; + TW_UINT32 DocumentNumber; + TW_UINT32 PageNumber; + TW_UINT32 FrameNumber; +} TW_IMAGELAYOUT, FAR * pTW_IMAGELAYOUT; + +/* Provides information for managing memory buffers. */ +typedef struct { + TW_UINT32 Flags; + TW_UINT32 Length; + TW_MEMREF TheMem; +} TW_MEMORY, FAR * pTW_MEMORY; + +/* Describes the form of the acquired data being passed from the Source to the application.*/ +typedef struct { + TW_UINT16 Compression; + TW_UINT32 BytesPerRow; + TW_UINT32 Columns; + TW_UINT32 Rows; + TW_UINT32 XOffset; + TW_UINT32 YOffset; + TW_UINT32 BytesWritten; + TW_MEMORY Memory; +} TW_IMAGEMEMXFER, FAR * pTW_IMAGEMEMXFER; + +/* Describes the information necessary to transfer a JPEG-compressed image. */ +typedef struct { + TW_UINT16 ColorSpace; + TW_UINT32 SubSampling; + TW_UINT16 NumComponents; + TW_UINT16 RestartFrequency; + TW_UINT16 QuantMap[4]; + TW_MEMORY QuantTable[4]; + TW_UINT16 HuffmanMap[4]; + TW_MEMORY HuffmanDC[2]; + TW_MEMORY HuffmanAC[2]; +} TW_JPEGCOMPRESSION, FAR * pTW_JPEGCOMPRESSION; + +/* Collects scanning metrics after returning to state 4 */ +typedef struct { + TW_UINT32 SizeOf; + TW_UINT32 ImageCount; + TW_UINT32 SheetCount; +} TW_METRICS, FAR * pTW_METRICS; + +/* Stores a single value (item) which describes a capability. */ +typedef struct { + TW_UINT16 ItemType; + TW_UINT32 Item; +} TW_ONEVALUE, FAR * pTW_ONEVALUE; + +/* This structure holds the color palette information. */ +typedef struct { + TW_UINT16 NumColors; + TW_UINT16 PaletteType; + TW_ELEMENT8 Colors[256]; +} TW_PALETTE8, FAR * pTW_PALETTE8; + +/* Used to bypass the TWAIN protocol when communicating with a device */ +typedef struct { + TW_MEMREF pCommand; + TW_UINT32 CommandBytes; + TW_INT32 Direction; + TW_MEMREF pData; + TW_UINT32 DataBytes; + TW_UINT32 DataBytesXfered; +} TW_PASSTHRU, FAR * pTW_PASSTHRU; + +/* This structure tells the application how many more complete transfers the Source currently has available. */ +typedef struct { + TW_UINT16 Count; + union { + TW_UINT32 EOJ; + TW_UINT32 Reserved; + #if defined(__APPLE__) /* cf: Mac version of TWAIN.h */ + union { + TW_UINT32 EOJ; + TW_UINT32 Reserved; + } TW_JOBCONTROL; + #endif + }; +} TW_PENDINGXFERS, FAR *pTW_PENDINGXFERS; + +/* Stores a range of individual values describing a capability. */ +typedef struct { + TW_UINT16 ItemType; + TW_UINT32 MinValue; + TW_UINT32 MaxValue; + TW_UINT32 StepSize; + TW_UINT32 DefaultValue; + TW_UINT32 CurrentValue; +} TW_RANGE, FAR * pTW_RANGE; + +/* This structure is used by the application to specify a set of mapping values to be applied to RGB color data. */ +typedef struct { + TW_ELEMENT8 Response[1]; +} TW_RGBRESPONSE, FAR * pTW_RGBRESPONSE; + +/* Describes the file format and file specification information for a transfer through a disk file. */ +typedef struct { + TW_STR255 FileName; + TW_UINT16 Format; + TW_INT16 VRefNum; +} TW_SETUPFILEXFER, FAR * pTW_SETUPFILEXFER; + +/* Provides the application information about the Source's requirements and preferences regarding allocation of transfer buffer(s). */ +typedef struct { + TW_UINT32 MinBufSize; + TW_UINT32 MaxBufSize; + TW_UINT32 Preferred; +} TW_SETUPMEMXFER, FAR * pTW_SETUPMEMXFER; + +/* Describes the status of a source. */ +typedef struct { + TW_UINT16 ConditionCode; + union { + TW_UINT16 Data; + TW_UINT16 Reserved; + }; +} TW_STATUS, FAR * pTW_STATUS; + +/* Translates the contents of Status into a localized UTF8string. */ +typedef struct { + TW_STATUS Status; + TW_UINT32 Size; + TW_HANDLE UTF8string; +} TW_STATUSUTF8, FAR * pTW_STATUSUTF8; + +typedef struct { + TW_UINT32 SizeOf; + TW_UINT16 CommunicationManager; + TW_HANDLE Send; + TW_UINT32 SendSize; + TW_HANDLE Receive; + TW_UINT32 ReceiveSize; +} TW_TWAINDIRECT, FAR * pTW_TWAINDIRECT; + +/* This structure is used to handle the user interface coordination between an application and a Source. */ +typedef struct { + TW_BOOL ShowUI; + TW_BOOL ModalUI; + TW_HANDLE hParent; +} TW_USERINTERFACE, FAR * pTW_USERINTERFACE; + + +/**************************************************************************** + * Generic Constants * + ****************************************************************************/ + +#define TWON_ARRAY 3 +#define TWON_ENUMERATION 4 +#define TWON_ONEVALUE 5 +#define TWON_RANGE 6 + +#define TWON_ICONID 962 +#define TWON_DSMID 461 +#define TWON_DSMCODEID 63 + +#define TWON_DONTCARE8 0xff +#define TWON_DONTCARE16 0xffff +#define TWON_DONTCARE32 0xffffffff + +/* Flags used in TW_MEMORY structure. */ +#define TWMF_APPOWNS 0x0001 +#define TWMF_DSMOWNS 0x0002 +#define TWMF_DSOWNS 0x0004 +#define TWMF_POINTER 0x0008 +#define TWMF_HANDLE 0x0010 + +#define TWTY_INT8 0x0000 +#define TWTY_INT16 0x0001 +#define TWTY_INT32 0x0002 + +#define TWTY_UINT8 0x0003 +#define TWTY_UINT16 0x0004 +#define TWTY_UINT32 0x0005 + +#define TWTY_BOOL 0x0006 + +#define TWTY_FIX32 0x0007 + +#define TWTY_FRAME 0x0008 + +#define TWTY_STR32 0x0009 +#define TWTY_STR64 0x000a +#define TWTY_STR128 0x000b +#define TWTY_STR255 0x000c +#define TWTY_HANDLE 0x000f + + +/**************************************************************************** + * Capability Constants * + ****************************************************************************/ + +/* CAP_ALARMS values */ +#define TWAL_ALARM 0 +#define TWAL_FEEDERERROR 1 +#define TWAL_FEEDERWARNING 2 +#define TWAL_BARCODE 3 +#define TWAL_DOUBLEFEED 4 +#define TWAL_JAM 5 +#define TWAL_PATCHCODE 6 +#define TWAL_POWER 7 +#define TWAL_SKEW 8 + +/* ICAP_AUTOSIZE values */ +#define TWAS_NONE 0 +#define TWAS_AUTO 1 +#define TWAS_CURRENT 2 + +/* TWEI_BARCODEROTATION values */ +#define TWBCOR_ROT0 0 +#define TWBCOR_ROT90 1 +#define TWBCOR_ROT180 2 +#define TWBCOR_ROT270 3 +#define TWBCOR_ROTX 4 + +/* ICAP_BARCODESEARCHMODE values */ +#define TWBD_HORZ 0 +#define TWBD_VERT 1 +#define TWBD_HORZVERT 2 +#define TWBD_VERTHORZ 3 + +/* ICAP_BITORDER values */ +#define TWBO_LSBFIRST 0 +#define TWBO_MSBFIRST 1 + +/* ICAP_AUTODISCARDBLANKPAGES values */ +#define TWBP_DISABLE -2 +#define TWBP_AUTO -1 + +/* ICAP_BITDEPTHREDUCTION values */ +#define TWBR_THRESHOLD 0 +#define TWBR_HALFTONE 1 +#define TWBR_CUSTHALFTONE 2 +#define TWBR_DIFFUSION 3 +#define TWBR_DYNAMICTHRESHOLD 4 + +/* ICAP_SUPPORTEDBARCODETYPES and TWEI_BARCODETYPE values*/ +#define TWBT_3OF9 0 +#define TWBT_2OF5INTERLEAVED 1 +#define TWBT_2OF5NONINTERLEAVED 2 +#define TWBT_CODE93 3 +#define TWBT_CODE128 4 +#define TWBT_UCC128 5 +#define TWBT_CODABAR 6 +#define TWBT_UPCA 7 +#define TWBT_UPCE 8 +#define TWBT_EAN8 9 +#define TWBT_EAN13 10 +#define TWBT_POSTNET 11 +#define TWBT_PDF417 12 +#define TWBT_2OF5INDUSTRIAL 13 +#define TWBT_2OF5MATRIX 14 +#define TWBT_2OF5DATALOGIC 15 +#define TWBT_2OF5IATA 16 +#define TWBT_3OF9FULLASCII 17 +#define TWBT_CODABARWITHSTARTSTOP 18 +#define TWBT_MAXICODE 19 +#define TWBT_QRCODE 20 + +/* ICAP_COMPRESSION values*/ +#define TWCP_NONE 0 +#define TWCP_PACKBITS 1 +#define TWCP_GROUP31D 2 +#define TWCP_GROUP31DEOL 3 +#define TWCP_GROUP32D 4 +#define TWCP_GROUP4 5 +#define TWCP_JPEG 6 +#define TWCP_LZW 7 +#define TWCP_JBIG 8 +#define TWCP_PNG 9 +#define TWCP_RLE4 10 +#define TWCP_RLE8 11 +#define TWCP_BITFIELDS 12 +#define TWCP_ZIP 13 +#define TWCP_JPEG2000 14 + +/* CAP_CAMERASIDE and TWEI_PAGESIDE values */ +#define TWCS_BOTH 0 +#define TWCS_TOP 1 +#define TWCS_BOTTOM 2 + +/* CAP_DEVICEEVENT values */ +#define TWDE_CUSTOMEVENTS 0x8000 +#define TWDE_CHECKAUTOMATICCAPTURE 0 +#define TWDE_CHECKBATTERY 1 +#define TWDE_CHECKDEVICEONLINE 2 +#define TWDE_CHECKFLASH 3 +#define TWDE_CHECKPOWERSUPPLY 4 +#define TWDE_CHECKRESOLUTION 5 +#define TWDE_DEVICEADDED 6 +#define TWDE_DEVICEOFFLINE 7 +#define TWDE_DEVICEREADY 8 +#define TWDE_DEVICEREMOVED 9 +#define TWDE_IMAGECAPTURED 10 +#define TWDE_IMAGEDELETED 11 +#define TWDE_PAPERDOUBLEFEED 12 +#define TWDE_PAPERJAM 13 +#define TWDE_LAMPFAILURE 14 +#define TWDE_POWERSAVE 15 +#define TWDE_POWERSAVENOTIFY 16 + +/* TW_PASSTHRU.Direction values. */ +#define TWDR_GET 1 +#define TWDR_SET 2 + +/* TWEI_DESKEWSTATUS values. */ +#define TWDSK_SUCCESS 0 +#define TWDSK_REPORTONLY 1 +#define TWDSK_FAIL 2 +#define TWDSK_DISABLED 3 + +/* CAP_DUPLEX values */ +#define TWDX_NONE 0 +#define TWDX_1PASSDUPLEX 1 +#define TWDX_2PASSDUPLEX 2 + +/* CAP_FEEDERALIGNMENT values */ +#define TWFA_NONE 0 +#define TWFA_LEFT 1 +#define TWFA_CENTER 2 +#define TWFA_RIGHT 3 + +/* ICAP_FEEDERTYPE values*/ +#define TWFE_GENERAL 0 +#define TWFE_PHOTO 1 + +/* ICAP_IMAGEFILEFORMAT values */ +#define TWFF_TIFF 0 +#define TWFF_PICT 1 +#define TWFF_BMP 2 +#define TWFF_XBM 3 +#define TWFF_JFIF 4 +#define TWFF_FPX 5 +#define TWFF_TIFFMULTI 6 +#define TWFF_PNG 7 +#define TWFF_SPIFF 8 +#define TWFF_EXIF 9 +#define TWFF_PDF 10 +#define TWFF_JP2 11 +#define TWFF_JPX 13 +#define TWFF_DEJAVU 14 +#define TWFF_PDFA 15 +#define TWFF_PDFA2 16 +#define TWFF_PDFRASTER 17 + +/* ICAP_FLASHUSED2 values */ +#define TWFL_NONE 0 +#define TWFL_OFF 1 +#define TWFL_ON 2 +#define TWFL_AUTO 3 +#define TWFL_REDEYE 4 + +/* CAP_FEEDERORDER values */ +#define TWFO_FIRSTPAGEFIRST 0 +#define TWFO_LASTPAGEFIRST 1 + +/* CAP_FEEDERPOCKET values*/ +#define TWFP_POCKETERROR 0 +#define TWFP_POCKET1 1 +#define TWFP_POCKET2 2 +#define TWFP_POCKET3 3 +#define TWFP_POCKET4 4 +#define TWFP_POCKET5 5 +#define TWFP_POCKET6 6 +#define TWFP_POCKET7 7 +#define TWFP_POCKET8 8 +#define TWFP_POCKET9 9 +#define TWFP_POCKET10 10 +#define TWFP_POCKET11 11 +#define TWFP_POCKET12 12 +#define TWFP_POCKET13 13 +#define TWFP_POCKET14 14 +#define TWFP_POCKET15 15 +#define TWFP_POCKET16 16 + +/* ICAP_FLIPROTATION values */ +#define TWFR_BOOK 0 +#define TWFR_FANFOLD 1 + +/* ICAP_FILTER values */ +#define TWFT_RED 0 +#define TWFT_GREEN 1 +#define TWFT_BLUE 2 +#define TWFT_NONE 3 +#define TWFT_WHITE 4 +#define TWFT_CYAN 5 +#define TWFT_MAGENTA 6 +#define TWFT_YELLOW 7 +#define TWFT_BLACK 8 + +/* TW_FILESYSTEM.FileType values */ +#define TWFY_CAMERA 0 +#define TWFY_CAMERATOP 1 +#define TWFY_CAMERABOTTOM 2 +#define TWFY_CAMERAPREVIEW 3 +#define TWFY_DOMAIN 4 +#define TWFY_HOST 5 +#define TWFY_DIRECTORY 6 +#define TWFY_IMAGE 7 +#define TWFY_UNKNOWN 8 + +/* ICAP_ICCPROFILE values */ +#define TWIC_NONE 0 +#define TWIC_LINK 1 +#define TWIC_EMBED 2 + +/* ICAP_IMAGEFILTER values */ +#define TWIF_NONE 0 +#define TWIF_AUTO 1 +#define TWIF_LOWPASS 2 +#define TWIF_BANDPASS 3 +#define TWIF_HIGHPASS 4 +#define TWIF_TEXT TWIF_BANDPASS +#define TWIF_FINELINE TWIF_HIGHPASS + +/* ICAP_IMAGEMERGE values */ +#define TWIM_NONE 0 +#define TWIM_FRONTONTOP 1 +#define TWIM_FRONTONBOTTOM 2 +#define TWIM_FRONTONLEFT 3 +#define TWIM_FRONTONRIGHT 4 + +/* CAP_JOBCONTROL values */ +#define TWJC_NONE 0 +#define TWJC_JSIC 1 +#define TWJC_JSIS 2 +#define TWJC_JSXC 3 +#define TWJC_JSXS 4 + +/* ICAP_JPEGQUALITY values */ +#define TWJQ_UNKNOWN -4 +#define TWJQ_LOW -3 +#define TWJQ_MEDIUM -2 +#define TWJQ_HIGH -1 + +/* ICAP_LIGHTPATH values */ +#define TWLP_REFLECTIVE 0 +#define TWLP_TRANSMISSIVE 1 + +/* ICAP_LIGHTSOURCE values */ +#define TWLS_RED 0 +#define TWLS_GREEN 1 +#define TWLS_BLUE 2 +#define TWLS_NONE 3 +#define TWLS_WHITE 4 +#define TWLS_UV 5 +#define TWLS_IR 6 + +/* TWEI_MAGTYPE values */ +#define TWMD_MICR 0 +#define TWMD_RAW 1 +#define TWMD_INVALID 2 + +/* ICAP_NOISEFILTER values */ +#define TWNF_NONE 0 +#define TWNF_AUTO 1 +#define TWNF_LONEPIXEL 2 +#define TWNF_MAJORITYRULE 3 + +/* ICAP_ORIENTATION values */ +#define TWOR_ROT0 0 +#define TWOR_ROT90 1 +#define TWOR_ROT180 2 +#define TWOR_ROT270 3 +#define TWOR_PORTRAIT TWOR_ROT0 +#define TWOR_LANDSCAPE TWOR_ROT270 +#define TWOR_AUTO 4 +#define TWOR_AUTOTEXT 5 +#define TWOR_AUTOPICTURE 6 + +/* ICAP_OVERSCAN values */ +#define TWOV_NONE 0 +#define TWOV_AUTO 1 +#define TWOV_TOPBOTTOM 2 +#define TWOV_LEFTRIGHT 3 +#define TWOV_ALL 4 + +/* Palette types for TW_PALETTE8 */ +#define TWPA_RGB 0 +#define TWPA_GRAY 1 +#define TWPA_CMY 2 + +/* ICAP_PLANARCHUNKY values */ +#define TWPC_CHUNKY 0 +#define TWPC_PLANAR 1 + +/* TWEI_PATCHCODE values*/ +#define TWPCH_PATCH1 0 +#define TWPCH_PATCH2 1 +#define TWPCH_PATCH3 2 +#define TWPCH_PATCH4 3 +#define TWPCH_PATCH6 4 +#define TWPCH_PATCHT 5 + +/* ICAP_PIXELFLAVOR values */ +#define TWPF_CHOCOLATE 0 +#define TWPF_VANILLA 1 + +/* CAP_PRINTERMODE values */ +#define TWPM_SINGLESTRING 0 +#define TWPM_MULTISTRING 1 +#define TWPM_COMPOUNDSTRING 2 + +/* CAP_PRINTER values */ +#define TWPR_IMPRINTERTOPBEFORE 0 +#define TWPR_IMPRINTERTOPAFTER 1 +#define TWPR_IMPRINTERBOTTOMBEFORE 2 +#define TWPR_IMPRINTERBOTTOMAFTER 3 +#define TWPR_ENDORSERTOPBEFORE 4 +#define TWPR_ENDORSERTOPAFTER 5 +#define TWPR_ENDORSERBOTTOMBEFORE 6 +#define TWPR_ENDORSERBOTTOMAFTER 7 + +/* CAP_PRINTERFONTSTYLE Added 2.3 */ +#define TWPF_NORMAL 0 +#define TWPF_BOLD 1 +#define TWPF_ITALIC 2 +#define TWPF_LARGESIZE 3 +#define TWPF_SMALLSIZE 4 + +/* CAP_PRINTERINDEXTRIGGER Added 2.3 */ +#define TWCT_PAGE 0 +#define TWCT_PATCH1 1 +#define TWCT_PATCH2 2 +#define TWCT_PATCH3 3 +#define TWCT_PATCH4 4 +#define TWCT_PATCHT 5 +#define TWCT_PATCH6 6 + +/* CAP_POWERSUPPLY values */ +#define TWPS_EXTERNAL 0 +#define TWPS_BATTERY 1 + +/* ICAP_PIXELTYPE values (PT_ means Pixel Type) */ +#define TWPT_BW 0 +#define TWPT_GRAY 1 +#define TWPT_RGB 2 +#define TWPT_PALETTE 3 +#define TWPT_CMY 4 +#define TWPT_CMYK 5 +#define TWPT_YUV 6 +#define TWPT_YUVK 7 +#define TWPT_CIEXYZ 8 +#define TWPT_LAB 9 +#define TWPT_SRGB 10 +#define TWPT_SCRGB 11 +#define TWPT_INFRARED 16 + +/* CAP_SEGMENTED values */ +#define TWSG_NONE 0 +#define TWSG_AUTO 1 +#define TWSG_MANUAL 2 + +/* ICAP_FILMTYPE values */ +#define TWFM_POSITIVE 0 +#define TWFM_NEGATIVE 1 + +/* CAP_DOUBLEFEEDDETECTION */ +#define TWDF_ULTRASONIC 0 +#define TWDF_BYLENGTH 1 +#define TWDF_INFRARED 2 + +/* CAP_DOUBLEFEEDDETECTIONSENSITIVITY */ +#define TWUS_LOW 0 +#define TWUS_MEDIUM 1 +#define TWUS_HIGH 2 + +/* CAP_DOUBLEFEEDDETECTIONRESPONSE */ +#define TWDP_STOP 0 +#define TWDP_STOPANDWAIT 1 +#define TWDP_SOUND 2 +#define TWDP_DONOTIMPRINT 3 + +/* ICAP_MIRROR values */ +#define TWMR_NONE 0 +#define TWMR_VERTICAL 1 +#define TWMR_HORIZONTAL 2 + +/* ICAP_JPEGSUBSAMPLING values */ +#define TWJS_444YCBCR 0 +#define TWJS_444RGB 1 +#define TWJS_422 2 +#define TWJS_421 3 +#define TWJS_411 4 +#define TWJS_420 5 +#define TWJS_410 6 +#define TWJS_311 7 + +/* CAP_PAPERHANDLING values */ +#define TWPH_NORMAL 0 +#define TWPH_FRAGILE 1 +#define TWPH_THICK 2 +#define TWPH_TRIFOLD 3 +#define TWPH_PHOTOGRAPH 4 + +/* CAP_INDICATORSMODE values */ +#define TWCI_INFO 0 +#define TWCI_WARNING 1 +#define TWCI_ERROR 2 +#define TWCI_WARMUP 3 + +/* ICAP_SUPPORTEDSIZES values (SS_ means Supported Sizes) */ +#define TWSS_NONE 0 +#define TWSS_A4 1 +#define TWSS_JISB5 2 +#define TWSS_USLETTER 3 +#define TWSS_USLEGAL 4 +#define TWSS_A5 5 +#define TWSS_ISOB4 6 +#define TWSS_ISOB6 7 +#define TWSS_USLEDGER 9 +#define TWSS_USEXECUTIVE 10 +#define TWSS_A3 11 +#define TWSS_ISOB3 12 +#define TWSS_A6 13 +#define TWSS_C4 14 +#define TWSS_C5 15 +#define TWSS_C6 16 +#define TWSS_4A0 17 +#define TWSS_2A0 18 +#define TWSS_A0 19 +#define TWSS_A1 20 +#define TWSS_A2 21 +#define TWSS_A7 22 +#define TWSS_A8 23 +#define TWSS_A9 24 +#define TWSS_A10 25 +#define TWSS_ISOB0 26 +#define TWSS_ISOB1 27 +#define TWSS_ISOB2 28 +#define TWSS_ISOB5 29 +#define TWSS_ISOB7 30 +#define TWSS_ISOB8 31 +#define TWSS_ISOB9 32 +#define TWSS_ISOB10 33 +#define TWSS_JISB0 34 +#define TWSS_JISB1 35 +#define TWSS_JISB2 36 +#define TWSS_JISB3 37 +#define TWSS_JISB4 38 +#define TWSS_JISB6 39 +#define TWSS_JISB7 40 +#define TWSS_JISB8 41 +#define TWSS_JISB9 42 +#define TWSS_JISB10 43 +#define TWSS_C0 44 +#define TWSS_C1 45 +#define TWSS_C2 46 +#define TWSS_C3 47 +#define TWSS_C7 48 +#define TWSS_C8 49 +#define TWSS_C9 50 +#define TWSS_C10 51 +#define TWSS_USSTATEMENT 52 +#define TWSS_BUSINESSCARD 53 +#define TWSS_MAXSIZE 54 + +/* ICAP_XFERMECH values (SX_ means Setup XFer) */ +#define TWSX_NATIVE 0 +#define TWSX_FILE 1 +#define TWSX_MEMORY 2 +#define TWSX_MEMFILE 4 + +/* ICAP_UNITS values (UN_ means UNits) */ +#define TWUN_INCHES 0 +#define TWUN_CENTIMETERS 1 +#define TWUN_PICAS 2 +#define TWUN_POINTS 3 +#define TWUN_TWIPS 4 +#define TWUN_PIXELS 5 +#define TWUN_MILLIMETERS 6 + + +/**************************************************************************** + * Country Constants * + ****************************************************************************/ + +#define TWCY_AFGHANISTAN 1001 +#define TWCY_ALGERIA 213 +#define TWCY_AMERICANSAMOA 684 +#define TWCY_ANDORRA 33 +#define TWCY_ANGOLA 1002 +#define TWCY_ANGUILLA 8090 +#define TWCY_ANTIGUA 8091 +#define TWCY_ARGENTINA 54 +#define TWCY_ARUBA 297 +#define TWCY_ASCENSIONI 247 +#define TWCY_AUSTRALIA 61 +#define TWCY_AUSTRIA 43 +#define TWCY_BAHAMAS 8092 +#define TWCY_BAHRAIN 973 +#define TWCY_BANGLADESH 880 +#define TWCY_BARBADOS 8093 +#define TWCY_BELGIUM 32 +#define TWCY_BELIZE 501 +#define TWCY_BENIN 229 +#define TWCY_BERMUDA 8094 +#define TWCY_BHUTAN 1003 +#define TWCY_BOLIVIA 591 +#define TWCY_BOTSWANA 267 +#define TWCY_BRITAIN 6 +#define TWCY_BRITVIRGINIS 8095 +#define TWCY_BRAZIL 55 +#define TWCY_BRUNEI 673 +#define TWCY_BULGARIA 359 +#define TWCY_BURKINAFASO 1004 +#define TWCY_BURMA 1005 +#define TWCY_BURUNDI 1006 +#define TWCY_CAMAROON 237 +#define TWCY_CANADA 2 +#define TWCY_CAPEVERDEIS 238 +#define TWCY_CAYMANIS 8096 +#define TWCY_CENTRALAFREP 1007 +#define TWCY_CHAD 1008 +#define TWCY_CHILE 56 +#define TWCY_CHINA 86 +#define TWCY_CHRISTMASIS 1009 +#define TWCY_COCOSIS 1009 +#define TWCY_COLOMBIA 57 +#define TWCY_COMOROS 1010 +#define TWCY_CONGO 1011 +#define TWCY_COOKIS 1012 +#define TWCY_COSTARICA 506 +#define TWCY_CUBA 5 +#define TWCY_CYPRUS 357 +#define TWCY_CZECHOSLOVAKIA 42 +#define TWCY_DENMARK 45 +#define TWCY_DJIBOUTI 1013 +#define TWCY_DOMINICA 8097 +#define TWCY_DOMINCANREP 8098 +#define TWCY_EASTERIS 1014 +#define TWCY_ECUADOR 593 +#define TWCY_EGYPT 20 +#define TWCY_ELSALVADOR 503 +#define TWCY_EQGUINEA 1015 +#define TWCY_ETHIOPIA 251 +#define TWCY_FALKLANDIS 1016 +#define TWCY_FAEROEIS 298 +#define TWCY_FIJIISLANDS 679 +#define TWCY_FINLAND 358 +#define TWCY_FRANCE 33 +#define TWCY_FRANTILLES 596 +#define TWCY_FRGUIANA 594 +#define TWCY_FRPOLYNEISA 689 +#define TWCY_FUTANAIS 1043 +#define TWCY_GABON 241 +#define TWCY_GAMBIA 220 +#define TWCY_GERMANY 49 +#define TWCY_GHANA 233 +#define TWCY_GIBRALTER 350 +#define TWCY_GREECE 30 +#define TWCY_GREENLAND 299 +#define TWCY_GRENADA 8099 +#define TWCY_GRENEDINES 8015 +#define TWCY_GUADELOUPE 590 +#define TWCY_GUAM 671 +#define TWCY_GUANTANAMOBAY 5399 +#define TWCY_GUATEMALA 502 +#define TWCY_GUINEA 224 +#define TWCY_GUINEABISSAU 1017 +#define TWCY_GUYANA 592 +#define TWCY_HAITI 509 +#define TWCY_HONDURAS 504 +#define TWCY_HONGKONG 852 +#define TWCY_HUNGARY 36 +#define TWCY_ICELAND 354 +#define TWCY_INDIA 91 +#define TWCY_INDONESIA 62 +#define TWCY_IRAN 98 +#define TWCY_IRAQ 964 +#define TWCY_IRELAND 353 +#define TWCY_ISRAEL 972 +#define TWCY_ITALY 39 +#define TWCY_IVORYCOAST 225 +#define TWCY_JAMAICA 8010 +#define TWCY_JAPAN 81 +#define TWCY_JORDAN 962 +#define TWCY_KENYA 254 +#define TWCY_KIRIBATI 1018 +#define TWCY_KOREA 82 +#define TWCY_KUWAIT 965 +#define TWCY_LAOS 1019 +#define TWCY_LEBANON 1020 +#define TWCY_LIBERIA 231 +#define TWCY_LIBYA 218 +#define TWCY_LIECHTENSTEIN 41 +#define TWCY_LUXENBOURG 352 +#define TWCY_MACAO 853 +#define TWCY_MADAGASCAR 1021 +#define TWCY_MALAWI 265 +#define TWCY_MALAYSIA 60 +#define TWCY_MALDIVES 960 +#define TWCY_MALI 1022 +#define TWCY_MALTA 356 +#define TWCY_MARSHALLIS 692 +#define TWCY_MAURITANIA 1023 +#define TWCY_MAURITIUS 230 +#define TWCY_MEXICO 3 +#define TWCY_MICRONESIA 691 +#define TWCY_MIQUELON 508 +#define TWCY_MONACO 33 +#define TWCY_MONGOLIA 1024 +#define TWCY_MONTSERRAT 8011 +#define TWCY_MOROCCO 212 +#define TWCY_MOZAMBIQUE 1025 +#define TWCY_NAMIBIA 264 +#define TWCY_NAURU 1026 +#define TWCY_NEPAL 977 +#define TWCY_NETHERLANDS 31 +#define TWCY_NETHANTILLES 599 +#define TWCY_NEVIS 8012 +#define TWCY_NEWCALEDONIA 687 +#define TWCY_NEWZEALAND 64 +#define TWCY_NICARAGUA 505 +#define TWCY_NIGER 227 +#define TWCY_NIGERIA 234 +#define TWCY_NIUE 1027 +#define TWCY_NORFOLKI 1028 +#define TWCY_NORWAY 47 +#define TWCY_OMAN 968 +#define TWCY_PAKISTAN 92 +#define TWCY_PALAU 1029 +#define TWCY_PANAMA 507 +#define TWCY_PARAGUAY 595 +#define TWCY_PERU 51 +#define TWCY_PHILLIPPINES 63 +#define TWCY_PITCAIRNIS 1030 +#define TWCY_PNEWGUINEA 675 +#define TWCY_POLAND 48 +#define TWCY_PORTUGAL 351 +#define TWCY_QATAR 974 +#define TWCY_REUNIONI 1031 +#define TWCY_ROMANIA 40 +#define TWCY_RWANDA 250 +#define TWCY_SAIPAN 670 +#define TWCY_SANMARINO 39 +#define TWCY_SAOTOME 1033 +#define TWCY_SAUDIARABIA 966 +#define TWCY_SENEGAL 221 +#define TWCY_SEYCHELLESIS 1034 +#define TWCY_SIERRALEONE 1035 +#define TWCY_SINGAPORE 65 +#define TWCY_SOLOMONIS 1036 +#define TWCY_SOMALI 1037 +#define TWCY_SOUTHAFRICA 27 +#define TWCY_SPAIN 34 +#define TWCY_SRILANKA 94 +#define TWCY_STHELENA 1032 +#define TWCY_STKITTS 8013 +#define TWCY_STLUCIA 8014 +#define TWCY_STPIERRE 508 +#define TWCY_STVINCENT 8015 +#define TWCY_SUDAN 1038 +#define TWCY_SURINAME 597 +#define TWCY_SWAZILAND 268 +#define TWCY_SWEDEN 46 +#define TWCY_SWITZERLAND 41 +#define TWCY_SYRIA 1039 +#define TWCY_TAIWAN 886 +#define TWCY_TANZANIA 255 +#define TWCY_THAILAND 66 +#define TWCY_TOBAGO 8016 +#define TWCY_TOGO 228 +#define TWCY_TONGAIS 676 +#define TWCY_TRINIDAD 8016 +#define TWCY_TUNISIA 216 +#define TWCY_TURKEY 90 +#define TWCY_TURKSCAICOS 8017 +#define TWCY_TUVALU 1040 +#define TWCY_UGANDA 256 +#define TWCY_USSR 7 +#define TWCY_UAEMIRATES 971 +#define TWCY_UNITEDKINGDOM 44 +#define TWCY_USA 1 +#define TWCY_URUGUAY 598 +#define TWCY_VANUATU 1041 +#define TWCY_VATICANCITY 39 +#define TWCY_VENEZUELA 58 +#define TWCY_WAKE 1042 +#define TWCY_WALLISIS 1043 +#define TWCY_WESTERNSAHARA 1044 +#define TWCY_WESTERNSAMOA 1045 +#define TWCY_YEMEN 1046 +#define TWCY_YUGOSLAVIA 38 +#define TWCY_ZAIRE 243 +#define TWCY_ZAMBIA 260 +#define TWCY_ZIMBABWE 263 +#define TWCY_ALBANIA 355 +#define TWCY_ARMENIA 374 +#define TWCY_AZERBAIJAN 994 +#define TWCY_BELARUS 375 +#define TWCY_BOSNIAHERZGO 387 +#define TWCY_CAMBODIA 855 +#define TWCY_CROATIA 385 +#define TWCY_CZECHREPUBLIC 420 +#define TWCY_DIEGOGARCIA 246 +#define TWCY_ERITREA 291 +#define TWCY_ESTONIA 372 +#define TWCY_GEORGIA 995 +#define TWCY_LATVIA 371 +#define TWCY_LESOTHO 266 +#define TWCY_LITHUANIA 370 +#define TWCY_MACEDONIA 389 +#define TWCY_MAYOTTEIS 269 +#define TWCY_MOLDOVA 373 +#define TWCY_MYANMAR 95 +#define TWCY_NORTHKOREA 850 +#define TWCY_PUERTORICO 787 +#define TWCY_RUSSIA 7 +#define TWCY_SERBIA 381 +#define TWCY_SLOVAKIA 421 +#define TWCY_SLOVENIA 386 +#define TWCY_SOUTHKOREA 82 +#define TWCY_UKRAINE 380 +#define TWCY_USVIRGINIS 340 +#define TWCY_VIETNAM 84 + +/**************************************************************************** + * Language Constants * + ****************************************************************************/ +#define TWLG_USERLOCALE -1 +#define TWLG_DAN 0 +#define TWLG_DUT 1 +#define TWLG_ENG 2 +#define TWLG_FCF 3 +#define TWLG_FIN 4 +#define TWLG_FRN 5 +#define TWLG_GER 6 +#define TWLG_ICE 7 +#define TWLG_ITN 8 +#define TWLG_NOR 9 +#define TWLG_POR 10 +#define TWLG_SPA 11 +#define TWLG_SWE 12 +#define TWLG_USA 13 +#define TWLG_AFRIKAANS 14 +#define TWLG_ALBANIA 15 +#define TWLG_ARABIC 16 +#define TWLG_ARABIC_ALGERIA 17 +#define TWLG_ARABIC_BAHRAIN 18 +#define TWLG_ARABIC_EGYPT 19 +#define TWLG_ARABIC_IRAQ 20 +#define TWLG_ARABIC_JORDAN 21 +#define TWLG_ARABIC_KUWAIT 22 +#define TWLG_ARABIC_LEBANON 23 +#define TWLG_ARABIC_LIBYA 24 +#define TWLG_ARABIC_MOROCCO 25 +#define TWLG_ARABIC_OMAN 26 +#define TWLG_ARABIC_QATAR 27 +#define TWLG_ARABIC_SAUDIARABIA 28 +#define TWLG_ARABIC_SYRIA 29 +#define TWLG_ARABIC_TUNISIA 30 +#define TWLG_ARABIC_UAE 31 +#define TWLG_ARABIC_YEMEN 32 +#define TWLG_BASQUE 33 +#define TWLG_BYELORUSSIAN 34 +#define TWLG_BULGARIAN 35 +#define TWLG_CATALAN 36 +#define TWLG_CHINESE 37 +#define TWLG_CHINESE_HONGKONG 38 +#define TWLG_CHINESE_PRC 39 +#define TWLG_CHINESE_SINGAPORE 40 +#define TWLG_CHINESE_SIMPLIFIED 41 +#define TWLG_CHINESE_TAIWAN 42 +#define TWLG_CHINESE_TRADITIONAL 43 +#define TWLG_CROATIA 44 +#define TWLG_CZECH 45 +#define TWLG_DANISH TWLG_DAN +#define TWLG_DUTCH TWLG_DUT +#define TWLG_DUTCH_BELGIAN 46 +#define TWLG_ENGLISH TWLG_ENG +#define TWLG_ENGLISH_AUSTRALIAN 47 +#define TWLG_ENGLISH_CANADIAN 48 +#define TWLG_ENGLISH_IRELAND 49 +#define TWLG_ENGLISH_NEWZEALAND 50 +#define TWLG_ENGLISH_SOUTHAFRICA 51 +#define TWLG_ENGLISH_UK 52 +#define TWLG_ENGLISH_USA TWLG_USA +#define TWLG_ESTONIAN 53 +#define TWLG_FAEROESE 54 +#define TWLG_FARSI 55 +#define TWLG_FINNISH TWLG_FIN +#define TWLG_FRENCH TWLG_FRN +#define TWLG_FRENCH_BELGIAN 56 +#define TWLG_FRENCH_CANADIAN TWLG_FCF +#define TWLG_FRENCH_LUXEMBOURG 57 +#define TWLG_FRENCH_SWISS 58 +#define TWLG_GERMAN TWLG_GER +#define TWLG_GERMAN_AUSTRIAN 59 +#define TWLG_GERMAN_LUXEMBOURG 60 +#define TWLG_GERMAN_LIECHTENSTEIN 61 +#define TWLG_GERMAN_SWISS 62 +#define TWLG_GREEK 63 +#define TWLG_HEBREW 64 +#define TWLG_HUNGARIAN 65 +#define TWLG_ICELANDIC TWLG_ICE +#define TWLG_INDONESIAN 66 +#define TWLG_ITALIAN TWLG_ITN +#define TWLG_ITALIAN_SWISS 67 +#define TWLG_JAPANESE 68 +#define TWLG_KOREAN 69 +#define TWLG_KOREAN_JOHAB 70 +#define TWLG_LATVIAN 71 +#define TWLG_LITHUANIAN 72 +#define TWLG_NORWEGIAN TWLG_NOR +#define TWLG_NORWEGIAN_BOKMAL 73 +#define TWLG_NORWEGIAN_NYNORSK 74 +#define TWLG_POLISH 75 +#define TWLG_PORTUGUESE TWLG_POR +#define TWLG_PORTUGUESE_BRAZIL 76 +#define TWLG_ROMANIAN 77 +#define TWLG_RUSSIAN 78 +#define TWLG_SERBIAN_LATIN 79 +#define TWLG_SLOVAK 80 +#define TWLG_SLOVENIAN 81 +#define TWLG_SPANISH TWLG_SPA +#define TWLG_SPANISH_MEXICAN 82 +#define TWLG_SPANISH_MODERN 83 +#define TWLG_SWEDISH TWLG_SWE +#define TWLG_THAI 84 +#define TWLG_TURKISH 85 +#define TWLG_UKRANIAN 86 +#define TWLG_ASSAMESE 87 +#define TWLG_BENGALI 88 +#define TWLG_BIHARI 89 +#define TWLG_BODO 90 +#define TWLG_DOGRI 91 +#define TWLG_GUJARATI 92 +#define TWLG_HARYANVI 93 +#define TWLG_HINDI 94 +#define TWLG_KANNADA 95 +#define TWLG_KASHMIRI 96 +#define TWLG_MALAYALAM 97 +#define TWLG_MARATHI 98 +#define TWLG_MARWARI 99 +#define TWLG_MEGHALAYAN 100 +#define TWLG_MIZO 101 +#define TWLG_NAGA 102 +#define TWLG_ORISSI 103 +#define TWLG_PUNJABI 104 +#define TWLG_PUSHTU 105 +#define TWLG_SERBIAN_CYRILLIC 106 +#define TWLG_SIKKIMI 107 +#define TWLG_SWEDISH_FINLAND 108 +#define TWLG_TAMIL 109 +#define TWLG_TELUGU 110 +#define TWLG_TRIPURI 111 +#define TWLG_URDU 112 +#define TWLG_VIETNAMESE 113 + + +/**************************************************************************** + * Data Groups * + ****************************************************************************/ +#define DG_CONTROL 0x0001L +#define DG_IMAGE 0x0002L +#define DG_AUDIO 0x0004L + +/* More Data Functionality may be added in the future. + * These are for items that need to be determined before DS is opened. + * NOTE: Supported Functionality constants must be powers of 2 as they are + * used as bitflags when Application asks DSM to present a list of DSs. + * to support backward capability the App and DS will not use the fields + */ +#define DF_DSM2 0x10000000L +#define DF_APP2 0x20000000L + +#define DF_DS2 0x40000000L + +#define DG_MASK 0xFFFFL + +/**************************************************************************** + * * + ****************************************************************************/ +#define DAT_NULL 0x0000 +#define DAT_CUSTOMBASE 0x8000 + +/* Data Argument Types for the DG_CONTROL Data Group. */ +#define DAT_CAPABILITY 0x0001 +#define DAT_EVENT 0x0002 +#define DAT_IDENTITY 0x0003 +#define DAT_PARENT 0x0004 +#define DAT_PENDINGXFERS 0x0005 +#define DAT_SETUPMEMXFER 0x0006 +#define DAT_SETUPFILEXFER 0x0007 +#define DAT_STATUS 0x0008 +#define DAT_USERINTERFACE 0x0009 +#define DAT_XFERGROUP 0x000a +#define DAT_CUSTOMDSDATA 0x000c +#define DAT_DEVICEEVENT 0x000d +#define DAT_FILESYSTEM 0x000e +#define DAT_PASSTHRU 0x000f +#define DAT_CALLBACK 0x0010 +#define DAT_STATUSUTF8 0x0011 +#define DAT_CALLBACK2 0x0012 +#define DAT_METRICS 0x0013 +#define DAT_TWAINDIRECT 0x0014 + +/* Data Argument Types for the DG_IMAGE Data Group. */ +#define DAT_IMAGEINFO 0x0101 +#define DAT_IMAGELAYOUT 0x0102 +#define DAT_IMAGEMEMXFER 0x0103 +#define DAT_IMAGENATIVEXFER 0x0104 +#define DAT_IMAGEFILEXFER 0x0105 +#define DAT_CIECOLOR 0x0106 +#define DAT_GRAYRESPONSE 0x0107 +#define DAT_RGBRESPONSE 0x0108 +#define DAT_JPEGCOMPRESSION 0x0109 +#define DAT_PALETTE8 0x010a +#define DAT_EXTIMAGEINFO 0x010b +#define DAT_FILTER 0x010c + +/* Data Argument Types for the DG_AUDIO Data Group. */ +#define DAT_AUDIOFILEXFER 0x0201 +#define DAT_AUDIOINFO 0x0202 +#define DAT_AUDIONATIVEXFER 0x0203 + +/* misplaced */ +#define DAT_ICCPROFILE 0x0401 +#define DAT_IMAGEMEMFILEXFER 0x0402 +#define DAT_ENTRYPOINT 0x0403 + + +/**************************************************************************** + * Messages * + ****************************************************************************/ + +/* All message constants are unique. + * Messages are grouped according to which DATs they are used with.*/ + +#define MSG_NULL 0x0000 +#define MSG_CUSTOMBASE 0x8000 + +/* Generic messages may be used with any of several DATs. */ +#define MSG_GET 0x0001 +#define MSG_GETCURRENT 0x0002 +#define MSG_GETDEFAULT 0x0003 +#define MSG_GETFIRST 0x0004 +#define MSG_GETNEXT 0x0005 +#define MSG_SET 0x0006 +#define MSG_RESET 0x0007 +#define MSG_QUERYSUPPORT 0x0008 +#define MSG_GETHELP 0x0009 +#define MSG_GETLABEL 0x000a +#define MSG_GETLABELENUM 0x000b +#define MSG_SETCONSTRAINT 0x000c + +/* Messages used with DAT_NULL */ +#define MSG_XFERREADY 0x0101 +#define MSG_CLOSEDSREQ 0x0102 +#define MSG_CLOSEDSOK 0x0103 +#define MSG_DEVICEEVENT 0X0104 + +/* Messages used with a pointer to DAT_PARENT data */ +#define MSG_OPENDSM 0x0301 +#define MSG_CLOSEDSM 0x0302 + +/* Messages used with a pointer to a DAT_IDENTITY structure */ +#define MSG_OPENDS 0x0401 +#define MSG_CLOSEDS 0x0402 +#define MSG_USERSELECT 0x0403 + +/* Messages used with a pointer to a DAT_USERINTERFACE structure */ +#define MSG_DISABLEDS 0x0501 +#define MSG_ENABLEDS 0x0502 +#define MSG_ENABLEDSUIONLY 0x0503 + +/* Messages used with a pointer to a DAT_EVENT structure */ +#define MSG_PROCESSEVENT 0x0601 + +/* Messages used with a pointer to a DAT_PENDINGXFERS structure */ +#define MSG_ENDXFER 0x0701 +#define MSG_STOPFEEDER 0x0702 + +/* Messages used with a pointer to a DAT_FILESYSTEM structure */ +#define MSG_CHANGEDIRECTORY 0x0801 +#define MSG_CREATEDIRECTORY 0x0802 +#define MSG_DELETE 0x0803 +#define MSG_FORMATMEDIA 0x0804 +#define MSG_GETCLOSE 0x0805 +#define MSG_GETFIRSTFILE 0x0806 +#define MSG_GETINFO 0x0807 +#define MSG_GETNEXTFILE 0x0808 +#define MSG_RENAME 0x0809 +#define MSG_COPY 0x080A +#define MSG_AUTOMATICCAPTUREDIRECTORY 0x080B + +/* Messages used with a pointer to a DAT_PASSTHRU structure */ +#define MSG_PASSTHRU 0x0901 + +/* used with DAT_CALLBACK */ +#define MSG_REGISTER_CALLBACK 0x0902 + +/* used with DAT_CAPABILITY */ +#define MSG_RESETALL 0x0A01 + +/* used with DAT_TWAINDIRECT */ +#define MSG_SETTASK 0x0B01 + +/**************************************************************************** + * Capabilities * + ****************************************************************************/ + +#define CAP_CUSTOMBASE 0x8000 /* Base of custom capabilities */ + +/* all data sources are REQUIRED to support these caps */ +#define CAP_XFERCOUNT 0x0001 + +/* image data sources are REQUIRED to support these caps */ +#define ICAP_COMPRESSION 0x0100 +#define ICAP_PIXELTYPE 0x0101 +#define ICAP_UNITS 0x0102 +#define ICAP_XFERMECH 0x0103 + +/* all data sources MAY support these caps */ +#define CAP_AUTHOR 0x1000 +#define CAP_CAPTION 0x1001 +#define CAP_FEEDERENABLED 0x1002 +#define CAP_FEEDERLOADED 0x1003 +#define CAP_TIMEDATE 0x1004 +#define CAP_SUPPORTEDCAPS 0x1005 +#define CAP_EXTENDEDCAPS 0x1006 +#define CAP_AUTOFEED 0x1007 +#define CAP_CLEARPAGE 0x1008 +#define CAP_FEEDPAGE 0x1009 +#define CAP_REWINDPAGE 0x100a +#define CAP_INDICATORS 0x100b +#define CAP_PAPERDETECTABLE 0x100d +#define CAP_UICONTROLLABLE 0x100e +#define CAP_DEVICEONLINE 0x100f +#define CAP_AUTOSCAN 0x1010 +#define CAP_THUMBNAILSENABLED 0x1011 +#define CAP_DUPLEX 0x1012 +#define CAP_DUPLEXENABLED 0x1013 +#define CAP_ENABLEDSUIONLY 0x1014 +#define CAP_CUSTOMDSDATA 0x1015 +#define CAP_ENDORSER 0x1016 +#define CAP_JOBCONTROL 0x1017 +#define CAP_ALARMS 0x1018 +#define CAP_ALARMVOLUME 0x1019 +#define CAP_AUTOMATICCAPTURE 0x101a +#define CAP_TIMEBEFOREFIRSTCAPTURE 0x101b +#define CAP_TIMEBETWEENCAPTURES 0x101c +#define CAP_MAXBATCHBUFFERS 0x101e +#define CAP_DEVICETIMEDATE 0x101f +#define CAP_POWERSUPPLY 0x1020 +#define CAP_CAMERAPREVIEWUI 0x1021 +#define CAP_DEVICEEVENT 0x1022 +#define CAP_SERIALNUMBER 0x1024 +#define CAP_PRINTER 0x1026 +#define CAP_PRINTERENABLED 0x1027 +#define CAP_PRINTERINDEX 0x1028 +#define CAP_PRINTERMODE 0x1029 +#define CAP_PRINTERSTRING 0x102a +#define CAP_PRINTERSUFFIX 0x102b +#define CAP_LANGUAGE 0x102c +#define CAP_FEEDERALIGNMENT 0x102d +#define CAP_FEEDERORDER 0x102e +#define CAP_REACQUIREALLOWED 0x1030 +#define CAP_BATTERYMINUTES 0x1032 +#define CAP_BATTERYPERCENTAGE 0x1033 +#define CAP_CAMERASIDE 0x1034 +#define CAP_SEGMENTED 0x1035 +#define CAP_CAMERAENABLED 0x1036 +#define CAP_CAMERAORDER 0x1037 +#define CAP_MICRENABLED 0x1038 +#define CAP_FEEDERPREP 0x1039 +#define CAP_FEEDERPOCKET 0x103a +#define CAP_AUTOMATICSENSEMEDIUM 0x103b +#define CAP_CUSTOMINTERFACEGUID 0x103c +#define CAP_SUPPORTEDCAPSSEGMENTUNIQUE 0x103d +#define CAP_SUPPORTEDDATS 0x103e +#define CAP_DOUBLEFEEDDETECTION 0x103f +#define CAP_DOUBLEFEEDDETECTIONLENGTH 0x1040 +#define CAP_DOUBLEFEEDDETECTIONSENSITIVITY 0x1041 +#define CAP_DOUBLEFEEDDETECTIONRESPONSE 0x1042 +#define CAP_PAPERHANDLING 0x1043 +#define CAP_INDICATORSMODE 0x1044 +#define CAP_PRINTERVERTICALOFFSET 0x1045 +#define CAP_POWERSAVETIME 0x1046 +#define CAP_PRINTERCHARROTATION 0x1047 +#define CAP_PRINTERFONTSTYLE 0x1048 +#define CAP_PRINTERINDEXLEADCHAR 0x1049 +#define CAP_PRINTERINDEXMAXVALUE 0x104A +#define CAP_PRINTERINDEXNUMDIGITS 0x104B +#define CAP_PRINTERINDEXSTEP 0x104C +#define CAP_PRINTERINDEXTRIGGER 0x104D +#define CAP_PRINTERSTRINGPREVIEW 0x104E +#define CAP_SHEETCOUNT 0x104F + + + +/* image data sources MAY support these caps */ +#define ICAP_AUTOBRIGHT 0x1100 +#define ICAP_BRIGHTNESS 0x1101 +#define ICAP_CONTRAST 0x1103 +#define ICAP_CUSTHALFTONE 0x1104 +#define ICAP_EXPOSURETIME 0x1105 +#define ICAP_FILTER 0x1106 +#define ICAP_FLASHUSED 0x1107 +#define ICAP_GAMMA 0x1108 +#define ICAP_HALFTONES 0x1109 +#define ICAP_HIGHLIGHT 0x110a +#define ICAP_IMAGEFILEFORMAT 0x110c +#define ICAP_LAMPSTATE 0x110d +#define ICAP_LIGHTSOURCE 0x110e +#define ICAP_ORIENTATION 0x1110 +#define ICAP_PHYSICALWIDTH 0x1111 +#define ICAP_PHYSICALHEIGHT 0x1112 +#define ICAP_SHADOW 0x1113 +#define ICAP_FRAMES 0x1114 +#define ICAP_XNATIVERESOLUTION 0x1116 +#define ICAP_YNATIVERESOLUTION 0x1117 +#define ICAP_XRESOLUTION 0x1118 +#define ICAP_YRESOLUTION 0x1119 +#define ICAP_MAXFRAMES 0x111a +#define ICAP_TILES 0x111b +#define ICAP_BITORDER 0x111c +#define ICAP_CCITTKFACTOR 0x111d +#define ICAP_LIGHTPATH 0x111e +#define ICAP_PIXELFLAVOR 0x111f +#define ICAP_PLANARCHUNKY 0x1120 +#define ICAP_ROTATION 0x1121 +#define ICAP_SUPPORTEDSIZES 0x1122 +#define ICAP_THRESHOLD 0x1123 +#define ICAP_XSCALING 0x1124 +#define ICAP_YSCALING 0x1125 +#define ICAP_BITORDERCODES 0x1126 +#define ICAP_PIXELFLAVORCODES 0x1127 +#define ICAP_JPEGPIXELTYPE 0x1128 +#define ICAP_TIMEFILL 0x112a +#define ICAP_BITDEPTH 0x112b +#define ICAP_BITDEPTHREDUCTION 0x112c +#define ICAP_UNDEFINEDIMAGESIZE 0x112d +#define ICAP_IMAGEDATASET 0x112e +#define ICAP_EXTIMAGEINFO 0x112f +#define ICAP_MINIMUMHEIGHT 0x1130 +#define ICAP_MINIMUMWIDTH 0x1131 +#define ICAP_AUTODISCARDBLANKPAGES 0x1134 +#define ICAP_FLIPROTATION 0x1136 +#define ICAP_BARCODEDETECTIONENABLED 0x1137 +#define ICAP_SUPPORTEDBARCODETYPES 0x1138 +#define ICAP_BARCODEMAXSEARCHPRIORITIES 0x1139 +#define ICAP_BARCODESEARCHPRIORITIES 0x113a +#define ICAP_BARCODESEARCHMODE 0x113b +#define ICAP_BARCODEMAXRETRIES 0x113c +#define ICAP_BARCODETIMEOUT 0x113d +#define ICAP_ZOOMFACTOR 0x113e +#define ICAP_PATCHCODEDETECTIONENABLED 0x113f +#define ICAP_SUPPORTEDPATCHCODETYPES 0x1140 +#define ICAP_PATCHCODEMAXSEARCHPRIORITIES 0x1141 +#define ICAP_PATCHCODESEARCHPRIORITIES 0x1142 +#define ICAP_PATCHCODESEARCHMODE 0x1143 +#define ICAP_PATCHCODEMAXRETRIES 0x1144 +#define ICAP_PATCHCODETIMEOUT 0x1145 +#define ICAP_FLASHUSED2 0x1146 +#define ICAP_IMAGEFILTER 0x1147 +#define ICAP_NOISEFILTER 0x1148 +#define ICAP_OVERSCAN 0x1149 +#define ICAP_AUTOMATICBORDERDETECTION 0x1150 +#define ICAP_AUTOMATICDESKEW 0x1151 +#define ICAP_AUTOMATICROTATE 0x1152 +#define ICAP_JPEGQUALITY 0x1153 +#define ICAP_FEEDERTYPE 0x1154 +#define ICAP_ICCPROFILE 0x1155 +#define ICAP_AUTOSIZE 0x1156 +#define ICAP_AUTOMATICCROPUSESFRAME 0x1157 +#define ICAP_AUTOMATICLENGTHDETECTION 0x1158 +#define ICAP_AUTOMATICCOLORENABLED 0x1159 +#define ICAP_AUTOMATICCOLORNONCOLORPIXELTYPE 0x115a +#define ICAP_COLORMANAGEMENTENABLED 0x115b +#define ICAP_IMAGEMERGE 0x115c +#define ICAP_IMAGEMERGEHEIGHTTHRESHOLD 0x115d +#define ICAP_SUPPORTEDEXTIMAGEINFO 0x115e +#define ICAP_FILMTYPE 0x115f +#define ICAP_MIRROR 0x1160 +#define ICAP_JPEGSUBSAMPLING 0x1161 + +/* image data sources MAY support these audio caps */ +#define ACAP_XFERMECH 0x1202 + + +/*************************************************************************** + * Extended Image Info Attributes section Added 1.7 * + ***************************************************************************/ + +#define TWEI_BARCODEX 0x1200 +#define TWEI_BARCODEY 0x1201 +#define TWEI_BARCODETEXT 0x1202 +#define TWEI_BARCODETYPE 0x1203 +#define TWEI_DESHADETOP 0x1204 +#define TWEI_DESHADELEFT 0x1205 +#define TWEI_DESHADEHEIGHT 0x1206 +#define TWEI_DESHADEWIDTH 0x1207 +#define TWEI_DESHADESIZE 0x1208 +#define TWEI_SPECKLESREMOVED 0x1209 +#define TWEI_HORZLINEXCOORD 0x120A +#define TWEI_HORZLINEYCOORD 0x120B +#define TWEI_HORZLINELENGTH 0x120C +#define TWEI_HORZLINETHICKNESS 0x120D +#define TWEI_VERTLINEXCOORD 0x120E +#define TWEI_VERTLINEYCOORD 0x120F +#define TWEI_VERTLINELENGTH 0x1210 +#define TWEI_VERTLINETHICKNESS 0x1211 +#define TWEI_PATCHCODE 0x1212 +#define TWEI_ENDORSEDTEXT 0x1213 +#define TWEI_FORMCONFIDENCE 0x1214 +#define TWEI_FORMTEMPLATEMATCH 0x1215 +#define TWEI_FORMTEMPLATEPAGEMATCH 0x1216 +#define TWEI_FORMHORZDOCOFFSET 0x1217 +#define TWEI_FORMVERTDOCOFFSET 0x1218 +#define TWEI_BARCODECOUNT 0x1219 +#define TWEI_BARCODECONFIDENCE 0x121A +#define TWEI_BARCODEROTATION 0x121B +#define TWEI_BARCODETEXTLENGTH 0x121C +#define TWEI_DESHADECOUNT 0x121D +#define TWEI_DESHADEBLACKCOUNTOLD 0x121E +#define TWEI_DESHADEBLACKCOUNTNEW 0x121F +#define TWEI_DESHADEBLACKRLMIN 0x1220 +#define TWEI_DESHADEBLACKRLMAX 0x1221 +#define TWEI_DESHADEWHITECOUNTOLD 0x1222 +#define TWEI_DESHADEWHITECOUNTNEW 0x1223 +#define TWEI_DESHADEWHITERLMIN 0x1224 +#define TWEI_DESHADEWHITERLAVE 0x1225 +#define TWEI_DESHADEWHITERLMAX 0x1226 +#define TWEI_BLACKSPECKLESREMOVED 0x1227 +#define TWEI_WHITESPECKLESREMOVED 0x1228 +#define TWEI_HORZLINECOUNT 0x1229 +#define TWEI_VERTLINECOUNT 0x122A +#define TWEI_DESKEWSTATUS 0x122B +#define TWEI_SKEWORIGINALANGLE 0x122C +#define TWEI_SKEWFINALANGLE 0x122D +#define TWEI_SKEWCONFIDENCE 0x122E +#define TWEI_SKEWWINDOWX1 0x122F +#define TWEI_SKEWWINDOWY1 0x1230 +#define TWEI_SKEWWINDOWX2 0x1231 +#define TWEI_SKEWWINDOWY2 0x1232 +#define TWEI_SKEWWINDOWX3 0x1233 +#define TWEI_SKEWWINDOWY3 0x1234 +#define TWEI_SKEWWINDOWX4 0x1235 +#define TWEI_SKEWWINDOWY4 0x1236 +#define TWEI_BOOKNAME 0x1238 +#define TWEI_CHAPTERNUMBER 0x1239 +#define TWEI_DOCUMENTNUMBER 0x123A +#define TWEI_PAGENUMBER 0x123B +#define TWEI_CAMERA 0x123C +#define TWEI_FRAMENUMBER 0x123D +#define TWEI_FRAME 0x123E +#define TWEI_PIXELFLAVOR 0x123F +#define TWEI_ICCPROFILE 0x1240 +#define TWEI_LASTSEGMENT 0x1241 +#define TWEI_SEGMENTNUMBER 0x1242 +#define TWEI_MAGDATA 0x1243 +#define TWEI_MAGTYPE 0x1244 +#define TWEI_PAGESIDE 0x1245 +#define TWEI_FILESYSTEMSOURCE 0x1246 +#define TWEI_IMAGEMERGED 0x1247 +#define TWEI_MAGDATALENGTH 0x1248 +#define TWEI_PAPERCOUNT 0x1249 +#define TWEI_PRINTERTEXT 0x124A +#define TWEI_TWAINDIRECTMETADATA 0x124B + +#define TWEJ_NONE 0x0000 +#define TWEJ_MIDSEPARATOR 0x0001 +#define TWEJ_PATCH1 0x0002 +#define TWEJ_PATCH2 0x0003 +#define TWEJ_PATCH3 0x0004 +#define TWEJ_PATCH4 0x0005 +#define TWEJ_PATCH6 0x0006 +#define TWEJ_PATCHT 0x0007 + + +/*************************************************************************** + * Return Codes and Condition Codes section * + ***************************************************************************/ + +#define TWRC_CUSTOMBASE 0x8000 + +#define TWRC_SUCCESS 0 +#define TWRC_FAILURE 1 +#define TWRC_CHECKSTATUS 2 +#define TWRC_CANCEL 3 +#define TWRC_DSEVENT 4 +#define TWRC_NOTDSEVENT 5 +#define TWRC_XFERDONE 6 +#define TWRC_ENDOFLIST 7 +#define TWRC_INFONOTSUPPORTED 8 +#define TWRC_DATANOTAVAILABLE 9 +#define TWRC_BUSY 10 +#define TWRC_SCANNERLOCKED 11 + +/* Condition Codes: Application gets these by doing DG_CONTROL DAT_STATUS MSG_GET. */ +#define TWCC_CUSTOMBASE 0x8000 + +#define TWCC_SUCCESS 0 +#define TWCC_BUMMER 1 +#define TWCC_LOWMEMORY 2 +#define TWCC_NODS 3 +#define TWCC_MAXCONNECTIONS 4 +#define TWCC_OPERATIONERROR 5 +#define TWCC_BADCAP 6 +#define TWCC_BADPROTOCOL 9 +#define TWCC_BADVALUE 10 +#define TWCC_SEQERROR 11 +#define TWCC_BADDEST 12 +#define TWCC_CAPUNSUPPORTED 13 +#define TWCC_CAPBADOPERATION 14 +#define TWCC_CAPSEQERROR 15 +#define TWCC_DENIED 16 +#define TWCC_FILEEXISTS 17 +#define TWCC_FILENOTFOUND 18 +#define TWCC_NOTEMPTY 19 +#define TWCC_PAPERJAM 20 +#define TWCC_PAPERDOUBLEFEED 21 +#define TWCC_FILEWRITEERROR 22 +#define TWCC_CHECKDEVICEONLINE 23 +#define TWCC_INTERLOCK 24 +#define TWCC_DAMAGEDCORNER 25 +#define TWCC_FOCUSERROR 26 +#define TWCC_DOCTOOLIGHT 27 +#define TWCC_DOCTOODARK 28 +#define TWCC_NOMEDIA 29 + +/* bit patterns: for query the operation that are supported by the data source on a capability */ +/* Application gets these through DG_CONTROL/DAT_CAPABILITY/MSG_QUERYSUPPORT */ +#define TWQC_GET 0x0001 +#define TWQC_SET 0x0002 +#define TWQC_GETDEFAULT 0x0004 +#define TWQC_GETCURRENT 0x0008 +#define TWQC_RESET 0x0010 +#define TWQC_SETCONSTRAINT 0x0020 +#define TWQC_GETHELP 0x0100 +#define TWQC_GETLABEL 0x0200 +#define TWQC_GETLABELENUM 0x0400 + +/**************************************************************************** + * Depreciated Items * + ****************************************************************************/ +#if defined(WIN32) || defined(WIN64) + #define TW_HUGE +#elif !defined(TWH_CMP_GNU) + #define TW_HUGE huge +#else + #define TW_HUGE +#endif + +typedef BYTE TW_HUGE * HPBYTE; +typedef void TW_HUGE * HPVOID; + +typedef unsigned char TW_STR1024[1026], FAR *pTW_STR1026, FAR *pTW_STR1024; +typedef wchar_t TW_UNI512[512], FAR *pTW_UNI512; + +#define TWTY_STR1024 0x000d +#define TWTY_UNI512 0x000e + +#define TWFF_JPN 12 + +#define DAT_TWUNKIDENTITY 0x000b +#define DAT_SETUPFILEXFER2 0x0301 + +#define CAP_CLEARBUFFERS 0x101d +#define CAP_SUPPORTEDCAPSEXT 0x100c +#define CAP_FILESYSTEM //0x???? +#define CAP_PAGEMULTIPLEACQUIRE 0x1023 +#define CAP_PAPERBINDING 0x102f +#define CAP_PASSTHRU 0x1031 +#define CAP_POWERDOWNTIME 0x1034 +#define ACAP_AUDIOFILEFORMAT 0x1201 + +#define MSG_CHECKSTATUS 0x0201 + +#define MSG_INVOKE_CALLBACK 0x0903 /* Mac Only, deprecated - use DAT_NULL and MSG_xxx instead */ + +#define TWQC_CONSTRAINABLE 0x0040 + +#define TWSX_FILE2 3 + +/* CAP_FILESYSTEM values (FS_ means file system) */ +#define TWFS_FILESYSTEM 0 +#define TWFS_RECURSIVEDELETE 1 + +/* ICAP_PIXELTYPE values (PT_ means Pixel Type) */ +#define TWPT_SRGB64 11 +#define TWPT_BGR 12 +#define TWPT_CIELAB 13 +#define TWPT_CIELUV 14 +#define TWPT_YCBCR 15 + +/* ICAP_SUPPORTEDSIZES values (SS_ means Supported Sizes) */ +#define TWSS_B 8 +#define TWSS_A4LETTER TWSS_A4 +#define TWSS_B3 TWSS_ISOB3 +#define TWSS_B4 TWSS_ISOB4 +#define TWSS_B6 TWSS_ISOB6 +#define TWSS_B5LETTER TWSS_JISB5 + +/* ACAP_AUDIOFILEFORMAT values (AF_ means audio format). Added 1.8 */ +#define TWAF_WAV 0 +#define TWAF_AIFF 1 +#define TWAF_AU 3 +#define TWAF_SND 4 + +/* CAP_CLEARBUFFERS values */ +#define TWCB_AUTO 0 +#define TWCB_CLEAR 1 +#define TWCB_NOCLEAR 2 + +/* DAT_SETUPFILEXFER2. Sets up DS to application data transfer via a file. Added 1.9 */ +typedef struct { + TW_MEMREF FileName; + TW_UINT16 FileNameType; + TW_UINT16 Format; + TW_INT16 VRefNum; + TW_UINT32 parID; +} TW_SETUPFILEXFER2, FAR * pTW_SETUPFILEXFER2; + +/* DAT_TWUNKIDENTITY. Provides DS identity and 'other' information necessary */ +/* across thunk link. */ +typedef struct { + TW_IDENTITY identity; + TW_STR255 dsPath; +} TW_TWUNKIDENTITY, FAR * pTW_TWUNKIDENTITY; + +/* Provides DS_Entry parameters over thunk link. */ +typedef struct +{ + TW_INT8 destFlag; + TW_IDENTITY dest; + TW_INT32 dataGroup; + TW_INT16 dataArgType; + TW_INT16 message; + TW_INT32 pDataSize; + // TW_MEMREF pData; +} TW_TWUNKDSENTRYPARAMS, FAR * pTW_TWUNKDSENTRYPARAMS; + +/* Provides DS_Entry results over thunk link. */ +typedef struct +{ + TW_UINT16 returnCode; + TW_UINT16 conditionCode; + TW_INT32 pDataSize; + // TW_MEMREF pData; +} TW_TWUNKDSENTRYRETURN, FAR * pTW_TWUNKDSENTRYRETURN; + +typedef struct +{ + TW_UINT16 Cap; + TW_UINT16 Properties; +} TW_CAPEXT, FAR * pTW_CAPEXT; + +/* DAT_SETUPAUDIOFILEXFER, information required to setup an audio file transfer */ +typedef struct { + TW_STR255 FileName; /* full path target file */ + TW_UINT16 Format; /* one of TWAF_xxxx */ + TW_INT16 VRefNum; +} TW_SETUPAUDIOFILEXFER, FAR * pTW_SETUPAUDIOFILEXFER; + + +/**************************************************************************** + * Entry Points * + ****************************************************************************/ + +/********************************************************************** + * Function: DSM_Entry, the only entry point into the Data Source Manager. + ********************************************************************/ +#ifdef TWH_CMP_MSC + #define TW_CALLINGSTYLE PASCAL +#else + #define TW_CALLINGSTYLE +#endif + +/* Don't mangle the name "DSM_Entry" if we're compiling in C++! */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +TW_UINT16 TW_CALLINGSTYLE DSM_Entry( pTW_IDENTITY pOrigin, + pTW_IDENTITY pDest, + TW_UINT32 DG, + TW_UINT16 DAT, + TW_UINT16 MSG, + TW_MEMREF pData); + +typedef TW_UINT16 (TW_CALLINGSTYLE *DSMENTRYPROC)(pTW_IDENTITY pOrigin, + pTW_IDENTITY pDest, + TW_UINT32 DG, + TW_UINT16 DAT, + TW_UINT16 MSG, + TW_MEMREF pData); +#ifdef __cplusplus +} +#endif /* cplusplus */ + + +/********************************************************************** + * Function: DS_Entry, the entry point provided by a Data Source. + ********************************************************************/ +/* Don't mangle the name "DS_Entry" if we're compiling in C++! */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +TW_UINT16 TW_CALLINGSTYLE DS_Entry(pTW_IDENTITY pOrigin, + TW_UINT32 DG, + TW_UINT16 DAT, + TW_UINT16 MSG, + TW_MEMREF pData); + +typedef TW_UINT16 (FAR PASCAL *DSENTRYPROC)(pTW_IDENTITY pOrigin, + TW_UINT32 DG, + TW_UINT16 DAT, + TW_UINT16 MSG, + TW_MEMREF pData); + +TW_UINT16 TW_CALLINGSTYLE TWAIN_Callback( pTW_IDENTITY pOrigin, + pTW_IDENTITY pDest, + TW_UINT32 DG, + TW_UINT16 DAT, + TW_UINT16 MSG, + TW_MEMREF pData); +typedef TW_UINT16 (TW_CALLINGSTYLE *TWAINCALLBACKPROC)(pTW_IDENTITY pOrigin, + pTW_IDENTITY pDest, + TW_UINT32 DG, + TW_UINT16 DAT, + TW_UINT16 MSG, + TW_MEMREF pData); + +TW_HANDLE TW_CALLINGSTYLE DSM_MemAllocate (TW_UINT32); +typedef TW_HANDLE (TW_CALLINGSTYLE *DSM_MEMALLOCATE)(TW_UINT32 _size); + +void TW_CALLINGSTYLE DSM_MemFree (TW_HANDLE); +typedef void (TW_CALLINGSTYLE *DSM_MEMFREE)(TW_HANDLE _handle); + +TW_MEMREF TW_CALLINGSTYLE DSM_MemLock (TW_HANDLE); +typedef TW_MEMREF (TW_CALLINGSTYLE *DSM_MEMLOCK)(TW_HANDLE _handle); + +void TW_CALLINGSTYLE DSM_MemUnlock (TW_HANDLE); +typedef void (TW_CALLINGSTYLE *DSM_MEMUNLOCK)(TW_HANDLE _handle); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +/* DAT_ENTRYPOINT. returns essential entry points. */ +typedef struct { + TW_UINT32 Size; + DSMENTRYPROC DSM_Entry; + DSM_MEMALLOCATE DSM_MemAllocate; + DSM_MEMFREE DSM_MemFree; + DSM_MEMLOCK DSM_MemLock; + DSM_MEMUNLOCK DSM_MemUnlock; +} TW_ENTRYPOINT, FAR * pTW_ENTRYPOINT; + +/* DAT_FILTER*/ +typedef struct { + TW_UINT32 Size; + TW_UINT32 HueStart; + TW_UINT32 HueEnd; + TW_UINT32 SaturationStart; + TW_UINT32 SaturationEnd; + TW_UINT32 ValueStart; + TW_UINT32 ValueEnd; + TW_UINT32 Replacement; +} TW_FILTER_DESCRIPTOR, *pTW_FILTER_DESCRIPTOR; + +/* DAT_FILTER */ +typedef struct { + TW_UINT32 Size; + TW_UINT32 DescriptorCount; + TW_UINT32 MaxDescriptorCount; + TW_UINT32 Condition; + TW_HANDLE hDescriptors; +} TW_FILTER, *pTW_FILTER; + + +/* Restore the previous packing alignment: this occurs after all structures are defined */ +#ifdef TWH_CMP_MSC + #pragma pack (pop, before_twain) +#elif defined(TWH_CMP_GNU) + #if defined(__APPLE__) /* cf: Mac version of TWAIN.h */ + #pragma options align = reset + #else + #pragma pack (pop, before_twain) + #endif +#elif defined(TWH_CMP_BORLAND) + #pragma option -a. +#endif + +#endif /* TWAIN */ diff --git a/huagaotwain/twain/twpp.hpp b/huagaotwain/twain/twpp.hpp new file mode 100644 index 0000000..a3d95a1 --- /dev/null +++ b/huagaotwain/twain/twpp.hpp @@ -0,0 +1,114 @@ +/* + +The MIT License (MIT) + +Copyright (c) 2015 Martin Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef TWPP_DETAIL_FILE_TWPP_HPP +#define TWPP_DETAIL_FILE_TWPP_HPP + +#include "twpp/env.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "twpp/utils.hpp" + +#include "twpp/types.hpp" +#include "twpp/strings.hpp" +#include "twpp/fix32.hpp" +#include "twpp/frame.hpp" +#include "twpp/exception.hpp" +#include "twpp/typesops.hpp" + +#include "twpp/memoryops.hpp" +#include "twpp/memory.hpp" + +#include "twpp/enums.hpp" +#include "twpp/status.hpp" +#include "twpp/identity.hpp" +#include "twpp/imageinfo.hpp" +#include "twpp/imagelayout.hpp" +#include "twpp/deviceevent.hpp" +#include "twpp/element8.hpp" + +#include "twpp/audio.hpp" +#include "twpp/capability.hpp" +#include "twpp/customdata.hpp" +#include "twpp/cie.hpp" +#include "twpp/curveresponse.hpp" +#include "twpp/event.hpp" +#include "twpp/extimageinfo.hpp" +#include "twpp/filesystem.hpp" +#include "twpp/imagememxfer.hpp" +#include "twpp/imagenativexfer.hpp" +#include "twpp/internal.hpp" +#include "twpp/jpegcompression.hpp" +#include "twpp/palette8.hpp" +#include "twpp/passthrough.hpp" +#include "twpp/pendingxfers.hpp" +#include "twpp/setupfilexfer.hpp" +#include "twpp/setupmemxfer.hpp" +#include "twpp/userinterface.hpp" + +#if !defined(TWPP_IS_DS) +# include "twpp/application.hpp" +#else +# include "twpp/datasource.hpp" +#endif + + +#if !defined(TWPP_NO_NOTES) +# if !defined(TWPP_IS_DS) +# pragma message ("note: using APPLICATION version of TWPP library, define TWPP_IS_DS before including twpp.hpp if you want DATA SOURCE version") +# if defined(TWPP_DETAIL_OS_WIN32) +# pragma message ("note: place the following into your module-definition (.def) file: EXPORTS DS_Entry @1") +# endif +# else +# pragma message ("note: using DATA SOURCE version of TWPP library, undefine TWPP_IS_DS if you want APPLICATION version") +# pragma message ("note: make sure to place TWPP_ENTRY() macro in exactly one source file") +# endif +# if defined(TWPP_DETAIL_OS_MAC) +# pragma message "warning: Str32, Str64, Str128 and Str255 are not null-terminated" +# endif +# pragma message ("note: to disable notes and warnings, define TWPP_NO_NOTES before including TWPP header") +#endif + + +#endif // TWPP_DETAIL_FILE_TWPP_HPP diff --git a/huagaotwain/twain/twpp/application.hpp b/huagaotwain/twain/twpp/application.hpp new file mode 100644 index 0000000..7ad02c7 --- /dev/null +++ b/huagaotwain/twain/twpp/application.hpp @@ -0,0 +1,1153 @@ +/* + +The MIT License (MIT) + +Copyright (c) 2015-2017 Martin Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef TWPP_DETAIL_FILE_APPLICATION_HPP +#define TWPP_DETAIL_FILE_APPLICATION_HPP + +#include "../twpp.hpp" + +namespace Twpp { + +namespace Detail { + +struct ManagerData { + + ManagerData(const Identity& appId) noexcept : + m_appId(appId){} + + Identity m_appId; + DsmState m_state = DsmState::PreSession; + Detail::DsmLib m_lib; + Detail::DsmEntry m_entry = nullptr; + +#if defined(TWPP_DETAIL_OS_WIN) + Handle m_rootWindow; + bool m_ownRootWindow; +#elif defined(TWPP_DETAIL_OS_MAC) + Detail::NSAutoreleasePool m_autoreleasePool; +#elif !defined(TWPP_DETAIL_OS_LINUX) +# error "ManagerData for your platform here" +#endif + +}; + +struct SourceData { + + SourceData(ManagerData* mgr, const Identity& srcIdent) noexcept : + m_mgr(mgr), m_srcId(srcIdent){} + + ManagerData* m_mgr; + std::function m_devEvent; + Handle m_uiHandle; + Identity m_srcId; + DsState m_state = DsState::Closed; + Msg m_readyMsg = Msg::Null; + +#if defined(TWPP_DETAIL_OS_LINUX) + std::mutex m_cbMutex; + std::condition_variable m_cbCond; +#elif !defined(TWPP_DETAIL_OS_WIN) && !defined(TWPP_DETAIL_OS_MAC) +# error "SourceData for your platform here" +#endif + +}; + +} + +class Manager; + +/// A single TWAIN source. +/// Source must belong to a manager in order to perform operations on it. +/// Any valid source instance must be destroyed or at least cleaned by `cleanup` +/// before parent manager is itself destroyed. +/// +/// `call` vs +/// They are ultimately the same: +/// `call` is more suitable for cases that need fixed number of arguments. +/// is better for user-defined calls. +class Source { + + friend class Manager; + +public: + typedef std::function EventCallBack; + + /// Creates an invalid source. + /// Calling any method on such source results in + /// undefined behaviour, and possibly segfault. + /// Only isValid() and operator bool() may be called. + Source() noexcept{} + + ~Source(){ + if (isValid()){ + cleanup(); + } + } + + Source(Source&&) = default; + Source& operator=(Source&& o) noexcept{ + if (&o != this){ + if (isValid()){ + cleanup(); + } + + m_data = std::move(o.m_data); + } + + return *this; + } + + /// Performs explicit cleanup. + /// Ultimately closes the source. + void cleanup() noexcept{ + assert(isValid()); + + PendingXfers xfers; + + switch (d()->m_state){ + case DsState::Xferring: + pendingXfers(Msg::EndXfer, xfers); + // fallthrough + case DsState::XferReady: + if (d()->m_state == DsState::XferReady){ // EndXfer might have moved to DsState::Enabled + pendingXfers(Msg::Reset, xfers); + } + + // fallthrough + case DsState::Enabled: + disable(); + // fallthrough + case DsState::Open: + close(); + // reset the ref even if close() fails somehow + Static::g_openSource = nullptr; + // fallthrough + case DsState::Closed: + break; + } + } + + /// TWAIN state of the source. + DsState state() const noexcept{ + assert(isValid()); + + return d()->m_state; + } + + /// Whether the source is valid. + /// Valid source was created by manager. + /// Invalid source was created using default constructor. + bool isValid() const noexcept{ + return static_cast(m_data); + } + + operator bool() const noexcept{ + return isValid(); + } + + /// Identity of the source. + const Identity& identity() const noexcept{ + assert(isValid()); + + return d()->m_srcId; + } + + /// Sets function (object) to receive device event notifications. + /// + /// {In state 5 (enabled), the function should only set a flag and return immediately. + /// `waitReady()` then returns CheckStatus, and the device event may be processed in + /// the main thread. Call `waitReady()` again once you are done.} + void setEventCallBack(EventCallBack devEvent){ + assert(isValid()); + + d()->m_devEvent = std::move(devEvent); + } + + + // Control -> + + /// Opens the source. + /// Only up to 1 source may be opened at the same time. + /// \throw std::bad_alloc + ReturnCode open(){ + assert(Static::g_openSource == nullptr); + + auto rc = dsm(nullptr, DataGroup::Control, Dat::Identity, Msg::OpenDs, d()->m_srcId); + if (success(rc)){ + d()->m_state = DsState::Open; + + // TWAIN manual is rather confusing on this topic. + // Their example sends the registration to DSM, operation tripet documentation mentions DS as destination. + // Looking at some other applications, Windows seems to send this to DS, MacOS to DSM. + Detail::CallBack cb1(callBack, static_cast(0), Msg::Null); + +#if defined(TWPP_DETAIL_OS_WIN) || defined(TWPP_DETAIL_OS_LINUX) + Detail::CallBack2 cb2(callBack, 0, Msg::Null); + + bool usesCb = success(dsm(DataGroup::Control, Dat::Callback2, Msg::RegisterCallback, cb2)) || + success(dsm(DataGroup::Control, Dat::Callback, Msg::RegisterCallback, cb1)); +#elif defined(TWPP_DETAIL_OS_MAC) + bool usesCb = success(dsm(nullptr, DataGroup::Control, Dat::Callback, Msg::RegisterCallback, cb1)); +#else +# error "callback setup for your platform here" +#endif + +#if defined(TWPP_DETAIL_OS_WIN) + Detail::unused(usesCb); +#elif defined(TWPP_DETAIL_OS_MAC) || defined(TWPP_DETAIL_OS_LINUX) + if (!usesCb){ + close(); + return ReturnCode::Failure; + } +#else +# error "source open setup for your platform here" +#endif + Static::g_openSource = d(); + } + + return rc; + } + + /// Closes the source. + ReturnCode close(){ + ReturnCode rc = dsm(nullptr, DataGroup::Control, Dat::Identity, Msg::CloseDs, d()->m_srcId); + if (success(rc)){ + Static::g_openSource = nullptr; + d()->m_state = DsState::Closed; + } + + return rc; + } + + /// Enables the source, showing its GUI if requested. + /// A call to `waitReady` must follow, advanced users may look at `processEvent` on Windows. + /// \param ui GUI settings. + /// \param uiOnly Whether the GUI should only be used to change values, not scan. + ReturnCode enable(const UserInterface& ui, bool uiOnly = false) noexcept{ + auto uiTmp = ui; // allow ui to be const, dsm doesnt take const + ReturnCode rc = dsm(DataGroup::Control, Dat::UserInterface, uiOnly ? Msg::EnableDsUiOnly : Msg::EnableDs, uiTmp); + if (success(rc) || (!uiOnly && rc == ReturnCode::CheckStatus)){ + d()->m_readyMsg = Msg::Null; + d()->m_uiHandle = ui.parent(); + d()->m_state = DsState::Enabled; + } + + return rc; + } + + /// Disables this source. + ReturnCode disable(){ + assert(isValid()); + + UserInterface ui(false, false, d()->m_uiHandle); + auto rc = dsm(DataGroup::Control, Dat::UserInterface, Msg::DisableDs, ui); + if (success(rc)){ + d()->m_state = DsState::Open; + } + + return rc; + } + + /// Waits on source GUI, blocking. + /// This method is meant for CMD applications, see `processEvent()` for GUI-friendly version. + /// The state is moved to XferReady, when Success is returned, and the source is enabled with full UI (uiOnly = false). + /// On Windows and Mac OS, call this method from the main thread, GUI events are processed here. + /// On Linux, this method may be called from any thread, GUI events are NOT processed. + /// Call this again after processing device event. + /// \return {Failure on error, Cancel on CANCEL button, Success on SAVE or SCAN button, + /// CheckStatus on device event.} + ReturnCode waitReady(){ + assert(isValid()); + + if (d()->m_state != DsState::Enabled){ + return ReturnCode::Failure; + } + +#if defined(TWPP_DETAIL_OS_WIN) + MSG msg; + memset(&msg, 0, sizeof(msg)); + + Event event(&msg, Msg::Null); + while (d()->m_readyMsg == Msg::Null){ + auto val = GetMessage(&msg, nullptr, 0, 0); + if (val == 0 || val == -1){ // 0 ... WM_QUIT; -1 ... error; otherwise ... success + return ReturnCode::Failure; + } + + auto rc = dsm(DataGroup::Control, Dat::Event, Msg::ProcessEvent, event); + switch (rc){ + case ReturnCode::NotDsEvent: + TranslateMessage(&msg); + DispatchMessage(&msg); + // fallthrough + case ReturnCode::DsEvent: + if (d()->m_readyMsg == Msg::Null){ + d()->m_readyMsg = event.message(); + } + + break; + + default: + return rc; + } + } +#elif defined(TWPP_DETAIL_OS_MAC) + Detail::NSAutoreleasePool pool; + + while(d()->m_readyMsg == Msg::Null) { + Detail::NSLoop::processEvent(); + } + + pool.release(); + +#elif defined(TWPP_DETAIL_OS_LINUX) + std::unique_lock lock(d()->m_cbMutex); + while (d()->m_readyMsg == Msg::Null){ + d()->m_cbCond.wait(lock); + } +#else +# error "waitReady for your platform here" +#endif + + switch (d()->m_readyMsg){ + case Msg::XferReady: // ok/scan button <=> Msg::EnableDs + d()->m_state = DsState::XferReady; + case Msg::CloseDsOk: // ok/scan button <=> Msg::EnableDsUiOnly + return ReturnCode::Success; + + case Msg::CloseDsReq: // cancel button + return ReturnCode::Cancel; + + case Msg::DeviceEvent: + d()->m_readyMsg = Msg::Null; + return ReturnCode::CheckStatus; + + default: + return ReturnCode::Failure; + } + } + + /// Processes a single GUI event without blocking. + /// Can be used instead of `waitReady()` to process a single event. + /// Windows users must pass events from GUI loop to this method to be sent to DS. + /// \return {Failure on error, Cancel on CANCEL button, Success on SAVE or SCAN button, + /// CheckStatus on device event. NotDsEvent OR DsEvent when not ready yet.} +#if defined (TWPP_DETAIL_OS_WIN) + ReturnCode processEvent(MSG* event){ + Event twEvent(event, Msg::Null); + auto rc = dsm(DataGroup::Control, Dat::Event, Msg::ProcessEvent, twEvent); + switch (rc){ + case ReturnCode::DsEvent: + case ReturnCode::NotDsEvent: + if (d()->m_readyMsg == Msg::Null){ + d()->m_readyMsg = twEvent.message(); + } + + break; + + default: + return rc; + } + + auto msg = d()->m_readyMsg; + +#elif defined(TWPP_DETAIL_OS_LINUX) || defined(TWPP_DETAIL_OS_MAC) + ReturnCode processEvent(){ + assert(isValid()); + auto rc = ReturnCode::NotDsEvent; + +# if defined(TWPP_DETAIL_OS_MAC) + auto msg = d()->m_readyMsg; +# else + std::unique_lock lock(d()->m_cbMutex); + auto msg = d()->m_readyMsg; + lock.unlock(); +# endif + +#else +# error "processEvent for your platform here" +#endif + switch (msg){ + case Msg::XferReady: // ok/scan button <=> Msg::EnableDs + d()->m_state = DsState::XferReady; + // fallthrough + case Msg::CloseDsOk: // ok/scan button <=> Msg::EnableDsUiOnly + return ReturnCode::Success; + + case Msg::CloseDsReq: // cancel button + return ReturnCode::Cancel; + + case Msg::DeviceEvent: + d()->m_readyMsg = Msg::Null; + return ReturnCode::CheckStatus; + + case Msg::Null: + return rc; + + default: + return ReturnCode::Failure; + } + } + + /// Sends custom, user-defined data to the source. + /// This operation is unsafe, there is no way to discover + /// possible connection state changes. + /// \tparam T Data type. + /// \param dg Data group. + /// \param dat Custom data type identifier. Dat::CustomBase and greater. + /// \param msg Message, action to perform. + /// \param data Custom data. + template + ReturnCode customBase(DataGroup dg, Dat dat, Msg msg, T& data){ + return dsm(dg, dat, msg, data); + } + + /// Sends custom, user-defined data to the source. + /// This operation is unsafe, there is no way to discover + /// possible connection state changes. + /// \param dg Data group. + /// \param dat Custom data type identifier. Dat::CustomBase and greater. + /// \param msg Message, action to perform. + /// \param data Custom data. + ReturnCode customBase(DataGroup dg, Dat dat, Msg msg, void* data){ + return dsmPtr(dg, dat, msg, data); + } + + ReturnCode capability(Msg msg, Capability& inOut){ + return call(DataGroup::Control, msg, inOut); + } + + /// \throw CapTypeException When input capability type does not match the + /// capability type of this template class. + /// \throw CapItemTypeException When input capability item type does not match + /// the expected item type of the capability. + template + ReturnCode capability(Msg msg, Cap& inOut){ + return call(DataGroup::Control, msg, inOut); + } + + ReturnCode customData(Msg msg, CustomData& inOut){ + return call(DataGroup::Control, msg, inOut); + } + + ReturnCode deviceEvent(DeviceEvent& out){ + return call(DataGroup::Control, Msg::Get, out); + } + + ReturnCode fileSystem(Msg msg, FileSystem& inOut){ + return call(DataGroup::Control, msg, inOut); + } + + ReturnCode passThrough(PassThrough& inOut){ + return call(DataGroup::Control, Msg::PassThrough, inOut); + } + + ReturnCode pendingXfers(Msg msg, PendingXfers& inOut){ + return call(DataGroup::Control, msg, inOut); + } + + ReturnCode setupFileXfer(Msg msg, SetupFileXfer& inOut){ + return call(DataGroup::Control, msg, inOut); + } + + ReturnCode setupMemXfer(SetupMemXfer& out){ + return call(DataGroup::Control, Msg::Get, out); + } + + ReturnCode xferGroup(Msg msg, DataGroup& inOut){ + return call(DataGroup::Control, msg, inOut); + } + + ReturnCode status(Status& out){ + return call(DataGroup::Control, Msg::Get, out); + } + + ReturnCode statusUtf8(StatusUtf8& inOut){ + return call(DataGroup::Control, Msg::Get, inOut); + } + // <- Control + + + // Image -> + // TODO CieColor + /* + ReturnCode cieColor(CieColor& out){ + return call(DataGroup::Image, Msg::Get, out); + }*/ + + ReturnCode extImageInfo(ExtImageInfo& inOut){ + return call(DataGroup::Image, Msg::Get, inOut); + } + + ReturnCode grayResponse(Msg msg, GrayResponse& inOut){ + return call(DataGroup::Image, msg, inOut); + } + + ReturnCode iccProfile(IccProfileMemory& out){ + return call(DataGroup::Image, Msg::Get, out); + } + + ReturnCode imageFileXfer(){ + return call(DataGroup::Image, Msg::Get, ImageFileXfer()); + } + + ReturnCode imageInfo(ImageInfo& out){ + return call(DataGroup::Image, Msg::Get, out); + } + + ReturnCode imageLayout(Msg msg, ImageLayout& inOut){ + return call(DataGroup::Image, msg, inOut); + } + + ReturnCode imageMemFileXfer(ImageMemFileXfer& inOut){ + return call(DataGroup::Image, Msg::Get, inOut); + } + + ReturnCode imageMemXfer(ImageMemXfer& inOut){ + return call(DataGroup::Image, Msg::Get, inOut); + } + + ReturnCode imageNativeXfer(ImageNativeXfer& out){ + return call(DataGroup::Image, Msg::Get, out); + } + + ReturnCode jpegCompression(Msg msg, JpegCompression& inOut){ + return call(DataGroup::Image, msg, inOut); + } + + ReturnCode palette8(Msg msg, Palette8& inOut){ + return call(DataGroup::Image, msg, inOut); + } + + ReturnCode rgbResponse(Msg msg, RgbResponse& inOut){ + return call(DataGroup::Image, msg, inOut); + } + // <- Image + + + // Audio -> + ReturnCode audioFileXfer(){ + return call(DataGroup::Audio, Msg::Get, AudioFileXfer()); + } + + ReturnCode audioInfo(AudioInfo& out){ + return call(DataGroup::Audio, Msg::Get, out); + } + + ReturnCode audioNativeXfer(AudioNativeXfer& out){ + return call(DataGroup::Audio, Msg::Get, out); + } + // <- Audio + + + // Raw -> + + // dg:: control follows + ReturnCode call(DataGroup dg, Msg msg, Capability& data){ + return dsm(dg, Dat::Capability, msg, data); + } + + /// \throw CapTypeException When input capability type does not match the + /// capability type of this template class. + /// \throw CapItemTypeException When input capability item type does not match + /// the expected item type of the capability. + template + ReturnCode call(DataGroup dg, Msg msg, Cap& data){ + auto rc = call(dg, msg, data.m_cap); + data.checkTypes(); + return rc; + } + + ReturnCode call(DataGroup dg, Msg msg, CustomData& data){ + return dsm(dg, Dat::CustomData, msg, data); + } + + ReturnCode call(DataGroup dg, Msg msg, DeviceEvent& data){ + return dsm(dg, Dat::DeviceEvent, msg, data); + } + + ReturnCode call(DataGroup dg, Msg msg, FileSystem& data){ + return dsm(dg, Dat::FileSystem, msg, data); + } + + ReturnCode call(DataGroup dg, Msg msg, PassThrough& data){ + return dsm(dg, Dat::PassThrough, msg, data); + } + + ReturnCode call(DataGroup dg, Msg msg, PendingXfers& data){ + auto rc = dsm(dg, Dat::PendingXfers, msg, data); + if (success(rc)){ + // FIXME: unsure about audio state transitions + DataGroup xg = DataGroup::Image; + switch (msg){ + case Msg::EndXfer: + xferGroup(Msg::Get, xg); + if (xg == DataGroup::Image && data.count() == 0){ + d()->m_state = DsState::Enabled; + } else { + d()->m_state = DsState::XferReady; + } + + break; + + case Msg::Reset: + xferGroup(Msg::Get, xg); + if (xg == DataGroup::Image){ + d()->m_state = DsState::Enabled; + } + + break; + + default: + break; + } + + + } + + return rc; + } + + ReturnCode call(DataGroup dg, Msg msg, SetupFileXfer& data){ + return dsm(dg, Dat::SetupFileXfer, msg, data); + } + + ReturnCode call(DataGroup dg, Msg msg, SetupMemXfer& data){ + return dsm(dg, Dat::SetupMemXfer, msg, data); + } + + ReturnCode call(DataGroup dg, Msg msg, DataGroup& data){ + return dsm(dg, Dat::XferGroup, msg, data); + } + + ReturnCode call(DataGroup dg, Msg msg, Status& data){ + return dsm(dg, Dat::Status, msg, data); + } + + ReturnCode call(DataGroup dg, Msg msg, StatusUtf8& data){ + return dsm(dg, Dat::StatusUtf8, msg, data); + } + + // dg::image follows + // TODO CieColor + /* + ReturnCode call(DataGroup dg, Msg msg, CieColor& data){ + return dsm(dg, Dat::CieColor, msg, data); + }*/ + + ReturnCode call(DataGroup dg, Msg msg, ExtImageInfo& data){ + char* raw = *Detail::alias_cast(&data); // ExtImageInfo is just an envelope; raw ~ ExtImageInfo.m_data + return dsmPtr(dg, Dat::ExtImageInfo, msg, raw); + } + + ReturnCode call(DataGroup dg, Msg msg, GrayResponse& data){ + return dsmPtr(dg, Dat::GrayResponse, msg, data.data()); + } + + ReturnCode call(DataGroup dg, Msg msg, IccProfileMemory& data){ + Memory mem; // DS allocates and owns the memory + ReturnCode rc = dsm(dg, Dat::IccProfile, msg, mem); + if (success(rc)){ + data = std::move(mem); + } + + return rc; + } + + ReturnCode call(DataGroup dg, Msg msg, const ImageFileXfer&){ + ReturnCode rc = dsmPtr(dg, Dat::ImageFileXfer, msg, nullptr); + if (success(rc)){ + d()->m_state = DsState::Xferring; + } + + return rc; + } + + ReturnCode call(DataGroup dg, Msg msg, ImageInfo& data){ + return dsm(dg, Dat::ImageInfo, msg, data); + } + + ReturnCode call(DataGroup dg, Msg msg, ImageLayout& data){ + return dsm(dg, Dat::ImageLayout, msg, data); + } + + ReturnCode call(DataGroup dg, Msg msg, ImageMemFileXfer& data){ + ReturnCode rc = dsm(dg, Dat::ImageMemFileXfer, msg, data); + if (success(rc) || rc == ReturnCode::XferDone){ + d()->m_state = DsState::Xferring; + } + + return rc; + } + + ReturnCode call(DataGroup dg, Msg msg, ImageMemXfer& data){ + ReturnCode rc = dsm(dg, Dat::ImageMemXfer, msg, data); + if (success(rc) || rc == ReturnCode::XferDone){ + d()->m_state = DsState::Xferring; + } + + return rc; + } + + ReturnCode call(DataGroup dg, Msg msg, ImageNativeXfer& data){ + Handle h; + ReturnCode rc = dsm(dg, Dat::ImageNativeXfer, msg, h); + if (rc == ReturnCode::XferDone){ + d()->m_state = DsState::Xferring; + } + + if (h){ + data = ImageNativeXfer(h); + } + + return rc; + } + + ReturnCode call(DataGroup dg, Msg msg, JpegCompression& data){ + return dsm(dg, Dat::JpegCompression, msg, data); + } + + ReturnCode call(DataGroup dg, Msg msg, Palette8& data){ + return dsm(dg, Dat::Palette8, msg, data); + } + + ReturnCode call(DataGroup dg, Msg msg, RgbResponse& data){ + return dsmPtr(dg, Dat::RgbResponse, msg, data.data()); + } + + // dg::audio follows + ReturnCode call(DataGroup dg, Msg msg, const AudioFileXfer&){ + // FIXME: unsure about state transitions + ReturnCode rc = dsmPtr(dg, Dat::AudioFileXfer, msg, nullptr); + if (rc == ReturnCode::XferDone){ + d()->m_state = DsState::Xferring; + } + + return rc; + } + + ReturnCode call(DataGroup dg, Msg msg, AudioInfo& data){ + return dsm(dg, Dat::AudioInfo, msg, data); + } + + ReturnCode call(DataGroup dg, Msg msg, AudioNativeXfer& data){ + Handle h; + ReturnCode rc = dsm(dg, Dat::AudioNativeXfer, msg, h); + if (success(rc)){ + d()->m_state = DsState::Xferring; + } + + if (h){ + data = AudioNativeXfer(h); + } + + return rc; + } + // <- Raw + +private: + Source(Detail::ManagerData* mgr, const Identity& srcId) : + m_data(new Detail::SourceData(mgr, srcId)){} + + Detail::SourceData* d() noexcept{ + return m_data.get(); + } + + const Detail::SourceData* d() const noexcept{ + return m_data.get(); + } + + template + ReturnCode dsm(Identity* dest, DataGroup dg, Dat dat, Msg msg, T& data) noexcept{ + return dsmPtr(dest, dg, dat, msg, &data); + } + + ReturnCode dsmPtr(Identity* dest, DataGroup dg, Dat dat, Msg msg, void* data) noexcept{ + assert(isValid()); + + auto mgr = d()->m_mgr; + return mgr->m_entry(&mgr->m_appId, dest, dg, dat, msg, data); + } + + template + ReturnCode dsm(DataGroup dg, Dat dat, Msg msg, T& data) noexcept{ + return dsm(&d()->m_srcId, dg, dat, msg, data); + } + + ReturnCode dsmPtr(DataGroup dg, Dat dat, Msg msg, void* data) noexcept{ + return dsmPtr(&d()->m_srcId, dg, dat, msg, data); + } + + // header-only, yet we need static variables + // templates behave as if defined in at most one source file + template + struct Static { + static Detail::SourceData* g_openSource; + }; + + template + static ReturnCode TWPP_DETAIL_CALLSTYLE callBack( + Identity*, + Identity*, + DataGroup, + Dat, + Msg msg, + void* + ) noexcept{ + Detail::SourceData* src = Static::g_openSource; + if (src == nullptr){ + return ReturnCode::Failure; + } + +#if defined(TWPP_DETAIL_OS_LINUX) + std::unique_lock lock(src->m_cbMutex); + if (src->m_state != DsState::Enabled){ + lock.unlock(); + } +#elif !defined(TWPP_DETAIL_OS_WIN) && !defined(TWPP_DETAIL_OS_MAC) +# error "callBack preparation for your platform here" +#endif + if (msg == Msg::DeviceEvent){ + if (!src->m_devEvent){ + return ReturnCode::Failure; + } + + src->m_devEvent(); + } + + if (src->m_state == DsState::Enabled){ + src->m_readyMsg = msg; + +#if defined(TWPP_DETAIL_OS_WIN) + PostMessageA(static_cast(src->m_mgr->m_rootWindow.raw()), WM_NULL, 0, 0); +#elif defined(TWPP_DETAIL_OS_LINUX) + src->m_cbCond.notify_one(); +#elif defined(TWPP_DETAIL_OS_MAC) + Detail::NSLoop::postDummy(); +#else +# error "callBack for your platform here" +#endif + } + + + return ReturnCode::Success; + } + + std::unique_ptr m_data; + +}; + +template +Detail::SourceData* Source::Static::g_openSource = nullptr; + +/// TWAIN data source manager. +/// At most one valid instance may exist at all times. +/// All corresponding valid sources must be destroyed or cleaned up +/// BEFORE their parent valid manager is closed (destroyed/cleaned up). +class Manager { + +public: + /// Creates an invalid manager. + Manager() noexcept{} + + /// Creates a valid, unloaded manager. + /// \param appIdentity Application identity. + explicit Manager(const Identity& appIdentity) : + m_data(new Detail::ManagerData(appIdentity)){} + + ~Manager(){ + if (isValid()){ + cleanup(); + } + } + + Manager(Manager&&) = default; + Manager& operator=(Manager&& o) noexcept{ + if (&o != this){ + if (isValid()){ + cleanup(); + } + + m_data = std::move(o.m_data); + } + + return *this; + } + + /// Explicitly cleanes the manager, ultimately closing it. + void cleanup() noexcept{ + assert(isValid()); + + switch (d()->m_state){ + case DsmState::Open: + close(); + // fallthrough + case DsmState::Loaded: + unload(); + // fallthrough + case DsmState::PreSession: + // nothing to do now + break; + } + } + + /// Loads the manager library. + /// Not a TWAIN call. + /// \param preferOld {Whether to prefer old DSM (TWAIN_32) instead + /// of the new one (TWAINDSM) on 32bit Windows. + /// Has no effect anywhere else.} + /// \return Whether this call loaded the library. + bool load(bool preferOld = false) noexcept{ + assert(isValid()); + + if (d()->m_state != DsmState::PreSession){ + return false; + } + + if (!d()->m_lib.load(preferOld)){ + return false; + } + + d()->m_state = DsmState::Loaded; + d()->m_entry = d()->m_lib.resolve(); + bool resolved = d()->m_entry != nullptr; + if (!resolved){ + unload(); + } + + return resolved; + } + + /// Unloads the manager library. + /// Not a TWAIN call. + /// \return Whether this call unloaded the library. + bool unload() noexcept{ + assert(isValid()); + + if (d()->m_state != DsmState::Loaded){ + return false; + } + + closeRootWindow(); + d()->m_lib.unload(); + d()->m_state = DsmState::PreSession; + return true; + } + + /// Opens the manager. + ReturnCode open(Handle rootWindow = Handle()) noexcept{ + assert(isValid()); + + if (d()->m_state != DsmState::Loaded){ + return ReturnCode::Failure; + } + +#if defined(TWPP_DETAIL_OS_WIN) + if (rootWindow){ + closeRootWindow(); + d()->m_rootWindow = rootWindow; + d()->m_ownRootWindow = false; + } else { + if (!d()->m_rootWindow || !d()->m_ownRootWindow){ + d()->m_rootWindow = Handle(CreateWindowA("STATIC", nullptr, 0, 0, 0, 0, 0, nullptr, nullptr, nullptr, nullptr)); + if (!d()->m_rootWindow){ + return ReturnCode::Failure; + } + } + + d()->m_ownRootWindow = true; + rootWindow = d()->m_rootWindow; + } +#elif !defined(TWPP_DETAIL_OS_MAC) && !defined(TWPP_DETAIL_OS_LINUX) +# error "manager open setup for your platform here" +#endif + + auto rc = dsm(nullptr, DataGroup::Control, Dat::Parent, Msg::OpenDsm, rootWindow); + if (success(rc)){ + Detail::resetMemFuncs(); + if (d()->m_appId.isDsmV2()){ + Detail::EntryPoint e; + if (success(dsm(nullptr, DataGroup::Control, Dat::EntryPoint, Msg::Get, e))){ + Detail::setMemFuncs(e.m_alloc, e.m_free, e.m_lock, e.m_unlock); + } + } + + d()->m_state = DsmState::Open; + } + + return rc; + } + + /// Closes the manager. + ReturnCode close() noexcept{ + assert(isValid()); + + // no need to check state, dsm will do it for us + +#if defined(TWPP_DETAIL_OS_WIN) + Handle rootWindow = d()->m_rootWindow; +#elif defined(TWPP_DETAIL_OS_MAC) || defined(TWPP_DETAIL_OS_LINUX) + Handle rootWindow; +#else +# error "close manager for your platform here" +#endif + + auto rc = dsm(nullptr, DataGroup::Control, Dat::Parent, Msg::CloseDsm, rootWindow); + if (success(rc)){ + d()->m_state = DsmState::Loaded; + } + + return rc; + } + + /// Creates a valid closed source. + /// Whether the source may be opened depends whether + /// a source with the supplied product name and manufacturer exists. + /// \throw std::bad_alloc + Source createSource(const Str32& productName, const Str32& manufacturer){ + assert(isValid()); + + return Source(d(), Identity(Version(), DataGroup::Control, manufacturer, Str32(), productName)); + } + + /// Creates a valid closed default source. + /// It is almost certain the source may be opened. + /// \throw std::bad_alloc + ReturnCode defaultSource(Source& out){ + Identity id; + auto rc = dsm(nullptr, DataGroup::Control, Dat::Identity, Msg::GetDefault, id); + if (success(rc)){ + out = Source(d(), id); + } + + return rc; + } + + /// Sets default source. + ReturnCode setDefaultSource(Source& in) noexcept{ + return dsm(nullptr, DataGroup::Control, Dat::Identity, Msg::Set, in.d()->m_srcId); + } + + /// Lists all available sources. + /// \tparam Container Container type, usually std::vector. + /// \param out The container to be filled with sources. + /// \return {RC::Success if one source, RC::EndOfList if more sources, RC::Failure if error.} + template + ReturnCode sources(Container& out){ + Identity id; + auto rc = dsm(nullptr, DataGroup::Control, Dat::Identity, Msg::GetFirst, id); + if (success(rc)){ + do { + out.push_back(Source(d(), id)); + + rc = dsm(nullptr, DataGroup::Control, Dat::Identity, Msg::GetNext, id); + } while(success(rc)); + } + + return rc; + } + + /// Shows a source-selection dialog. + /// Available only on Windows and MacOS. + ReturnCode showSourceDialog(Source& out){ + Identity id; + ReturnCode rc = dsm(nullptr, DataGroup::Control, Dat::Identity, Msg::UserSelect, id); + if (success(rc)){ + out = Source(d(), id); + } + + return rc; + } + + /// Obtains the last manager status. + ReturnCode status(Status& status) noexcept{ + return dsm(nullptr, DataGroup::Control, Dat::Status, Msg::Get, status); + } + + /// The current manager TWAIN state. + DsmState state() const noexcept{ + assert(isValid()); + + return d()->m_state; + } + + /// Application identity the manager was/will be open with. + const Identity& identity() const noexcept{ + assert(isValid()); + + return d()->m_appId; + } + + /// Whether this object is a valid manager. + /// Valid manager object is created using constructor with at least one parameter. + /// Using constructor without any parameters results in invalid manager. + bool isValid() const noexcept{ + return static_cast(m_data); + } + + operator bool() noexcept{ + return isValid(); + } + +private: + void closeRootWindow() noexcept{ +#if defined(TWPP_DETAIL_OS_WIN) + if (d()->m_rootWindow && d()->m_ownRootWindow){ + DestroyWindow(static_cast(d()->m_rootWindow.raw())); + d()->m_ownRootWindow = Handle(); + } +#elif !defined(TWPP_DETAIL_OS_MAC) && !defined(TWPP_DETAIL_OS_LINUX) +# error "closeRootWindow for your platform here" +#endif + } + + Detail::ManagerData* d() noexcept{ + return m_data.get(); + } + + const Detail::ManagerData* d() const noexcept{ + return m_data.get(); + } + + template + ReturnCode dsm(Identity* dest, DataGroup dg, Dat dat, Msg msg, T& data){ + return dsmPtr(dest, dg, dat, msg, &data); + } + + ReturnCode dsmPtr(Identity* dest, DataGroup dg, Dat dat, Msg msg, void* data){ + assert(isValid()); + + return d()->m_entry(&d()->m_appId, dest, dg, dat, msg, data); + } + + std::unique_ptr m_data; + +}; + +} + +#endif // TWPP_DETAIL_FILE_APPLICATION_HPP + diff --git a/huagaotwain/twain/twpp/audio.hpp b/huagaotwain/twain/twpp/audio.hpp new file mode 100644 index 0000000..6aa8491 --- /dev/null +++ b/huagaotwain/twain/twpp/audio.hpp @@ -0,0 +1,119 @@ +/* + +The MIT License (MIT) + +Copyright (c) 2015 Martin Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef TWPP_DETAIL_FILE_AUDIO_HPP +#define TWPP_DETAIL_FILE_AUDIO_HPP + +#include "../twpp.hpp" + +namespace Twpp { + +TWPP_DETAIL_PACK_BEGIN +/// Information about current audio transfer. +/// ArgType::AudioInfo +class AudioInfo { + +public: + /// Creates empty audio info. + constexpr AudioInfo() noexcept : + m_name(), m_reserved(){} + + /// Creates audio info with set name of audio data. + explicit constexpr AudioInfo(const Str255& name, UInt32 reserved = 0) noexcept : + m_name(name), m_reserved(reserved){} + + /// Name of audio data. + constexpr const Str255& name() const noexcept{ + return m_name; + } + + /// Name of audio data. + Str255& name() noexcept{ + return m_name; + } + + constexpr UInt32 reserved() const noexcept{ + return m_reserved; + } + + void setReserved(UInt32 reserved) noexcept{ + m_reserved = reserved; + } + +private: + Str255 m_name; + UInt32 m_reserved; + +}; + +/// Owner of audio transfer handle. +class AudioNativeXfer { + +public: + template + using Data = Detail::Lock::type>; + + template + using ConstData = Detail::Lock::type>; + + + /// Creates an empty handle owner. + AudioNativeXfer() noexcept : + m_handle(){} + + /// Creates a memory area of desired size for audio native transfer. + /// \throw std::bad_alloc + explicit AudioNativeXfer(UInt32 size) : + m_handle(Detail::alloc(size)){} + + /// Audio data. + template + Data data() noexcept{ + return m_handle.lock::type>(); + } + + /// Audio data. + template + ConstData data() const noexcept{ + return m_handle.lock::type>(); + } + + /// Releases the owned handle. + /// The user becomes responsible for freeing the handle. + Handle release() noexcept{ + return m_handle.release(); + } + +private: + Detail::UniqueHandle m_handle; + +}; +TWPP_DETAIL_PACK_END + +} + +#endif // TWPP_DETAIL_FILE_AUDIO_HPP + diff --git a/huagaotwain/twain/twpp/capability.hpp b/huagaotwain/twain/twpp/capability.hpp new file mode 100644 index 0000000..06a4b33 --- /dev/null +++ b/huagaotwain/twain/twpp/capability.hpp @@ -0,0 +1,2297 @@ +/* + +The MIT License (MIT) + +Copyright (c) 2015 Martin Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef TWPP_DETAIL_FILE_CAPABILITY_HPP +#define TWPP_DETAIL_FILE_CAPABILITY_HPP + +#include "../twpp.hpp" + +namespace Twpp { + +namespace Detail { + +/// Mapping of capability type to type identifier and data type. +template struct Cap {}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef Alarm DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Int32; typedef Int32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Str128; typedef Str128 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Bool; typedef Bool DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Int32; typedef Int32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Bool; typedef Bool DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Bool; typedef Bool DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef XferMech DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Int32; typedef Int32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Int16; typedef Int16 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Bool; typedef Bool DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef PixelType DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Bool; typedef Bool DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef CameraSide DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Str255; typedef Str255 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef ClearBuffers DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Bool; typedef Bool DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Bool; typedef Bool DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Str255; typedef Str255 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef DeviceEvent::Type DataType;}; // Capability->UInt16, DeviceEvent->UInt32 +template<> struct Cap {static constexpr const Type twty = Type::Bool; typedef Bool DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Str32; typedef Str32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef DoubleFeedDetection DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Fix32; typedef Fix32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef DoubleFeedResponse DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef DoubleFeedSensitivity DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef Duplex DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Bool; typedef Bool DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Bool; typedef Bool DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef CapType DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef FeederAlignment DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Bool; typedef Bool DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Bool; typedef Bool DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef FeederOrder DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef FeederPocket DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Bool; typedef Bool DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Bool; typedef Bool DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Bool; typedef Bool DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Int32; typedef DiscardBlankPages DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Bool; typedef Bool DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Bool; typedef Bool DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef PixelType DataType;}; // only BW/Gray +template<> struct Cap {static constexpr const Type twty = Type::Bool; typedef Bool DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Bool; typedef Bool DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Bool; typedef Bool DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Bool; typedef Bool DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef AutoSize DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Bool; typedef Bool DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef SearchMode DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef BarCodeType DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef UInt16 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef BitDepthReduction DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef BitOrder DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef BitOrder DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Fix32; typedef Fix32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef UInt16 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Bool; typedef Bool DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef Compression DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Fix32; typedef Fix32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt8; typedef UInt8 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Fix32; typedef Fix32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Bool; typedef Bool DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef FeederType DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef FilmType DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef Filter DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Bool; typedef Bool DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef Flash DataType;}; // Capability->UInt16, DeviceEvent->UInt32 +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef FlipRotation DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Frame; typedef Frame DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Fix32; typedef Fix32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Str32; typedef Str32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Fix32; typedef Fix32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef IccProfile DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef ImageFileFormat DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef ImageFilter DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef ImageMerge DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Fix32; typedef Fix32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef PixelType DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef JpegQuality DataType;}; // JpegQuality or 0-100 +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef JpegSubSampling DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Bool; typedef Bool DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef LightPath DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef LightSource DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef UInt16 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Fix32; typedef Fix32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Fix32; typedef Fix32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef Mirror DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Bool; typedef Bool DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef IndicatorsMode DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef NoiseFilter DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef Orientation DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef OverScan DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Bool; typedef Bool DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef SearchMode DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef PatchCode DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Fix32; typedef Fix32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Fix32; typedef Fix32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef PixelFlavor DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef PixelFlavor DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef PixelType DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef ColorFormat DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Fix32; typedef Fix32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Fix32; typedef Fix32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef BarCodeType DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef Twpp::InfoId DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef PatchCode DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef PaperSize DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Fix32; typedef Fix32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Bool; typedef Bool DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef UInt16 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Bool; typedef Bool DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef Unit DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef XferMech DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Fix32; typedef Fix32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Fix32; typedef Fix32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Fix32; typedef Fix32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Fix32; typedef Fix32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Fix32; typedef Fix32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Fix32; typedef Fix32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Int16; typedef Int16 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef JobControl DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef Language DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Bool; typedef Bool DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Bool; typedef Bool DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef PaperHandling DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Int32; typedef Int32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef PowerSupply DataType;}; // Capability->UInt16, DeviceEvent->Int32 +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef Printer DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Bool; typedef Bool DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef FontStyle DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Str32; typedef Str32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef IndexTrigger DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef PrinterMode DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Str255; typedef Str255 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Str255; typedef Str255 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Str255; typedef Str255 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Fix32; typedef Fix32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Bool; typedef Bool DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Bool; typedef Bool DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef Segmented DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Str255; typedef Str255 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef CapType DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef CapType DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Bool; typedef Bool DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Int32; typedef Int32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Int32; typedef Int32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Str32; typedef Str32 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Bool; typedef Bool DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::Int16; typedef Int16 DataType;}; + +TWPP_DETAIL_PACK_BEGIN +// certain apps assume that size of OneValue item is always at least 4 bytes +// add padding that extends the sign of signed integers +// and pads with zeroes for unsigned integers +// all other cases use their data types directly +template // false, any +struct OneValueProxy { + OneValueProxy& operator=(const DataType& value) noexcept{ + m_data = value; + return *this; + } + + operator const DataType&() const noexcept{ + return m_data; + } + + operator DataType&() noexcept{ + return m_data; + } + + DataType m_data; +}; + +template +struct OneValueProxy { + OneValueProxy& operator=(DataType value) noexcept{ + m_signed = static_cast(value); + return *this; + } + + operator DataType() const noexcept{ + return m_data; + } + + operator DataType&() noexcept{ + return m_data; + } + + union { + DataType m_data; + Int32 m_signed; + }; +}; + +template +struct OneValueProxy { + OneValueProxy& operator=(DataType value) noexcept{ + m_unsigned = static_cast(value); + return *this; + } + + operator DataType() const noexcept{ + return m_data; + } + + operator DataType&() noexcept{ + return m_data; + } + + union { + DataType m_data; + UInt32 m_unsigned; + }; +}; + +template +struct OneValueData { + Type m_itemType; + OneValueProxy::value> m_item; +}; + +template +struct ArrayData { + Type m_itemType; + UInt32 m_numItems; + DataType m_items[1]; +}; + +template +struct EnumerationData { + Type m_itemType; + UInt32 m_numItems; + UInt32 m_currIndex; + UInt32 m_defIndex; + DataType m_items[1]; +}; + +// Range items are always 4 bytes large, +// add padding for smaller data types +template +struct RangeProxy { + typedef typename std::conditional< + std::is_signed::value, Int32, UInt32 + >::type InnerType; + + RangeProxy& operator=(DataType value) noexcept{ + m_data = value; + return *this; + } + + operator DataType() const noexcept{ + return static_cast(m_data); + } + + operator DataType&() noexcept{ + return *alias_cast(&m_data); + } + + InnerType m_data; +}; + +template<> +struct RangeProxy { + RangeProxy& operator=(Fix32 value) noexcept{ + m_data = value; + return *this; + } + + operator Fix32() const noexcept{ + return m_data; + } + + operator Fix32&() noexcept{ + return m_data; + } + + Fix32 m_data; +}; + +template +struct RangeData { + Type m_itemType; + RangeProxy m_minValue; + RangeProxy m_maxValue; + RangeProxy m_stepSize; + RangeProxy m_defValue; + RangeProxy m_currValue; +}; +TWPP_DETAIL_PACK_END + + +template +struct IsNumeric { + static constexpr bool value = std::is_integral::value || std::is_same::value; +}; + +} + +class Capability; + +/// Capability container holding a single value. +/// \tparam twty ID of the internal data type. +/// \tparam DataType Exported data type. +template::Type> +class OneValue { + + friend class Capability; + +public: + static constexpr const ConType contype = ConType::OneValue; + typedef DataType* iterator; + typedef const DataType* const_iterator; + + /// Creates an invalid container. + constexpr OneValue() noexcept{} + + /// ID of the internal data type. + Type type() const noexcept{ + return m_data->m_itemType; + } + + /// The contained value. + DataType& item() noexcept{ + return m_data->m_item; + } + + /// The contained value. + const DataType& item() const noexcept{ + return m_data->m_item; + } + + /// Sets the contained value. + void setItem(const DataType& item) noexcept{ + m_data->m_item = item; + } + + operator bool() const noexcept{ + return m_data; + } + + + iterator begin() noexcept{ + return &m_data->m_item; + } + + const_iterator begin() const noexcept{ + return cbegin(); + } + + const_iterator cbegin() const noexcept{ + return &m_data->m_item; + } + + iterator end() noexcept{ + return &m_data->m_item + 1; + } + + const_iterator end() const noexcept{ + return cend(); + } + + const_iterator cend() const noexcept{ + return &m_data->m_item + 1; + } + +private: + OneValue(Handle h) : m_data(h){} + + Detail::Lock > m_data; + +}; + +// disable OneValue for incompatible types +template +class OneValue; +template +class OneValue; + + +/// Capability container holding an array of values. +/// \tparam twty ID of the internal data type. +/// \tparam DataType Exported data type. +template::Type> +class Array { + + friend class Capability; + +public: + static constexpr const ConType contype = ConType::Array; + typedef DataType* iterator; + typedef const DataType* const_iterator; + + /// Creates an invalid container. + constexpr Array() noexcept{} + + /// ID of the internal data type. + Type type() const noexcept{ + return m_data->m_itemType; + } + + /// Number of items in the array. + UInt32 size() const noexcept{ + return m_data->m_numItems; + } + + /// Access contained value in array. + DataType& at(std::size_t i) noexcept{ + return m_data->m_items[i]; + } + + /// Access contained value in array. + const DataType& at(std::size_t i) const noexcept{ + return m_data->m_items[i]; + } + + /// Sets value in array. + void set(std::size_t i, const DataType& val) noexcept{ + at(i) = val; + } + + + DataType& operator[](std::size_t i) noexcept{ + return at(i); + } + + const DataType& operator[](std::size_t i) const noexcept{ + return at(i); + } + + operator bool() const noexcept{ + return m_data; + } + + + iterator begin() noexcept{ + return m_data->m_items; + } + + const_iterator begin() const noexcept{ + return cbegin(); + } + + const_iterator cbegin() const noexcept{ + return m_data->m_items; + } + + iterator end() noexcept{ + return m_data->m_items + m_data->m_numItems; + } + + const_iterator end() const noexcept{ + return cend(); + } + + const_iterator cend() const noexcept{ + return m_data->m_items + m_data->m_numItems; + } + +private: + Array(Handle h) : m_data(h){} + + Detail::Lock > m_data; + +}; + +// disable Array for incompatible types +template +class Array; +template +class Array; + + +/// Capability container holding an array of values, +/// and default and current indexes. +/// \tparam twty ID of the internal data type. +/// \tparam DataType Exported data type. +template::Type> +class Enumeration { + + friend class Capability; + +public: + static constexpr const ConType contype = ConType::Enumeration; + typedef DataType* iterator; + typedef const DataType* const_iterator; + + /// Creates an invalid container. + constexpr Enumeration() noexcept{} + + /// ID of the internal data type. + Type type() const noexcept{ + return m_data->m_itemType; + } + + /// Number of items in the array. + UInt32 size() const noexcept{ + return m_data->m_numItems; + } + + + /// Index of the currently selected item. + UInt32 currentIndex() const noexcept{ + return m_data->m_currIndex; + } + + /// Sets index of the currently selected item. + void setCurrentIndex(UInt32 index) noexcept{ + m_data->m_currIndex = index; + } + + /// Item at the current index. + DataType& currentItem() noexcept{ + return at(m_data->m_currIndex); + } + + /// Item at the current index. + const DataType& currentItem() const noexcept{ + return at(m_data->m_currIndex); + } + + /// Sets item at the current index. + void setCurrentItem(const DataType& item) noexcept{ + currentItem() = item; + } + + + /// Index of the default item. + UInt32 defaultIndex() const noexcept{ + return m_data->m_defIndex; + } + + /// Sets index of the default item. + void setDefaultIndex(UInt32 index) noexcept{ + m_data->m_defIndex = index; + } + + /// Item at the default index. + DataType& defaultItem() noexcept{ + return at(m_data->m_defIndex); + } + + /// Item at the default index. + const DataType& defaultItem() const noexcept{ + return at(m_data->m_defIndex); + } + + /// Sets item at the default index. + void setDefaultItem(const DataType& item) noexcept{ + defaultItem() = item; + } + + + /// Access contained value in array. + DataType& at(std::size_t i) noexcept{ + return m_data->m_items[i]; + } + + /// Access contained value in array. + const DataType& at(std::size_t i) const noexcept{ + return m_data->m_items[i]; + } + + /// Sets value in array. + void set(std::size_t i, const DataType& val) noexcept{ + at(i) = val; + } + + + DataType& operator[](std::size_t i) noexcept{ + return at(i); + } + + const DataType& operator[](std::size_t i) const noexcept{ + return at(i); + } + + operator bool() const noexcept{ + return m_data; + } + + + iterator begin() noexcept{ + return m_data->m_items; + } + + const_iterator begin() const noexcept{ + return cbegin(); + } + + const_iterator cbegin() const noexcept{ + return m_data->m_items; + } + + iterator end() noexcept{ + return m_data->m_items + m_data->m_numItems; + } + + const_iterator end() const noexcept{ + return cend(); + } + + const_iterator cend() const noexcept{ + return m_data->m_items + m_data->m_numItems; + } + +private: + Enumeration(Handle h) : m_data(h){} + + Detail::Lock > m_data; + +}; + +// disable Enumeration for incompatible types +template +class Enumeration; +template +class Enumeration; + + +/// Capability container holding a range of numeric values, +/// and default and current values. +/// \tparam twty ID of the internal data type. +/// \tparam DataType Exported data type. +template::Type> +class Range { + + friend class Capability; + static_assert(Detail::IsNumeric::value, "not a numeric type"); + +private: + static constexpr const ConType contype = ConType::Range; + template + class IteratorImpl { + + friend class Range; + + public: + constexpr IteratorImpl() noexcept : + m_curr(), m_parent(nullptr){} + + IterDataType operator*() const noexcept{ + return m_curr; + } + + IteratorImpl& operator++() noexcept{ // prefix + m_curr += step(); + checkValue(); + return *this; + } + + IteratorImpl operator++(int) noexcept{ // postfix + IteratorImpl ret(*this); + m_curr += step(); + checkValue(); + return ret; + } + + IteratorImpl& operator--() noexcept{ // prefix + m_curr -= step(); + return *this; + } + + IteratorImpl operator--(int) noexcept{ // postfix + IteratorImpl ret(*this); + m_curr -= step(); + return ret; + } + + bool operator==(const IteratorImpl& o) const noexcept{ + return m_curr == o.m_curr && + (m_parent == o.m_parent || + (m_parent && o.m_parent && step() == o.step()) + ); + } + + bool operator!=(const IteratorImpl& o) const noexcept{ + return (*this == o); + } + + private: + IterDataType step() const noexcept{ + return m_parent->stepSize(); + } + + IterDataType max() const noexcept{ + return m_parent->maxValue(); + } + + void checkValue() noexcept{ + // avoid infinite loops in case no such N exists: `min + N * step == max` + if (m_curr > max()){ + m_curr = max() + step(); + } + } + + IteratorImpl(IterDataType curr, const Range& parent) noexcept : + m_curr(curr), m_parent(&parent){} + + IterDataType m_curr; + const Range* m_parent; + + }; + +public: + typedef IteratorImpl const_iterator; + + /// Creates an invalid container. + constexpr Range() noexcept{} + + /// ID of the internal data type. + Type type() const noexcept{ + return m_data->m_itemType; + } + + /// Minimal value in the range. + DataType minValue() const noexcept{ + return m_data->m_minValue; + } + + /// Sets minimal value in the range. + void setMinValue(DataType val) noexcept{ + m_data->m_minValue = val; + } + + /// Maximal value in the range. + DataType maxValue() const noexcept{ + return m_data->m_maxValue; + } + + /// Sets maximal value in the range. + void setMaxValue(DataType val) noexcept{ + m_data->m_maxValue = val; + } + + /// Size of a single step. + DataType stepSize() const noexcept{ + return m_data->m_stepSize; + } + + ///Sets size of a single step. + void setStepSize(DataType val) noexcept{ + m_data->m_stepSize = val; + } + + /// Default value in the range. + DataType defaultValue() const noexcept{ + return m_data->m_defValue; + } + + /// Sets default value in the range. + void setDefaultValue(DataType val) noexcept{ + m_data->m_defValue = val; + } + + /// Current value in the range. + DataType currentValue() const noexcept{ + return m_data->m_currValue; + } + + /// Sets current value in the range. + void setCurrentValue(DataType val) noexcept{ + m_data->m_currValue = val; + } + + operator bool() const noexcept{ + return m_data; + } + + const_iterator begin() const noexcept{ + return cbegin(); + } + + const_iterator cbegin() const noexcept{ + return const_iterator(m_data->m_minValue, *this); + } + + const_iterator end() const noexcept{ + return cend(); + } + + const_iterator cend() const noexcept{ + auto step = m_data->m_stepSize; + if (step != DataType()){ + return const_iterator(m_data->m_maxValue + step, *this); + } else { + return cbegin(); // no items with step equal to zero + } + } + +private: + Range(Handle h) : m_data(h){} + + Detail::Lock > m_data; + +}; + +// disable Range for incompatible types +// (non-numeric types) +template +class Range; +template +class Range; +template +class Range; +template +class Range; +template +class Range; +template +class Range; +template +class Range; +template +class Range; + + +namespace Detail { + +template +class CapDataImpl; + +template +class CapData; + +/// Capability iterator. +/// The default implementation is designed for non-numeric values. +/// Meaning it can't handle ranges. +template // false +class CapIterator { + + friend class Capability; + + template + friend class CapDataImpl; + +public: + constexpr CapIterator() noexcept : + m_ptr(nullptr){} + + DataType& operator*() const noexcept{ + return *m_ptr; + } + + CapIterator& operator++() noexcept{ // prefix + ++m_ptr; + return *this; + } + + CapIterator operator++(int) noexcept{ // postfix + CapIterator ret(*this); + ++m_ptr; + return ret; + } + + CapIterator& operator--() noexcept{ // prefix + --m_ptr; + return *this; + } + + CapIterator operator--(int) noexcept{ // postfix + CapIterator ret(*this); + --m_ptr; + return ret; + } + + bool operator==(const CapIterator& o) const noexcept{ + return m_ptr == o.m_ptr; + } + + bool operator!=(const CapIterator& o) const noexcept{ + return !(*this == o); + } + +private: + constexpr CapIterator(DataType* ptr) noexcept : + m_ptr(ptr){} + + DataType* m_ptr; + +}; + +/// Capability iterator. +/// This specialization can handles numeric values only. +/// Ranges included. +template +class CapIterator { + + friend class Capability; + + template + friend class CapDataImpl; + +public: + typedef typename std::remove_const::type ReturnType; + + constexpr CapIterator() noexcept : + m_ptr(nullptr), m_isPtr(true){} + + ReturnType operator*() const noexcept{ + if (m_isPtr){ + return *m_ptr; + } else { + return *m_rng; + } + } + + CapIterator& operator++() noexcept{ // prefix + if (m_isPtr){ + ++m_ptr; + } else { + ++m_rng; + } + + return *this; + } + + CapIterator operator++(int) noexcept{ // postfix + CapIterator ret(*this); + if (m_isPtr){ + ++m_ptr; + } else { + ++m_rng; + } + + return ret; + } + + CapIterator& operator--() noexcept{ // prefix + if (m_isPtr){ + --m_ptr; + } else { + --m_rng; + } + + return *this; + } + + CapIterator operator--(int) noexcept{ // postfix + CapIterator ret(*this); + if (m_isPtr){ + --m_ptr; + } else { + --m_rng; + } + + return ret; + } + + bool operator==(const CapIterator& o) const noexcept{ + if (m_isPtr != o.m_isPtr){ + return false; + } + + return m_isPtr ? m_ptr == o.m_ptr : m_rng == o.m_rng; + } + + bool operator!=(const CapIterator& o) const noexcept{ + return !(*this == o); + } + +private: + constexpr CapIterator(DataType* ptr) noexcept : + m_ptr(ptr), m_isPtr(true){} + + constexpr CapIterator(typename Range::const_iterator rng) noexcept : + m_rng(rng), m_isPtr(false){} + + union { + DataType* m_ptr; + typename Range::const_iterator m_rng; + }; + bool m_isPtr; + +}; + +/// Capability iterator lock implementation. +/// The default implementation is designed for non-numeric values. +/// Meaning it can't handle ranges. +template::Type> // numeric=false +class CapDataImpl { + + friend class Capability; + + template + friend class CapData; + +public: + typedef CapIterator const_iterator; + + /// Creates an invalid container. + constexpr CapDataImpl() noexcept : + m_data(){ + + static_assert(type != Type::DontCare, "type may not be DontCare"); + static_assert(sizeof(typename Detail::Twty::Type) == sizeof(DataType), "type sizes dont match"); + } + + const_iterator begin() const noexcept{ + return cbegin(); + } + + const_iterator cbegin() const noexcept{ + return const_iterator(reinterpret_cast(m_data.data() + offset())); + } + + const_iterator end() const noexcept{ + return cend(); + } + + const_iterator cend() const noexcept{ + return const_iterator(reinterpret_cast(m_data.data() + offset()) + size()); + } + + UInt32 size() const noexcept{ + switch (m_conType){ + case ConType::Array: + case ConType::Enumeration: + return reinterpret_cast*>(m_data.data())->m_numItems; + case ConType::OneValue: + return 1; + case ConType::Range: + default: + return 0; // should not happen + } + } + +private: + CapDataImpl(const Capability& cap); + + UInt32 offset() const noexcept{ + switch (m_conType){ + case ConType::Array: + return sizeof(Type) + sizeof(UInt32); + case ConType::Enumeration: + return sizeof(Type) + 3 * sizeof(UInt32); + case ConType::OneValue: + return sizeof(Type); + case ConType::Range: + default: + return 0; // should not happen + } + } + + ConType m_conType; + Detail::Lock m_data; // actual type resolved at runtime + +}; + +/// Capability iterator lock implementation. +/// This specialization can handles numeric values only. +/// Ranges included. +template +class CapDataImpl { + + friend class Capability; + + template + friend class CapData; + +public: + typedef CapIterator const_iterator; + + /// Creates an invalid container. + constexpr CapDataImpl() noexcept : + m_data(){ + + static_assert(type != Type::DontCare, "type may not be DontCare"); + static_assert(sizeof(typename Detail::Twty::Type) == sizeof(DataType), "type sizes dont match"); + } + + const_iterator begin() const noexcept{ + return cbegin(); + } + + const_iterator cbegin() const noexcept{ + if (m_conType != ConType::Range){ + return const_iterator(reinterpret_cast(m_data.data() + offset())); + } else { + const auto& rng = *Detail::alias_cast*>(&m_data); + return const_iterator(rng.cbegin()); + } + } + + const_iterator end() const noexcept{ + return cend(); + } + + const_iterator cend() const noexcept{ + if (m_conType != ConType::Range){ + return const_iterator(reinterpret_cast(m_data.data() + offset()) + size()); + } else { + const auto& rng = *Detail::alias_cast*>(&m_data); + return const_iterator(rng.cend()); + } + } + + UInt32 size() const noexcept{ + switch (m_conType){ + case ConType::Array: + case ConType::Enumeration: + return reinterpret_cast*>(m_data.data())->m_numItems; + case ConType::OneValue: + return 1; + case ConType::Range: { + auto& rng = *reinterpret_cast*>(m_data.data()); + if (rng.m_stepSize != DataType()){ + return static_cast((Detail::abs(rng.m_maxValue - rng.m_minValue) / rng.m_stepSize).toFloat()) + 1; + } else { + return 0; + } + } + default: + return 0; // should not happen + } + } + +private: + CapDataImpl(const Capability& cap); + + UInt32 offset() const noexcept{ + switch (m_conType){ + case ConType::Array: + return sizeof(Type) + sizeof(UInt32); + case ConType::Enumeration: + return sizeof(Type) + 3 * sizeof(UInt32); + case ConType::OneValue: + return sizeof(Type); + case ConType::Range: + default: + return 0; // should not happen + } + } + + ConType m_conType; + Detail::Lock m_data; // actual type resolved at runtime + +}; + +/// Capability iterator lock. +template +class CapData : public CapDataImpl::value, DataType> { + + typedef CapDataImpl::value, DataType> Base; + +public: + constexpr CapData() noexcept{} + + CapData(const Capability& cap) : + Base(cap){} + +}; + + +/// Capability current item implementation. +/// The default implementation is designed for non-numeric values. +/// Meaning it can't handle ranges. +template // false +struct CurrentItemImpl { + static DataType item(Capability& cap); +}; + +/// Capability current item implementation. +/// This specialization can handles numeric values only. +/// Ranges included. +template +struct CurrentItemImpl { + static DataType item(Capability& cap); +}; + +/// Capability current item. +template +struct CurrentItem : CurrentItemImpl::value> { + +}; + +} + +/// Base capability exception. +class CapabilityException : public Exception { + +public: + virtual const char* what() const noexcept override{ + return "Capability handling error."; + } + +}; + +/// Invalid or unsupported container capability exception. +class ContainerException : public CapabilityException { + +public: + virtual const char* what() const noexcept override{ + return "Unexpected container."; + } + +}; + +/// Invalid, unsupported or mismatched item type identifier capability exception. +class ItemTypeException : public CapabilityException { + +public: + virtual const char* what() const noexcept override{ + return "Invalid item type."; + } + +}; + +/// No data capability exception. +/// Capability does not contain any data (container). +class DataException : public CapabilityException { + +public: + virtual const char* what() const noexcept override{ + return "No data."; + } + +}; + +TWPP_DETAIL_PACK_BEGIN +/// TWAIN capability. +/// Any access to containers must be finished before destroying +/// the according capability instance. +class Capability { + + template + friend class Detail::CapDataImpl; + +public: + /// Creates capability holding OneValue container. + /// \tparam type ID of the internal data type. + /// \tparam DataType Exported data type. + /// \param cap Capability type. + /// \param value Initial value. + /// \throw std::bad_alloc + template + static Capability createOneValue(CapType cap, const DataType& value = DataType()){ + Capability ret(cap, ConType::OneValue, type, sizeof(Detail::OneValueData)); + auto ov = ret.oneValue(); + ov.setItem(value); + return std::move(ret); + } + + /// Creates capability holding OneValue container. + /// \tparam type ID of the internal data type. + /// \param cap Capability type. + /// \param value Initial value. + /// \throw std::bad_alloc + template + static Capability createOneValue(CapType cap, const typename Detail::Twty::Type& value = typename Detail::Twty::Type()){ + return createOneValue::Type>(cap, value); + } + + /// Creates capability holding OneValue container. + /// \tparam T Data type. + /// \param cap Capability type. + /// \param value Initial value. + /// \throw std::bad_alloc + template + static Capability createOneValue(CapType cap, const T& value = T()){ + return createOneValue::twty, T>(cap, value); + } + + /// Creates capability holding OneValue container. + /// \tparam cap Capability type. Data types are set accordingly. + /// \param value Initial value. + /// \throw std::bad_alloc + template + static Capability createOneValue(const typename Detail::Cap::DataType& value = typename Detail::Cap::DataType()){ + return createOneValue::twty, typename Detail::Cap::DataType>(cap, value); + } + + + /// Creates capability holding Array container. + /// \tparam type ID of the internal data type. + /// \tparam DataType Exported data type. + /// \param cap Capability type. + /// \param size Number of elements in the array. + /// \throw std::bad_alloc + template + static Capability createArray(CapType cap, UInt32 size){ + Capability ret(cap, ConType::Array, type, sizeof(Detail::ArrayData) - sizeof(DataType) + size * sizeof(DataType)); + auto arr = ret.array(); + arr.m_data->m_numItems = size; + return std::move(ret); + } + + /// Creates capability holding Array container. + /// \tparam type ID of the internal data type. + /// \param cap Capability type. + /// \param size Number of elements in the array. + /// \throw std::bad_alloc + template + static Capability createArray(CapType cap, UInt32 size){ + return createArray::Type>(cap, size); + } + + /// Creates capability holding Array container. + /// \tparam type ID of the internal data type. + /// \tparam DataType Exported data type. + /// \param cap Capability type. + /// \param values Initial values in the array. + /// \throw std::bad_alloc + template + static Capability createArray(CapType cap, std::initializer_list values){ + Capability ret = createArray(cap, static_cast(values.size())); + auto arr = ret.array(); + + UInt32 i = 0; + for (const auto& val : values){ + arr[i] = val; + i++; + } + + return std::move(ret); + } + + /// Creates capability holding Array container. + /// \tparam type ID of the internal data type. + /// \param cap Capability type. + /// \param values Initial values in the array. + /// \throw std::bad_alloc + template + static Capability createArray(CapType cap, std::initializer_list::Type> values){ + return createArray::Type>(cap, values); + } + + /// Creates capability holding Array container. + /// \tparam T Data type. + /// \param cap Capability type. + /// \param size Number of elements in the array. + /// \throw std::bad_alloc + template + static Capability createArray(CapType cap, UInt32 size){ + return createArray::twty, T>(cap, size); + } + + /// Creates capability holding Array container. + /// \tparam T Data type. + /// \param cap Capability type. + /// \param values Initial values in the array. + /// \throw std::bad_alloc + template + static Capability createArray(CapType cap, std::initializer_list values){ + return createArray::twty, T>(cap, values); + } + + /// Creates capability holding Array container. + /// \tparam cap Capability type. Data types are set accordingly. + /// \param size Number of elements in the array. + /// \throw std::bad_alloc + template + static Capability createArray(UInt32 size){ + return createArray::twty, typename Detail::Cap::DataType>(cap, size); + } + + /// Creates capability holding Array container. + /// \tparam cap Capability type. Data types are set accordingly. + /// \param values Initial values in the array. + /// \throw std::bad_alloc + template + static Capability createArray(std::initializer_list::DataType> values){ + return createArray::twty, typename Detail::Cap::DataType>(cap, values); + } + + + /// Creates capability holding Enumeration container. + /// \tparam type ID of the internal data type. + /// \tparam DataType Exported data type. + /// \param cap Capability type. + /// \param size Number of elements in the array. + /// \param currIndex Index of the currently selected item. + /// \param defIndex Index of the default item. + /// \throw std::bad_alloc + template + static Capability createEnumeration(CapType cap, UInt32 size, UInt32 currIndex = 0, UInt32 defIndex = 0){ + Capability ret(cap, ConType::Enumeration, type, sizeof(Detail::EnumerationData) - sizeof(DataType) + size * sizeof(DataType)); + auto enm = ret.enumeration(); + enm.m_data->m_numItems = size; + enm.m_data->m_currIndex = currIndex; + enm.m_data->m_defIndex = defIndex; + return std::move(ret); + } + + /// Creates capability holding Enumeration container. + /// \tparam type ID of the internal data type. + /// \param cap Capability type. + /// \param size Number of elements in the array. + /// \param currIndex Index of the currently selected item. + /// \param defIndex Index of the default item. + /// \throw std::bad_alloc + template + static Capability createEnumeration(CapType cap, UInt32 size, UInt32 currIndex = 0, UInt32 defIndex = 0){ + return createEnumeration::Type>(cap, size, currIndex, defIndex); + } + + /// Creates capability holding Enumeration container. + /// \tparam type ID of the internal data type. + /// \tparam DataType Exported data type. + /// \param cap Capability type. + /// \param values Initial values in the array. + /// \param currIndex Index of the currently selected item. + /// \param defIndex Index of the default item. + /// \throw std::bad_alloc + template + static Capability createEnumeration(CapType cap, std::initializer_list values, UInt32 currIndex = 0, UInt32 defIndex = 0){ + Capability ret = createEnumeration(cap, static_cast(values.size()), currIndex, defIndex); + auto enm = ret.enumeration(); + + UInt32 i = 0; + for (const auto& val : values){ + enm[i] = val; + i++; + } + + return std::move(ret); + } + + /// Creates capability holding Enumeration container. + /// \tparam type ID of the internal data type. + /// \param cap Capability type. + /// \param values Initial values in the array. + /// \param currIndex Index of the currently selected item. + /// \param defIndex Index of the default item. + /// \throw std::bad_alloc + template + static Capability createEnumeration(CapType cap, std::initializer_list::Type> values, UInt32 currIndex = 0, UInt32 defIndex = 0){ + return createEnumeration::Type>(cap, values, currIndex, defIndex); + } + + /// Creates capability holding Enumeration container. + /// \tparam T Data type. + /// \param cap Capability type. + /// \param size Number of elements in the array. + /// \param currIndex Index of the currently selected item. + /// \param defIndex Index of the default item. + /// \throw std::bad_alloc + template + static Capability createEnumeration(CapType cap, UInt32 size, UInt32 currIndex = 0, UInt32 defIndex = 0){ + return createEnumeration::twty, T>(cap, size, currIndex, defIndex); + } + + /// Creates capability holding Enumeration container. + /// \tparam T Data type. + /// \param cap Capability type. + /// \param values Initial values in the array. + /// \param currIndex Index of the currently selected item. + /// \param defIndex Index of the default item. + /// \throw std::bad_alloc + template + static Capability createEnumeration(CapType cap, std::initializer_list values, UInt32 currIndex = 0, UInt32 defIndex = 0){ + return createEnumeration::twty, T>(cap, values, currIndex, defIndex); + } + + /// Creates capability holding Enumeration container. + /// \tparam cap Capability type. Data types are set accordingly. + /// \param size Number of elements in the array. + /// \param currIndex Index of the currently selected item. + /// \param defIndex Index of the default item. + /// \throw std::bad_alloc + template + static Capability createEnumeration(UInt32 size, UInt32 currIndex = 0, UInt32 defIndex = 0){ + return createEnumeration::twty, typename Detail::Cap::DataType>(cap, size, currIndex, defIndex); + } + + /// Creates capability holding Enumeration container. + /// \tparam cap Capability type. Data types are set accordingly. + /// \param values Initial values in the array. + /// \param currIndex Index of the currently selected item. + /// \param defIndex Index of the default item. + /// \throw std::bad_alloc + template + static Capability createEnumeration(std::initializer_list::DataType> values, UInt32 currIndex = 0, UInt32 defIndex = 0){ + return createEnumeration::twty, typename Detail::Cap::DataType>(cap, values, currIndex, defIndex); + } + + + /// Creates capability holding Range container. + /// \tparam type ID of the internal data type. + /// \tparam DataType Exported data type. + /// \param cap Capability type. + /// \param min Minimal range value. + /// \param max Maximal range value. + /// \param step Size of a single step. + /// \param curr Current value. + /// \param def Default value. + /// \throw std::bad_alloc + template + static Capability createRange(CapType cap, DataType min, DataType max, DataType step, DataType curr, DataType def){ + Capability ret(cap, ConType::Range, type, sizeof(Detail::RangeData)); + auto rng = ret.range(); + rng.setMinValue(min); + rng.setMaxValue(max); + rng.setStepSize(step); + rng.setCurrentValue(curr); + rng.setDefaultValue(def); + return std::move(ret); + } + + /// Creates capability holding Range container. + /// \tparam type ID of the internal data type. + /// \param cap Capability type. + /// \param min Minimal range value. + /// \param max Maximal range value. + /// \param step Size of a single step. + /// \param curr Current value. + /// \param def Default value. + /// \throw std::bad_alloc + template + static Capability createRange( + CapType cap, + typename Detail::Twty::Type min, + typename Detail::Twty::Type max, + typename Detail::Twty::Type step, + typename Detail::Twty::Type curr, + typename Detail::Twty::Type def + ){ + return createRange::Type>(cap, min, max, step, curr, def); + } + + /// Creates capability holding Range container. + /// \tparam T Data type. + /// \param cap Capability type. + /// \param min Minimal range value. + /// \param max Maximal range value. + /// \param step Size of a single step. + /// \param curr Current value. + /// \param def Default value. + /// \throw std::bad_alloc + template + static Capability createRange(CapType cap, T min, T max, T step, T curr, T def){ + return createRange::twty, T>(cap, min, max, step, curr, def); + } + + /// Creates capability holding Range container. + /// \tparam cap Capability type. Data types are set accordingly. + /// \param min Minimal range value. + /// \param max Maximal range value. + /// \param step Size of a single step. + /// \param curr Current value. + /// \param def Default value. + /// \throw std::bad_alloc + template + static Capability createRange( + typename Detail::Cap::DataType min, + typename Detail::Cap::DataType max, + typename Detail::Cap::DataType step, + typename Detail::Cap::DataType curr, + typename Detail::Cap::DataType def + ){ + return createRange::twty, typename Detail::Cap::DataType>( + cap, min, max, step, curr, def); + } + + + /// Creates capability of the supplied type without any data. + /// Useful for retrieving data from data source. + explicit Capability(CapType cap) noexcept : + m_cap(cap), m_conType(ConType::DontCare), m_cont(){} + + Capability(Capability&&) = default; + Capability& operator=(Capability&&) = default; + + /// Capability type. + CapType type() const noexcept{ + return m_cap; + } + + /// Container type. + ConType container() const noexcept{ + return m_conType; + } + + /// Item type. + /// Valid only if the capability contains data. + /// \throw DataException When there is no data. + Type itemType() const{ + if (!m_cont){ + throw DataException(); + } + + return *m_cont.lock().data(); + } + + operator bool() const noexcept{ + return m_cont; + } + + /// Contained OneValue container. + /// \tparam type ID of the internal data type. + /// \tparam DataType Exported data type. + /// \throw DataException When there is no data. + /// \throw ContainerException When container is not OneValue. + /// \throw ItemTypeException When item type does not match. + template + OneValue oneValue(){ + return containerCheck(); + } + + /// Contained OneValue container. + /// \tparam type ID of the internal data type. + /// \throw DataException When there is no data. + /// \throw ContainerException When container is not OneValue. + /// \throw ItemTypeException When item type does not match. + template + OneValue::Type> oneValue(){ + return oneValue::Type>(); + } + + /// Contained OneValue container. + /// \tparam T Data type. + /// \throw DataException When there is no data. + /// \throw ContainerException When container is not OneValue. + /// \throw ItemTypeException When item type does not match. + template + OneValue::twty, T> oneValue(){ + return oneValue::twty, T>(); + } + + /// Contained OneValue container. + /// \tparam cap Capability type. Data types are set accordingly. + /// \throw DataException When there is no data. + /// \throw ContainerException When container is not OneValue. + /// \throw ItemTypeException When item type does not match. + template + OneValue::twty, typename Detail::Cap::DataType> oneValue(){ + return oneValue::twty, typename Detail::Cap::DataType>(); + } + + /// Contained Array container. + /// \tparam type ID of the internal data type. + /// \tparam DataType Exported data type. + /// \throw DataException When there is no data. + /// \throw ContainerException When container is not Array. + /// \throw ItemTypeException When item type does not match. + template + Array array(){ + return containerCheck(); + } + + /// Contained Array container. + /// \tparam type ID of the internal data type. + /// \throw DataException When there is no data. + /// \throw ContainerException When container is not Array. + /// \throw ItemTypeException When item type does not match. + template + Array::Type> array(){ + return array::Type>(); + } + + /// Contained Array container. + /// \tparam T Data type. + /// \throw DataException When there is no data. + /// \throw ContainerException When container is not Array. + /// \throw ItemTypeException When item type does not match. + template + Array::twty, T> array(){ + return array::twty, T>(); + } + + /// Contained Array container. + /// \tparam cap Capability type. Data types are set accordingly. + /// \throw DataException When there is no data. + /// \throw ContainerException When container is not Array. + /// \throw ItemTypeException When item type does not match. + template + Array::twty, typename Detail::Cap::DataType> array(){ + return array::twty, typename Detail::Cap::DataType>(); + } + + /// Contained Enumeration container. + /// \tparam type ID of the internal data type. + /// \tparam DataType Exported data type. + /// \throw DataException When there is no data. + /// \throw ContainerException When container is not Enumeration. + /// \throw ItemTypeException When item type does not match. + template + Enumeration enumeration(){ + return containerCheck(); + } + + /// Contained Enumeration container. + /// \tparam type ID of the internal data type. + /// \throw DataException When there is no data. + /// \throw ContainerException When container is not Enumeration. + /// \throw ItemTypeException When item type does not match. + template + Enumeration::Type> enumeration(){ + return enumeration::Type>(); + } + + /// Contained Enumeration container. + /// \tparam T Data type. + /// \throw DataException When there is no data. + /// \throw ContainerException When container is not Enumeration. + /// \throw ItemTypeException When item type does not match. + template + Enumeration::twty, T> enumeration(){ + return enumeration::twty, T>(); + } + + /// Contained Enumeration container. + /// \tparam cap Capability type. Data types are set accordingly. + /// \throw DataException When there is no data. + /// \throw ContainerException When container is not Enumeration. + /// \throw ItemTypeException When item type does not match. + template + Enumeration::twty, typename Detail::Cap::DataType> enumeration(){ + return enumeration::twty, typename Detail::Cap::DataType>(); + } + + /// Contained Range container. + /// \tparam type ID of the internal data type. + /// \tparam DataType Exported data type. + /// \throw DataException When there is no data. + /// \throw ContainerException When container is not Enumeration. + /// \throw ItemTypeException When item type does not match. + template + Range range(){ + return containerCheck(); + } + + /// Contained Range container. + /// \tparam type ID of the internal data type. + /// \throw DataException When there is no data. + /// \throw ContainerException When container is not Enumeration. + /// \throw ItemTypeException When item type does not match. + template + Range::Type> range(){ + return range::Type>(); + } + + /// Contained Range container. + /// \tparam T Data type. + /// \throw DataException When there is no data. + /// \throw ContainerException When container is not Range. + /// \throw ItemTypeException When item type does not match. + template + Range::twty, T> range(){ + return range::twty, T>(); + } + + /// Contained Range container. + /// \tparam cap Capability type. Data types are set accordingly. + /// \throw DataException When there is no data. + /// \throw ContainerException When container is not Range. + /// \throw ItemTypeException When item type does not match. + template + Range::twty, typename Detail::Cap::DataType> range(){ + return range::twty, typename Detail::Cap::DataType>(); + } + + template + using Data = Detail::CapData; + + /// Returns a data container for iterating over all possible values. + /// Use this only if you don't care about current or default values and container type. + /// \tparam type ID of the internal data type. + /// \tparam DataType Exported data type. + /// \throw DataException When there is no data. + /// \throw ContainerException When container is invalid. + /// \throw ItemTypeException When item type does not match. + template + Data data() const{ + return *this; + } + + /// Returns a data container for iterating over all possible values. + /// Use this only if you don't care about current or default values and container type. + /// \tparam type ID of the internal data type. + /// \throw DataException When there is no data. + /// \throw ContainerException When container is invalid. + /// \throw ItemTypeException When item type does not match. + template + Data::Type> data() const{ + return *this; + } + + /// Returns a data container for iterating over all possible values. + /// Use this only if you don't care about current or default values and container type. + /// \tparam T Data type. + /// \throw DataException When there is no data. + /// \throw ContainerException When container is invalid. + /// \throw ItemTypeException When item type does not match. + template + Data::twty, T> data() const{ + return *this; + } + + /// Returns a data container for iterating over all possible values. + /// Use this only if you don't care about current or default values and container type. + /// \tparam cap Capability type. Data types are set accordingly. + /// \throw DataException When there is no data. + /// \throw ContainerException When container is invalid. + /// \throw ItemTypeException When item type does not match. + template + Data::twty, typename Detail::Cap::DataType> data() const{ + return *this; + } + + + /// Returns a copy of the current item of this capability. + /// Can be used only with Enumeration, OneValue, and Range containers. + /// \tparam type ID of the internal data type. + /// \tparam DataType Exported data type. + /// \throw DataException When there is no data. + /// \throw ContainerException When container is not Enumeration, OneValue, nor Range. + /// \throw ItemTypeException When item type does not match. + template + DataType currentItem(){ + return Detail::CurrentItem::item(*this); + } + + /// Returns a copy of the current item of this capability. + /// Can be used only with Enumeration, OneValue, and Range containers. + /// \tparam type ID of the internal data type. + /// \throw DataException When there is no data. + /// \throw ContainerException When container is not Enumeration, OneValue, nor Range. + /// \throw ItemTypeException When item type does not match. + template + typename Detail::Twty::Type currentItem(){ + return currentItem::Type>(); + } + + /// Returns a copy of the current item of this capability. + /// Can be used only with Enumeration, OneValue, and Range containers. + /// \tparam T Data type. + /// \throw DataException When there is no data. + /// \throw ContainerException When container is not Enumeration, OneValue, nor Range. + /// \throw ItemTypeException When item type does not match. + template + T currentItem(){ + return currentItem::twty, T>(); + } + + /// Returns a copy of the current item of this capability. + /// Can be used only with Enumeration, OneValue, and Range containers. + /// \tparam cap Capability type. Data types are set accordingly. + /// \throw DataException When there is no data. + /// \throw ContainerException When container is not Enumeration, OneValue, nor Range. + /// \throw ItemTypeException When item type does not match. + template + typename Detail::Cap::DataType currentItem(){ + return currentItem::twty, typename Detail::Cap::DataType>(); + } + +private: + /// \throw DataException + /// \throw ContainerException + /// \throw ItemTypeException + Capability(CapType cap, ConType conType, Type twty, UInt32 size) : + m_cap(cap), m_conType(conType), m_cont(Detail::alloc(size)){ + + *m_cont.lock().data() = twty; + } + + template class Container, Type type, typename DataType> + Container containerCheck(){ + static_assert(type != Type::DontCare, "type may not be DontCare"); + static_assert(sizeof(typename Detail::Twty::Type) == sizeof(DataType), "type sizes dont match"); + + if (!m_cont){ + throw DataException(); + } + + if (Container::contype != container()){ + throw ContainerException(); + } + + Container ret(m_cont.get()); + UINT16 r_type = (UINT16)ret.type(); + UINT16 m_type = (UINT16)type; + if (!((((r_type >= 0) || (r_type <= 5)) && ((m_type >= 0) || (m_type <= 5))) || (((r_type >= 9) || (r_type <= 12)) && ((m_type >= 9) || (m_type <= 12))) || (m_type == r_type))) { + //if (type != r_type){ + throw ItemTypeException(); + } + + return std::move(ret); + } + + CapType m_cap; + ConType m_conType; + Detail::UniqueHandle m_cont; + +}; +TWPP_DETAIL_PACK_END + +/// Invalid, unsupported or mismatched item type identifier capability exception. +/// Holds the Capability instance that caused the exception. +class CapItemTypeException : public ItemTypeException { + +public: + CapItemTypeException(Capability cap) noexcept : + m_cap(std::move(cap)){} + + CapItemTypeException(CapItemTypeException&&) = default; + CapItemTypeException& operator=(CapItemTypeException&&) = default; + + CapItemTypeException(const CapItemTypeException&) = delete; + CapItemTypeException& operator=(const CapItemTypeException&) = delete; + + Capability& capability() noexcept{ + return m_cap; + } + + const Capability& capability() const noexcept{ + return m_cap; + } + + virtual const char* what() const noexcept override{ + return "Unexpected item type."; + } + +private: + Capability m_cap; + +}; + +/// Invalid, unexpected, unmatched capability type. +/// Holds the Capability instance that caused the exception. +class CapTypeException : public CapabilityException { + +public: + CapTypeException(Capability cap) noexcept : + m_cap(std::move(cap)){} + + CapTypeException(CapTypeException&&) = default; + CapTypeException& operator=(CapTypeException&&) = default; + + CapTypeException(const CapTypeException&) = delete; + CapTypeException& operator=(const CapTypeException&) = delete; + + Capability& capability() noexcept{ + return m_cap; + } + + const Capability& capability() const noexcept{ + return m_cap; + } + + virtual const char* what() const noexcept override{ + return "Unexpected capability type."; + } + +private: + Capability m_cap; + +}; + +class Source; + +/// Convenience Capability wrapper class. +/// Guaranteed to contain the same capability type and item type +/// throughout the whole lifetime. +template +class Cap { + + friend class Source; + +public: + typedef typename Detail::Cap::DataType DataType; + static constexpr const Type twty = Detail::Cap::twty; + + /// Creates capability holding OneValue container. + /// \param value Initial value. + /// \throw std::bad_alloc + static Cap createOneValue(const DataType& value = DataType()){ + return Cap(Capability::createOneValue(value), 0); + } + + + /// Creates capability holding Array container. + /// \param size Number of elements in the array. + /// \throw std::bad_alloc + static Cap createArray(UInt32 size){ + return Cap(Capability::createArray(size), 0); + } + + /// Creates capability holding Array container. + /// \param values Initial values in the array. + /// \throw std::bad_alloc + static Cap createArray(std::initializer_list values){ + return Cap(Capability::createArray(values), 0); + } + + + /// Creates capability holding Enumeration container. + /// \param size Number of elements in the array. + /// \param currIndex Index of the currently selected item. + /// \param defIndex Index of the default item. + /// \throw std::bad_alloc + static Cap createEnumeration(UInt32 size, UInt32 currIndex = 0, UInt32 defIndex = 0){ + return Cap(Capability::createEnumeration(size, currIndex, defIndex), 0); + } + + /// Creates capability holding Enumeration container. + /// \param values Initial values in the array. + /// \param currIndex Index of the currently selected item. + /// \param defIndex Index of the default item. + /// \throw std::bad_alloc + static Cap createEnumeration(std::initializer_list values, UInt32 currIndex = 0, UInt32 defIndex = 0){ + return Cap(Capability::createEnumeration(values, currIndex, defIndex), 0); + } + + + /// Creates capability holding Range container. + /// \param min Minimal range value. + /// \param max Maximal range value. + /// \param step Size of a single step. + /// \param curr Current value. + /// \param def Default value. + /// \throw std::bad_alloc + static Cap createRange(DataType min, DataType max, DataType step, DataType curr, DataType def){ + return Cap(Capability::createRange(min, max, step, curr, def), 0); + } + + /// Creates capability of the supplied type without any data. + /// Useful for retrieving data from data source. + Cap() noexcept : m_cap(cap){} + + /// Converts Capability to Cap. + /// The capability ownership is taken over. + /// Capability type and item type checkings are performed. In case of exception, + /// the original Capability instance may be retrieved from the exception object. + /// \param capability Capability to be converted to Cap. + /// \throw CapTypeException When input capability type does not match the + /// capability type of this template class. + /// \throw CapItemTypeException When input capability item type does not match + /// the expected item type of the capability. + explicit Cap(Capability capability) : + m_cap(std::move(capability)){ + + checkTypes(); + } + + Cap(Cap&&) = default; + Cap& operator=(Cap&&) = default; + + Cap(const Cap&) = delete; + Cap& operator=(const Cap&) = delete; + + /// Capability type. + CapType type() const noexcept{ + return m_cap.type(); + } + + /// Container type. + ConType container() const noexcept{ + return m_cap.container(); + } + + /// Item type. + /// Valid only if the capability contains data. + /// \throw DataException When there is no data. + Type itemType() const{ + return m_cap.itemType(); + } + + operator bool() const noexcept{ + return m_cap; + } + + /// Contained OneValue container. + /// \throw DataException When there is no data. + /// \throw ContainerException When container is not OneValue. + /// \throw ItemTypeException When item type does not match. + OneValue oneValue(){ + return m_cap.oneValue(); + } + + /// Contained Array container. + /// \throw DataException When there is no data. + /// \throw ContainerException When container is not Array. + /// \throw ItemTypeException When item type does not match. + Array array(){ + return m_cap.array(); + } + + /// Contained Enumeration container. + /// \throw DataException When there is no data. + /// \throw ContainerException When container is not Enumeration. + /// \throw ItemTypeException When item type does not match. + Enumeration enumeration(){ + return m_cap.enumeration(); + } + + /// Contained Range container. + /// \throw DataException When there is no data. + /// \throw ContainerException When container is not Enumeration. + /// \throw ItemTypeException When item type does not match. + Range range(){ + return m_cap.range(); + } + + + typedef Detail::CapData Data; + + /// Returns a data container for iterating over all possible values. + /// Use this only if you don't care about current or default values and container type. + /// \throw DataException When there is no data. + /// \throw ContainerException When container is invalid. + /// \throw ItemTypeException When item type does not match. + Data data() const{ + return m_cap.data(); + } + + + /// Returns a copy of the current item of this capability. + /// Can be used only with Enumeration, OneValue, and Range containers. + /// \throw DataException When there is no data. + /// \throw ContainerException When container is not Enumeration, OneValue, nor Range. + /// \throw ItemTypeException When item type does not match. + DataType currentItem(){ + return m_cap.currentItem(); + } + + /// Moves out the contained Capability instance. + /// This instance becomes empty. + Capability toCapability() noexcept{ + return std::move(m_cap); + } + +private: + Cap(Capability capability, int) noexcept : + m_cap(std::move(capability)){} + + void checkTypes(){ + if (m_cap){ + if (m_cap.type() != cap){ + throw CapTypeException(std::move(m_cap)); + } + + if (m_cap.itemType() != twty){ + throw CapItemTypeException(std::move(m_cap)); + } + } + } + + Capability m_cap; + +}; + + +namespace Detail { + +/// \throw DataException +/// \throw ContainerException +/// \throw ItemTypeException +template // numeric = false +inline CapDataImpl::CapDataImpl(const Capability& cap) : + m_conType(cap.m_conType), m_data(cap.m_cont.get()){ + + static_assert(type != Type::DontCare, "type may not be DontCare"); + static_assert(sizeof(typename Detail::Twty::Type) == sizeof(DataType), "type sizes dont match"); + + if (!cap.m_cont){ + throw DataException(); + } + + switch (m_conType){ + case ConType::Array: + case ConType::Enumeration: + case ConType::OneValue: + break; + case ConType::Range: + default: + throw ContainerException(); + } + + if (type != cap.itemType()){ + throw ItemTypeException(); + } +} + +/// \throw DataException +/// \throw ContainerException +/// \throw ItemTypeException +template +inline CapDataImpl::CapDataImpl(const Capability& cap) : + m_conType(cap.m_conType), m_data(cap.m_cont.get()){ + + static_assert(type != Type::DontCare, "type may not be DontCare"); + static_assert(sizeof(typename Detail::Twty::Type) == sizeof(DataType), "type sizes dont match"); + + if (!cap.m_cont){ + throw DataException(); + } + + switch (m_conType){ + case ConType::Array: + case ConType::Enumeration: + case ConType::OneValue: + case ConType::Range: + break; + default: + throw ContainerException(); + } + + if (type != cap.itemType()){ + throw ItemTypeException(); + } +} + +/// \throw DataException +/// \throw ContainerException +/// \throw ItemTypeException +template // false +DataType CurrentItemImpl::item(Capability& cap){ + switch (cap.container()){ + case ConType::Enumeration: + return cap.enumeration().currentItem(); + + case ConType::OneValue: + return cap.oneValue().item(); + + default: + throw ContainerException(); + } +} + +/// \throw DataException +/// \throw ContainerException +/// \throw ItemTypeException +template +DataType CurrentItemImpl::item(Capability& cap){ + switch (cap.container()){ + case ConType::Enumeration: + return cap.enumeration().currentItem(); + + case ConType::OneValue: + return cap.oneValue().item(); + + case ConType::Range: + return cap.range().currentValue(); + + default: + throw ContainerException(); + } +} + +} + +} + +#endif // TWPP_DETAIL_FILE_CAPABILITY_HPP + diff --git a/huagaotwain/twain/twpp/cie.hpp b/huagaotwain/twain/twpp/cie.hpp new file mode 100644 index 0000000..2a1f641 --- /dev/null +++ b/huagaotwain/twain/twpp/cie.hpp @@ -0,0 +1,269 @@ +/* + +The MIT License (MIT) + +Copyright (c) 2015 Martin Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef TWPP_DETAIL_FILE_CIE_HPP +#define TWPP_DETAIL_FILE_CIE_HPP + +#if 0 +#include "../twpp.hpp" + +namespace Twpp { + +TWPP_DETAIL_PACK_BEGIN +/// Part of CieColor structure. +class CiePoint { + +public: + /// Creates zero-initialized cie point. + constexpr CiePoint() noexcept : + m_x(), m_y(), m_z(){} + + /// Creates cie point with desired values. + constexpr CiePoint(Fix32 x, Fix32 y, Fix32 z) noexcept : + m_x(x), m_y(y), m_z(z){} + + /// X value of CIE space. + constexpr Fix32 x() const noexcept{ + return m_x; + } + + /// Y value of CIE space. + constexpr Fix32 y() const noexcept{ + return m_y; + } + + /// Z value of CIE space. + constexpr Fix32 z() const noexcept{ + return m_z; + } + + /// Sets x value of CIE space. + void setX(Fix32 x) noexcept{ + m_x = x; + } + + /// Sets y value of CIE space. + void setY(Fix32 y) noexcept{ + m_y = y; + } + + /// Sets z value of CIE space. + void setZ(Fix32 z) noexcept{ + m_z = z; + } + +private: + Fix32 m_x; + Fix32 m_y; + Fix32 m_z; + +}; + +/// Defines parameters for channel transformations. +/// Part of TransformStage. +class DecodeFunction { + +public: + /// Creates zero-initialized decode function. + constexpr DecodeFunction() noexcept{} + + /// Creates initialized decode function. + constexpr DecodeFunction( + Fix32 startIn, + Fix32 breakIn, + Fix32 endIn, + Fix32 startOut, + Fix32 breakOut, + Fix32 endOut, + Fix32 gamma, + Fix32 sampleCount + ) noexcept : + m_startIn(startIn), m_breakIn(breakIn), m_endIn(endIn), + m_startOut(startOut), m_breakOut(breakOut), m_endOut(endOut), + m_gamma(gamma), m_sampleCount(sampleCount){} + + /// Starting input value. + constexpr Fix32 startIn() const noexcept{ + return m_startIn; + } + + /// Sets starting input value. + void setStartIn(Fix32 startIn) noexcept{ + m_startIn = startIn; + } + + /// Ending input value. + constexpr Fix32 breakIn() const noexcept{ + return m_breakIn; + } + + /// Sets ending input value. + void setBreakIn(Fix32 breakIn) noexcept{ + m_breakIn = breakIn; + } + + /// Input value when to switch from linear to gamma transformation. + constexpr Fix32 endIn() const noexcept{ + return m_endIn; + } + + /// Sets input value when to switch from linear to gamma transformation. + void setEndIn(Fix32 endIn) noexcept{ + m_endIn = endIn; + } + + /// Starting output value. + constexpr Fix32 startOut() const noexcept{ + return m_startOut; + } + + /// Sets starting output value. + void setStartOut(Fix32 startOut) noexcept{ + m_startOut = startOut; + } + + /// Ending output value. + constexpr Fix32 breakOut() const noexcept{ + return m_breakOut; + } + + /// Sets ending output value. + void setBreakOut(Fix32 breakOut) noexcept{ + m_breakOut = breakOut; + } + + /// Output value when to switch from linear to gamma transformation. + constexpr Fix32 endOut() const noexcept{ + return m_endOut; + } + + /// Sets output value when to switch from linear to gamma transformation. + void setEndOut(Fix32 endOut) noexcept{ + m_endOut = endOut; + } + + /// Constant, exponential used in gamma funciton. + constexpr Fix32 gamma() const noexcept{ + return m_gamma; + } + + /// Sets constant, exponential used in gamma funciton. + void setGamma(Fix32 gamma) noexcept{ + m_gamma = gamma; + } + + /// Number of samples in lookup table. + constexpr Fix32 sampleCount() const noexcept{ + return m_sampleCount; + } + + /// Sets number of samples in lookup table. + void setSampleCount(Fix32 sampleCount) noexcept{ + m_sampleCount = sampleCount; + } + +private: + Fix32 m_startIn; + Fix32 m_breakIn; + Fix32 m_endIn; + Fix32 m_startOut; + Fix32 m_breakOut; + Fix32 m_endOut; + Fix32 m_gamma; + Fix32 m_sampleCount; + +}; + +/// Parameters of ABC or LMN transformations. +/// Refer to manual for more information about members. +class TransformStage { + +public: + typedef std::array Decode; + typedef std::array, 3> Mix; + + constexpr TransformStage() noexcept : + m_decode(), m_mix(){} + + constexpr TransformStage(const Decode& decode) noexcept : + m_decode(decode), m_mix(){} + + constexpr TransformStage(const Mix& mix) noexcept : + m_decode(), m_mix(mix){} + + constexpr TransformStage(const Decode& decode, const Mix& mix) noexcept : + m_decode(decode), m_mix(mix){} + + constexpr const Decode& decode() const noexcept{ + return m_decode; + } + + Decode& decode() noexcept{ + return m_decode; + } + + constexpr const Mix& mix() const noexcept{ + return m_mix; + } + + Mix& mix() noexcept{ + return m_mix; + } + +private: + Decode m_decode; + Mix m_mix; + +}; + +namespace Unsupported { + +// TODO CieColor +/// Cie color +/// Currently stub, more info required. +struct CieColor { + UInt16 m_colorSpace; + Bool m_lowEndian; + Bool m_deviceDependent; + Int32 m_versionNumber; + TransformStage m_stageAbc; + TransformStage m_stageLmn; + CiePoint m_whitePoint; + CiePoint m_blackPoint; + CiePoint m_whitePaper; + CiePoint m_blackInk; + Fix32 m_samples[1]; // <- how many elements? how to use? +}; + +} + +TWPP_DETAIL_PACK_END + +} +#endif + +#endif // TWPP_DETAIL_FILE_CIE_HPP + diff --git a/huagaotwain/twain/twpp/curveresponse.hpp b/huagaotwain/twain/twpp/curveresponse.hpp new file mode 100644 index 0000000..e5d71f7 --- /dev/null +++ b/huagaotwain/twain/twpp/curveresponse.hpp @@ -0,0 +1,116 @@ +/* + +The MIT License (MIT) + +Copyright (c) 2015 Martin Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef TWPP_DETAIL_FILE_CURVERESPONSE_HPP +#define TWPP_DETAIL_FILE_CURVERESPONSE_HPP + +#include "../twpp.hpp" + +namespace Twpp { + +namespace Detail { + +/// Base response class. +class CurveResponse { + +public: + CurveResponse() noexcept{} + + /// Creates a new (Rgb|Gray)Response with default elements, make sure that info.bitsPerPixel() is <= 8. + /// \throw RangeException When info.bitsPerPixel() is negative or greater than 8. + explicit CurveResponse(const ImageInfo& info) : CurveResponse(info.bitsPerPixel()){} + + /// Creates a new (Rgb|Gray)Response with default elements, make sure that bitsPerPixel is <= 8. + /// \throw RangeException When bitsPerPixel is negative or greater than 8. + explicit CurveResponse(Int16 bitsPerPixel){ + if (bitsPerPixel <= 0 || bitsPerPixel > 8){ + throw RangeException(); + } + + UInt16 size = 1 << static_cast(bitsPerPixel); + m_data.reset(new Element8[size]); + for (UInt16 i = 0; i < size; i++){ + m_data[i] = Element8(static_cast(i)); // 0..255 max + } + } + + /// Array of size `2^ImageInfo.bitesPerPixel()`, up to 256 elements (2^8) + Element8* data() noexcept{ + return m_data.get(); + } + + /// Array of size `2^ImageInfo.bitesPerPixel()`, up to 256 elements (2^8) + const Element8* data() const noexcept{ + return m_data.get(); + } + +private: + std::unique_ptr m_data; + +}; + +} + +/// Rgb response class. +class RgbResponse : public Detail::CurveResponse { + +public: + RgbResponse() noexcept{} + + /// Creates a new RgbResponse with default elements, make sure that info.bitesPerPixel() is <= 8. + /// \throw RangeException When info.bitsPerPixel() is negative or greater than 8. + explicit RgbResponse(const ImageInfo& info) : + Detail::CurveResponse(info) {} + + /// Creates a new RgbResponse with default elements, make sure that bitsPerPixel is <= 8. + /// \throw RangeException When bitsPerPixel is negative or greater than 8. + explicit RgbResponse(Int16 bitsPerPixel) : + Detail::CurveResponse(bitsPerPixel) {} + +}; + +/// Gray response class. +class GrayResponse : public Detail::CurveResponse { + +public: + GrayResponse() noexcept{} + + /// Creates a new GrayResponse with default elements, make sure that info.bitesPerPixel() is <= 8. + /// \throw RangeException When info.bitsPerPixel() is negative or greater than 8. + explicit GrayResponse(const ImageInfo& info) : + Detail::CurveResponse(info) {} + + /// Creates a new GrayResponse with default elements, make sure that bitsPerPixel is <= 8. + /// \throw RangeException When bitsPerPixel is negative or greater than 8. + explicit GrayResponse(Int16 bitsPerPixel) : + Detail::CurveResponse(bitsPerPixel) {} + +}; + +} + +#endif // TWPP_DETAIL_FILE_CURVERESPONSE_HPP + diff --git a/huagaotwain/twain/twpp/customdata.hpp b/huagaotwain/twain/twpp/customdata.hpp new file mode 100644 index 0000000..fb3e004 --- /dev/null +++ b/huagaotwain/twain/twpp/customdata.hpp @@ -0,0 +1,71 @@ +/* + +The MIT License (MIT) + +Copyright (c) 2015 Martin Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef TWPP_DETAIL_FILE_CUSTOMDATA_HPP +#define TWPP_DETAIL_FILE_CUSTOMDATA_HPP + +#include "../twpp.hpp" + +namespace Twpp { + +TWPP_DETAIL_PACK_BEGIN +/// Structure for sending custom data to source or application. +class CustomData { + +public: + template + using Data = typename Detail::Lock; + + /// Creates empty custom data. + CustomData() noexcept : + m_size(0), m_handle(){} + + /// Creates custom data with allocated memory. + /// \throw std::bad_alloc + explicit CustomData(UInt32 size) : + m_size(size), m_handle(Detail::alloc(size)){} + + /// Locks and returns pointer to custom data memory. + template + Data lock() const noexcept{ + return Data(m_handle.get()); + } + + /// The size of contained memory block. + UInt32 size() const noexcept{ + return m_size; + } + +private: + UInt32 m_size; + Detail::UniqueHandle m_handle; + +}; +TWPP_DETAIL_PACK_END + +} + +#endif // TWPP_DETAIL_FILE_CUSTOMDATA_HPP diff --git a/huagaotwain/twain/twpp/datasource.hpp b/huagaotwain/twain/twpp/datasource.hpp new file mode 100644 index 0000000..cfbf81b --- /dev/null +++ b/huagaotwain/twain/twpp/datasource.hpp @@ -0,0 +1,2220 @@ +/* + +The MIT License (MIT) + +Copyright (c) 2015-2018 Martin Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef TWPP_DETAIL_FILE_DATASOURCE_HPP +#define TWPP_DETAIL_FILE_DATASOURCE_HPP + +#include "../twpp.hpp" + +namespace Twpp { + + namespace Detail { + + TWPP_DETAIL_PACK_BEGIN + struct AppCapability { + + CapType m_cap; + ConType m_conType; + Handle m_cont; + + }; + TWPP_DETAIL_PACK_END + + struct DoNotFreeHandle { + + DoNotFreeHandle(Handle handle) { + Detail::GlobalMemFuncs::doNotFreeHandle = handle; + } + + ~DoNotFreeHandle() { + Detail::GlobalMemFuncs::doNotFreeHandle = Handle(); + } + + }; + + } + +#define TWPP_ENTRY(SourceClass)\ + extern "C" TWPP_DETAIL_EXPORT Twpp::ReturnCode TWPP_DETAIL_CALLSTYLE \ + DS_Entry(Twpp::Identity* origin, Twpp::DataGroup dg, Twpp::Dat dat, Twpp::Msg msg, void* data){\ + static_assert(\ + std::is_base_of, SourceClass>::value ||\ + std::is_base_of, SourceClass>::value,\ + "Class " #SourceClass " is not derived from SourceFromThis."\ + );\ + return SourceClass::entry(origin, dg, dat, msg, data);\ + } + + /// Result of a data source operation. + /// Contains both return code and status. + class Result { + + public: + /// Creates successful result. + constexpr Result() noexcept : + m_status(), m_rc(ReturnCode::Success) {} + + /// Creates result with supplied return code and status. + constexpr Result(ReturnCode rc, Status status) noexcept : + m_status(status), m_rc(rc) {} + + /// Status part of the result. + constexpr Status status() const noexcept { + return m_status; + } + + /// Return code part of the result. + constexpr ReturnCode returnCode() const noexcept { + return m_rc; + } + + /// Sets status part of the result. + void setStatus(Status status) noexcept { + m_status = status; + } + + /// Sets return code part of the result. + void setReturnCode(ReturnCode rc) noexcept { + m_rc = rc; + } + + constexpr operator ReturnCode() const noexcept { + return m_rc; + } + + constexpr operator Status() const noexcept { + return m_status; + } + + private: + Status m_status; + ReturnCode m_rc; + + }; + + static constexpr inline bool success(const Result& res) noexcept { + return success(res.returnCode()); + } + + + namespace Detail { + + template // false + struct StaticCustomBaseProc { + Result operator()(Dat, Msg, void*) { + return { ReturnCode::Failure, ConditionCode::BadProtocol }; + } + }; + + template + struct StaticCustomBaseProc { + Result operator()(Dat dat, Msg msg, void* data) { + return Derived::staticCustomBase(dat, msg, data); + } + }; + + TWPP_DETAIL_CREATE_HAS_STATIC_METHOD(defaultIdentity) + TWPP_DETAIL_CREATE_HAS_STATIC_METHOD(staticCustomBase) + + } + + namespace SourceFromThisProcs { + + /// Returns data source identity not associated with any instance. + const Identity& defaultIdentity(); + + /// Processes custom TWAIN operations without having any opened connection. + /// DataGroup is always Control. + /// \param dat Type of data. Dat::CustomBase + X. + /// \param msg Message, action to perform. + /// \param data The data, may be null. + /// \return Operation result code. + Result staticCustomBase(Dat dat, Msg msg, void* data); + + } + + /// Base class of a TWAIN data source. + /// It handles instances creation and all static calls. + /// + /// The derived class must: + /// 1) Implement at least all pure virtual methods. + /// 2) Provide `static const Identity& defaultIdentity()`. + /// 3) If hasStaticCustomBaseProc == true, provide + /// `static Result staticCustomBase(Dat dat, Msg msg, void* data)`. + /// + /// After defining your source class, do not forget to use macro + /// TWPP_ENTRY() + /// where the name is a literal, not string: + /// + /// TWPP_ENTRY(Source) // <- no semicolon required + /// \tparam Derived The class inheriting from this. + /// \tparam hasStaticCustomBaseProc {Whether the Derived + /// class handles static custom base operations, see above.} + template + class SourceFromThis { + + public: + SourceFromThis(const SourceFromThis&) = delete; + SourceFromThis& operator=(const SourceFromThis&) = delete; + + SourceFromThis(SourceFromThis&&) = delete; + SourceFromThis& operator=(SourceFromThis&&) = delete; + + virtual ~SourceFromThis() noexcept = default; + + protected: + /// Creates closed instance. + constexpr SourceFromThis() noexcept : + m_lastStatus(ConditionCode::Bummer), m_state(DsState::Closed) {} + + /// The last TWAIN status. + Status lastStatus() const noexcept { + return m_lastStatus; + } + + /// Current TWAIN state. + DsState state() const noexcept { + return m_state; + } + + /// Whether the source is in the supplied TWAIN state. + bool inState(DsState state) const noexcept { + return m_state == state; + } + + /// Whether the source is between min and max states (both inclusive). + bool inState(DsState min, DsState max) const noexcept { + return m_state >= min && m_state <= max; + } + + /// Whether there exists an enabled source. + static bool hasEnabled() noexcept { + for (auto& src : g_sources) { + if (src.inState(DsState::Enabled, DsState::Xferring)) { + return true; + } + } + + return false; + } + + /// Source identity. + const Identity& sourceIdentity() const noexcept { + return m_srcId; + } + + /// Identity of the application that opened the source. + const Identity& applicationIdentity() const noexcept { + return m_appId; + } + + /// Sets current TWAIN state, use with care. + void setState(DsState state) noexcept { + m_state = state; + } + + /// Sets current source identity, use with care. + void setSourceIdentity(const Identity& sourceIdentity) noexcept { + m_srcId = sourceIdentity; + } + + /// Sets current application identity, use with care. + void setApplicationIdentity(const Identity& appIdentity) noexcept { + m_appId = appIdentity; + } + + /// Shortcut for Result(RC::Success, CC::Success). + static constexpr Result success() noexcept { + return { ReturnCode::Success, ConditionCode::Success }; + } + + /// Shortcut for Result(RC::Failure, CC::BadValue). + static constexpr Result badValue() noexcept { + return { ReturnCode::Failure, ConditionCode::BadValue }; + } + + /// Shortcut for Result(RC::Failure, CC::BadProtocol). + static constexpr Result badProtocol() noexcept { + return { ReturnCode::Failure, ConditionCode::BadProtocol }; + } + + /// Shortcut for Result(RC::Failure, CC::SeqError). + static constexpr Result seqError() noexcept { + return { ReturnCode::Failure, ConditionCode::SeqError }; + } + + /// Shortcut for Result(RC::Failure, CC::CapBadOperation). + static constexpr Result capBadOperation() noexcept { + return { ReturnCode::Failure, ConditionCode::CapBadOperation }; + } + + /// Shortcut for Result(RC::Failure, CC::CapUnsupported). + static constexpr Result capUnsupported() noexcept { + return { ReturnCode::Failure, ConditionCode::CapUnsupported }; + } + + /// Shortcut for Result(RC::Failure, CC::Bummber). + static constexpr Result bummer() noexcept { + return { ReturnCode::Failure, ConditionCode::Bummer }; + } + + + /// Notifies application about clicking on OK button. + ReturnCode notifyCloseOk() noexcept { + return notifyApp(Msg::CloseDsOk); + } + + /// Notifies application about clicking on Cancel button. + ReturnCode notifyCloseCancel() noexcept { + return notifyApp(Msg::CloseDsReq); + } + + /// Notifies application about a device event. + ReturnCode notifyDeviceEvent() noexcept { + return notifyApp(Msg::DeviceEvent); + } + + /// Notifies application about ready transfer (after clicking scan button is GUI is shown). + ReturnCode notifyXferReady() noexcept { + return notifyApp(Msg::XferReady); + } + + + + /// Root of source TWAIN calls. + /// \param origin Identity of the caller. + /// \param dg Data group of the call. + /// \param dat Type of data. + /// \param msg Message, action to perform. + /// \param data The data, may be null. + virtual Result call(const Identity& origin, DataGroup dg, Dat dat, Msg msg, void* data) { + switch (dg) { + case DataGroup::Control: + return control(origin, dat, msg, data); + + case DataGroup::Image: + return image(origin, dat, msg, data); + + case DataGroup::Audio: + return audio(origin, dat, msg, data); + + default: + return badProtocol(); + + } + } + + /// Root of source control TWAIN calls. + /// \param origin Identity of the caller. + /// \param dat Type of data. + /// \param msg Message, action to perform. + /// \param data The data, may be null. + virtual Result control(const Identity& origin, Dat dat, Msg msg, void* data) { + if (!data) { + // all control triplets require data + return badValue(); + } + + switch (dat) { + case Dat::Capability: + return capability(origin, msg, *static_cast(data)); + case Dat::CustomData: + return customData(origin, msg, *static_cast(data)); + case Dat::DeviceEvent: + return deviceEvent(origin, msg, *static_cast(data)); + case Dat::Event: // Windows only + return event(origin, msg, *static_cast(data)); + case Dat::FileSystem: + return fileSystem(origin, msg, *static_cast(data)); + case Dat::Identity: + return identity(origin, msg, *static_cast(data)); + case Dat::PassThrough: + return passThrough(origin, msg, *static_cast(data)); + case Dat::PendingXfers: + return pendingXfers(origin, msg, *static_cast(data)); + case Dat::SetupFileXfer: + return setupFileXfer(origin, msg, *static_cast(data)); + case Dat::SetupMemXfer: + return setupMemXfer(origin, msg, *static_cast(data)); + case Dat::Status: + return status(origin, msg, *static_cast(data)); + case Dat::StatusUtf8: + return statusUtf8(origin, msg, *static_cast(data)); + case Dat::UserInterface: + return userInterface(origin, msg, *static_cast(data)); + case Dat::XferGroup: { + return xferGroup(origin, msg, *static_cast(data)); + } + default: + return badProtocol(); + } + } + + /// Capability TWAIN call. + /// Reset, set and set constraint operations are limited to + /// state DsState::Open (4), override this method if you + /// support CapType::ExtendedCaps. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Capability data. + virtual Result capability(const Identity& origin, Msg msg, Capability& data) { + switch (msg) { + case Msg::Get: + // 4 - 7 + return capabilityGet(origin, data); + + case Msg::GetCurrent: + // 4 - 7 + return capabilityGetCurrent(origin, data); + + case Msg::GetDefault: + // 4 - 7 + return capabilityGetDefault(origin, data); + + case Msg::GetHelp: + if (!inState(DsState::Open)) { + return seqError(); + } + + return capabilityGetHelp(origin, data); + + case Msg::GetLabel: + if (!inState(DsState::Open)) { + return seqError(); + } + + return capabilityGetLabel(origin, data); + + case Msg::GetLabelEnum: + if (!inState(DsState::Open)) { + return seqError(); + } + + return capabilityGetLabelEnum(origin, data); + + case Msg::QuerySupport: + // 4 - 7 + return capabilityQuerySupport(origin, data); + + case Msg::Reset: + // 4, extended: 5, 6, 7 + if (!inState(DsState::Open)) { + return seqError(); + } + + return capabilityReset(origin, data); + + case Msg::ResetAll: + if (!inState(DsState::Open)) { + return seqError(); + } + + return capabilityResetAll(origin); // data has no meaning here + + case Msg::Set: + // 4, extended: 5, 6, 7 + if (!inState(DsState::Open)) { + return seqError(); + } + + if (!data) { + return badValue(); + } + + return capabilitySet(origin, data); + + case Msg::SetConstraint: + // 4, extended: 5, 6, 7 + if (!inState(DsState::Open)) { + return seqError(); + } + + if (!data) { + return badValue(); + } + + return capabilitySetConstraint(origin, data); + + default: + return badProtocol(); + } + } + + /// Get capability TWAIN call. + /// Always called in correct state. + /// \param origin Identity of the caller. + /// \param data Capability data. + virtual Result capabilityGet(const Identity& origin, Capability& data) = 0; + + /// Get current capability TWAIN call. + /// Always called in correct state. + /// \param origin Identity of the caller. + /// \param data Capability data. + virtual Result capabilityGetCurrent(const Identity& origin, Capability& data) = 0; + + /// Get default capability TWAIN call. + /// \param origin Identity of the caller. + /// \param data Capability data. + virtual Result capabilityGetDefault(const Identity& origin, Capability& data) = 0; + + /// Get help capability TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Capability data. + virtual Result capabilityGetHelp(const Identity& origin, Capability& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Get label capability TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Capability data. + virtual Result capabilityGetLabel(const Identity& origin, Capability& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Get label enum capability TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Capability data. + virtual Result capabilityGetLabelEnum(const Identity& origin, Capability& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Query support capability TWAIN call. + /// Always called in correct state. + /// \param origin Identity of the caller. + /// \param data Capability data. + virtual Result capabilityQuerySupport(const Identity& origin, Capability& data) = 0; + + /// Reset capability TWAIN call. + /// Always called in correct state: 4, if you support extended + /// capabilities, override `capability` method. + /// \param origin Identity of the caller. + /// \param data Capability data. + virtual Result capabilityReset(const Identity& origin, Capability& data) = 0; + + /// Reset all capability TWAIN call. + /// Always called in correct state. + /// \param origin Identity of the caller. + virtual Result capabilityResetAll(const Identity& origin) = 0; + + /// Set capability TWAIN call. + /// Always called in correct state: 4, if you support extended + /// capabilities, override `capability` method. + /// \param origin Identity of the caller. + /// \param data Capability data. + virtual Result capabilitySet(const Identity& origin, Capability& data) = 0; + + /// Set capability TWAIN call. + /// Always called in correct state: 4, if you support extended + /// capabilities, override `capability` method. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Capability data. + virtual Result capabilitySetConstraint(const Identity& origin, Capability& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + + + /// Custom data TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Custom data. + virtual Result customData(const Identity& origin, Msg msg, CustomData& data) { + if (!inState(DsState::Open)) { + return seqError(); + } + + switch (msg) { + case Msg::Get: + return customDataGet(origin, data); + + case Msg::Set: + return customDataSet(origin, data); + + default: + return badProtocol(); + } + } + + /// Get custom data TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Custom data. + virtual Result customDataGet(const Identity& origin, CustomData& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Set custom data TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Custom data. + virtual Result customDataSet(const Identity& origin, CustomData& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Device event TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Device event data. + virtual Result deviceEvent(const Identity& origin, Msg msg, DeviceEvent& data) { + if (msg != Msg::Get) { + return badProtocol(); + } + + return deviceEventGet(origin, data); + } + + /// Get device event TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Device event data. + virtual Result deviceEventGet(const Identity& origin, DeviceEvent& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + + + /// Event TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Event data. + virtual Result event(const Identity& origin, Msg msg, Event& data) { + if (msg != Msg::ProcessEvent) { + return badProtocol(); + } + + if (!inState(DsState::Enabled, DsState::Xferring)) { + return seqError(); + } + return eventProcess(origin, data); + } + +#if defined(TWPP_DETAIL_OS_WIN) || defined(TWPP_DETAIL_OS_MAC) + /// Process event TWAIN call. + /// Always called in correct state. + /// \param origin Identity of the caller. + /// \param data Event data. + virtual Result eventProcess(const Identity& origin, Event& data) = 0; +#elif defined(TWPP_DETAIL_OS_LINUX) + /// Process event TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Event data. + virtual Result eventProcess(const Identity& origin, Event& data) { + Detail::unused(origin, data); + return badProtocol(); + } +#else +# error "eventProcess for your platform here" +#endif + + /// Identity TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Identity data. + virtual Result identity(const Identity& origin, Msg msg, Identity& data) { + Result rc; + switch (msg) { + case Msg::Get: + // any state + data = sourceIdentity(); + return success(); + + case Msg::OpenDs: { + if (!inState(DsState::Closed)) { + return seqError(); + } + + setSourceIdentity(data); + setApplicationIdentity(origin); + rc = identityOpenDs(origin); + if (Twpp::success(rc)) { + setState(DsState::Open); + } + + return rc; + } + + case Msg::CloseDs: { + if (inState(DsState::Enabled)) { + setState(DsState::Open); + } + if (!inState(DsState::Open)) { + return seqError(); + } + + rc = identityCloseDs(origin); + if (Twpp::success(rc)) { + setState(DsState::Closed); + } + + return rc; + } + + default: + return badProtocol(); + } + } + + /// Open source identity TWAIN call. + /// Always called in correct state. + /// \param origin Identity of the caller. + virtual Result identityOpenDs(const Identity& origin) = 0; + + /// Close source identity TWAIN call. + /// Always called in correct state. + /// \param origin Identity of the caller. + virtual Result identityCloseDs(const Identity& origin) = 0; + + /// File system TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data File system data. + virtual Result fileSystem(const Identity& origin, Msg msg, FileSystem& data) { + switch (msg) { + case Msg::AutomaticCaptureDir: + if (!inState(DsState::Open)) { + return seqError(); + } + + return fileSystemAutomatic(origin, data); + + case Msg::ChangeDir: + if (!inState(DsState::Open)) { + return seqError(); + } + + return fileSystemChange(origin, data); + + case Msg::Copy: + if (!inState(DsState::Open)) { + return seqError(); + } + + return fileSystemCopy(origin, data); + + case Msg::CreateDir: + if (!inState(DsState::Open)) { + return seqError(); + } + + return fileSystemCreate(origin, data); + + case Msg::Delete: + if (!inState(DsState::Open)) { + return seqError(); + } + + return fileSystemDelete(origin, data); + + case Msg::FormatMedia: + if (!inState(DsState::Open)) { + return seqError(); + } + + return fileSystemFormat(origin, data); + + case Msg::GetClose: + if (!inState(DsState::Open, DsState::XferReady)) { + return seqError(); + } + + return fileSystemGetClose(origin, data); + + case Msg::GetFirstFile: + if (!inState(DsState::Open, DsState::XferReady)) { + return seqError(); + } + + return fileSystemGetFirst(origin, data); + + case Msg::GetInfo: + // 4 - 7 + return fileSystemGetInfo(origin, data); + + case Msg::GetNextFile: + if (!inState(DsState::Open, DsState::XferReady)) { + return seqError(); + } + + return fileSystemGetNext(origin, data); + + case Msg::Rename: + if (!inState(DsState::Open)) { + return seqError(); + } + + return fileSystemRename(origin, data); + + default: + return badProtocol(); + } + } + + /// Automatic capture directory file system TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data File system data. + virtual Result fileSystemAutomatic(const Identity& origin, FileSystem& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Change directory file system TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data File system data. + virtual Result fileSystemChange(const Identity& origin, FileSystem& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + + /// Copy file system TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data File system data. + virtual Result fileSystemCopy(const Identity& origin, FileSystem& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Create directory file system TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data File system data. + virtual Result fileSystemCreate(const Identity& origin, FileSystem& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Delete file system TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data File system data. + virtual Result fileSystemDelete(const Identity& origin, FileSystem& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Format media file system TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data File system data. + virtual Result fileSystemFormat(const Identity& origin, FileSystem& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Get close file system TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data File system data. + virtual Result fileSystemGetClose(const Identity& origin, FileSystem& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Get first file file system TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data File system data. + virtual Result fileSystemGetFirst(const Identity& origin, FileSystem& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Get info file system TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data File system data. + virtual Result fileSystemGetInfo(const Identity& origin, FileSystem& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Get next file file system TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data File system data. + virtual Result fileSystemGetNext(const Identity& origin, FileSystem& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Rename file system TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data File system data. + virtual Result fileSystemRename(const Identity& origin, FileSystem& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + + /// Pass through TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Pass through data. + virtual Result passThrough(const Identity& origin, Msg msg, PassThrough& data) { + if (msg != Msg::PassThrough) { + return badProtocol(); + } + + // 4 - 7 + return passThroughPass(origin, data); + } + + /// Pass through pass through TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Pass through data. + virtual Result passThroughPass(const Identity& origin, PassThrough& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Pending xfers TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Pending xfers data. + virtual Result pendingXfers(const Identity& origin, Msg msg, PendingXfers& data) { + switch (msg) { + case Msg::EndXfer: { + if (!inState(DsState::XferReady, DsState::Xferring)) { + return seqError(); + } + + auto rc = pendingXfersEnd(origin, data); + if (Twpp::success(rc)) { + DataGroup xferGroup = DataGroup::Image; + if (!Twpp::success(this->xferGroup(origin, Msg::Get, xferGroup))) { + xferGroup = DataGroup::Image; + } + + if (xferGroup == DataGroup::Audio) { + setState(DsState::XferReady); + } + else { + //setState(data.count() ? DsState::XferReady : DsState::Enabled); + setState(data.count() ? DsState::XferReady : DsState::Enabled); + } + } + + return rc; + } + + + case Msg::Reset: { + if (!inState(DsState::XferReady)) { + return seqError(); + } + + auto rc = pendingXfersReset(origin, data); + if (Twpp::success(rc)) { + DataGroup xferGroup = DataGroup::Image; + if (!Twpp::success(this->xferGroup(origin, Msg::Get, xferGroup))) { + xferGroup = DataGroup::Image; + } + + if (xferGroup != DataGroup::Audio) { + setState(DsState::Enabled); + } + } + + return rc; + } + + case Msg::StopFeeder: + if (!inState(DsState::XferReady)) { + return seqError(); + } + + return pendingXfersStopFeeder(origin, data); + + case Msg::Get: + if (!inState(DsState::Open, DsState::Xferring)) { + return seqError(); + } + + return pendingXfersGet(origin, data); + + default: + return badProtocol(); + } + } + + /// Get pending xfers TWAIN call. + /// Always called in correct state. + /// \param origin Identity of the caller. + /// \param data Pending xfers data. + virtual Result pendingXfersGet(const Identity& origin, PendingXfers& data) = 0; + + /// End xfer pending xfers TWAIN call. + /// Always called in correct state. + /// \param origin Identity of the caller. + /// \param data Pending xfers data. + virtual Result pendingXfersEnd(const Identity& origin, PendingXfers& data) = 0; + + /// Reset xfers pending xfers TWAIN call. + /// Always called in correct state. + /// \param origin Identity of the caller. + /// \param data Pending xfers data. + virtual Result pendingXfersReset(const Identity& origin, PendingXfers& data) = 0; + + /// Stop feeder pending xfers TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Pending xfers data. + virtual Result pendingXfersStopFeeder(const Identity& origin, PendingXfers& data) = 0; + + /// Setup file xfer TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Setup file xfer data. + virtual Result setupFileXfer(const Identity& origin, Msg msg, SetupFileXfer& data) { + switch (msg) { + case Msg::Get: + if (!inState(DsState::Open, DsState::XferReady)) { + return seqError(); + } + + return setupFileXferGet(origin, data); + + case Msg::GetDefault: + if (!inState(DsState::Open, DsState::XferReady)) { + return seqError(); + } + + return setupFileXferGetDefault(origin, data); + + case Msg::Set: + if (!inState(DsState::Open, DsState::XferReady)) { + return seqError(); + } + + return setupFileXferSet(origin, data); + + case Msg::Reset: + if (!inState(DsState::Open)) { + return seqError(); + } + + return setupFileXferReset(origin, data); + + default: + return badProtocol(); + } + } + + /// Get setup file xfer TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Setup file xfer data. + virtual Result setupFileXferGet(const Identity& origin, SetupFileXfer& data) = 0; + + /// Get default setup file xfer TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Setup file xfer data. + virtual Result setupFileXferGetDefault(const Identity& origin, SetupFileXfer& data) = 0; + + /// Set setup file xfer TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Setup file xfer data. + virtual Result setupFileXferSet(const Identity& origin, SetupFileXfer& data) = 0; + + /// Reset setup file xfer TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Setup file xfer data. + virtual Result setupFileXferReset(const Identity& origin, SetupFileXfer& data) = 0; + + /// Setup memory xfer TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Setup memory xfer data. + virtual Result setupMemXfer(const Identity& origin, Msg msg, SetupMemXfer& data) { + if (msg != Msg::Get) { + return badProtocol(); + } + + if (!inState(DsState::Open, DsState::XferReady)) { + return seqError(); + } + + return setupMemXferGet(origin, data); + } + + /// Get setup memory xfer TWAIN call. + /// Always called in correct state. + /// \param origin Identity of the caller. + /// \param data Setup memory xfer data. + virtual Result setupMemXferGet(const Identity& origin, SetupMemXfer& data) = 0; + + /// Status TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Status data. + virtual Result status(const Identity& origin, Msg msg, Status& data) { + if (msg != Msg::Get) { + return badProtocol(); + } + + return statusGet(origin, data); + } + + /// Get status TWAIN call. + /// Always called in correct state. + /// Default implementation returns last status. + /// \param origin Identity of the caller. + /// \param data Status data. + virtual Result statusGet(const Identity& origin, Status& data) { + Detail::unused(origin); + data = lastStatus(); + return success(); + } + + /// Status utf8 TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Status utf8 data. + virtual Result statusUtf8(const Identity& origin, Msg msg, StatusUtf8& data) { + if (msg != Msg::Get) { + return badProtocol(); + } + + // 3 - 7 + return statusUtf8Get(origin, data); + } + + /// Get status utf8 TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Status utf8 data. + virtual Result statusUtf8Get(const Identity& origin, StatusUtf8& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// User interface TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data User interface data. + virtual Result userInterface(const Identity& origin, Msg msg, UserInterface& data) { + Result rc; + switch (msg) { + case Msg::DisableDs: + if (!inState(DsState::Enabled)) { + setState(DsState::Enabled); + } + + rc = userInterfaceDisable(origin, data); + if (Twpp::success(rc)) { + setState(DsState::Open); + } + + return rc; + + case Msg::EnableDs: + if (!inState(DsState::Open) || hasEnabled()) { // only a single source can be enabled at any given time + return seqError(); + } + + rc = userInterfaceEnable(origin, data); + if (Twpp::success(rc) || rc == ReturnCode::CheckStatus) { + if (inState(DsState::Open)) { // allow userInterfaceEnable to transfer to higher states + setState(DsState::Enabled); + if(!data.showUi()) + notifyXferReady(); + } + } + + return rc; + + case Msg::EnableDsUiOnly: + if (!inState(DsState::Open)) { + return seqError(); + } + + rc = userInterfaceEnableUiOnly(origin, data); + if (Twpp::success(rc)) { + setState(DsState::Enabled); + } + + return rc; + + default: + return badProtocol(); + } + } + + /// Disable user interface TWAIN call. + /// Always called in correct state. + /// \param origin Identity of the caller. + /// \param data User interface data. + virtual Result userInterfaceDisable(const Identity& origin, UserInterface& data) = 0; + + /// Enable user interface TWAIN call. + /// Always called in correct state. + /// \param origin Identity of the caller. + /// \param data User interface data. + virtual Result userInterfaceEnable(const Identity& origin, UserInterface& data) = 0; + + /// Enable UI only user interface TWAIN call. + /// Always called in correct state. + /// \param origin Identity of the caller. + /// \param data User interface data. + virtual Result userInterfaceEnableUiOnly(const Identity& origin, UserInterface& data) = 0; + + /// Xfer group TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Xfer group data. + virtual Result xferGroup(const Identity& origin, Msg msg, DataGroup& data) { + switch (msg) { + case Msg::Get: + if (!inState(DsState::Open, DsState::XferReady)) { + return seqError(); + } + + return xferGroupGet(origin, data); + + case Msg::Set: + if (!inState(DsState::XferReady)) { + return seqError(); + } + + return xferGroupSet(origin, data); + + default: + return badProtocol(); + } + } + + /// Get xfer group TWAIN call. + /// Always called in correct state. + /// Default implementation returns DataGroup::Image. + /// \param origin Identity of the caller. + /// \param data Xfer group data. + virtual Result xferGroupGet(const Identity& origin, DataGroup& data) { + Detail::unused(origin); + data = DataGroup::Image; + return success(); + } + + /// Set xfer group TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Xfer group data. + virtual Result xferGroupSet(const Identity& origin, DataGroup& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Root of source image TWAIN calls. + /// + /// Special data to type casts: + /// ExtImageInfo: reinterpret_cast(data) + /// GrayResponse: reinterpret_cast(data) + /// RgbResponse: reinterpret_cast(data) + /// + /// \param origin Identity of the caller. + /// \param dat Type of data. + /// \param msg Message, action to perform. + /// \param data The data, may be null. + virtual Result image(const Identity& origin, Dat dat, Msg msg, void* data) { + if (dat != Dat::ImageFileXfer && !data) { + return badValue(); + } + + switch (dat) { + // TODO CieColor + /*case Dat::CieColor: + return cieColor(origin, msg, *static_cast(data));*/ + case Dat::ExtImageInfo: + return extImageInfo(origin, msg, reinterpret_cast(data)); // ExtImageInfo is simply a `pointer to TW_EXTIMAGEINFO` + case Dat::GrayResponse: + return grayResponse(origin, msg, reinterpret_cast(data)); // GrayResponse is simply a `pointer to TW_GRAYRESPONSE` + case Dat::IccProfile: + return iccProfile(origin, msg, *static_cast(data)); + case Dat::ImageFileXfer: + return imageFileXfer(origin, msg); + case Dat::ImageInfo: + return imageInfo(origin, msg, *static_cast(data)); + case Dat::ImageLayout: + return imageLayout(origin, msg, *static_cast(data)); + case Dat::ImageMemFileXfer: + return imageMemFileXfer(origin, msg, *static_cast(data)); + case Dat::ImageMemXfer: + return imageMemXfer(origin, msg, *static_cast(data)); + case Dat::ImageNativeXfer: + return imageNativeXfer(origin, msg, *static_cast(data)); + case Dat::JpegCompression: + return jpegCompression(origin, msg, *static_cast(data)); + case Dat::Palette8: + return palette8(origin, msg, *static_cast(data)); + case Dat::RgbResponse: + return rgbResponse(origin, msg, reinterpret_cast(data)); // RgbResponse is simply a `pointer to TW_RGBRESPONSE` + default: + return badProtocol(); + } + } + + // TODO CieColor + /* + /// Cie color TWAIN call. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Cie color data. + virtual Result cieColor(const Identity& origin, Msg msg, CieColor& data){ + Detail::unused(origin, msg, data); + return badProtocol(); + }*/ + + /// Ext image info TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Ext image info data. + virtual Result extImageInfo(const Identity& origin, Msg msg, ExtImageInfo& data) { + if (msg != Msg::Get) { + return badProtocol(); + } + + if (!inState(DsState::Xferring)) { + return seqError(); + } + + return extImageInfoGet(origin, data); + } + + /// Get ext image info TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Ext image info data. + virtual Result extImageInfoGet(const Identity& origin, ExtImageInfo& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Gray response TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Gray response data. + virtual Result grayResponse(const Identity& origin, Msg msg, GrayResponse& data) { + if (!inState(DsState::Open)) { + return seqError(); + } + + switch (msg) { + case Msg::Set: + return grayResponseSet(origin, data); + + case Msg::Reset: + return grayResponseReset(origin, data); + + default: + return badProtocol(); + } + } + + /// Set gray response TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Gray response data. + virtual Result grayResponseSet(const Identity& origin, GrayResponse& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Reset gray response TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Gray response data. + virtual Result grayResponseReset(const Identity& origin, GrayResponse& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// ICC profile TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data ICC profile data. + virtual Result iccProfile(const Identity& origin, Msg msg, IccProfileMemory& data) { + if (msg != Msg::Get) { + return badProtocol(); + } + + if (!inState(DsState::XferReady, DsState::Xferring)) { + return seqError(); + } + + return iccProfileGet(origin, data); + } + + /// Get ICC profile TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data ICC profile data. + virtual Result iccProfileGet(const Identity& origin, IccProfileMemory& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Image file xfer TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + virtual Result imageFileXfer(const Identity& origin, Msg msg) { + if (msg != Msg::Get) { + return badProtocol(); + } + + if (!inState(DsState::XferReady)) { + return seqError(); + } + + auto rc = imageFileXferGet(origin); + if (rc == ReturnCode::XferDone) { + setState(DsState::Xferring); + } + + return rc; + } + + /// Get image file xfer TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// Always called in correct state. + /// \param origin Identity of the caller. + virtual Result imageFileXferGet(const Identity& origin) = 0; + + /// Image info TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Image info data. + virtual Result imageInfo(const Identity& origin, Msg msg, ImageInfo& data) { + if (msg != Msg::Get) { + return badProtocol(); + } + + if (!inState(DsState::XferReady, DsState::Xferring)) { + return seqError(); + } + + return imageInfoGet(origin, data); + } + + /// Get image info TWAIN call. + /// Always called in correct state. + /// \param origin Identity of the caller. + /// \param data Image info data. + virtual Result imageInfoGet(const Identity& origin, ImageInfo& data) = 0; + + + /// Image layout TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Image layout data. + virtual Result imageLayout(const Identity& origin, Msg msg, ImageLayout& data) { + switch (msg) { + case Msg::Get: + if (!inState(DsState::Open, DsState::XferReady)) { + return seqError(); + } + + return imageLayoutGet(origin, data); + + case Msg::GetDefault: + if (!inState(DsState::Open, DsState::XferReady)) { + return seqError(); + } + + return imageLayoutGetDefault(origin, data); + + case Msg::Set: + if (!inState(DsState::Open)) { + return seqError(); + } + + return imageLayoutSet(origin, data); + + case Msg::Reset: + if (!inState(DsState::Open)) { + return seqError(); + } + + return imageLayoutReset(origin, data); + + default: + return badProtocol(); + } + } + + /// Get image layout TWAIN call. + /// Always called in correct state. + /// \param origin Identity of the caller. + /// \param data Image layout data. + virtual Result imageLayoutGet(const Identity& origin, ImageLayout& data) = 0; + + /// Get default image layout TWAIN call. + /// Always called in correct state. + /// \param origin Identity of the caller. + /// \param data Image layout data. + virtual Result imageLayoutGetDefault(const Identity& origin, ImageLayout& data) = 0; + + /// Set image layout TWAIN call. + /// Always called in correct state. + /// \param origin Identity of the caller. + /// \param data Image layout data. + virtual Result imageLayoutSet(const Identity& origin, ImageLayout& data) = 0; + + /// Reset image layout TWAIN call. + /// Always called in correct state. + /// \param origin Identity of the caller. + /// \param data Image layout data. + virtual Result imageLayoutReset(const Identity& origin, ImageLayout& data) = 0; + + + /// Image memory file xfer TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Image memory file xfer data. + virtual Result imageMemFileXfer(const Identity& origin, Msg msg, ImageMemFileXfer& data) { + if (msg != Msg::Get) { + return badProtocol(); + } + + if (!inState(DsState::XferReady)) { + return seqError(); + } + + auto rc = imageMemFileXferGet(origin, data); + if (rc == ReturnCode::XferDone) { + setState(DsState::Xferring); + } + + return rc; + } + + /// Get image memory file xfer TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Image memory file xfer data. + virtual Result imageMemFileXferGet(const Identity& origin, ImageMemFileXfer& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Image memory xfer TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Image memory xfer data. + virtual Result imageMemXfer(const Identity& origin, Msg msg, ImageMemXfer& data) { + if (msg != Msg::Get) { + return badProtocol(); + } + + if (!inState(DsState::XferReady, DsState::Xferring)) { + return seqError(); + } + + auto rc = imageMemXferGet(origin, data); + if (Twpp::success(rc) || rc == ReturnCode::XferDone) { + setState(DsState::Xferring); + } + + return rc; + } + + /// Get image memory xfer TWAIN call. + /// Always called in correct state. + /// \param origin Identity of the caller. + /// \param data Image memory xfer data. + virtual Result imageMemXferGet(const Identity& origin, ImageMemXfer& data) = 0; + + /// Image native xfer TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Handle to image native xfer data. + virtual Result imageNativeXfer(const Identity& origin, Msg msg, ImageNativeXfer& data) { + if (msg != Msg::Get) { + return badProtocol(); + } + + if (!inState(DsState::XferReady)) { + return seqError(); + } + + auto rc = imageNativeXferGet(origin, data); + if (rc == ReturnCode::XferDone) { + setState(DsState::Xferring); + } + + return rc; + } + + /// Get image native xfer TWAIN call. + /// Always called in correct state. + /// \param origin Identity of the caller. + /// \param data Handle to image native xfer data. + virtual Result imageNativeXferGet(const Identity& origin, ImageNativeXfer& data) = 0; + + /// JPEG compression TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data JPEG compression data. + virtual Result jpegCompression(const Identity& origin, Msg msg, JpegCompression& data) { + switch (msg) { + case Msg::Get: + if (!inState(DsState::Open, DsState::XferReady)) { + return seqError(); + } + + return jpegCompressionGet(origin, data); + + case Msg::GetDefault: + if (!inState(DsState::Open, DsState::XferReady)) { + return seqError(); + } + + return jpegCompressionGetDefault(origin, data); + + case Msg::Set: + if (!inState(DsState::Open)) { + return seqError(); + } + + return jpegCompressionSet(origin, data); + + case Msg::Reset: + if (!inState(DsState::Open)) { + return seqError(); + } + + return jpegCompressionReset(origin, data); + + default: + return badProtocol(); + } + } + + /// Get JPEG compression TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data JPEG compression data. + virtual Result jpegCompressionGet(const Identity& origin, JpegCompression& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Get default JPEG compression TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data JPEG compression data. + virtual Result jpegCompressionGetDefault(const Identity& origin, JpegCompression& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Set JPEG compression TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data JPEG compression data. + virtual Result jpegCompressionSet(const Identity& origin, JpegCompression& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Reset JPEG compression TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data JPEG compression data. + virtual Result jpegCompressionReset(const Identity& origin, JpegCompression& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Palette8 TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Palette8 data. + virtual Result palette8(const Identity& origin, Msg msg, Palette8& data) { + switch (msg) { + case Msg::Get: + if (!inState(DsState::Open, DsState::XferReady)) { + return seqError(); + } + + return palette8Get(origin, data); + + case Msg::GetDefault: + if (!inState(DsState::Open, DsState::XferReady)) { + return seqError(); + } + + return palette8GetDefault(origin, data); + + case Msg::Set: + if (!inState(DsState::Open)) { + return seqError(); + } + + return palette8Set(origin, data); + + case Msg::Reset: + if (!inState(DsState::Open)) { + return seqError(); + } + + return palette8Reset(origin, data); + + default: + return badProtocol(); + } + } + + /// Get Palette8 TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Palette8 data. + virtual Result palette8Get(const Identity& origin, Palette8& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Get default Palette8 TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Palette8 data. + virtual Result palette8GetDefault(const Identity& origin, Palette8& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Set Palette8 TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Palette8 data. + virtual Result palette8Set(const Identity& origin, Palette8& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Reset Palette8 TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Palette8 data. + virtual Result palette8Reset(const Identity& origin, Palette8& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// RGB response TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data RGB response data. + virtual Result rgbResponse(const Identity& origin, Msg msg, RgbResponse& data) { + if (!inState(DsState::Open)) { + return seqError(); + } + + switch (msg) { + case Msg::Set: + return rgbResponseSet(origin, data); + + case Msg::Reset: + return rgbResponseReset(origin, data); + + default: + return badProtocol(); + } + } + + /// Set RGB response TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data RGB response data. + virtual Result rgbResponseSet(const Identity& origin, RgbResponse& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Reset RGB response TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data RGB response data. + virtual Result rgbResponseReset(const Identity& origin, RgbResponse& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + + /// Root of source audio TWAIN calls. + /// \param origin Identity of the caller. + /// \param dat Type of data. + /// \param msg Message, action to perform. + /// \param data The data, may be null. + virtual Result audio(const Identity& origin, Dat dat, Msg msg, void* data) { + if (dat != Dat::AudioFileXfer && !data) { + return badValue(); + } + + switch (dat) { + case Dat::AudioFileXfer: + return audioFileXfer(origin, msg); + case Dat::AudioInfo: + return audioInfo(origin, msg, *static_cast(data)); + case Dat::AudioNativeXfer: + return audioNativeXfer(origin, msg, *static_cast(data)); + default: + return badProtocol(); + } + } + + /// Audio file xfer TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + virtual Result audioFileXfer(const Identity& origin, Msg msg) { + if (msg != Msg::Get) { + return badProtocol(); + } + + if (!inState(DsState::XferReady)) { + return seqError(); + } + + auto rc = audioFileXferGet(origin); + if (rc == ReturnCode::XferDone) { + setState(DsState::Xferring); + } + + return rc; + } + + /// Get audio file xfer TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + virtual Result audioFileXferGet(const Identity& origin) { + Detail::unused(origin); + return badProtocol(); + } + + /// Audio info TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Audio info data. + virtual Result audioInfo(const Identity& origin, Msg msg, AudioInfo& data) { + if (msg != Msg::Get) { + return badProtocol(); + } + + if (!inState(DsState::XferReady, DsState::Xferring)) { + return seqError(); + } + + return audioInfoGet(origin, data); + } + + /// Get audio info TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Audio info data. + virtual Result audioInfoGet(const Identity& origin, AudioInfo& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Audio native xfer TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Handle to audio native xfer data. + virtual Result audioNativeXfer(const Identity& origin, Msg msg, AudioNativeXfer& data) { + if (msg != Msg::Get) { + return badProtocol(); + } + + if (!inState(DsState::XferReady)) { + return seqError(); + } + + auto rc = audioNativeXferGet(origin, data); + if (Twpp::success(rc)) { + setState(DsState::Xferring); + } + + return rc; + } + + /// Get audio native xfer TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Handle to audio native xfer data. + virtual Result audioNativeXferGet(const Identity& origin, AudioNativeXfer& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + private: + ReturnCode notifyApp(Msg msg) noexcept { + switch (msg) { + case Msg::XferReady: + if (!inState(DsState::Enabled)) { + return ReturnCode::Failure; + } + + break; + case Msg::CloseDsOk: + case Msg::CloseDsReq: + if (!inState(DsState::Enabled, DsState::Xferring)) { + return ReturnCode::Failure; + } + + break; + default: + break; + } + + auto rc = g_entry(&m_srcId, &m_appId, DataGroup::Control, Dat::Null, msg, nullptr); + if (Twpp::success(rc)) { + switch (msg) { + case Msg::XferReady: + setState(DsState::XferReady); + break; + case Msg::CloseDsOk: + case Msg::CloseDsReq: + setState(DsState::Enabled); + break; + default: + break; + } + } + + return rc; + } + + Result callRoot(Identity* origin, DataGroup dg, Dat dat, Msg msg, void* data) noexcept { + if (!origin) { + return badProtocol(); + } + + bool isCapability = dg == DataGroup::Control && dat == Dat::Capability && data != nullptr; + try { + return isCapability + ? callCapability(*origin, dg, dat, msg, data) + : call(*origin, dg, dat, msg, data); + } + catch (const std::bad_alloc&) { + return { ReturnCode::Failure, ConditionCode::LowMemory }; + } + catch (...) { + // the exception would be caught in the static handler below + // that would set static status, we want to set local one + return bummer(); + } + } + + Result callCapability(const Identity& origin, DataGroup dg, Dat dat, Msg msg, void* data) { + // it is the responsibility of the APP to free capability handle + // we must assume the APP does not set the handle to zero after freeing it + // that would break capability (handle) move-assignment operator + // make sure such handle is not freed + Detail::AppCapability& cap = *static_cast(data); + Detail::DoNotFreeHandle doNotFree(cap.m_cont); + Detail::unused(doNotFree); + + return call(origin, dg, dat, msg, data); + } + + + Identity m_srcId; + Identity m_appId; + Status m_lastStatus; + DsState m_state; + + + static typename std::list::iterator find(Identity* origin) noexcept { + if (origin) { + for (auto it = g_sources.begin(); it != g_sources.end(); ++it) { + if (it->m_appId.id() == origin->id()) { + return it; + } + } + } + + return g_sources.end(); + } + + static void resetDsm() { + g_entry = nullptr; + +#if defined(TWPP_DETAIL_OS_WIN32) + g_dsm.unload(); +#endif + } + + static Result staticCall(typename std::list::iterator src, Identity* origin, + DataGroup dg, Dat dat, Msg msg, void* data) { + +#if defined(TWPP_DETAIL_OS_WIN32) + if (!g_entry) { + if (!g_dsm && !g_dsm.load(true)) { + return bummer(); + } + + g_entry = g_dsm.resolve(); + } +#endif + + if (!g_entry) { + return bummer(); + } + + auto rc = src->callRoot(origin, dg, dat, msg, data); + src->m_lastStatus = rc.status(); + + if (dg == DataGroup::Control && dat == Dat::Identity && ( + (msg == Msg::CloseDs && Twpp::success(rc)) || + (msg == Msg::OpenDs && !Twpp::success(rc)) + ) + ) { + g_sources.erase(src); + if (g_sources.empty()) { + resetDsm(); + } + } + + return rc; + } + + static Result staticControl(Identity* origin, DataGroup dg, Dat dat, Msg msg, void* data) { + if (dg != DataGroup::Control) { + return seqError(); + } + + switch (dat) { + case Dat::EntryPoint: + if (msg == Msg::Set) { + if (!data) { + return badValue(); + } + + auto& e = *static_cast(data); + g_entry = e.m_entry; + Detail::setMemFuncs(e.m_alloc, e.m_free, e.m_lock, e.m_unlock); + return success(); + } + + break; + + case Dat::Status: { + if (msg == Msg::Get) { + if (!data) { + return badValue(); + } + + *static_cast(data) = g_lastStatus; + return success(); + } + + break; + } + + case Dat::Identity: { + switch (msg) { + case Msg::Get: { + if (!data) { + return badValue(); + } + + static_assert(Detail::HasStaticMethod_defaultIdentity::value, + "Your source class lacks `static const Identity& defaultIdentity()` method."); + + auto& ident = *static_cast(data); + const Identity& def = Derived::defaultIdentity(); + ident = Identity(ident.id(), def.version(), def.protocolMajor(), + def.protocolMinor(), def.dataGroupsRaw(), def.manufacturer(), + def.productFamily(), def.productName()); + + return success(); + } + + case Msg::OpenDs: { + g_sources.emplace_back(); + return staticCall(--g_sources.end(), origin, dg, dat, msg, data); + } + + case Msg::CloseDs: + // not open yet + return success(); + + case Msg::UserSelect: + if (!data) { + return badValue(); + } + else + { + auto& ident = *static_cast(data); + + return Derived::selectIdentity(ident); + + return success(); + } + break; + + default: + break; + } + + break; + } + + default: + if (dat >= Dat::CustomBase) { + static_assert(Detail::HasStaticMethod_staticCustomBase::value || + !hasStaticCustomBaseProc, + "Your source class lacks `static Result staticCustomBase(Dat, Msg, void*)` method."); + + return Detail::StaticCustomBaseProc()(dat, msg, data); + } + + break; + } + + return badProtocol(); + } + + public: + /// TWAIN entry, do not call from data source. + static ReturnCode entry(Identity* origin, DataGroup dg, Dat dat, Msg msg, void* data) noexcept { + auto src = find(origin); + //FileTools::write_log("D:\\1.txt", "call:datagroup-" + to_string((int)dg) + "dat-" + to_string(int(dat)) + "msg-" + to_string(int(msg))); + try { + auto rc = src == g_sources.end() ? + staticControl(origin, dg, dat, msg, data) : + staticCall(src, origin, dg, dat, msg, data); + + g_lastStatus = rc.status(); + return rc.returnCode(); + } + catch (const std::bad_alloc&) { + g_lastStatus = ConditionCode::LowMemory; + return ReturnCode::Failure; + } + catch (...) { + // we can't throw exceptions out of data sources + // the C interface can't really handle them + // especially when there are different implementations + g_lastStatus = ConditionCode::Bummer; + return ReturnCode::Failure; + } + } + + private: + static std::list g_sources; + static Detail::DsmEntry g_entry; + static Status g_lastStatus; + +#if defined(TWPP_DETAIL_OS_WIN32) + static Detail::DsmLib g_dsm; // only old windows dsm requires this +#endif + + }; + + template + std::list SourceFromThis::g_sources; + + template + Detail::DsmEntry SourceFromThis::g_entry; + + template + Status SourceFromThis::g_lastStatus = ConditionCode::Bummer; + +#if defined(TWPP_DETAIL_OS_WIN32) + template + Detail::DsmLib SourceFromThis::g_dsm; +#endif + +} + +#endif // TWPP_DETAIL_FILE_DATASOURCE_HPP + diff --git a/huagaotwain/twain/twpp/deviceevent.hpp b/huagaotwain/twain/twpp/deviceevent.hpp new file mode 100644 index 0000000..cdf530a --- /dev/null +++ b/huagaotwain/twain/twpp/deviceevent.hpp @@ -0,0 +1,251 @@ +/* + +The MIT License (MIT) + +Copyright (c) 2015 Martin Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef TWPP_DETAIL_FILE_DEVICEEVENT_HPP +#define TWPP_DETAIL_FILE_DEVICEEVENT_HPP + +#include "../twpp.hpp" + +namespace Twpp { + +TWPP_DETAIL_PACK_BEGIN +/// Information about event sent by source. +class DeviceEvent { + +public: + /// Event type. + enum class Type : UInt16 { // Capability->UInt16, DeviceEvent->UInt32 + CheckAutomaticCapture = 0, + CheckBattery = 1, + CheckDeviceOnline = 2, + CheckFlash = 3, + CheckPowerSupply = 4, + CheckResolution = 5, + DeviceAdded = 6, + DeviceOffline = 7, + DeviceReady = 8, + DeviceRemoved = 9, + ImageCaptured = 10, + ImageDeleted = 11, + PaperDoubleFeed = 12, + PaperJam = 13, + LampFailure = 14, + PowerSave = 15, + PowerSaveNotify = 16, + CustomEvents = 0x8000 + }; + + /// Creates event with only type and device name set. + static constexpr DeviceEvent simple(Type type, const Str255& deviceName) noexcept; + + /// Creates event for checking battery. + static constexpr DeviceEvent checkBattery( + const Str255& deviceName, + UInt32 batteryMinutes, + Int16 batteryPercentage + ) noexcept; + + /// Creates event for checking power supply. + static constexpr DeviceEvent checkPowerSupply( + const Str255& deviceName, + PowerSupply powerSupply + ) noexcept; + + /// Creates event for checking resolution. + static constexpr DeviceEvent checkResolution( + const Str255& deviceName, + Fix32 xres, + Fix32 yres + ) noexcept; + + /// Creates event for checking flash settings. + static constexpr DeviceEvent checkFlash( + const Str255& deviceName, + Flash flash + ) noexcept; + + /// Creates event for checking number of images camera is going to capture. + static constexpr DeviceEvent checkAutomaticCapture( + const Str255& deviceName, + UInt32 autoCapture, + UInt32 timeBeforeFirstCapture, + UInt32 timeBetweenCaptures + ) noexcept; + + /// Creates uninitialized deice event. + constexpr DeviceEvent() noexcept : + m_type(static_cast(Type::CheckAutomaticCapture)), m_batteryMinutes(0), + m_batteryPercent(0), m_powerSupply(static_cast(PowerSupply::External)), + m_flashUsed(static_cast(Flash::None)), m_autoCapture(0), + m_timeBeforeFirstCapture(0), m_timeBetweenCaptures(0){} + + /// Event type. + constexpr Type type() const noexcept{ + return static_cast(m_type); + } + + /// Name of the device that sent the event. + constexpr const Str255& deviceName() const noexcept{ + return m_deviceName; + } + + /// Minutes of battery power remaining. + /// Valid only for Type::CheckBattery. + constexpr UInt32 batteryMinutes() const noexcept{ + return m_batteryMinutes; + } + + /// Percentage of battery power remaining. + /// Valid only for Type::CheckBattery. + constexpr Int16 batteryPercentage() const noexcept{ + return m_batteryPercent; + } + + /// Power supply in use. + /// Valid only for Type::CheckPowerSupply. + constexpr PowerSupply powerSupply() const noexcept{ + return static_cast(m_powerSupply); + } + + /// X resolution. + /// Valif only for Type::CheckResolution. + constexpr Fix32 xResolution() const noexcept{ + return m_xres; + } + + /// Y resolution. + /// Valid only for Type::CheckResolution. + constexpr Fix32 yResolution() const noexcept{ + return m_yres; + } + + /// Flash settings. + /// Valid only for Type::CheckFlash. + constexpr Flash flash() const noexcept{ + return static_cast(m_flashUsed); + } + + /// Number of images camera will capture. + /// Valid only for Type::CheckAutomaticCapture. + constexpr UInt32 automaticCapture() const noexcept{ + return m_autoCapture; + } + + /// Number of seconds before first capture. + /// Valid only for Type::CheckAutomaticCapture. + constexpr UInt32 timeBeforeFirstCapture() const noexcept{ + return m_timeBeforeFirstCapture; + } + + /// Number of 1/100-seconds between captures. + /// Valid only for Type::CheckAutomaticCapture. + constexpr UInt32 timeBetweenCaptures() const noexcept{ + return m_timeBetweenCaptures; + } + +private: + constexpr DeviceEvent( + Type type, + const Str255& deviceName, + UInt32 batteryMinutes, + Int16 batteryPercentage, + PowerSupply powerSupply, + Fix32 xres, + Fix32 yres, + Flash flash, + UInt32 autoCapture, + UInt32 tbfc, + UInt32 tbc + ) noexcept : + m_type(static_cast(type)), m_deviceName(deviceName), + m_batteryMinutes(batteryMinutes), m_batteryPercent(batteryPercentage), + m_powerSupply(static_cast(powerSupply)), m_xres(xres), m_yres(yres), + m_flashUsed(static_cast(flash)), m_autoCapture(autoCapture), + m_timeBeforeFirstCapture(tbfc), m_timeBetweenCaptures(tbc){} + + UInt32 m_type; + Str255 m_deviceName; + UInt32 m_batteryMinutes; + Int16 m_batteryPercent; + Int32 m_powerSupply; + Fix32 m_xres; + Fix32 m_yres; + UInt32 m_flashUsed; + UInt32 m_autoCapture; + UInt32 m_timeBeforeFirstCapture; + UInt32 m_timeBetweenCaptures; + +}; +TWPP_DETAIL_PACK_END + +// must be defined outside the class because of msvc2015 +constexpr inline DeviceEvent DeviceEvent::simple(Type type, const Str255& deviceName) noexcept{ + return DeviceEvent(type, deviceName, 0, 0, PowerSupply::External, Fix32(), Fix32(), Flash::None, 0, 0, 0); +} + +constexpr inline DeviceEvent DeviceEvent::checkBattery( + const Str255& deviceName, + UInt32 batteryMinutes, + Int16 batteryPercentage +) noexcept{ + return DeviceEvent(Type::CheckBattery, deviceName, batteryMinutes, batteryPercentage, PowerSupply::External, Fix32(), Fix32(), Flash::None, 0, 0, 0); +} + +constexpr inline DeviceEvent DeviceEvent::checkPowerSupply( + const Str255& deviceName, + PowerSupply powerSupply +) noexcept{ + return DeviceEvent(Type::CheckPowerSupply, deviceName, 0, 0, powerSupply, Fix32(), Fix32(), Flash::None, 0, 0, 0); +} + +constexpr inline DeviceEvent DeviceEvent::checkResolution( + const Str255& deviceName, + Fix32 xres, + Fix32 yres +) noexcept{ + return DeviceEvent(Type::CheckResolution, deviceName, 0, 0, PowerSupply::External, xres, yres, Flash::None, 0, 0, 0); +} + +constexpr inline DeviceEvent DeviceEvent::checkFlash( + const Str255& deviceName, + Flash flash +) noexcept{ + return DeviceEvent(Type::CheckFlash, deviceName, 0, 0, PowerSupply::External, Fix32(), Fix32(), flash, 0, 0, 0); +} + +constexpr inline DeviceEvent DeviceEvent::checkAutomaticCapture( + const Str255& deviceName, + UInt32 autoCapture, + UInt32 timeBeforeFirstCapture, + UInt32 timeBetweenCaptures +) noexcept{ + return DeviceEvent(Type::CheckAutomaticCapture, deviceName, 0, 0, PowerSupply::External, + Fix32(), Fix32(), Flash::None, autoCapture, timeBeforeFirstCapture, timeBetweenCaptures); +} + +} + +#endif // TWPP_DETAIL_FILE_DEVICEEVENT_HPP diff --git a/huagaotwain/twain/twpp/element8.hpp b/huagaotwain/twain/twpp/element8.hpp new file mode 100644 index 0000000..585d571 --- /dev/null +++ b/huagaotwain/twain/twpp/element8.hpp @@ -0,0 +1,118 @@ +/* + +The MIT License (MIT) + +Copyright (c) 2015 Martin Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef TWPP_DETAIL_FILE_ELEMENT8_HPP +#define TWPP_DETAIL_FILE_ELEMENT8_HPP + +#include "../twpp.hpp" + +namespace Twpp { + +TWPP_DETAIL_PACK_BEGIN +/// Element in a palette consisting of 3 parts (RGB, CMY, ...) +/// in the order of the type alphabetic representation. +class Element8 { + +public: + /// Creates zero-initialized element. + constexpr Element8() noexcept : + m_index(0), m_channel1(0), m_channel2(0), m_channel3(0){} + + /// Creates zero-initialized element with specified index. + explicit constexpr Element8(UInt8 index) noexcept : + m_index(index), m_channel1(0), m_channel2(0), m_channel3(0){} + + /// Creates element with set channels. + constexpr Element8( + UInt8 channel1, + UInt8 channel2, + UInt8 channel3 + ) noexcept : + m_index(0), m_channel1(channel1), m_channel2(channel2), + m_channel3(channel3){} + + /// Creates element with set channels at index. + constexpr Element8( + UInt8 index, + UInt8 channel1, + UInt8 channel2, + UInt8 channel3 + ) noexcept : + m_index(index), m_channel1(channel1), m_channel2(channel2), + m_channel3(channel3){} + + /// Index of the element in palette. + constexpr UInt8 index() const noexcept{ + return m_index; + } + + /// Sets index of the element in palette. + void setIndex(UInt8 index) noexcept{ + m_index = index; + } + + /// Channel 1 information. + constexpr UInt8 channel1() const noexcept{ + return m_channel1; + } + + /// Sets channel 1 information. + void setChannel1(UInt8 channel1) noexcept{ + m_channel1 = channel1; + } + + /// Channel 2 information. + constexpr UInt8 channel2() const noexcept{ + return m_channel2; + } + + /// Sets channel 2 information. + void setChannel2(UInt8 channel2) noexcept{ + m_channel2 = channel2; + } + + /// Channel 3 information. + constexpr UInt8 channel3() const noexcept{ + return m_channel3; + } + + /// Sets channel 3 information. + void setChannel3(UInt8 channel3) noexcept{ + m_channel3 = channel3; + } + +private: + UInt8 m_index; + UInt8 m_channel1; + UInt8 m_channel2; + UInt8 m_channel3; + +}; +TWPP_DETAIL_PACK_END + +} + +#endif // TWPP_DETAIL_FILE_ELEMENT8_HPP diff --git a/huagaotwain/twain/twpp/enums.hpp b/huagaotwain/twain/twpp/enums.hpp new file mode 100644 index 0000000..9a51b96 --- /dev/null +++ b/huagaotwain/twain/twpp/enums.hpp @@ -0,0 +1,1459 @@ +/* + +The MIT License (MIT) + +Copyright (c) 2015 Martin Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef TWPP_DETAIL_FILE_ENUMS_HPP +#define TWPP_DETAIL_FILE_ENUMS_HPP + +#include "../twpp.hpp" + +namespace Twpp { + +enum class Alarm : UInt16 { + General = 0, // aka TWAL_ALARM + FeederError = 1, + FeederWarning = 2, + BarCode = 3, + DoubleFeed = 4, + Jam = 5, + PatchCode = 6, + Power = 7, + Skew = 8 +}; + +/// Argument types. +enum class Dat : UInt16 { + Null = 0x0000, + Capability = 0x0001, + Event = 0x0002, + Identity = 0x0003, + Parent = 0x0004, + PendingXfers = 0x0005, + SetupMemXfer = 0x0006, + SetupFileXfer = 0x0007, + Status = 0x0008, + UserInterface = 0x0009, + XferGroup = 0x000a, + CustomData = 0x000c, + DeviceEvent = 0x000d, + FileSystem = 0x000e, + PassThrough = 0x000f, + Callback = 0x0010, + StatusUtf8 = 0x0011, + Callback2 = 0x0012, + ImageInfo = 0x0101, + ImageLayout = 0x0102, + ImageMemXfer = 0x0103, + ImageNativeXfer = 0x0104, + ImageFileXfer = 0x0105, + CieColor = 0x0106, + GrayResponse = 0x0107, + RgbResponse = 0x0108, + JpegCompression = 0x0109, + Palette8 = 0x010a, + ExtImageInfo = 0x010b, + Filter = 0x010c, + AudioFileXfer = 0x0201, + AudioInfo = 0x0202, + AudioNativeXfer = 0x0203, + IccProfile = 0x0401, + ImageMemFileXfer = 0x0402, + EntryPoint = 0x0403, + + CustomBase = 0x8000 +}; + +/// Values of CapType::IAutoSize. +enum class AutoSize : UInt16 { + None = 0, + Auto = 1, + Current = 2 +}; + +/// Values of CapType::ISupportedBarcodeTypes. +enum class BarCodeType : UInt16 { + ThreeOfNine = 0, + ThreeOfFiveInterleaved = 1, + ThreeOfFiveNonInterleaved = 2, + Code93 = 3, + Code128 = 4, + Ucc128 = 5, + CodaBar = 6, + Upca = 7, + Upce = 8, + Ean8 = 9, + Ean13 = 10, + Postnet = 11, + Pdf417 = 12, + TwoOfFiveIndustrial = 13, + TwoOfFiveMatrix = 14, + TwoOfFiveDatalogic = 15, + TwoOfFiveIata = 16, + ThreeOfNineFullAscii = 17, + CodaBarWithStartStop = 18, + MaxiCode = 19, + QrCode = 20 +}; + +/// Values of CapType::IBitDepthReduction. +enum class BitDepthReduction : UInt16 { + Threshold = 0, + HalfTone = 1, + CustHalfTone = 2, + Diffusion = 3, + DynamicThreshold = 4 +}; + +/// Values of CapType::IBitOrder. +enum class BitOrder : UInt16 { + LsbFirst = 0, + MsbFirst = 1 +}; + +/// Values of CapType::CameraSide. +enum class CameraSide : UInt16 { + Both = 0, + Top = 1, + Bottom = 2 +}; + +enum class ConditionCode : UInt16 { + Success = 0, + Bummer = 1, + LowMemory = 2, + NoDs = 3, + MaxConnections = 4, + OperationError = 5, + BadCap = 6, + BadProtocol = 9, + BadValue = 10, + SeqError = 11, + BadDest = 12, + CapUnsupported = 13, + CapBadOperation = 14, + CapSeqError = 15, + Denied = 16, + FileExists = 17, + FileNotFound = 18, + NotEmpty = 19, + PaperJam = 20, + PaperDoubleFeed = 21, + FileWriteError = 22, + CheckDeviceOnline = 23, + InterLock = 24, + DamagedCorner = 25, + FocusError = 26, + DocTooLight = 27, + DocTooDark = 28, + NoMedia = 29, + + CustomBase = 0x8000 +}; + +typedef ConditionCode CC; + +static inline constexpr bool success(CC cc) noexcept{ + return cc == CC::Success; +} + +/// Capability container type. +enum class ConType : UInt16 { + Array = 3, + Enumeration = 4, + OneValue = 5, + Range = 6, + DontCare = 0xFFFF +}; + +/// Capability type. +enum class CapType : UInt16 { + XferCount = 0x0001, + ICompression = 0x0100, + IPixelType = 0x0101, + IUnits = 0x0102, + IXferMech = 0x0103, + Author = 0x1000, + Caption = 0x1001, + FeederEnabled = 0x1002, + FeederLoaded = 0x1003, + TimeDate = 0x1004, + SupportedCaps = 0x1005, + ExtendedCaps = 0x1006, + AutoFeed = 0x1007, + ClearPage = 0x1008, + FeedPage = 0x1009, + RewindPage = 0x100a, + Indicators = 0x100b, + PaperDetectable = 0x100d, + UiControllable = 0x100e, + DeviceOnline = 0x100f, + AutoScan = 0x1010, + ThumbnailsEnabled = 0x1011, + Duplex = 0x1012, + DuplexEnabled = 0x1013, + EnableDsUiOnly = 0x1014, + CustomDsData = 0x1015, + Endorser = 0x1016, + JobControl = 0x1017, + Alarms = 0x1018, + AlarmVolume = 0x1019, + AutomaticCapture = 0x101a, + TimeBeforeFirstCapture = 0x101b, + TimeBetweenCaptures = 0x101c, + ClearBuffers = 0x101d, + MaxBatchBuffers = 0x101e, + DeviceTimeDate = 0x101f, + PowerSupply = 0x1020, + CameraPreviewUi = 0x1021, + DeviceEvent = 0x1022, + SerialNumber = 0x1024, + Printer = 0x1026, + PrinterEnabled = 0x1027, + PrinterIndex = 0x1028, + PrinterMode = 0x1029, + PrinterString = 0x102a, + PrinterSuffix = 0x102b, + Language = 0x102c, + FeederAlignment = 0x102d, + FeederOrder = 0x102e, + ReacquireAllowed = 0x1030, + BatteryMinutes = 0x1032, + BatteryPercentage = 0x1033, + CameraSide = 0x1034, + Segmented = 0x1035, + CameraEnabled = 0x1036, + CameraOrder = 0x1037, + MicrEnabled = 0x1038, + FeederPrep = 0x1039, + FeederPocket = 0x103a, + AutomaticSenseMedium = 0x103b, + CustomInterfaceGuid = 0x103c, + SupportedCapsSegmentUnique = 0x103d, + SupportedDats = 0x103e, + DoubleFeedDetection = 0x103f, + DoubleFeedDetectionLength = 0x1040, + DoubleFeedDetectionSensitivity = 0x1041, + DoubleFeedDetectionResponse = 0x1042, + PaperHandling = 0x1043, + IndicatorsMode = 0x1044, + PrinterVerticalOffset = 0x1045, + PowerSaveTime = 0x1046, + PrinterCharRotation = 0x1047, + PrinterFontStyle = 0x1048, + PrinterIndexLeadChar = 0x1049, + PrinterIndexMaxValue = 0x104A, + PrinterIndexNumDigits = 0x104B, + PrinterIndexStep = 0x104C, + PrinterIndexTrigger = 0x104D, + PrinterStringPreview = 0x104E, + IAutoBright = 0x1100, + IBrightness = 0x1101, + IContrast = 0x1103, + ICustHalfTone = 0x1104, + IExposureTime = 0x1105, + IFilter = 0x1106, + IFlashUsed = 0x1107, + IGamma = 0x1108, + IHalfTones = 0x1109, + IHighLight = 0x110a, + IImageFileFormat = 0x110c, + ILampState = 0x110d, + ILightSource = 0x110e, + IOrientation = 0x1110, + IPhysicalWidth = 0x1111, + IPhysicalHeight = 0x1112, + IShadow = 0x1113, + IFrames = 0x1114, + IXNativeResolution = 0x1116, + IYNativeResolution = 0x1117, + IXResolution = 0x1118, + IYResolution = 0x1119, + IMaxFrames = 0x111a, + ITiles = 0x111b, + IBitOrder = 0x111c, + ICcittKFactor = 0x111d, + ILightPath = 0x111e, + IPixelFlavor = 0x111f, + IPlanarChunky = 0x1120, + IRotation = 0x1121, + ISupportedSizes = 0x1122, + IThreshold = 0x1123, + IXScaling = 0x1124, + IYScaling = 0x1125, + IBitOrderCodes = 0x1126, + IPixelFlavorCodes = 0x1127, + IJpegPixelType = 0x1128, + ITimeFill = 0x112a, + IBitDepth = 0x112b, + IBitDepthReduction = 0x112c, + IUndefinedImageSize = 0x112d, + IImageDataSet = 0x112e, + IExtImageInfo = 0x112f, + IMinimumHeight = 0x1130, + IMinimumWidth = 0x1131, + IAutoDiscardBlankPages = 0x1134, + IFlipRotation = 0x1136, + IBarCodeDetectionEnabled = 0x1137, + ISupportedBarCodeTypes = 0x1138, + IBarCodeMaxSearchPriorities = 0x1139, + IBarCodeSearchPriorities = 0x113a, + IBarCodeSearchMode = 0x113b, + IBarCodeMaxRetries = 0x113c, + IBarCodeTimeOut = 0x113d, + IZoomFactor = 0x113e, + IPatchCodeDetectionEnabled = 0x113f, + ISupportedPatchCodeTypes = 0x1140, + IPatchCodeMaxSearchPriorities = 0x1141, + IPatchCodeSearchPriorities = 0x1142, + IPatchCodeSearchMode = 0x1143, + IPatchCodeMaxRetries = 0x1144, + IPatchCodeTimeOut = 0x1145, + IFlashUsed2 = 0x1146, + IImageFilter = 0x1147, + INoiseFilter = 0x1148, + IOverScan = 0x1149, + IAutomaticBorderDetection = 0x1150, + IAutomaticDeskew = 0x1151, + IAutomaticRotate = 0x1152, + IJpegQuality = 0x1153, + IFeederType = 0x1154, + IIccProfile = 0x1155, + IAutoSize = 0x1156, + IAutomaticCropUsesFrame = 0x1157, + IAutomaticLengthDetection = 0x1158, + IAutomaticColorEnabled = 0x1159, + IAutomaticColorNonColorPixelType = 0x115a, + IColorManagementEnabled = 0x115b, + IImageMerge = 0x115c, + IImageMergeHeightThreshold = 0x115d, + ISupportedExtImageInfo = 0x115e, + IFilmType = 0x115f, + IMirror = 0x1160, + IJpegSubSampling = 0x1161, + AXferMech = 0x1202, + CustomBase = 0x8000 +}; + +/// Values of CapType::ClearBuffers. +enum class ClearBuffers : UInt16 { + Auto = 0, + Clear = 1, + NoClear = 2 +}; + +/// Values of CapType::IPlanarChunky. +enum class ColorFormat : UInt16 { + Chunky = 0, + Planar = 1 +}; + +typedef ColorFormat PlanarChunky; + +/// Values of CapType::ICompression. +/// Also used in ImageInfo and ImageMemXfer. +enum class Compression : UInt16 { + None = 0, + PackBits = 1, + Group31D = 2, + Group31DEol = 3, + Group32D = 4, + Group4 = 5, + Jpeg = 6, + Lzw = 7, + JBig = 8, + Png = 9, + Rle4 = 10, + Rle8 = 11, + BitFields = 12, + Ziz = 13, + Jpeg2000 = 14, + DontCare = 0xFFFF +}; + +/// Countries for Version. +enum class Country : UInt16 { + Afghanistan = 1001, + Algeria = 213, + AmericanSamoa = 684, + Andorra = 033, + Angola = 1002, + Anguilla = 8090, + Antigua = 8091, + Argentina = 54, + Aruba = 297, + Ascensioni = 247, + Australia = 61, + Austria = 43, + Bahamas = 8092, + Bahrain = 973, + Bangladesh = 880, + Barbados = 8093, + Belgium = 32, + Belize = 501, + Benin = 229, + Bermuda = 8094, + Bhutan = 1003, + Bolivia = 591, + Botswana = 267, + Britain = 6, + BritVirginIs = 8095, + Brazil = 55, + Brunei = 673, + Bulgaria = 359, + BurkinaFaso = 1004, + Burma = 1005, + Burundi = 1006, + Camaroon = 237, + Canada = 2, + CapeVerdeIs = 238, + CaymanIs = 8096, + CentralAfRep = 1007, + Chad = 1008, + Chile = 56, + China = 86, + ChristmasIs = 1009, + CocosIs = 1009, + Colombia = 57, + Comoros = 1010, + Congo = 1011, + CookIs = 1012, + Costarica = 506, + Cuba = 005, + Cyprus = 357, + Czechoslovakia = 42, + Denmark = 45, + Djibouti = 1013, + Dominica = 8097, + DomincanRep = 8098, + EasterIs = 1014, + Ecuador = 593, + Egypt = 20, + ElSalvador = 503, + EqGuinea = 1015, + Ethiopia = 251, + FalklandIs = 1016, + FaeroeIs = 298, + FijiIslands = 679, + Finland = 358, + France = 33, + FrAntilles = 596, + FrGuiana = 594, + FrPolyneisa = 689, + FutanaIs = 1043, + Gabon = 241, + Gambia = 220, + Germany = 49, + Ghana = 233, + Gibralter = 350, + Greece = 30, + Greenland = 299, + Grenada = 8099, + Grenedines = 8015, + Guadeloupe = 590, + Guam = 671, + GuantanamoBay = 5399, + Guatemala = 502, + Guinea = 224, + GuineaBissau = 1017, + Guyana = 592, + Haiti = 509, + Honduras = 504, + HongKong = 852, + Hungary = 36, + Iceland = 354, + India = 91, + Indonesia = 62, + Iran = 98, + Iraq = 964, + Ireland = 353, + Israel = 972, + Italy = 39, + IvoryCoast = 225, + Jamaica = 8010, + Japan = 81, + Jordan = 962, + Kenya = 254, + Kiribati = 1018, + Korea = 82, + Kuwait = 965, + Laos = 1019, + Lebanon = 1020, + Liberia = 231, + Libya = 218, + Liechtenstein = 41, + Luxenbourg = 352, + Macao = 853, + Madagascar = 1021, + Malawi = 265, + Malaysia = 60, + Maldives = 960, + Mali = 1022, + Malta = 356, + MarshallIs = 692, + Mauritania = 1023, + Mauritius = 230, + Mexico = 3, + Micronesia = 691, + Miquelon = 508, + Monaco = 33, + Mongolia = 1024, + Montserrat = 8011, + Morocco = 212, + Mozambique = 1025, + Namibia = 264, + Nauru = 1026, + Nepal = 977, + Netherlands = 31, + NethAntilles = 599, + Nevis = 8012, + NewCaledonia = 687, + NewZealand = 64, + Nicaragua = 505, + Niger = 227, + Nigeria = 234, + Niue = 1027, + Norfolki = 1028, + Norway = 47, + Oman = 968, + Pakistan = 92, + Palau = 1029, + Panama = 507, + Paraguay = 595, + Peru = 51, + Phillippines = 63, + PitcairnIs = 1030, + PNewGuinea = 675, + Poland = 48, + Portugal = 351, + Qatar = 974, + Reunioni = 1031, + Romania = 40, + Rwanda = 250, + Saipan = 670, + SanMarino = 39, + SaoTome = 1033, + SaudiArabia = 966, + Senegal = 221, + Seychellesis = 1034, + SierraLeone = 1035, + Singapore = 65, + SolomonIs = 1036, + Somali = 1037, + SouthAfrica = 27, + Spain = 34, + SriLanka = 94, + StHelena = 1032, + StKitts = 8013, + StLucia = 8014, + StPierre = 508, + StVincent = 8015, + Sudan = 1038, + Suriname = 597, + Swaziland = 268, + Sweden = 46, + Switzerland = 41, + Syria = 1039, + Taiwan = 886, + Tanzania = 255, + Thailand = 66, + Tobago = 8016, + Togo = 228, + Tongais = 676, + Trinidad = 8016, + Tunisia = 216, + Turkey = 90, + TurksCaicos = 8017, + Tuvalu = 1040, + Uganda = 256, + Ussr = 7, + UaEmirates = 971, + UnitedKingdom = 44, + Usa = 1, + Uruguay = 598, + Vanuatu = 1041, + VaticanCity = 39, + Venezuela = 58, + Wake = 1042, + WallisIs = 1043, + WesternSahara = 1044, + WesternSamoa = 1045, + Yemen = 1046, + Yugoslavia = 38, + Zaire = 243, + Zambia = 260, + Zimbabwe = 263, + Albania = 355, + Armenia = 374, + Azerbaijan = 994, + Belarus = 375, + BosniaHerzgo = 387, + Cambodia = 855, + Croatia = 385, + CzechRepublic = 420, + DiegoGarcia = 246, + Eritrea = 291, + Estonia = 372, + Georgia = 995, + Latvia = 371, + Lesotho = 266, + Lithuania = 370, + Macedonia = 389, + MayotteIs = 269, + Moldova = 373, + Myanmar = 95, + NorthKorea = 850, + Puertorico = 787, + Russia = 7, + Serbia = 381, + Slovakia = 421, + Slovenia = 386, + SouthKorea = 82, + Ukraine = 380, + UsVirginIs = 340, + Vietnam = 84 +}; + +/// Data group for distinguishing different categories of TWAIN operations. +enum class DataGroup : UInt32 { + Control = 0x0001L, + Image = 0x0002L, + Audio = 0x0004L +}; + +typedef DataGroup DG; + +static constexpr inline UInt32 operator~(DataGroup g) noexcept{ + return ~static_cast(g); +} + +static constexpr inline UInt32 operator|(DataGroup a, DataGroup b) noexcept{ + return static_cast(a) | static_cast(b); +} + +static constexpr inline UInt32 operator|(DataGroup a, UInt32 b) noexcept{ + return static_cast(a) | b; +} + +static constexpr inline UInt32 operator&(DataGroup a, DataGroup b) noexcept{ + return static_cast(a) & static_cast(b); +} + +static constexpr inline UInt32 operator&(UInt32 a, DataGroup b) noexcept{ + return static_cast(a) & b; +} + + +/// Values of CapType::IAutoDiscardBlankPages. +enum class DiscardBlankPages : Int32 { + Disabled = -2, + Auto = -1 +}; + +static constexpr inline DiscardBlankPages discardBytes(Int32 value) noexcept{ + return static_cast(value); +} + +/// Values of CapType::DoubleFeedDetection. +enum class DoubleFeedDetection : UInt16 { + Ultrasonic = 0, + ByLength = 1, + Infrared = 2, +}; + +/// Values of CapType::DoubleFeedDetectionResponse. +enum class DoubleFeedResponse : UInt16 { + Stop = 0, + StopAndWait = 1, + Sound = 2, + DoNotImprint = 3 +}; + +/// Values of CapType::DoubleFeedDetectionSensitivity. +enum class DoubleFeedSensitivity : UInt16 { + Low = 0, + Medium = 1, + High = 2 +}; + +/// Values of CapType::Duplex. +enum class Duplex : UInt16 { + None = 0, + OnePass = 1, + TwoPass = 2 +}; + +/// Values for CapType::FeederAlignment. +enum class FeederAlignment : UInt16 { + None = 0, + Left = 1, + Center = 2, + Right = 3 +}; + +/// Values for CapType::FeederOrder. +enum class FeederOrder : UInt16 { + FirstPageFirst = 0, + LastPageFirst = 1 +}; + + +/// Values for CapType::FeederPocket. +enum class FeederPocket : UInt16 { + PError = 0, + P1 = 1, + P2 = 2, + P3 = 3, + P4 = 4, + P5 = 5, + P6 = 6, + P7 = 7, + P8 = 8, + P9 = 9, + P10 = 10, + P11 = 11, + P12 = 12, + P13 = 13, + P14 = 14, + P15 = 15, + P16 = 16 +}; + +/// Values for CapType::IFeederType. +enum class FeederType : UInt16 { + General = 0, + Photo = 1, +}; + +/// Values for CapType::IFilmType. +enum class FilmType : UInt16 { + Positive = 0, + Negative = 1 +}; + +/// Values for CapType::IFilter. +enum class Filter : UInt16 { + Red = 0, + Green = 1, + Blue = 2, + None = 3, + White = 4, + Cyan = 5, + Magenta = 6, + Yellow = 7, + Black = 8 +}; + +/// Values for CapType::IFlashUsed2 and DeviceEvent.flash. +enum class Flash : UInt16 { // Capability->UInt16, DeviceEvent->UInt32 + None = 0, + Off = 1, + On = 2, + Auto = 3, + RedEye = 4 +}; + +/// Values for CapType::IFlipRotation. +enum class FlipRotation : UInt16 { + Book = 0, + Fanfold = 1 +}; + +/// Values for CapType::PrinterFontStyle +enum class FontStyle : UInt16 { + Normal = 0, + Bold = 1, + Italic = 2, + LargeSize = 3, + SmallSize = 4 +}; + +/// Values for CapType::IIccProfile. +enum class IccProfile : UInt16 { + None = 0, + Link = 1, + Embed = 2 +}; + +/// Values for CapType::IImageFileFormat. +enum class ImageFileFormat : UInt16 { + Tiff = 0, + Pict = 1, + Bmp = 2, + Xbm = 3, + Jfif = 4, + Fpx = 5, + TiffMulti = 6, + Png = 7, + Spiff = 8, + Exif = 9, + Pdf = 10, + Jp2 = 11, + Jpx = 13, + Dejavu = 14, + PdfA = 15, + PdfA2 = 16 +}; + +/// Values for CapType::IImageFilter. +enum class ImageFilter : UInt16 { + None = 0, + Auto = 1, + LowPass = 2, + BandPass = 3, + HighPass = 4, + Text = 3, + FineLine = 4 +}; + +/// Values of CapType::IImageMerge. +enum class ImageMerge : UInt16 { + None = 0, + FrontOnTop = 1, + FrontOnBottom = 2, + FrontOnLeft = 3, + FrontOnRight = 4 +}; + +/// Values of CapType::PrinterIndexTrigger. +enum class IndexTrigger : UInt16 { + Page = 0, + Patch1 = 1, + Patch2 = 2, + Patch3 = 3, + Patch4 = 4, + PatchT = 5, + Patch6 = 6 +}; + +/// Values of CapType::IndicatorsMode. +enum class IndicatorsMode : UInt16 { + Info = 0, + Warning = 1, + Error = 2, + Warmup = 3 +}; + +/// Values of CapType::JobControl. +enum class JobControl : UInt16 { + None = 0, + InclSepContScan = 1, + InclSepStopScan = 2, + ExclSepContScan = 3, + ExclSepStopScap = 4 +}; + +/// Values of CapType::IJpegQuality. +enum class JpegQuality : Int16 { + Unknown = -4, + Low = -3, + Medium = -2, + High = -1 +}; + +static constexpr inline JpegQuality jpegQuality(Int16 value) noexcept{ + return static_cast(value); +} + + +/// Values of CapType::IJpegSubSampling. +enum class JpegSubSampling : UInt16 { + Jp444Ycbcr = 0, + Jp444Rgb = 1, + Jp422 = 2, + Jp421 = 3, + Jp411 = 4, + Jp420 = 5, + Jp410 = 6, + Jp311 = 7 +}; + +/// Values of CapType::Language and Version structure. +enum class Language : UInt16 { + UserLocale = 0xFFFF, + Afrikaans = 14, + Albania = 15, + Arabic = 16, + ArabicAlgeria = 17, + ArabicBahrain = 18, + ArabicEgypt = 19, + ArabicIraq = 20, + ArabicJordan = 21, + ArabicKuwait = 22, + ArabicLebanon = 23, + ArabicLibya = 24, + ArabicMorocco = 25, + ArabicOman = 26, + ArabicQatar = 27, + ArabicSaudiArabia = 28, + ArabicSyria = 29, + ArabicTunisia = 30, + ArabicUae = 31, + ArabicYemen = 32, + Basque = 33, + ByeloRussian = 34, + Bulgarian = 35, + Catalan = 36, + Chinese = 37, + ChineseHongKong = 38, + ChinesePrc = 39, + ChineseSingapore = 40, + ChineseSimplified = 41, + ChineseTaiwan = 42, + ChineseTraditional = 43, + Croatia = 44, + Czech = 45, + Danish = 0, + Dutch = 1, + DutchBelgian = 46, + English = 2, + EnglishAustralian = 47, + EnglishCanadian = 48, + EnglishIreland = 49, + EnglishNewZealand = 50, + EnglishSouthAfrica = 51, + EnglishUk = 52, + EnglishUsa = 13, + Estonian = 53, + Faeroese = 54, + Farsi = 55, + Finnish = 4, + French = 5, + FrenchBelgian = 56, + FrenchCanadian = 3, + FrenchLuxembourg = 57, + FrenchSwiss = 58, + German = 6, + GermanAustrian = 59, + GermanLuxembourg = 60, + GermanLiechtenstein = 61, + GermanSwiss = 62, + Greek = 63, + Hebrew = 64, + Hungarian = 65, + Icelandic = 7, + Indonesian = 66, + Italian = 8, + ItalianSwiss = 67, + Japanese = 68, + Korean = 69, + KoreanJohab = 70, + Latvian = 71, + Lithuanian = 72, + Norwegian = 9, + NorwegianBokmal = 73, + NorwegianNynorsk = 74, + Polish = 75, + Portuguese = 10, + PortugueseBrazil = 76, + Romanian = 77, + Russian = 78, + SerbianLatin = 79, + Slovak = 80, + Slovenian = 81, + Spanish = 11, + SpanishMexican = 82, + SpanishModern = 83, + Swedish = 12, + Thai = 84, + Turkish = 85, + Ukranian = 86, + Assamese = 87, + Bengali = 88, + Bihari = 89, + Bodo = 90, + Dogri = 91, + Gujarati = 92, + Haryanvi = 93, + Hindi = 94, + Kannada = 95, + Kashmiri = 96, + Malayalam = 97, + Marathi = 98, + Marwari = 99, + Meghalayan = 100, + Mizo = 101, + Naga = 102, + Orissi = 103, + Punjabi = 104, + Pushtu = 105, + SerbianCyrillic = 106, + Sikkimi = 107, + SwedishFinland = 108, + Tamil = 109, + Telugu = 110, + Tripuri = 111, + Urdu = 112, + Vietnamese = 113 +}; + +/// Values of CapType::ILightPath. +enum class LightPath : UInt16 { + Reflective = 0, + Transmissive = 1 +}; + +/// Values of CapType::ILightSource. +enum class LightSource : UInt16 { + Red = 0, + Green = 1, + Blue = 2, + None = 3, + White = 4, + Uv = 5, + Ir = 6 +}; + +/// Values for CapType::IMirror. +enum class Mirror : UInt16 { + None = 0, + Vertical = 1, + Horizontal = 2 +}; + +/// Values of possible actions of TWAIN operations. +enum class Msg : UInt16 { + Null = 0x0000, + Get = 0x0001, + GetCurrent = 0x0002, + GetDefault = 0x0003, + GetFirst = 0x0004, + GetNext = 0x0005, + Set = 0x0006, + Reset = 0x0007, + QuerySupport = 0x0008, + GetHelp = 0x0009, + GetLabel = 0x000a, + GetLabelEnum = 0x000b, + SetConstraint = 0x000c, + XferReady = 0x0101, + CloseDsReq = 0x0102, + CloseDsOk = 0x0103, + DeviceEvent = 0x0104, + OpenDsm = 0x0301, + CloseDsm = 0x0302, + OpenDs = 0x0401, + CloseDs = 0x0402, + UserSelect = 0x0403, + DisableDs = 0x0501, + EnableDs = 0x0502, + EnableDsUiOnly = 0x0503, + ProcessEvent = 0x0601, + EndXfer = 0x0701, + StopFeeder = 0x0702, + ChangeDir = 0x0801, + CreateDir = 0x0802, + Delete = 0x0803, + FormatMedia = 0x0804, + GetClose = 0x0805, + GetFirstFile = 0x0806, + GetInfo = 0x0807, + GetNextFile = 0x0808, + Rename = 0x0809, + Copy = 0x080A, + AutomaticCaptureDir = 0x080B, + PassThrough = 0x0901, + RegisterCallback = 0x0902, + ResetAll = 0x0A01, + CustomBase = 0x8000 +}; + +/// Capability action support flags. +enum class MsgSupport : Int32 { + Get = 0x0001, + Set = 0x0002, + GetDefault = 0x0004, + GetCurrent = 0x0008, + Reset = 0x0010, + SetConstraint = 0x0020, + GetHelp = 0x0100, + GetLabel = 0x0200, + GetLabelEnum = 0x0400 +}; + +static inline constexpr MsgSupport operator|(MsgSupport a, MsgSupport b){ + return static_cast(static_cast(a) | static_cast(b)); +} + +static inline constexpr MsgSupport operator&(MsgSupport a, MsgSupport b){ + return static_cast(static_cast(a) & static_cast(b)); +} + +static inline constexpr MsgSupport operator^(MsgSupport a, MsgSupport b){ + return static_cast(static_cast(a) ^ static_cast(b)); +} + +/// Action support flags, nothing supported. +static constexpr const MsgSupport msgSupportEmpty = static_cast(0); + +/// Action support flags, all `get` actions. +static constexpr const MsgSupport msgSupportGetAll = MsgSupport::Get | MsgSupport::GetDefault | MsgSupport::GetCurrent; + +/// Action support flags, all `get` actions, `set` and `reset`. +static constexpr const MsgSupport msgSupportGetAllSetReset = msgSupportGetAll | MsgSupport::Set | MsgSupport::Reset; + +/// Values for CapType::INoiseFilter. +enum class NoiseFilter : UInt16 { + None = 0, + Auto = 1, + LonePixel = 2, + MajorityRule = 3 +}; + +/// Values for CapType::IOrientation. +enum class Orientation : UInt16 { + Rot0 = 0, + Rot90 = 1, + Rot180 = 2, + Rot270 = 3, + Portrait = 0, + Landscape = 3, + Auto = 4, + AutoText = 5, + AutoPicture = 6 +}; + +/// Values for CapType::IOverscan. +enum class OverScan : UInt16 { + None = 0, + Auto = 1, + TopBottom = 2, + LeftRight = 3, + All = 4 +}; + +/// Values for CapType::PaperHandling. +enum class PaperHandling : UInt16 { + Normal = 0, + Fragile = 1, + Thick = 2, + TriFold = 3, + Photograph = 4 +}; + +/// Values for CapType::ISupportedSizes. +enum class PaperSize : UInt16 { + None = 0, + A4 = 1, + JisB5 = 2, + UsLetter = 3, + UsLegal = 4, + A5 = 5, + IsoB4 = 6, + IsoB6 = 7, + UsLedger = 9, + UsExecutive = 10, + A3 = 11, + IsoB3 = 12, + A6 = 13, + C4 = 14, + C5 = 15, + C6 = 16, + Ps4A0 = 17, // 4A0 + Ps2A0 = 18, // 2A0 + A0 = 19, + A1 = 20, + A2 = 21, + A7 = 22, + A8 = 23, + A9 = 24, + A10 = 25, + IsoB0 = 26, + IsoB1 = 27, + IsoB2 = 28, + IsoB5 = 29, + IsoB7 = 30, + IsoB8 = 31, + IsoB9 = 32, + IsoB10 = 33, + JisB0 = 34, + JisB1 = 35, + JisB2 = 36, + JisB3 = 37, + JisB4 = 38, + JisB6 = 39, + JisB7 = 40, + JisB8 = 41, + JisB9 = 42, + JisB10 = 43, + C0 = 44, + C1 = 45, + C2 = 46, + C3 = 47, + C7 = 48, + C8 = 49, + C9 = 50, + C10 = 51, + UsStatement = 52, + BusinessCard = 53, + MaxSize = 54 +}; + +/// Values for CapType::IPixelFlavor, CapType::IPixelFlavorCodes, InfoId::PixelFlavor. +/// Chocolate - pixel represents darkest data. +/// Vanilla - pixel represents lightest data. +enum class PixelFlavor : UInt16 { + Chocolate = 0, + Vanilla = 1 +}; + +/// Values for CapType::IPixelType, ImageInfo. +enum class PixelType : UInt16 { + BlackWhite = 0, + Gray = 1, + Rgb = 2, + Palette = 3, + Cmy = 4, + Cmyk = 5, + Yuv = 6, + Yuvk = 7, + CieXyz = 8, + Lab = 9, + SRgb = 10, + ScRgb = 11, + Infrared = 16 +}; + +/// Values for CapType::PowerSupply. +enum class PowerSupply : UInt16 { // Capability->UInt16, DeviceEvent->Int32 + External = 0, + Battery = 1, +}; + +/// Values for CapType::Printer. +enum class Printer : UInt16 { + ImprinterTopBefore = 0, + ImprinterTopAfter = 1, + ImprinterBottomBefore = 2, + ImprinterBottomAfter = 3, + EndorserTopBefore = 4, + EndorserTopAfter = 5, + EndorserBottomBefore = 6, + EndorserBottomAfter = 7 +}; + +/// Values for CapType::PrinterMode. +enum class PrinterMode : UInt16 { + SingleString = 0, + MultiString = 1, + CompoundString = 2 +}; + +enum class ReturnCode : UInt16 { + Success = 0, + Failure = 1, + CheckStatus = 2, + Cancel = 3, + DsEvent = 4, + NotDsEvent = 5, + XferDone = 6, + EndOfList = 7, + InfoNotSupported = 8, + DataNotAvailable = 9, + Busy = 10, + ScannerLocked = 11, + + CustomBase = 0x8000 +}; + +typedef ReturnCode RC; + +static inline constexpr bool success(ReturnCode rc) noexcept{ + return rc == RC::Success; +} + + +/// Values for CapType::IBarCodeSearchMode. +enum class SearchMode : UInt16 { + Horizontal = 0, + Vertical = 1, + HorizVert = 2, + VertHoriz = 3 +}; + +/// Values for CapType::Segmented. +enum class Segmented : UInt16 { + None = 0, + Auto = 1, + Manual = 2 +}; + +/// TWAIN manager states. +enum class DsmState : UInt16 { + PreSession = 1, + Loaded = 2, + Open = 3 +}; + +/// TWAIN source states. +enum class DsState : UInt16 { + Closed = 3, + Open = 4, + Enabled = 5, + XferReady = 6, + Xferring = 7 +}; + +/// Values for CapType::IUnits. +enum class Unit : UInt16 { + Inches = 0, + CentiMetres = 1, + Picas = 2, + Points = 3, + Twips = 4, + Pixels = 5, + MilliMetres = 6 +}; + +/// Values for CapType::IXferMech, CapType::AXferMech. +enum class XferMech : UInt16 { + Native = 0, + File = 1, + Memory = 2, + MemFile = 4, +}; + + +/// Type of the extended information. +enum class InfoId : UInt16 { + BarCodeX = 0x1200, + BarCodeY = 0x1201, + BarCodeText = 0x1202, + BarCodeType = 0x1203, + DeShadeTop = 0x1204, + DeShadeLeft = 0x1205, + DeShadeHeight = 0x1206, + DeShadeWidth = 0x1207, + DeShadeSize = 0x1208, + SpecklesRemoved = 0x1209, + HorzLineXCoord = 0x120A, + HorzLineYCoord = 0x120B, + HorzLineLength = 0x120C, + HorzLineThickness = 0x120D, + VertLineXCoord = 0x120E, + VertLineYCoord = 0x120F, + VertLineLength = 0x1210, + VertLineThickness = 0x1211, + PatchCode = 0x1212, + EndorsedText = 0x1213, + FormConfidence = 0x1214, + FormTemplateMatch = 0x1215, + FormTemplatePageMatch = 0x1216, + FormHorzDocOffset = 0x1217, + FormVertDocOffset = 0x1218, + BarCodeCount = 0x1219, + BarCodeConfidence = 0x121A, + BarCodeRotation = 0x121B, + BarCodeTextLength = 0x121C, + DeShadeCount = 0x121D, + DeShadeBlackCountOld = 0x121E, + DeShadeBlackCountNew = 0x121F, + DeShadeBlackRlMin = 0x1220, + DeShadeBlackRlMax = 0x1221, + DeShadeWhiteCountOld = 0x1222, + DeShadeWhiteCountNew = 0x1223, + DeShadeWhiteRlMin = 0x1224, + DeShadEWhiteRlAve = 0x1225, + DeShadeWhiteRlMax = 0x1226, + BlackSpecklesRemoved = 0x1227, + WhiteSpecklesRemoved = 0x1228, + HorzLineCount = 0x1229, + VertLineCount = 0x122A, + DeskewStatus = 0x122B, + SkewOriginalAngle = 0x122C, + SkewFinalAngle = 0x122D, + SkewConfidence = 0x122E, + SkewWindowX1 = 0x122F, + SkewWindowY1 = 0x1230, + SkewWindowX2 = 0x1231, + SkewWindowY2 = 0x1232, + SkewWindowX3 = 0x1233, + SkewWindowY3 = 0x1234, + SkewWindowX4 = 0x1235, + SkewWindowY4 = 0x1236, + BookName = 0x1238, + ChapterNumber = 0x1239, + DocumentNumber = 0x123A, + PageNumber = 0x123B, + Camera = 0x123C, + FrameNumber = 0x123D, + Frame = 0x123E, + PixelFlavor = 0x123F, + IccProfile = 0x1240, + LastSegment = 0x1241, + SegmentNumber = 0x1242, + MagData = 0x1243, + MagType = 0x1244, + PageSide = 0x1245, + FileSystemSource = 0x1246, + ImageMerged = 0x1247, + MagDataLength = 0x1248, + PaperCount = 0x1249, + PrinterText = 0x124A +}; + +/// Values for InfoId::BarCodeRotation. +enum class BarCodeRotation : UInt16 { + Rot0 = 0, + Rot90 = 1, + Rot180 = 2, + Rot270 = 3, + RotUnknown = 4 +}; + +/// Values for InfoId::PageSide. +enum class PageSide : UInt16 { + Top = 1, + Bottom = 2 +}; + +/// Values for InfoId::DeskewStatus. +enum class DeskewStatus : UInt16 { + Success = 0, + ReportOnly = 1, + Fail = 2, + Disabled = 3 +}; + +/// Values for InfoId::MagType. +enum class MagType : UInt16 { + Micr = 0, + Raw = 1, + Invalid = 2 +}; + +/// Values for InfoId::PatchCode. +enum class PatchCode : UInt16 { + P1 = 0, + P2 = 1, + P3 = 2, + P4 = 3, + P6 = 4, + PT = 5 +}; + +} + +#endif // TWPP_DETAIL_FILE_ENUMS_HPP + diff --git a/huagaotwain/twain/twpp/env.hpp b/huagaotwain/twain/twpp/env.hpp new file mode 100644 index 0000000..fae3d4b --- /dev/null +++ b/huagaotwain/twain/twpp/env.hpp @@ -0,0 +1,356 @@ +/* + +The MIT License (MIT) + +Copyright (c) 2015-2017 Martin Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef TWPP_DETAIL_FILE_ENV_HPP +#define TWPP_DETAIL_FILE_ENV_HPP + +// ============= +// Twpp specific + +namespace Twpp { + +namespace Detail { + +enum { + ProtoMajor = 2, + ProtoMinor = 3, + Dsm2 = 0x10000000L, + App2 = 0x20000000L, + Ds2 = 0x40000000L +}; + +} + +} + +#if defined(TWPP_IS_DS) +# define TWPP_DETAIL_IS_DS 1 +#else +# define TWPP_DETAIL_IS_DS 0 +#endif + + +// =========== +// OS specific + +// Windows +#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) +# define TWPP_DETAIL_OS_WIN 1 +# if defined(WIN64) || defined(_WIN64) +# define TWPP_DETAIL_OS_WIN64 1 +# else +# define TWPP_DETAIL_OS_WIN32 1 +# endif +# if !defined(WIN32_LEAN_AND_MEAN) +# define WIN32_LEAN_AND_MEAN +# endif +# if !defined(NOMINMAX) +# define NOMINMAX +# endif +extern "C" { +# include +} +# define TWPP_DETAIL_CALLSTYLE PASCAL +# define TWPP_DETAIL_EXPORT __declspec(dllexport) +namespace Twpp { + +namespace Detail { + +typedef HANDLE RawHandle; + + +namespace DsmLibOs { + +typedef HMODULE Handle; +static constexpr const Handle nullHandle = nullptr; + +template +static inline T resolve(Handle h) noexcept{ + return reinterpret_cast(::GetProcAddress(h, "DSM_Entry")); +} + +# if defined(TWPP_DETAIL_OS_WIN32) +static inline Handle load(bool old) noexcept{ + if (old){ + auto h = ::LoadLibraryA("TWAIN_32.dll"); + if (!h){ + h = ::LoadLibraryA("TWAINDSM.dll"); + } + + return h; + } else { + auto h = ::LoadLibraryA("TWAINDSM.dll"); + if (!h){ + h = ::LoadLibraryA("TWAIN_32.dll"); + } + + return h; + } +} +# else +static inline Handle load(bool) noexcept{ + return ::LoadLibraryA("TWAINDSM.dll"); +} +# endif + +static inline void unload(Handle h) noexcept{ + ::FreeLibrary(h); +} + +} // namespace DsmLibOs + +} // namespace Detail + +} // namespace Twpp + + +// Mac OS +#elif defined(__APPLE__) +# pragma message "No testing has been done on this platform, this framework might not work correctly." +# define TWPP_DETAIL_OS_MAC 1 +# include +extern "C" { +# include +# include +# include +# include +# include +} +# define TWPP_DETAIL_CALLSTYLE pascal +namespace Twpp { + +namespace Detail { + +typedef Handle RawHandle; + + +namespace DsmLibOs { + +typedef void* Handle; +static constexpr const Handle nullHandle = nullptr; + +template +static inline T resolve(Handle h) noexcept{ + return reinterpret_cast(::dlsym(h, "DSM_Entry")); +} + +static inline Handle load(bool) noexcept{ + return ::dlopen("/System/Library/Frameworks/TWAIN.framework/TWAIN", RTLD_LAZY); +} + +static inline void unload(Handle h) noexcept{ + ::dlclose(h); +} + +} // namespace DsmLibOs + +template +struct MacStatic { + + static const ::Class g_autoreleasePool; + static const ::SEL g_release; + static const ::SEL g_alloc; + static const ::SEL g_init; + + static const ::SEL g_nextEvent; + static const ::SEL g_postEvent; + static const ::SEL g_sendEvent; + static const ::id g_app; + static const ::id g_distantFuture; + + static const ::Class g_event; + static const ::SEL g_otherEventWithType; + +}; + +template const ::Class MacStatic::g_autoreleasePool = objc_getClass("NSAutoreleasePool"); +template const ::SEL MacStatic::g_release = sel_registerName("release"); +template const ::SEL MacStatic::g_alloc = sel_registerName("alloc"); +template const ::SEL MacStatic::g_init = sel_registerName("init"); + +template const ::SEL MacStatic::g_nextEvent = sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:"); +template const ::SEL MacStatic::g_postEvent = sel_registerName("postEvent:atStart:"); +template const ::SEL MacStatic::g_sendEvent = sel_registerName("sendEvent:"); +template const ::id MacStatic::g_app = objc_msgSend(reinterpret_cast<::id>(objc_getClass("NSApplication")), sel_registerName("sharedApplication")); +template const ::id MacStatic::g_distantFuture = objc_msgSend(reinterpret_cast<::id>(objc_getClass("NSDate")), sel_registerName("distantFuture")); + +template const ::Class MacStatic::g_event = objc_getClass("NSEvent"); +template const ::SEL MacStatic::g_otherEventWithType = sel_registerName("otherEventWithType:location:modifierFlags:timestamp:windowNumber:context:subtype:data1:data2:"); + +class NSAutoreleasePool { + +public: + NSAutoreleasePool() noexcept : + m_id(createPool()) {} + + ~NSAutoreleasePool(){ + release(); + } + + NSAutoreleasePool(const NSAutoreleasePool&) = delete; + NSAutoreleasePool& operator=(const NSAutoreleasePool&) = delete; + + NSAutoreleasePool(NSAutoreleasePool&& o) noexcept : + m_id(o.m_id){ + + o.m_id = nullptr; + } + + NSAutoreleasePool& operator=(NSAutoreleasePool&& o) noexcept{ + if (this != &o){ + release(); + std::swap(m_id, o.m_id); + } + + return *this; + } + + void release() noexcept{ + if (m_id != nullptr){ + objc_msgSend(m_id, MacStatic::g_release); + m_id = nullptr; + } + } + +private: + static ::id createPool() noexcept{ + auto poolId = objc_msgSend(reinterpret_cast<::id>(MacStatic::g_autoreleasePool), MacStatic::g_alloc); + return objc_msgSend(poolId, MacStatic::g_init); + } + + ::id m_id; + +}; + +namespace NSLoop { + +static constexpr ::NSUInteger NSAnyEventMask = std::numeric_limits<::NSUInteger>::max(); +static constexpr ::NSUInteger NSApplicationDefined = 15; + +static void processEvent() noexcept{ + auto event = objc_msgSend(MacStatic::g_app, MacStatic::g_nextEvent, NSAnyEventMask, MacStatic::g_distantFuture, kCFRunLoopDefaultMode, YES); + objc_msgSend(MacStatic::g_app, MacStatic::g_sendEvent, event); +} + +static void postDummy() noexcept{ + auto event = objc_msgSend(reinterpret_cast<::id>(MacStatic::g_event), MacStatic::g_otherEventWithType, NSApplicationDefined, nullptr, 1, 0.0, 0, nullptr, static_cast(0), 0, 0); + objc_msgSend(MacStatic::g_app, MacStatic::g_postEvent, event, NO); +} + +} // namespace NSLoop + +} // namespace Detail + +} // namespace Twpp + +// Linux +#elif defined(__linux__) +# warning "No testing has been done on this platform, this framework might not work correctly." +# define TWPP_DETAIL_OS_LINUX 1 +extern "C" { +# include +} +# define TWPP_DETAIL_CALLSTYLE +namespace Twpp { + +namespace Detail { + +typedef void* RawHandle; + + +namespace DsmLibOs { + +typedef void* Handle; +static constexpr const Handle nullHandle = nullptr; + +template +static inline T resolve(Handle h) noexcept{ + return reinterpret_cast(::dlsym(h, "DSM_Entry")); +} + +static inline Handle load(bool) noexcept{ + return ::dlopen("libtwaindsm.so", RTLD_LAZY); +} + +static inline void unload(Handle h) noexcept{ + ::dlclose(h); +} + +} // namespace DsmLibOs + +} // namespace Detail + +} // namespace Twpp + +// fail everything else +#else +# error "unsupported platform, supports only Windows, Mac OS and Linux" +#endif + + +// ================= +// compiler specific + +// MSVC +#if defined(_MSC_VER) +# define TWPP_DETAIL_PACK_BEGIN \ + __pragma(pack (push, beforeTwpp)) \ + __pragma(pack (2)) +# define TWPP_DETAIL_PACK_END __pragma(pack (pop, beforeTwpp)); + +// GNU or CLang +#elif defined(__GNUC__) || defined(__clang__) +# if defined(TWPP_DETAIL_OS_MAC) +# define TWPP_DETAIL_PACK_BEGIN _Pragma("options align = power") +# define TWPP_DETAIL_PACK_END _Pragma("options align = reset") +# else +# define TWPP_DETAIL_PACK_BEGIN \ + _Pragma("pack (push, beforeTwpp)") \ + _Pragma("pack (2)") +# define TWPP_DETAIL_PACK_END _Pragma("pack (pop, beforeTwpp)") +# endif +# if !defined(TWPP_DETAIL_EXPORT) +# define TWPP_DETAIL_EXPORT __attribute__((__visibility__("default"))) +# endif + +// Borland +#elif defined(__BORLAND__) || defined(__BORLANDC__) || defined(__CODEGEARC__) +# define TWPP_DETAIL_PACK_BEGIN _Pragma("option -a2") +# define TWPP_DETAIL_PACK_END _Pragma("option -a") + +// fail everything else +#else +# error "unsupported compiler, please define your own TWPP_DETAIL_PACK_BEGIN and TWPP_DETAIL_PACK_END and possibly TWPP_DETAIL_EXPORT in twpp/env.hpp and send me your patch" +#endif + + +#if (!defined(_MSC_VER) && __cplusplus < 201103L) || (defined(_MSC_VER) && _MSC_VER < 1900) // msvc2015 +# error "C++11 or later is required" +#endif + + +#endif // TWPP_DETAIL_FILE_ENV_HPP + diff --git a/huagaotwain/twain/twpp/event.hpp b/huagaotwain/twain/twpp/event.hpp new file mode 100644 index 0000000..1aff32d --- /dev/null +++ b/huagaotwain/twain/twpp/event.hpp @@ -0,0 +1,72 @@ +/* + +The MIT License (MIT) + +Copyright (c) 2015 Martin Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef TWPP_DETAIL_FILE_EVENT_HPP +#define TWPP_DETAIL_FILE_EVENT_HPP + +#include "../twpp.hpp" + +namespace Twpp { + +TWPP_DETAIL_PACK_BEGIN +/// Loop event on Windows. +/// Used while waiting for transfer. +/// See manual for more info. +class Event { + +public: + constexpr Event() noexcept : + m_event(nullptr), m_msg(Msg::Null){} + + constexpr Event(void* event, Msg msg) noexcept : + m_event(event), m_msg(msg){} + + constexpr void* event() const noexcept{ + return m_event; + } + + void setEvent(void* event) noexcept{ + m_event = event; + } + + constexpr Msg message() const noexcept{ + return m_msg; + } + + void setMessage(Msg msg) noexcept{ + m_msg = msg; + } + +private: + void* m_event; + Msg m_msg; + +}; +TWPP_DETAIL_PACK_END + +} + +#endif // TWPP_DETAIL_FILE_EVENT_HPP diff --git a/huagaotwain/twain/twpp/exception.hpp b/huagaotwain/twain/twpp/exception.hpp new file mode 100644 index 0000000..3aa34dc --- /dev/null +++ b/huagaotwain/twain/twpp/exception.hpp @@ -0,0 +1,42 @@ +#ifndef TWPP_DETAIL_FILE_EXCEPTION_HPP +#define TWPP_DETAIL_FILE_EXCEPTION_HPP + +#include "../twpp.hpp" + +namespace Twpp { + +/// Base class of TWPP exceptions. +class Exception : public std::exception { + +public: + virtual const char* what() const noexcept override{ + return "General TWPP error."; + } + +}; + +/// Invalid type exception. +/// Used when an invalid or unsupported type identifier is used. +class TypeException : public Exception { + +public: + virtual const char* what() const noexcept override{ + return "Invalid type."; + } + +}; + +/// Value out of valid range exception. +class RangeException : Exception { + +public: + virtual const char* what() const noexcept override{ + return "Value out of allowed range."; + } + +}; + +} + +#endif // TWPP_DETAIL_FILE_EXCEPTION_HPP + diff --git a/huagaotwain/twain/twpp/extimageinfo.hpp b/huagaotwain/twain/twpp/extimageinfo.hpp new file mode 100644 index 0000000..3fb452f --- /dev/null +++ b/huagaotwain/twain/twpp/extimageinfo.hpp @@ -0,0 +1,532 @@ +/* + +The MIT License (MIT) + +Copyright (c) 2015 Martin Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef TWPP_DETAIL_FILE_EXTIMAGEINFO_HPP +#define TWPP_DETAIL_FILE_EXTIMAGEINFO_HPP + +#include "../twpp.hpp" + +namespace Twpp { + +namespace Detail { + +/// Mapping of info type to type identifier and data type. +template struct Ext {}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef BarCodeRotation DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::Handle; typedef char DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef BarCodeType DataType;}; + +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; + +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; + +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; + +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; + +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef PatchCode DataType;}; + +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef DeskewStatus DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; + +template<> struct Ext {static constexpr const Type twty = Type::Str255; typedef Str255 DataType;}; + +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::Str255; typedef Str255 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; + +template<> struct Ext {static constexpr const Type twty = Type::Str255; typedef Str255 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::Str255; typedef Str255 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::Frame; typedef Frame DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt16; typedef PixelFlavor DataType;}; + +template<> struct Ext {static constexpr const Type twty = Type::Str255; typedef Str255 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::Bool; typedef Bool DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; + +template<> struct Ext {static constexpr const Type twty = Type::UInt16; typedef MagType DataType;}; + +template<> struct Ext {static constexpr const Type twty = Type::Str255; typedef Str255 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::Bool; typedef Bool DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::Str255; typedef char DataType;}; // NOTE: InfoId::MagData may also contain Handle +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; +template<> struct Ext {static constexpr const Type twty = Type::UInt16; typedef PageSide DataType;}; + +template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; + +template<> struct Ext {static constexpr const Type twty = Type::Str255; typedef Str255 DataType;}; + +} + +class Info; +class ExtImageInfo; + +namespace Detail { + +static Handle handleItem(Info& info) noexcept; + +static void deleteInfo(Info& info) noexcept; + +} + +TWPP_DETAIL_PACK_BEGIN +/// Extended image information entry. +class Info { + + friend class ExtImageInfo; + friend Handle Detail::handleItem(Info& info) noexcept; + friend void Detail::deleteInfo(Info& info) noexcept; + static constexpr const UInt32 DATA_HANDLE_THRESHOLD = sizeof(UIntPtr); // NOTE: specification says 4 bytes, yet pointer size makes more sense + +public: + template + class Items { + + friend class Info; + + public: + typedef Detail::MaybeLock Data; + + constexpr Items() noexcept : + m_parent(nullptr){} + + Items(const Items&) = default; + Items& operator=(const Items&) = default; + + Items(Items&&) = default; + Items& operator=(Items&&) = default; + + operator bool() const noexcept{ + return m_data; + } + + Data at(UInt32 i) const{ + if (m_parent->hasDataHandle() && m_parent->type() == Type::Handle){ + return reinterpret_cast(m_data.data())[i]; + } else { + return reinterpret_cast(m_data.data() + i * typeSize(m_parent->type())); + } + } + + Data operator[](UInt32 i) const{ + return at(i); + } + + private: + Items(Info& parent, Detail::MaybeLock data) noexcept : + m_parent(&parent), m_data(data){} + + Info* m_parent; + Detail::MaybeLock m_data; + // [items] <=> !(big and handle) + // [handles]->handles*[items] <=> big and handle (this should teoretically not happen) + + }; + + Info(const Info&) = delete; + Info& operator=(const Info&) = delete; + + Info(Info&&) = delete; + Info& operator=(Info&&) = delete; + + /// Information type ID. + InfoId id() const noexcept{ + return m_infoId; + } + + /// Information data type ID. + Type type() const noexcept{ + return m_itemType; + } + + /// Number of items in this entry. + UInt16 size() const noexcept{ + return m_numItems; + } + + /// Allocates space for the supplied number of items. + /// Allocating handles is not supported. + /// \tparam id Information type ID. Data types are set accordingly. + /// \param count Number of items to allocate. + /// \throw TypeException When `type` is handle or invalid. + /// \throw std::bad_alloc + template + void allocSimple(UInt16 count = 1){ + allocSimple(Detail::Ext::twty, count); + } + + /// Allocates space for the supplied number of items. + /// Allocating handles is not supported. + /// \param type Data type ID. + /// \param count Number of items to allocate. + /// \throw TypeException When `type` is handle or invalid. + /// \throw std::bad_alloc + void allocSimple(Type type, UInt16 count = 1){ + if (type == Type::Handle){ + throw TypeException(); + } + + if (type == m_itemType && count == m_numItems){ + return; + } + + auto itemSize = typeSize(type); + + bool big = hasDataHandle(type, count); + // [items] <=> !big + // handle->[items] <=> big + + Detail::UniqueHandle newItem; + if (big){ + newItem = Detail::alloc(itemSize * count); + } + + Detail::deleteInfo(*this); + + if (big){ + *Detail::alias_cast(&m_item) = newItem.release(); + } + + m_itemType = type; + m_numItems = count; + } + + /// Allocates a single memory area owned by a handle. + /// Info type changes to handle. + /// \param itemSize Number of bytes to allocate. + /// \throw std::bad_alloc + void allocHandle(UInt32 itemSize){ + // handle->[chars] + auto newItem = Detail::UniqueHandle(Detail::alloc(itemSize)); + + Detail::deleteInfo(*this); + *Detail::alias_cast(&m_item) = newItem.release(); + + m_itemType = Type::Handle; + m_numItems = 1; + } + + /// Status of this entry. + ReturnCode returnCode() const noexcept{ + return m_returnCode; + } + + /// Sets status of this entry. + void setReturnCode(ReturnCode rc) noexcept{ + m_returnCode = rc; + } + + /// Returns items contained in this entry. + /// \tparam type ID of the internal data type. + /// \tparam DataType Exported data type. + /// \throw TypeException When types don't match. + template + Items items(){ + if (type != m_itemType || (type != Type::Handle && typeSize(type) != sizeof(DataType))){ + throw TypeException(); + } + + return itemsPriv(); + } + + /// Returns items contained in this entry. + /// \tparam type ID of the internal data type. + /// \throw TypeException When types don't match. + template + Items::Type> items(){ + if (type != m_itemType){ + throw TypeException(); + } + + return itemsPriv::Type>(); + } + + /// Returns items contained in this entry. + /// \tparam id Information type ID. Data types are set accordingly. + /// \throw TypeException When types don't match. + template + Items::DataType> items(){ + if (Detail::Ext::twty != m_itemType){ + throw TypeException(); + } + + return itemsPriv::DataType>(); + } + +private: + bool hasDataHandle() const{ + return hasDataHandle(type(), size()); + } + + static bool hasDataHandle(Type type, UInt16 size){ + return type != Type::DontCare && size * typeSize(type) > DATA_HANDLE_THRESHOLD; + } + + template + Items itemsPriv(){ + bool big = hasDataHandle(); + bool handle = m_itemType == Type::Handle; + + Detail::MaybeLock lock; + if (!big && !handle){ + lock = Detail::alias_cast(&m_item); + } else { + lock = *Detail::alias_cast(&m_item); + } + + return {*this, std::move(lock)}; + } + + template + static bool arrContains(const T(& arr)[len], const T& val) noexcept{ + for (std::size_t i = 0; i < len; i++){ + if (arr[i] == val){ + return true; + } + } + + return false; + } + + InfoId m_infoId; + Type m_itemType; + UInt16 m_numItems; + ReturnCode m_returnCode; + UIntPtr m_item; + // [items] <=> !big and !handle + // handle->[items] <=> big xor handle + // handle->[handles]->handles*[items] <=> big and handle (this should teoretically not happen) + +}; + +namespace Detail { + +static inline Handle handleItem(Info& info) noexcept{ + return Handle(*Detail::alias_cast(&info.m_item)); +} + +static inline void deleteInfo(Info& info) noexcept{ + bool big = isType(info.type()) && info.hasDataHandle(); + bool handle = info.type() == Type::Handle; + + // [items] <=> !big and !handle + // handle->[items] <=> big xor handle + // handle->[handles]->handles*[items] <=> big and handle (this should teoretically not happen) + + if (big && handle){ + Detail::Lock lock(handleItem(info)); + for (UInt16 i = 0; i < info.size(); i++){ + Detail::free(lock.data()[i]); + } + } + + if (big || handle){ + Detail::free(handleItem(info)); + } +} + +struct ExtImageInfoData { + UInt32 m_numInfos; + Info m_infos[1]; +}; + +} + +TWPP_DETAIL_PACK_END +/// Extended image information. +/// Application sends list of info IDs, +/// source sets their data. +class ExtImageInfo { + +public: + typedef Info* iterator; + typedef const Info* const_iterator; + + /// Creates an invalid object. + ExtImageInfo() noexcept {} + + /// Creates a new structure for all supplied info IDs. + /// Sources must not call this constructor, they + /// are required to fill data in existing instance. + /// \param ids List of requested info IDs to be filled in by the source. + ExtImageInfo(std::initializer_list ids) : + m_data(new char[sizeof(Detail::ExtImageInfoData) - sizeof(Info) + ids.size() * sizeof(Info)]()){ + + d()->m_numInfos = static_cast(ids.size()); + + Info* infos = d()->m_infos; + + UInt32 i = 0; + for (auto id : ids){ + auto& info = infos[i]; + i++; + + info.m_infoId = id; + info.m_itemType = Type::DontCare; + } + } + + ExtImageInfo(ExtImageInfo&&) = default; + ExtImageInfo& operator=(ExtImageInfo&&) = default; + + operator bool() const noexcept{ + return isValid(); + } + + bool isValid() const noexcept{ + return static_cast(m_data); + } + + /// Number of requested entries. + UInt32 size() const noexcept{ + assert(isValid()); + return d()->m_numInfos; + } + + /// Information entry. + Info& at(UInt32 i) noexcept{ + assert(isValid()); + return d()->m_infos[i]; + } + + /// Information entry. + const Info& at(UInt32 i) const noexcept{ + assert(isValid()); + return d()->m_infos[i]; + } + + Info& operator[](UInt32 i) noexcept{ + return at(i); + } + + const Info& operator[](UInt32 i) const noexcept{ + return at(i); + } + + + iterator begin() noexcept{ + assert(isValid()); + return d()->m_infos; + } + + const_iterator begin() const noexcept{ + return cbegin(); + } + + const_iterator cbegin() const noexcept{ + assert(isValid()); + return d()->m_infos; + } + + iterator end() noexcept{ + assert(isValid()); + return d()->m_infos + d()->m_numInfos; + } + + const_iterator end() const noexcept{ + return cend(); + } + + const_iterator cend() const noexcept{ + assert(isValid()); + return d()->m_infos + d()->m_numInfos; + } + +private: + Detail::ExtImageInfoData* d() noexcept{ + return reinterpret_cast(m_data.get()); + } + + Detail::ExtImageInfoData* d() const noexcept{ + return reinterpret_cast(m_data.get()); + } + + struct Deleter { + void operator()(char* ptr) noexcept{ + Detail::ExtImageInfoData* data = reinterpret_cast(ptr); + if (data){ + for (UInt32 i = 0; i < data->m_numInfos; i++){ + Detail::deleteInfo(data->m_infos[i]); + } + + delete [] ptr; + } + } + }; + + std::unique_ptr m_data; + +}; + +} + +#endif // TWPP_DETAIL_FILE_EXTIMAGEINFO_HPP + diff --git a/huagaotwain/twain/twpp/filesystem.hpp b/huagaotwain/twain/twpp/filesystem.hpp new file mode 100644 index 0000000..b7bbc79 --- /dev/null +++ b/huagaotwain/twain/twpp/filesystem.hpp @@ -0,0 +1,248 @@ +/* + +The MIT License (MIT) + +Copyright (c) 2015 Martin Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef TWPP_DETAIL_FILE_FILESYSTEM_HPP +#define TWPP_DETAIL_FILE_FILESYSTEM_HPP + +#include "../twpp.hpp" + +namespace Twpp { + +TWPP_DETAIL_PACK_BEGIN +/// Structure representing device filesystem and operations on it. +class FileSystem { + +public: + /// Type of file. + enum class Type : Int32 { + Camera = 0, + CameraTop = 1, + CameraBottom = 2, + CameraPreview = 3, + Domain = 4, + Host = 5, + Directory = 6, + Image = 7, + Unknown = 8 + }; + + /// Creates uninitialized file system. + constexpr FileSystem() noexcept : + m_context(nullptr), m_recursiveBool(), m_fileType(Type::Camera), m_size(), + m_freeSpace(), m_newImageSize(), m_numberOfFiles(), m_numberOfSnippets(), + m_deviceGroupMask(), m_reserved(){} + + /// Creates file system with input and output paths and optional context. + constexpr FileSystem(const Str255& inputPath, const Str255& outputPath, void* context = nullptr) noexcept : + m_inputPath(inputPath), m_outputPath(outputPath), m_context(context), + m_recursiveBool(), m_fileType(Type::Camera), m_size(), m_freeSpace(), m_newImageSize(), + m_numberOfFiles(), m_numberOfSnippets(), m_deviceGroupMask(), m_reserved(){} + + /// Input or source file. + constexpr const Str255& inputPath() const noexcept{ + return m_inputPath; + } + + /// Sets input or source file. + void setInputPath(const Str255& path) noexcept{ + m_inputPath = path; + } + + /// Operation result, or destination file. + constexpr const Str255& outputPath() const noexcept{ + return m_outputPath; + } + + /// Sets operation result, or destination file. + void setOutputPath(const Str255& path) noexcept{ + m_outputPath = path; + } + + /// Source specific context. + constexpr void* context() const noexcept{ + return m_context; + } + + /// Sets source specific context. + void setContext(void* context) noexcept{ + m_context = context; + } + + /// Whether the operation is recursive. + /// Valid for Msg::GetInfo, Msg::GetFileFirst and Msg::Delete. + constexpr Bool recursive() const noexcept{ + return m_recursiveBool; + } + + /// Sets whether the operation is recursive. + /// Valid for Msg::GetInfo, Msg::GetFileFirst and Msg::Delete. + void setRecursive(Bool recursive) noexcept{ + m_recursiveBool = recursive; + } + + /// File type. + /// Valid for Msg::GetInfo, Msg::GetFileFirst and Msg::GetFileNext. + constexpr Type type() const noexcept{ + return m_fileType; + } + + /// Sets file type. + /// Valid for Msg::GetInfo, Msg::GetFileFirst and Msg::GetFileNext. + void setType(Type type) noexcept{ + m_fileType = type; + } + + /// Number of bytes of the entry. + /// Valid for Msg::GetInfo, Msg::GetFileFirst and Msg::GetFileNext. + constexpr UInt32 size() const noexcept{ + return m_size; + } + + /// Sets number of bytes of the entry. + /// Valid for Msg::GetInfo, Msg::GetFileFirst and Msg::GetFileNext. + void setSize(UInt32 size) noexcept{ + m_size = size; + } + + /// Creation date of the file. + /// Valid for Msg::GetInfo, Msg::GetFileFirst and Msg::GetFileNext. + /// YYYY/MM/DD HH:mm:SS:sss + constexpr const Str32& createdTimeDate() const noexcept{ + return m_createdTimeDate; + } + + /// Sets creation date of the file. + /// Valid for Msg::GetInfo, Msg::GetFileFirst and Msg::GetFileNext. + /// YYYY/MM/DD HH:mm:SS:sss + void setCreatedTimeDate(const Str32& val) noexcept{ + m_createdTimeDate = val; + } + + /// Modification date of the file. + /// Valid for Msg::GetInfo, Msg::GetFileFirst and Msg::GetFileNext. + /// YYYY/MM/DD HH:mm:SS:sss + constexpr const Str32& modifiedTimeDate() const noexcept{ + return m_modifiedTimeDate; + } + + /// Sets modification date of the file. + /// Valid for Msg::GetInfo, Msg::GetFileFirst and Msg::GetFileNext. + /// YYYY/MM/DD HH:mm:SS:sss + void setModifiedTimeDate(const Str32& val) noexcept{ + m_modifiedTimeDate = val; + } + + /// Number of bytes left on the device. + /// Valid for Msg::GetInfo, Msg::GetFileFirst and Msg::GetFileNext. + constexpr UInt32 freeSpace() const noexcept{ + return m_freeSpace; + } + + /// Sets number of bytes left on the device. + /// Valid for Msg::GetInfo, Msg::GetFileFirst and Msg::GetFileNext. + void setFreeSpace(UInt32 freeSpace) noexcept{ + m_freeSpace = freeSpace; + } + + /// Estimated image size in bytes. + /// Valid for Msg::GetInfo, Msg::GetFileFirst and Msg::GetFileNext. + constexpr Int32 newImageSize() const noexcept{ + return m_newImageSize; + } + + /// Sets estimated image size in bytes. + /// Valid for Msg::GetInfo, Msg::GetFileFirst and Msg::GetFileNext. + void setNewImageSize(Int32 newImageSize) noexcept{ + m_newImageSize = newImageSize; + } + + /// Total number of files including subdirectories. + /// Valid for Msg::GetInfo, Msg::GetFileFirst and Msg::GetFileNext. + constexpr UInt32 files() const noexcept{ + return m_numberOfFiles; + } + + /// Sets total number of files including subdirectories. + /// Valid for Msg::GetInfo, Msg::GetFileFirst and Msg::GetFileNext. + void setFiles(UInt32 files) noexcept{ + m_numberOfFiles = files; + } + + /// Number of audio snippets. + /// Valid for Msg::GetInfo, Msg::GetFileFirst and Msg::GetFileNext. + constexpr UInt32 snippets() const noexcept{ + return m_numberOfSnippets; + } + + /// Sets number of audio snippets. + /// Valid for Msg::GetInfo, Msg::GetFileFirst and Msg::GetFileNext. + void snippets(UInt32 snippets) noexcept{ + m_numberOfSnippets = snippets; + } + + /// See manual for explanation of this field, `DeviceGroupMask`. + constexpr UInt32 groupMask() const noexcept{ + return m_deviceGroupMask; + } + + /// See manual for explanation of this field, `DeviceGroupMask`. + void groupMask(UInt32 groupMask) noexcept{ + m_deviceGroupMask = groupMask; + } + +private: + void unused() const{ + Detail::unused(m_reserved); + } + + Str255 m_inputPath; + Str255 m_outputPath; + void* m_context; + + // Copy, Delete + union { + int m_recursive; + Bool m_recursiveBool; + }; + + // GetInfo + Type m_fileType; + UInt32 m_size; + Str32 m_createdTimeDate; + Str32 m_modifiedTimeDate; + UInt32 m_freeSpace; + Int32 m_newImageSize; + UInt32 m_numberOfFiles; + UInt32 m_numberOfSnippets; + UInt32 m_deviceGroupMask; + Int8 m_reserved[508]; + +}; +TWPP_DETAIL_PACK_END + +} + +#endif // TWPP_DETAIL_FILE_FILESYSTEM_HPP diff --git a/huagaotwain/twain/twpp/fix32.hpp b/huagaotwain/twain/twpp/fix32.hpp new file mode 100644 index 0000000..fc99b79 --- /dev/null +++ b/huagaotwain/twain/twpp/fix32.hpp @@ -0,0 +1,198 @@ +/* + +The MIT License (MIT) + +Copyright (c) 2015 Martin Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef TWPP_DETAIL_FILE_FIX32_HPP +#define TWPP_DETAIL_FILE_FIX32_HPP + +#include "../twpp.hpp" + +namespace Twpp { + +namespace Detail { + +static constexpr inline Int32 floatToValue(float val){ + return static_cast( + (val >= 0.0f) ? + (val * 65536.0f + 0.5f) : + (val * 65536.0f - 0.5f) + ); +} + +static constexpr inline Int16 floatToWhole(float val){ + return static_cast(floatToValue(val) >> 16); +} + +static constexpr inline UInt16 floatToFrac(float val){ + return static_cast(floatToValue(val) & 0xFFFF); +} + +} + +TWPP_DETAIL_PACK_BEGIN +/// TWAIN fixed point fractional type. +/// The fractional part has resolution of 1/65536. +class Fix32 { + +public: + /// Creates zero-initialized fixed type. + constexpr Fix32() noexcept : + m_whole(0), m_frac(0){} + + /// Creates fixed type from float at compile time if possible. + constexpr Fix32(float value) noexcept : + m_whole(Detail::floatToWhole(value)), m_frac(Detail::floatToFrac(value)){} + + /// Creates fixed type from whole and fractional parts. + /// The fractional part has resolution of 1/65536. + constexpr Fix32(Int16 whole, UInt16 frac) noexcept : + m_whole(whole), m_frac(frac){} + + + /// Whole part of this fixed type. + constexpr Int16 whole() const noexcept{ + return m_whole; + } + + /// Sets whole part of this fixed type. + void setWhole(Int16 whole) noexcept{ + m_whole = whole; + } + + /// Fractional part of this fixed type. + /// Resolution of 1/65536. + constexpr UInt16 frac() const noexcept{ + return m_frac; + } + + /// Sets fractional part of this fixed type. + /// Resolution of 1/65536. + void setFrac(UInt16 frac) noexcept{ + m_frac = frac; + } + + explicit constexpr operator float() const noexcept{ + return m_whole + m_frac / 65536.0f; + } + + constexpr float toFloat() const noexcept{ + return m_whole + m_frac / 65536.0f; + } + + constexpr Fix32 operator-() const noexcept{ + return -toFloat(); + } + +private: + Int16 m_whole; + UInt16 m_frac; + +}; +TWPP_DETAIL_PACK_END + +namespace Detail { + +static inline constexpr Fix32 fix32AddHelper(Int32 frac, Int16 whole){ + return frac < 65536 ? Fix32(whole, frac) : Fix32(whole + 1, frac - 65536); +} + +static inline constexpr Fix32 fix32SubHelper(Int32 frac, Int16 whole){ + return frac >= 0 ? Fix32(whole, frac) : Fix32(whole - 1, frac + 65536); +} + +} + +static inline constexpr bool operator>(Fix32 a, Fix32 b) noexcept{ + return a.whole() > b.whole() || (a.whole() == b.whole() && a.frac() > b.frac()); +} + +static inline constexpr bool operator<(Fix32 a, Fix32 b) noexcept{ + return a.whole() < b.whole() || (a.whole() == b.whole() && a.frac() < b.frac()); +} + +static inline constexpr bool operator>=(Fix32 a, Fix32 b) noexcept{ + return !(a < b); +} + +static inline constexpr bool operator<=(Fix32 a, Fix32 b) noexcept{ + return !(a > b); +} + +static inline constexpr bool operator==(Fix32 a, Fix32 b) noexcept{ + return a.whole() == b.whole() && a.frac() == b.frac(); +} + +static inline constexpr bool operator!=(Fix32 a, Fix32 b) noexcept{ + return !(a == b); +} + +static inline constexpr Fix32 operator+(Fix32 a, Fix32 b) noexcept{ + return Detail::fix32AddHelper(static_cast(a.frac()) + b.frac(), a.whole() + b.whole()); +} + +static inline constexpr Fix32 operator-(Fix32 a, Fix32 b) noexcept{ + return Detail::fix32SubHelper(static_cast(a.frac()) - b.frac(), a.whole() - b.whole()); +} + +static inline constexpr Fix32 operator*(Fix32 a, Fix32 b) noexcept{ + return Fix32(static_cast(a) * static_cast(b)); +} + +static inline constexpr Fix32 operator/(Fix32 a, Fix32 b) noexcept{ // wonder about zero b + return Fix32(static_cast(a) / static_cast(b)); +} + +static inline Fix32& operator+=(Fix32& a, Fix32 b) noexcept{ + return a = a + b; +} + +static inline Fix32& operator-=(Fix32& a, Fix32 b) noexcept{ + return a = a - b; +} + +static inline Fix32& operator*=(Fix32& a, Fix32 b) noexcept{ + return a = a * b; +} + +static inline Fix32& operator/=(Fix32& a, Fix32 b) noexcept{ // wonder about zero b + return a = a / b; +} + +namespace Literals { + +static inline constexpr Fix32 operator "" _fix(long double val) noexcept{ + return Fix32(static_cast(val)); +} + +static inline constexpr Fix32 operator "" _fix(unsigned long long val) noexcept{ + return Fix32(static_cast(val)); +} + +} + +} + +#endif // TWPP_DETAIL_FILE_FIX32_HPP + diff --git a/huagaotwain/twain/twpp/frame.hpp b/huagaotwain/twain/twpp/frame.hpp new file mode 100644 index 0000000..7c87816 --- /dev/null +++ b/huagaotwain/twain/twpp/frame.hpp @@ -0,0 +1,106 @@ +/* + +The MIT License (MIT) + +Copyright (c) 2015 Martin Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef TWPP_DETAIL_FILE_FRAME_HPP +#define TWPP_DETAIL_FILE_FRAME_HPP + +#include "../twpp.hpp" + +namespace Twpp { + +TWPP_DETAIL_PACK_BEGIN +/// Section of an image to retrieve. +class Frame { + +public: + /// Creates zero-initialized frame. + constexpr Frame() noexcept{} + + /// Creates frame with set top-left and bottom-right corners. + constexpr Frame(Fix32 left, Fix32 top, Fix32 right, Fix32 bottom) noexcept : + m_left(left), m_top(top), m_right(right), m_bottom(bottom){} + + /// Left position of the image frame. + constexpr Fix32 left() const noexcept{ + return m_left; + } + + /// Sets left position of the image frame. + void setLeft(Fix32 left) noexcept{ + m_left = left; + } + + /// Top position of the image frame. + constexpr Fix32 top() const noexcept{ + return m_top; + } + + /// Sets top position of the image frame. + void setTop(Fix32 top) noexcept{ + m_top = top; + } + + /// Right position of the image frame. + constexpr Fix32 right() const noexcept{ + return m_right; + } + + /// Sets right position of the image frame. + void setRight(Fix32 right) noexcept{ + m_right = right; + } + + /// Bottom position of the image frame. + constexpr Fix32 bottom() const noexcept{ + return m_bottom; + } + + /// Sets bottom position of the image frame. + void setBottom(Fix32 bottom) noexcept{ + m_bottom = bottom; + } + +private: + Fix32 m_left; + Fix32 m_top; + Fix32 m_right; + Fix32 m_bottom; + +}; +TWPP_DETAIL_PACK_END + +static constexpr inline bool operator==(const Frame& a, const Frame& b) noexcept{ + return a.left() == b.left() && a.top() == b.top() && a.right() == b.right() && a.bottom() == b.bottom(); +} + +static constexpr inline bool operator!=(const Frame& a, const Frame& b) noexcept{ + return !(a == b); +} + +} + +#endif // TWPP_DETAIL_FILE_FRAME_HPP + diff --git a/huagaotwain/twain/twpp/identity.hpp b/huagaotwain/twain/twpp/identity.hpp new file mode 100644 index 0000000..b50e930 --- /dev/null +++ b/huagaotwain/twain/twpp/identity.hpp @@ -0,0 +1,247 @@ +/* + +The MIT License (MIT) + +Copyright (c) 2015-2017 Martin Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef TWPP_DETAIL_FILE_IDENTITY_HPP +#define TWPP_DETAIL_FILE_IDENTITY_HPP + +#include "../twpp.hpp" + +namespace Twpp { + +namespace Detail { + +static constexpr const UInt32 identV2 = TWPP_DETAIL_IS_DS ? Detail::Ds2 : Detail::App2; + +} + +TWPP_DETAIL_PACK_BEGIN +/// Source or application version information. +class Version { + +public: + /// Creates default-initialized version. + constexpr Version() noexcept : + m_majorNum(0), m_minorNum(0), m_language(Language::English), + m_country(Country::UnitedKingdom){} + + /// Creates version initialized with supplied values. + constexpr Version( + UInt16 majorNumber, + UInt16 minorNumber, + Language language, + Country country, + const Str32& info = Str32()) noexcept : + m_majorNum(majorNumber), m_minorNum(minorNumber), m_language(language), + m_country(country), m_info(info){} + + /// Major version number of the source or application. + constexpr UInt16 majorNumber() const noexcept{ + return m_majorNum; + } + + /// Sets major version number of the source or application. + void setMajorNumber(UInt16 major) noexcept{ + m_majorNum = major; + } + + /// Minor version number of the source or application. + constexpr UInt16 minorNumber() const noexcept{ + return m_minorNum; + } + + /// Sets minor version number of the source or application. + void setMinorNumber(UInt16 minor) noexcept{ + m_minorNum = minor; + } + + /// Language of the source or application. + constexpr Language language() const noexcept{ + return m_language; + } + + /// Sets language of the source or application. + void setLanguage(Language language) noexcept{ + m_language = language; + } + + /// Original country of the source or application. + constexpr Country country() const noexcept{ + return m_country; + } + + /// Set original country of the source or application. + void setCountry(Country country) noexcept{ + m_country = country; + } + + /// Additional version information of the source or application. + constexpr const Str32& info() const noexcept{ + return m_info; + } + + /// Sets additional version information of the source or application. + void setInfo(const Str32& info) noexcept{ + m_info = info; + } + +private: + UInt16 m_majorNum; + UInt16 m_minorNum; + Language m_language; + Country m_country; + Str32 m_info; + +}; + +/// Source or application identity. +/// Uniquely identifies an endpoint. +class Identity { + +public: + typedef +#if defined(TWPP_DETAIL_OS_MAC) + void* +#elif defined(TWPP_DETAIL_OS_WIN) || defined(TWPP_DETAIL_OS_LINUX) + UInt32 +#else +# error "Identity::Id for your platform here" +#endif + Id; + + /// Creates default-initialized identity. + /// ID is set to zero. + /// TWAIN protocol is always Detail::ProtoMajor and Detail::ProtoMinor. + /// Supported group always contains DG::Control and V2. + constexpr Identity() noexcept : + m_id(), m_protoMaj(Detail::ProtoMajor), m_protoMin(Detail::ProtoMinor), + m_groups(DataGroup::Control | Detail::identV2){} + + /// Creates identity initialized with supplied values. + /// ID is set to zero. + /// TWAIN protocol is always Detail::ProtoMajor and Detail::ProtoMinor. + /// Supported group always contains DG::Control and V2. + constexpr Identity( + const Version& version, + DataGroup group, + const Str32& manufacturer, + const Str32& productFamily, + const Str32& productName) noexcept : + m_id(), m_version(version), m_protoMaj(Detail::ProtoMajor), + m_protoMin(Detail::ProtoMinor), m_groups(DataGroup::Control | group | Detail::identV2), + m_manuf(manufacturer), m_prodFamily(productFamily), m_prodName(productName){} + + /// Creates identity initialized with supplied values. + constexpr Identity( + Id id, + const Version& version, + UInt16 protoMajor, + UInt16 protoMinor, + UInt32 groups, + const Str32& manufacturer, + const Str32& productFamily, + const Str32& productName) noexcept : + m_id(id), m_version(version), m_protoMaj(protoMajor), m_protoMin(protoMinor), + m_groups(groups), m_manuf(manufacturer), m_prodFamily(productFamily), + m_prodName(productName){} + + /// DSM-supplied ID of this identity. + constexpr Id id() const{ + return m_id; + } + + /// Version information. + constexpr const Version& version() const noexcept{ + return m_version; + } + + /// Whether a data group is supported. + constexpr bool supports(DataGroup group) const noexcept{ + return (m_groups & group) != 0; + } + + /// Whether this is V2 application. + constexpr bool isAppV2() const noexcept{ + return (m_groups & Detail::App2) != 0; + } + + /// Whether this is V2 DSM. + constexpr bool isDsmV2() const noexcept{ + return (m_groups & Detail::Dsm2) != 0; + } + + /// Whether this is V2 source. + constexpr bool isDsV2() const noexcept{ + return (m_groups & Detail::Ds2) != 0; + } + + /// The manufacturer. + /// Manufacturer and product name uniquely identify a source. + constexpr const Str32& manufacturer() const noexcept{ + return m_manuf; + } + + /// The product name. + /// Manufacturer and product name uniquely identify a source. + constexpr const Str32& productName() const noexcept{ + return m_prodName; + } + + /// The product family. + constexpr const Str32& productFamily() const noexcept{ + return m_prodFamily; + } + + /// Raw data group flags. + constexpr UInt32 dataGroupsRaw() const noexcept{ + return m_groups; + } + + /// TWAIN protocol major version. + constexpr UInt16 protocolMajor() const noexcept{ + return m_protoMaj; + } + + /// TWAIN protocol minor version. + constexpr UInt16 protocolMinor() const noexcept{ + return m_protoMin; + } + +private: + Id m_id; + Version m_version; + UInt16 m_protoMaj; + UInt16 m_protoMin; + UInt32 m_groups; + Str32 m_manuf; + Str32 m_prodFamily; + Str32 m_prodName; + +}; +TWPP_DETAIL_PACK_END + +} + +#endif // TWPP_DETAIL_FILE_IDENTITY_HPP diff --git a/huagaotwain/twain/twpp/imageinfo.hpp b/huagaotwain/twain/twpp/imageinfo.hpp new file mode 100644 index 0000000..78cbf84 --- /dev/null +++ b/huagaotwain/twain/twpp/imageinfo.hpp @@ -0,0 +1,190 @@ +/* + +The MIT License (MIT) + +Copyright (c) 2015 Martin Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef TWPP_DETAIL_FILE_IMAGEINFO_HPP +#define TWPP_DETAIL_FILE_IMAGEINFO_HPP + +#include "../twpp.hpp" + +namespace Twpp { + +TWPP_DETAIL_PACK_BEGIN +/// Contains information about transfered image. +class ImageInfo { + + typedef Detail::FixedArray BitsPerSampleImpl; + +public: + typedef Int16 BitsPerSample[8]; + + /// Creates zero-initialized info. + constexpr ImageInfo() noexcept : + m_imgWidth(0), m_imgHeight(0), m_spp(0), m_bps(), m_bpp(0), + m_planar(0), m_pixelType(PixelType::BlackWhite), m_compression(Compression::None){} + + /// Creates info with supplied values. + template + constexpr ImageInfo( + Fix32 xResolution, + Fix32 yResolution, + Int32 width, + Int32 height, + Int16 samplesPerPixel, + const Int16(& bitsPerSample)[inputSize], + Int16 bitsPerPixel, + Bool planar, + PixelType pixelType, + Compression compression + ) noexcept : + m_xres(xResolution), m_yres(yResolution), m_imgWidth(width), m_imgHeight(height), + m_spp(samplesPerPixel), m_bps(bitsPerSample), m_bpp(bitsPerPixel), m_planar(planar), + m_pixelType(pixelType), m_compression(compression){} + + /// X-axis resolution of the image. + constexpr Fix32 xResolution() const noexcept{ + return m_xres; + } + + /// Sets x-axis resolution of the image. + void setXResolution(Fix32 xres) noexcept{ + m_xres = xres; + } + + /// Y-axis resolution of the image. + constexpr Fix32 yResolution() const noexcept{ + return m_yres; + } + + /// Sets y-axis resolution of the image. + void setYResolution(Fix32 yres) noexcept{ + m_yres = yres; + } + + /// Image width in pixels. + constexpr Int32 width() const noexcept{ + return m_imgWidth; + } + + /// Sets image width in pixels. + void setWidth(Int32 width) noexcept{ + m_imgWidth = width; + } + + /// Image height in pixels. + constexpr Int32 height() const noexcept{ + return m_imgHeight; + } + + /// Sets image height in pixels. + void setHeight(Int32 height) noexcept{ + m_imgHeight = height; + } + + /// Samples per single pixel. + constexpr Int16 samplesPerPixel() const noexcept{ + return m_spp; + } + + /// Sets samples per single pixel. + void setSamplesPerPixel(Int16 spp) noexcept{ + m_spp = spp; + } + + /// Array of bits per sample. + /// Contains `samplesPerPixel` entries. + constexpr const BitsPerSample& bitsPerSample() const noexcept{ + return m_bps.array(); + } + + /// Array of bits per sample. + /// Contains `samplesPerPixel` entries. + BitsPerSample& bitsPerSample() noexcept{ + return m_bps.array(); + } + + /// Total number of bits per pixel. + /// This should be true: bitsPerPixel = SUM[i=0..samplesPerPixel-1](bitsPerSample[i]) + constexpr Int16 bitsPerPixel() const noexcept{ + return m_bpp; + } + + /// Sets total number of bits per pixel. + /// This should be true: bitsPerPixel = SUM[i=0..samplesPerPixel-1](bitsPerSample[i]) + void setBitsPerPixel(Int16 bpp) noexcept{ + m_bpp = bpp; + } + + /// Whether the image is planar (consists of several sample planes) or is chunky + /// (samples are transferes in one plane and are interlaced). + constexpr Bool planar() const noexcept{ + return m_planar; + } + + /// Sets whether the image is planar (consists of several sample planes) or is chunky + /// (samples are transferes in one plane and are interlaced). + void setPlanar(Bool planar) noexcept{ + m_planar = planar; + } + + /// The type of image. + constexpr PixelType pixelType() const noexcept{ + return m_pixelType; + } + + /// Sets the type of image. + void setPixelType(PixelType pixelType) noexcept{ + m_pixelType = pixelType; + } + + /// Image compression. + constexpr Compression compression() const noexcept{ + return m_compression; + } + + /// Sets image compression. + void compression(Compression compression) noexcept{ + m_compression = compression; + } + +private: + Fix32 m_xres; + Fix32 m_yres; + Int32 m_imgWidth; + Int32 m_imgHeight; + Int16 m_spp; + BitsPerSampleImpl m_bps; + Int16 m_bpp; + Bool m_planar; + PixelType m_pixelType; + Compression m_compression; + +}; +TWPP_DETAIL_PACK_END + +} + +#endif // TWPP_DETAIL_FILE_IMAGEINFO_HPP + diff --git a/huagaotwain/twain/twpp/imagelayout.hpp b/huagaotwain/twain/twpp/imagelayout.hpp new file mode 100644 index 0000000..c61eb5b --- /dev/null +++ b/huagaotwain/twain/twpp/imagelayout.hpp @@ -0,0 +1,100 @@ +/* + +The MIT License (MIT) + +Copyright (c) 2015 Martin Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef TWPP_DETAIL_FILE_IMAGELAYOUT_HPP +#define TWPP_DETAIL_FILE_IMAGELAYOUT_HPP + +#include "../twpp.hpp" + +namespace Twpp { + +TWPP_DETAIL_PACK_BEGIN +/// Provides image size and its position on the scanner and information about order of the image. +class ImageLayout { + +public: + /// Creates layout. + constexpr ImageLayout( + const Frame& frame = Frame(), + UInt32 documentNumber = 1, + UInt32 pageNumber = 1, + UInt32 frameNumber = 1 + ) noexcept : + m_frame(frame), m_docNumber(documentNumber), + m_pageNumber(pageNumber), m_frameNumber(frameNumber){} + + /// The image frame. + constexpr const Frame& frame() const noexcept{ + return m_frame; + } + + /// Sets the image frame. + void setFrame(const Frame& frame) noexcept{ + m_frame = frame; + } + + /// Number of the document, set by source. + constexpr UInt32 documentNumber() const noexcept{ + return m_docNumber; + } + + /// Sets number of the document. + void setDocumentNumber(UInt32 documentNumber) noexcept{ + m_docNumber = documentNumber; + } + + /// Number of the page, set by source. + constexpr UInt32 pageNumber() const noexcept{ + return m_pageNumber; + } + + /// Sets number of the page. + void setPageNumber(UInt32 pageNumber) noexcept{ + m_pageNumber = pageNumber; + } + + /// Number of the frame, set by source. + constexpr UInt32 frameNumber() const noexcept{ + return m_frameNumber; + } + + /// Sets number of the frame. + void setFrameNumber(UInt32 frameNumber) noexcept{ + m_frameNumber = frameNumber; + } + +private: + Frame m_frame; + UInt32 m_docNumber; + UInt32 m_pageNumber; + UInt32 m_frameNumber; + +}; +TWPP_DETAIL_PACK_END + +} + +#endif // TWPP_DETAIL_FILE_IMAGELAYOUT_HPP diff --git a/huagaotwain/twain/twpp/imagememxfer.hpp b/huagaotwain/twain/twpp/imagememxfer.hpp new file mode 100644 index 0000000..2be7a3a --- /dev/null +++ b/huagaotwain/twain/twpp/imagememxfer.hpp @@ -0,0 +1,207 @@ +/* + +The MIT License (MIT) + +Copyright (c) 2015 Martin Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef TWPP_DETAIL_FILE_IMAGEMEMXFER_HPP +#define TWPP_DETAIL_FILE_IMAGEMEMXFER_HPP + +#include "../twpp.hpp" + +namespace Twpp { + +TWPP_DETAIL_PACK_BEGIN +namespace Detail { + +/// Structure holding the information and data of memory and memory file transfers. +class ImageMemXferImpl { + +public: + /// Creates a zero-initialized structure without any memory. + ImageMemXferImpl() noexcept : + m_compression(Compression::None), m_bytesPerRow(0), m_columns(0), m_rows(0), + m_xoff(0), m_yoff(0), m_bytesWritten(0){} + + /// Creates an initialized structure from the supplied values and memory. + /// The ownership of the memory is taken over. + ImageMemXferImpl( + Compression compression, + UInt32 bytesPerRow, + UInt32 columns, + UInt32 rows, + UInt32 xOffset, + UInt32 yOffset, + UInt32 bytesWritten, + Memory memory + ) noexcept : + m_compression(compression), m_bytesPerRow(bytesPerRow), + m_columns(columns), m_rows(rows), m_xoff(xOffset), m_yoff(yOffset), + m_bytesWritten(bytesWritten), m_memory(std::move(memory)){} + + /// Compression used in the transfer. + Compression compression() const noexcept{ + return m_compression; + } + + /// Sets compression used in the transfer. + void setCompression(Compression compression) noexcept{ + m_compression = compression; + } + + /// Number of bytes per single row. + UInt32 bytesPerRow() const noexcept{ + return m_bytesPerRow; + } + + /// Sets number of bytes per single row. + void setBytesPerRow(UInt32 bytesPerRow) noexcept{ + m_bytesPerRow = bytesPerRow; + } + + /// Number of columns in the transfer. + UInt32 columns() const noexcept{ + return m_columns; + } + + /// Sets number of columns in the transfer. + void setColumns(UInt32 columns) noexcept{ + m_columns = columns; + } + + /// Number of rows in the transfer. + UInt32 rows() const noexcept{ + return m_rows; + } + + /// Sets number of rows in the transfer. + void setRows(UInt32 rows) noexcept{ + m_rows = rows; + } + + /// X offset from top-left corner in pixels of the image data in the transfer. + UInt32 xOffset() const noexcept{ + return m_xoff; + } + + /// Sets X offset from top-left corner in pixels of the image data in the transfer. + void setXOffset(UInt32 xOffset) noexcept{ + m_xoff = xOffset; + } + + /// Y offset from top-left corner in pixels of the image data in the transfer. + UInt32 yOffset() const noexcept{ + return m_yoff; + } + + /// Sets Y offset from top-left corner in pixels of the image data in the transfer. + void setYOffset(UInt32 yOffset) noexcept{ + m_yoff = yOffset; + } + + /// Number of bytes in this transfer, always contains whole rows or tiles. + UInt32 bytesWritten() const noexcept{ + return m_bytesWritten; + } + + /// Sets number of bytes in this transfer. + void setBytesWritten(UInt32 bytesWritten) noexcept{ + m_bytesWritten = bytesWritten; + } + + /// Contained memory structure. + const Memory& memory() const noexcept{ + return m_memory; + } + + /// Contained memory structure. + Memory& memory() noexcept{ + return m_memory; + } + +private: + Compression m_compression; + UInt32 m_bytesPerRow; + UInt32 m_columns; + UInt32 m_rows; + UInt32 m_xoff; + UInt32 m_yoff; + UInt32 m_bytesWritten; + Memory m_memory; + +}; + +} + +/// Structure holding the information and data of memory transfer. +class ImageMemXfer : public Detail::ImageMemXferImpl { + +public: + /// Creates a zero-initialized structure without any memory. + ImageMemXfer() noexcept : Detail::ImageMemXferImpl(){} + + /// Creates an initialized structure from the supplied values and memory. + /// The ownership of the memory is taken over. + ImageMemXfer( + Compression compression, + UInt32 bytesPerRow, + UInt32 columns, + UInt32 rows, + UInt32 xOffset, + UInt32 yOffset, + UInt32 bytesWritten, + Memory memory + ) noexcept : Detail::ImageMemXferImpl( + compression, bytesPerRow, columns, rows, xOffset, + yOffset, bytesWritten, std::move(memory)){} + +}; + +/// Structure holding the information and data of memory file transfer. +class ImageMemFileXfer : public Detail::ImageMemXferImpl { + +public: + /// Creates a zero-initialized structure without any memory. + ImageMemFileXfer() noexcept : Detail::ImageMemXferImpl(){} + + /// Creates an initialized structure from the supplied values and memory. + /// The ownership of the memory is taken over. + ImageMemFileXfer( + Compression compression, + UInt32 bytesPerRow, + UInt32 columns, + UInt32 rows, + UInt32 xOffset, + UInt32 yOffset, + UInt32 bytesWritten, + Memory memory + ) noexcept : Detail::ImageMemXferImpl( + compression, bytesPerRow, columns, rows, xOffset, + yOffset, bytesWritten, std::move(memory)){} + +}; +TWPP_DETAIL_PACK_END + +} + +#endif // TWPP_DETAIL_FILE_IMAGEMEMXFER_HPP diff --git a/huagaotwain/twain/twpp/imagenativexfer.hpp b/huagaotwain/twain/twpp/imagenativexfer.hpp new file mode 100644 index 0000000..8a90bc0 --- /dev/null +++ b/huagaotwain/twain/twpp/imagenativexfer.hpp @@ -0,0 +1,98 @@ +/* + +The MIT License (MIT) + +Copyright (c) 2015 Martin Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef TWPP_DETAIL_FILE_IMAGENATIVEXFER_HPP +#define TWPP_DETAIL_FILE_IMAGENATIVEXFER_HPP + +#include "../twpp.hpp" + +namespace Twpp { + +TWPP_DETAIL_PACK_BEGIN +/// Structure holding native transfer image handle. +class ImageNativeXfer { + +public: + template + using Data = Detail::Lock::type>; + + template + using ConstData = Detail::Lock::type>; + + + /// Creates empty, invalid native transfer. + ImageNativeXfer() noexcept : + m_handle(){} + + /// Creates a new ImageNativeXfer object from a handle. + /// The ownership of the handle is taken over. + explicit ImageNativeXfer(Handle h) : + m_handle(h){} + + /// Creates uninitialized native image with defines size in bytes. + /// \throw std::bad_alloc + explicit ImageNativeXfer(UInt32 size) : + m_handle(Detail::alloc(size)){} + + /// Data of this native transfer. + /// Actual type depends on system and source. + /// Windows sources use BMP format without file header, version varies. + /// Linux uses TIFF, version varies. + /// Mac uses QuickDraw Picture. + template + Data data() noexcept{ + return m_handle.lock::type>(); + } + + /// Data of this native transfer. + /// Actual type depends on system and source. + /// Windows sources use BMP format without file header, version varies. + /// Linux uses TIFF, version varies. + /// Mac uses QuickDraw Picture. + template + ConstData data() const noexcept{ + return m_handle.lock::type>(); + } + + operator bool() const noexcept{ + return m_handle; + } + + /// Releases the contained handle, making user responsible for freeing it. + Handle release() noexcept{ + return m_handle.release(); + } + +private: + Detail::UniqueHandle m_handle; + +}; +TWPP_DETAIL_PACK_END + +} + +#endif // TWPP_DETAIL_FILE_IMAGENATIVEXFER_HPP + diff --git a/huagaotwain/twain/twpp/internal.hpp b/huagaotwain/twain/twpp/internal.hpp new file mode 100644 index 0000000..8abe360 --- /dev/null +++ b/huagaotwain/twain/twpp/internal.hpp @@ -0,0 +1,158 @@ +/* + +The MIT License (MIT) + +Copyright (c) 2015-2017 Martin Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef TWPP_DETAIL_FILE_INTERNAL_HPP +#define TWPP_DETAIL_FILE_INTERNAL_HPP + +#include "../twpp.hpp" + +namespace Twpp { + +struct AudioFileXfer {}; +struct ImageFileXfer {}; +typedef Memory IccProfileMemory; + +namespace Detail { + +typedef ReturnCode (TWPP_DETAIL_CALLSTYLE* DsmEntry)( + Identity* origin, + Identity* dest, + DataGroup dg, + Dat dat, + Msg msg, + void* data +); + +typedef DsmEntry CallBackFunc; + +typedef +#if defined(TWPP_DETAIL_OS_MAC) +void* +#elif defined(TWPP_DETAIL_OS_WIN) || defined(TWPP_DETAIL_OS_LINUX) +UInt32 +#else +# error "CallBackConstant for your platform here" +#endif +CallBackConstant; + + +TWPP_DETAIL_PACK_BEGIN +struct EntryPoint { + constexpr EntryPoint() noexcept : + m_size(sizeof(EntryPoint)), m_entry(nullptr), m_alloc(nullptr), + m_free(nullptr), m_lock(nullptr), m_unlock(nullptr){} + + UInt32 m_size; + DsmEntry m_entry; + MemAlloc m_alloc; + MemFree m_free; + MemLock m_lock; + MemUnlock m_unlock; +}; + +struct CallBack { + + constexpr CallBack(CallBackFunc func, CallBackConstant constant, Msg msg) noexcept : + m_func(func), m_constant(constant), m_msg(msg){} + + CallBackFunc m_func; + CallBackConstant m_constant; + Msg m_msg; + +}; + +struct CallBack2 { + + constexpr CallBack2(CallBackFunc func, UIntPtr constant, Msg msg) noexcept : + m_func(func), m_constant(constant), m_msg(msg){} + + CallBackFunc m_func; + UIntPtr m_constant; + Msg m_msg; +}; +TWPP_DETAIL_PACK_END + +/// Manages DSM dll/so/framework connection. +class DsmLib { + +public: + constexpr DsmLib() noexcept : + m_handle(DsmLibOs::nullHandle){} + + ~DsmLib(){ + unload(); + } + + DsmLib(const DsmLib&) = delete; + DsmLib& operator=(const DsmLib&) = delete; + + DsmLib(DsmLib&& o) noexcept : + m_handle(o.m_handle){ + + o.m_handle = DsmLibOs::nullHandle; + } + + DsmLib& operator=(DsmLib&& o) noexcept{ + if (&o != this){ + unload(); + + m_handle = o.m_handle; + o.m_handle = DsmLibOs::nullHandle; + } + + return *this; + } + + operator bool() const noexcept{ + return m_handle != DsmLibOs::nullHandle; + } + + bool load(bool preferOld = false) noexcept{ + m_handle = DsmLibOs::load(preferOld); + return m_handle != DsmLibOs::nullHandle; + } + + void unload() noexcept{ + if (m_handle != DsmLibOs::nullHandle){ + DsmLibOs::unload(m_handle); + m_handle = DsmLibOs::nullHandle; + } + } + + DsmEntry resolve() const noexcept{ + return DsmLibOs::resolve(m_handle); + } + +private: + DsmLibOs::Handle m_handle; + +}; + +} + +} + +#endif // TWPP_DETAIL_FILE_INTERNAL_HPP diff --git a/huagaotwain/twain/twpp/jpegcompression.hpp b/huagaotwain/twain/twpp/jpegcompression.hpp new file mode 100644 index 0000000..b42a176 --- /dev/null +++ b/huagaotwain/twain/twpp/jpegcompression.hpp @@ -0,0 +1,173 @@ +/* + +The MIT License (MIT) + +Copyright (c) 2015 Martin Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef TWPP_DETAIL_FILE_JPEGCOMPRESSION_HPP +#define TWPP_DETAIL_FILE_JPEGCOMPRESSION_HPP + +#include "../twpp.hpp" + +namespace Twpp { + +TWPP_DETAIL_PACK_BEGIN +/// See manual for more info. +class JpegCompression { + +public: + typedef UInt16 UInt16Arr4[4]; + typedef Memory MemoryArr2[2]; + typedef Memory MemoryArr4[4]; + + JpegCompression() noexcept : + m_colorSpace(PixelType::BlackWhite), m_subSampling(0x10001000), m_components(0), + m_restartFrequency(0), m_quantMap(), m_huffmanMap(){} + + template< + std::size_t quantTableMapSize, + std::size_t quantTableSize, + std::size_t huffmanTableMapSize, + std::size_t huffmanDcSize, + std::size_t huffmanAcSize + > + JpegCompression( + PixelType colorSpace, + UInt32 subSampling, + UInt16 components, + UInt16 restartFrequency, + const UInt16(& quantTableMap)[quantTableMapSize], + Memory(& quantTable)[quantTableSize], + const UInt16(& huffmanTableMap)[huffmanTableMapSize], + Memory(& huffmanDc)[huffmanDcSize], + Memory(& huffmanAc)[huffmanAcSize] + ) noexcept : + m_colorSpace(colorSpace), + m_subSampling(subSampling), + m_components(components), + m_restartFrequency(restartFrequency), + m_quantMap(quantTableMap), + m_huffmanMap(huffmanTableMap){ + + for (std::size_t i = 0; i < quantTableSize; i++){ + m_quantTable[i] = std::move(quantTable[i]); + } + + for (std::size_t i = 0; i < huffmanDcSize; i++){ + m_huffmanDc[i] = std::move(huffmanDc[i]); + } + + for (std::size_t i = 0; i < huffmanAcSize; i++){ + m_huffmanAc[i] = std::move(huffmanAc[i]); + } + } + + PixelType pixelType() const noexcept{ + return m_colorSpace; + } + + void setPixelType(PixelType pixelType) noexcept{ + m_colorSpace = pixelType; + } + + UInt32 subSampling() const noexcept{ + return m_subSampling; + } + + void setSubSampling(UInt32 subSampling) noexcept{ + m_subSampling = subSampling; + } + + UInt16 components() const noexcept{ + return m_components; + } + + void setComponents(UInt16 components) noexcept{ + m_components = components; + } + + UInt16 restartFrequency() const noexcept{ + return m_restartFrequency; + } + + void setRestartFrequency(UInt16 restartFrequency) noexcept{ + m_restartFrequency = restartFrequency; + } + + const UInt16Arr4& quantTableMap() const noexcept{ + return m_quantMap.array(); + } + + UInt16Arr4& quantTableMap() noexcept{ + return m_quantMap.array(); + } + + const MemoryArr4& quantTable() const noexcept{ + return m_quantTable; + } + + MemoryArr4& quantTable() noexcept{ + return m_quantTable; + } + + const UInt16Arr4& huffmanTableMap() const noexcept{ + return m_huffmanMap.array(); + } + + UInt16Arr4& huffmanTableMap() noexcept{ + return m_huffmanMap.array(); + } + + const MemoryArr2& huffmanDc() const noexcept{ + return m_huffmanDc; + } + + MemoryArr2& huffmanDc() noexcept{ + return m_huffmanDc; + } + + const MemoryArr2& huffmanAc() const noexcept{ + return m_huffmanAc; + } + + MemoryArr2& huffmanAc() noexcept{ + return m_huffmanAc; + } + +private: + PixelType m_colorSpace; + UInt32 m_subSampling; + UInt16 m_components; + UInt16 m_restartFrequency; + Detail::FixedArray m_quantMap; + MemoryArr4 m_quantTable; + Detail::FixedArray m_huffmanMap; + MemoryArr2 m_huffmanDc; + MemoryArr2 m_huffmanAc; + +}; +TWPP_DETAIL_PACK_END + +} + +#endif // TWPP_DETAIL_FILE_JPEGCOMPRESSION_HPP diff --git a/huagaotwain/twain/twpp/memory.hpp b/huagaotwain/twain/twpp/memory.hpp new file mode 100644 index 0000000..63859b1 --- /dev/null +++ b/huagaotwain/twain/twpp/memory.hpp @@ -0,0 +1,194 @@ +/* + +The MIT License (MIT) + +Copyright (c) 2015 Martin Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef TWPP_DETAIL_FILE_MEMORY_HPP +#define TWPP_DETAIL_FILE_MEMORY_HPP + +#include "../twpp.hpp" + +namespace Twpp { + +namespace Detail { + +namespace Flags { + +enum { + AppOwns = 0x0001, + DsmOwns = 0x0002, + DsOwns = 0x0004, + Pointer = 0x0008, + Handle = 0x0010 +}; + + +#if !defined(TWPP_IS_DS) +static constexpr const UInt32 thisOwns = AppOwns; +static constexpr const UInt32 otherOwns = DsOwns; +#else +static constexpr const UInt32 thisOwns = DsOwns; +static constexpr const UInt32 otherOwns = AppOwns; +#endif + +} + +} + +TWPP_DETAIL_PACK_BEGIN +/// Holds and potentially owns a block of memory using either pointer or handle. +class Memory { + +public: + typedef Detail::MaybeLock Data; + typedef Detail::MaybeLock ConstData; + + /// Creates an empty memory. + constexpr Memory() noexcept : + m_flags(0), m_size(0), m_data(nullptr){} + + /// Creates a memory block of supplied size. + /// \throw std::bad_alloc + explicit Memory(UInt32 size) : + m_flags(Detail::Flags::thisOwns | Detail::Flags::Handle), m_size(size), + m_data(Detail::alloc(size).raw()){} + + /// Creates a new memory object from Handle. + /// The memory ownership is taken over. + /// \param h The handle, see thisOwns for more information about memory ownership. + /// \param size Size of the memory in bytes, that handle h manages. + /// \param thisOwns { + /// If true, this object frees the memory once it goes out of scope. + /// + /// If false the memory is not freed, and MUST be passed to the other side + /// (APP->DS or DS->APP) of the connection, that will free it. + /// } + Memory(Handle h, UInt32 size, bool thisOwns = true) noexcept : + m_flags((thisOwns ? Detail::Flags::thisOwns : Detail::Flags::otherOwns) | Detail::Flags::Handle), + m_size(size), + m_data(h.raw()){} + + /// Creates a memory object from container. + /// The memory object does NOT take over the ownership of the data. + /// Make sure the container is destroyed after the memory object is. + template + explicit Memory(const Container& container) noexcept : + m_flags(Detail::Flags::thisOwns | Detail::Flags::Pointer), + m_size(sizeof(Container::value_type) * container.size()), + m_data(container.data()){} + + /// Creates a memory object from pointer. + /// The memory object does NOT take over the ownership of the data. + /// Make sure the data is destroyed after the memory object is. + constexpr Memory(void* data, UInt32 size) noexcept : + m_flags(Detail::Flags::thisOwns | Detail::Flags::Pointer), m_size(size), + m_data(data){} + + ~Memory(){ + freePriv(); + } + + Memory(const Memory& o) = delete; + Memory& operator=(const Memory& o) = delete; + + Memory(Memory&& o) noexcept : + m_flags(o.m_flags), m_size(o.m_size), m_data(o.m_data) + { + o.m_flags = 0; + o.m_size = 0; + o.m_data = nullptr; + } + + Memory& operator=(Memory&& o) noexcept{ + if (&o != this){ + freePriv(); + + m_flags = o.m_flags; + m_size = o.m_size; + m_data = o.m_data; + + o.m_flags = 0; + o.m_size = 0; + o.m_data = nullptr; + } + + return *this; + } + + /// The data in this memory block. + ConstData data() const noexcept{ + return m_flags & Detail::Flags::Handle ? + ConstData(Handle(static_cast(m_data))) : + ConstData(static_cast(m_data)); + } + + /// The data in this memory block. + Data data() noexcept{ + return m_flags & Detail::Flags::Handle ? + Data(Handle(static_cast(m_data))) : + Data(static_cast(m_data)); + } + + /// Number of bytes in the memory block. + UInt32 size() const noexcept{ + return m_size; + } + + /// In case of handle, frees memory regardless its owner; does nothing otherwise (pointer). + /// Potentially unsafe operation. + void free(){ + if (m_flags & Detail::Flags::Handle){ + Handle h(static_cast(m_data)); + if (h){ + Detail::free(h); + } + + m_size = 0; + m_data = nullptr; + m_flags = 0; + } + } + +private: + void freePriv(){ + if (m_flags & Detail::Flags::thisOwns){ + if (m_flags & Detail::Flags::Handle){ + Detail::free(Handle(static_cast(m_data))); + } + } + } + + UInt32 m_flags; + UInt32 m_size; + void* m_data; + +}; +TWPP_DETAIL_PACK_END + + + +} + +#endif // TWPP_DETAIL_FILE_MEMORY_HPP + diff --git a/huagaotwain/twain/twpp/memoryops.hpp b/huagaotwain/twain/twpp/memoryops.hpp new file mode 100644 index 0000000..abf499a --- /dev/null +++ b/huagaotwain/twain/twpp/memoryops.hpp @@ -0,0 +1,439 @@ +/* + +The MIT License (MIT) + +Copyright (c) 2015-2017 Martin Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef TWPP_DETAIL_FILE_MEMORYOPS_HPP +#define TWPP_DETAIL_FILE_MEMORYOPS_HPP + +#include "../twpp.hpp" + +namespace Twpp { + +namespace Detail { + +extern "C" { + +typedef Handle::Raw (TWPP_DETAIL_CALLSTYLE* MemAlloc)(UInt32 size); +typedef void (TWPP_DETAIL_CALLSTYLE* MemFree)(Handle::Raw handle); +typedef void* (TWPP_DETAIL_CALLSTYLE* MemLock)(Handle::Raw handle); +typedef void (TWPP_DETAIL_CALLSTYLE* MemUnlock)(Handle::Raw handle); + +} + +// templates behave as if they were defined in at most one module +// ideal for storing static data +template +struct GlobalMemFuncs { + +#if defined(TWPP_DETAIL_OS_WIN) + static Handle::Raw TWPP_DETAIL_CALLSTYLE defAlloc(UInt32 size){ + return ::GlobalAlloc(GHND, size); + } + + static void TWPP_DETAIL_CALLSTYLE defFree(Handle::Raw handle){ + ::GlobalFree(handle); + } + + static void* TWPP_DETAIL_CALLSTYLE defLock(Handle::Raw handle){ + return ::GlobalLock(handle); + } + + static void TWPP_DETAIL_CALLSTYLE defUnlock(Handle::Raw handle){ + ::GlobalUnlock(handle); + } +#elif defined(TWPP_DETAIL_OS_MAC) + static Handle::Raw TWPP_DETAIL_CALLSTYLE defAlloc(UInt32 size){ + return ::NewHandle(size); + } + + static void TWPP_DETAIL_CALLSTYLE defFree(Handle::Raw handle){ + ::DisposeHandle(handle); + } + + static void* TWPP_DETAIL_CALLSTYLE defLock(Handle::Raw handle){ + return *handle; + } + + static void TWPP_DETAIL_CALLSTYLE defUnlock(Handle::Raw){ + // noop + } +#elif !defined(TWPP_DETAIL_OS_LINUX) // Linux doesnt need default functions +# error "default memory functions for your platform here" +#endif + + static MemAlloc alloc; + static MemFree free; + static MemLock lock; + static MemUnlock unlock; + +#if defined(TWPP_IS_DS) + static Handle doNotFreeHandle; +#endif + +}; + +#if defined(TWPP_DETAIL_OS_WIN) || defined(TWPP_DETAIL_OS_MAC) +template +MemAlloc GlobalMemFuncs::alloc = GlobalMemFuncs::defAlloc; + +template +MemFree GlobalMemFuncs::free = GlobalMemFuncs::defFree; + +template +MemLock GlobalMemFuncs::lock = GlobalMemFuncs::defLock; + +template +MemUnlock GlobalMemFuncs::unlock = GlobalMemFuncs::defUnlock; +#elif defined(TWPP_DETAIL_OS_LINUX) +template +MemAlloc GlobalMemFuncs::alloc = nullptr; + +template +MemFree GlobalMemFuncs::free = nullptr; + +template +MemLock GlobalMemFuncs::lock = nullptr; + +template +MemUnlock GlobalMemFuncs::unlock = nullptr; +#else +# error "default memory functions setup for your platform here" +#endif + +#if defined(TWPP_IS_DS) + template + Handle GlobalMemFuncs::doNotFreeHandle; +#endif + +inline static void setMemFuncs(MemAlloc alloc, MemFree free, MemLock lock, MemUnlock unlock) noexcept{ + GlobalMemFuncs::alloc = alloc; + GlobalMemFuncs::free = free; + GlobalMemFuncs::lock = lock; + GlobalMemFuncs::unlock = unlock; +} + +inline static void resetMemFuncs() noexcept{ +#if defined(TWPP_DETAIL_OS_WIN) || defined(TWPP_DETAIL_OS_MAC) + GlobalMemFuncs::alloc = GlobalMemFuncs::defAlloc; + GlobalMemFuncs::free = GlobalMemFuncs::defFree; + GlobalMemFuncs::lock = GlobalMemFuncs::defLock; + GlobalMemFuncs::unlock = GlobalMemFuncs::defUnlock; +#elif defined(TWPP_DETAIL_OS_LINUX) + GlobalMemFuncs::alloc = nullptr; + GlobalMemFuncs::free = nullptr; + GlobalMemFuncs::lock = nullptr; + GlobalMemFuncs::unlock = nullptr; +#else +# error "resetMemFuncs for your platform here" +#endif +} + +inline static Handle alloc(UInt32 size){ + auto h = GlobalMemFuncs::alloc(size); + if (!h){ + throw std::bad_alloc(); + } + + return Handle(h); +} + +inline static void* lock(Handle handle) noexcept{ + return GlobalMemFuncs::lock(handle.raw()); +} + +inline static void unlock(Handle handle) noexcept{ + GlobalMemFuncs::unlock(handle.raw()); +} + +inline static void free(Handle handle) noexcept{ + GlobalMemFuncs::free(handle.raw()); +} + +template +static inline T* typeLock(Handle handle) noexcept{ + return static_cast(lock(handle)); +} + +/// A lock that can contain either handle or raw pointer. +/// Locks and unlocks handle, noop for pointer. +template +class MaybeLock { + +public: + constexpr MaybeLock() noexcept : + m_handle(), m_pointer(nullptr){} + + MaybeLock(Handle h) noexcept : + m_handle(h), m_pointer(typeLock(h)){} + + constexpr MaybeLock(T* ptr) noexcept : + m_handle(), m_pointer(ptr){} + + ~MaybeLock(){ + unlock(); + } + + MaybeLock(const MaybeLock& o) noexcept : + m_handle(o.m_handle), m_pointer(o.m_handle ? typeLock(o.m_handle) : o.m_pointer){} + + MaybeLock& operator=(const MaybeLock& o) noexcept{ + if (&o != this){ + unlock(); + + m_handle = o.m_handle; + m_pointer = m_handle ? typeLock(m_handle) : o.m_pointer; + } + + return *this; + } + + + MaybeLock(MaybeLock&& o) noexcept : + m_handle(o.m_handle), m_pointer(o.m_pointer){ + + o.m_handle = Handle(); + o.m_pointer = nullptr; + } + + MaybeLock& operator=(MaybeLock&& o) noexcept{ + if (&o != this){ + unlock(); + + m_handle = o.m_handle; + m_pointer = o.m_pointer; + + o.m_handle = Handle(); + o.m_pointer = nullptr; + } + + return *this; + } + + T* data() const noexcept{ + return m_pointer; + } + + operator T*() const noexcept{ + return m_pointer; + } + + T* operator->() noexcept{ + return m_pointer; + } + + T* operator->() const noexcept{ + return m_pointer; + } + + bool hasData() const noexcept{ + return m_pointer; + } + + operator bool() const noexcept{ + return m_pointer; + } + +private: + void unlock() noexcept{ + if (m_handle){ + Detail::unlock(m_handle); + } + } + + Handle m_handle; + T* m_pointer; + +}; + +/// Simple handle lock. +/// Locks on creation and unlocks on destruction. +template +class Lock { + +public: + constexpr Lock() noexcept : + m_handle(), m_pointer(nullptr){} + + Lock(Handle h) noexcept : + m_handle(h), m_pointer(typeLock(h)){} + + ~Lock(){ + unlock(); + } + + + Lock(const Lock& o) noexcept : + m_handle(o.m_handle), m_pointer(typeLock(o.m_handle)){} + + Lock& operator=(const Lock& o) noexcept{ + if (&o != this){ + unlock(); + + m_handle = o.m_handle; + m_pointer = typeLock(m_handle); + } + + return *this; + } + + + Lock(Lock&& o) noexcept : + m_handle(o.m_handle), m_pointer(o.m_pointer){ + + o.m_handle = Handle(); + o.m_pointer = nullptr; + } + + Lock& operator=(Lock&& o) noexcept{ + if (&o != this){ + unlock(); + + m_handle = o.m_handle; + m_pointer = o.m_pointer; + + o.m_handle = Handle(); + o.m_pointer = nullptr; + } + + return *this; + } + + + T* data() const noexcept{ + return m_pointer; + } + + operator T*() const noexcept{ + return m_pointer; + } + + T* operator->() noexcept{ + return m_pointer; + } + + T* operator->() const noexcept{ + return m_pointer; + } + + bool hasData() const noexcept{ + return m_pointer; + } + + operator bool() const noexcept{ + return m_pointer; + } + +private: + void unlock() noexcept{ + if (m_handle){ + Detail::unlock(m_handle); + } + } + + Handle m_handle; + T* m_pointer; + +}; + +/// Owns a handle and frees it upon destruction, +/// unless `release` is called beforehand. +class UniqueHandle { + +public: + constexpr UniqueHandle(Handle h = Handle()) noexcept : + m_handle(h){} + + ~UniqueHandle(){ + free(); + } + + UniqueHandle(const UniqueHandle&) = delete; + UniqueHandle& operator=(const UniqueHandle&) = delete; + + UniqueHandle(UniqueHandle&& o) noexcept : + m_handle(o.m_handle){ + + o.m_handle = Handle(); + } + + UniqueHandle& operator=(UniqueHandle&& o) noexcept{ + if (&o != this){ + free(); + + m_handle = o.m_handle; + + o.m_handle = Handle(); + } + + return *this; + } + + operator bool() const noexcept{ + return m_handle; + } + + /// The contained handle. + Handle get() noexcept{ + return m_handle; + } + + /// The contained handle. + Handle get() const noexcept{ + return m_handle; + } + + /// Releases the contained handle, making the user responsible for freeing it. + Handle release() noexcept{ + Handle ret = m_handle; + m_handle = Handle(); + return ret; + } + + template + Lock lock() const{ + return m_handle; + } + +private: + void free() noexcept{ +#if defined(TWPP_IS_DS) + if (m_handle && m_handle != GlobalMemFuncs::doNotFreeHandle){ +#else + if (m_handle){ +#endif + Detail::free(m_handle); + } + } + + Handle m_handle; + +}; + +} + +} + +#endif // TWPP_DETAIL_FILE_MEMORYOPS_HPP + diff --git a/huagaotwain/twain/twpp/palette8.hpp b/huagaotwain/twain/twpp/palette8.hpp new file mode 100644 index 0000000..71a05bc --- /dev/null +++ b/huagaotwain/twain/twpp/palette8.hpp @@ -0,0 +1,145 @@ +/* + +The MIT License (MIT) + +Copyright (c) 2015 Martin Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef TWPP_DETAIL_FILE_PALETTE8_HPP +#define TWPP_DETAIL_FILE_PALETTE8_HPP + +#include "../twpp.hpp" + + +namespace Twpp { + +namespace Detail { + +// specialization for Element8 +// we also want to set index of the element when placing it inside array +template +struct FixedArrayData > { + + static constexpr Element8 updateIndex(UInt8 index, const Element8& e) noexcept{ + return Element8(index, e.channel1(), e.channel2(), e.channel3()); + } + + template + constexpr FixedArrayData(const Element8(& arr)[inputSize]) noexcept : + m_arr{updateIndex(i, FixedArrayFlat(arr)[i])...}{} + + constexpr FixedArrayData() noexcept : + m_arr{Element8(i)...}{} + + Element8 m_arr[arraySize]; + +}; + +} + + +TWPP_DETAIL_PACK_BEGIN +/// Palette information for memory transfers +class Palette8 { + +public: + enum class Type : UInt16 { + Rgb = 0, + Gray = 1, + Cmy = 2 + }; + + typedef Element8 Element8Arr256[256]; + + /// Creates an uninitialized palette. + constexpr Palette8() noexcept : + m_size(0), m_type(Type::Rgb), m_colors(){} + + /// Creates a palette with the supplied type and elements. + template + constexpr Palette8(Type type, const Element8(& colors)[inputSize]) noexcept : + m_size(inputSize), m_type(type), + m_colors(colors){ + + static_assert(inputSize <= 256, "too many colors"); + } + + /// Creates a palette with the supplied type and elements from container. + /// \throw RangeException When there are more than 256 colors. + template + Palette8(Type type, const Container& colors) : + m_size(static_cast(colors.size())), m_type(type){ + + if (colors.size() > 256){ + throw RangeException(); + } + + auto& array = m_colors.array(); + for (UInt16 i = 0; i < m_size; i++){ + array[i] = colors[i]; + array[i].setIndex(i); + } + } + + /// Creates a palette with the supplied type and elements. + /// \throw RangeException When there are more than 256 colors. + Palette8(Type type, const Element8* colors, UInt16 size) : + m_size(size), m_type(type){ + + if (m_size > 256){ + throw RangeException(); + } + + auto& array = m_colors.array(); + for (UInt16 i = 0; i < m_size; i++){ + array[i] = colors[i]; + array[i].setIndex(static_cast(i)); // 0..255 max + } + } + + /// Number of elements in the palette. + constexpr UInt16 size() const noexcept{ + return m_size; + } + + /// Type of palette data. + constexpr Type type() const noexcept{ + return m_type; + } + + /// Array of palette elements. + constexpr const Element8Arr256& colors() const noexcept{ + return m_colors.array(); + } + +private: + UInt16 m_size; + Type m_type; + Detail::FixedArray m_colors; + +}; +TWPP_DETAIL_PACK_END + +} + +#endif // TWPP_DETAIL_FILE_PALETTE8_HPP + diff --git a/huagaotwain/twain/twpp/passthrough.hpp b/huagaotwain/twain/twpp/passthrough.hpp new file mode 100644 index 0000000..49c33fd --- /dev/null +++ b/huagaotwain/twain/twpp/passthrough.hpp @@ -0,0 +1,126 @@ +/* + +The MIT License (MIT) + +Copyright (c) 2015 Martin Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef TWPP_DETAIL_FILE_PASSTHROUGH_HPP +#define TWPP_DETAIL_FILE_PASSTHROUGH_HPP + +#include "../twpp.hpp" + +namespace Twpp { + +TWPP_DETAIL_PACK_BEGIN +/// Structure for raw comminication with device in source. +/// See manual for more information, DAT_PASSTHRU, MSG_PASSTHRU. +class PassThrough { + +public: + enum class Direction : Int32 { + Get = 1, + Set = 2 + }; + + constexpr PassThrough( + void* command, + UInt32 commandSize, + Direction direction, + void* data, + UInt32 dataSize, + UInt32 dataXfered + ) noexcept : + m_cmd(command), m_cmdSize(commandSize), + m_direction(direction), + m_data(data), m_dataSize(dataSize), m_dataXfered(dataXfered){} + + constexpr void* command() const noexcept{ + return m_cmd; + } + + constexpr UInt32 commandSize() const noexcept{ + return m_cmdSize; + } + + template + void setCommand(const Container& command) noexcept{ + m_cmd = command.data(); + m_cmdSize = sizeof(Container::value_type) * command.size(); + } + + void setCommand(void* command, UInt32 size) noexcept{ + m_cmd = command; + m_cmdSize = size; + } + + constexpr Direction direction() const noexcept{ + return m_direction; + } + + void setDirection(Direction direction) noexcept{ + m_direction = direction; + } + + constexpr void* data() const noexcept{ + return m_data; + } + + constexpr UInt32 dataSize() const noexcept{ + return m_dataSize; + } + + template + void setData(const Container& data) noexcept{ + m_data = data.data(); + m_dataSize = sizeof(Container::value_type) * data.size(); + m_dataXfered = 0; + } + + void setData(void* data, UInt32 dataSize) noexcept{ + m_data = data; + m_dataSize = dataSize; + m_dataXfered = 0; + } + + constexpr UInt32 dataXfered() const noexcept{ + return m_dataXfered; + } + + void setDataXfered(Int32 dataXfered) noexcept{ + m_dataXfered = dataXfered; + } + +private: + void* m_cmd; + UInt32 m_cmdSize; + Direction m_direction; + void* m_data; + UInt32 m_dataSize; + UInt32 m_dataXfered; + +}; +TWPP_DETAIL_PACK_END + +} + +#endif // TWPP_DETAIL_FILE_PASSTHROUGH_HPP diff --git a/huagaotwain/twain/twpp/pendingxfers.hpp b/huagaotwain/twain/twpp/pendingxfers.hpp new file mode 100644 index 0000000..9ba875b --- /dev/null +++ b/huagaotwain/twain/twpp/pendingxfers.hpp @@ -0,0 +1,86 @@ +/* + +The MIT License (MIT) + +Copyright (c) 2015 Martin Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef TWPP_DETAIL_FILE_PENDINGXFERS_HPP +#define TWPP_DETAIL_FILE_PENDINGXFERS_HPP + +#include "../twpp.hpp" + +namespace Twpp { + +TWPP_DETAIL_PACK_BEGIN +/// Reports number of pending images, transfers. +class PendingXfers { + +public: + /// Job control settings. + enum class JobPatch : UInt32 { + None = 0x0000, + MidSeparator = 0x0001, + P1 = 0x0002, + P2 = 0x0003, + P3 = 0x0004, + P4 = 0x0005, + P6 = 0x0006, + PT = 0x0007 + }; + + /// Creates object to report number of pending transfers. + /// \param count Number of pending transfers. + /// \param patch Job control settings. + constexpr PendingXfers(UInt16 count = 0, JobPatch patch = JobPatch::None) noexcept : + m_count(count), m_eoj(patch){} + + /// Number of pending images/transfers. + constexpr UInt16 count() const noexcept{ + return m_count; + } + + /// Sets number of pending images/transfers. + void setCount(UInt16 count) noexcept{ + m_count = count; + } + + /// Job control settings. + constexpr JobPatch jobPatch() const noexcept{ + return m_eoj; + } + + /// Sets job control settings. + void setJobPatch(JobPatch eoj) noexcept{ + m_eoj = eoj; + } + +private: + UInt16 m_count; + JobPatch m_eoj; + +}; +TWPP_DETAIL_PACK_END + +} + +#endif // TWPP_DETAIL_FILE_PENDINGXFERS_HPP diff --git a/huagaotwain/twain/twpp/setupfilexfer.hpp b/huagaotwain/twain/twpp/setupfilexfer.hpp new file mode 100644 index 0000000..f4a4a2f --- /dev/null +++ b/huagaotwain/twain/twpp/setupfilexfer.hpp @@ -0,0 +1,103 @@ +/* + +The MIT License (MIT) + +Copyright (c) 2015-2017 Martin Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef TWPP_DETAIL_FILE_SETUPFILEXFER_HPP +#define TWPP_DETAIL_FILE_SETUPFILEXFER_HPP + +#include "../twpp.hpp" + +namespace Twpp { + +TWPP_DETAIL_PACK_BEGIN +/// Structure for setting up file transfer. +class SetupFileXfer { + +public: + /// Creates zero-initialized instance. + constexpr SetupFileXfer() noexcept : + m_format(ImageFileFormat::Tiff), m_volRefNum(0){} + + /// Creates instance with set file path and format. + /// And volume reference number on Mac OS. + /// \param filePath Path to transfered file. + /// \param format File format. + /// \param vrn Volume reference number. Mac OS only. + constexpr SetupFileXfer( + const Str255& filePath, + ImageFileFormat format, + Int16 vrn +#if defined(TWPP_DETAIL_OS_WIN) || defined(TWPP_DETAIL_OS_LINUX) + = -1 +#elif !defined(TWPP_DETAIL_OS_MAC) +# error "Volume reference number for your platform here" +#endif + ) noexcept : + m_filePath(filePath), m_format(format), + m_volRefNum(vrn){} + + /// Path to transfered file. + constexpr const Str255& filePath() const noexcept{ + return m_filePath; + } + + /// Sets path to transfered file. + void setFilePath(const Str255& filePath) noexcept{ + m_filePath = filePath; + } + + /// Format of the transfered file. + constexpr ImageFileFormat format() const noexcept{ + return m_format; + } + + /// Sets format of the transfered file. + void setFormat(ImageFileFormat format) noexcept{ + m_format = format; + } + + /// Volume reference number. + /// Mac OS only. + constexpr Int16 volumeReferenceNumber() const noexcept{ + return m_volRefNum; + } + + /// Sets volume reference number. + /// Mac OS only. + void setVolumeReferenceNumber(Int16 volumeReferenceNumber) noexcept{ + m_volRefNum = volumeReferenceNumber; + } + +private: + Str255 m_filePath; + ImageFileFormat m_format; + Int16 m_volRefNum; + +}; +TWPP_DETAIL_PACK_END + +} + +#endif // TWPP_DETAIL_FILE_SETUPFILEXFER_HPP diff --git a/huagaotwain/twain/twpp/setupmemxfer.hpp b/huagaotwain/twain/twpp/setupmemxfer.hpp new file mode 100644 index 0000000..e645f68 --- /dev/null +++ b/huagaotwain/twain/twpp/setupmemxfer.hpp @@ -0,0 +1,92 @@ +/* + +The MIT License (MIT) + +Copyright (c) 2015 Martin Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef TWPP_DETAIL_FILE_SETUPMEMXFER_HPP +#define TWPP_DETAIL_FILE_SETUPMEMXFER_HPP + +#include "../twpp.hpp" + +namespace Twpp { + +TWPP_DETAIL_PACK_BEGIN +/// Structure for setting up memory transfer. +class SetupMemXfer { + +public: + /// Creates zero-initialized instance. + constexpr SetupMemXfer() noexcept : + m_minSize(0), m_maxSize(0), m_prefSize(0){} + + /// Creates an initialized instance with set minimal, maximal and preferred sizes. + /// Must be true, or the behaviour is undefined: minSize <= preferredSize <= maxSize + constexpr SetupMemXfer( + UInt32 minSize, + UInt32 maxSize, + UInt32 preferredSize + ) noexcept : + m_minSize(minSize), m_maxSize(maxSize), m_prefSize(preferredSize){} + + /// Minimal supported buffer size in bytes. + constexpr UInt32 minSize() const noexcept{ + return m_minSize; + } + + /// Sets minimal supported buffer size in bytes. + void setMinSize(UInt32 minSize) noexcept{ + m_minSize = minSize; + } + + /// Maximal supported buffer size in bytes. + constexpr UInt32 maxSize() const noexcept{ + return m_maxSize; + } + + /// Sets maximal supported buffer size in bytes. + void setMaxSize(UInt32 maxSize) noexcept{ + m_maxSize = maxSize; + } + + /// Preferred buffer size in bytes. + constexpr UInt32 preferredSize() const noexcept{ + return m_prefSize; + } + + /// Sets preferred buffer size in bytes. + void setPreferredSize(UInt32 prefSize) noexcept{ + m_prefSize = prefSize; + } + +private: + UInt32 m_minSize; + UInt32 m_maxSize; + UInt32 m_prefSize; + +}; +TWPP_DETAIL_PACK_END + +} + +#endif // TWPP_DETAIL_FILE_SETUPMEMXFER_HPP diff --git a/huagaotwain/twain/twpp/status.hpp b/huagaotwain/twain/twpp/status.hpp new file mode 100644 index 0000000..7d72a5f --- /dev/null +++ b/huagaotwain/twain/twpp/status.hpp @@ -0,0 +1,230 @@ +/* + +The MIT License (MIT) + +Copyright (c) 2015 Martin Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef TWPP_DETAIL_FILE_STATUS_HPP +#define TWPP_DETAIL_FILE_STATUS_HPP + +#include "../twpp.hpp" + +namespace Twpp { + +TWPP_DETAIL_PACK_BEGIN +/// Additional status information about a performed TWAIN operation. +class Status { + +public: + /// Creates operation status. + /// \param cond Status condition code. + /// \param data Additional status data, source-specific. + constexpr Status(CC cond = CC::Success, UInt16 data = 0) noexcept : + m_cond(cond), m_data(data){} + + /// Status condition code. + constexpr CC condition() const noexcept{ + return m_cond; + } + + /// Sets status condition code. + void setCondition(CC cc) noexcept{ + m_cond = cc; + } + + /// Aditional status data, source-specific. + constexpr UInt16 data() const noexcept{ + return m_data; + } + + /// Sets aditional status data, source-specific. + void setData(UInt16 data) noexcept{ + m_data = data; + } + + constexpr operator CC() const noexcept{ + return m_cond; + } + + constexpr operator bool() const noexcept{ + return success(m_cond); + } + + constexpr bool operator==(CC o) const noexcept{return m_cond == o;} + constexpr bool operator!=(CC o) const noexcept{return m_cond != o;} + + constexpr bool operator==(Status o) const noexcept{return m_cond == o.m_cond && m_data == o.m_data;} + constexpr bool operator!=(Status o) const noexcept{return m_cond != o.m_cond || m_data != o.m_data;} + + +private: + CC m_cond; + UInt16 m_data; + +}; + +static inline constexpr bool success(Status stat) noexcept{ + return stat; +} + +/// Structure for translating status to UTF8 text. +class StatusUtf8 { + +public: + typedef Detail::Lock ConstString; + + + /// Creates a status utf8 without string data. + StatusUtf8(Status status = Status()) noexcept : + m_status(status), m_size(0), m_string(){} + + /// Creates a status utf8 containing copy of string data. + /// The string must be null-terminated. + /// \tparam inputSize Size of the string including null terminator. + /// \param str The string, must be null-terminated. + /// \throw std::bad_alloc + template + StatusUtf8(Status status, const char(& str)[inputSize]) : + m_status(status), m_size(inputSize), m_string(Detail::alloc(inputSize)){ + + std::copy(str, str + inputSize, string().data()); + } + + /// Creates a new status utf8 containing a copy of the supplied string. + /// \param status + /// \param str Utf-8 string to copy, must be null-terminated. + /// \throw RangeException When string is too long, could not insert null terminator. + /// \throw std::bad_alloc + StatusUtf8(Status status, const char* str) : + m_status(status), m_size(0), m_string(){ + + auto len = strlen(str); + if (len >= std::numeric_limits::max()){ + throw RangeException(); + } + + m_size = static_cast(len) + 1; + m_string = Detail::alloc(m_size); + std::copy(str, str + len + 1, m_string.lock().data()); + } + + /// Creates a new status utf8 containing a copy of the supplied string. + /// \param status + /// \param str Utf-8 string to copy. + /// \throw RangeException When string is too long, could not insert null terminator. + /// \throw std::bad_alloc + StatusUtf8(Status status, const std::string& str) : + m_status(status), m_size(0), m_string(){ + + auto len = str.length(); + if (len >= std::numeric_limits::max()){ + throw RangeException(); + } + + m_size = static_cast(len) + 1; + m_string = Detail::alloc(m_size); + + auto lock = m_string.lock(); + std::copy(str.cbegin(), str.cend(), lock.data()); + lock[len] = '\0'; + } + + /// Creates a new StatusUtf8 containing a copy of the supplied string. + /// \param status + /// \param str Utf-8 string to copy, null terminator is not required. + /// \param strSize {Number of bytes to copy including null terminator. + /// Null terminator is inserted automatically.} + /// \throw RangeException When string is too short to satisfy the requested size. + /// \throw std::bad_alloc + StatusUtf8(Status status, const char* str, UInt32 strSize) : + m_status(status), m_size(0), m_string(){ + + auto len = strlen(str); + if (len < strSize){ + throw RangeException(); + } + + m_size = static_cast(strSize) + 1; + m_string = Detail::alloc(m_size); + + auto lock = m_string.lock(); + std::copy(str, str + strSize, lock.data()); + lock[strSize] = '\0'; + } + + StatusUtf8(const StatusUtf8&) = delete; + StatusUtf8& operator=(const StatusUtf8&) = delete; + + StatusUtf8(StatusUtf8&& o) noexcept : + m_status(o.m_status), m_size(o.m_size), m_string(std::move(o.m_string)){ + + o.m_status = Status(); + o.m_size = 0; + } + + StatusUtf8& operator=(StatusUtf8&& o) noexcept{ + if (&o != this){ + m_status = o.m_status; + m_size = o.m_size; + m_string = std::move(o.m_string); + + o.m_status = Status(); + o.m_size = 0; + } + + return *this; + } + + /// Returns the interpreted status. + Status status() const noexcept{ + return m_status; + } + + /// Sets the status to be interpreted. + void setStatus(Status status) noexcept{ + m_status = status; + } + + /// Returns the total number of bytes including null byte. + UInt32 size() const noexcept{ + return m_string ? m_size : 0; + } + + /// The UTF8 string itself. + ConstString string() const noexcept{ + return m_string.lock(); + } + +private: + Status m_status; + UInt32 m_size; + Detail::UniqueHandle m_string; + +}; + +TWPP_DETAIL_PACK_END + +} + +#endif // TWPP_DETAIL_FILE_STATUS_HPP + diff --git a/huagaotwain/twain/twpp/strings.hpp b/huagaotwain/twain/twpp/strings.hpp new file mode 100644 index 0000000..8698402 --- /dev/null +++ b/huagaotwain/twain/twpp/strings.hpp @@ -0,0 +1,310 @@ +/* + +The MIT License (MIT) + +Copyright (c) 2015-2017 Martin Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef TWPP_DETAIL_FILE_STRINGS_HPP +#define TWPP_DETAIL_FILE_STRINGS_HPP + +#include "../twpp.hpp" + +namespace Twpp { + +namespace Detail { + +// specialization for twain strings +// on mac os, these strings do not contain null terminator +// instead, the first byte contains the length +template +struct FixedArrayData > { + + template + constexpr FixedArrayData(const char(& arr)[inputSize]) noexcept : + m_arr{ +#if defined(TWPP_DETAIL_OS_MAC) + unsignedToSigned(inputSize - 1), +#elif !defined(TWPP_DETAIL_OS_WIN) && !defined(TWPP_DETAIL_OS_LINUX) +# error "string data setup for yout platform here" +#endif + FixedArrayFlat(arr)[i]... + }{} + + constexpr FixedArrayData() noexcept : + m_arr(){} + + char m_arr[arraySize]; + +}; + +// specialization for twain strings +// on mac os, these strings do not contain null terminator +// instead, the first byte contains the length +// so we provide one less index for the fixed array +// on windows, its element is zero-initialized due to it not being specified +// on mac os, the first byte contains the length, so the index is not used anyway +template +struct FixedArray : public FixedArrayData::Result> { + + typedef FixedArrayData::Result> ParentType; + typedef char Array[arraySize]; + + constexpr FixedArray() noexcept : + ParentType(){} + + template + constexpr FixedArray(const char(& arr)[inputSize]) noexcept : + ParentType(arr){ + + static_assert(inputSize <= arraySize, "string literal is too long"); + } + + constexpr const Array& array() const noexcept{ + return ParentType::m_arr; + } + + Array& array() noexcept{ + return ParentType::m_arr; + } + +}; + +/// TWAIN string template. +/// \tparam arraySize String capacity, including either null byte, or length byte (Mac OS). +template +class Str : private FixedArray{ + + typedef FixedArray DataType; + +public: + typedef const char* const_iterator; + typedef char* iterator; + + /// Maximal number of characters this string may hold. + /// Excluding null byte (length byte). + static constexpr UInt32 maxSize() noexcept{ + return arraySize - 1; + } + + static_assert(maxSize() <= std::numeric_limits::max(), "string type exceeds allowed sizes"); + + + /// Creates an empty, zero-initialized string. + constexpr Str() noexcept{} + + /// Creates a compile-time string from string literal (or char array). + /// \tparam inputSize Size of the string literal including null terminator. + /// \param str The string literal. + template + constexpr Str(const char(& str)[inputSize]) noexcept : + DataType(str){ + + static_assert(inputSize <= arraySize, "string literal is too long"); + } + + /// Alias to length(). + constexpr UInt32 size() const noexcept{ + return length(); + } + + /// Length of the string (number of 8-bit characters). + /// O(1) on Mac OS, O(n) anywhere else. + constexpr UInt32 length() const noexcept{ +#if defined(TWPP_DETAIL_OS_MAC) + return static_cast(this->array()[0]); +#elif defined(TWPP_DETAIL_OS_WIN) || defined(TWPP_DETAIL_OS_LINUX) + return strLen(data()); +#else +# error "String::length for your platform here" +#endif + } + + /// Pointer to constant data. + /// On Mac OS, the data is NOT null-terminated, + /// and points to the first character after size byte. + /// This operation is unsafe, and its use may not be platform-independent. + constexpr const char* data() const noexcept{ +#if defined(TWPP_DETAIL_OS_MAC) + return this->array() + 1; +#elif defined(TWPP_DETAIL_OS_WIN) || defined(TWPP_DETAIL_OS_LINUX) + return this->array(); +#else +# error "String::data for your platform here" +#endif + } + + /// Pointer to data. + /// On Mac OS, the data is NOT null-terminated, + /// and points to the first character after size byte. + /// This operation is unsafe, and its use may not be platform-independent. + char* data() noexcept{ +#if defined(TWPP_DETAIL_OS_MAC) + return this->array() + 1; +#elif defined(TWPP_DETAIL_OS_WIN) || defined(TWPP_DETAIL_OS_LINUX) + return this->array(); +#else +# error "String::data for your platform here" +#endif + } + + /// Sets string data. + /// Copies as much data as possible, discarding the rest. + /// The data needn't be null terminated. + /// \param str Data to copy. + /// \param size Maximal number of bytes to copy. + /// \return Number of bytes copied - the new length of this string. + UInt32 setData(const char* data, UInt32 size) noexcept{ + char* arr = this->data(); + UInt32 i = 0; + + auto maxLen = std::min(maxSize(), size); + for ( ; i < maxLen && *data; i++, data++){ + arr[i] = *data; + } + +#if defined(TWPP_DETAIL_OS_MAC) + *reinterpret_cast(this->array()) = static_cast(i); +#elif defined(TWPP_DETAIL_OS_WIN) || defined(TWPP_DETAIL_OS_LINUX) + arr[i] = '\0'; +#else +# error "String::setData for your platform here" +#endif + + return i; + } + + /// Sets string data. + /// Copies as much data as possible, discarding the rest. + /// The string must be null terminated. + /// \param str String to copy. + /// \return Number of characters copied - the new length of this string. + UInt32 setData(const char* str) noexcept{ + return setData(str, maxSize()); + } + + /// Sets string data from container (e.g. std::string). + /// Copies as much data as possible, discarding the rest. + /// The string needn't be null terminated. + /// \tparam Contaier Container type. + /// \param cont Container with data to be copied. + /// \return Number of characters copied - the new length of this string. + template::value>::type> + UInt32 setData(const Container& cont) noexcept{ + return setData(cont.data(), static_cast(std::min(cont.size(), maxSize()))); + } + + char operator[](UInt32 i) const noexcept{ + return data()[i]; + } + + char& operator[](UInt32 i) noexcept{ + return data()[i]; + } + + iterator begin() noexcept{ + return data(); + } + + constexpr const_iterator begin() const noexcept{ + return cbegin(); + } + + constexpr const_iterator cbegin() const noexcept{ + return data(); + } + + iterator end() noexcept{ + return data() + length(); + } + + constexpr const_iterator end() const noexcept{ + return cend(); + } + + constexpr const_iterator cend() const noexcept{ + return data() + length(); + } + + std::string string() const{ + return std::string(cbegin(), cend()); + } + +}; + +} + +template +constexpr bool operator==(const Detail::Str& a, const Detail::Str& b) noexcept{ + // length() is O(1) on mac os, O(n) anywhere else +#if defined(TWPP_DETAIL_OS_MAC) + return a.length() == b.length() && Detail::strCmp(a.data(), b.data()) == 0; +#elif defined(TWPP_DETAIL_OS_WIN) || defined(TWPP_DETAIL_OS_LINUX) + return Detail::strCmp(a.data(), b.data()) == 0; +#else +# error "String equals operator for your platform here" +#endif + +} + +template +constexpr bool operator<(const Detail::Str& a, const Detail::Str& b) noexcept{ + return Detail::strCmp(a.data(), b.data()) < 0; +} + +template +constexpr bool operator>(const Detail::Str& a, const Detail::Str& b) noexcept{ + return Detail::strCmp(a.data(), b.data()) > 0; +} + +template +constexpr bool operator!=(const Detail::Str& a, const Detail::Str& b) noexcept{ + return !(a == b); +} + +template +constexpr bool operator<=(const Detail::Str& a, const Detail::Str& b) noexcept{ + return !(a > b); +} + +template +constexpr bool operator>=(const Detail::Str& a, const Detail::Str& b) noexcept{ + return !(a < b); +} + +/// TWAIN string that can contain up to 33 characters (bytes). +typedef Detail::Str<34> Str32; + +/// TWAIN string that can contain up to 65 characters (bytes). +typedef Detail::Str<66> Str64; + +/// TWAIN string that can contain up to 129 characters (bytes). +typedef Detail::Str<130> Str128; + +/// TWAIN string that can contain up to 255 characters (bytes). +typedef Detail::Str<256> Str255; + +} + + +#endif // TWPP_DETAIL_FILE_STRINGS_HPP + diff --git a/huagaotwain/twain/twpp/twglue.hpp b/huagaotwain/twain/twpp/twglue.hpp new file mode 100644 index 0000000..be5b549 --- /dev/null +++ b/huagaotwain/twain/twpp/twglue.hpp @@ -0,0 +1,17 @@ +#ifndef TWGLUE_HPP +#define TWGLUE_HPP + +#include +// #include "Device/PublicFunc.h" + +struct TwGlue { + + TwGlue(const std::function& scan, const std::function& cancel) : + m_scan(scan), m_cancel(cancel){} + + std::function m_scan; + std::function m_cancel; + +}; + +#endif // TWGLUE_HPP diff --git a/huagaotwain/twain/twpp/types.hpp b/huagaotwain/twain/twpp/types.hpp new file mode 100644 index 0000000..ef01d75 --- /dev/null +++ b/huagaotwain/twain/twpp/types.hpp @@ -0,0 +1,88 @@ +/* + +The MIT License (MIT) + +Copyright (c) 2015 Martin Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef TWPP_DETAIL_FILE_TYPES_HPP +#define TWPP_DETAIL_FILE_TYPES_HPP + +#include "../twpp.hpp" + +namespace Twpp { + +TWPP_DETAIL_PACK_BEGIN +typedef std::uintptr_t UIntPtr; +typedef std::uint8_t UInt8; +typedef std::uint16_t UInt16; +typedef std::uint32_t UInt32; +typedef std::int8_t Int8; +typedef std::int16_t Int16; +typedef std::int32_t Int32; + +/// Boolean value. +/// Implemented as a class to provide better type safety. +class Bool { + +public: + constexpr Bool(bool value = false) noexcept : + m_value(value){} + + constexpr operator bool() const noexcept{ + return m_value != 0; + } + +private: + Int16 m_value; + +}; + +/// Handle to memory area. +/// Implemented as a class to provide better type safety. +class Handle { + +public: + typedef Detail::RawHandle Raw; + + constexpr explicit Handle(Raw raw = Raw()) noexcept : + m_raw(raw){} + + /// Underlying OS-dependent handle. + constexpr Raw raw() const noexcept{ + return m_raw; + } + + constexpr operator bool() const noexcept{ + return m_raw != Raw(); + } + +private: + Raw m_raw; + +}; +TWPP_DETAIL_PACK_END + +} + +#endif // TWPP_DETAIL_FILE_TYPES_HPP + diff --git a/huagaotwain/twain/twpp/typesops.hpp b/huagaotwain/twain/twpp/typesops.hpp new file mode 100644 index 0000000..3c187fd --- /dev/null +++ b/huagaotwain/twain/twpp/typesops.hpp @@ -0,0 +1,149 @@ +/* + +The MIT License (MIT) + +Copyright (c) 2015 Martin Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef TWPP_DETAIL_FILE_TYPESOPS_HPP +#define TWPP_DETAIL_FILE_TYPESOPS_HPP + +#include "../twpp.hpp" + +namespace Twpp { + +/// Enumeration representing basic types. +enum class Type : UInt16 { + DontCare = 0xFFFF, + Int8 = 0x0000, + Int16 = 0x0001, + Int32 = 0x0002, + UInt8 = 0x0003, + UInt16 = 0x0004, + UInt32 = 0x0005, + Bool = 0x0006, + Fix32 = 0x0007, + Frame = 0x0008, + Str32 = 0x0009, + Str64 = 0x000a, + Str128 = 0x000b, + Str255 = 0x000c, + Handle = 0x000f +}; + +/// Whether the enum value actually is a type, DontCare is not a type. +static inline bool isType(Type type){ + switch (type){ + case Type::Int8: + case Type::UInt8: + case Type::Int16: + case Type::UInt16: + case Type::Int32: + case Type::UInt32: + case Type::Bool: + case Type::Fix32: + case Type::Str32: + case Type::Str64: + case Type::Str128: + case Type::Str255: + case Type::Frame: + case Type::Handle: + return true; + + default: + return false; + } +} + +/// Size in bytes of a type represented by enum value. +static inline UInt32 typeSize(Type type){ + switch (type){ + case Type::Int8: return sizeof(Int8); + case Type::UInt8: return sizeof(UInt8); + case Type::Int16: return sizeof(Int16); + case Type::UInt16: return sizeof(UInt16); + case Type::Int32: return sizeof(Int32); + case Type::UInt32: return sizeof(UInt32); + case Type::Bool: return sizeof(Bool); + case Type::Fix32: return sizeof(Fix32); + case Type::Str32: return sizeof(Str32); + case Type::Str64: return sizeof(Str64); + case Type::Str128: return sizeof(Str128); + case Type::Str255: return sizeof(Str255); + case Type::Frame: return sizeof(Frame); + case Type::Handle: return sizeof(Handle); + default: throw TypeException(); + } +} + +namespace Detail { + +/// Conversion from Type enum to actual data type. +template struct Twty {}; +template<> struct Twty {typedef Int8 Type;}; +template<> struct Twty {typedef Int16 Type;}; +template<> struct Twty {typedef Int32 Type;}; +template<> struct Twty {typedef UInt8 Type;}; +template<> struct Twty {typedef UInt16 Type;}; +template<> struct Twty {typedef UInt32 Type;}; +template<> struct Twty {typedef Bool Type;}; +template<> struct Twty {typedef Fix32 Type;}; +template<> struct Twty {typedef Frame Type;}; +template<> struct Twty {typedef Str32 Type;}; +template<> struct Twty {typedef Str64 Type;}; +template<> struct Twty {typedef Str128 Type;}; +template<> struct Twty {typedef Str255 Type;}; +template<> struct Twty {typedef Handle Type;}; + + +// Conversion from data type to Type enum helpers. +template struct Tytw; + +template // true +struct TytwHelper : Tytw::type> {}; + +template +struct TytwHelper {}; + +/// Conversion from data type to Type enum. +template struct Tytw : TytwHelper::value> {}; +template<> struct Tytw {static constexpr const Type twty = Type::Int8;}; +template<> struct Tytw {static constexpr const Type twty = Type::Int16;}; +template<> struct Tytw {static constexpr const Type twty = Type::Int32;}; +template<> struct Tytw {static constexpr const Type twty = Type::UInt8;}; +template<> struct Tytw {static constexpr const Type twty = Type::UInt16;}; +template<> struct Tytw {static constexpr const Type twty = Type::UInt32;}; +template<> struct Tytw {static constexpr const Type twty = Type::Bool;}; +template<> struct Tytw {static constexpr const Type twty = Type::Fix32;}; +template<> struct Tytw {static constexpr const Type twty = Type::Frame;}; +template<> struct Tytw {static constexpr const Type twty = Type::Str32;}; +template<> struct Tytw {static constexpr const Type twty = Type::Str64;}; +template<> struct Tytw {static constexpr const Type twty = Type::Str128;}; +template<> struct Tytw {static constexpr const Type twty = Type::Str255;}; +template<> struct Tytw {static constexpr const Type twty = Type::Handle;}; + +} + +} + +#endif // TWPP_DETAIL_FILE_TYPESOPS_HPP + diff --git a/huagaotwain/twain/twpp/userinterface.hpp b/huagaotwain/twain/twpp/userinterface.hpp new file mode 100644 index 0000000..ba42bcd --- /dev/null +++ b/huagaotwain/twain/twpp/userinterface.hpp @@ -0,0 +1,79 @@ +/* + +The MIT License (MIT) + +Copyright (c) 2015-2017 Martin Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef TWPP_DETAIL_FILE_USERINTERFACE_HPP +#define TWPP_DETAIL_FILE_USERINTERFACE_HPP + +#include "../twpp.hpp" + +namespace Twpp { + +TWPP_DETAIL_PACK_BEGIN +/// Structure holding parameters for enabling or disabling data source. +class UserInterface { + +public: + /// Creates a new UserInterface. + /// \param showUi Whether to show internal DS GUI. Disabling DS GUI might not be supported. + /// \param modalUi Whether DS GUI should be modal. Not used on Linux. Might not be supported on Windows. + /// \param parent Windows-only, others set to null. Handle to parent window. This object does NOT take ownership. +#if defined(TWPP_DETAIL_OS_WIN) + constexpr UserInterface(Bool showUi, Bool modalUi, Handle parent) noexcept : + m_showUi(showUi), m_modalUi(modalUi), m_parent(parent){} +#elif defined(TWPP_DETAIL_OS_MAC) || defined(TWPP_DETAIL_OS_LINUX) + constexpr UserInterface(Bool showUi, Bool modalUi, Handle parent = Handle()) noexcept : + m_showUi(showUi), m_modalUi(modalUi), m_parent(parent){} +#else +# error "UserInterface constructor for your platform here" +#endif + + /// Whether to show internal DS GUI. + constexpr Bool showUi() const noexcept{ + return m_showUi; + } + + /// Whether DS GUI should be modal + constexpr Bool modalUi() const noexcept{ + return m_modalUi; + } + + /// Handle to parent window. + constexpr Handle parent() const noexcept{ + return m_parent; + } + +private: + Bool m_showUi; + Bool m_modalUi; + Handle m_parent; + +}; +TWPP_DETAIL_PACK_END + +} + +#endif // TWPP_DETAIL_FILE_USERINTERFACE_HPP + diff --git a/huagaotwain/twain/twpp/utils.hpp b/huagaotwain/twain/twpp/utils.hpp new file mode 100644 index 0000000..5eb122c --- /dev/null +++ b/huagaotwain/twain/twpp/utils.hpp @@ -0,0 +1,485 @@ +/* + +The MIT License (MIT) + +Copyright (c) 2015 Martin Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#ifndef TWPP_DETAIL_FILE_UTILS_HPP +#define TWPP_DETAIL_FILE_UTILS_HPP + +#undef max +#undef min +#include +#include "../twpp.hpp" + +namespace Twpp { + +namespace Detail { + +/// Creates a template for testing whether a class contains public static method. +/// Use this macro anywhere a class may be defined, and pass method name +/// as its parameter. Then use `HasStaticMethod_` template. +/// +/// E. g.: +/// TWPP_DETAIL_CREATE_HAS_STATIC_METHOD(myMethod) // <- semicolon not required +/// HasStaticMethod_myMethod::value +/// +/// This test whether `MyClass` has static method `void MyClass::myMethod(int, char)`. +/// That is whether you may do this: +/// MyClass::myMethod(10, 'a'); +#define TWPP_DETAIL_CREATE_HAS_STATIC_METHOD(methodName) \ + template\ + class HasStaticMethod_ ## methodName;\ + \ + template\ + class HasStaticMethod_ ## methodName {\ + \ + template\ + static constexpr auto test(U*) ->\ + typename std::is_same()...)), Ret>::type;\ + \ + template\ + static constexpr std::false_type test(...);\ + \ + public:\ + typedef decltype(test(0)) type;\ + static constexpr const bool value = type::value;\ + \ + }; + +/// Creates a template for testing whether a class contains public method. +/// Use this macro anywhere a class may be defined, and pass method name +/// as its parameter. Then use `HasMethod_` template. +/// +/// E. g.: +/// TWPP_DETAIL_CREATE_HAS_METHOD(myMethod) // <- semicolon not required +/// HasMethod_myMethod::value +/// +/// This test whether `MyClass` has method (AKA member function) `void MyClass::myMethod(int, char)`. +/// That is whether you may do this: +/// MyClass o ... ; +/// o.myMethod(10, 'a'); +#define TWPP_DETAIL_CREATE_HAS_METHOD(methodName) \ + template\ + class HasMethod_ ## methodName;\ + \ + template\ + class HasMethod_ ## methodName {\ + \ + template\ + static constexpr auto test(U*) ->\ + typename std::is_same().methodName(std::declval()...)), Ret>::type;\ + \ + template\ + static constexpr std::false_type test(...);\ + \ + public:\ + typedef decltype(test(0)) type;\ + static constexpr const bool value = type::value;\ + \ + }; + +/// Performs a pointer type cast, suppresses strict aliasing warnings. +/// \tparam T Type of the returned pointer. Must be pointer type (e.g. `char*`). +/// \param ptr Pointer to be cast. +/// \return Cast pointer. +template +static constexpr inline T alias_cast(void* ptr) noexcept{ + return reinterpret_cast(ptr); +} + +/// Performs a constant pointer type cast, suppresses strict aliasing warnings. +/// \tparam T Type of the returned pointer. Must be pointer type (e.g. `char*`). +/// \param ptr Pointer to be cast. +/// \return Cast pointer. +template +static constexpr inline T alias_cast(const void* ptr) noexcept{ + return reinterpret_cast(ptr); +} + +/// Suppresses warnings about unused parameters or arguments. +/// \tparam Args List of argument types. No need to specify explicitly. +template +static inline void unused(const Args& ...) noexcept{} + + + +// CODE FROM http://www.macieira.org/blog/2011/07/initialising-an-array-with-cx0x-using-constexpr-and-variadic-templates/ +// BEGIN +template struct IndexList {}; + +template struct Append; +template +struct Append, Right>{ typedef IndexList Result; }; + +template struct Indexes { + typedef typename Append::Result, N - 1>::Result Result; +}; +template<> struct Indexes<0> { typedef IndexList<> Result; }; +// END + +/// Converts an array of arbitary size to array-like recursive structure of fixed size (at compile time). +/// Provide template specialization if special handling of elements is required, and you do care +/// about their positions - otherwise see FixedArrayData below. +/// \tparam T Element type. +/// \tparam arraySize Number of elements in the fixed array. +template +struct FixedArrayFlat : FixedArrayFlat { + + /// The index this structure (with this `arraySize`) holds. + static constexpr const std::size_t g_index = arraySize - 1; + + /// Performs the conversion from arbiraty-size array to fixed-size structure. + /// We use left recursion to initialize values of all inherited structures first. + /// Then the value of this one is initialized, either copied from the input array itself, + /// or default-initialized in case the array is not large enough. + /// \tparam inputSize {Size of the input array. If smaller than the fixed array, + /// excessive elements are default-initialized (may be changed in specializations). + /// Providing larger array results in undefined behaviour.} + /// \param arr The arbitary-size array. + template + constexpr inline FixedArrayFlat(const T(& arr)[inputSize]) noexcept : + FixedArrayFlat(arr), m_val(g_index < inputSize ? arr[g_index] : T()){} + + /// Returns value contained at specific index. + /// If the index if smaller than the size of the input array, a value is returned + /// as if the operation was performed on that array. Otherwise a default value + /// of the type `T` is returned (or anything else a specialization provides). + /// Behaviour of this operator is undefined if the index equals to or is greater than + /// the size of the fixed array. + /// \param i Value index. + /// \return Value at index. + constexpr inline T operator[](std::size_t i) const noexcept{ + return i == g_index ? m_val : FixedArrayFlat::operator [](i); + } + + /// Value held by this structure. + T m_val; + +}; + +/// Converts an array of arbitary size to array-like recursive structure of fixed size (at compile time). +/// This template specialization terminates the recursion. +/// No need to provide any further specializations. +/// \tparam T Element type. +template +struct FixedArrayFlat { + + template + constexpr inline FixedArrayFlat(const T(&)[inputSize]) noexcept{} + + constexpr inline T operator[](std::size_t) const noexcept{ + return T(); + } + +}; + + +/// Converts an array of arbitary size to array of fixed size at compile time. +/// The job itself is done in the specialization below. +/// \tparam T Element type. +/// \tparam arraySize Number of elements in the fixed array. +/// \tparam IndexList Type holding indexes of the fixed array. +template +struct FixedArrayData {}; + +/// Converts an array of arbitary size to array of fixed size at compile time. +/// Provide template specialization if special handling of elements is required, and you +/// don't care about their positions. +/// \tparam T Element type. +/// \tparam arraySize Number of elements in the fixed array. +/// \tparam i Indexes of the fixed array. +template +struct FixedArrayData > { + + /// Performs the conversion from arbiraty-size array to fixed-size array. + /// Uses FixedArrayFlat to extend the input array to desired size. + /// \tparam inputSize Size of the input array. + /// \param arr The input array. + template + constexpr FixedArrayData(const T(& arr)[inputSize]) noexcept : + m_arr{FixedArrayFlat(arr)[i]...}{} + + /// Creates default-initialized array. + constexpr FixedArrayData() noexcept : + m_arr(){} + + /// The fixed array. + T m_arr[arraySize]; + +}; + +/// Compile-time constructible fixed-size array of type `T` and length `arraySize`. +/// The array can be constructed from variable-sized array +/// of up to `arraySize` elements at compile time. +/// \tparam T Element type. +/// \tparam arraySize Number of elements in the array. +template +struct FixedArray : public FixedArrayData::Result> { + + typedef FixedArrayData::Result> ParentType; + typedef T Array[arraySize]; + + /// Creates default-initialized array. + constexpr FixedArray() noexcept : + ParentType(){} + + /// Creates fixed-size array from variable-size array at compile time. + /// If the size of input array exceeds `arraySize`, a compile-time error is emited. + /// \tparam inputSize Number of elements of the input array. + /// \param arr The input array. + template + constexpr FixedArray(const T(& arr)[inputSize]) noexcept : + ParentType(arr){ + + static_assert(inputSize <= arraySize, "array literal is too big"); + } + + /// The contained array. + constexpr const Array& array() const noexcept{ + return ParentType::m_arr; + } + + /// The contained array. + Array& array() noexcept{ + return ParentType::m_arr; + } + +}; + +/// Joins two arrays at compile time. +/// The job itself is done in the specialization below. +/// \tparam T Element type. +/// \tparam lenA Size of the first array. +/// \tparam lenB Size of the second array. +/// \tparam IndexList Type holding indexes of the resulting array. +template +struct ArrayJoinData {}; + +/// Joins two arrays at compile time. +/// The result of this operation is an array that contains all the elements +/// from the first array immediately followed by all the elements from +/// the second array. +/// \tparam T Element type. +/// \tparam lenA Size of the first array. +/// \tparam lenB Size of the second array. +/// \tparam i Indexes of the resulting array. +template +struct ArrayJoinData > { + + /// Performs the join operation. + /// \param a The first array. + /// \param b The second array. + constexpr ArrayJoinData(const T(& a)[lenA], const T(& b)[lenB]) noexcept : + m_arr{(i < lenA ? a[i] : b[i - lenA])...}{} + + /// The resulting array. + T m_arr[lenA + lenB]; + +}; + +/// Compile-time join operation of two arrays of the same type. +/// \tparam T Element type. +/// \tparam lenA Size of the first array. +/// \tparam lenB Size of the second array. +template +struct ArrayJoin : public ArrayJoinData::Result> { + + typedef ArrayJoinData::Result> ParentType; + typedef T Array[lenA + lenB]; + + /// Performs the join operation. + /// \param a The first array. + /// \param b The second array. + constexpr ArrayJoin(const T(& a)[lenA], const T(& b)[lenB]) noexcept : + ParentType(a, b){} + + /// The joined array. + constexpr const Array& array() const noexcept{ + return ParentType::m_arr; + } + + /// The joined array. + Array& array() noexcept{ + return ParentType::m_arr; + } + +}; + +/// Performs compile-time array join operation. +/// This is a helper function, see ArrayJoin and ArrayJoinData for more info. +/// \tparam T Element type. +/// \tparam lenA Size of the first array. +/// \tparam lenB Size of the second array. +/// \param a The first array. +/// \param b The second array. +/// \return The joined array. +template +static constexpr inline ArrayJoin arrayJoin(const T(& a)[lenA], const T(& b)[lenB]) noexcept{ + return {a, b}; +} + + +/// The loop that checks the suffix at compile time, see endsWith below. +/// Checks are performed from right to left. +/// \tparam T Element type. +/// \tparam arrLen The size of the array to be checked for the suffix. +/// \tparam subLen The size of the suffix array. +/// \param arr The array to be checked for the suffix. +/// \param sub The suffix array. +/// \param endOff Offset from the last element to be checked in this call. +/// \return Whether the suffix is contained. +template +static constexpr inline bool endsWithLoop(const T(& arr)[arrLen], const T(& sub)[subLen], std::size_t endOff){ + return endOff >= subLen || (arr[arrLen - 1 - endOff] == sub[subLen - 1 - endOff] && endsWithLoop(arr, sub, endOff + 1)); +} + +/// Checks whether the input array contains supplied suffix at compile time. +/// \tparam T Element type. +/// \tparam arrLen The size of the array to be checked for the suffix. +/// \tparam subLen The size of the suffix array. +/// \param arr The array to be checked for the suffix. +/// \param sub The suffix array. +/// \return Whether the suffix is contained. +template +static constexpr inline bool endsWith(const T(& arr)[arrLen], const T(& sub)[subLen]){ + return arrLen >= subLen && endsWithLoop(arr, sub, 0); +} + +/// Implementation of compile-time C string length. +/// Uses tail recursion. +/// \param str The string, or its remaining part. +/// \param len Length of the previous, already processed, part of the string. +/// \return Length of the string. +static constexpr inline std::size_t strLenImpl(const char* str, std::size_t len = 0) noexcept{ + return *str == '\0' ? len : strLenImpl(str + 1, len + 1); +} + +/// Compile-time C string length. +/// \param str The string. +/// \return Length of the string. +static constexpr inline std::size_t strLen(const char* str) noexcept{ + return strLenImpl(str); +} + + +/// Unsigned to signed conversion, using static_cast. +/// Available only if integers are represented using 2 complement. +/// Specialization handles non-2 complement cases. +/// \tparam T An integral type. +/// \tparam _2complement Whether ints are represented as 2 complement. +template // true +struct UnsigToSig { + typedef typename std::make_signed::type Signed; + typedef typename std::make_unsigned::type Unsigned; + + static constexpr Signed convert(Unsigned val) noexcept{ + return static_cast(val); + } +}; + +/// Unsigned to signed conversion. +/// This specialization is used when architecture does not use 2 complement. +/// \tparam T An integral type. +template +struct UnsigToSig { + typedef typename std::make_signed::type Signed; + typedef typename std::make_unsigned::type Unsigned; + + static constexpr Signed convert(Unsigned val) noexcept{ + return val <= std::numeric_limits::max() ? + static_cast(val) : + static_cast(val - std::numeric_limits::min()) + std::numeric_limits::min(); + } +}; + +/// Converts, at compile time, an unsigned integer to its signed counterpart. +/// This holds true: unsignedValue == static_cast(unsignedToSigned(unsignedValue)) +/// \tparam T Unsigned integral type. +/// \param val Unsigned value to be converted to signed. +/// \return Signed value that can be converted back to its unsigned type. +template::value>::type> +static constexpr inline typename std::make_signed::type unsignedToSigned(T val) noexcept{ + typedef typename std::make_signed::type Signed; + typedef typename std::make_unsigned::type Unsigned; + + return UnsigToSig(-1) == static_cast(~Unsigned(0))>::convert(val); +} + +/// Compares two C strings at compile time as if strcmp was used. +/// \param a First string. +/// \param b Second string. +/// \return See strcmp. +static constexpr inline int strCmp(const char* a, const char* b) noexcept{ + return *a != *b ? (static_cast(*a) - *b) : (*a == '\0' ? 0 : strCmp(a + 1, b + 1)); +} + +/// Absolute value. +/// Default implementation handles signed values +/// of non-integral types. +/// \tparam T Data type. +/// \tparam integral Whether the type is integral. +/// \tparam unsig Whether the data type is unsigned. +template // false, false +struct Abs { + static constexpr inline T abs(T a) noexcept{ + return a >= T() ? a : -a; + } +}; + +/// Absolute value. +/// This handles signed values of integral types. +/// \tparam T Data type. +template +struct Abs { + static constexpr inline T abs(T a) noexcept{ + return std::abs(a); + } +}; + +/// Absolute value. +/// This handles unsigned values. +/// \tparam T Data type. +template +struct Abs { + static constexpr inline T abs(T a) noexcept{ + return a; + } +}; + +/// Absolute value. +/// Handles anything that has `bool operator >=(const T&)` (or equiv.), +/// `T operator-()`, and its default value represents `zero`. +/// \tparam T Data type. +/// \param a Value. +template +static constexpr inline T abs(T a) noexcept{ + return Abs::value, std::is_unsigned::value>::abs(a); +} + +} + +} + +#endif // TWPP_DETAIL_FILE_UTILS_HPP + diff --git a/huagaotwain/ui.cpp b/huagaotwain/ui.cpp new file mode 100644 index 0000000..7c9c779 --- /dev/null +++ b/huagaotwain/ui.cpp @@ -0,0 +1,77 @@ +#include "pch.h" +#include "ui.h" + +#include "huagaotwain.h" // for sane_invoker::load_dll + + +twain_ui::twain_ui(const wchar_t* path) : path_(path), dll_(NULL) + , show_(NULL), hide_(NULL), event_(NULL), hui_(NULL) + , good_(false) +{ + good_ = load(); +} +twain_ui::~twain_ui() +{ + if (hui_ && hide_) + hide_(hui_); + + if (dll_) + FreeLibrary(dll_); +} + +bool twain_ui::load() +{ + std::wstring dll(path_ + L"\\huagaoui.dll"); + + sane_invoker::load_dll(dll.c_str(), &dll_); + if (!dll_) + return false; + + show_ = (ui_show_api)GetProcAddress(dll_, "ui_show"); + hide_ = (ui_hide_api)GetProcAddress(dll_, "ui_hide"); + event_ = (handle_event_api)GetProcAddress(dll_, "handle_event"); + + return show_ && hide_ && event_; +} + +void twain_ui::show_main_ui(LPSANEAPI api) +{ + type_ = UITYPE::UI_MAIN; + if (show_) + hui_ = show_(UITYPE::UI_MAIN, api); +} +void twain_ui::show_setting_ui(LPSANEAPI api, bool with_scan) +{ + if (show_) + { + type_ = with_scan ? UITYPE::UI_SETTING_AND_SCAN : UITYPE::UI_SETTING; + hui_ = show_(type_, api); + } +} +void twain_ui::show_progress_ui(LPSANEAPI api) +{ + type_ = UITYPE::UI_PROGRESS; + if (show_) + hui_ = show_(UITYPE::UI_PROGRESS, api); +} +void twain_ui::hide_ui(void) +{ + if (hui_ && hide_) + hide_(hui_); + hui_ = NULL; +} +void twain_ui::handle_sane_event(int sane_ev, void* data, unsigned int* len) +{ + if (event_) + event_((SANE_Event)sane_ev, data, len); +} + +bool twain_ui::is_ok(void) +{ + return good_; +} + +bool twain_ui::is_progress_ui_showing(void) +{ + return type_ == UITYPE::UI_PROGRESS; +} \ No newline at end of file diff --git a/huagaotwain/ui.h b/huagaotwain/ui.h new file mode 100644 index 0000000..3cd151a --- /dev/null +++ b/huagaotwain/ui.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#include +#include "huagao/huagao_ui.h" + + +class twain_ui +{ + HMODULE dll_; + ui_show_api show_; + ui_hide_api hide_; + handle_event_api event_; + ui_handle hui_; + std::wstring path_; + bool good_; + UITYPE type_; + + bool load(void); + +public: + twain_ui(const wchar_t* path); + ~twain_ui(); + +public: + void show_main_ui(LPSANEAPI api); + void show_setting_ui(LPSANEAPI api, bool with_scan); + void show_progress_ui(LPSANEAPI api); + void hide_ui(void); + void handle_sane_event(int sane_ev, void* data, unsigned int* len); + + bool is_ok(void); + bool is_progress_ui_showing(void); +}; diff --git a/protocol/hgsane.vcxproj b/protocol/hgsane.vcxproj new file mode 100644 index 0000000..b315be4 --- /dev/null +++ b/protocol/hgsane.vcxproj @@ -0,0 +1,222 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {6eec8a02-7f98-4422-8ed6-2434d43bd1e1} + hgsane + 10.0 + hgsane + + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + false + v142 + true + Unicode + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)..\..\sdk\include;$(SolutionDir)..\..\device\include\;$(IncludePath) + $(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\;$(LibraryPath) + $(SolutionDir)..\..\tmp\$(PlatformTarget)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)..\..\release\win\$(PlatformTarget)\$(Configuration)\ + + + false + $(SolutionDir)..\..\sdk\include;$(SolutionDir)..\..\device\include\;$(IncludePath) + $(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\;$(LibraryPath) + $(SolutionDir)..\..\tmp\$(PlatformTarget)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)..\..\release\win\$(PlatformTarget)\$(Configuration)\ + + + true + $(SolutionDir)..\..\release\win\$(PlatformTarget)\$(Configuration)\ + $(SolutionDir)..\..\tmp\$(PlatformTarget)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)..\..\sdk\include;$(SolutionDir)..\..\device\include\;$(IncludePath) + $(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\;$(LibraryPath) + + + false + $(SolutionDir)..\..\release\win\$(PlatformTarget)\$(Configuration)\ + $(SolutionDir)..\..\tmp\$(PlatformTarget)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)..\..\sdk\include;$(SolutionDir)..\..\device\include\;$(IncludePath) + $(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\;$(LibraryPath) + + + + Level3 + true + BACKEND_NAME=hgsane;TWPP_IS_DS;EXPORT_SANE_API;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp17 + 4996 + + + Console + true + %(AdditionalDependencies) + $(ProjectDir)sane.def + + + mkdir $(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration) +move /Y "$(OutDirFullPath)$(ProjectName).exp" "$(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration)" +move /Y "$(OutDirFullPath)$(ProjectName).lib" "$(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration)" +move /Y "$(OutDirFullPath)$(ProjectName).pdb" "$(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration)" + + + + + + Level3 + true + true + true + BACKEND_NAME=hgsane;TWPP_IS_DS;EXPORT_SANE_API;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp17 + 4996 + + + Console + true + true + true + %(AdditionalDependencies) + $(ProjectDir)sane.def + + + mkdir $(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration) +move /Y "$(OutDirFullPath)$(ProjectName).exp" "$(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration)" +move /Y "$(OutDirFullPath)$(ProjectName).lib" "$(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration)" +move /Y "$(OutDirFullPath)$(ProjectName).pdb" "$(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration)" + + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + mkdir $(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration) +move /Y "$(OutDirFullPath)$(ProjectName).exp" "$(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration)" +move /Y "$(OutDirFullPath)$(ProjectName).lib" "$(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration)" +move /Y "$(OutDirFullPath)$(ProjectName).pdb" "$(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration)" + + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + mkdir $(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration) +move /Y "$(OutDirFullPath)$(ProjectName).exp" "$(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration)" +move /Y "$(OutDirFullPath)$(ProjectName).lib" "$(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration)" +move /Y "$(OutDirFullPath)$(ProjectName).pdb" "$(SolutionDir)..\..\sdk\lib\win\$(PlatformTarget)\$(Configuration)" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/protocol/hgsane.vcxproj.filters b/protocol/hgsane.vcxproj.filters new file mode 100644 index 0000000..dbda086 --- /dev/null +++ b/protocol/hgsane.vcxproj.filters @@ -0,0 +1,80 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + + + 源文件 + + + \ No newline at end of file diff --git a/protocol/sane.def b/protocol/sane.def new file mode 100644 index 0000000..afbaa6e --- /dev/null +++ b/protocol/sane.def @@ -0,0 +1,19 @@ +LIBRARY hgsane +EXPORTS + sane_hgsane_init + sane_hgsane_exit + sane_hgsane_get_devices + sane_hgsane_open + sane_hgsane_close + sane_hgsane_get_option_descriptor + sane_hgsane_control_option + sane_hgsane_get_parameters + sane_hgsane_start + sane_hgsane_read + sane_hgsane_cancel + sane_hgsane_set_io_mode + sane_hgsane_get_select_fd + sane_hgsane_strstatus + sane_hgsane_init_ex + sane_hgsane_io_control + hg_debug_log \ No newline at end of file diff --git a/sln/hgscanner.sln b/sln/hgscanner.sln new file mode 100644 index 0000000..139bbc3 --- /dev/null +++ b/sln/hgscanner.sln @@ -0,0 +1,52 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.32106.194 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hgscanner", "..\device\hgscanner.vcxproj", "{9ED4B425-73E0-423E-9712-455E777481B4}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hgsane", "..\protocol\hgsane.vcxproj", "{6EEC8A02-7F98-4422-8ED6-2434D43BD1E1}" + ProjectSection(ProjectDependencies) = postProject + {9ED4B425-73E0-423E-9712-455E777481B4} = {9ED4B425-73E0-423E-9712-455E777481B4} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "huagaotwain", "..\huagaotwain\huagaotwain.vcxproj", "{C3B47CE2-27CE-4509-AB59-3C0F194F0FCE}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9ED4B425-73E0-423E-9712-455E777481B4}.Debug|x64.ActiveCfg = Debug|x64 + {9ED4B425-73E0-423E-9712-455E777481B4}.Debug|x64.Build.0 = Debug|x64 + {9ED4B425-73E0-423E-9712-455E777481B4}.Debug|x86.ActiveCfg = Debug|Win32 + {9ED4B425-73E0-423E-9712-455E777481B4}.Debug|x86.Build.0 = Debug|Win32 + {9ED4B425-73E0-423E-9712-455E777481B4}.Release|x64.ActiveCfg = Release|x64 + {9ED4B425-73E0-423E-9712-455E777481B4}.Release|x64.Build.0 = Release|x64 + {9ED4B425-73E0-423E-9712-455E777481B4}.Release|x86.ActiveCfg = Release|Win32 + {9ED4B425-73E0-423E-9712-455E777481B4}.Release|x86.Build.0 = Release|Win32 + {6EEC8A02-7F98-4422-8ED6-2434D43BD1E1}.Debug|x64.ActiveCfg = Debug|x64 + {6EEC8A02-7F98-4422-8ED6-2434D43BD1E1}.Debug|x64.Build.0 = Debug|x64 + {6EEC8A02-7F98-4422-8ED6-2434D43BD1E1}.Debug|x86.ActiveCfg = Debug|Win32 + {6EEC8A02-7F98-4422-8ED6-2434D43BD1E1}.Debug|x86.Build.0 = Debug|Win32 + {6EEC8A02-7F98-4422-8ED6-2434D43BD1E1}.Release|x64.ActiveCfg = Release|x64 + {6EEC8A02-7F98-4422-8ED6-2434D43BD1E1}.Release|x64.Build.0 = Release|x64 + {6EEC8A02-7F98-4422-8ED6-2434D43BD1E1}.Release|x86.ActiveCfg = Release|Win32 + {6EEC8A02-7F98-4422-8ED6-2434D43BD1E1}.Release|x86.Build.0 = Release|Win32 + {C3B47CE2-27CE-4509-AB59-3C0F194F0FCE}.Debug|x64.ActiveCfg = Debug|Win32 + {C3B47CE2-27CE-4509-AB59-3C0F194F0FCE}.Debug|x86.ActiveCfg = Debug|Win32 + {C3B47CE2-27CE-4509-AB59-3C0F194F0FCE}.Debug|x86.Build.0 = Debug|Win32 + {C3B47CE2-27CE-4509-AB59-3C0F194F0FCE}.Release|x64.ActiveCfg = Release|Win32 + {C3B47CE2-27CE-4509-AB59-3C0F194F0FCE}.Release|x86.ActiveCfg = Release|Win32 + {C3B47CE2-27CE-4509-AB59-3C0F194F0FCE}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {A89068FF-95C4-3C1E-B126-70B66C9824BB} + EndGlobalSection +EndGlobal