/*************************************************************************** * 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 dsm.h * Everything we need to make our .cpp files happy. * * @author TWAIN Working Group * @date March 2007 */ #ifndef __DSM_H__ #define __DSM_H__ /** * @defgroup Enviroment the computer enviroment * First off, figure out what compiler we're running and on which * platform we think we're running it. We assume that you're building * on the same platform you intend to run, so if you are cross compiling * you will likely have a bit of work to do here... * @{ */ /** * @defgroup Compilers Compilers we support... * @{ */ #define TWNDSM_CMP_VISUALCPP 0x1001 ///< Preferably 2005+ #define TWNDSM_CMP_GNUGPP 0x1002 ///< Preferably v4.x+ //@} /** * @defgroup Platforms Platforms we support... * @{ */ #define TWNDSM_OS_WINDOWS 0x2001 ///< Preferably Win2K+ #define TWNDSM_OS_MACOSX 0x2002 ///< Preferably 10.4+ #define TWNDSM_OS_LINUX 0x2003 ///< Preferably 2.6+ kernel //@} /** * If the user defines TWNDSM_CMP in their make file or project, * then we'll assume they want to take responsibility for picking * how we'll build the system. At this point it seems like the * compiler definition is used to select which native library calls * we're dealing with, while the os definition is more about * where we'll expect to find stuff on the running system, like * directories... */ #ifndef TWNDSM_CMP /** * @def TWNDSM_CMP * The compliler used * * @def TWNDSM_CMP_VERSION * The version of the compliler used * * @def TWNDSM_OS * The Operating system of the compliler used * * @def TWNDSM_OS_64BIT * defined to 1 if system is 64 bit * * @def TWNDSM_OS_32BIT * defined to 1 if system is 32 bit */ // GNU g++ #if defined(__GNUC__) #define TWNDSM_CMP TWNDSM_CMP_GNUGPP #define TWNDSM_CMP_VERSION __GNUC__ #if defined(__APPLE__) #define TWNDSM_OS TWNDSM_OS_MACOSX #else #define TWNDSM_OS TWNDSM_OS_LINUX #endif #if defined(__x86_64__) || defined(__LP64__) #define TWNDSM_OS_64BIT 1 #else #define TWNDSM_OS_32BIT 1 #endif // Visual Studio C++ #elif defined(_MSC_VER) #define TWNDSM_CMP TWNDSM_CMP_VISUALCPP #define TWNDSM_CMP_VERSION _MSC_VER #define TWNDSM_OS TWNDSM_OS_WINDOWS #if defined(_M_X64) || defined(_M_IA64) #define TWNDSM_OS_64BIT 1 #else #define TWNDSM_OS_32BIT 1 #endif // ruh-roh... #else Sorry, we do not recognize this system... #endif #endif /** * Pull in the system specific headers... */ #if (TWNDSM_CMP == TWNDSM_CMP_VISUALCPP) #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers #endif #include #include #include #elif (TWNDSM_CMP == TWNDSM_CMP_GNUGPP) #include #include #include #include #include #include #include #include #define gettid() syscall(SYS_gettid) #else #error Sorry, we do not recognize this system... #endif // End @defgroup Enviroment //@} /** * We use resource.h to specify version info on all platforms... */ #include "resource.h" /** * These headers are available on all platforms... */ #include #include #include #include #include #include /** * This is for IDEs like Visual Studio .Net 2003, that does not understand the SAL Annotations */ #ifndef __in #define __in #define __out #define __in_opt #endif /** * Don't forget to include TWAIN... */ #include "twain.h" /** * @defgroup CrossPlatformFunc Cross platform functions, defines, and macroes * @{ * * * @def DllExport * set system dll export configuration __declspec( dllexport ) * * @def NCHARS * The number of characters in a charter array * * @def PATH_SEPERATOR * the operating system's symble used as a path seperator * * @def LOADLIBRARY(lib, hook, DSid) * Call system loadibrary function. OS abstraction macro that tries to load a library. * @param[in] lib path and name of library * @param[in] hook true if we want to attempt to hook this library * @param[in] DSid if hooking is the ID of the DS we are hooking * * @def LOADFUNCTION(lib, func) * Call system GetProcAddress function. OS abstraction macro that tries to locate the addess of a funtion name. * @param[in] lib path and name of library * @param[in] func name of the funtion * * @def UNLOADLIBRARY(lib, unhook, DSid) * Call system FreeLibrary function. OS abstraction macro that tries to release the library. * @param[in] lib library modual to unload * @param[in] unhook true if we want to attempt to unhook this library * @param[in] DSid if unhooking is the ID of the DS we are unhooking * * @def READ * OS abstraction macro that calls system _read function. * * @def CLOSE * OS abstraction macro that calls system _close function. * * @def SNPRINTF * OS abstraction macro that calls system _snprintf function. * * @def UNLINK * OS abstraction macro that calls system _unlink function. * * @def STRNICMP * OS abstraction macro that calls system _strnicmp function. * * @def DSMENTRY * the DSM entry point type * * @def GETTHREADID * get the thread ID * * @def FOPEN * @param[out] pf pointer to the file to store the opened file * @param[in] name the path and name of the file to open * @param[in] mode the mode to open the file * * @def kTWAIN_DS_DIR * The path to where TWAIN Data Sources are stored on the system */ #if (TWNDSM_CMP == TWNDSM_CMP_VISUALCPP) // Define TW_IDENTITY.Id #define TWID_T TW_UINT32 #define TWIDDEST_T TW_UINT32 // For 64-bit systems we work the same as on Linux/MacOSX... #if TWNDSM_OS_64BIT #define LOADLIBRARY(lib,hook,DSID) LoadLibrary(lib) #define UNLOADLIBRARY(hmodule,unhook,DSID) FreeLibrary((HMODULE)hmodule) // For 32-bit systems we use a hooking mechanism to help 1.x // drivers find the new TWAINDSM.DLL... #else HMODULE InstallTwain32DllHooks ( const char* const _lib, const bool _hook, const TWID_T _DSID ); BOOL UninstallTwain32DllHooks ( const HMODULE _hmodule, const bool _unhook, const TWID_T _DSID ); #define LOADLIBRARY(lib,hook,DSID) InstallTwain32DllHooks(lib,hook,DSID) #define UNLOADLIBRARY(hmodule,unhook,DSID) UninstallTwain32DllHooks((HMODULE)hmodule,unhook,DSID) #endif #define DllExport __declspec( dllexport ) #define NCHARS(s) sizeof(s)/sizeof(s[0]) #define PATH_SEPERATOR '\\' #define LOADFUNCTION(lib, func) GetProcAddress((HMODULE)lib, func) #define READ _read #define CLOSE _close #if (TWNDSM_CMP_VERSION >= 1400) #define SNPRINTF _snprintf_s #else #define SNPRINTF _snprintf #endif #define UNLINK _unlink #define STRNICMP _strnicmp #define DSMENTRY TW_UINT16 FAR PASCAL #define GETTHREADID ::GetCurrentThreadId #define FOPEN(pf, name, mode) pf = _fsopen(name, mode, _SH_DENYNO) #ifndef kTWAIN_DS_DIR #if TWNDSM_OS_64BIT #define kTWAIN_DS_DIR "twain_64" #else #define kTWAIN_DS_DIR "twain_32" #endif #endif #elif (TWNDSM_CMP == TWNDSM_CMP_GNUGPP) #define DllExport #define NCHARS(s) sizeof(s)/sizeof(s[0]) #define PATH_SEPERATOR '/' #if (TWNDSM_OS == TWNDSM_OS_MACOSX) #define LOADLIBRARY(lib,hook,DSID) \ CFBundleCreate(0, CFURLCreateWithFileSystemPath(0, CFStringCreateWithCStringNoCopy(0, _pPath, kCFStringEncodingUTF8, 0), kCFURLPOSIXPathStyle, TRUE)) #define UNLOADLIBRARY(lib,unhook,DSID) 0; CFRelease((CFBundleRef)(lib)) #else #define LOADLIBRARY(lib,hook,DSID) dlopen(lib, RTLD_LAZY) #define UNLOADLIBRARY(lib,unhook,DSID) dlclose(lib) #endif #define LOADFUNCTION(lib, func) dlsym(lib, func) #define READ read #define CLOSE close #define SNPRINTF snprintf #define UNLINK unlink #define STRNICMP strncasecmp #define GETTHREADID gettid #define FOPEN(pf,name,mode) pf = fopen(name,mode) #ifndef kTWAIN_DS_DIR #if (TWNDSM_OS == TWNDSM_OS_MACOSX) #define kTWAIN_DS_DIR "/Library/Image Capture/TWAIN Data Sources" #else #define kTWAIN_DS_DIR "/usr/local/lib/twain" #endif #endif typedef unsigned int UINT; typedef void* HINSTANCE; typedef void* HWND; #define DSMENTRY FAR PASCAL TW_UINT16 #if (TWNDSM_OS == TWNDSM_OS_MACOSX) #if TWNDSM_OS_64BIT #define TWID_T unsigned long long #define TWIDDEST_T TW_MEMREF #else #define TWID_T unsigned long #define TWIDDEST_T TW_MEMREF #endif #else #define TWID_T TW_UINT32 #define TWIDDEST_T TW_UINT32 #endif #if !defined(TRUE) #define FALSE 0 #define TRUE 1 #endif #else #error Sorry, we do not recognize this system... #endif /** * @defgroup StringFunctions use secure string functions if we have them * We want to use secure string functions whenever possible, if g++ * every includes a set I think it would be excellent to switch over * to it, but at least with Windows using them we stand a better * chance of finding boo-boos... * @{ * * @def SSTRCPY * Secure String copy * @param[out] d destination string * @param[in] z size of destination in char * @param[in] s the source string * * @def SSTRCAT * Secure String catinate * @param[out] d destination string * @param[in] z size of destination in char * @param[in] s the source string * * @def SSTRNCPY * Secure String n copy * @param[out] d destination string * @param[in] z size of destination in char * @param[in] s the source string * @param[in] m the number of char to copy * * @def SGETENV * Secure Get enviroment varable * @param[out] d destination string * @param[in] z size of destination in char * @param[in] n the source string * */ #if (TWNDSM_CMP == TWNDSM_CMP_VISUALCPP) && (TWNDSM_CMP_VERSION >= 1400) #define SSTRCPY(d,z,s) strncpy_s(d,z,s,_TRUNCATE) #define SSTRCAT(d,z,s) strncat_s(d,z,s,_TRUNCATE) #define SSTRNCPY(d,z,s,m) strncpy_s(d,z,s,m) #define SGETENV(d,z,n) ::GetEnvironmentVariable(n,d,z) inline int SSNPRINTF(char *d, const size_t z, const size_t c, const char* const f,...) { int result; va_list valist; va_start(valist,f); result = _vsnprintf_s(d,z,c,f,valist); va_end(valist); return result; } /** * These functions are insecure, but everybody has them, so we * don't need an else/error section like we use everywhere else... */ #elif __APPLE__ #define SSTRCPY(d,z,s) strlcpy(d,s,z) #define SSTRCAT(d,z,s) strcat(d,s) #define SSTRNCPY(d,z,s,m) strncpy(d,s,m) #define SGETENV(d,z,n) strcpy(d,getenv(n)?getenv(n):"") inline int SSNPRINTF(char *d, const size_t, const size_t c, const char* const f,...) { int result; va_list valist; va_start(valist,f); #if (TWNDSM_CMP == TWNDSM_CMP_VISUALCPP) result = _vsnprintf(d,c,f,valist); #elif (TWNDSM_CMP == TWNDSM_CMP_GNUGPP) result = vsnprintf(d,c,f,valist); #else #error Sorry, we do not recognize this system... #endif va_end(valist); return result; } /** * These functions are insecure, but everybody has them, so we * don't need an else/error section like we use everywhere else... */ #else #define SSTRCPY(d,z,s) strcpy(d,s) #define SSTRCAT(d,z,s) strcat(d,s) #define SSTRNCPY(d,z,s,m) strncpy(d,s,m) #define SGETENV(d,z,n) strcpy(d,getenv(n)?getenv(n):"") inline int SSNPRINTF(char *d, const size_t, const size_t c, const char* const f,...) { int result; va_list valist; va_start(valist,f); #if (TWNDSM_CMP == TWNDSM_CMP_VISUALCPP) result = _vsnprintf(d,c,f,valist); #elif (TWNDSM_CMP == TWNDSM_CMP_GNUGPP) result = vsnprintf(d,c,f,valist); #else #error Sorry, we do not recognize this system... #endif va_end(valist); return result; } #endif // End @defgroup StringFunctions //@} // End @defgroup CrossPlatformFunc //@} /** *@defgroup Logging logging defines and functions * These aren't logging levels, these are definitions to tell us whether * or not to assert. * @see kLOG */ /** * write info messages to LogFile. */ #define kLOGINFO 0,__FILE__,__LINE__ /** * write error messages to LogFile. */ #define kLOGERR 1,__FILE__,__LINE__ /** * Define to write messages to LogFile. * @see CTwnDsmLog */ #define kLOG(a) if (g_ptwndsmlog) g_ptwndsmlog->Log a // End @defgroup Logging //@} /** * Display message to user. Use this if logging is not an * option, and this is the only way to track a problem!!! * @see kLOG */ #if (TWNDSM_CMP == TWNDSM_CMP_VISUALCPP) #define kPANIC(msg) ::MessageBox(NULL,msg,"TWAIN Data Source Manager",MB_OK); #elif (TWNDSM_CMP == TWNDSM_CMP_GNUGPP) #define kPANIC(msg) fprintf(stderr,"TWAIN Data Source Manager: %s\r\n",msg); #else #error Sorry, we do not recognize this system... #endif /** * Maximum number of Data Sources that can be opened under one * application. This item seems useful, though the number * seems rather high. */ #define MAX_NUM_DS 50 /** * Possible States of the DSM. * The three possible states of the Data Source Manager. We don't * want to know about the other states, because that would add * needless complexity. */ typedef enum { dsmState_PreSession = 1, /**< Source Manager not loaded. */ dsmState_Loaded = 2, /**< Source Manager is loaded, but not open. */ dsmState_Open = 3 /**< Source Manager is open. */ } DSM_State; /** * This function wraps the function loading calls. Linux has a * special way to check dlsym failures. */ void* DSM_LoadFunction(void* _pHandle, const char* _pszSymbol); /** * @class CTwnDsmLog * Our logging class. We use the impl to encapsulate the private * portions of the class, which doesn't matter for this class so * much as it does for the next one. Then we give ourselves an * extern, because life is easier if we treat this object as globally * accessible (think of it like a service). */ class CTwnDsmLogImpl; class CTwnDsmLog { public: /** * The CTwnDsmLog constructor. */ CTwnDsmLog(); /** * The CTwnDsmLog destructor. */ ~CTwnDsmLog(); /** * The logging function. This should only be access through * the kLOG macro... * @param[in] _doassert decides if we assert or not * @param[in] _file the source file of the message * @param[in] _line the source line of the message * @param[in] _format the format of the message (same as sprintf) * @param[in] ... arguments to the format of the message */ void Log(const int _doassert, const char* const _file, const int _line, const char* const _format, ...); /** * Indent the logging to help with seeing recursive calls * param[in] nChange Either +1 or -1 */ void Indent(int nChange); private: /** * The implementation pointer helps with encapulation. */ CTwnDsmLogImpl *m_ptwndsmlogimpl; }; extern CTwnDsmLog *g_ptwndsmlog; /** * @class CTwnDsmApps * Class to hold list of connected applications. * In 32bit enviroments each application will connect to a seperate * instance of DSM data but with this list it allows ONE application * to connect several time, as long as it uses a different name with * each connection. I'm still not sure why you'd want to do that, * but there it is. This class is intended to hide the gory details * of how we're storing the data, so an impl is used. */ class CTwnDsmAppsImpl; class CTwnDsmApps { public: /** * The CTwnDsmApps constructor. */ CTwnDsmApps(); /** * The CTwnDsmApps destructor. */ ~CTwnDsmApps(); /** * Add an application. * This supports MSG_OPENDSM. * @param[out] _pAppId Origin of message * @param[in] _MemRef the HWND on Window, null otherwise * @return a valid TWRC_xxxx return code */ TW_UINT16 AddApp(TW_IDENTITY *_pAppId, TW_MEMREF _MemRef); /** * Remove an application. * This supports MSG_CLOSEDSM. * @param[in] _pAppId Origin of message * @return a valid TWRC_xxxx return code */ TW_UINT16 RemoveApp(TW_IDENTITY *_pAppId); /** * Loads a DS from disk and adds it to a global list of DS's. * @param[in] _pAppId Origin of message * @param[in] _DsId the source index of the library to open * @return a valid TWRC_xxxx return code */ TW_INT16 LoadDS(TW_IDENTITY *_pAppId, TWID_T _DsId); /** * Unloads a DS and frees all its resources... * @param[in] _pAppId Origin of message * @param[in] _DsId the source index */ void UnloadDS(TW_IDENTITY *_pAppId, TWID_T _DsId); /** * Validate that an id is in range... * @param[in] _pAppId id of App to test * @return TRUE if valid, else FALSE */ TW_BOOL AppValidateId(TW_IDENTITY *_pAppId); /** * Validate that the App ID and DS ID are in range... * @param[in] _pAppId id of App to test * @param[in] _pDSId id of DS to test * @return TRUE if valid, else FALSE */ TW_BOOL AppValidateIds(TW_IDENTITY *_pAppId, TW_IDENTITY *_pDSId); /** * Return a pointer to the application's identity. * Yeah, I know, this sorta violates encapsulation, but we do not * want to get silly about this... * @param[in] _pAppId id of identity to get * @return pointer to identity or NULL */ TW_IDENTITY *AppGetIdentity(TW_IDENTITY *_pAppId); /** * Get the condition code, then reset it internally to TWCC_SUCCESS, * so you can only get it once, per the specification... * @param[in] _pAppId id of app, or NULL if we have no apps * @return TWCC_ value */ TW_UINT16 AppGetConditionCode(TW_IDENTITY *_pAppId); /** * Set the condition code * @param[in] _pAppId id of app, or NULL if we have no apps * @param[in] _conditioncode the code to use */ void AppSetConditionCode(TW_IDENTITY *_pAppId, TW_UINT16 _conditioncode); /** * Get the state of the DSM for all applications * @return DSM_State, Open if at least one application has DSM open */ DSM_State AppGetState(); /** * Get the state of the DSM for the specified application * @param[in] _pAppId id of app * @return DSM_State of the application */ DSM_State AppGetState(TW_IDENTITY *_pAppId); /** * Get the hwnd sent in with the call to MSG_OPENDSM * @param[in] _pAppId id of app * @return hwnd for the application that is calling us */ void *AppHwnd(TW_IDENTITY *_pAppId); /** * Get the number of drivers we found as the result of a * successful call to LoadDS with _boolKeepOpen set to * false (meaning that we were just browsing)... * @param[in] _pAppId id of app * @return DSM_State of the application */ TWID_T AppGetNumDs(TW_IDENTITY *_pAppId); /** * Poke the application to wake it up when sending a * DAT_NULL message to it... * @param[in] _pAppId id of app */ void AppWakeup(TW_IDENTITY *_pAppId); /** * Get a pointer to the identity of the specified driver... * @param[in] _pAppId id of app * @param[in] _DsId numeric id of driver * @return pointer to drivers identity or NULL */ TW_IDENTITY *DsGetIdentity(TW_IDENTITY *_pAppId, TWID_T _DsId); /** * Get a pointer to the DS_Entry function of the specified driver... * @param[in] _pAppId id of app * @param[in] _DsId numeric id of driver * @return pointer to DS_Entry for this driver or NULL */ DSENTRYPROC DsGetEntryProc(TW_IDENTITY *_pAppId, TWID_T _DsId); /** * Get a pointer to the driver file path and name, which is guaranteed to * be unique, even if the ProductName's aren't for some horrible * reason... * @param[in] _pAppId id of app * @param[in] _DsId numeric id of driver * @return pointer to file path and name for this driver or NULL */ char *DsGetPath(TW_IDENTITY *_pAppId, TWID_T _DsId); /** * Get a pointer to TW_CALLBACK structure for the specified driver... * reason... * @param[in] _pAppId id of app * @param[in] _DsId numeric id of driver * @return pointer to the callback structure for this driver or NULL */ TW_CALLBACK2 *DsCallback2Get(TW_IDENTITY *_pAppId, TWID_T _DsId); /** * Test if the driver has a callback pending for attention... * @param[in] _pAppId id of app * @param[in] _DsId numeric id of driver * @return TRUE if the driver needs its callback called */ TW_BOOL DsCallbackIsWaiting(TW_IDENTITY *_pAppId, TWID_T _DsId); /** * Set the callback flag for the driver to TRUE if the callback * needs to have its callback called, and set it to FALSE after * the call has been made... * @param[in] _pAppId id of app * @param[in] _DsId numeric id of driver * @param[in] _Waiting the new state for the waiting flag */ void DsCallbackSetWaiting(TW_IDENTITY *_pAppId, TWID_T _DsId, TW_BOOL _Waiting); /** * Check if the DS is still processing last message * @param[in] _pAppId id of app * @param[in] _DsId numeric id of driver * @return TRUE if the DS has not finished processing message */ TW_BOOL DsIsProcessingMessage(TW_IDENTITY *_pAppId, TWID_T _DsId); /** * Set the ProcessingMessage flag. * This is how we know the DS is not done processing the previous message * @param[in] _pAppId id of app * @param[in] _DsId numeric id of driver * @param[in] _Processing the new state for the processing flag */ void DsSetProcessingMessage(TW_IDENTITY *_pAppId, TWID_T _DsId, TW_BOOL _Processing); /** * Check if the App is still processing last callback. * @param[in] _pAppId id of app * @param[in] _DsId numeric id of driver * @return TRUE if the App has not finished processing callback */ TW_BOOL DsIsAppProcessingCallback(TW_IDENTITY *_pAppId, TWID_T _DsId); /** * Set the AppProcessingCallback flag. * This is how we know the App is not done processing the previous callback * @param[in] _pAppId id of app * @param[in] _DsId numeric id of driver * @param[in] _Processing the new state for the processing flag */ void DsSetAppProcessingCallback(TW_IDENTITY *_pAppId, TWID_T _DsId, TW_BOOL _Processing); /** * Get number of allocated App slots (Last valid App ID +1) * @return number of allocated App slots (Last valid App ID +1) */ TWID_T AppGetNumApp(); private: /** * The implementation pointer helps with encapulation. */ CTwnDsmAppsImpl *m_ptwndsmappsimpl; }; /** * This is the main class for the Data Source Manager. Unlike the * other classes this one isn't using an impl interface. The * rationale is that DSM_Entry is the true interface point, nobody * who calls the DSM has to know anything about the implementation. * So there's no benefit (except a programmer's desire for * consistency) to putting in the impl. I'm resisting that on the * theory that if I don't need it, why make things more complex. * YMMV... */ class CTwnDsm { // // All of our public functions go here... // public: /** * Our CTwnDsm constructor... */ CTwnDsm(); /** * Our CTwnDsm destructor... */ ~CTwnDsm(); /** * The guts of the DSM_Entry, the resource management portion * resides in a our DSM_Entry entry point, which isn't a part * of this class. Hopefully it's not confusing that they have * the same name... * @param[in] _pOrigin Origin of message in this case a DS * @param[in] _pDest destination of message in this case an App * @param[in] _DG message id: DG_xxxx * @param[in] _DAT message id: DAT_xxxx * @param[in] _MSG message id: MSG_xxxx * @param[in] _pData the Data * @return a valid TWRC_xxxx return code */ TW_UINT16 DSM_Entry(TW_IDENTITY *_pOrigin, TW_IDENTITY *_pDest, TW_UINT32 _DG, TW_UINT16 _DAT, TW_UINT16 _MSG, TW_MEMREF _pData); #if (TWNDSM_CMP == TWNDSM_CMP_VISUALCPP) /** * Selection dialog, for apps that don't want to do GetFirst * GetNext. This is only public because of the way that * dialogs are implemented. * @param[in] _hWnd Window handle of the dialog * @param[in] _Message message * @param[in] _wParam wparam * @param[in] _lParam lparam * @return FALSE if we processed the message */ BOOL CALLBACK SelectDlgProc(HWND _hWnd, UINT _Message, WPARAM _wParam, LPARAM _lParam); #elif (TWNDSM_CMP == TWNDSM_CMP_GNUGPP) // We don't have one of these... #else #error Sorry, we do not recognize this system... #endif /** * Get the state of the DSM by checking the state of all applications * @return DSM_State, Open if at least one application has DSM open */ DSM_State DSMGetState(); // // All of our private functions go here... // private: /** * Handles DAT_NULL calls from DS for Application. * @param[in] _pAppId Origin of message * @param[in] _pDsId TW_IDENTITY structure * @param[in] _MSG message id: MSG_xxxx * @return a valid TWRC_xxxx return code */ TW_INT16 DSM_Null(TW_IDENTITY *_pAppId, TW_IDENTITY *_pDsId, TW_UINT16 _MSG); /** * Returns the current DSM status. Resets pod.m_ConditionCode to * TWCC_SUCCESS per the specification. * @param[in] _pAppId Orgin of message * @param[in] _MSG message id: MSG_xxxx * @param[out] _pStatus TW_STATUS structure * @return a valid TWRC_xxxx return code */ TW_INT16 DSM_Status(TW_IDENTITY *_pAppId, TW_UINT16 _MSG, TW_STATUS *_pStatus); /** * Initializes or closes the DSM * @param[in] _pAppId Orgin of message * @param[in] _MSG message id: MSG_xxxx * @param[in] _MemRef for Windows during MSG_OPENDSM it is HWND, null otherwise * @return a valid TWRC_xxxx return code */ TW_INT16 DSM_Parent(TW_IDENTITY *_pAppId, TW_UINT16 _MSG, TW_MEMREF _MemRef); /** * Source operations * @param[in] _pAppId Origin of message * @param[in] _MSG message id: MSG_xxxx * @param[in] _pDsId TW_IDENTITY structure * @return a valid TWRC_xxxx return code */ TW_INT16 DSM_Identity(TW_IDENTITY *_pAppId, TW_UINT16 _MSG, TW_IDENTITY *_pDsId); /** * This routine will return the path to a DS. * This is here for backwards compatibility. DAT_TWUNKIDENTITY is * undocumented. It was used by the Twunking layer. Some old * applications use it to get the path to the DS. We need to * continue to support it. * @param[in] _pAppId Origin of message * @param[in] _MSG message id: MSG_GET * @param[in,out] _pTwunkId TW_TWUNKIDENTITY structure with a valid TW_IDENTITY, returns path * @return a valid TWRC_xxxx return code */ TW_INT16 DSM_TwunkIdentity(TW_IDENTITY *_pAppId, TW_UINT16 _MSG, TW_TWUNKIDENTITY *_pTwunkId); /** * Gets entry points * @param[in] _pAppId Origin of message * @param[in] _MSG message id: MSG_xxxx * @param[out] _pEntrypoint TW_IDENTITY structure * @return a valid TWRC_xxxx return code */ TW_INT16 DSM_Entrypoint(TW_IDENTITY *_pAppId, TW_UINT16 _MSG, TW_ENTRYPOINT *_pEntrypoint); /** * Register application's callback. * @param[in] _pAppId Origin of message * @param[in] _pDsId TW_IDENTITY structure * @param[in] _MSG message id: MSG_xxxx valid = MSG_REGISTER_CALLBACK * @param[in] _pData pointer to a callback struct * @return a valid TWRC_xxxx return code */ TW_INT16 DSM_Callback(TW_IDENTITY *_pAppId, TW_IDENTITY *_pDsId, TW_UINT16 _MSG, TW_CALLBACK *_pData); /** * Register application's callback. * @param[in] _pAppId Origin of message * @param[in] _pDsId TW_IDENTITY structure * @param[in] _MSG message id: MSG_xxxx valid = MSG_REGISTER_CALLBACK * @param[in] _pData pointer to a callback2 struct * @return a valid TWRC_xxxx return code */ TW_INT16 DSM_Callback2(TW_IDENTITY *_pAppId, TW_IDENTITY *_pDsId, TW_UINT16 _MSG, TW_CALLBACK2 *_pData); /** * Opens the Data Source specified by pDSIdentity. * pDSIdentity must be valid, but if a null name and id * is 0 then open default. * @param[in] _pAppId Origin of message * @param[in] _pDsId TW_IDENTITY structure * @return a valid TWRC_xxxx return code */ TW_INT16 OpenDS(TW_IDENTITY *_pAppId, TW_IDENTITY *_pDsId); /** * Closes the Data Source specified by pDSIdentity. * @param[in] _pAppId Origin of message * @param[in] _pDsId TW_IDENTITY structure * @return a valid TWRC_xxxx return code */ TW_INT16 CloseDS(TW_IDENTITY *_pAppId, TW_IDENTITY *_pDsId); /** * Displays the source select dialog and sets the default source. * @param[in] _pAppId Origin of message * @param[in,out] _pDsId TW_IDENTITY structure * @return a valid TWRC_xxxx return code */ TW_INT16 DSM_SelectDS(TW_IDENTITY *_pAppId, TW_IDENTITY *_pDsId); /** * Set the default source. * @param[in] _pAppId Origin of message * @param[in] _pDsId TW_IDENTITY structure * @return a valid TWRC_xxxx return code */ TW_INT16 DSM_SetDefaultDS(TW_IDENTITY *_pAppId, TW_IDENTITY *_pDsId); /** * Goes through the applications supported data sources looking for one that has * the exact same name as product name in the passed in identity. Will update the * _pDsId structure to match the name. * @param[in] _pAppId Origin of message * @param[in,out] _pDsId TW_IDENTITY structure * @return a valid TWRC_xxxx return code */ TW_INT16 GetDSFromProductName(TW_IDENTITY *_pAppId, TW_IDENTITY *_pDsId); /** * Copies the applications first available source into _pDsId. * @param[in] _pAppId The origin identity structure * @param[out] _pDsId the identity structure to copy data into * @return a valid TWRC_xxxx return code */ TW_INT16 DSM_GetFirst(TW_IDENTITY *_pAppId, TW_IDENTITY *_pDsId); /** * Copies the applications next available source into _pDsId. A call to * DSM_GetFirst must have been made at least once before calling this function. * @param[in] _pAppId The origin identity structure * @param[out] _pDsId the identity structure to copy data into * @return a valid TWRC_xxxx return code */ TW_INT16 DSM_GetNext(TW_IDENTITY *_pAppId, TW_IDENTITY *_pDsId); /** * This routine will check if the current default source matches the * applications supported groups. If it does it will copy it into the default * Source's identity (_pDsId), otherwise this routine will search for a source that * does match the app's supported groups and copy it into _pDsId. * @param[in] _pAppId The application identity * @param[in,out] _pDsId A pointer reference that will be set to point to the default identity. * @return a valid TWRC_xxxx return code */ TW_INT16 GetMatchingDefault(TW_IDENTITY *_pAppId, TW_IDENTITY *_pDsId); /** * Return back the tw_identity of the current source. In state 3 * this will be the default source. In state 4 this will be the * currently opened source. * @param[in] _pAppId The application identity * @param[in,out] _pDsId A pointer reference that will be set to point to the current identity. * @return a valid TWRC_xxxx return code */ TW_INT16 GetIdentity(TW_IDENTITY *_pAppId, TW_IDENTITY *_pDsId); /** * prints to stdout information about the triplets. * @param[in] _pOrigin the Orgin to print the Product Name * @param[in] _pDest the Destination to print the Product Name * @param[in] _DG the Data Group * @param[in] _DAT the Data Argument Type * @param[in] _MSG the Message * @param[in] _pData the Data * @return return true if actually printed triplet */ bool printTripletsInfo(const TW_IDENTITY *_pOrigin, const TW_IDENTITY *_pDest, const TW_UINT32 _DG, const TW_UINT16 _DAT, const TW_UINT16 _MSG, const TW_MEMREF _pData); /** * prints to stdout information about result of processing the triplets. * @param[in] _DG the Data Group * @param[in] _DAT the Data Argument Type * @param[in] _MSG the Message * @param[in] _pData the Data * @param[in] _RC the Return Code after */ void printResults(const TW_UINT32 _DG, const TW_UINT16 _DAT, const TW_UINT16 _MSG, const TW_MEMREF _pData, const TW_UINT16 _RC); /** * Translates the _MSG passed in into a string and returns it * @param[out] _szMsg string to copy into * @param[in] _nChars max chars in _szMsg * @param[in] _MSG the TWAIN message to translate */ void StringFromMsg(char *_szMsg, const int _nChars, const TW_UINT16 _MSG); /** * Translates the _DAT passed in into a string and returns it * @param[out] _szDat string to copy into * @param[in] _nChars max chars in _szDat * @param[in] _DAT the TWAIN data argument type to translate */ void StringFromDat(char *_szDat, const int _nChars, const TW_UINT16 _DAT); /** * Translates the _DG passed in into a string and returns it * @param[out] _szDg string to copy into * @param[in] _nChars max chars in _szDg * @param[in] _DG the TWAIN data group to translate */ void StringFromDg(char *_szDg, const int _nChars, const TW_UINT32 _DG); /** * Translates the _Cap passed in into a string and returns it * @param[out] _szCap string to copy into * @param[in] _nChars max chars in _szCap * @param[in] _Cap the TWAIN Capability to translate */ void StringFromCap(char *_szCap, const int _nChars, const TW_UINT16 _Cap); /** * Translates the _ConType and _hContainer passed in into a string and returns it * @param[out] _szConType string to copy into * @param[in] _nChars max chars in _szCap * @param[in] _ConType the TWAIN Container Type to translate */ void StringFromConType(char *_szConType, const int _nChars, const TW_UINT16 _ConType); /** * Translates the rc passed in into a string and returns it * @param[out] _szRc string to copy into * @param[in] _nChars max chars in szRc * @param[in] _rc the TWAIN Return Code to translate */ void StringFromRC(char *_szRc, const int _nChars, const TW_UINT16 _rc); /** * Translates the Condition Code passed in into a string and returns it * @param[out] _szCondCode string to copy into * @param[in] _nChars max chars in szRc * @param[in] _cc the TWAIN Condition Code to translate */ void StringFromConditionCode(char *_szCondCode, const int _nChars, const TW_UINT16 _cc); // // All of our attributes should be private. Encapsulation // is a good thing... :) // private: /* ** If you add a class in future, declare it here and not ** in the pod, or the memset we do on pod will ruin your ** day... */ /** * We use a pod system because it help prevents us from * making dumb initialization mistakes. */ struct _pod { /** * The class takes care of our list of applications and drivers. */ CTwnDsmApps *m_ptwndsmapps; /** * The path to the default DS. The Default DS is identified when * the DSM is opened. A new Default is saved if SelectDlg is used. * So this value will be compared against DsGetPath()... */ char m_DefaultDSPath[FILENAME_MAX]; /** * The next id to test for GetFirst/GetNext... */ TWID_T m_nextDsId; /** * The DS ID we end up with from SelectDlgProc. This is only * used on the Windows platform. */ TW_IDENTITY *m_pSelectDlgDsId; /** * The Application ID we're using inside of SelectDlgProc. This * is only used on the Windows platform. */ TW_IDENTITY *m_pSelectDlgAppId; } pod; /**< Pieces of Data for the DSM class*/ }; #endif // __DSM_H__