xref: /trunk/main/extensions/source/scanner/twain.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
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