Click here to Skip to main content
15,891,033 members
Articles / Desktop Programming / MFC

Scan2PDF

Rate me:
Please Sign up or sign in to vote.
4.90/5 (75 votes)
22 Apr 20053 min read 433.7K   20.9K   230  
A utility for bulk scanning, converting the scanned pages to PDF and burning them on CD/DVD for archiving.
#include "stdafx.h"
#include "twaincpp.h"

/*
Constructor:
	Parameters : HWND 
				Window to subclass
				 
*/
CTwain::CTwain(HWND hWnd)
{
	m_hTwainDLL = NULL;
	m_pDSMProc = NULL;
	m_bSourceSelected = FALSE;
	m_bDSOpen = m_bDSMOpen = FALSE;
	m_bSourceEnabled = FALSE;
	m_bModalUI = TRUE;
	m_nImageCount = TWCPP_ANYCOUNT;
	if(hWnd)
	{
		InitTwain(hWnd);
	}
}

CTwain::~CTwain()
{
	ReleaseTwain();
}

/*
Initializes TWAIN interface . Is already called from the constructor. 
It should be called again if ReleaseTwain is called.

  hWnd is the window which has to subclassed in order to recieve
  Twain messaged. Normally - this would be your main application window.

*/
BOOL CTwain::InitTwain(HWND hWnd)
{
char libName[512];
	if(IsValidDriver()) 
	{
		return TRUE;
	}
	memset(&m_AppId,0,sizeof(m_AppId));
	if(!IsWindow(hWnd))
	{
		return FALSE;
	}
	m_hMessageWnd = hWnd;
	strcpy(libName,"TWAIN_32.DLL");
	
	m_hTwainDLL  = LoadLibrary(libName);
	if(m_hTwainDLL != NULL)
	{
		if(!(m_pDSMProc = (DSMENTRYPROC)GetProcAddress(m_hTwainDLL,MAKEINTRESOURCE(1))))
		{
			FreeLibrary(m_hTwainDLL);
			m_hTwainDLL = NULL;
		}
	}
	if(IsValidDriver())
	{
		GetIdentity();
		m_bDSMOpen= CallTwainProc(&m_AppId,NULL,DG_CONTROL,DAT_PARENT,MSG_OPENDSM,(TW_MEMREF)&m_hMessageWnd);
		return TRUE;
	}
	else
	{
		return FALSE;
	}
}

/*
Releases the twain interface . Need not be called unless you
want to specifically shut it down.
*/
void CTwain::ReleaseTwain()
{
	if(IsValidDriver())
	{
		CloseDSM();
		FreeLibrary(m_hTwainDLL);
		m_hTwainDLL = NULL;
		m_pDSMProc = NULL;
	}
}

/*
Returns true if a valid driver has been loaded
*/
BOOL CTwain::IsValidDriver() const
{
	return (m_hTwainDLL && m_pDSMProc);
}
/*
* Fucntion: CallDSMEntry
* Author:	Nancy Letourneau / J.F.L. Peripherals Inc.
* Input:  
*		Function - 
*		pApp - 
*		pSrc - 
*		DG -
*		DAT -
*		MSG -
*		pData -
* Output: 
*		TW_UINT16 - Value of Item field of container. 
* Comments:
*
*/
TW_UINT16 CTwain::CallDSMEntry(pTW_IDENTITY pApp, pTW_IDENTITY pSrc,
										TW_UINT32 DG, TW_UINT16 DAT, TW_UINT16 MSG, TW_MEMREF pData)
{
	TW_UINT16 twRC = (*m_pDSMProc)(pApp, pSrc, DG, DAT, MSG, pData);

	if((twRC != TWRC_SUCCESS)&&(DAT!=DAT_EVENT))
	{
		VERIFY((*m_pDSMProc)(pApp, pSrc, DG_CONTROL, DAT_STATUS, MSG_GET, 
					(TW_MEMREF)&m_Status) == TWRC_SUCCESS);
		TRACE("CallDSMEntry function: call failed with RC = %d, CC = %d.\n", 
					twRC, m_Status);
	}
	return twRC;
}
/*
Entry point into Twain. For a complete description of this
routine  please refer to the Twain specification 1.8
*/
BOOL CTwain::CallTwainProc(pTW_IDENTITY pOrigin,pTW_IDENTITY pDest,
					   TW_UINT32 DG,TW_UINT16 DAT,TW_UINT16 MSG,
					   TW_MEMREF pData)
{
	if(IsValidDriver())
	{
	USHORT ret_val;
		ret_val = (*m_pDSMProc)(pOrigin,pDest,DG,DAT,MSG,pData);
		m_returnCode = ret_val;
		if(ret_val != TWRC_SUCCESS)
		{
			(*m_pDSMProc)(pOrigin,pDest,DG_CONTROL,DAT_STATUS,MSG_GET,&m_Status);
		}
		return (ret_val == TWRC_SUCCESS);
	}
	else
	{
		m_returnCode = TWRC_FAILURE;
		return FALSE;
	}
}

