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
;
39 #ifndef SONAME_LIBSANE
40 #define SONAME_LIBSANE "libsane.so"
43 static void *libsane_handle
;
45 static void close_libsane(void *h
)
48 wine_dlclose(h
, NULL
, 0);
51 static void *open_libsane(void)
55 h
= wine_dlopen(SONAME_LIBSANE
, RTLD_GLOBAL
| RTLD_NOW
, NULL
, 0);
58 WARN("dlopen(%s) failed\n", SONAME_LIBSANE
);
62 #define LOAD_FUNCPTR(f) \
63 if((p##f = wine_dlsym(h, #f, NULL, 0)) == NULL) { \
65 ERR("Could not dlsym %s\n", #f); \
69 LOAD_FUNCPTR(sane_init
)
70 LOAD_FUNCPTR(sane_exit
)
71 LOAD_FUNCPTR(sane_get_devices
)
72 LOAD_FUNCPTR(sane_open
)
73 LOAD_FUNCPTR(sane_close
)
74 LOAD_FUNCPTR(sane_get_option_descriptor
)
75 LOAD_FUNCPTR(sane_control_option
)
76 LOAD_FUNCPTR(sane_get_parameters
)
77 LOAD_FUNCPTR(sane_start
)
78 LOAD_FUNCPTR(sane_read
)
79 LOAD_FUNCPTR(sane_cancel
)
80 LOAD_FUNCPTR(sane_set_io_mode
)
81 LOAD_FUNCPTR(sane_get_select_fd
)
82 LOAD_FUNCPTR(sane_strstatus
)
88 #endif /* HAVE_SANE */
90 BOOL WINAPI
DllMain (HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpvReserved
)
92 TRACE("%p,%x,%p\n", hinstDLL
, fdwReason
, lpvReserved
);
96 case DLL_PROCESS_ATTACH
: {
99 SANE_Int version_code
;
101 libsane_handle
= open_libsane();
102 if (! libsane_handle
)
105 status
= psane_init (&version_code
, NULL
);
107 SANE_instance
= hinstDLL
;
108 DisableThreadLibraryCalls(hinstDLL
);
111 case DLL_PROCESS_DETACH
:
113 TRACE("calling sane_exit()\n");
116 close_libsane(libsane_handle
);
117 libsane_handle
= NULL
;
119 SANE_instance
= NULL
;
127 static TW_UINT16
SANE_GetIdentity( pTW_IDENTITY
, pTW_IDENTITY
);
128 static TW_UINT16
SANE_OpenDS( pTW_IDENTITY
, pTW_IDENTITY
);
131 static TW_UINT16
SANE_SourceControlHandler (
132 pTW_IDENTITY pOrigin
,
137 TW_UINT16 twRC
= TWRC_SUCCESS
;
146 psane_close (activeDS
.deviceHandle
);
151 twRC
= SANE_OpenDS( pOrigin
, (pTW_IDENTITY
)pData
);
158 twRC
= SANE_GetIdentity( pOrigin
, (pTW_IDENTITY
)pData
);
169 twRC
= SANE_CapabilityGet (pOrigin
, pData
);
172 twRC
= SANE_CapabilityGetCurrent (pOrigin
, pData
);
175 twRC
= SANE_CapabilityGetDefault (pOrigin
, pData
);
177 case MSG_QUERYSUPPORT
:
178 twRC
= SANE_CapabilityQuerySupport (pOrigin
, pData
);
181 twRC
= SANE_CapabilityReset (pOrigin
, pData
);
184 twRC
= SANE_CapabilitySet (pOrigin
, pData
);
188 FIXME("unrecognized opertion triplet\n");
192 case DAT_CUSTOMDSDATA
:
196 twRC
= SANE_CustomDSDataGet (pOrigin
, pData
);
199 twRC
= SANE_CustomDSDataSet (pOrigin
, pData
);
209 /*case MSG_AUTOMATICCAPTUREDIRECTORY:
210 twRC = SANE_AutomaticCaptureDirectory
213 case MSG_CHANGEDIRECTORY
:
214 twRC
= SANE_ChangeDirectory (pOrigin
, pData
);
217 twRC = SANE_FileSystemCopy (pOrigin, pData);
219 case MSG_CREATEDIRECTORY
:
220 twRC
= SANE_CreateDirectory (pOrigin
, pData
);
223 twRC
= SANE_FileSystemDelete (pOrigin
, pData
);
225 case MSG_FORMATMEDIA
:
226 twRC
= SANE_FormatMedia (pOrigin
, pData
);
229 twRC
= SANE_FileSystemGetClose (pOrigin
, pData
);
231 case MSG_GETFIRSTFILE
:
232 twRC
= SANE_FileSystemGetFirstFile (pOrigin
, pData
);
235 twRC
= SANE_FileSystemGetInfo (pOrigin
, pData
);
237 case MSG_GETNEXTFILE
:
238 twRC
= SANE_FileSystemGetNextFile (pOrigin
, pData
);
241 twRC
= SANE_FileSystemRename (pOrigin
, pData
);
250 if (MSG
== MSG_PROCESSEVENT
)
251 twRC
= SANE_ProcessEvent (pOrigin
, pData
);
257 if (MSG
== MSG_PASSTHRU
)
258 twRC
= SANE_PassThrough (pOrigin
, pData
);
263 case DAT_PENDINGXFERS
:
267 twRC
= SANE_PendingXfersEndXfer (pOrigin
, pData
);
270 twRC
= SANE_PendingXfersGet (pOrigin
, pData
);
273 twRC
= SANE_PendingXfersReset (pOrigin
, pData
);
275 /*case MSG_STOPFEEDER:
276 twRC = SANE_PendingXfersStopFeeder (pOrigin, pData);
283 case DAT_SETUPFILEXFER
:
287 twRC
= SANE_SetupFileXferGet (pOrigin
, pData
);
290 twRC
= SANE_SetupFileXferGetDefault (pOrigin
, pData
);
293 twRC
= SANE_SetupFileXferReset (pOrigin
, pData
);
296 twRC
= SANE_SetupFileXferSet (pOrigin
, pData
);
304 /*case DAT_SETUPFILEXFER2:
308 twRC = SANE_SetupFileXfer2Get (pOrigin, pData);
311 twRC = SANE_SetupFileXfer2GetDefault (pOrigin, pData);
314 twRC = SANE_SetupFileXfer2Reset (pOrigin, pData);
317 twRC = SANE_SetupFileXfer2Set (pOrigin, pData);
321 case DAT_SETUPMEMXFER
:
323 twRC
= SANE_SetupMemXferGet (pOrigin
, pData
);
330 twRC
= SANE_GetDSStatus (pOrigin
, pData
);
335 case DAT_USERINTERFACE
:
339 twRC
= SANE_DisableDSUserInterface (pOrigin
, pData
);
342 twRC
= SANE_EnableDSUserInterface (pOrigin
, pData
);
344 case MSG_ENABLEDSUIONLY
:
345 twRC
= SANE_EnableDSUIOnly (pOrigin
, pData
);
357 twRC
= SANE_XferGroupGet (pOrigin
, pData
);
360 twRC
= SANE_XferGroupSet (pOrigin
, pData
);
369 FIXME("code unknown: %d\n", DAT
);
378 TW_UINT16
SANE_ImageGroupHandler (
379 pTW_IDENTITY pOrigin
,
384 TW_UINT16 twRC
= TWRC_SUCCESS
;
390 twRC
= SANE_CIEColorGet (pOrigin
, pData
);
395 case DAT_EXTIMAGEINFO
:
397 twRC
= SANE_ExtImageInfoGet (pOrigin
, pData
);
402 case DAT_GRAYRESPONSE
:
406 twRC
= SANE_GrayResponseReset (pOrigin
, pData
);
409 twRC
= SANE_GrayResponseSet (pOrigin
, pData
);
413 activeDS
.twCC
= TWCC_BADPROTOCOL
;
414 FIXME("unrecognized operation triplet\n");
418 case DAT_IMAGEFILEXFER
:
420 twRC
= SANE_ImageFileXferGet (pOrigin
, pData
);
427 twRC
= SANE_ImageInfoGet (pOrigin
, pData
);
432 case DAT_IMAGELAYOUT
:
436 twRC
= SANE_ImageLayoutGet (pOrigin
, pData
);
439 twRC
= SANE_ImageLayoutGetDefault (pOrigin
, pData
);
442 twRC
= SANE_ImageLayoutReset (pOrigin
, pData
);
445 twRC
= SANE_ImageLayoutSet (pOrigin
, pData
);
449 activeDS
.twCC
= TWCC_BADPROTOCOL
;
450 ERR("unrecognized operation triplet\n");
455 case DAT_IMAGEMEMXFER
:
457 twRC
= SANE_ImageMemXferGet (pOrigin
, pData
);
462 case DAT_IMAGENATIVEXFER
:
464 twRC
= SANE_ImageNativeXferGet (pOrigin
, pData
);
469 case DAT_JPEGCOMPRESSION
:
473 twRC
= SANE_JPEGCompressionGet (pOrigin
, pData
);
476 twRC
= SANE_JPEGCompressionGetDefault (pOrigin
, pData
);
479 twRC
= SANE_JPEGCompressionReset (pOrigin
, pData
);
482 twRC
= SANE_JPEGCompressionSet (pOrigin
, pData
);
486 activeDS
.twCC
= TWCC_BADPROTOCOL
;
487 WARN("unrecognized operation triplet\n");
496 twRC
= SANE_Palette8Get (pOrigin
, pData
);
499 twRC
= SANE_Palette8GetDefault (pOrigin
, pData
);
502 twRC
= SANE_Palette8Reset (pOrigin
, pData
);
505 twRC
= SANE_Palette8Set (pOrigin
, pData
);
509 activeDS
.twCC
= TWCC_BADPROTOCOL
;
510 WARN("unrecognized operation triplet\n");
514 case DAT_RGBRESPONSE
:
518 twRC
= SANE_RGBResponseReset (pOrigin
, pData
);
521 twRC
= SANE_RGBResponseSet (pOrigin
, pData
);
525 activeDS
.twCC
= TWCC_BADPROTOCOL
;
526 WARN("unrecognized operation triplet\n");
533 activeDS
.twCC
= TWCC_BADPROTOCOL
;
534 FIXME("unrecognized DG type %d\n", DAT
);
539 /* Main entry point for the TWAIN library */
541 DS_Entry ( pTW_IDENTITY pOrigin
,
547 TW_UINT16 twRC
= TWRC_SUCCESS
; /* Return Code */
549 TRACE("(DG=%ld DAT=%d MSG=%d)\n", DG
, DAT
, MSG
);
554 twRC
= SANE_SourceControlHandler (pOrigin
,DAT
,MSG
,pData
);
557 twRC
= SANE_ImageGroupHandler (pOrigin
,DAT
,MSG
,pData
);
560 FIXME("Audio group of controls not implemented yet.\n");
562 activeDS
.twCC
= TWCC_BADPROTOCOL
;
570 /* Sane returns device names that are longer than the 32 bytes allowed
571 by TWAIN. However, it colon separates them, and the last bit is
572 the most interesting. So we use the last bit, and add a signature
573 to ensure uniqueness */
574 static void copy_sane_short_name(const char *in
, char *out
, size_t outsize
)
579 if (strlen(in
) <= outsize
- 1)
585 for (p
= in
; *p
; p
++)
588 p
= strrchr(in
, ':');
594 if (strlen(p
) > outsize
- 7 - 1)
595 p
+= strlen(p
) - (outsize
- 7 - 1);
598 sprintf(out
+ strlen(out
), "(%04X)", signature
% 0x10000);
602 static const SANE_Device
**sane_devlist
;
605 detect_sane_devices(void) {
606 if (sane_devlist
&& sane_devlist
[0]) return;
607 TRACE("detecting sane...\n");
608 if (psane_get_devices (&sane_devlist
, SANE_FALSE
) != SANE_STATUS_GOOD
)
613 SANE_GetIdentity( pTW_IDENTITY pOrigin
, pTW_IDENTITY self
) {
614 static int cursanedev
= 0;
616 detect_sane_devices();
617 if (!sane_devlist
[cursanedev
])
619 self
->ProtocolMajor
= TWON_PROTOCOLMAJOR
;
620 self
->ProtocolMinor
= TWON_PROTOCOLMINOR
;
621 copy_sane_short_name(sane_devlist
[cursanedev
]->name
, self
->ProductName
, sizeof(self
->ProductName
) - 1);
622 lstrcpynA (self
->Manufacturer
, sane_devlist
[cursanedev
]->vendor
, sizeof(self
->Manufacturer
) - 1);
623 lstrcpynA (self
->ProductFamily
, sane_devlist
[cursanedev
]->model
, sizeof(self
->ProductFamily
) - 1);
626 if (!sane_devlist
[cursanedev
] ||
627 !sane_devlist
[cursanedev
]->model
||
628 !sane_devlist
[cursanedev
]->vendor
||
629 !sane_devlist
[cursanedev
]->name
631 cursanedev
= 0; /* wrap to begin */
635 static TW_UINT16
SANE_OpenDS( pTW_IDENTITY pOrigin
, pTW_IDENTITY self
) {
639 detect_sane_devices();
640 if (!sane_devlist
[0]) {
641 ERR("No scanners? We should not get to OpenDS?\n");
645 for (i
=0; sane_devlist
[i
] && sane_devlist
[i
]->model
; i
++) {
648 /* To make string as short as above */
649 lstrcpynA(name
, sane_devlist
[i
]->vendor
, sizeof(name
)-1);
650 if (strcmp(name
, self
->Manufacturer
))
652 lstrcpynA(name
, sane_devlist
[i
]->model
, sizeof(name
)-1);
653 if (strcmp(name
, self
->ProductFamily
))
655 copy_sane_short_name(sane_devlist
[i
]->name
, name
, sizeof(name
) - 1);
656 if (strcmp(name
, self
->ProductName
))
660 if (!sane_devlist
[i
]) {
661 FIXME("Scanner not found? Using first one!\n");
664 status
= psane_open(sane_devlist
[i
]->name
,&activeDS
.deviceHandle
);
665 if (status
== SANE_STATUS_GOOD
) {
666 activeDS
.currentState
= 4;
667 activeDS
.twCC
= TWRC_SUCCESS
;
670 FIXME("sane_open(%s): %s\n", sane_devlist
[i
]->name
, psane_strstatus (status
));