4 * Copyright 2000 Shi Quan He <shiquan@cyberdude.com>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "wine/port.h"
28 #include "wine/debug.h"
29 #include "wine/library.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(twain
);
33 HINSTANCE SANE_instance
;
37 static void *libsane_handle
;
39 static void close_libsane(void *h
)
42 wine_dlclose(h
, NULL
, 0);
45 static void *open_libsane(void)
49 h
= wine_dlopen(SONAME_LIBSANE
, RTLD_GLOBAL
| RTLD_NOW
, NULL
, 0);
52 WARN("dlopen(%s) failed\n", SONAME_LIBSANE
);
56 #define LOAD_FUNCPTR(f) \
57 if((p##f = wine_dlsym(h, #f, NULL, 0)) == NULL) { \
59 ERR("Could not dlsym %s\n", #f); \
63 LOAD_FUNCPTR(sane_init
)
64 LOAD_FUNCPTR(sane_exit
)
65 LOAD_FUNCPTR(sane_get_devices
)
66 LOAD_FUNCPTR(sane_open
)
67 LOAD_FUNCPTR(sane_close
)
68 LOAD_FUNCPTR(sane_get_option_descriptor
)
69 LOAD_FUNCPTR(sane_control_option
)
70 LOAD_FUNCPTR(sane_get_parameters
)
71 LOAD_FUNCPTR(sane_start
)
72 LOAD_FUNCPTR(sane_read
)
73 LOAD_FUNCPTR(sane_cancel
)
74 LOAD_FUNCPTR(sane_set_io_mode
)
75 LOAD_FUNCPTR(sane_get_select_fd
)
76 LOAD_FUNCPTR(sane_strstatus
)
82 #endif /* SONAME_LIBSANE */
84 BOOL WINAPI
DllMain (HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpvReserved
)
86 TRACE("%p,%x,%p\n", hinstDLL
, fdwReason
, lpvReserved
);
90 case DLL_PROCESS_ATTACH
: {
92 SANE_Int version_code
;
94 libsane_handle
= open_libsane();
98 psane_init (&version_code
, NULL
);
100 SANE_instance
= hinstDLL
;
101 DisableThreadLibraryCalls(hinstDLL
);
104 case DLL_PROCESS_DETACH
:
105 if (lpvReserved
) break;
106 #ifdef SONAME_LIBSANE
107 TRACE("calling sane_exit()\n");
109 close_libsane(libsane_handle
);
117 #ifdef SONAME_LIBSANE
118 static TW_UINT16
SANE_GetIdentity( pTW_IDENTITY
, pTW_IDENTITY
);
119 static TW_UINT16
SANE_OpenDS( pTW_IDENTITY
, pTW_IDENTITY
);
122 static TW_UINT16
SANE_SourceControlHandler (
123 pTW_IDENTITY pOrigin
,
128 TW_UINT16 twRC
= TWRC_SUCCESS
;
136 #ifdef SONAME_LIBSANE
137 psane_close (activeDS
.deviceHandle
);
140 activeDS
.twCC
= TWCC_CAPUNSUPPORTED
;
144 #ifdef SONAME_LIBSANE
145 twRC
= SANE_OpenDS( pOrigin
, (pTW_IDENTITY
)pData
);
148 activeDS
.twCC
= TWCC_CAPUNSUPPORTED
;
152 #ifdef SONAME_LIBSANE
153 twRC
= SANE_GetIdentity( pOrigin
, (pTW_IDENTITY
)pData
);
156 activeDS
.twCC
= TWCC_CAPUNSUPPORTED
;
165 twRC
= SANE_CapabilityGet (pOrigin
, pData
);
168 twRC
= SANE_CapabilityGetCurrent (pOrigin
, pData
);
171 twRC
= SANE_CapabilityGetDefault (pOrigin
, pData
);
173 case MSG_QUERYSUPPORT
:
174 twRC
= SANE_CapabilityQuerySupport (pOrigin
, pData
);
177 twRC
= SANE_CapabilityReset (pOrigin
, pData
);
180 twRC
= SANE_CapabilitySet (pOrigin
, pData
);
184 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
185 FIXME("unrecognized opertion triplet\n");
191 if (MSG
== MSG_PROCESSEVENT
)
192 twRC
= SANE_ProcessEvent (pOrigin
, pData
);
195 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
200 case DAT_PENDINGXFERS
:
204 twRC
= SANE_PendingXfersEndXfer (pOrigin
, pData
);
207 twRC
= SANE_PendingXfersGet (pOrigin
, pData
);
210 twRC
= SANE_PendingXfersReset (pOrigin
, pData
);
213 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
218 case DAT_SETUPMEMXFER
:
220 twRC
= SANE_SetupMemXferGet (pOrigin
, pData
);
223 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
230 twRC
= SANE_GetDSStatus (pOrigin
, pData
);
233 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
238 case DAT_USERINTERFACE
:
242 twRC
= SANE_DisableDSUserInterface (pOrigin
, pData
);
245 twRC
= SANE_EnableDSUserInterface (pOrigin
, pData
);
247 case MSG_ENABLEDSUIONLY
:
248 twRC
= SANE_EnableDSUIOnly (pOrigin
, pData
);
251 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
261 twRC
= SANE_XferGroupGet (pOrigin
, pData
);
264 twRC
= SANE_XferGroupSet (pOrigin
, pData
);
267 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
274 WARN("code unsupported: %d\n", DAT
);
275 activeDS
.twCC
= TWCC_CAPUNSUPPORTED
;
284 static TW_UINT16
SANE_ImageGroupHandler (
285 pTW_IDENTITY pOrigin
,
290 TW_UINT16 twRC
= TWRC_SUCCESS
;
296 twRC
= SANE_ImageInfoGet (pOrigin
, pData
);
299 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
304 case DAT_IMAGELAYOUT
:
308 twRC
= SANE_ImageLayoutGet (pOrigin
, pData
);
311 twRC
= SANE_ImageLayoutGetDefault (pOrigin
, pData
);
314 twRC
= SANE_ImageLayoutReset (pOrigin
, pData
);
317 twRC
= SANE_ImageLayoutSet (pOrigin
, pData
);
321 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
322 ERR("unrecognized operation triplet\n");
327 case DAT_IMAGEMEMXFER
:
329 twRC
= SANE_ImageMemXferGet (pOrigin
, pData
);
332 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
337 case DAT_IMAGENATIVEXFER
:
339 twRC
= SANE_ImageNativeXferGet (pOrigin
, pData
);
342 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
349 activeDS
.twCC
= TWCC_CAPUNSUPPORTED
;
350 WARN("unsupported DG type %d\n", DAT
);
356 /* Main entry point for the TWAIN library */
358 DS_Entry ( pTW_IDENTITY pOrigin
,
364 TW_UINT16 twRC
= TWRC_SUCCESS
; /* Return Code */
366 TRACE("(DG=%d DAT=%d MSG=%d)\n", DG
, DAT
, MSG
);
371 twRC
= SANE_SourceControlHandler (pOrigin
,DAT
,MSG
,pData
);
374 twRC
= SANE_ImageGroupHandler (pOrigin
,DAT
,MSG
,pData
);
377 WARN("Audio group of controls not implemented yet.\n");
379 activeDS
.twCC
= TWCC_CAPUNSUPPORTED
;
382 activeDS
.twCC
= TWCC_BADPROTOCOL
;
389 #ifdef SONAME_LIBSANE
390 /* Sane returns device names that are longer than the 32 bytes allowed
391 by TWAIN. However, it colon separates them, and the last bit is
392 the most interesting. So we use the last bit, and add a signature
393 to ensure uniqueness */
394 static void copy_sane_short_name(const char *in
, char *out
, size_t outsize
)
399 if (strlen(in
) <= outsize
- 1)
405 for (p
= in
; *p
; p
++)
408 p
= strrchr(in
, ':');
414 if (strlen(p
) > outsize
- 7 - 1)
415 p
+= strlen(p
) - (outsize
- 7 - 1);
418 sprintf(out
+ strlen(out
), "(%04X)", signature
% 0x10000);
422 static const SANE_Device
**sane_devlist
;
425 detect_sane_devices(void) {
426 if (sane_devlist
&& sane_devlist
[0]) return;
427 TRACE("detecting sane...\n");
428 if (psane_get_devices (&sane_devlist
, SANE_FALSE
) != SANE_STATUS_GOOD
)
433 SANE_GetIdentity( pTW_IDENTITY pOrigin
, pTW_IDENTITY self
) {
434 static int cursanedev
= 0;
436 detect_sane_devices();
437 if (!sane_devlist
[cursanedev
])
439 self
->ProtocolMajor
= TWON_PROTOCOLMAJOR
;
440 self
->ProtocolMinor
= TWON_PROTOCOLMINOR
;
441 self
->SupportedGroups
= DG_CONTROL
| DG_IMAGE
;
442 copy_sane_short_name(sane_devlist
[cursanedev
]->name
, self
->ProductName
, sizeof(self
->ProductName
) - 1);
443 lstrcpynA (self
->Manufacturer
, sane_devlist
[cursanedev
]->vendor
, sizeof(self
->Manufacturer
) - 1);
444 lstrcpynA (self
->ProductFamily
, sane_devlist
[cursanedev
]->model
, sizeof(self
->ProductFamily
) - 1);
447 if (!sane_devlist
[cursanedev
] ||
448 !sane_devlist
[cursanedev
]->model
||
449 !sane_devlist
[cursanedev
]->vendor
||
450 !sane_devlist
[cursanedev
]->name
452 cursanedev
= 0; /* wrap to begin */
456 static TW_UINT16
SANE_OpenDS( pTW_IDENTITY pOrigin
, pTW_IDENTITY self
) {
460 detect_sane_devices();
461 if (!sane_devlist
[0]) {
462 ERR("No scanners? We should not get to OpenDS?\n");
466 for (i
=0; sane_devlist
[i
] && sane_devlist
[i
]->model
; i
++) {
469 /* To make string as short as above */
470 lstrcpynA(name
, sane_devlist
[i
]->vendor
, sizeof(name
)-1);
471 if (*self
->Manufacturer
&& strcmp(name
, self
->Manufacturer
))
473 lstrcpynA(name
, sane_devlist
[i
]->model
, sizeof(name
)-1);
474 if (*self
->ProductFamily
&& strcmp(name
, self
->ProductFamily
))
476 copy_sane_short_name(sane_devlist
[i
]->name
, name
, sizeof(name
) - 1);
477 if (*self
->ProductName
&& strcmp(name
, self
->ProductName
))
481 if (!sane_devlist
[i
]) {
482 WARN("Scanner not found.\n");
485 status
= psane_open(sane_devlist
[i
]->name
,&activeDS
.deviceHandle
);
486 if (status
== SANE_STATUS_GOOD
) {
487 activeDS
.twCC
= SANE_SaneSetDefaults();
488 if (activeDS
.twCC
== TWCC_SUCCESS
) {
489 activeDS
.currentState
= 4;
493 psane_close(activeDS
.deviceHandle
);
496 ERR("sane_open(%s): %s\n", sane_devlist
[i
]->name
, psane_strstatus (status
));