/*
This function should ideally be overridden in the derived class . If only a 
few fields need to be updated , call CTawin::GetIdentity first in your
derived class
*/
void CTwain::GetIdentity()
{
	// Expects all the fields in m_AppId to be set except for the id field.
	m_AppId.Id = 0; // Initialize to 0 (Source Manager
	// will assign real value)
	m_AppId.Version.MajorNum = 1; //Your app's version number
	m_AppId.Version.MinorNum = 0;
	m_AppId.Version.Language = TWLG_USA;
	m_AppId.Version.Country = TWCY_USA;
	strcpy (m_AppId.Version.Info, "1.0");
	m_AppId.ProtocolMajor = TWON_PROTOCOLMAJOR;
	m_AppId.ProtocolMinor = TWON_PROTOCOLMINOR;
	m_AppId.SupportedGroups = DG_IMAGE | DG_CONTROL;
	strcpy (m_AppId.Manufacturer, "MICSS");
	strcpy (m_AppId.ProductFamily, "Generic");
	strcpy (m_AppId.ProductName, "Twain Test");

}


/*
Called to display a dialog box to select the Twain source to use.
This can be overridden if a list of all sources is available
to the application. These sources can be enumerated by Twain.
it is not yet supportted by CTwain.
*/
BOOL CTwain::SelectSource()
{
	memset(&m_Source,0,sizeof(m_Source));
	if(!SourceSelected())
	{
		SelectDefaultSource();
	}
	if(CallTwainProc(&m_AppId,NULL,DG_CONTROL,DAT_IDENTITY,MSG_USERSELECT,&m_Source))
	{
		m_bSourceSelected = TRUE;
	}
	return m_bSourceSelected;
}

/*
Called to select the default source
*/
BOOL CTwain::SelectDefaultSource()
{
	m_bSourceSelected = CallTwainProc(&m_AppId,NULL,DG_CONTROL,DAT_IDENTITY,MSG_GETDEFAULT,&m_Source);
	return m_bSourceSelected;
}

/*
Closes the Data Source
*/
void CTwain::CloseDS()
{
	if(DSOpen())
	{
		DisableSource();
		CallTwainProc(&m_AppId,NULL,DG_CONTROL,DAT_IDENTITY,MSG_CLOSEDS,(TW_MEMREF)&m_Source);
		m_bDSOpen = FALSE;
	}
}

/*
Closes the Data Source Manager
*/
void CTwain::CloseDSM()
{
	if(DSMOpen())
	{
		CloseDS();
		CallTwainProc(&m_AppId,NULL,DG_CONTROL,DAT_PARENT,MSG_CLOSEDSM,(TW_MEMREF)&m_hMessageWnd);
		m_bDSMOpen = FALSE;
	}
}

/*
Returns true if the Data Source Manager is Open
*/
BOOL CTwain::DSMOpen() const
{
	return IsValidDriver() && m_bDSMOpen;
}

/*
Returns true if the Data Source is Open
*/
BOOL CTwain::DSOpen() const
{
	return IsValidDriver() && DSMOpen() && m_bDSOpen;
}

/*
Opens a Data Source supplied as the input parameter
*/
BOOL CTwain::OpenSource(TW_IDENTITY *pSource)
{
	if(pSource) 
	{
		m_Source = *pSource;
	}
	if(DSMOpen())
	{
		if(!SourceSelected())
		{
			SelectDefaultSource();
		}
		m_bDSOpen = CallTwainProc(&m_AppId,NULL,DG_CONTROL,DAT_IDENTITY,MSG_OPENDS,(TW_MEMREF)&m_Source);
	}
	return DSOpen();
}

/*
Should be called from the main message loop of the application. Can always be called,
it will not process the message unless a scan is in progress.
*/
BOOL CTwain::ProcessMessage(MSG msg)
{
	if(SourceEnabled()){

		TW_UINT16  twRC = TWRC_NOTDSEVENT;
		TW_EVENT twEvent;

		memset(&twEvent, 0, sizeof(TW_EVENT));
	//	twEvent.TWMessage = MSG_NULL;

		twEvent.pEvent = (TW_MEMREF)&msg;

		twRC = CallDSMEntry(&m_AppId,&m_Source,DG_CONTROL,DAT_EVENT,MSG_PROCESSEVENT,(TW_MEMREF)&twEvent);

	//	CallTwainProc(&m_AppId,&m_Source,DG_CONTROL,DAT_EVENT,MSG_PROCESSEVENT,(TW_MEMREF)&twEvent);
	//	if(GetRC() != TWRC_NOTDSEVENT)
	//	{
		TranslateMessage(twEvent);
	//	}

		// tell the caller what happened
		return (twRC==TWRC_DSEVENT);           // returns TRUE or FALSE
	}
	return FALSE;
}

