xref: /trunk/main/extensions/source/scanner/twain.cxx (revision 2a97ec55)
1  /**************************************************************
2   *
3   * Licensed to the Apache Software Foundation (ASF) under one
4   * or more contributor license agreements.  See the NOTICE file
5   * distributed with this work for additional information
6   * regarding copyright ownership.  The ASF licenses this file
7   * to you under the Apache License, Version 2.0 (the
8   * "License"); you may not use this file except in compliance
9   * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   *
20   *************************************************************/
21  
22  
23  
24  // MARKER(update_precomp.py): autogen include statement, do not remove
25  #include "precompiled_extensions.hxx"
26  
27  #include <string.h>
28  #include <math.h>
29  
30  #if defined( WNT )
31  #include <tools/svwin.h>
32  #endif
33  #ifdef OS2
34  #include <svpm.h>
35  #endif // OS2
36  #include <vos/module.hxx>
37  #include <tools/stream.hxx>
38  #include <vcl/svapp.hxx>
39  #include <vcl/wrkwin.hxx>
40  #include <vcl/sysdata.hxx>
41  #include "twain.hxx"
42  
43  // -----------
44  // - Defines -
45  // -----------
46  
47  #define PFUNC						(*pDSM)
48  #define FIXTODOUBLE( nFix ) 		((double)nFix.Whole+(double)nFix.Frac/65536.)
49  #define FIXTOLONG( nFix )			((long)floor(FIXTODOUBLE(nFix)+0.5))
50  
51  #if defined WNT
52  #define TWAIN_LIBNAME				"TWAIN_32.DLL"
53  #define TWAIN_FUNCNAME				"DSM_Entry"
54  #elif defined OS2
55  #define TWAIN_LIBNAME				"twain"
56  #define TWAIN_FUNCNAME				"DSM_ENTRY"
57  #endif
58  
59  // -----------
60  // - Statics -
61  // -----------
62  
63  static ImpTwain* pImpTwainInstance = NULL;
64  
65  // ---------
66  // - Procs -
67  // ---------
68  
69  #ifdef OS2
70  
71  	#define PTWAINMSG QMSG*
72  
73  	MRESULT EXPENTRY TwainWndProc( HWND hWnd, ULONG nMsg, MPARAM nParam1, MPARAM nParam2 )
74  	{
75  		return (MRESULT) TRUE;
76  	}
77  
78  
79  #else // OS2
80  
81  	#define PTWAINMSG MSG*
82  
83  	// -------------------------------------------------------------------------
84  
85  	LRESULT CALLBACK TwainWndProc( HWND hWnd,UINT nMsg, WPARAM nPar1, LPARAM nPar2 )
86  	{
87  		return DefWindowProc( hWnd, nMsg, nPar1, nPar2 );
88  	}
89  
90  	// -------------------------------------------------------------------------
91  
92  	LRESULT CALLBACK TwainMsgProc( int nCode, WPARAM wParam, LPARAM lParam )
93  	{
94  		MSG* pMsg = (MSG*) lParam;
95  
96  		if( ( nCode < 0 ) ||
97  			( pImpTwainInstance->hTwainWnd != pMsg->hwnd ) ||
98  			!pImpTwainInstance->ImplHandleMsg( (void*) lParam ) )
99  		{
100  			return CallNextHookEx( pImpTwainInstance->hTwainHook, nCode, wParam, lParam );
101  		}
102  		else
103  		{
104  			pMsg->message = WM_USER;
105  			pMsg->lParam = 0;
106  
107  			return 0;
108  		}
109  	}
110  
111  #endif // OS2
112  
113  // ------------
114  // - ImpTwain -
115  // ------------
116  
117  ImpTwain::ImpTwain( const Link& rNotifyLink ) :
118  			aNotifyLink ( rNotifyLink ),
119  			pDSM		( NULL ),
120  			pMod		( NULL ),
121  			hTwainWnd	( 0 ),
122  			hTwainHook	( 0 ),
123  			nCurState	( 1 )
124  {
125  	pImpTwainInstance = this;
126  
127  	aAppIdent.Id = 0;
128  	aAppIdent.Version.MajorNum = 1;
129  	aAppIdent.Version.MinorNum = 0;
130  	aAppIdent.Version.Language = TWLG_USA;
131  	aAppIdent.Version.Country = TWCY_USA;
132  	aAppIdent.ProtocolMajor = TWON_PROTOCOLMAJOR;
133  	aAppIdent.ProtocolMinor = TWON_PROTOCOLMINOR;
134  	aAppIdent.SupportedGroups =	DG_IMAGE | DG_CONTROL;
135  	strcpy( aAppIdent.Version.Info, "6.0" );
136  	strcpy( aAppIdent.Manufacturer, "Sun Microsystems");
137  	strcpy( aAppIdent.ProductFamily,"Office");
138  	strcpy( aAppIdent.ProductName, "Office");
139  
140  #ifdef OS2
141  
142  	hAB = Sysdepen::GethAB();
143  	ImplFallback( TWAIN_EVENT_QUIT );
144  	// hTwainWnd = WinCreateWindow( HWND_DESKTOP, WC_FRAME, "dummy", 0, 0, 0, 0, 0, HWND_DESKTOP, HWND_BOTTOM, 0, 0, 0 );
145  
146  #else
147  
148  	HWND		hParentWnd = HWND_DESKTOP;
149  	WNDCLASS	aWc = { 0, &TwainWndProc, 0, sizeof( WNDCLASS ), GetModuleHandle( NULL ),
150  						NULL, NULL, NULL, NULL, "TwainClass" };
151  
152  	RegisterClass( &aWc );
153  	hTwainWnd = CreateWindowEx( WS_EX_TOPMOST, aWc.lpszClassName, "TWAIN", 0, 0, 0, 0, 0, hParentWnd, NULL, aWc.hInstance, 0 );
154  	hTwainHook = SetWindowsHookEx( WH_GETMESSAGE, &TwainMsgProc, NULL, GetCurrentThreadId() );
155  
156  #endif
157  }
158  
159  // -----------------------------------------------------------------------------
160  
161  ImpTwain::~ImpTwain()
162  {
163  }
164  
165  // -----------------------------------------------------------------------------
166  
167  void ImpTwain::Destroy()
168  {
169  	ImplFallback( TWAIN_EVENT_NONE );
170  	Application::PostUserEvent( LINK( this, ImpTwain, ImplDestroyHdl ), NULL );
171  }
172  
173  // -----------------------------------------------------------------------------
174  
175  sal_Bool ImpTwain::SelectSource()
176  {
177  	TW_UINT16 nRet = TWRC_FAILURE;
178  
179  	if( !!aBitmap )
180  		aBitmap = Bitmap();
181  
182  	ImplOpenSourceManager();
183  
184  	if( 3 == nCurState )
185  	{
186  		TW_IDENTITY aIdent;
187  
188  		aIdent.Id = 0, aIdent.ProductName[ 0 ] = '\0';
189  		aNotifyLink.Call( (void*) TWAIN_EVENT_SCANNING );
190  		nRet = PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_IDENTITY, MSG_USERSELECT, &aIdent );
191  	}
192  
193  	ImplFallback( TWAIN_EVENT_QUIT );
194  
195  	return( nRet == TWRC_SUCCESS || nRet == TWRC_CANCEL );
196  }
197  
198  // -----------------------------------------------------------------------------
199  
200  sal_Bool ImpTwain::InitXfer()
201  {
202  	sal_Bool bRet = sal_False;
203  
204  	if( !!aBitmap )
205  		aBitmap = Bitmap();
206  
207  	ImplOpenSourceManager();
208  
209  	if( 3 == nCurState )
210  	{
211  		ImplOpenSource();
212  
213  		if( 4 == nCurState )
214  			bRet = ImplEnableSource();
215  	}
216  
217  	if( !bRet )
218  		ImplFallback( TWAIN_EVENT_QUIT );
219  
220  	return bRet;
221  }
222  
223  // -----------------------------------------------------------------------------
224  
225  Bitmap ImpTwain::GetXferBitmap()
226  {
227  	Bitmap aRet( aBitmap );
228  	aBitmap = Bitmap();
229  	return aRet;
230  }
231  
232  // -----------------------------------------------------------------------------
233  
234  void ImpTwain::ImplOpenSourceManager()
235  {
236  	if( 1 == nCurState )
237  	{
238  		pMod = new vos:: OModule ();
239  
240  		if( pMod->load( TWAIN_LIBNAME ) )
241  		{
242  			nCurState = 2;
243  
244  			if( ( ( pDSM = (DSMENTRYPROC) pMod->getSymbol( TWAIN_FUNCNAME ) ) != NULL ) &&
245  				( PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_PARENT, MSG_OPENDSM, &hTwainWnd ) == TWRC_SUCCESS ) )
246  			{
247  				nCurState = 3;
248  			}
249  		}
250  		else
251  		{
252  			delete pMod;
253  			pMod = NULL;
254  		}
255  	}
256  }
257  
258  // -----------------------------------------------------------------------------
259  
260  void ImpTwain::ImplOpenSource()
261  {
262  	if( 3 == nCurState )
263  	{
264  		if( ( PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_IDENTITY, MSG_GETDEFAULT, &aSrcIdent ) == TWRC_SUCCESS ) &&
265  			( PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_IDENTITY, MSG_OPENDS, &aSrcIdent ) == TWRC_SUCCESS ) )
266  		{
267  #ifdef OS2
268  
269  			// negotiate capabilities
270  
271  #else
272  
273  			TW_CAPABILITY	aCap = { CAP_XFERCOUNT, TWON_ONEVALUE, GlobalAlloc( GHND, sizeof( TW_ONEVALUE ) ) };
274  			TW_ONEVALUE*	pVal = (TW_ONEVALUE*) GlobalLock( aCap.hContainer );
275  
276  			pVal->ItemType = TWTY_INT16, pVal->Item = 1;
277  			GlobalUnlock( aCap.hContainer );
278  			PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_CAPABILITY, MSG_SET, &aCap );
279  			GlobalFree( aCap.hContainer );
280  #endif
281  
282  			nCurState = 4;
283  		}
284  	}
285  }
286  
287  // -----------------------------------------------------------------------------
288  
289  BOOL ImpTwain::ImplEnableSource()
290  {
291  	BOOL bRet = FALSE;
292  
293  	if( 4 == nCurState )
294  	{
295  		TW_USERINTERFACE aUI = { TRUE, TRUE, hTwainWnd };
296  
297  		aNotifyLink.Call( (void*) TWAIN_EVENT_SCANNING );
298  		nCurState = 5;
299  
300  		if( PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_USERINTERFACE, MSG_ENABLEDS, &aUI ) == TWRC_SUCCESS )
301  			bRet = TRUE;
302  		else
303  			nCurState = 4;
304  	}
305  
306  	return bRet;
307  }
308  
309  // -----------------------------------------------------------------------------
310  
311  BOOL ImpTwain::ImplHandleMsg( void* pMsg )
312  {
313  	TW_UINT16	nRet;
314  	PTWAINMSG	pMess = (PTWAINMSG) pMsg;
315  	TW_EVENT	aEvt = { pMess, MSG_NULL };
316  
317  	nRet = PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_EVENT, MSG_PROCESSEVENT, &aEvt );
318  
319  	if( aEvt.TWMessage != MSG_NULL )
320  	{
321  		switch( aEvt.TWMessage )
322  		{
323  			case MSG_XFERREADY:
324  			{
325  				ULONG nEvent = TWAIN_EVENT_QUIT;
326  
327  				if( 5 == nCurState )
328  				{
329  					nCurState = 6;
330  					ImplXfer();
331  
332  					if( !!aBitmap )
333  						nEvent = TWAIN_EVENT_XFER;
334  				}
335  
336  				ImplFallback( nEvent );
337  			}
338  			break;
339  
340  			case MSG_CLOSEDSREQ:
341  				ImplFallback( TWAIN_EVENT_QUIT );
342  			break;
343  
344  			default:
345  			break;
346  		}
347  	}
348  	else
349  		nRet = TWRC_NOTDSEVENT;
350  
351  	return( TWRC_DSEVENT == nRet );
352  }
353  
354  // -----------------------------------------------------------------------------
355  
356  void ImpTwain::ImplXfer()
357  {
358  	if( nCurState == 6 )
359  	{
360  		TW_IMAGEINFO	aInfo;
361  		TW_UINT32		hDIB = 0;
362  		long			nWidth = aInfo.ImageWidth;
363  		long			nHeight = aInfo.ImageLength;
364  		long			nXRes = FIXTOLONG( aInfo.XResolution );
365  		long			nYRes = FIXTOLONG( aInfo.YResolution );
366  
367  		if( PFUNC( &aAppIdent, &aSrcIdent, DG_IMAGE, DAT_IMAGEINFO, MSG_GET, &aInfo ) == TWRC_SUCCESS )
368  		{
369  			nWidth = aInfo.ImageWidth;
370  			nHeight = aInfo.ImageLength;
371  			nXRes = FIXTOLONG( aInfo.XResolution );
372  			nYRes = FIXTOLONG( aInfo.YResolution );
373  		}
374  		else
375  			nWidth = nHeight = nXRes = nYRes = -1L;
376  
377  		switch( PFUNC( &aAppIdent, &aSrcIdent, DG_IMAGE, DAT_IMAGENATIVEXFER, MSG_GET, &hDIB ) )
378  		{
379  			case( TWRC_CANCEL ):
380  				nCurState = 7;
381  			break;
382  
383  			case( TWRC_XFERDONE ):
384  			{
385  #ifdef OS2
386  
387  				// get OS/2-Bitmap
388  
389  #else // OS2
390  				const ULONG nSize = GlobalSize( (HGLOBAL) hDIB );
391  				char*		pBuf = (char*) GlobalLock( (HGLOBAL) hDIB );
392  
393  				if( pBuf )
394  				{
395  					SvMemoryStream aMemStm;
396  					aMemStm.SetBuffer( pBuf, nSize, FALSE, nSize );
397  					aBitmap.Read( aMemStm, FALSE );
398  					GlobalUnlock( (HGLOBAL) hDIB );
399  				}
400  
401  				GlobalFree( (HGLOBAL) hDIB );
402  #endif // OS2
403  
404  				// set resolution of bitmap if neccessary
405  				if ( ( nXRes != -1 ) && ( nYRes != - 1 ) && ( nWidth != - 1 ) && ( nHeight != - 1 ) )
406  				{
407  					const MapMode aMapMode( MAP_100TH_INCH, Point(), Fraction( 100, nXRes ), Fraction( 100, nYRes ) );
408  					aBitmap.SetPrefMapMode( aMapMode );
409  					aBitmap.SetPrefSize( Size( nWidth, nHeight ) );
410  				}
411  
412  				nCurState = 7;
413  			}
414  			break;
415  
416  			default:
417  			break;
418  		}
419  	}
420  }
421  
422  // -----------------------------------------------------------------------------
423  
424  void ImpTwain::ImplFallback( ULONG nEvent )
425  {
426  	Application::PostUserEvent( LINK( this, ImpTwain, ImplFallbackHdl ), (void*) nEvent );
427  }
428  
429  // -----------------------------------------------------------------------------
430  
431  IMPL_LINK( ImpTwain, ImplFallbackHdl, void*, pData )
432  {
433  	const ULONG	nEvent = (ULONG) pData;
434  	sal_Bool		bFallback = sal_True;
435  
436  	switch( nCurState )
437  	{
438  		case( 7 ):
439  		case( 6 ):
440  		{
441  			TW_PENDINGXFERS aXfers;
442  
443  			if( PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_PENDINGXFERS, MSG_ENDXFER, &aXfers ) == TWRC_SUCCESS )
444  			{
445  				if( aXfers.Count != 0 )
446  					PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_PENDINGXFERS, MSG_RESET, &aXfers );
447  			}
448  
449  			nCurState = 5;
450  		}
451  		break;
452  
453  		case( 5 ):
454  		{
455  			TW_USERINTERFACE aUI = { TRUE, TRUE, hTwainWnd };
456  
457  			PFUNC( &aAppIdent, &aSrcIdent, DG_CONTROL, DAT_USERINTERFACE, MSG_DISABLEDS, &aUI );
458  			nCurState = 4;
459  		}
460  		break;
461  
462  		case( 4 ):
463  		{
464  			PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_IDENTITY, MSG_CLOSEDS, &aSrcIdent );
465  			nCurState = 3;
466  		}
467  		break;
468  
469  		case( 3 ):
470  		{
471  			PFUNC( &aAppIdent, NULL, DG_CONTROL, DAT_PARENT, MSG_CLOSEDSM, &hTwainWnd );
472  			nCurState = 2;
473  		}
474  		break;
475  
476  		case( 2 ):
477  		{
478  			delete pMod;
479  			pMod = NULL;
480  			nCurState = 1;
481  		}
482  		break;
483  
484  		default:
485  		{
486  			if( nEvent != TWAIN_EVENT_NONE )
487  				aNotifyLink.Call( (void*) nEvent );
488  
489  			bFallback = sal_False;
490  		}
491  		break;
492  	}
493  
494  	if( bFallback )
495  		ImplFallback( nEvent );
496  
497  	return 0L;
498  }
499  
500  // -----------------------------------------------------------------------------
501  
502  IMPL_LINK( ImpTwain, ImplDestroyHdl, void*, p )
503  {
504  #ifdef OS2
505  
506  	if( hWndTwain )
507  		WinDestroyWindow( hWndTwain );
508  
509  	// unset hook
510  
511  #else
512  
513  	if( hTwainWnd )
514  		DestroyWindow( hTwainWnd );
515  
516  	if( hTwainHook )
517  		UnhookWindowsHookEx( hTwainHook );
518  
519  #endif
520  
521  	delete this;
522  	pImpTwainInstance = NULL;
523  
524  	return 0L;
525  }
526