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