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"
31 #include "wine/debug.h"
32 #include "wine/library.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(twain);
36 HINSTANCE SANE_instance;
40 static void *libsane_handle;
42 static void close_libsane(void *h)
45 wine_dlclose(h, NULL, 0);
48 static void *open_libsane(void)
52 h = wine_dlopen(SONAME_LIBSANE, RTLD_GLOBAL | RTLD_NOW, NULL, 0);
55 WARN("dlopen(%s) failed\n", SONAME_LIBSANE);
59 #define LOAD_FUNCPTR(f) \
60 if((p##f = wine_dlsym(h, #f, NULL, 0)) == NULL) { \
62 ERR("Could not dlsym %s\n", #f); \
66 LOAD_FUNCPTR(sane_init)
67 LOAD_FUNCPTR(sane_exit)
68 LOAD_FUNCPTR(sane_get_devices)
69 LOAD_FUNCPTR(sane_open)
70 LOAD_FUNCPTR(sane_close)
71 LOAD_FUNCPTR(sane_get_option_descriptor)
72 LOAD_FUNCPTR(sane_control_option)
73 LOAD_FUNCPTR(sane_get_parameters)
74 LOAD_FUNCPTR(sane_start)
75 LOAD_FUNCPTR(sane_read)
76 LOAD_FUNCPTR(sane_cancel)
77 LOAD_FUNCPTR(sane_set_io_mode)
78 LOAD_FUNCPTR(sane_get_select_fd)
79 LOAD_FUNCPTR(sane_strstatus)
85 #endif /* SONAME_LIBSANE */
87 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
89 TRACE("%p,%x,%p\n", hinstDLL, fdwReason, lpvReserved);
93 case DLL_PROCESS_ATTACH: {
95 SANE_Int version_code;
97 libsane_handle = open_libsane();
101 psane_init (&version_code, NULL);
103 SANE_instance = hinstDLL;
104 DisableThreadLibraryCalls(hinstDLL);
107 case DLL_PROCESS_DETACH:
108 #ifdef SONAME_LIBSANE
109 TRACE("calling sane_exit()\n");
112 close_libsane(libsane_handle);
113 libsane_handle = NULL;
115 SANE_instance = NULL;
122 #ifdef SONAME_LIBSANE
123 static TW_UINT16 SANE_GetIdentity( pTW_IDENTITY, pTW_IDENTITY);
124 static TW_UINT16 SANE_OpenDS( pTW_IDENTITY, pTW_IDENTITY);
127 static TW_UINT16 SANE_SourceControlHandler (
128 pTW_IDENTITY pOrigin,
133 TW_UINT16 twRC = TWRC_SUCCESS;
141 #ifdef SONAME_LIBSANE
142 psane_close (activeDS.deviceHandle);
145 activeDS.twCC = TWCC_CAPUNSUPPORTED;
149 #ifdef SONAME_LIBSANE
150 twRC = SANE_OpenDS( pOrigin, (pTW_IDENTITY)pData);
153 activeDS.twCC = TWCC_CAPUNSUPPORTED;
157 #ifdef SONAME_LIBSANE
158 twRC = SANE_GetIdentity( pOrigin, (pTW_IDENTITY)pData);
161 activeDS.twCC = TWCC_CAPUNSUPPORTED;
170 twRC = SANE_CapabilityGet (pOrigin, pData);
173 twRC = SANE_CapabilityGetCurrent (pOrigin, pData);
176 twRC = SANE_CapabilityGetDefault (pOrigin, pData);
178 case MSG_QUERYSUPPORT:
179 twRC = SANE_CapabilityQuerySupport (pOrigin, pData);
182 twRC = SANE_CapabilityReset (pOrigin, pData);
185 twRC = SANE_CapabilitySet (pOrigin, pData);
189 activeDS.twCC = TWCC_CAPBADOPERATION;
190 FIXME("unrecognized opertion triplet\n");
196 if (MSG == MSG_PROCESSEVENT)
197 twRC = SANE_ProcessEvent (pOrigin, pData);
200 activeDS.twCC = TWCC_CAPBADOPERATION;
205 case DAT_PENDINGXFERS:
209 twRC = SANE_PendingXfersEndXfer (pOrigin, pData);
212 twRC = SANE_PendingXfersGet (pOrigin, pData);
215 twRC = SANE_PendingXfersReset (pOrigin, pData);
218 activeDS.twCC = TWCC_CAPBADOPERATION;
223 case DAT_SETUPMEMXFER:
225 twRC = SANE_SetupMemXferGet (pOrigin, pData);
228 activeDS.twCC = TWCC_CAPBADOPERATION;
235 twRC = SANE_GetDSStatus (pOrigin, pData);
238 activeDS.twCC = TWCC_CAPBADOPERATION;
243 case DAT_USERINTERFACE:
247 twRC = SANE_DisableDSUserInterface (pOrigin, pData);
250 twRC = SANE_EnableDSUserInterface (pOrigin, pData);
252 case MSG_ENABLEDSUIONLY:
253 twRC = SANE_EnableDSUIOnly (pOrigin, pData);
256 activeDS.twCC = TWCC_CAPBADOPERATION;
266 twRC = SANE_XferGroupGet (pOrigin, pData);
269 twRC = SANE_XferGroupSet (pOrigin, pData);
272 activeDS.twCC = TWCC_CAPBADOPERATION;
279 WARN("code unsupported: %d\n", DAT);
280 activeDS.twCC = TWCC_CAPUNSUPPORTED;
289 static TW_UINT16 SANE_ImageGroupHandler (
290 pTW_IDENTITY pOrigin,
295 TW_UINT16 twRC = TWRC_SUCCESS;
301 twRC = SANE_ImageInfoGet (pOrigin, pData);
304 activeDS.twCC = TWCC_CAPBADOPERATION;
309 case DAT_IMAGELAYOUT:
313 twRC = SANE_ImageLayoutGet (pOrigin, pData);
316 twRC = SANE_ImageLayoutGetDefault (pOrigin, pData);
319 twRC = SANE_ImageLayoutReset (pOrigin, pData);
322 twRC = SANE_ImageLayoutSet (pOrigin, pData);
326 activeDS.twCC = TWCC_CAPBADOPERATION;
327 ERR("unrecognized operation triplet\n");
332 case DAT_IMAGEMEMXFER:
334 twRC = SANE_ImageMemXferGet (pOrigin, pData);
337 activeDS.twCC = TWCC_CAPBADOPERATION;
342 case DAT_IMAGENATIVEXFER:
344 twRC = SANE_ImageNativeXferGet (pOrigin, pData);
347 activeDS.twCC = TWCC_CAPBADOPERATION;
354 activeDS.twCC = TWCC_CAPUNSUPPORTED;
355 WARN("unsupported DG type %d\n", DAT);
361 /* Main entry point for the TWAIN library */
363 DS_Entry ( pTW_IDENTITY pOrigin,
369 TW_UINT16 twRC = TWRC_SUCCESS; /* Return Code */
371 TRACE("(DG=%d DAT=%d MSG=%d)\n", DG, DAT, MSG);
376 twRC = SANE_SourceControlHandler (pOrigin,DAT,MSG,pData);
379 twRC = SANE_ImageGroupHandler (pOrigin,DAT,MSG,pData);
382 WARN("Audio group of controls not implemented yet.\n");
384 activeDS.twCC = TWCC_CAPUNSUPPORTED;
387 activeDS.twCC = TWCC_BADPROTOCOL;
394 #ifdef SONAME_LIBSANE
395 /* Sane returns device names that are longer than the 32 bytes allowed
396 by TWAIN. However, it colon separates them, and the last bit is
397 the most interesting. So we use the last bit, and add a signature
398 to ensure uniqueness */
399 static void copy_sane_short_name(const char *in, char *out, size_t outsize)
404 if (strlen(in) <= outsize - 1)
410 for (p = in; *p; p++)
413 p = strrchr(in, ':');
419 if (strlen(p) > outsize - 7 - 1)
420 p += strlen(p) - (outsize - 7 - 1);
423 sprintf(out + strlen(out), "(%04X)", signature % 0x10000);
427 static const SANE_Device **sane_devlist;
430 detect_sane_devices(void) {
431 if (sane_devlist && sane_devlist[0]) return;
432 TRACE("detecting sane...\n");
433 if (psane_get_devices (&sane_devlist, SANE_FALSE) != SANE_STATUS_GOOD)
438 SANE_GetIdentity( pTW_IDENTITY pOrigin, pTW_IDENTITY self) {
439 static int cursanedev = 0;
441 detect_sane_devices();
442 if (!sane_devlist[cursanedev])
444 self->ProtocolMajor = TWON_PROTOCOLMAJOR;
445 self->ProtocolMinor = TWON_PROTOCOLMINOR;
446 self->SupportedGroups = DG_CONTROL | DG_IMAGE;
447 copy_sane_short_name(sane_devlist[cursanedev]->name, self->ProductName, sizeof(self->ProductName) - 1);
448 lstrcpynA (self->Manufacturer, sane_devlist[cursanedev]->vendor, sizeof(self->Manufacturer) - 1);
449 lstrcpynA (self->ProductFamily, sane_devlist[cursanedev]->model, sizeof(self->ProductFamily) - 1);
452 if (!sane_devlist[cursanedev] ||
453 !sane_devlist[cursanedev]->model ||
454 !sane_devlist[cursanedev]->vendor ||
455 !sane_devlist[cursanedev]->name
457 cursanedev = 0; /* wrap to begin */
461 static TW_UINT16 SANE_OpenDS( pTW_IDENTITY pOrigin, pTW_IDENTITY self) {
465 detect_sane_devices();
466 if (!sane_devlist[0]) {
467 ERR("No scanners? We should not get to OpenDS?\n");
471 for (i=0; sane_devlist[i] && sane_devlist[i]->model; i++) {
474 /* To make string as short as above */
475 lstrcpynA(name, sane_devlist[i]->vendor, sizeof(name)-1);
476 if (self->Manufacturer && *self->Manufacturer && strcmp(name, self->Manufacturer))
478 lstrcpynA(name, sane_devlist[i]->model, sizeof(name)-1);
479 if (self->ProductFamily && *self->ProductFamily && strcmp(name, self->ProductFamily))
481 copy_sane_short_name(sane_devlist[i]->name, name, sizeof(name) - 1);
482 if (self->ProductName && *self->ProductName && strcmp(name, self->ProductName))
486 if (!sane_devlist[i]) {
487 WARN("Scanner not found.\n");
490 status = psane_open(sane_devlist[i]->name,&activeDS.deviceHandle);
491 if (status == SANE_STATUS_GOOD) {
492 activeDS.twCC = SANE_SaneSetDefaults();
493 if (activeDS.twCC == TWCC_SUCCESS) {
494 activeDS.currentState = 4;
498 psane_close(activeDS.deviceHandle);
501 ERR("sane_open(%s): %s\n", sane_devlist[i]->name, psane_strstatus (status));