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 #ifdef SONAME_LIBSANE
106 TRACE("calling sane_exit()\n");
109 close_libsane(libsane_handle);
110 libsane_handle = NULL;
112 SANE_instance = NULL;
119 #ifdef SONAME_LIBSANE
120 static TW_UINT16 SANE_GetIdentity( pTW_IDENTITY, pTW_IDENTITY);
121 static TW_UINT16 SANE_OpenDS( pTW_IDENTITY, pTW_IDENTITY);
124 static TW_UINT16 SANE_SourceControlHandler (
125 pTW_IDENTITY pOrigin,
130 TW_UINT16 twRC = TWRC_SUCCESS;
138 #ifdef SONAME_LIBSANE
139 psane_close (activeDS.deviceHandle);
142 activeDS.twCC = TWCC_CAPUNSUPPORTED;
146 #ifdef SONAME_LIBSANE
147 twRC = SANE_OpenDS( pOrigin, (pTW_IDENTITY)pData);
150 activeDS.twCC = TWCC_CAPUNSUPPORTED;
154 #ifdef SONAME_LIBSANE
155 twRC = SANE_GetIdentity( pOrigin, (pTW_IDENTITY)pData);
158 activeDS.twCC = TWCC_CAPUNSUPPORTED;
167 twRC = SANE_CapabilityGet (pOrigin, pData);
170 twRC = SANE_CapabilityGetCurrent (pOrigin, pData);
173 twRC = SANE_CapabilityGetDefault (pOrigin, pData);
175 case MSG_QUERYSUPPORT:
176 twRC = SANE_CapabilityQuerySupport (pOrigin, pData);
179 twRC = SANE_CapabilityReset (pOrigin, pData);
182 twRC = SANE_CapabilitySet (pOrigin, pData);
186 activeDS.twCC = TWCC_CAPBADOPERATION;
187 FIXME("unrecognized opertion triplet\n");
193 if (MSG == MSG_PROCESSEVENT)
194 twRC = SANE_ProcessEvent (pOrigin, pData);
197 activeDS.twCC = TWCC_CAPBADOPERATION;
202 case DAT_PENDINGXFERS:
206 twRC = SANE_PendingXfersEndXfer (pOrigin, pData);
209 twRC = SANE_PendingXfersGet (pOrigin, pData);
212 twRC = SANE_PendingXfersReset (pOrigin, pData);
215 activeDS.twCC = TWCC_CAPBADOPERATION;
220 case DAT_SETUPMEMXFER:
222 twRC = SANE_SetupMemXferGet (pOrigin, pData);
225 activeDS.twCC = TWCC_CAPBADOPERATION;
232 twRC = SANE_GetDSStatus (pOrigin, pData);
235 activeDS.twCC = TWCC_CAPBADOPERATION;
240 case DAT_USERINTERFACE:
244 twRC = SANE_DisableDSUserInterface (pOrigin, pData);
247 twRC = SANE_EnableDSUserInterface (pOrigin, pData);
249 case MSG_ENABLEDSUIONLY:
250 twRC = SANE_EnableDSUIOnly (pOrigin, pData);
253 activeDS.twCC = TWCC_CAPBADOPERATION;
263 twRC = SANE_XferGroupGet (pOrigin, pData);
266 twRC = SANE_XferGroupSet (pOrigin, pData);
269 activeDS.twCC = TWCC_CAPBADOPERATION;
276 WARN("code unsupported: %d\n", DAT);
277 activeDS.twCC = TWCC_CAPUNSUPPORTED;
286 static TW_UINT16 SANE_ImageGroupHandler (
287 pTW_IDENTITY pOrigin,
292 TW_UINT16 twRC = TWRC_SUCCESS;
298 twRC = SANE_ImageInfoGet (pOrigin, pData);
301 activeDS.twCC = TWCC_CAPBADOPERATION;
306 case DAT_IMAGELAYOUT:
310 twRC = SANE_ImageLayoutGet (pOrigin, pData);
313 twRC = SANE_ImageLayoutGetDefault (pOrigin, pData);
316 twRC = SANE_ImageLayoutReset (pOrigin, pData);
319 twRC = SANE_ImageLayoutSet (pOrigin, pData);
323 activeDS.twCC = TWCC_CAPBADOPERATION;
324 ERR("unrecognized operation triplet\n");
329 case DAT_IMAGEMEMXFER:
331 twRC = SANE_ImageMemXferGet (pOrigin, pData);
334 activeDS.twCC = TWCC_CAPBADOPERATION;
339 case DAT_IMAGENATIVEXFER:
341 twRC = SANE_ImageNativeXferGet (pOrigin, pData);
344 activeDS.twCC = TWCC_CAPBADOPERATION;
351 activeDS.twCC = TWCC_CAPUNSUPPORTED;
352 WARN("unsupported DG type %d\n", DAT);
358 /* Main entry point for the TWAIN library */
360 DS_Entry ( pTW_IDENTITY pOrigin,
366 TW_UINT16 twRC = TWRC_SUCCESS; /* Return Code */
368 TRACE("(DG=%d DAT=%d MSG=%d)\n", DG, DAT, MSG);
373 twRC = SANE_SourceControlHandler (pOrigin,DAT,MSG,pData);
376 twRC = SANE_ImageGroupHandler (pOrigin,DAT,MSG,pData);
379 WARN("Audio group of controls not implemented yet.\n");
381 activeDS.twCC = TWCC_CAPUNSUPPORTED;
384 activeDS.twCC = TWCC_BADPROTOCOL;
391 #ifdef SONAME_LIBSANE
392 /* Sane returns device names that are longer than the 32 bytes allowed
393 by TWAIN. However, it colon separates them, and the last bit is
394 the most interesting. So we use the last bit, and add a signature
395 to ensure uniqueness */
396 static void copy_sane_short_name(const char *in, char *out, size_t outsize)
401 if (strlen(in) <= outsize - 1)
407 for (p = in; *p; p++)
410 p = strrchr(in, ':');
416 if (strlen(p) > outsize - 7 - 1)
417 p += strlen(p) - (outsize - 7 - 1);
420 sprintf(out + strlen(out), "(%04X)", signature % 0x10000);
424 static const SANE_Device **sane_devlist;
427 detect_sane_devices(void) {
428 if (sane_devlist && sane_devlist[0]) return;
429 TRACE("detecting sane...\n");
430 if (psane_get_devices (&sane_devlist, SANE_FALSE) != SANE_STATUS_GOOD)
435 SANE_GetIdentity( pTW_IDENTITY pOrigin, pTW_IDENTITY self) {
436 static int cursanedev = 0;
438 detect_sane_devices();
439 if (!sane_devlist[cursanedev])
441 self->ProtocolMajor = TWON_PROTOCOLMAJOR;
442 self->ProtocolMinor = TWON_PROTOCOLMINOR;
443 self->SupportedGroups = DG_CONTROL | DG_IMAGE;
444 copy_sane_short_name(sane_devlist[cursanedev]->name, self->ProductName, sizeof(self->ProductName) - 1);
445 lstrcpynA (self->Manufacturer, sane_devlist[cursanedev]->vendor, sizeof(self->Manufacturer) - 1);
446 lstrcpynA (self->ProductFamily, sane_devlist[cursanedev]->model, sizeof(self->ProductFamily) - 1);
449 if (!sane_devlist[cursanedev] ||
450 !sane_devlist[cursanedev]->model ||
451 !sane_devlist[cursanedev]->vendor ||
452 !sane_devlist[cursanedev]->name
454 cursanedev = 0; /* wrap to begin */
458 static TW_UINT16 SANE_OpenDS( pTW_IDENTITY pOrigin, pTW_IDENTITY self) {
462 detect_sane_devices();
463 if (!sane_devlist[0]) {
464 ERR("No scanners? We should not get to OpenDS?\n");
468 for (i=0; sane_devlist[i] && sane_devlist[i]->model; i++) {
471 /* To make string as short as above */
472 lstrcpynA(name, sane_devlist[i]->vendor, sizeof(name)-1);
473 if (*self->Manufacturer && strcmp(name, self->Manufacturer))
475 lstrcpynA(name, sane_devlist[i]->model, sizeof(name)-1);
476 if (*self->ProductFamily && strcmp(name, self->ProductFamily))
478 copy_sane_short_name(sane_devlist[i]->name, name, sizeof(name) - 1);
479 if (*self->ProductName && strcmp(name, self->ProductName))
483 if (!sane_devlist[i]) {
484 WARN("Scanner not found.\n");
487 status = psane_open(sane_devlist[i]->name,&activeDS.deviceHandle);
488 if (status == SANE_STATUS_GOOD) {
489 activeDS.twCC = SANE_SaneSetDefaults();
490 if (activeDS.twCC == TWCC_SUCCESS) {
491 activeDS.currentState = 4;
495 psane_close(activeDS.deviceHandle);
498 ERR("sane_open(%s): %s\n", sane_devlist[i]->name, psane_strstatus (status));