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: {
96 SANE_Int version_code;
98 libsane_handle = open_libsane();
102 status = psane_init (&version_code, NULL);
104 SANE_instance = hinstDLL;
105 DisableThreadLibraryCalls(hinstDLL);
108 case DLL_PROCESS_DETACH:
109 #ifdef SONAME_LIBSANE
110 TRACE("calling sane_exit()\n");
113 close_libsane(libsane_handle);
114 libsane_handle = NULL;
116 SANE_instance = NULL;
123 #ifdef SONAME_LIBSANE
124 static TW_UINT16 SANE_GetIdentity( pTW_IDENTITY, pTW_IDENTITY);
125 static TW_UINT16 SANE_OpenDS( pTW_IDENTITY, pTW_IDENTITY);
128 static TW_UINT16 SANE_SourceControlHandler (
129 pTW_IDENTITY pOrigin,
134 TW_UINT16 twRC = TWRC_SUCCESS;
142 #ifdef SONAME_LIBSANE
143 psane_close (activeDS.deviceHandle);
146 activeDS.twCC = TWCC_CAPUNSUPPORTED;
150 #ifdef SONAME_LIBSANE
151 twRC = SANE_OpenDS( pOrigin, (pTW_IDENTITY)pData);
154 activeDS.twCC = TWCC_CAPUNSUPPORTED;
158 #ifdef SONAME_LIBSANE
159 twRC = SANE_GetIdentity( pOrigin, (pTW_IDENTITY)pData);
162 activeDS.twCC = TWCC_CAPUNSUPPORTED;
171 twRC = SANE_CapabilityGet (pOrigin, pData);
174 twRC = SANE_CapabilityGetCurrent (pOrigin, pData);
177 twRC = SANE_CapabilityGetDefault (pOrigin, pData);
179 case MSG_QUERYSUPPORT:
180 twRC = SANE_CapabilityQuerySupport (pOrigin, pData);
183 twRC = SANE_CapabilityReset (pOrigin, pData);
186 twRC = SANE_CapabilitySet (pOrigin, pData);
190 activeDS.twCC = TWCC_CAPBADOPERATION;
191 FIXME("unrecognized opertion triplet\n");
197 if (MSG == MSG_PROCESSEVENT)
198 twRC = SANE_ProcessEvent (pOrigin, pData);
201 activeDS.twCC = TWCC_CAPBADOPERATION;
206 case DAT_PENDINGXFERS:
210 twRC = SANE_PendingXfersEndXfer (pOrigin, pData);
213 twRC = SANE_PendingXfersGet (pOrigin, pData);
216 twRC = SANE_PendingXfersReset (pOrigin, pData);
219 activeDS.twCC = TWCC_CAPBADOPERATION;
224 case DAT_SETUPMEMXFER:
226 twRC = SANE_SetupMemXferGet (pOrigin, pData);
229 activeDS.twCC = TWCC_CAPBADOPERATION;
236 twRC = SANE_GetDSStatus (pOrigin, pData);
239 activeDS.twCC = TWCC_CAPBADOPERATION;
244 case DAT_USERINTERFACE:
248 twRC = SANE_DisableDSUserInterface (pOrigin, pData);
251 twRC = SANE_EnableDSUserInterface (pOrigin, pData);
253 case MSG_ENABLEDSUIONLY:
254 twRC = SANE_EnableDSUIOnly (pOrigin, pData);
257 activeDS.twCC = TWCC_CAPBADOPERATION;
267 twRC = SANE_XferGroupGet (pOrigin, pData);
270 twRC = SANE_XferGroupSet (pOrigin, pData);
273 activeDS.twCC = TWCC_CAPBADOPERATION;
280 WARN("code unsupported: %d\n", DAT);
281 activeDS.twCC = TWCC_CAPUNSUPPORTED;
290 static TW_UINT16 SANE_ImageGroupHandler (
291 pTW_IDENTITY pOrigin,
296 TW_UINT16 twRC = TWRC_SUCCESS;
302 twRC = SANE_ImageInfoGet (pOrigin, pData);
305 activeDS.twCC = TWCC_CAPBADOPERATION;
310 case DAT_IMAGELAYOUT:
314 twRC = SANE_ImageLayoutGet (pOrigin, pData);
317 twRC = SANE_ImageLayoutGetDefault (pOrigin, pData);
320 twRC = SANE_ImageLayoutReset (pOrigin, pData);
323 twRC = SANE_ImageLayoutSet (pOrigin, pData);
327 activeDS.twCC = TWCC_CAPBADOPERATION;
328 ERR("unrecognized operation triplet\n");
333 case DAT_IMAGEMEMXFER:
335 twRC = SANE_ImageMemXferGet (pOrigin, pData);
338 activeDS.twCC = TWCC_CAPBADOPERATION;
343 case DAT_IMAGENATIVEXFER:
345 twRC = SANE_ImageNativeXferGet (pOrigin, pData);
348 activeDS.twCC = TWCC_CAPBADOPERATION;
355 activeDS.twCC = TWCC_CAPUNSUPPORTED;
356 WARN("unsupported DG type %d\n", DAT);
362 /* Main entry point for the TWAIN library */
364 DS_Entry ( pTW_IDENTITY pOrigin,
370 TW_UINT16 twRC = TWRC_SUCCESS; /* Return Code */
372 TRACE("(DG=%d DAT=%d MSG=%d)\n", DG, DAT, MSG);
377 twRC = SANE_SourceControlHandler (pOrigin,DAT,MSG,pData);
380 twRC = SANE_ImageGroupHandler (pOrigin,DAT,MSG,pData);
383 WARN("Audio group of controls not implemented yet.\n");
385 activeDS.twCC = TWCC_CAPUNSUPPORTED;
388 activeDS.twCC = TWCC_BADPROTOCOL;
395 #ifdef SONAME_LIBSANE
396 /* Sane returns device names that are longer than the 32 bytes allowed
397 by TWAIN. However, it colon separates them, and the last bit is
398 the most interesting. So we use the last bit, and add a signature
399 to ensure uniqueness */
400 static void copy_sane_short_name(const char *in, char *out, size_t outsize)
405 if (strlen(in) <= outsize - 1)
411 for (p = in; *p; p++)
414 p = strrchr(in, ':');
420 if (strlen(p) > outsize - 7 - 1)
421 p += strlen(p) - (outsize - 7 - 1);
424 sprintf(out + strlen(out), "(%04X)", signature % 0x10000);
428 static const SANE_Device **sane_devlist;
431 detect_sane_devices(void) {
432 if (sane_devlist && sane_devlist[0]) return;
433 TRACE("detecting sane...\n");
434 if (psane_get_devices (&sane_devlist, SANE_FALSE) != SANE_STATUS_GOOD)
439 SANE_GetIdentity( pTW_IDENTITY pOrigin, pTW_IDENTITY self) {
440 static int cursanedev = 0;
442 detect_sane_devices();
443 if (!sane_devlist[cursanedev])
445 self->ProtocolMajor = TWON_PROTOCOLMAJOR;
446 self->ProtocolMinor = TWON_PROTOCOLMINOR;
447 self->SupportedGroups = DG_CONTROL | DG_IMAGE;
448 copy_sane_short_name(sane_devlist[cursanedev]->name, self->ProductName, sizeof(self->ProductName) - 1);
449 lstrcpynA (self->Manufacturer, sane_devlist[cursanedev]->vendor, sizeof(self->Manufacturer) - 1);
450 lstrcpynA (self->ProductFamily, sane_devlist[cursanedev]->model, sizeof(self->ProductFamily) - 1);
453 if (!sane_devlist[cursanedev] ||
454 !sane_devlist[cursanedev]->model ||
455 !sane_devlist[cursanedev]->vendor ||
456 !sane_devlist[cursanedev]->name
458 cursanedev = 0; /* wrap to begin */
462 static TW_UINT16 SANE_OpenDS( pTW_IDENTITY pOrigin, pTW_IDENTITY self) {
466 detect_sane_devices();
467 if (!sane_devlist[0]) {
468 ERR("No scanners? We should not get to OpenDS?\n");
472 for (i=0; sane_devlist[i] && sane_devlist[i]->model; i++) {
475 /* To make string as short as above */
476 lstrcpynA(name, sane_devlist[i]->vendor, sizeof(name)-1);
477 if (self->Manufacturer && *self->Manufacturer && strcmp(name, self->Manufacturer))
479 lstrcpynA(name, sane_devlist[i]->model, sizeof(name)-1);
480 if (self->ProductFamily && *self->ProductFamily && strcmp(name, self->ProductFamily))
482 copy_sane_short_name(sane_devlist[i]->name, name, sizeof(name) - 1);
483 if (self->ProductName && *self->ProductName && strcmp(name, self->ProductName))
487 if (!sane_devlist[i]) {
488 WARN("Scanner not found.\n");
491 status = psane_open(sane_devlist[i]->name,&activeDS.deviceHandle);
492 if (status == SANE_STATUS_GOOD) {
493 activeDS.twCC = SANE_SaneSetDefaults();
494 if (activeDS.twCC == TWCC_SUCCESS) {
495 activeDS.currentState = 4;
499 psane_close(activeDS.deviceHandle);
502 ERR("sane_open(%s): %s\n", sane_devlist[i]->name, psane_strstatus (status));