add dsm component and adjust directories

This commit is contained in:
gb 2023-07-14 11:35:50 +08:00
parent 05788d91f1
commit 8fc62ad16f
28 changed files with 11207 additions and 22 deletions

View File

@ -220,10 +220,13 @@ echo Make your choice, plz:
read choice
if [ "$choice" == "y" ] || [ "$choice" == "Y" ]; then
cd ../code_device/twain
cd ../code_device/twain/dsm
./build.sh $docpath $cpu
cd ../ds
for pid in ${devpids[@]}
do
./build.sh $oem $pid
./build.sh $oem $pid "nocopy"
done
cd ../
fi

View File

@ -103,6 +103,7 @@ extern "C"
utils::to_log(LOG_LEVEL_DEBUG, "Module device: [%u.%u.%u.%u] - %s\n", VERSION_MAJOR, VERSION_MINOR, VERSION_YEAR, GET_BUILD_VER, scanner.c_str());
utils::to_log(LOG_LEVEL_DEBUG, "Module sane : [%s] - %s\n", g_sane_ver.c_str(), sane.c_str());
utils::to_log(LOG_LEVEL_DEBUG, "Module exe : %s\n", (pe + name).c_str());
utils::to_log(LOG_LEVEL_DEBUG, "Current Path : %s\n", utils::get_command_result("pwd").c_str());
if (lang_initialize() == -1)
{

View File

@ -10,8 +10,8 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -fvisibility=hidden")
aux_source_directory(${PROJECT_SOURCE_DIR} DIR_SRCS)
# add_subdirectory(twain)
file(GLOB DIR_HEADS "${PROJECT_SOURCE_DIR}/*.h" "${PROJECT_SOURCE_DIR}/*.hpp" "${PROJECT_SOURCE_DIR}/*.cpp"
"${PROJECT_SOURCE_DIR}/../sdk/hginclude/*.h"
"${PROJECT_SOURCE_DIR}/../sdk/hginclude/*.cpp"
"${PROJECT_SOURCE_DIR}/../../sdk/hginclude/*.h"
"${PROJECT_SOURCE_DIR}/../../sdk/hginclude/*.cpp"
)
set(DIR_SRCS ${DIR_SRCS} ${DIR_HEADS})
@ -24,20 +24,20 @@ link_libraries(dl)
# )
target_include_directories(${PROJECT_NAME} PRIVATE ${PROJECT_SOURCE_DIR}
${PROJECT_SOURCE_DIR}/../sdk/hginclude
${PROJECT_SOURCE_DIR}/../../sdk/include
${PROJECT_SOURCE_DIR}/../../sdk/include/huagao
${PROJECT_SOURCE_DIR}/../../sdk/include/twain
${PROJECT_SOURCE_DIR}/../../sdk/include/twain/twpp
${PROJECT_SOURCE_DIR}/../../sdk/hginclude
${PROJECT_SOURCE_DIR}/../../../sdk/include
${PROJECT_SOURCE_DIR}/../../../sdk/include/huagao
${PROJECT_SOURCE_DIR}/../../../sdk/include/twain
${PROJECT_SOURCE_DIR}/../../../sdk/include/twain/twpp
)
target_link_directories(${PROJECT_NAME} PRIVATE ${PROJECT_SOURCE_DIR}
${PROJECT_SOURCE_DIR}/../../release/kylin/x86_64)
${PROJECT_SOURCE_DIR}/../../../release/kylin/x86_64)
target_link_libraries(${PROJECT_NAME} PRIVATE
pthread
usb-1.0
)
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/../../release/kylin/x86_64)
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/../../../release/kylin/x86_64)

View File

