code_device/twain/dsm/dsm.h

1271 lines
41 KiB
C++

/***************************************************************************
* 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 <windows.h>
#include <direct.h>
#include <share.h>
#elif (TWNDSM_CMP == TWNDSM_CMP_GNUGPP)
#include <dirent.h>
#include <dlfcn.h>
#include <unistd.h>
#include <errno.h>
#include <stdarg.h>
#include <time.h>
#include <sys/syscall.h>
#include <sys/time.h>
#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 <stdio.h>
#include <assert.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdlib.h>
/**
* 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__