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"
30 WINE_DEFAULT_DEBUG_CHANNEL(twain
);
32 struct tagActiveDS activeDS
;
34 DSMENTRYPROC SANE_dsmentry
;
37 #define MAKE_FUNCPTR(f) typeof(f) * p##f;
38 MAKE_FUNCPTR(sane_init
)
39 MAKE_FUNCPTR(sane_exit
)
40 MAKE_FUNCPTR(sane_get_devices
)
41 MAKE_FUNCPTR(sane_open
)
42 MAKE_FUNCPTR(sane_close
)
43 MAKE_FUNCPTR(sane_get_option_descriptor
)
44 MAKE_FUNCPTR(sane_control_option
)
45 MAKE_FUNCPTR(sane_get_parameters
)
46 MAKE_FUNCPTR(sane_start
)
47 MAKE_FUNCPTR(sane_read
)
48 MAKE_FUNCPTR(sane_cancel
)
49 MAKE_FUNCPTR(sane_set_io_mode
)
50 MAKE_FUNCPTR(sane_get_select_fd
)
51 MAKE_FUNCPTR(sane_strstatus
)
54 HINSTANCE SANE_instance
;
56 static void *libsane_handle
;
58 static void close_libsane(void *h
)
64 static void *open_libsane(void)
68 h
= dlopen(SONAME_LIBSANE
, RTLD_GLOBAL
| RTLD_NOW
);
71 WARN("failed to load %s; %s\n", SONAME_LIBSANE
, dlerror());
75 #define LOAD_FUNCPTR(f) \
76 if((p##f = dlsym(h, #f)) == NULL) { \
78 ERR("Could not dlsym %s\n", #f); \
82 LOAD_FUNCPTR(sane_init
)
83 LOAD_FUNCPTR(sane_exit
)
84 LOAD_FUNCPTR(sane_get_devices
)
85 LOAD_FUNCPTR(sane_open
)
86 LOAD_FUNCPTR(sane_close
)
87 LOAD_FUNCPTR(sane_get_option_descriptor
)
88 LOAD_FUNCPTR(sane_control_option
)
89 LOAD_FUNCPTR(sane_get_parameters
)
90 LOAD_FUNCPTR(sane_start
)
91 LOAD_FUNCPTR(sane_read
)
92 LOAD_FUNCPTR(sane_cancel
)
93 LOAD_FUNCPTR(sane_set_io_mode
)
94 LOAD_FUNCPTR(sane_get_select_fd
)
95 LOAD_FUNCPTR(sane_strstatus
)
101 BOOL WINAPI
DllMain (HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpvReserved
)
103 TRACE("%p,%x,%p\n", hinstDLL
, fdwReason
, lpvReserved
);
107 case DLL_PROCESS_ATTACH
: {
108 SANE_Int version_code
;
110 libsane_handle
= open_libsane();
111 if (! libsane_handle
)
114 psane_init (&version_code
, NULL
);
115 SANE_instance
= hinstDLL
;
116 DisableThreadLibraryCalls(hinstDLL
);
119 case DLL_PROCESS_DETACH
:
120 if (lpvReserved
) break;
121 TRACE("calling sane_exit()\n");
123 close_libsane(libsane_handle
);
130 static TW_UINT16
SANE_GetIdentity( pTW_IDENTITY
, pTW_IDENTITY
);
131 static TW_UINT16
SANE_OpenDS( pTW_IDENTITY
, pTW_IDENTITY
);
133 #endif /* SONAME_LIBSANE */
135 static TW_UINT16
SANE_SetEntryPoint (pTW_IDENTITY pOrigin
, TW_MEMREF pData
);
137 static TW_UINT16
SANE_SourceControlHandler (
138 pTW_IDENTITY pOrigin
,
143 TW_UINT16 twRC
= TWRC_SUCCESS
;
151 #ifdef SONAME_LIBSANE
152 psane_close (activeDS
.deviceHandle
);
155 activeDS
.twCC
= TWCC_CAPUNSUPPORTED
;
159 #ifdef SONAME_LIBSANE
160 twRC
= SANE_OpenDS( pOrigin
, (pTW_IDENTITY
)pData
);
163 activeDS
.twCC
= TWCC_CAPUNSUPPORTED
;
167 #ifdef SONAME_LIBSANE
168 twRC
= SANE_GetIdentity( pOrigin
, (pTW_IDENTITY
)pData
);
171 activeDS
.twCC
= TWCC_CAPUNSUPPORTED
;
180 twRC
= SANE_CapabilityGet (pOrigin
, pData
);
183 twRC
= SANE_CapabilityGetCurrent (pOrigin
, pData
);
186 twRC
= SANE_CapabilityGetDefault (pOrigin
, pData
);
188 case MSG_QUERYSUPPORT
:
189 twRC
= SANE_CapabilityQuerySupport (pOrigin
, pData
);
192 twRC
= SANE_CapabilityReset (pOrigin
, pData
);
195 twRC
= SANE_CapabilitySet (pOrigin
, pData
);
199 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
200 FIXME("unrecognized operation triplet\n");
207 twRC
= SANE_SetEntryPoint (pOrigin
, pData
);
211 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
212 FIXME("unrecognized operation triplet\n");
217 if (MSG
== MSG_PROCESSEVENT
)
218 twRC
= SANE_ProcessEvent (pOrigin
, pData
);
221 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
226 case DAT_PENDINGXFERS
:
230 twRC
= SANE_PendingXfersEndXfer (pOrigin
, pData
);
233 twRC
= SANE_PendingXfersGet (pOrigin
, pData
);
236 twRC
= SANE_PendingXfersReset (pOrigin
, pData
);
239 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
244 case DAT_SETUPMEMXFER
:
246 twRC
= SANE_SetupMemXferGet (pOrigin
, pData
);
249 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
256 twRC
= SANE_GetDSStatus (pOrigin
, pData
);
259 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
264 case DAT_USERINTERFACE
:
268 twRC
= SANE_DisableDSUserInterface (pOrigin
, pData
);
271 twRC
= SANE_EnableDSUserInterface (pOrigin
, pData
);
273 case MSG_ENABLEDSUIONLY
:
274 twRC
= SANE_EnableDSUIOnly (pOrigin
, pData
);
277 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
287 twRC
= SANE_XferGroupGet (pOrigin
, pData
);
290 twRC
= SANE_XferGroupSet (pOrigin
, pData
);
293 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
300 WARN("code unsupported: %d\n", DAT
);
301 activeDS
.twCC
= TWCC_CAPUNSUPPORTED
;
310 static TW_UINT16
SANE_ImageGroupHandler (
311 pTW_IDENTITY pOrigin
,
316 TW_UINT16 twRC
= TWRC_SUCCESS
;
322 twRC
= SANE_ImageInfoGet (pOrigin
, pData
);
325 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
330 case DAT_IMAGELAYOUT
:
334 twRC
= SANE_ImageLayoutGet (pOrigin
, pData
);
337 twRC
= SANE_ImageLayoutGetDefault (pOrigin
, pData
);
340 twRC
= SANE_ImageLayoutReset (pOrigin
, pData
);
343 twRC
= SANE_ImageLayoutSet (pOrigin
, pData
);
347 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
348 ERR("unrecognized operation triplet\n");
353 case DAT_IMAGEMEMXFER
:
355 twRC
= SANE_ImageMemXferGet (pOrigin
, pData
);
358 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
363 case DAT_IMAGENATIVEXFER
:
365 twRC
= SANE_ImageNativeXferGet (pOrigin
, pData
);
368 activeDS
.twCC
= TWCC_CAPBADOPERATION
;
375 activeDS
.twCC
= TWCC_CAPUNSUPPORTED
;
376 WARN("unsupported DG type %d\n", DAT
);
382 /* Main entry point for the TWAIN library */
384 DS_Entry ( pTW_IDENTITY pOrigin
,
390 TW_UINT16 twRC
= TWRC_SUCCESS
; /* Return Code */
392 TRACE("(DG=%d DAT=%d MSG=%d)\n", DG
, DAT
, MSG
);
397 twRC
= SANE_SourceControlHandler (pOrigin
,DAT
,MSG
,pData
);
400 twRC
= SANE_ImageGroupHandler (pOrigin
,DAT
,MSG
,pData
);
403 WARN("Audio group of controls not implemented yet.\n");
405 activeDS
.twCC
= TWCC_CAPUNSUPPORTED
;
408 activeDS
.twCC
= TWCC_BADPROTOCOL
;
415 void SANE_Notify (TW_UINT16 message
)
417 SANE_dsmentry (&activeDS
.identity
, &activeDS
.appIdentity
, DG_CONTROL
, DAT_NULL
, message
, NULL
);
420 /* DG_CONTROL/DAT_ENTRYPOINT/MSG_SET */
421 TW_UINT16
SANE_SetEntryPoint (pTW_IDENTITY pOrigin
, TW_MEMREF pData
)
423 TW_ENTRYPOINT
*entry
= (TW_ENTRYPOINT
*)pData
;
425 SANE_dsmentry
= entry
->DSM_Entry
;
430 #ifdef SONAME_LIBSANE
431 /* Sane returns device names that are longer than the 32 bytes allowed
432 by TWAIN. However, it colon separates them, and the last bit is
433 the most interesting. So we use the last bit, and add a signature
434 to ensure uniqueness */
435 static void copy_sane_short_name(const char *in
, char *out
, size_t outsize
)
440 if (strlen(in
) <= outsize
- 1)
446 for (p
= in
; *p
; p
++)
449 p
= strrchr(in
, ':');
455 if (strlen(p
) > outsize
- 7 - 1)
456 p
+= strlen(p
) - (outsize
- 7 - 1);
459 sprintf(out
+ strlen(out
), "(%04X)", signature
% 0x10000);
463 static const SANE_Device
**sane_devlist
;
466 detect_sane_devices(void) {
467 if (sane_devlist
&& sane_devlist
[0]) return;
468 TRACE("detecting sane...\n");
469 if (psane_get_devices (&sane_devlist
, SANE_FALSE
) != SANE_STATUS_GOOD
)
474 SANE_GetIdentity( pTW_IDENTITY pOrigin
, pTW_IDENTITY self
) {
475 static int cursanedev
= 0;
477 detect_sane_devices();
478 if (!sane_devlist
[cursanedev
])
480 self
->ProtocolMajor
= TWON_PROTOCOLMAJOR
;
481 self
->ProtocolMinor
= TWON_PROTOCOLMINOR
;
482 self
->SupportedGroups
= DG_CONTROL
| DG_IMAGE
| DF_DS2
;
483 copy_sane_short_name(sane_devlist
[cursanedev
]->name
, self
->ProductName
, sizeof(self
->ProductName
) - 1);
484 lstrcpynA (self
->Manufacturer
, sane_devlist
[cursanedev
]->vendor
, sizeof(self
->Manufacturer
) - 1);
485 lstrcpynA (self
->ProductFamily
, sane_devlist
[cursanedev
]->model
, sizeof(self
->ProductFamily
) - 1);
488 if (!sane_devlist
[cursanedev
] ||
489 !sane_devlist
[cursanedev
]->model
||
490 !sane_devlist
[cursanedev
]->vendor
||
491 !sane_devlist
[cursanedev
]->name
493 cursanedev
= 0; /* wrap to begin */
497 static TW_UINT16
SANE_OpenDS( pTW_IDENTITY pOrigin
, pTW_IDENTITY self
) {
501 if (SANE_dsmentry
== NULL
)
503 static const WCHAR twain32W
[] = {'t','w','a','i','n','_','3','2',0};
504 HMODULE moddsm
= GetModuleHandleW(twain32W
);
507 SANE_dsmentry
= (void*)GetProcAddress(moddsm
, "DSM_Entry");
511 ERR("can't find DSM entry point\n");
516 detect_sane_devices();
517 if (!sane_devlist
[0]) {
518 ERR("No scanners? We should not get to OpenDS?\n");
522 for (i
=0; sane_devlist
[i
] && sane_devlist
[i
]->model
; i
++) {
525 /* To make string as short as above */
526 lstrcpynA(name
, sane_devlist
[i
]->vendor
, sizeof(name
)-1);
527 if (*self
->Manufacturer
&& strcmp(name
, self
->Manufacturer
))
529 lstrcpynA(name
, sane_devlist
[i
]->model
, sizeof(name
)-1);
530 if (*self
->ProductFamily
&& strcmp(name
, self
->ProductFamily
))
532 copy_sane_short_name(sane_devlist
[i
]->name
, name
, sizeof(name
) - 1);
533 if (*self
->ProductName
&& strcmp(name
, self
->ProductName
))
537 if (!sane_devlist
[i
]) {
538 WARN("Scanner not found.\n");
541 status
= psane_open(sane_devlist
[i
]->name
,&activeDS
.deviceHandle
);
542 if (status
== SANE_STATUS_GOOD
) {
543 activeDS
.twCC
= SANE_SaneSetDefaults();
544 if (activeDS
.twCC
== TWCC_SUCCESS
) {
545 activeDS
.currentState
= 4;
546 activeDS
.identity
.Id
= self
->Id
;
547 activeDS
.appIdentity
= *pOrigin
;
551 psane_close(activeDS
.deviceHandle
);
554 ERR("sane_open(%s): %s\n", sane_devlist
[i
]->name
, psane_strstatus (status
));