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
);
33 DSMENTRYPROC SANE_dsmentry
;
37 HINSTANCE SANE_instance
;
39 static void *libsane_handle
;
41 static void close_libsane(void *h
)
44 wine_dlclose(h
, NULL
, 0);
47 static void *open_libsane(void)
51 h
= wine_dlopen(SONAME_LIBSANE
, RTLD_GLOBAL
| RTLD_NOW
, NULL
, 0);
54 WARN("dlopen(%s) failed\n", SONAME_LIBSANE
);
58 #define LOAD_FUNCPTR(f) \
59 if((p##f = wine_dlsym(h, #f, NULL, 0)) == NULL) { \
61 ERR("Could not dlsym %s\n", #f); \
65 LOAD_FUNCPTR(sane_init
)
66 LOAD_FUNCPTR(sane_exit
)
67 LOAD_FUNCPTR(sane_get_devices
)
68 LOAD_FUNCPTR(sane_open
)
69 LOAD_FUNCPTR(sane_close
)
70 LOAD_FUNCPTR(sane_get_option_descriptor
)
71 LOAD_FUNCPTR(sane_control_option
)
72 LOAD_FUNCPTR(sane_get_parameters
)
73 LOAD_FUNCPTR(sane_start
)
74 LOAD_FUNCPTR(sane_read
)
75 LOAD_FUNCPTR(sane_cancel
)
76 LOAD_FUNCPTR(sane_set_io_mode
)
77 LOAD_FUNCPTR(sane_get_select_fd
)
78 LOAD_FUNCPTR(sane_strstatus
)
84 BOOL WINAPI
DllMain (HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpvReserved
)
86 TRACE("%p,%x,%p\n", hinstDLL
, fdwReason
, lpvReserved
);
90 case DLL_PROCESS_ATTACH
: {
91 SANE_Int version_code
;
93 libsane_handle
= open_libsane();
97 psane_init (&version_code
, NULL
);
98 SANE_instance
= hinstDLL
;
99 DisableThreadLibraryCalls(hinstDLL
);
102 case DLL_PROCESS_DETACH
:
103 if (lpvReserved
) break;
104 TRACE("calling sane_exit()\n");
106 close_libsane(libsane_handle
);
113 static TW_UINT16
SANE_GetIdentity( pTW_IDENTITY
, pTW_IDENTITY
);
114 static TW_UINT16
SANE_OpenDS( pTW_IDENTITY
, pTW_IDENTITY
);
116 #endif /* SONAME_LIBSANE */
118 static TW_UINT16
SANE_SetEntryPoint (pTW_IDENTITY pOrigin
, TW_MEMREF pData
);
120 static TW_UINT16
SANE_SourceControlHandler (
121 pTW_IDENTITY pOrigin
,
126 TW_UINT16 twRC
= TWRC_SUCCESS
;
134 #ifdef SONAME_LIBSANE
135 psane_close (activeDS
.deviceHandle
);
138 activeDS
.twCC
= TWCC_CAPUNSUPPORTED
;
142 #ifdef SONAME_LIBSANE
143 twRC
= SANE_OpenDS( pOrigin
, (pTW_IDENTITY
)pData
);
146 activeDS
.twCC
= TWCC_CAPUNSUPPORTED
;
150 #ifdef SONAME_LIBSANE
151 twRC
= SANE_GetIdentity( pOrigin
, (pTW_IDENTITY
)pData
);
154 activeDS
.twCC
= TWCC_CAPUNSUPPORTED
;
163 twRC
= SANE_CapabilityGet (pOrigin
, pData
);
166 twRC
= SANE_CapabilityGetCurrent (pOrigin
, pData
);
169 twRC
= SANE_CapabilityGetDefault (pOrigin
, pData
);
171 case MSG_QUERYSUPPORT
:
172 twRC
= SANE_CapabilityQuerySupport (pOrigin
, pData
);
175 twRC
= SANE_CapabilityReset (pOrigin
, pData
);
178 twRC
= SANE_CapabilitySet (pOrigin
, pData
);
182 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
183 FIXME("unrecognized operation triplet\n");
190 twRC
= SANE_SetEntryPoint (pOrigin
, pData
);
194 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
195 FIXME("unrecognized operation triplet\n");
200 if (MSG
== MSG_PROCESSEVENT
)
201 twRC
= SANE_ProcessEvent (pOrigin
, pData
);
204 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
209 case DAT_PENDINGXFERS
:
213 twRC
= SANE_PendingXfersEndXfer (pOrigin
, pData
);
216 twRC
= SANE_PendingXfersGet (pOrigin
, pData
);
219 twRC
= SANE_PendingXfersReset (pOrigin
, pData
);
222 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
227 case DAT_SETUPMEMXFER
:
229 twRC
= SANE_SetupMemXferGet (pOrigin
, pData
);
232 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
239 twRC
= SANE_GetDSStatus (pOrigin
, pData
);
242 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
247 case DAT_USERINTERFACE
:
251 twRC
= SANE_DisableDSUserInterface (pOrigin
, pData
);
254 twRC
= SANE_EnableDSUserInterface (pOrigin
, pData
);
256 case MSG_ENABLEDSUIONLY
:
257 twRC
= SANE_EnableDSUIOnly (pOrigin
, pData
);
260 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
270 twRC
= SANE_XferGroupGet (pOrigin
, pData
);
273 twRC
= SANE_XferGroupSet (pOrigin
, pData
);
276 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
283 WARN("code unsupported: %d\n", DAT
);
284 activeDS
.twCC
= TWCC_CAPUNSUPPORTED
;
293 static TW_UINT16
SANE_ImageGroupHandler (
294 pTW_IDENTITY pOrigin
,
299 TW_UINT16 twRC
= TWRC_SUCCESS
;
305 twRC
= SANE_ImageInfoGet (pOrigin
, pData
);
308 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
313 case DAT_IMAGELAYOUT
:
317 twRC
= SANE_ImageLayoutGet (pOrigin
, pData
);
320 twRC
= SANE_ImageLayoutGetDefault (pOrigin
, pData
);
323 twRC
= SANE_ImageLayoutReset (pOrigin
, pData
);
326 twRC
= SANE_ImageLayoutSet (pOrigin
, pData
);
330 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
331 ERR("unrecognized operation triplet\n");
336 case DAT_IMAGEMEMXFER
:
338 twRC
= SANE_ImageMemXferGet (pOrigin
, pData
);
341 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
346 case DAT_IMAGENATIVEXFER
:
348 twRC
= SANE_ImageNativeXferGet (pOrigin
, pData
);
351 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
358 activeDS
.twCC
= TWCC_CAPUNSUPPORTED
;
359 WARN("unsupported DG type %d\n", DAT
);
365 /* Main entry point for the TWAIN library */
367 DS_Entry ( pTW_IDENTITY pOrigin
,
373 TW_UINT16 twRC
= TWRC_SUCCESS
; /* Return Code */
375 TRACE("(DG=%d DAT=%d MSG=%d)\n", DG
, DAT
, MSG
);
380 twRC
= SANE_SourceControlHandler (pOrigin
,DAT
,MSG
,pData
);
383 twRC
= SANE_ImageGroupHandler (pOrigin
,DAT
,MSG
,pData
);
386 WARN("Audio group of controls not implemented yet.\n");
388 activeDS
.twCC
= TWCC_CAPUNSUPPORTED
;
391 activeDS
.twCC
= TWCC_BADPROTOCOL
;
398 void SANE_Notify (TW_UINT16 message
)
400 SANE_dsmentry (&activeDS
.identity
, &activeDS
.appIdentity
, DG_CONTROL
, DAT_NULL
, message
, NULL
);
403 /* DG_CONTROL/DAT_ENTRYPOINT/MSG_SET */
404 TW_UINT16
SANE_SetEntryPoint (pTW_IDENTITY pOrigin
, TW_MEMREF pData
)
406 TW_ENTRYPOINT
*entry
= (TW_ENTRYPOINT
*)pData
;
408 SANE_dsmentry
= entry
->DSM_Entry
;
413 #ifdef SONAME_LIBSANE
414 /* Sane returns device names that are longer than the 32 bytes allowed
415 by TWAIN. However, it colon separates them, and the last bit is
416 the most interesting. So we use the last bit, and add a signature
417 to ensure uniqueness */
418 static void copy_sane_short_name(const char *in
, char *out
, size_t outsize
)
423 if (strlen(in
) <= outsize
- 1)
429 for (p
= in
; *p
; p
++)
432 p
= strrchr(in
, ':');
438 if (strlen(p
) > outsize
- 7 - 1)
439 p
+= strlen(p
) - (outsize
- 7 - 1);
442 sprintf(out
+ strlen(out
), "(%04X)", signature
% 0x10000);
446 static const SANE_Device
**sane_devlist
;
449 detect_sane_devices(void) {
450 if (sane_devlist
&& sane_devlist
[0]) return;
451 TRACE("detecting sane...\n");
452 if (psane_get_devices (&sane_devlist
, SANE_FALSE
) != SANE_STATUS_GOOD
)
457 SANE_GetIdentity( pTW_IDENTITY pOrigin
, pTW_IDENTITY self
) {
458 static int cursanedev
= 0;
460 detect_sane_devices();
461 if (!sane_devlist
[cursanedev
])
463 self
->ProtocolMajor
= TWON_PROTOCOLMAJOR
;
464 self
->ProtocolMinor
= TWON_PROTOCOLMINOR
;
465 self
->SupportedGroups
= DG_CONTROL
| DG_IMAGE
| DF_DS2
;
466 copy_sane_short_name(sane_devlist
[cursanedev
]->name
, self
->ProductName
, sizeof(self
->ProductName
) - 1);
467 lstrcpynA (self
->Manufacturer
, sane_devlist
[cursanedev
]->vendor
, sizeof(self
->Manufacturer
) - 1);
468 lstrcpynA (self
->ProductFamily
, sane_devlist
[cursanedev
]->model
, sizeof(self
->ProductFamily
) - 1);
471 if (!sane_devlist
[cursanedev
] ||
472 !sane_devlist
[cursanedev
]->model
||
473 !sane_devlist
[cursanedev
]->vendor
||
474 !sane_devlist
[cursanedev
]->name
476 cursanedev
= 0; /* wrap to begin */
480 static TW_UINT16
SANE_OpenDS( pTW_IDENTITY pOrigin
, pTW_IDENTITY self
) {
484 if (SANE_dsmentry
== NULL
)
486 static const WCHAR twain32W
[] = {'t','w','a','i','n','_','3','2',0};
487 HMODULE moddsm
= GetModuleHandleW(twain32W
);
490 SANE_dsmentry
= (void*)GetProcAddress(moddsm
, "DSM_Entry");
494 ERR("can't find DSM entry point\n");
499 detect_sane_devices();
500 if (!sane_devlist
[0]) {
501 ERR("No scanners? We should not get to OpenDS?\n");
505 for (i
=0; sane_devlist
[i
] && sane_devlist
[i
]->model
; i
++) {
508 /* To make string as short as above */
509 lstrcpynA(name
, sane_devlist
[i
]->vendor
, sizeof(name
)-1);
510 if (*self
->Manufacturer
&& strcmp(name
, self
->Manufacturer
))
512 lstrcpynA(name
, sane_devlist
[i
]->model
, sizeof(name
)-1);
513 if (*self
->ProductFamily
&& strcmp(name
, self
->ProductFamily
))
515 copy_sane_short_name(sane_devlist
[i
]->name
, name
, sizeof(name
) - 1);
516 if (*self
->ProductName
&& strcmp(name
, self
->ProductName
))
520 if (!sane_devlist
[i
]) {
521 WARN("Scanner not found.\n");
524 status
= psane_open(sane_devlist
[i
]->name
,&activeDS
.deviceHandle
);
525 if (status
== SANE_STATUS_GOOD
) {
526 activeDS
.twCC
= SANE_SaneSetDefaults();
527 if (activeDS
.twCC
== TWCC_SUCCESS
) {
528 activeDS
.currentState
= 4;
529 activeDS
.identity
.Id
= self
->Id
;
530 activeDS
.appIdentity
= *pOrigin
;
534 psane_close(activeDS
.deviceHandle
);
537 ERR("sane_open(%s): %s\n", sane_devlist
[i
]->name
, psane_strstatus (status
));