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);
147 #ifdef SONAME_LIBSANE
148 twRC = SANE_OpenDS( pOrigin, (pTW_IDENTITY)pData);
154 #ifdef SONAME_LIBSANE
155 twRC = SANE_GetIdentity( pOrigin, (pTW_IDENTITY)pData);
166 twRC = SANE_CapabilityGet (pOrigin, pData);
169 twRC = SANE_CapabilityGetCurrent (pOrigin, pData);
172 twRC = SANE_CapabilityGetDefault (pOrigin, pData);
174 case MSG_QUERYSUPPORT:
175 twRC = SANE_CapabilityQuerySupport (pOrigin, pData);
178 twRC = SANE_CapabilityReset (pOrigin, pData);
181 twRC = SANE_CapabilitySet (pOrigin, pData);
185 FIXME("unrecognized opertion triplet\n");
189 case DAT_CUSTOMDSDATA:
193 twRC = SANE_CustomDSDataGet (pOrigin, pData);
196 twRC = SANE_CustomDSDataSet (pOrigin, pData);
206 /*case MSG_AUTOMATICCAPTUREDIRECTORY:
207 twRC = SANE_AutomaticCaptureDirectory
210 case MSG_CHANGEDIRECTORY:
211 twRC = SANE_ChangeDirectory (pOrigin, pData);
214 twRC = SANE_FileSystemCopy (pOrigin, pData);
216 case MSG_CREATEDIRECTORY:
217 twRC = SANE_CreateDirectory (pOrigin, pData);
220 twRC = SANE_FileSystemDelete (pOrigin, pData);
222 case MSG_FORMATMEDIA:
223 twRC = SANE_FormatMedia (pOrigin, pData);
226 twRC = SANE_FileSystemGetClose (pOrigin, pData);
228 case MSG_GETFIRSTFILE:
229 twRC = SANE_FileSystemGetFirstFile (pOrigin, pData);
232 twRC = SANE_FileSystemGetInfo (pOrigin, pData);
234 case MSG_GETNEXTFILE:
235 twRC = SANE_FileSystemGetNextFile (pOrigin, pData);
238 twRC = SANE_FileSystemRename (pOrigin, pData);
247 if (MSG == MSG_PROCESSEVENT)
248 twRC = SANE_ProcessEvent (pOrigin, pData);
254 if (MSG == MSG_PASSTHRU)
255 twRC = SANE_PassThrough (pOrigin, pData);
260 case DAT_PENDINGXFERS:
264 twRC = SANE_PendingXfersEndXfer (pOrigin, pData);
267 twRC = SANE_PendingXfersGet (pOrigin, pData);
270 twRC = SANE_PendingXfersReset (pOrigin, pData);
272 /*case MSG_STOPFEEDER:
273 twRC = SANE_PendingXfersStopFeeder (pOrigin, pData);
280 case DAT_SETUPFILEXFER:
284 twRC = SANE_SetupFileXferGet (pOrigin, pData);
287 twRC = SANE_SetupFileXferGetDefault (pOrigin, pData);
290 twRC = SANE_SetupFileXferReset (pOrigin, pData);
293 twRC = SANE_SetupFileXferSet (pOrigin, pData);
301 /*case DAT_SETUPFILEXFER2:
305 twRC = SANE_SetupFileXfer2Get (pOrigin, pData);
308 twRC = SANE_SetupFileXfer2GetDefault (pOrigin, pData);
311 twRC = SANE_SetupFileXfer2Reset (pOrigin, pData);
314 twRC = SANE_SetupFileXfer2Set (pOrigin, pData);
318 case DAT_SETUPMEMXFER:
320 twRC = SANE_SetupMemXferGet (pOrigin, pData);
327 twRC = SANE_GetDSStatus (pOrigin, pData);
332 case DAT_USERINTERFACE:
336 twRC = SANE_DisableDSUserInterface (pOrigin, pData);
339 twRC = SANE_EnableDSUserInterface (pOrigin, pData);
341 case MSG_ENABLEDSUIONLY:
342 twRC = SANE_EnableDSUIOnly (pOrigin, pData);
354 twRC = SANE_XferGroupGet (pOrigin, pData);
357 twRC = SANE_XferGroupSet (pOrigin, pData);
366 FIXME("code unknown: %d\n", DAT);
375 TW_UINT16 SANE_ImageGroupHandler (
376 pTW_IDENTITY pOrigin,
381 TW_UINT16 twRC = TWRC_SUCCESS;
387 twRC = SANE_CIEColorGet (pOrigin, pData);
392 case DAT_EXTIMAGEINFO:
394 twRC = SANE_ExtImageInfoGet (pOrigin, pData);
399 case DAT_GRAYRESPONSE:
403 twRC = SANE_GrayResponseReset (pOrigin, pData);
406 twRC = SANE_GrayResponseSet (pOrigin, pData);
410 activeDS.twCC = TWCC_BADPROTOCOL;
411 FIXME("unrecognized operation triplet\n");
415 case DAT_IMAGEFILEXFER:
417 twRC = SANE_ImageFileXferGet (pOrigin, pData);
424 twRC = SANE_ImageInfoGet (pOrigin, pData);
429 case DAT_IMAGELAYOUT:
433 twRC = SANE_ImageLayoutGet (pOrigin, pData);
436 twRC = SANE_ImageLayoutGetDefault (pOrigin, pData);
439 twRC = SANE_ImageLayoutReset (pOrigin, pData);
442 twRC = SANE_ImageLayoutSet (pOrigin, pData);
446 activeDS.twCC = TWCC_BADPROTOCOL;
447 ERR("unrecognized operation triplet\n");
452 case DAT_IMAGEMEMXFER:
454 twRC = SANE_ImageMemXferGet (pOrigin, pData);
459 case DAT_IMAGENATIVEXFER:
461 twRC = SANE_ImageNativeXferGet (pOrigin, pData);
466 case DAT_JPEGCOMPRESSION:
470 twRC = SANE_JPEGCompressionGet (pOrigin, pData);
473 twRC = SANE_JPEGCompressionGetDefault (pOrigin, pData);
476 twRC = SANE_JPEGCompressionReset (pOrigin, pData);
479 twRC = SANE_JPEGCompressionSet (pOrigin, pData);
483 activeDS.twCC = TWCC_BADPROTOCOL;
484 WARN("unrecognized operation triplet\n");
493 twRC = SANE_Palette8Get (pOrigin, pData);
496 twRC = SANE_Palette8GetDefault (pOrigin, pData);
499 twRC = SANE_Palette8Reset (pOrigin, pData);
502 twRC = SANE_Palette8Set (pOrigin, pData);
506 activeDS.twCC = TWCC_BADPROTOCOL;
507 WARN("unrecognized operation triplet\n");
511 case DAT_RGBRESPONSE:
515 twRC = SANE_RGBResponseReset (pOrigin, pData);
518 twRC = SANE_RGBResponseSet (pOrigin, pData);
522 activeDS.twCC = TWCC_BADPROTOCOL;
523 WARN("unrecognized operation triplet\n");
530 activeDS.twCC = TWCC_BADPROTOCOL;
531 FIXME("unrecognized DG type %d\n", DAT);
536 /* Main entry point for the TWAIN library */
538 DS_Entry ( pTW_IDENTITY pOrigin,
544 TW_UINT16 twRC = TWRC_SUCCESS; /* Return Code */
546 TRACE("(DG=%ld DAT=%d MSG=%d)\n", DG, DAT, MSG);
551 twRC = SANE_SourceControlHandler (pOrigin,DAT,MSG,pData);
554 twRC = SANE_ImageGroupHandler (pOrigin,DAT,MSG,pData);
557 FIXME("Audio group of controls not implemented yet.\n");
559 activeDS.twCC = TWCC_BADPROTOCOL;
566 #ifdef SONAME_LIBSANE
567 /* Sane returns device names that are longer than the 32 bytes allowed
568 by TWAIN. However, it colon separates them, and the last bit is
569 the most interesting. So we use the last bit, and add a signature
570 to ensure uniqueness */
571 static void copy_sane_short_name(const char *in, char *out, size_t outsize)
576 if (strlen(in) <= outsize - 1)
582 for (p = in; *p; p++)
585 p = strrchr(in, ':');
591 if (strlen(p) > outsize - 7 - 1)
592 p += strlen(p) - (outsize - 7 - 1);
595 sprintf(out + strlen(out), "(%04X)", signature % 0x10000);
599 static const SANE_Device **sane_devlist;
602 detect_sane_devices(void) {
603 if (sane_devlist && sane_devlist[0]) return;
604 TRACE("detecting sane...\n");
605 if (psane_get_devices (&sane_devlist, SANE_FALSE) != SANE_STATUS_GOOD)
610 SANE_GetIdentity( pTW_IDENTITY pOrigin, pTW_IDENTITY self) {
611 static int cursanedev = 0;
613 detect_sane_devices();
614 if (!sane_devlist[cursanedev])
616 self->ProtocolMajor = TWON_PROTOCOLMAJOR;
617 self->ProtocolMinor = TWON_PROTOCOLMINOR;
618 copy_sane_short_name(sane_devlist[cursanedev]->name, self->ProductName, sizeof(self->ProductName) - 1);
619 lstrcpynA (self->Manufacturer, sane_devlist[cursanedev]->vendor, sizeof(self->Manufacturer) - 1);
620 lstrcpynA (self->ProductFamily, sane_devlist[cursanedev]->model, sizeof(self->ProductFamily) - 1);
623 if (!sane_devlist[cursanedev] ||
624 !sane_devlist[cursanedev]->model ||
625 !sane_devlist[cursanedev]->vendor ||
626 !sane_devlist[cursanedev]->name
628 cursanedev = 0; /* wrap to begin */
632 static TW_UINT16 SANE_OpenDS( pTW_IDENTITY pOrigin, pTW_IDENTITY self) {
636 detect_sane_devices();
637 if (!sane_devlist[0]) {
638 ERR("No scanners? We should not get to OpenDS?\n");
642 for (i=0; sane_devlist[i] && sane_devlist[i]->model; i++) {
645 /* To make string as short as above */
646 lstrcpynA(name, sane_devlist[i]->vendor, sizeof(name)-1);
647 if (strcmp(name, self->Manufacturer))
649 lstrcpynA(name, sane_devlist[i]->model, sizeof(name)-1);
650 if (strcmp(name, self->ProductFamily))
652 copy_sane_short_name(sane_devlist[i]->name, name, sizeof(name) - 1);
653 if (strcmp(name, self->ProductName))
657 if (!sane_devlist[i]) {
658 FIXME("Scanner not found? Using first one!\n");
661 status = psane_open(sane_devlist[i]->name,&activeDS.deviceHandle);
662 if (status == SANE_STATUS_GOOD) {
663 activeDS.currentState = 4;
664 activeDS.twCC = TWRC_SUCCESS;
667 FIXME("sane_open(%s): %s\n", sane_devlist[i]->name, psane_strstatus (status));