/*
Queries the capability of the Twain Data Source
*/
BOOL CTwain::GetCapability(TW_CAPABILITY& twCap,TW_UINT16 cap,TW_UINT16 conType)
{
	if(DSOpen())
	{
		twCap.Cap = cap;
		twCap.ConType = conType;
		twCap.hContainer = NULL;

		if(CallTwainProc(&m_AppId,&m_Source,DG_CONTROL,DAT_CAPABILITY,MSG_GET,(TW_MEMREF)&twCap))
		{
			return TRUE;
		}
	}
	return FALSE;
}

/*
Queries the capability of the Twain Data Source
*/
BOOL CTwain::GetCapability(TW_UINT16 cap,TW_UINT32& value)
{
TW_CAPABILITY twCap;
	if(GetCapability(twCap,cap))
	{
	pTW_ONEVALUE pVal;
		pVal = (pTW_ONEVALUE )GlobalLock(twCap.hContainer);
		if(pVal)
		{
			value = pVal->Item;
			GlobalUnlock(pVal);
			GlobalFree(twCap.hContainer);
			return TRUE;
		}
	}
	return FALSE;
}


/*
Sets the capability of the Twain Data Source
*/
BOOL CTwain::SetCapability(TW_UINT16 cap,TW_UINT16 value,BOOL sign)
{
	if(DSOpen())
	{
	TW_CAPABILITY twCap;
	pTW_ONEVALUE pVal;
	BOOL ret_value = FALSE;

		twCap.Cap = cap;
		twCap.ConType = TWON_ONEVALUE;
		
		twCap.hContainer = GlobalAlloc(GHND,sizeof(TW_ONEVALUE));
		if(twCap.hContainer)
		{
			pVal = (pTW_ONEVALUE)GlobalLock(twCap.hContainer);
			pVal->ItemType = sign ? TWTY_INT16 : TWTY_UINT16;
			pVal->Item = (TW_UINT32)value;
			GlobalUnlock(twCap.hContainer);
			ret_value = SetCapability(twCap);
			GlobalFree(twCap.hContainer);
		}
		return ret_value;
	}
	return FALSE;
}

/*
Sets the capability of the Twain Data Source
*/
BOOL CTwain::SetCapability(TW_CAPABILITY& cap)
{
	if(DSOpen())
	{
		return CallTwainProc(&m_AppId,&m_Source,DG_CONTROL,DAT_CAPABILITY,MSG_SET,(TW_MEMREF)&cap);
	}
	return FALSE;
}

/*
Sets the number of images which can be accpeted by the application at one time
*/
BOOL CTwain::SetImageCount(TW_INT16 nCount)
{
	if(SetCapability(CAP_XFERCOUNT,(TW_UINT16)nCount,TRUE))
	{
		m_nImageCount = nCount;
		return TRUE;
	}
	else
	{
		if(GetRC() == TWRC_CHECKSTATUS)
		{
		TW_UINT32 count;
			if(GetCapability(CAP_XFERCOUNT,count))
			{
				nCount = (TW_INT16)count;
				if(SetCapability(CAP_XFERCOUNT,nCount))
				{
					m_nImageCount = nCount;
					return TRUE;
				}
			}
		}
	}
	return FALSE;
}

/*
Called to enable the Twain Acquire Dialog. This too can be
overridden but is a helluva job . 
*/
BOOL CTwain::EnableSource(BOOL showUI)
{
	if(DSOpen() && !SourceEnabled())
	{
		TW_USERINTERFACE twUI;
		twUI.ShowUI = showUI;
		twUI.hParent = (TW_HANDLE)m_hMessageWnd;
		if(CallTwainProc(&m_AppId,&m_Source,DG_CONTROL,DAT_USERINTERFACE,MSG_ENABLEDS,(TW_MEMREF)&twUI))
		{
			m_bSourceEnabled = TRUE;
			m_bModalUI = twUI.ModalUI;
		}
		else
		{
			m_bSourceEnabled = FALSE;
			m_bModalUI = TRUE;
		}
		return m_bSourceEnabled;
	}
	return FALSE;
}