@ -60,11 +60,11 @@ echo origin path is $origin_dir
if [ -f ../../build/twain/Makefile ]; then
echo ""
else
mkdir ../../build
mkdir ../../build/twain
mkdir ../../../build
mkdir ../../../build/twainds
fi
cd ../../build/twain
cd ../../../build/twainds
echo building path is $(pwd)
rm -rf ./*
cmake $origin_dir
@ -81,8 +81,8 @@ else
mv ../../release/${sys}/${cpu}/lib${oem}twain.so ../../release/${sys}/${cpu}/lib${oem}twain${pid}.ds
fi
if [ -f ../../code_device/twain/CMakeLists.txtbkp ]; then
mv ../../code_device/twain/CMakeLists.txtbkp ../../code_device/twain/CMakeLists.txt
if [ -f ../../code_device/twain/ds/CMakeLists.txtbkp ]; then
mv ../../code_device/twain/ds/CMakeLists.txtbkp ../../code_device/twain/ds/CMakeLists.txt
pwd
fi
@ -91,6 +91,7 @@ cd $origin_dir
exit $err
# echo -------copy DS to system directory ...-------
# sudo cp ../../release/kylin/x86_64/libhgtwain.so /usr/local/lib/twain/libhgtwain.so.ds
if [ "$3" == "" ]; then
echo -------copy DS to system directory ...-------
sudo cp ../../../release/${sys}/${cpu}/lib${oem}twain${pid}.ds /usr/local/lib/twain/
fi

View File

@ -9,7 +9,7 @@
#include <string>
#include <thread>
#include "twpp.hpp"
#include "../sdk/hginclude/utils.h"
#include "../../sdk/hginclude/utils.h"
#include "s2t_api.h"
namespace std {

View File

@ -1,6 +1,6 @@
#include "sane_helper.h"
#include "huagao/brand.h"
#include "../sdk/hginclude/utils.h"
#include "../../sdk/hginclude/utils.h"
#include <string.h>

View File

@ -13,7 +13,7 @@
#include <twain_user/twainui.h>
#include <huagao/brand.h>
#include "sane_helper.h"
#include "../sdk/hginclude/utils.h"
#include "../../sdk/hginclude/utils.h"
#define START_SCAN_IN_THREAD

80
twain/dsm/CMakeLists.txt Normal file
View File

@ -0,0 +1,80 @@
# this is just a basic CMakeLists.txt, for more information see the cmake manpage...
cmake_minimum_required(VERSION 2.4)
SET(OSTARGET "${OSTARGET}" CACHE STRING "woof")
IF(EXISTS "/bin/uname")
EXEC_PROGRAM("/bin/uname" ARGS -p OUTPUT_VARIABLE CMAKE_SYSTEM_PROCESSOR)
ELSEIF("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8")
SET(CMAKE_SYSTEM_PROCESSOR "x86_64" CACHE STRING "woof" FORCE)
ELSE()
SET(CMAKE_SYSTEM_PROCESSOR "x86" CACHE STRING "woof" FORCE)
ENDIF(EXISTS "/bin/uname")
IF("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "mips64")
message(STATUS "Detected processor: ${CMAKE_SYSTEM_PROCESSOR} building ${OSTARGET}")
ELSE()
message(STATUS "Detected processor: ${CMAKE_SYSTEM_PROCESSOR}")
ENDIF("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "mips64")
# Setup the install prefix, if it's not already defined
IF(NOT CMAKE_INSTALL_PREFIX)
SET(CMAKE_INSTALL_PREFIX "/usr/local")
ENDIF(NOT CMAKE_INSTALL_PREFIX)
# Setup the build prefix, if it's not already defined
IF(NOT CMAKE_BUILD_TYPE)
SET(CMAKE_BUILD_TYPE "Release")
ENDIF(NOT CMAKE_BUILD_TYPE)
#add definitions, compiler switches, etc.
IF(APPLE)
SET(CMAKE_OSX_ARCHITECTURES "i386;x86_64")
ADD_DEFINITIONS(-Wall -Wextra -Werror -isysroot /Developer/SDKs/MacOSX10.6.sdk -mmacosx-version-min=10.6 -fexceptions -fPIC)
ELSEIF("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "mips64")
IF("${OSTARGET}" STREQUAL "mips64el")
ADD_DEFINITIONS(-Wall -Wextra -Werror)
ELSE()
ADD_DEFINITIONS(-Wall -Wextra -Werror -march=from-abi -mabi=32)
ENDIF()
ELSE()
ADD_DEFINITIONS(-Wall -Wextra -Werror -Wno-implicit-fallthrough)
ENDIF(APPLE)
#let's not be sharing our symbols...
IF(APPLE)
SET(CMAKE_SHARED_LINKER_FLAGS "-Wl,-ldl -Wl,-framework,CoreServices -Wl,-framework,Foundation" CACHE STRING "woof" FORCE)
ELSEIF("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "mips64")
IF("${OSTARGET}" STREQUAL "mips64el")
SET(CMAKE_SHARED_LINKER_FLAGS "-Wl,-Bsymbolic -Wl,--no-undefined -Wl,-ldl" CACHE STRING "woof" FORCE)
ELSE()
SET(CMAKE_SHARED_LINKER_FLAGS "-Wl,-Bsymbolic -Wl,--no-undefined -Wl,-ldl -march=from-abi -mabi=32" CACHE STRING "woof" FORCE)
ENDIF()
ELSE()
SET(CMAKE_SHARED_LINKER_FLAGS "-Wl,-Bsymbolic -Wl,--no-undefined -Wl,-ldl" CACHE STRING "woof" FORCE)
ENDIF(APPLE)
#project name
PROJECT(twaindsm)
#project version
SET(${PROJECT_NAME}_MAJOR_VERSION 2)
SET(${PROJECT_NAME}_MINOR_VERSION 5)
SET(${PROJECT_NAME}_PATCH_LEVEL 0)
#build a shared library
ADD_LIBRARY(twaindsm SHARED dsm.cpp apps.cpp log.cpp)
target_link_libraries(twaindsm dl)
#
SET_TARGET_PROPERTIES(twaindsm PROPERTIES
VERSION ${${PROJECT_NAME}_MAJOR_VERSION}.${${PROJECT_NAME}_MINOR_VERSION}.${${PROJECT_NAME}_PATCH_LEVEL}
SOVERSION ${${PROJECT_NAME}_MAJOR_VERSION})
#add an install target here
INSTALL(FILES twain.h DESTINATION include)
INSTALL(TARGETS twaindsm
LIBRARY DESTINATION lib
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)

View File

@ -0,0 +1,319 @@
This file has the translations for the User Selection dialog in the Data Source Manager (DSM), it's
saved as UTF-8, so if you're running a savvy editor with a suitable font you should see the proper
characters under the "Translation" heading.
In terms of the TWLG_* values, mappings default to the primary (ex: English, French, Spanish). There
is support to have different tranlations for the secondaries, if needed (ex: French vs French-Belgian
vs French=Swiss).
Some languages may not be fully translated, in that case English fills in the missing fields. The
idea is that a little translating is better than none at all.
Many of these translations come from a version of the DSM released for Microsoft Windows 98. The
words "Select Source" and "Sources:" have been consistently used. If any translator feels that the
words "Select Driver" and "Drivers:" would be clearer or more appropriate, please go to the TWAIN
Working Group website, and from there go to the forums and submit your recommendation.
There are no translations for any languages that require the dialog box to be arranged from
right to left. If such a translation is submitted, please make mention that the switch needs to
be done as well.
Note: It's not always clear what the sublang for a language should be, which is one reason the DSM
will fail over to just the primary if it can't make a match.
Language Translation UTF-8
-----------------------------------------------------------------------------------------------------------
TWLG_AFRIKAANS, ANSI_CHARSET, MAKELANGID(LANG_AFRIKAANS,SUBLANG_NEUTRAL)
Select Source
Sources:
Select
Cancel Kanselleer \x4b\x61\x6e\x73\x65\x6c\x6c\x65\x65\x72
TWLG_ALBANIA, EASTEUROPE_CHARSET, MAKELANGID(LANG_ALBANIAN,SUBLANG_NEUTRAL)
TWLG_ARABIC, ARABIC_CHARSET, MAKELANGID(LANG_ARABIC,SUBLANG_NEUTRAL)
TWLG_ARABIC_ALGERIA, ARABIC_CHARSET, MAKELANGID(LANG_ARABIC,SUBLANG_ARABIC_ALGERIA)
TWLG_ARABIC_BAHRAIN, ARABIC_CHARSET, MAKELANGID(LANG_ARABIC,SUBLANG_ARABIC_BAHRAIN)
TWLG_ARABIC_EGYPT, ARABIC_CHARSET, MAKELANGID(LANG_ARABIC,SUBLANG_ARABIC_EGYPT)
TWLG_ARABIC_IRAQ, ARABIC_CHARSET, MAKELANGID(LANG_ARABIC,SUBLANG_ARABIC_IRAQ)
TWLG_ARABIC_JORDAN, ARABIC_CHARSET, MAKELANGID(LANG_ARABIC,SUBLANG_ARABIC_JORDAN)
TWLG_ARABIC_KUWAIT, ARABIC_CHARSET, MAKELANGID(LANG_ARABIC,SUBLANG_ARABIC_KUWAIT)
TWLG_ARABIC_LEBANON, ARABIC_CHARSET, MAKELANGID(LANG_ARABIC,SUBLANG_ARABIC_LEBANON)
TWLG_ARABIC_LIBYA, ARABIC_CHARSET, MAKELANGID(LANG_ARABIC,SUBLANG_ARABIC_LIBYA)
TWLG_ARABIC_MOROCCO, ARABIC_CHARSET, MAKELANGID(LANG_ARABIC,SUBLANG_ARABIC_MOROCCO)
TWLG_ARABIC_OMAN, ARABIC_CHARSET, MAKELANGID(LANG_ARABIC,SUBLANG_ARABIC_OMAN)
TWLG_ARABIC_QATAR, ARABIC_CHARSET, MAKELANGID(LANG_ARABIC,SUBLANG_ARABIC_QATAR)
TWLG_ARABIC_SAUDIARABIA, ARABIC_CHARSET, MAKELANGID(LANG_ARABIC,SUBLANG_ARABIC_SAUDI_ARABIA)
TWLG_ARABIC_SYRIA, ARABIC_CHARSET, MAKELANGID(LANG_ARABIC,SUBLANG_ARABIC_SYRIA)
TWLG_ARABIC_TUNISIA, ARABIC_CHARSET, MAKELANGID(LANG_ARABIC,SUBLANG_ARABIC_TUNISIA)
TWLG_ARABIC_UAE, ARABIC_CHARSET, MAKELANGID(LANG_ARABIC,SUBLANG_ARABIC_UAE)
TWLG_ARABIC_YEMEN, ARABIC_CHARSET, MAKELANGID(LANG_ARABIC,SUBLANG_ARABIC_YEMEN)
TWLG_ASSAMESE, ANSI_CHARSET, MAKELANGID(LANG_ASSAMESE,SUBLANG_NEUTRAL)
TWLG_BASQUE, ANSI_CHARSET, MAKELANGID(LANG_BASQUE,SUBLANG_NEUTRAL)
Select Source
Sources:
Select
Cancel Utzi \x55\x74\x7a\x69
TWLG_BENGALI, ANSI_CHARSET, MAKELANGID(LANG_BENGALI,SUBLANG_NEUTRAL)
TWLG_BIHARI, 0, 0
TWLG_BODO, 0, 0
TWLG_BULGARIAN, RUSSIAN_CHARSET, MAKELANGID(LANG_BULGARIAN,SUBLANG_NEUTRAL)
TWLG_BYELORUSSIAN, RUSSIAN_CHARSET, MAKELANGID(LANG_BELARUSIAN,SUBLANG_NEUTRAL)
TWLG_CATALAN ANSI_CHARSET, MAKELANGID(LANG_CATALAN,SUBLANG_NEUTRAL)
Select Source
Sources:
Select
Cancel Cancel·la \x43\x61\x6e\x63\x65\x6c\xc2\xb7\x6c\x61
TWLG_CHINESE, GB2312_CHARSET, MAKELANGID(LANG_CHINESE,SUBLANG_NEUTRAL)
TWLG_CHINESE_PRC, GB2312_CHARSET, MAKELANGID(LANG_CHINESE,SUBLANG_CHINESE_SIMPLIFIED)
TWLG_CHINESE_SIMPLIFIED, GB2312_CHARSET, MAKELANGID(LANG_CHINESE,SUBLANG_CHINESE_SIMPLIFIED)
TWLG_CHINESE_SINGAPORE, GB2312_CHARSET, MAKELANGID(LANG_CHINESE,SUBLANG_CHINESE_SIMPLIFIED)
Select Source 选择数据源 \xe9\x80\x89\xe6\x8b\xa9\xe6\x95\xb0\xe6\x8d\xae\xe6\xba\x90
Sources: 数据源: \xe6\x95\xb0\xe6\x8d\xae\xe6\xba\x90\x3a
Select 选择 \xe9\x80\x89\xe6\x8b\xa9
Cancel 取消 \xe5\x8f\x96\xe6\xb6\x88
TWLG_CHINESE_HONGKONG, CHINESEBIG5_CHARSET, MAKELANGID(LANG_CHINESE,SUBLANG_CHINESE_HONGKONG)
TWLG_CHINESE_TAIWAN, CHINESEBIG5_CHARSET, MAKELANGID(LANG_CHINESE,SUBLANG_CHINESE_TRADITIONAL)
TWLG_CHINESE_TRADITIONAL, CHINESEBIG5_CHARSET, MAKELANGID(LANG_CHINESE,SUBLANG_CHINESE_TRADITIONAL)
Select Source 選擇影像來源 \xe9\x81\xb8\xe6\x93\x87\xe5\xbd\xb1\xe5\x83\x8f\xe4\xbe\x86\xe6\xba\x90
Sources: 影像來源: \xe5\xbd\xb1\xe5\x83\x8f\xe4\xbe\x86\xe6\xba\x90\x3a
Select 確定 \xe7\xa2\xba\xe5\xae\x9a
Cancel 取消 \xe5\x8f\x96\xe6\xb6\x88
TWLG_CROATIA, EASTEUROPE_CHARSET, MAKELANGID(LANG_CROATIAN,SUBLANG_NEUTRAL)
Select Source
Sources:
Select
Cancel Odustani \x4f\x64\x75\x73\x74\x61\x6e\x69
TWLG_CZECH, EASTEUROPE_CHARSET, MAKELANGID(LANG_CZECH,SUBLANG_DEFAULT)
Select Source
Sources:
Select
Cancel Storno \x53\x74\x6f\x72\x6e\x6f
TWLG_DANISH, ANSI_CHARSET, MAKELANGID(LANG_DANISH,SUBLANG_NEUTRAL)
Select Source: Vælg Enhed \x56\xC3\xA6\x6C\x67\x20\x45\x6E\x68\x65\x64
Source: Enhed \x45\x6E\x68\x65\x64
Select:Vælg \x56\xE6\x6C\x67
Cancel: Annuller \x41\x6E\x6E\x75\x6C\x6C\x65\x72
TWLG_DOGRI, 0, 0
TWLG_DUTCH, ANSI_CHARSET, MAKELANGID(LANG_DUTCH,SUBLANG_DUTCH)
TWLG_DUTCH_BELGIAN, ANSI_CHARSET, MAKELANGID(LANG_DUTCH,SUBLANG_DUTCH_BELGIAN)
Select Source Selecteer bron \x53\x65\x6c\x65\x63\x74\x65\x65\x72\x20\x62\x72\x6f\x6e
Sources: Bronnen: \x42\x72\x6f\x6e\x6e\x65\x6e\x3a
Select Selecteren \x53\x65\x6c\x65\x63\x74\x65\x72\x65\x6e
Cancel Annuleren \x41\x6e\x6e\x75\x6c\x65\x72\x65\x6e
TWLG_ENGLISH, ANSI_CHARSET, MAKELANGID(LANG_ENGLISH,SUBLANG_NEUTRAL)
TWLG_ENGLISH_AUSTRALIAN, ANSI_CHARSET, MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_AUS)
TWLG_ENGLISH_CANADIAN, ANSI_CHARSET, MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_CAN)
TWLG_ENGLISH_IRELAND, ANSI_CHARSET, MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_EIRE)
TWLG_ENGLISH_NEWZEALAND, ANSI_CHARSET, MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_NZ)
TWLG_ENGLISH_SOUTHAFRICA, ANSI_CHARSET, MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_SOUTH_AFRICA)
TWLG_ENGLISH_UK, ANSI_CHARSET, MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_UK)
TWLG_ENGLISH_USA, ANSI_CHARSET, MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US)
Select Source Select Source \x53\x65\x6c\x65\x63\x74\x20\x53\x6f\x75\x72\x63\x65
Sources: Sources: \x53\x6f\x75\x72\x63\x65\x73\x3a
Select Select \x53\x65\x6c\x65\x63\x74
Cancel Cancel \x43\x61\x6e\x63\x65\x6c
TWLG_ESTONIAN, BALTIC_CHARSET, MAKELANGID(LANG_ESTONIAN,SUBLANG_NEUTRAL)
Select Source
Sources:
Select
Cancel Kustuta \x4b\x75\x73\x74\x75\x74\x61
TWLG_FAEROESE, EASTEUROPE_CHARSET, MAKELANGID(LANG_FAEROESE,SUBLANG_NEUTRAL)
TWLG_FARSI, ARABIC_CHARSET, MAKELANGID(LANG_FARSI,SUBLANG_NEUTRAL)
TWLG_FINNISH, ANSI_CHARSET, MAKELANGID(LANG_FINNISH,SUBLANG_NEUTRAL)
Select Source
Sources:
Select
Cancel Peruuta \x50\x65\x72\x75\x75\x74\x61
TWLG_FRENCH, ANSI_CHARSET, MAKELANGID(LANG_FRENCH,SUBLANG_FRENCH)
TWLG_FRENCH_BELGIAN, ANSI_CHARSET, MAKELANGID(LANG_FRENCH,SUBLANG_FRENCH_BELGIAN)
TWLG_FRENCH_CANADIAN, ANSI_CHARSET, MAKELANGID(LANG_FRENCH,SUBLANG_FRENCH_CANADIAN)
TWLG_FRENCH_LUXEMBOURG, ANSI_CHARSET, MAKELANGID(LANG_FRENCH,SUBLANG_FRENCH_LUXEMBOURG)
TWLG_FRENCH_SWISS, ANSI_CHARSET, MAKELANGID(LANG_FRENCH,SUBLANG_FRENCH_SWISS)
Select Source Sélectionner source \x53\xc3\xa9\x6c\x65\x63\x74\x69\x6f\x6e\x6e\x65\x72\x20\x73\x6f\x75\x72\x63\x65
Sources: Sources: \x53\x6f\x75\x72\x63\x65\x73\x3a
Select Sélectionner \x53\xc3\xa9\x6c\x65\x63\x74\x69\x6f\x6e\x6e\x65\x72
Cancel Annuler \x41\x6e\x6e\x75\x6c\x65\x72
TWLG_GERMAN, ANSI_CHARSET, MAKELANGID(LANG_GERMAN,SUBLANG_GERMAN)
TWLG_GERMAN_AUSTRIAN, ANSI_CHARSET, MAKELANGID(LANG_GERMAN,SUBLANG_GERMAN_AUSTRIAN)
TWLG_GERMAN_LIECHTENSTEIN, ANSI_CHARSET, MAKELANGID(LANG_GERMAN,SUBLANG_GERMAN_LIECHTENSTEIN)
TWLG_GERMAN_LUXEMBOURG, ANSI_CHARSET, MAKELANGID(LANG_GERMAN,SUBLANG_GERMAN_LUXEMBOURG)
TWLG_GERMAN_SWISS, ANSI_CHARSET, MAKELANGID(LANG_GERMAN,SUBLANG_GERMAN_SWISS)
Select Source Quelle wählen \x51\x75\x65\x6c\x6c\x65\x20\x77\xc3\xa4\x68\x6c\x65\x6e
Sources: Quellen: \x51\x75\x65\x6c\x6c\x65\x6e\x3a
Select Auswählen \x41\x75\x73\x77\xc3\xa4\x68\x6c\x65\x6e
Cancel Abbrechen \x41\x62\x62\x72\x65\x63\x68\x65\x6e
TWLG_GREEK, GREEK_CHARSET, MAKELANGID(LANG_GREEK,SUBLANG_DEFAULT)
TWLG_GUJARATI, GREEK_CHARSET, MAKELANGID(LANG_GUJARATI,SUBLANG_DEFAULT)
TWLG_HARYANVI, 0, 0
TWLG_HEBREW, HEBREW_CHARSET, MAKELANGID(LANG_HEBREW,SUBLANG_NEUTRAL)
TWLG_HINDI, HEBREW_CHARSET, MAKELANGID(LANG_HINDI,SUBLANG_NEUTRAL)
TWLG_HUNGARIAN, EASTEUROPE_CHARSET, MAKELANGID(LANG_HUNGARIAN,SUBLANG_NEUTRAL)
Select Source
Sources:
Select
Cancel Mégse \x4d\xc3\xa9\x67\x73\x65
TWLG_ICELANDIC, ANSI_CHARSET, MAKELANGID(LANG_ICELANDIC,SUBLANG_NEUTRAL)
TWLG_INDONESIAN, ANSI_CHARSET, MAKELANGID(LANG_INDONESIAN,SUBLANG_NEUTRAL)
Select Source Pilith Sumber \x50\x69\x6c\x69\x74\x68\x20\x53\x75\x6d\x62\x65\x72
Sources: Sumber: \x53\x75\x6d\x62\x65\x72\x3a
Select Pilith \x50\x69\x6c\x69\x74\x68
Cancel Batal \x42\x61\x74\x61\x6c
TWLG_ITALIAN, ANSI_CHARSET, MAKELANGID(LANG_ITALIAN,SUBLANG_ITALIAN)
TWLG_ITALIAN_SWISS, ANSI_CHARSET, MAKELANGID(LANG_ITALIAN,SUBLANG_ITALIAN_SWISS)
Select Source Seleziona origine \x41\x62\x62\x72\x65\x63\x68\x65\x6e
Sources: Origini: \x4f\x72\x69\x67\x69\x6e\x69\x3a
Select Seleziona \x53\x65\x6c\x65\x7a\x69\x6f\x6e\x61
Cancel Annulla \x41\x6e\x6e\x75\x6c\x6c\x61
TWLG_JAPANESE, SHIFTJIS_CHARSET, MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT)
Select Source 原稿の選択 \xe5\x8e\x9f\xe7\xa8\xbf\xe3\x81\xae\xe9\x81\xb8\xe6\x8a\x9e
Sources: 原稿: \xe5\x8e\x9f\xe7\xa8\xbf\x3a
Select 選択 \xe9\x81\xb8\xe6\x8a\x9e
Cancel キャンセル \xe3\x82\xad\xe3\x83\xa3\xe3\x83\xb3\xe3\x82\xbb\xe3\x83\xab
TWLG_KANNADA, ANSI_CHARSET, MAKELANGID(LANG_KANNADA,SUBLANG_NEUTRAL)
TWLG_KASHMIRI, ANSI_CHARSET, MAKELANGID(LANG_KASHMIRI,SUBLANG_NEUTRAL)
TWLG_KOREAN, HANGUL_CHARSET, MAKELANGID(LANG_KOREAN,SUBLANG_KOREAN)
TWLG_KOREAN_JOHAB, JOHAB_CHARSET, MAKELANGID(LANG_KOREAN,SUBLANG_KOREAN)
Select Source 장치 선택 \xec\x9e\xa5\xec\xb9\x98\x20\xec\x84\xa0\xed\x83\x9d
Sources: 장치 \xec\x9e\xa5\xec\xb9\x98
Select 선택 \xec\x84\xa0\xed\x83\x9d
Cancel 취소 \xec\xb7\xa8\xec\x86\x8c
TWLG_LATVIAN, BALTIC_CHARSET, MAKELANGID(LANG_LATVIAN,SUBLANG_NEUTRAL)
TWLG_LITHUANIAN, BALTIC_CHARSET, MAKELANGID(LANG_LITHUANIAN,SUBLANG_NEUTRAL)
TWLG_MALAYALAM, BALTIC_CHARSET, MAKELANGID(LANG_MALAYALAM,SUBLANG_NEUTRAL)
TWLG_MARATHI, ANSI_CHARSET, MAKELANGID(LANG_MARATHI,SUBLANG_NEUTRAL)
TWLG_MARWARI, 0, 0
TWLG_MEGHALAYAN, 0, 0
TWLG_MIZO, 0, 0
TWLG_NAGA, 0, 0
TWLG_NORWEGIAN, ANSI_CHARSET, MAKELANGID(LANG_NORWEGIAN,SUBLANG_NEUTRAL)
TWLG_NORWEGIAN_BOKMAL, ANSI_CHARSET, MAKELANGID(LANG_NORWEGIAN,SUBLANG_NORWEGIAN_BOKMAL)
TWLG_NORWEGIAN_NYNORSK, ANSI_CHARSET, MAKELANGID(LANG_NORWEGIAN,SUBLANG_NORWEGIAN_NYNORSK)
TWLG_ORISSI, 0, 0
TWLG_POLISH, EASTEUROPE_CHARSET, MAKELANGID(LANG_POLISH,SUBLANG_NEUTRAL)
Select Source
Sources:
Select
Cancel Anuluj \x41\x6e\x75\x6c\x75\x6a
TWLG_PORTUGUESE, EASTEUROPE_CHARSET, MAKELANGID(LANG_PORTUGUESE,SUBLANG_PORTUGUESE)
TWLG_PORTUGUESE_BRAZIL, ANSI_CHARSET, MAKELANGID(LANG_PORTUGUESE,SUBLANG_PORTUGUESE_BRAZILIAN)
Select Source Selecionar Origem \x53\x65\x6c\x65\x63\x69\x6f\x6e\x61\x72\x20\x4f\x72\x69\x67\x65\x6d
Sources: Origens: \x4f\x72\x69\x67\x65\x6e\x73\x3a
Select Selecionar \x53\x65\x6c\x65\x63\x69\x6f\x6e\x61\x72
Cancel Cancelar \x43\x61\x6e\x63\x65\x6c\x61\x72
TWLG_PUNJABI, ANSI_CHARSET, MAKELANGID(LANG_PUNJABI,SUBLANG_NEUTRAL)
TWLG_PUSHTU, 0, 0
TWLG_ROMANIAN, EASTEUROPE_CHARSET, MAKELANGID(LANG_ROMANIAN,SUBLANG_NEUTRAL)
TWLG_RUSSIAN, RUSSIAN_CHARSET, MAKELANGID(LANG_RUSSIAN,SUBLANG_DEFAULT)
Select Source Выбрать источник \xd0\x92\xd1\x8b\xd0\xb1\xd1\x80\xd0\xb0\xd1\x82\xd1\x8c\x20\xd0\xb8\xd1\x81\xd1\x82\xd0\xbe\xd1\x87\xd0\xbd\xd0\xb8\xd0\xba
Sources: Источники: \xd0\x98\xd1\x81\xd1\x82\xd0\xbe\xd1\x87\xd0\xbd\xd0\xb8\xd0\xba\xd0\xb8\x3a
Select Выбрать \xd0\x92\xd1\x8b\xd0\xb1\xd1\x80\xd0\xb0\xd1\x82\xd1\x8c
Cancel Отменить \xd0\x9e\xd1\x82\xd0\xbc\xd0\xb5\xd0\xbd\xd0\xb8\xd1\x82\xd1\x8c
TWLG_SERBIAN_CYRILLIC, ANSI_CHARSET, MAKELANGID(LANG_SERBIAN,SUBLANG_SERBIAN_CYRILLIC)
TWLG_SERBIAN_LATIN, EASTEUROPE_CHARSET, MAKELANGID(LANG_SERBIAN,SUBLANG_SERBIAN_LATIN)
TWLG_SIKKIMI, 0, 0
TWLG_SLOVAK, EASTEUROPE_CHARSET, MAKELANGID(LANG_SLOVAK,SUBLANG_NEUTRAL)
TWLG_SLOVENIAN, EASTEUROPE_CHARSET, MAKELANGID(LANG_SLOVENIAN,SUBLANG_NEUTRAL)
Select Source
Sources:
Select
Cancel Prekini \x50\x72\x65\x6b\x69\x6e\x69
TWLG_SPANISH, ANSI_CHARSET, MAKELANGID(LANG_SPANISH,SUBLANG_SPANISH)
TWLG_SPANISH_MEXICAN, ANSI_CHARSET, MAKELANGID(LANG_SPANISH,SUBLANG_SPANISH_MEXICAN)
TWLG_SPANISH_MODERN, ANSI_CHARSET, MAKELANGID(LANG_SPANISH,SUBLANG_SPANISH_MODERN)
Select Source Selección de fuente \x53\x65\x6c\x65\x63\x63\x69\xc3\xb3\x6e\x20\x64\x65\x20\x66\x75\x65\x6e\x74\x65
Sources: Fuentes: \x46\x75\x65\x6e\x74\x65\x73\x3a
Select Seleccionar \x53\x65\x6c\x65\x63\x63\x69\x6f\x6e\x61\x72
Cancel Cancelar \x43\x61\x6e\x63\x65\x6c\x61\x72
TWLG_SWEDISH, ANSI_CHARSET, MAKELANGID(LANG_SWEDISH,SUBLANG_SWEDISH)
TWLG_SWEDISH_FINLAND, ANSI_CHARSET, MAKELANGID(LANG_SWEDISH,SUBLANG_SWEDISH_FINLAND)
Select Source
Sources:
Select
Cancel Avbryt \x41\x76\x62\x72\x79\x74
TWLG_TAMIL, ANSI_CHARSET, MAKELANGID(LANG_TAMIL,SUBLANG_NEUTRAL)
TWLG_TELUGU, ANSI_CHARSET, MAKELANGID(LANG_TELUGU,SUBLANG_NEUTRAL)
TWLG_THAI, THAI_CHARSET, MAKELANGID(LANG_THAI,SUBLANG_NEUTRAL)
TWLG_TRIPURI, 0, 0
TWLG_TURKISH, TURKISH_CHARSET, MAKELANGID(LANG_TURKISH,SUBLANG_DEFAULT)
Select Source Kaynak seçiniz \x4b\x61\x79\x6e\x61\x6b\x20\x73\x65\xc3\xa7\x69\x6e\x69\x7a
Sources: Kaynak \x4b\x61\x79\x6e\x61\x6b
Select Seçiniz \x53\x65\xc3\xa7\x69\x6e\x69\x7a
Cancel İptal \xc4\xb0\x70\x74\x61\x6c
TWLG_UKRANIAN, RUSSIAN_CHARSET, MAKELANGID(LANG_UKRAINIAN,SUBLANG_NEUTRAL)
TWLG_URDU, ANSI_CHARSET, MAKELANGID(LANG_URDU,SUBLANG_NEUTRAL)
TWLG_VIETNAMESE, VIETNAMESE_CHARSET, MAKELANGID(LANG_VIETNAMESE,SUBLANG_NEUTRAL)

1920
twain/dsm/apps.cpp Normal file

File diff suppressed because it is too large Load Diff

37
twain/dsm/build.sh Executable file
View File

@ -0,0 +1,37 @@
# Main and minor version definition
# usage: ./build.sh os cpu ---> ./build.sh uos x86_64
@echo off
# clear
if [ -f ../../build/twaindsm/Makefile ]; then
echo ""
else
mkdir ../../../build
mkdir ../../../build/twaindsm
fi
origin_dir=$(pwd)
cd ../../../build/twaindsm
echo building path is $(pwd)
rm -rf ./*
cmake $origin_dir
make -j4
if [ $? -ne 0 ];then
err=1
echo "--------------------------------------make fail---------------------------------------"
# commented, we should restore the CMakeLists.txts...
else
err=0
echo "--------------------------------------make succeed------------------------------------"
cp ./libtwaindsm.so.2.5.0 ../../release/$1/$2/libtwaindsm.so
fi
cd $origin_dir
exit $err

3918
twain/dsm/dsm.cpp Normal file

File diff suppressed because it is too large Load Diff

5
twain/dsm/dsm.def Normal file
View File

@ -0,0 +1,5 @@
LIBRARY "TWAINDSM"
EXPORTS
DSM_Entry

1270
twain/dsm/dsm.h Normal file

File diff suppressed because it is too large Load Diff

139
twain/dsm/dsm.rc Normal file
View File

@ -0,0 +1,139 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#define APSTUDIO_HIDDEN_SYMBOLS
#include "windows.h"
#undef APSTUDIO_HIDDEN_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
"#include ""windows.h""\r\n"
"#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION TWNDSM_VERSION_NUM
PRODUCTVERSION TWNDSM_VERSION_NUM
FILEFLAGSMASK 0x1fL
#ifdef _DEBUG
FILEFLAGS 0x9L
#else
FILEFLAGS 0x8L
#endif
FILEOS 0x4L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", TWNDSM_ORGANIZATION
VALUE "FileDescription", TWNDSM_DESCRIPTION
VALUE "FileVersion", TWNDSM_VERSION_STR
VALUE "InternalName", "DSM"
VALUE "LegalCopyright", "(C) 1993-2021 TWAIN Working Group. All rights reserved."
VALUE "OriginalFilename", "TWAIN_32.dll"
VALUE "ProductName", "TWAIN DSM Dynamic Link Library"
VALUE "ProductVersion", TWNDSM_VERSION_STR
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_DLG_SOURCE DIALOGEX 64, 60, 245, 89
STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
CAPTION "Select Source"
FONT 8, "Arial Unicode MS", 400, 0, 0x0
BEGIN
PUSHBUTTON "Select",IDOK,177,43,62,15,WS_GROUP
PUSHBUTTON "Cancel",IDCANCEL,177,63,62,15
LTEXT "Sources:",IDC_STATIC,9,6,85,8,NOT WS_GROUP
LISTBOX ID_LST_SOURCES,8,16,164,71,LBS_SORT | WS_VSCROLL | WS_GROUP | WS_TABSTOP
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_DLG_SOURCE, DIALOG
BEGIN
RIGHTMARGIN, 244
END
END
#endif // APSTUDIO_INVOKED
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

854
twain/dsm/hook.cpp Normal file
View File

@ -0,0 +1,854 @@
/*
* [Overview]
* The contents of this module allow the new TWAINDSM.DLL (tied to the 2.x version
* of the TWAIN Specifiction) to hook functions that might try to access the 1.x
* TWAIN_32.DLL. We need this because the DG_CONTROL/DAT_NULL/MSG_* triplets are
* sent from the data source (driver) to the application through the data source
* manager (DSM). The technique used was for a driver to issue a LoadLibrary or
* a GetModuleHandle, which would result in it attaching to the same TWAIN_32.DLL
* first loaded by the application. We have to force the driver to attach to the
* new TWAINDSM.DLL instead.
*
*
* [Diagram]
* This is the problem we have...
* +-----+ +--------------+ +--------------+
* | app | <-------> | TWAINDSM.DLL | --------> | |
* +-----+ +--------------+ | |
* | driver (1.x) |
* +--------------+ | |
* error <----- | TWAIN_32.DLL | <-------- | |
* +--------------+ +--------------+
*
* By hooking the appropriate function, we change the driver's request to get
* the DSM_Entry function from TWAIN_32.DLL into the DSM_Entry function from
* DSM_ TWAINDSM.DLL
* +-----+ +--------------+ +--------------+
* | app | <-------> | TWAINDSM.DLL | <-------> | |
* +-----+ +--------------+ | |
* | driver (1.x) |
* +--------------+ | |
* | TWAIN_32.DLL | | |
* +--------------+ +--------------+
*
* Note that TWAIN_32.DLL is still in the picture. This is intentional,
* because we're (indirectly) hooking GetProcAddress. The driver still
* does a LoadLibrary or GetModuleHandle on TWAIN_32.DLL. This design
* was selected because it results in the smallest possible hook code,
* and makes the smallest possible change to the 1.x driver. Everything
* runs the same as a TWAIN_32.DLL session, we just return a pointer to
* a different DSM_Entry function.
*
*
* [Hooked Functions]
* This is the ntdll.dll function we're hooking from kernel32.dll...
* LdrGetProcedureAddress (or LdrGetProcedureAddressForCaller)
* This gives us full coverage for the following function...
* GetProcAddress
*
*
* [Solution]
* The hook code is derived from the BugSlayer HookImportedFunctionByName function
* described in the August 1998 MSJ. The code has been considerably simplified to
* meet the limited needs of the DSM.
*
*
* [Risks]
* 32-bit Windows applications using TWAINDSM.DLL will never be able to access
* the TWAIN_32.DLL DSM_Entry function. Since this is by design, it's not so
* much a risk as "the plan", but it still deserves to be mentioned.
*
* We're not fully loading the TWAIN_32.DLL, because we don't have control over
* it, and we can't be sure what it's doing in DllMain. This could be a problem
* with a very badly behaved application. The scenerio is so convoluted, though,
* that it seems a good risk to keep TWAIN_32.DLL as uninvolved as possible.
*
* The application will crash if it does a FreeLibrary() on the DSM without first
* doing all the necessary MSG_CLOSEDS and MSG_CLOSEDSM calls. This can be
* mitigated by hooking LdrUnloadDll() and watching for an attempt to unload the
* DSM. But this adds complexity that rewards extremely bad coding behavior, so
* it's not going to be added unless we have a lot of bad actors we have to deal
* with.
*
* Hooks should be avoided whenever possible. Therefore the DSM code only installs
* the hook if the application attempts to DG_CONTROL/DAT_IDENTITY/MSG_OPENDS a 1.x
* driver on a 32-bit Windows system.
*
* This system is only designed to work with Window 2000 and higher, there is no
* intention of supporting either Windows NT or any of the Windows 9x platforms.
* Nor is there a reason to, since they don't have a file protection scheme (save for
* WinME, but hopefully nobody is still using that)...
*/
#include "dsm.h"
/**
* This entire file is only used for 32-bit Windows systems, so there is no need to
* compile it for anything else...
*/
#if TWNDSM_OS_64BIT
#pragma message( "hook code disabled for 64-bit builds..." )
#elif TWNDSM_OS_32BIT
#pragma message( "hook code enabled for 32-bit builds..." )
/**
* We use this to build pointers from the various data structures we
* have to navigate to set up the hooks...
*/
#define MakePtr(cast,ptr,AddValue) (cast)((DWORD_PTR)(ptr)+(DWORD_PTR)(AddValue))
/**
* Things we do with our Hook function...
*/
enum EHOOK
{
HOOK_ATTACH = 0,
HOOK_DETACH = 1
};
/**
* Need this for our Ldr functions...
*/
typedef struct _ANSI_STRING {
USHORT Length;
USHORT MaximumLength;
PSTR Buffer;
} ANSI_STRING, *PANSI_STRING;
/**
* typedefs of our hooked functions, so we can cast them nice when we make
* our calls...
*/
typedef NTSYSAPI DWORD (NTAPI *LdrGetProcedureAddress_t)
(
__in HMODULE ModuleHandle,
__in_opt PANSI_STRING FunctionName,
__in_opt WORD Oridinal,
__out PVOID *FunctionAddress
);
typedef NTSYSAPI DWORD (NTAPI *LdrGetProcedureAddressForCaller_t)
(
__in HMODULE ModuleHandle,
__in_opt PANSI_STRING FunctionName,
__in_opt WORD Oridinal,
__out PVOID *FunctionAddress,
__in BOOL bValue,
__in PVOID *CallbackAddress
);
/**
* Forward declarations for our functions, so we can build our m_proc table...
*/
DWORD NTAPI LocalLdrGetProcedureAddress
(
__in HMODULE ModuleHandle,
__in_opt PANSI_STRING FunctionName,
__in_opt WORD Oridinal,
__out PVOID *FunctionAddress
);
DWORD NTAPI LocalLdrGetProcedureAddressForCaller
(
__in HMODULE ModuleHandle,
__in_opt PANSI_STRING FunctionName,
__in_opt WORD Oridinal,
__out PVOID *FunctionAddress,
__in BOOL bValue,
__in PVOID *CallbackAddress
);
/**
* The entry point we want to return to the caller, instead of the one they
* thought they were getting from TWAIN_32.DLL...
*/
extern DSMENTRY DSM_Entry
(
TW_IDENTITY *_pOrigin,
TW_IDENTITY *_pDest,
TW_UINT32 _DG,
TW_UINT16 _DAT,
TW_UINT16 _MSG,
TW_MEMREF _pData
);
/**
* The hook class...
*/
class CTwHook
{
public:
// Initialize our piece-of-data...
CTwHook()
{
memset(&pod,0,sizeof(pod));
}
// The destructor cleans us all up (but Hook does the real work)...
~CTwHook()
{
Hook(HOOK_DETACH);
memset(&pod,0,sizeof(pod));
}
// The workhorse, this is where the hooking fun really takes place...
bool Hook
(
EHOOK _ehook
);
// Determine if this DS ID has been hooked
bool DSID_Is_Hooked
(
TW_UINT32 DSID
);
// Add this DS ID as being hooked
void Hook_Add_DSID
(
TW_UINT32 DSID
);
// Remove this DS ID as being hooked
bool Hook_Remove_DSID
(
TW_UINT32 DSID
);
private:
// We use a pod so that we don't have to worry about initialization
// issues...
struct Pod
{
PROC pOriginal; // The original procedure we found
TW_UINT32 HookedDSs[MAX_NUM_DS];
} pod;
};
/**
* This is where we're keeping our stuff, it has global scope in this module so we can
* use it in our hook functions. Even though this is static, every attempt has been
* made to make it thread safe. We also have a reference counter, since the application
* may choose to load more than one 1.x driver...
*/
static int s_iHookCount = 0;
static CTwHook *s_ptwhook = (CTwHook*)NULL;
/**
* We start by loading these functions using GetProcAddress, since they are
* wacky NTDLL things that are undocumented. Later on we change them to the
* actual pointers to the Ldr functions, and this is what allows us to be
* used safely, no matter what the state of the CTwHook object is in...
*/
static LdrGetProcedureAddress_t OriginalLdrGetProcedureAddress = 0;
static LdrGetProcedureAddressForCaller_t OriginalLdrGetProcedureAddressForCaller = 0;
/**
* A static value for the TWAIN_32.DLL we load, which provides us a very
* simple way to see if someone is working with this DLL...
*/
static HMODULE s_hmoduleTWAIN32 = 0;
/**
* A static value for the DSMEntry of the TWAIN_32.DLL we load,
* which provides us a way to call the original TWAIN_32 if we
* did not want to hook this data souce.
*/
static DSMENTRYPROC TWAIN32_DSMEntry = 0;
/**
* The entry point we want to return to the caller, instead of the one they
* thought they were getting from TWAIN_32.DLL...
*/
DSMENTRY DSM_HookedEntry
(
TW_IDENTITY *_pOrigin,
TW_IDENTITY *_pDest,
TW_UINT32 _DG,
TW_UINT16 _DAT,
TW_UINT16 _MSG,
TW_MEMREF _pData
)
{
if ( ((_DAT == DAT_NULL)
|| (_DAT == DAT_CALLBACK && _MSG == MSG_INVOKE_CALLBACK))
&& _pOrigin
&& s_ptwhook
&& s_ptwhook->DSID_Is_Hooked(_pOrigin->Id))
{
return (DSM_Entry(_pOrigin,_pDest,_DG,_DAT,_MSG,_pData));
}
return (TWAIN32_DSMEntry(_pOrigin,_pDest,_DG,_DAT,_MSG,_pData));
}
/**
* Derived from John Robbins' BugSlayer code in MSJ (so the 'I' in the comments in this
* function refers to John), this function hooks or unhooks the stuff we want to examine.
* Note that this code is optimized to hook the Ldr functions in ntdll.dll. If you want
* to hook something else, especially if it's in a different DLL, you're going to have
* some work to do...
* @param[in] EHOOK _ehook we're hooking or unhooking
* @return true or false
*/
bool CTwHook::Hook
(
EHOOK _ehook
)
{
UINT uResult;
BOOL boolResult;
PIMAGE_IMPORT_DESCRIPTOR pImportDesc;
PIMAGE_THUNK_DATA pOrigThunk;
PIMAGE_THUNK_DATA pRealThunk;
PIMAGE_IMPORT_BY_NAME pByName;
bool bDoHook;
MEMORY_BASIC_INFORMATION mbi_thunk;
DWORD_PTR *pTemp;
DWORD dwOldProtect;
PIMAGE_DOS_HEADER pDOSHeader;
PIMAGE_NT_HEADERS pNTHeader;
PSTR szCurrMod;
HMODULE hmodule;
char szTwain32[MAX_PATH];
const char *szFunctionName;
// Initialize stuff when we're doing an attach...
if (_ehook == HOOK_ATTACH)
{
// If we don't find TWAIN_32.DLL, then we're not going to
// make life any better by doing the hooks, so bail. Also,
// We're not going to allow any flavor of GetProcAddress
// to access this library, which is why we're using the
// extra flag, to keep TWAIN_32.DLL from loading anything
// other than itself.
//
// BUG ALERT
// ~~~~~~~~~
// There is a potential bug here, but one that depends
// on really bad behavior. If the application loads
// TWAINDSM.DLL, then loads TWAIN_32.DLL, then unloads
// TWAINDSM.DLL, then does a GetProcAddress for DSM_Entry
// with TWAIN_32.DLL, it's going to go ka-boom. If this
// is a problem, then go back to using ::LoadLibrary()...
memset(szTwain32,0,sizeof(szTwain32));
uResult = ::GetWindowsDirectory(szTwain32,sizeof(szTwain32)-1);
if (!uResult)
{
return(false);
}
SSTRCAT(szTwain32,sizeof(szTwain32)-1,"\\TWAIN_32.DLL");
s_hmoduleTWAIN32 = ::LoadLibraryEx(szTwain32,NULL,DONT_RESOLVE_DLL_REFERENCES);
if (0 == s_hmoduleTWAIN32)
{
return(false);
}
// Load the undocumented routine, we're going for both, if we find
// LdrGetProcedureAddressForCaller, then we'll prefer it over LdrGetProcedureAddress...
szFunctionName = "";
OriginalLdrGetProcedureAddress = 0;
OriginalLdrGetProcedureAddressForCaller = 0;
hmodule = GetModuleHandle("ntdll.dll");
if (hmodule)
{
szFunctionName = "LdrGetProcedureAddressForCaller";
OriginalLdrGetProcedureAddressForCaller = (LdrGetProcedureAddressForCaller_t)GetProcAddress(hmodule,szFunctionName);
if (!OriginalLdrGetProcedureAddressForCaller)
{
szFunctionName = "LdrGetProcedureAddress";
OriginalLdrGetProcedureAddress = (LdrGetProcedureAddress_t)GetProcAddress(hmodule,szFunctionName);
}
}
}
// If we're detaching, then make sure our reference to TWAIN_32.DLL is gone...
else
{
if (s_hmoduleTWAIN32)
{
::FreeLibrary(s_hmoduleTWAIN32);
s_hmoduleTWAIN32 = 0;
}
// If we don't have an old pointer, then we're done...
if (NULL == pod.pOriginal)
{
return (true);
}
// Pick the name...
if (OriginalLdrGetProcedureAddressForCaller)
{
szFunctionName = "LdrGetProcedureAddressForCaller";
}
else
{
szFunctionName = "LdrGetProcedureAddress";
}
}
// This is where we'll be hooking into Ldr functions, the calls
// themselves are in ntdll.dll. Kernel32 calls them, and that's
// where we can take advantage of the DLL indirection to do this
// spiffy DLL injection thingy...
// Starting with Windows7 the hooking has moved from kernel32.dll
// to a new library kernelbase.dll. Atempt kernelbase first
// if it fails then we are not Windows7 and try kernel32
hmodule = GetModuleHandle("kernelbase.dll");
if ( NULL == hmodule )
{
hmodule = GetModuleHandle("kernel32.dll");
}
// Get the DOS header...
pDOSHeader = (PIMAGE_DOS_HEADER)hmodule;
// Is this the MZ header?
if ( !pDOSHeader
|| (TRUE == IsBadReadPtr(pDOSHeader,sizeof(IMAGE_DOS_HEADER)))
|| (IMAGE_DOS_SIGNATURE != pDOSHeader->e_magic))
{
return (false);
}
// Get the PE header.
pNTHeader = MakePtr(PIMAGE_NT_HEADERS,pDOSHeader,pDOSHeader->e_lfanew);
// Is this a real PE image?
if ( (TRUE == IsBadReadPtr(pNTHeader,sizeof(IMAGE_NT_HEADERS)))
|| (IMAGE_NT_SIGNATURE != pNTHeader->Signature))
{
return (false);
}
// If there is no imports section, leave now.
if (0 == pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
{
return (false);
}
// Get the pointer to the imports section.
pImportDesc = MakePtr(PIMAGE_IMPORT_DESCRIPTOR,pDOSHeader,pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
// Loop through the import module descriptors looking for the
// ntdll.dll module, which is where the Ldr functions live...
while (NULL != pImportDesc->Name)
{
szCurrMod = MakePtr(PSTR,pDOSHeader,pImportDesc->Name);
if (0 == _stricmp(szCurrMod,"ntdll.dll"))
{
// Found it.
break;
}
// Look at the next one.
pImportDesc++ ;
}
// If the name is NULL, then the module is not imported.
if (NULL == pImportDesc->Name)
{
return (false);
}
// Get the original thunk information for this DLL. I can't use
// the thunk information stored in pImportDesc->FirstThunk
// because the loader has already changed that array to fix up
// all the imports. The original thunk gives me access to the
// function names.
pOrigThunk = MakePtr(PIMAGE_THUNK_DATA,hmodule,pImportDesc->OriginalFirstThunk);
// Get the array the pImportDesc->FirstThunk points to because
// I'll do the actual bashing and hooking there.
pRealThunk = MakePtr(PIMAGE_THUNK_DATA,hmodule,pImportDesc->FirstThunk);
// Determines whether I hook the function
bDoHook = false;
// Loop through and find the function to hook.
while (NULL != pOrigThunk->u1.Function)
{
// Look only at functions that are imported by name, not those
// that are imported by ordinal value.
if (IMAGE_ORDINAL_FLAG != (pOrigThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG))
{
// Look at the name of this imported function.
pByName = MakePtr(PIMAGE_IMPORT_BY_NAME,hmodule,pOrigThunk->u1.AddressOfData);
// We found it, so scoot...
if ( pByName->Name
&& ('\0' != pByName->Name[0])
&& (0 == _stricmp(szFunctionName,(char*)pByName->Name)))
{
bDoHook = true;
break;
}
// Increment both tables, and continue...
pOrigThunk++;
pRealThunk++;
}
}
// If we found something, then hook or unhook it, as appropriate...
if (true == bDoHook)
{
// I found a function to hook. Now I need to change
// the memory protection to writable before I overwrite
// the function pointer. Note that I'm now writing into
// the real thunk area!
VirtualQuery(pRealThunk,&mbi_thunk,sizeof(MEMORY_BASIC_INFORMATION));
if (FALSE == VirtualProtect(mbi_thunk.BaseAddress,mbi_thunk.RegionSize,PAGE_EXECUTE_READWRITE,&mbi_thunk.Protect))
{
return(false);
}
// Save the original address, if we're hooking...
if (_ehook == HOOK_ATTACH)
{
// This cast should make the compiler happy about the change in the word size...
pod.pOriginal = (PROC)(INT_PTR)pRealThunk->u1.Function;
if (OriginalLdrGetProcedureAddressForCaller)
{
OriginalLdrGetProcedureAddressForCaller = (LdrGetProcedureAddressForCaller_t)pod.pOriginal;
}
else
{
OriginalLdrGetProcedureAddress = (LdrGetProcedureAddress_t)pod.pOriginal;
}
}
// Microsoft has two different definitions of the
// PIMAGE_THUNK_DATA fields as they are moving to
// support Win64. The W2K RC2 Platform SDK is the
// latest header, so I'll use that one and force the
// Visual C++ 6 Service Pack 3 headers to deal with it.
// Hook the new function if we're hooking, or the original function
// if we're closing...
if (_ehook == HOOK_ATTACH)
{
pTemp = (DWORD_PTR*)&pRealThunk->u1.Function;
if (OriginalLdrGetProcedureAddressForCaller)
{
*pTemp = (DWORD_PTR)LocalLdrGetProcedureAddressForCaller;
}
else
{
*pTemp = (DWORD_PTR)LocalLdrGetProcedureAddress;
}
}
else
{
pTemp = (DWORD_PTR*)&pRealThunk->u1.Function;
*pTemp = (DWORD_PTR)(pod.pOriginal);
}
// Change the protection back to what it was before I
// overwrote the function pointer.
boolResult = VirtualProtect(mbi_thunk.BaseAddress,mbi_thunk.RegionSize,mbi_thunk.Protect,&dwOldProtect);
if (boolResult == FALSE)
{
// Okay, this isn't good, but we're not going to do
// anything about it, because presumably this isn't
// the end of the world...
}
}
// All done...
return(true);
}
/**
* Determine if the DS has been hooked by checking the ID
* @param[in] DSID The DS ID to check to see if it has been hooked
* @return true or false
*/
bool CTwHook::DSID_Is_Hooked(TW_UINT32 DSID)
{
int count = min(MAX_NUM_DS,s_iHookCount);
for (int i=0; i<count; i++)
{
if (pod.HookedDSs[i] == DSID)
{
return (true);
}
}
return (false);
}
/**
* Add this DS to the list of being hooked
* @param[in] DSID The DS ID to add to the list
* @note We allow an application to open the DSM several times and each
* application to open several DSs. (The application must use a different
* name each time it loads the DSM). It is possible for a DS to be opened
* several times by different applications. (Although most DSs only support
* one connection.) Therefore we need to allow multiple instances of the
* same DSID. No duplicate check needed.
*/
void CTwHook::Hook_Add_DSID(TW_UINT32 DSID)
{
pod.HookedDSs[s_iHookCount] = DSID;
s_iHookCount++;
}
/**
* Remove this DS from the list of being hooked
* @param[in] DSID The DS ID to remove from the list
* @return true or false
*/
bool CTwHook::Hook_Remove_DSID(TW_UINT32 DSID)
{
int count = min(MAX_NUM_DS, s_iHookCount);
for(int i=0; i<count; i++)
{
if(pod.HookedDSs[i] == DSID)
{
while(i+1<count)
{
pod.HookedDSs[i] = pod.HookedDSs[i+1];
}
pod.HookedDSs[i] = 0;
s_iHookCount--;
return true;
}
}
// Should never get here. It means we are trying to
// remove a DS that was never hooked.
kLOG((kLOGERR,"Trying to removing a hook for a DSID (%d) that was never added.", DSID ));
return false;
}
/**
* The undocumented LdrGetProcedureAddress...
* @param[in] PHMODULE ModuleHandle we're using to get a function pointer
* @param[in_opt] PANSI_STRING FunctionName of thing we're trying to find
* @param[in_opt] WORD Ordinal, or the number of the things we're trying to find
* @param[out] PVOID *FunctionAddress being sent back to the caller
* @return DWORD
*/
DWORD NTAPI LocalLdrGetProcedureAddress
(
__in HMODULE ModuleHandle,
__in_opt PANSI_STRING FunctionName,
__in_opt WORD Ordinal,
__out PVOID *FunctionAddress
)
{
// See if the caller is asking for TWAIN_32.DLL, and if so, then dive in
// and return our DSM_Entry. This works because attempts to load the
// same DLL more than once just bump up the reference count. Or put
// another way, if function A does a LoadLibrary("xyz") and then function
// B does a LoadLibrary("xzy") the HMODULE values returned will be found
// to be the same.
//
// We don't have to check the FunctionName or the Ordinal, there's only
// one possible return from TWAIN_32.DLL (thank you initial designers),
// and I haven't throught of a good security reason why I need to bother
// checking...
if (ModuleHandle == s_hmoduleTWAIN32)
{
// Get and store the original address in case we need it
(OriginalLdrGetProcedureAddress(ModuleHandle,FunctionName,Ordinal,(PVOID*)&TWAIN32_DSMEntry));
// Return the address to our own function
*FunctionAddress = ::DSM_HookedEntry;
return (ERROR_SUCCESS);
}
// Otherwise let the call continue unmolested...
return (OriginalLdrGetProcedureAddress(ModuleHandle,FunctionName,Ordinal,FunctionAddress));
}
/**
* The undocumented LdrGetProcedureAddressForCaller...
* @param[in] PHMODULE ModuleHandle we're using to get a function pointer
* @param[in_opt] PANSI_STRING FunctionName of thing we're trying to find
* @param[in_opt] WORD Ordinal, or the number of the things we're trying to find
* @param[out] PVOID *FunctionAddress being sent back to the caller
* @param[in] BOOL bValue
* @param[in] PVOID *CallbackAddress
* @return DWORD
*/
DWORD NTAPI LocalLdrGetProcedureAddressForCaller
(
__in HMODULE ModuleHandle,
__in_opt PANSI_STRING FunctionName,
__in_opt WORD Ordinal,
__out PVOID *FunctionAddress,
__in BOOL bValue,
__in PVOID *CallbackAddress
)
{
// See if the caller is asking for TWAIN_32.DLL, and if so, then dive in
// and return our DSM_Entry. This works because attempts to load the
// same DLL more than once just bump up the reference count. Or put
// another way, if function A does a LoadLibrary("xyz") and then function
// B does a LoadLibrary("xzy") the HMODULE values returned will be found
// to be the same.
//
// We don't have to check the FunctionName or the Ordinal, there's only
// one possible return from TWAIN_32.DLL (thank you initial designers),
// and I haven't throught of a good security reason why I need to bother
// checking...
if (ModuleHandle == s_hmoduleTWAIN32)
{
// Get and store the original address in case we need it
(OriginalLdrGetProcedureAddressForCaller(ModuleHandle,FunctionName,Ordinal,(PVOID*)&TWAIN32_DSMEntry,bValue,CallbackAddress));
// Return the address to our own function
*FunctionAddress = ::DSM_HookedEntry;
return (ERROR_SUCCESS);
}
// Otherwise let the call continue unmolested...
return (OriginalLdrGetProcedureAddressForCaller(ModuleHandle,FunctionName,Ordinal,FunctionAddress,bValue,CallbackAddress));
}
/**
* Install the hooks and load the library, if hooks are already installed,
* then just load the library...
*/
HMODULE InstallTwain32DllHooks
(
const char* const _lib,
const bool _hook,
const TW_UINT32 _DSID
)
{
HMODULE hmodule;
CTwHook *ptwhook;
DWORD dwResult;
// Init stuff...
ptwhook = (CTwHook*)NULL;
// We hook before we load the library so that we can intercept calls
// to the Ldr functions during DllMain. But we only do the hook if
// it's the first time we've been here, and we've been asked to do
// hooking (which we won't be if the DSM is doing GetFirst/GetNext to
// enumerate the drivers)...
if (_hook)
{
// If we already have a hook in place, then bump up our
// reference counter...
if ( (s_iHookCount > 0)
&& ((CTwHook*)NULL != s_ptwhook))
{
s_ptwhook->Hook_Add_DSID(_DSID);
}
// Otherwise load the beastie...
else
{
// Allocate our object...
s_iHookCount = 0;
ptwhook = new CTwHook();
if (ptwhook)
{
// Do the hook...
if (ptwhook->Hook(HOOK_ATTACH))
{
// This activates our hooking functions to look for
// attempts to get DSM_Entry...
s_ptwhook = ptwhook;
s_ptwhook->Hook_Add_DSID(_DSID);
}
// No joy, cleanup...
else
{
delete ptwhook;
ptwhook = (CTwHook*)NULL;
s_ptwhook = (CTwHook*)NULL;
}
}
}
}
// Load the library the caller asked for...
hmodule = ::LoadLibrary(_lib);
// If we hooked for this module, and the LoadLibrary failed, then
// undo the hook...
if ( (NULL == hmodule)
&& ((CTwHook*)NULL != ptwhook)
&& _hook)
{
dwResult = ::GetLastError();
s_ptwhook->Hook_Remove_DSID(_DSID);
if (s_iHookCount <= 0)
{
s_ptwhook = (CTwHook*)NULL;
delete ptwhook;
s_iHookCount = 0;
}
::SetLastError(dwResult);
}
// All done...
return(hmodule);
}
/**
* Uninstall the hooks (if needed), and free the library, if hooks are not currently
* installed, then just free the library...
*/
BOOL UninstallTwain32DllHooks
(
const HMODULE _hmodule,
const bool _unhook,
const TW_UINT32 _DSID
)
{
if(_unhook)
{
if (s_ptwhook)
{
// Remove the DS from the list and decrement the count...
s_ptwhook->Hook_Remove_DSID(_DSID);
// If we're at zero, then cleanup. I'm probably being a bit
// paranoid about the cleanup scheme, but I like being paranoid
// when it comes to hooks...
if (s_iHookCount <= 0)
{
CTwHook *ptwhook = s_ptwhook;
s_ptwhook = (CTwHook*)NULL;
delete ptwhook;
s_iHookCount = 0;
}
}
}
// Free the library...
return(::FreeLibrary(_hmodule));
}
// TWDSM_OS_64BIT/TWNDSM_OS_32BIT
#else
#error error, we need to be either 32-bit or 64-bit...
#endif

305
twain/dsm/log.cpp Normal file
View File

@ -0,0 +1,305 @@
/***************************************************************************
* TWAIN Data Source Manager version 2.1
* Manages image acquisition data sources used by a machine.
* Copyright © 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.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Contact the TWAIN Working Group by emailing the Technical Subcommittee at
* twainwg@twain.org or mailing us at 13090 Hwy 9, Suite 3, Boulder Creek, CA 95006.
*
***************************************************************************/
/**
* @file log.cpp
* Log messages.
* Provide logging for the messages to and from the Data Source Manager.
* @author TWAIN Working Group
* @date March 2007
*/
#include "dsm.h"
/**
* Enviroment varible of path to where to write the LogFile name.
* @see CTwnDsmLog
*/
#define kLOGENV "TWAINDSM_LOG"
/**
* Enviroment varible of the fopen logmode to use (if you need to
* grow the log). The default behavior is to wipe it clean each time
* we start up...
* @see CTwnDsmLog
*/
#define kLOGMODEENV "TWAINDSM_LOGMODE"
/**
* Maximum message length we can handle...
* @see CTwnDsmLog
*/
#define TWNDSM_MAX_MSG 1024
/**
* Our implementation class where we hide our attributes...
*/
class CTwnDsmLogImpl
{
public:
/// Make sure we're squeaky clean...
CTwnDsmLogImpl()
{
memset(&pod,0,sizeof(pod));
}
public:
// If you add a class in future, (and I can't imagine why you
// would) declare it here and not in the pod, or the memset
// we do in the constructor will ruin your day...
/**
* We use a pod system because it help prevents us from
* making dumb initialization mistakes...
*/
struct _pod
{
FILE *m_plog; /**< where we'll dump information. */
char *m_message; /**< buffer for our messages. */
char m_logpath[FILENAME_MAX]; /**< where we put the file. */
char m_logmode[16]; /**< how we fopen the file. */
int m_nIndent; /**< how far to indent the log message */
} pod; /**< Pieces of data for CTwnDsmAppsImpl*/
};
/**
* The constructor for our class. This is where we see if we have a
* file in the TWAINDSM_LOG environment variable. If so, then we'll
* log stuff. If not, then we'll log nothing. TWAINDSM_LOGMODE
* selects how we open the file. The default value is "w+", which
* means it's wiped out each time a new session is started. Setting
* this environmental to "a+" will cause the log information to be
* appended to an existing file (a new one will still be created if
* needed...
*/
CTwnDsmLog::CTwnDsmLog()
{
// Init stuff...
m_ptwndsmlogimpl = new CTwnDsmLogImpl;
// see if a logfile is to be used
SGETENV(m_ptwndsmlogimpl->pod.m_logpath,NCHARS(m_ptwndsmlogimpl->pod.m_logpath),kLOGENV);
// If we have a path, then get our mode...
if (m_ptwndsmlogimpl->pod.m_logpath[0])
{
SGETENV(m_ptwndsmlogimpl->pod.m_logmode,NCHARS(m_ptwndsmlogimpl->pod.m_logmode),kLOGMODEENV);
if (!m_ptwndsmlogimpl->pod.m_logmode[0])
{
// The default is to wipe the log clean...
SSTRCPY(m_ptwndsmlogimpl->pod.m_logmode,sizeof(m_ptwndsmlogimpl->pod.m_logmode),"w");
}
// Only bother to allocate a buffer if logging is on...
m_ptwndsmlogimpl->pod.m_message = (char*)calloc(TWNDSM_MAX_MSG,1);
if (!m_ptwndsmlogimpl->pod.m_message)
{
kPANIC("Unable to allocate a buffer for logging...");
}
}
}
/**
* The destructor for our class. Make sure the log is closed,
* free the buffer and destroy our implementation class...
*/
CTwnDsmLog::~CTwnDsmLog()
{
if (m_ptwndsmlogimpl)
{
if (m_ptwndsmlogimpl->pod.m_plog)
{
fclose(m_ptwndsmlogimpl->pod.m_plog);
}
if (m_ptwndsmlogimpl->pod.m_message)
{
free(m_ptwndsmlogimpl->pod.m_message);
}
delete m_ptwndsmlogimpl;
m_ptwndsmlogimpl = 0;
}
}
/**
* Logging function.
*
* We provide a timestamp from hours to milliseconds, which can be
* used to help with performance, and to detect large, unexpected
* idle times. The filename and line number in the source code is
* provided. GetLastError or errno may offer a hint about a problem
* with a system call, but be careful, since it's not cleared and so
* it may report a message that has nothing to do with the current
* calls, or anything going on in the DSM. The id of the thread that
* called us is useful for finding problems with unsafe use, or use
* that crosses thread boundaries in a bad way (like on Windows, when
* one has to stay in the same thread as the HWND if the DAT_NULL
* messages are going to work)...
*/
void CTwnDsmLog::Log(const int _doassert,
const char* const _file,
const int _line,
const char* const _format,
...)
{
// We've nothing to do, so bail...
if (0 == m_ptwndsmlogimpl->pod.m_logpath[0])
{
return;
}
// Okay, now use the stack...
UINT nError = 0;
UINT nChars = 0;
char *message = NULL;
const char *file = NULL;
// Grab the system error, this can be really useful...
#if (TWNDSM_CMP == TWNDSM_CMP_VISUALCPP)
nError = GetLastError();
if (nError == 0)
{
// Yeah, yeah...this is dumb, but I like a clean prefast log... :)
nError = 0;
}
#elif (TWNDSM_CMP == TWNDSM_CMP_GNUGPP)
nError = errno;
#else
#error Sorry, we do not recognize this system...
#endif
// If we have no log yet, try to get one...
if (0 == m_ptwndsmlogimpl->pod.m_plog)
{
FOPEN(m_ptwndsmlogimpl->pod.m_plog,m_ptwndsmlogimpl->pod.m_logpath,m_ptwndsmlogimpl->pod.m_logmode);
if (0 == m_ptwndsmlogimpl->pod.m_plog)
{
fprintf(stderr,"DSM: Error - logging has been disabled because logfile could not be opened: file=<%s>, mode=<%s>, errno=%d\r\n",m_ptwndsmlogimpl->pod.m_logpath,m_ptwndsmlogimpl->pod.m_logmode,errno);
m_ptwndsmlogimpl->pod.m_logpath[0] = 0;
}
return;
}
// Trim the filename down to just the filename, no path...
file = 0;
#if (TWNDSM_CMP == TWNDSM_CMP_VISUALCPP)
// Only look for this on Windows...
file = strrchr(_file,'\\');
#endif
if (!file)
{
// If we didn't find a backslash, try a forward slash...
file = strrchr(_file,'/');
}
if (file)
{
// skip the slash...
file = &file[1];
}
else
{
// Couldn't find any slashes...
file = (char*)_file;
}
// Build the message header...
#if (TWNDSM_CMP == TWNDSM_CMP_VISUALCPP)
SYSTEMTIME st;
GetLocalTime(&st);
nChars = SNPRINTF(m_ptwndsmlogimpl->pod.m_message,
TWNDSM_MAX_MSG,
#if (TWNDSM_CMP_VERSION >= 1400)
TWNDSM_MAX_MSG,
#endif
"[%02d%02d%02d%03d %-8s %4d %5u %p] %.*s",
(int)st.wHour, (int)st.wMinute, (int)st.wSecond,(int)st.wMilliseconds,
file, (int)_line,
nError,
(void*)(UINT_PTR)GETTHREADID(),
m_ptwndsmlogimpl->pod.m_nIndent*2, " ");
#elif (TWNDSM_CMP == TWNDSM_CMP_GNUGPP)
timeval tv;
tm tm;
gettimeofday(&tv,NULL);
tzset();
localtime_r(&tv.tv_sec,&tm);
nChars = SNPRINTF(m_ptwndsmlogimpl->pod.m_message,
TWNDSM_MAX_MSG,
"[%02d%02d%02d%03d %-8s %4d %5d %p] %.*s",
tm.tm_hour,tm.tm_min,tm.tm_sec,(int)(tv.tv_usec / 1000),
file,_line,
nError,
(void*)GETTHREADID(),
m_ptwndsmlogimpl->pod.m_nIndent*2, " ");
#else
#error Sorry, we do not recognize this system...
#endif
// This is the room remaining in the buffer, with room for a null...
nChars = (TWNDSM_MAX_MSG - nChars) - 1;
message = &m_ptwndsmlogimpl->pod.m_message[strlen(m_ptwndsmlogimpl->pod.m_message)];
// Finally, tack on the user portion of the message...
va_list valist;
va_start(valist,_format);
#if (TWNDSM_CMP == TWNDSM_CMP_VISUALCPP) && (TWNDSM_CMP_VERSION >= 1400)
_vsnprintf_s(message,nChars,nChars,_format,valist);
#elif (TWNDSM_CMP == TWNDSM_CMP_VISUALCPP)
_vsnprintf(message,nChars,_format,valist);
#elif (TWNDSM_CMP == TWNDSM_CMP_GNUGPP)
vsnprintf(message,nChars,_format,valist);
#else
#error Sorry, we do not recognize this system...
#endif
va_end(valist);
// Write the message...
fprintf(m_ptwndsmlogimpl->pod.m_plog,"%s\r\n",m_ptwndsmlogimpl->pod.m_message);
fflush(m_ptwndsmlogimpl->pod.m_plog);
// Do the assert, if asked for...
if (_doassert)
{
assert(0);
}
}
void CTwnDsmLog::Indent(int nChange)
{
m_ptwndsmlogimpl->pod.m_nIndent += nChange;
}

BIN
twain/dsm/readme.doc Normal file

Binary file not shown.

31
twain/dsm/resource.h Normal file
View File

@ -0,0 +1,31 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by dsm.rc
//
// Determine what bit verison of OS we are using
#if defined(WIN64) || defined(__x86_64__) || defined(__LP64__) || defined(_M_X64) || defined(_M_IA64)
#define TWNDSM_OS_BIT_STR "64"
#else
#define TWNDSM_OS_BIT_STR "32"
#endif
//
// Identity information that we'll toss into the log and into the version
// resource on Windows...
//
#define TWNDSM_ORGANIZATION "TWAIN Working Group"
#define TWNDSM_DESCRIPTION "TWAIN " TWNDSM_OS_BIT_STR " Source Manager (Image Acquisition Interface)"
#define TWNDSM_VERSION_NUM 2, 5, 0, 0
#define TWNDSM_VERSION_STR "2, 5, 0, 0"
#define ID_LST_SOURCES 10
#define IDC_STATIC 11
#define IDD_DLG_SOURCE 101
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 102
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1003
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

2302
twain/dsm/twain.h Normal file

File diff suppressed because it is too large Load Diff