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 
TwainWndProc(HWND hWnd,ULONG nMsg,MPARAM nParam1,MPARAM nParam2)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 
TwainWndProc(HWND hWnd,UINT nMsg,WPARAM nPar1,LPARAM nPar2)85 	LRESULT CALLBACK TwainWndProc( HWND hWnd,UINT nMsg, WPARAM nPar1, LPARAM nPar2 )
86 	{
87 		return DefWindowProc( hWnd, nMsg, nPar1, nPar2 );
88 	}
89 
90 	// -------------------------------------------------------------------------
91 
TwainMsgProc(int nCode,WPARAM wParam,LPARAM lParam)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 
ImpTwain(const Link & rNotifyLink)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 
~ImpTwain()161 ImpTwain::~ImpTwain()
162 {
163 }
164 
165 // -----------------------------------------------------------------------------
166 
Destroy()167 void ImpTwain::Destroy()
168 {
169 	ImplFallback( TWAIN_EVENT_NONE );
170 	Application::PostUserEvent( LINK( this, ImpTwain, ImplDestroyHdl ), NULL );
171 }
172 
173 // -----------------------------------------------------------------------------
174 
SelectSource()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 
InitXfer()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 
GetXferBitmap()225 Bitmap ImpTwain::GetXferBitmap()
226 {
227 	Bitmap aRet( aBitmap );
228 	aBitmap = Bitmap();
229 	return aRet;
230 }
231 
232 // -----------------------------------------------------------------------------
233 
ImplOpenSourceManager()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 
ImplOpenSource()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 
ImplEnableSource()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 
ImplHandleMsg(void * pMsg)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 
ImplXfer()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 
ImplFallback(ULONG nEvent)424 void ImpTwain::ImplFallback( ULONG nEvent )
425 {
426 	Application::PostUserEvent( LINK( this, ImpTwain, ImplFallbackHdl ), (void*) nEvent );
427 }
428 
429 // -----------------------------------------------------------------------------
430 
IMPL_LINK(ImpTwain,ImplFallbackHdl,void *,pData)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 
IMPL_LINK(ImpTwain,ImplDestroyHdl,void *,p)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