_IMAGE ACQUISITION USING TWAIN_ by Craig A. Lindley Listing One /***************************************************************************/ /*** containr.hpp -- interface class for TWAIN containers. ***/ /*** adapted by Craig A. Lindley -- Revision: 1.0 Last Update: 12/11/93 ***/ /****************************************************************************/ // See the file containr.cpp for the revision history // Check to see if this file already included #ifndef CONTAINR_HPP #define CONTAINR_HPP #include "dc.h" class huge Containr { private: void GetItem(DC_UINT16 Type, LPVOID lpSource, LPVOID lpDest, int SourceIndex, int DestIndex); public: DC_FIX32 FloatToFIX32(float AFloat); float FIX32ToFloat(DC_FIX32 Fix32); BOOL BuildUpOneValue(pDC_CAPABILITY pCap,DC_UINT16 ItemType,DC_UINT32 Item); BOOL ExtractOneValue(pDC_CAPABILITY pCap, LPVOID pVoid); BOOL BuildUpEnumerationType(pDC_CAPABILITY pCap,pDC_ENUMERATION pE, LPVOID lpList); BOOL ExtractEnumerationValue(pDC_CAPABILITY pCap, LPVOID pVoid, int Index); BOOL BuildUpArrayType(pDC_CAPABILITY pCap, pDC_ARRAY pA, LPVOID lpList); BOOL ExtractArrayValue(pDC_CAPABILITY pCap, LPVOID pVoid, int Index); BOOL BuildUpRangeType(pDC_CAPABILITY pCap, pDC_RANGE lpRange); BOOL ExtractRange(pDC_CAPABILITY pCap, pDC_RANGE lpRange); }; #endif Listing Two /****************************************************************************/ /*** containr.cpp -- interface class for TWAIN containers. ***/ /*** adapted by Craig A. Lindley -- Revision: 1.0 Last Update: 12/11/93 ***/ /***************************************************************************/ #include "containr.hpp" // Array of type sizes in bytes DCItemSize[] = { sizeof(DC_INT8), sizeof(DC_INT16), sizeof(DC_INT32), sizeof(DC_UINT8), sizeof(DC_UINT16), sizeof(DC_UINT32), sizeof(DC_BOOL), sizeof(DC_FIX32), sizeof(DC_FRAME), sizeof(DC_STR32), sizeof(DC_STR64), sizeof(DC_STR128), sizeof(DC_STR255), }; /*** FloatToFIX32 -- Convert a floating point value into a FIX32. ***/ DC_FIX32 Containr::FloatToFIX32(float AFloat) { DC_FIX32 Fix32_value; DC_INT32 Value = (DC_INT32) (AFloat * 65536.0 + 0.5); Fix32_value.Whole = Value >> 16; Fix32_value.Frac = Value & 0x0000ffffL; return(Fix32_value); } /*** FIX32ToFloat -- Convert a FIX32 value into a floating point value ***/ float Containr::FIX32ToFloat(DC_FIX32 Fix32) { float AFloat; AFloat = (float) Fix32.Whole + (float) Fix32.Frac / 65536.0; return(AFloat); } /*** GetItem -- Gets data item at lpSource[SIndex] of datatype Type and stores *** it at lpDest[DIndex]. ***/ void Containr::GetItem(DC_UINT16 Type, LPVOID lpSource, LPVOID lpDest, int SIndex, int DIndex) { switch (Type) { case DCTY_INT8: *((pDC_INT8)lpDest + DIndex) = *((pDC_INT8)lpSource + SIndex); break; case DCTY_UINT8: *((pDC_UINT8)lpDest + DIndex) = *((pDC_UINT8)lpSource + SIndex); break; case DCTY_INT16: case 44: // DCTY_HANDLE *((pDC_INT16)lpDest + DIndex) = *((pDC_INT16)lpSource + SIndex); break; case DCTY_UINT16: case DCTY_BOOL: *((pDC_UINT16)lpDest + DIndex) = *((pDC_UINT16)lpSource + SIndex); break; case DCTY_INT32: *((pDC_INT32)lpDest + DIndex) = *((pDC_INT32)lpSource + SIndex); break; case DCTY_UINT32: case 43: // DCTY_MEMREF *((pDC_UINT32)lpDest + DIndex) = *((pDC_UINT32)lpSource + SIndex); break; case DCTY_FIX32: *((pDC_FIX32)lpDest + DIndex) = *((pDC_FIX32)lpSource + SIndex); break; case DCTY_STR32: lstrcpy((pDC_STR32)lpDest + DIndex, (pDC_STR32)lpSource + SIndex); break; case DCTY_STR64: lstrcpy((pDC_STR64)lpDest + DIndex, (pDC_STR64)lpSource + SIndex); break; case DCTY_STR128: lstrcpy((pDC_STR128)lpDest + DIndex, (pDC_STR128)lpSource + SIndex); break; case DCTY_STR255: lstrcpy((pDC_STR255)lpDest + DIndex, (pDC_STR255)lpSource + SIndex); break; } } /*** FUNCTION: BuildUpOneValue ***/ *** ARGS: pCap, pointer to a capability structure, details about container * ItemType, constant that defines the type of the Item to follow * Item, the data to put into the OneValue container * RETURNS: pData->hContainer set to address of the container handle, ptr is * returned there. A TRUE BOOL is returned from this function if * all is well and FALSE if container memory could not be allocated. * NOTES: This function creates a container of type OneValue and returning * with the hContainer value (excuse me) "pointing" to container. Container * is filled with values for ItemType and Item requested by the caller. */ BOOL Containr::BuildUpOneValue(pDC_CAPABILITY pCap, DC_UINT16 ItemType, DC_UINT32 Item) { pDC_ONEVALUE pOneValue; if ((pCap->hContainer = (DC_HANDLE) GlobalAlloc(GHND, sizeof(DC_ONEVALUE))) != NULL) { // log the container type pCap->ConType = DCON_ONEVALUE; if ((pOneValue = (pDC_ONEVALUE)GlobalLock(pCap->hContainer)) != NULL) { pOneValue->ItemType = ItemType; // DCTY_XXXX pOneValue->Item = Item; // DCPT_XXXX... GlobalUnlock(pCap->hContainer); return TRUE; } else { // If lock error, free memory GlobalFree(pCap->hContainer); pCap->hContainer = 0; } } // Could not allocate or lock memory return FALSE; } /*** FUNCTION: ExtractOneValue * ARGS: pCap pointer to a capability structure, details about container * pVoid ptr will be set to point to the item on return * RETURNS: pVoid pts to extracted value. * NOTES: This routine will open a container and extract the Item. The Item * will be returned to the caller in pVoid. I will type cast the returned * value to that of ItemType. */ BOOL Containr::ExtractOneValue(pDC_CAPABILITY pCap, LPVOID pVoid) { pDC_ONEVALUE pOneValue; if ((pOneValue = (pDC_ONEVALUE)GlobalLock(pCap->hContainer)) != NULL) { // Extract the one value GetItem(pOneValue->ItemType, (LPVOID) &(pOneValue->Item), pVoid, 0, 0); GlobalUnlock(pCap->hContainer); return TRUE; } return FALSE; } /*** FUNCTION: BuildUpEnumerationType * ARGS: pCap pointer to a capability structure, details about container * pE ptr to struct that contains the other fields of ENUM struct * *pList ptr to array of elements to put into the ENUM array * RETURNS: pData->hContainer set to address of the container handle, ptr is * returned here * NOTES: The routine dynamically allocates a chunk of memory large enough * to contain all the struct pDC_ENUMERATION as well as store it's ItemList * array INTERNAL to the struct. The array itself and it's elements must be * type cast to ItemType. I do not know how to dynamically cast elements * of an array to ItemType so it is time for a big static switch.>>> * Protocol: Used by MSG_GET.. calls were Source allocates the container and * APP uses and then frees the container. */ BOOL Containr::BuildUpEnumerationType(pDC_CAPABILITY pCap, pDC_ENUMERATION pE, LPVOID lpList) { pDC_ENUMERATION pEnumeration; // template for ENUM fields int Index; // anyone with more than 32K array elements // should crash. Could type on NumItems. LPVOID pVoid; // allocate a block large enough for struct and complete enumeration array if ((pCap->hContainer = (DC_HANDLE) GlobalAlloc(GHND, (sizeof(DC_ENUMERATION)-sizeof(DC_UINT8))+ pE->NumItems*DCItemSize[pE->ItemType])) == NULL) return FALSE; // return FALSE if memory error if ((pEnumeration = (pDC_ENUMERATION) GlobalLock(pCap->hContainer)) == NULL) { GlobalFree(pCap->hContainer); // return FALSE if memory error return FALSE; } pCap->ConType = DCON_ENUMERATION; // Fill in container type pEnumeration->ItemType = pE->ItemType; // DCTY_XXXX pEnumeration->NumItems = pE->NumItems; // DCPT_XXXX... pEnumeration->CurrentIndex = pE->CurrentIndex; // current index setting pEnumeration->DefaultIndex = pE->DefaultIndex; // default index setting // Assign base address of ItemList array to 'generic' pointer // i.e. reposition the struct pointer to overlay the allocated block pVoid = (LPVOID)pEnumeration->ItemList; // Now store the enumerated items for (Index=0; Index < (int)pE->NumItems; Index++) GetItem(pE->ItemType, (LPVOID) lpList, (LPVOID) pVoid, Index, Index); // Unlock the container GlobalUnlock(pCap->hContainer); return TRUE; } /*** FUNCTION: ExtractEnumerationValue * ARGS: pCap pointer to a capability structure, details about container * pVoid ptr will be set to point to the item on return * Index requested index into the enumeration * RETURNS: pVoid is set to pointer to itemtype * NOTES: This routine will open a container and extract the Item. The * Item will be returned to the caller in pVoid. Returned value will * be type cast to that of ItemType. * COMMENTS: only a single value is returned; referred to by indexed value. */ BOOL Containr::ExtractEnumerationValue(pDC_CAPABILITY pCap, LPVOID pVoid, int Index) { pDC_ENUMERATION pEnumeration; LPVOID pItemList; // Lock the container for access if ((pEnumeration = (pDC_ENUMERATION) GlobalLock(pCap->hContainer)) == NULL) return FALSE; // Check that Index is within range if (Index > pEnumeration->NumItems-1) return FALSE; // Assign base address of ItemList array to 'generic' pointer pItemList = (LPVOID) pEnumeration->ItemList; GetItem(pEnumeration->ItemType, pItemList, pVoid, Index, 0); GlobalUnlock(pCap->hContainer); return TRUE; } /*** FUNCTION: BuildUpArrayType * ARGS: pCap pointer to a capability structure, details about container * pA ptr to struct that contains the other fields of ARRAY struct * *pList ptr to array of elements to put into the ARRAY struct * RETURNS: pData->hContainer set to address of the container handle, ptr is * returned here * NOTES: The routine dynamically allocates a chunk of memory large enough to * contain all the struct pDC_ARRAY as well as store it's ItemList array * INTERNAL to the struct. The array itself and it's elements must be * type cast to ItemType. */ BOOL Containr::BuildUpArrayType(pDC_CAPABILITY pCap, pDC_ARRAY pA, LPVOID lpList) { pDC_ARRAY pArray; int Index; // No more than 32K array elements LPVOID pVoid; // Allocate a block large enough for struct and complete array if ((pCap->hContainer = (DC_HANDLE) GlobalAlloc(GHND, (sizeof(DC_ARRAY)-sizeof(DC_UINT8))+ pA->NumItems*DCItemSize[pA->ItemType])) == NULL) return FALSE; // Return FALSE if error // Lock the memory if ((pArray = (pDC_ARRAY) GlobalLock(pCap->hContainer)) == NULL) { GlobalFree(pCap->hContainer); return FALSE; // Return FALSE if error } pArray->ItemType = pA->ItemType; // DCTY_XXXX pArray->NumItems = pA->NumItems; // DCPT_XXXX... // Assign base address of ItemList array to 'generic' pointer // i.e. reposition the struct pointer to overlay the allocated block pVoid = (LPVOID)pArray->ItemList; // For each item of the array for (Index=0; Index < (int)pA->NumItems; Index++) GetItem(pA->ItemType, lpList, pVoid, Index, Index); // Unlock the memory GlobalUnlock(pCap->hContainer); return TRUE; } /*** FUNCTION: ExtractArrayValue * ARGS: pCap pointer to a capability structure, details about container * pVoid ptr will be set to point to the item on return * Index requested index into the array * RETURNS: pVoid is set to pointer to itemtype * NOTES: This routine will open a container and extract the Item. The * Item will be returned to the caller in pVoid. Returned value will * be type cast to that of ItemType. * COMMENTS: only a single value is returned; referred to by indexed value. */ BOOL Containr::ExtractArrayValue(pDC_CAPABILITY pCap,LPVOID pVoid,int Index) { pDC_ARRAY pArray; LPVOID pItemList; // Lock the container for access if ((pArray = (pDC_ARRAY) GlobalLock(pCap->hContainer)) == NULL) return FALSE; // Check that Index is within range if (Index > pArray->NumItems-1) return FALSE; // Assign base address of ItemList array to 'generic' pointer pItemList = (LPVOID) pArray->ItemList; GetItem(pArray->ItemType, pItemList, pVoid, Index, 0); GlobalUnlock(pCap->hContainer); return TRUE; } /*** FUNCTION: BuildUpRangeType * ARGS: pCap pointer to a capability structure, details about container * lpRange ptr to RANGE struct * RETURNS: pCap->hContainer set to address of the container handle, ptr is * returned here * NOTES: The routine dynamically allocates a chunk of memory large enough to * contain the RANGE struct. */ BOOL Containr::BuildUpRangeType(pDC_CAPABILITY pCap, pDC_RANGE lpRange) { pDC_RANGE pRange; // Allocate a block large enough for RANGE struct if ((pCap->hContainer = (DC_HANDLE) GlobalAlloc(GHND, sizeof(DC_RANGE))) == NULL) return FALSE; // Return FALSE if error // Lock the memory if ((pRange = (pDC_RANGE) GlobalLock(pCap->hContainer)) == NULL) { GlobalFree(pCap->hContainer); return FALSE; // Return FALSE if error } // Copy complete RANGE structure *pRange = *lpRange; // Unlock the memory GlobalUnlock(pCap->hContainer); return TRUE; } /*** FUNCTION: ExtractRange * ARGS: pCap pointer to a capability structure, details about container * lpRange ptr to RANGE struct for return * NOTES: This routine will open a container and extract the RANGE. * COMMENTS: the complete RANGE struct is returned at lpRange. */ BOOL Containr::ExtractRange(pDC_CAPABILITY pCap, pDC_RANGE lpRange) { pDC_RANGE pRange; // Lock the container for access if ((pRange = (pDC_RANGE) GlobalLock(pCap->hContainer)) == NULL) return FALSE; // Copy the complete structure *lpRange = *pRange; GlobalUnlock(pCap->hContainer); return TRUE; } Listing Three // Sample TWAIN Application Program -- (c) Craig A. Lindley 1993 /* This program exercises the MYTWAIN.DLL. It is written in Borland's OWL. It allows the user to select a Source for acquisition and to acquire an image from the selected Source. Each acquired image is written to the file c:\scanimg.tif in the root directory of drive C. Images are not displayed. */ #include #include "app.h" #include "twain.hpp" class TSampleTWAINApp : public TApplication { public: TSampleTWAINApp(LPSTR AName, HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) : TApplication(AName, hInstance, hPrevInstance, lpCmdLine, nCmdShow) {}; virtual void InitMainWindow(); }; _CLASSDEF(TAppWindow) class TAppWindow : public TWindow { private: virtual BOOL CanClose(); virtual void CMSelectSource(RTMessage Msg) = [CM_FIRST + CMID_SELECTSOURCE]; virtual void CMAcquire(RTMessage Msg) = [CM_FIRST + CMID_ACQUIRE]; virtual void CMHelp(RTMessage Msg) = [CM_FIRST + CMID_HELP]; Twain *TwainClassPtr; // Pointer the the Twain object public: TAppWindow(PTWindowsObject AParent, LPSTR ATitle); ~TAppWindow(); }; // Window Class Constructor TAppWindow::TAppWindow(PTWindowsObject AParent, LPSTR ATitle) : TWindow(AParent, ATitle) { AssignMenu("CmdMenu"); // Assign the menu to the window TwainClassPtr = new Twain; // Instantiate the Twain class object } // Window Class Destructor TAppWindow::~TAppWindow() { delete TwainClassPtr; // Delete the Twain class object } BOOL TAppWindow::CanClose() { return TRUE; // Allow the window to close } // This function is called when the Select Source menu item is clicked void TAppWindow::CMSelectSource(RTMessage) { // Make a call to the DLL to perform the operation TwainClassPtr->SelectSource(HWindow); } // This function is called when the Acquire menu item is clicked void TAppWindow::CMAcquire(RTMessage) { // Make a call to the DLL to perform the operation TwainClassPtr->ScanImage("c:\\scanimg.tif"); } // This function is called when the Help menu item is clicked void TAppWindow::CMHelp(RTMessage) { MessageBox(HWindow, "(c) Craig A. Lindley, 1993", "Sample TWAIN Application", MB_OK); } void TSampleTWAINApp::InitMainWindow() { MainWindow = new TAppWindow(NULL, Name); } int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { TSampleTWAINApp MyApp("Sample TWAIN Application Program", hInstance, hPrevInstance, lpCmdLine, nCmdShow); MyApp.nCmdShow = SW_SHOWMAXIMIZED; MyApp.Run(); return MyApp.Status; }