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
);
35 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 BOOL WINAPI
DllMain (HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpvReserved
)
84 TRACE("%p,%x,%p\n", hinstDLL
, fdwReason
, lpvReserved
);
88 case DLL_PROCESS_ATTACH
: {
89 SANE_Int version_code
;
91 libsane_handle
= open_libsane();
95 psane_init (&version_code
, NULL
);
96 SANE_instance
= hinstDLL
;
97 DisableThreadLibraryCalls(hinstDLL
);
100 case DLL_PROCESS_DETACH
:
101 if (lpvReserved
) break;
102 TRACE("calling sane_exit()\n");
104 close_libsane(libsane_handle
);
111 static TW_UINT16
SANE_GetIdentity( pTW_IDENTITY
, pTW_IDENTITY
);
112 static TW_UINT16
SANE_OpenDS( pTW_IDENTITY
, pTW_IDENTITY
);
114 #endif /* SONAME_LIBSANE */
116 static TW_UINT16
SANE_SourceControlHandler (
117 pTW_IDENTITY pOrigin
,
122 TW_UINT16 twRC
= TWRC_SUCCESS
;
130 #ifdef SONAME_LIBSANE
131 psane_close (activeDS
.deviceHandle
);
134 activeDS
.twCC
= TWCC_CAPUNSUPPORTED
;
138 #ifdef SONAME_LIBSANE
139 twRC
= SANE_OpenDS( pOrigin
, (pTW_IDENTITY
)pData
);
142 activeDS
.twCC
= TWCC_CAPUNSUPPORTED
;
146 #ifdef SONAME_LIBSANE
147 twRC
= SANE_GetIdentity( pOrigin
, (pTW_IDENTITY
)pData
);
150 activeDS
.twCC
= TWCC_CAPUNSUPPORTED
;
159 twRC
= SANE_CapabilityGet (pOrigin
, pData
);
162 twRC
= SANE_CapabilityGetCurrent (pOrigin
, pData
);
165 twRC
= SANE_CapabilityGetDefault (pOrigin
, pData
);
167 case MSG_QUERYSUPPORT
:
168 twRC
= SANE_CapabilityQuerySupport (pOrigin
, pData
);
171 twRC
= SANE_CapabilityReset (pOrigin
, pData
);
174 twRC
= SANE_CapabilitySet (pOrigin
, pData
);
178 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
179 FIXME("unrecognized opertion triplet\n");
185 if (MSG
== MSG_PROCESSEVENT
)
186 twRC
= SANE_ProcessEvent (pOrigin
, pData
);
189 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
194 case DAT_PENDINGXFERS
:
198 twRC
= SANE_PendingXfersEndXfer (pOrigin
, pData
);
201 twRC
= SANE_PendingXfersGet (pOrigin
, pData
);
204 twRC
= SANE_PendingXfersReset (pOrigin
, pData
);
207 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
212 case DAT_SETUPMEMXFER
:
214 twRC
= SANE_SetupMemXferGet (pOrigin
, pData
);
217 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
224 twRC
= SANE_GetDSStatus (pOrigin
, pData
);
227 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
232 case DAT_USERINTERFACE
:
236 twRC
= SANE_DisableDSUserInterface (pOrigin
, pData
);
239 twRC
= SANE_EnableDSUserInterface (pOrigin
, pData
);
241 case MSG_ENABLEDSUIONLY
:
242 twRC
= SANE_EnableDSUIOnly (pOrigin
, pData
);
245 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
255 twRC
= SANE_XferGroupGet (pOrigin
, pData
);
258 twRC
= SANE_XferGroupSet (pOrigin
, pData
);
261 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
268 WARN("code unsupported: %d\n", DAT
);
269 activeDS
.twCC
= TWCC_CAPUNSUPPORTED
;
278 static TW_UINT16
SANE_ImageGroupHandler (
279 pTW_IDENTITY pOrigin
,
284 TW_UINT16 twRC
= TWRC_SUCCESS
;
290 twRC
= SANE_ImageInfoGet (pOrigin
, pData
);
293 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
298 case DAT_IMAGELAYOUT
:
302 twRC
= SANE_ImageLayoutGet (pOrigin
, pData
);
305 twRC
= SANE_ImageLayoutGetDefault (pOrigin
, pData
);
308 twRC
= SANE_ImageLayoutReset (pOrigin
, pData
);
311 twRC
= SANE_ImageLayoutSet (pOrigin
, pData
);
315 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
316 ERR("unrecognized operation triplet\n");
321 case DAT_IMAGEMEMXFER
:
323 twRC
= SANE_ImageMemXferGet (pOrigin
, pData
);
326 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
331 case DAT_IMAGENATIVEXFER
:
333 twRC
= SANE_ImageNativeXferGet (pOrigin
, pData
);
336 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
343 activeDS
.twCC
= TWCC_CAPUNSUPPORTED
;
344 WARN("unsupported DG type %d\n", DAT
);
350 /* Main entry point for the TWAIN library */
352 DS_Entry ( pTW_IDENTITY pOrigin
,
358 TW_UINT16 twRC
= TWRC_SUCCESS
; /* Return Code */
360 TRACE("(DG=%d DAT=%d MSG=%d)\n", DG
, DAT
, MSG
);
365 twRC
= SANE_SourceControlHandler (pOrigin
,DAT
,MSG
,pData
);
368 twRC
= SANE_ImageGroupHandler (pOrigin
,DAT
,MSG
,pData
);
371 WARN("Audio group of controls not implemented yet.\n");
373 activeDS
.twCC
= TWCC_CAPUNSUPPORTED
;
376 activeDS
.twCC
= TWCC_BADPROTOCOL
;
383 #ifdef SONAME_LIBSANE
384 /* Sane returns device names that are longer than the 32 bytes allowed
385 by TWAIN. However, it colon separates them, and the last bit is
386 the most interesting. So we use the last bit, and add a signature
387 to ensure uniqueness */
388 static void copy_sane_short_name(const char *in
, char *out
, size_t outsize
)
393 if (strlen(in
) <= outsize
- 1)
399 for (p
= in
; *p
; p
++)
402 p
= strrchr(in
, ':');
408 if (strlen(p
) > outsize
- 7 - 1)
409 p
+= strlen(p
) - (outsize
- 7 - 1);
412 sprintf(out
+ strlen(out
), "(%04X)", signature
% 0x10000);
416 static const SANE_Device
**sane_devlist
;
419 detect_sane_devices(void) {
420 if (sane_devlist
&& sane_devlist
[0]) return;
421 TRACE("detecting sane...\n");
422 if (psane_get_devices (&sane_devlist
, SANE_FALSE
) != SANE_STATUS_GOOD
)
427 SANE_GetIdentity( pTW_IDENTITY pOrigin
, pTW_IDENTITY self
) {
428 static int cursanedev
= 0;
430 detect_sane_devices();
431 if (!sane_devlist
[cursanedev
])
433 self
->ProtocolMajor
= TWON_PROTOCOLMAJOR
;
434 self
->ProtocolMinor
= TWON_PROTOCOLMINOR
;
435 self
->SupportedGroups
= DG_CONTROL
| DG_IMAGE
;
436 copy_sane_short_name(sane_devlist
[cursanedev
]->name
, self
->ProductName
, sizeof(self
->ProductName
) - 1);
437 lstrcpynA (self
->Manufacturer
, sane_devlist
[cursanedev
]->vendor
, sizeof(self
->Manufacturer
) - 1);
438 lstrcpynA (self
->ProductFamily
, sane_devlist
[cursanedev
]->model
, sizeof(self
->ProductFamily
) - 1);
441 if (!sane_devlist
[cursanedev
] ||
442 !sane_devlist
[cursanedev
]->model
||
443 !sane_devlist
[cursanedev
]->vendor
||
444 !sane_devlist
[cursanedev
]->name
446 cursanedev
= 0; /* wrap to begin */
450 static TW_UINT16
SANE_OpenDS( pTW_IDENTITY pOrigin
, pTW_IDENTITY self
) {
454 detect_sane_devices();
455 if (!sane_devlist
[0]) {
456 ERR("No scanners? We should not get to OpenDS?\n");
460 for (i
=0; sane_devlist
[i
] && sane_devlist
[i
]->model
; i
++) {
463 /* To make string as short as above */
464 lstrcpynA(name
, sane_devlist
[i
]->vendor
, sizeof(name
)-1);
465 if (*self
->Manufacturer
&& strcmp(name
, self
->Manufacturer
))
467 lstrcpynA(name
, sane_devlist
[i
]->model
, sizeof(name
)-1);
468 if (*self
->ProductFamily
&& strcmp(name
, self
->ProductFamily
))
470 copy_sane_short_name(sane_devlist
[i
]->name
, name
, sizeof(name
) - 1);
471 if (*self
->ProductName
&& strcmp(name
, self
->ProductName
))
475 if (!sane_devlist
[i
]) {
476 WARN("Scanner not found.\n");
479 status
= psane_open(sane_devlist
[i
]->name
,&activeDS
.deviceHandle
);
480 if (status
== SANE_STATUS_GOOD
) {
481 activeDS
.twCC
= SANE_SaneSetDefaults();
482 if (activeDS
.twCC
== TWCC_SUCCESS
) {
483 activeDS
.currentState
= 4;
487 psane_close(activeDS
.deviceHandle
);
490 ERR("sane_open(%s): %s\n", sane_devlist
[i
]->name
, psane_strstatus (status
));