/*
Called to acquire images from the source. parameter numImages i the
numberof images that you an handle concurrently
*/
BOOL CTwain::Acquire(int numImages)
{
	if(DSOpen() || OpenSource())
	{
		if(SetImageCount(numImages))
		{
			if(EnableSource())
			{
				return TRUE;
			}
		}
	}
	return FALSE;
}

/*
 Called to disable the source.
*/
BOOL CTwain::DisableSource()
{
	if(SourceEnabled())
	{
	TW_USERINTERFACE twUI;
		if(CallTwainProc(&m_AppId,&m_Source,DG_CONTROL,DAT_USERINTERFACE,MSG_DISABLEDS,&twUI))
		{
			m_bSourceEnabled = FALSE;
			return TRUE;
		}
	}
	return FALSE;
}

/*
Called by ProcessMessage to Translate a TWAIN message
*/
void CTwain::TranslateMessage(TW_EVENT& twEvent)
{
	switch(twEvent.TWMessage)
	{
	case MSG_XFERREADY:
		TransferImage();
		break;
	case MSG_CLOSEDSREQ:
		if(CanClose())
		{
			CloseDS();
		}
		break;

	// No message from the Source to the App break;
	// possible new message
	case MSG_NULL:
	default:
		break;
	}
}

/*
Gets Imageinfo for an image which is about to be transferred.
*/
BOOL CTwain::GetImageInfo(TW_IMAGEINFO& info)
{
	if(SourceEnabled())
	{
		return CallTwainProc(&m_AppId,&m_Source,DG_IMAGE,DAT_IMAGEINFO,MSG_GET,(TW_MEMREF)&info);
	}
	return FALSE;
}

/*
Trasnfers the image or cancels the transfer depending on the state of the
TWAIN system
*/
void CTwain::TransferImage()
{
TW_IMAGEINFO info;
BOOL bContinue=TRUE;
	while(bContinue)
	{
		if(GetImageInfo(info))
		{
			int permission;
			permission = ShouldTransfer(info);
			switch(permission)
			{
			case TWCPP_CANCELTHIS:
					bContinue=EndTransfer();
					break;
			case TWCPP_CANCELALL:
					CancelTransfer();
					bContinue=FALSE;
					break;
			case TWCPP_DOTRANSFER:
					bContinue=GetImage(info);
					break;
			}
		}
	}
}

/*
Ends the current transfer.
Returns TRUE if the more images are pending
*/
BOOL CTwain::EndTransfer()
{
TW_PENDINGXFERS twPend;
	if(CallTwainProc(&m_AppId,&m_Source,DG_CONTROL,DAT_PENDINGXFERS,MSG_ENDXFER,(TW_MEMREF)&twPend))
	{
		return twPend.Count != 0;
	}
	return FALSE;
}

/*
Aborts all transfers
*/
void CTwain::CancelTransfer()
{
TW_PENDINGXFERS twPend;
	CallTwainProc(&m_AppId,&m_Source,DG_CONTROL,DAT_PENDINGXFERS,MSG_RESET,(TW_MEMREF)&twPend);
}

/*
Calls TWAIN to actually get the image
*/
BOOL CTwain::GetImage(TW_IMAGEINFO& info)
{
HANDLE hBitmap;
	CallTwainProc(&m_AppId,&m_Source,DG_IMAGE,DAT_IMAGENATIVEXFER,MSG_GET,&hBitmap);
	switch(m_returnCode)
	{
	case TWRC_XFERDONE:
			SetImage(hBitmap,info);
			break;
	case TWRC_CANCEL:
			break;
	case TWRC_FAILURE:
			CancelTransfer();
			return FALSE;

	}
	GlobalFree(hBitmap);
	return EndTransfer();
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
CEO Solaris Electronics LLC
United Arab Emirates United Arab Emirates
I was born in Shiraz, a very beautiful famous city in Iran. I started programming when I was 12 years old with GWBASIC. Since now, I worked with various programming languages from Basic, Foxpro, C/C++, Visual Basic, Pascal to MATLAB and now Visual C++.
I graduated from Iran University of Science & Technology in Communication Eng., and now work as a system programmer for a telecommunication industry.
I wrote several programs and drivers for Synthesizers, Power Amplifiers, GPIB, GPS devices, Radio cards, Data Acquisition cards and so many related devices.
I'm author of several books like Learning C (primary and advanced), Learning Visual Basic, API application for VB, Teach Yourself Object Oriented Programming (OOP) and etc.
I'm winner of January, May, August 2003 and April 2005 best article of month competition, my articles are:


You can see list of my articles, by clicking here


Comments and Discussions