1 /*
2 * SANE.DS functions
3 *
4 * Copyright 2000 Shi Quan He <shiquan@cyberdude.com>
5 *
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.
10 *
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.
15 *
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
19 */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <stdarg.h>
25 #include <stdio.h>
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "twain.h"
30 #include "sane_i.h"
31 #include "wine/debug.h"
32 #include "wine/library.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(twain);
35
36 HINSTANCE SANE_instance;
37
38 #ifdef SONAME_LIBSANE
39
40 static void *libsane_handle;
41
42 static void close_libsane(void *h)
43 {
44 if (h)
45 wine_dlclose(h, NULL, 0);
46 }
47
48 static void *open_libsane(void)
49 {
50 void *h;
51
52 h = wine_dlopen(SONAME_LIBSANE, RTLD_GLOBAL | RTLD_NOW, NULL, 0);
53 if (!h)
54 {
55 WARN("dlopen(%s) failed\n", SONAME_LIBSANE);
56 return NULL;
57 }
58
59 #define LOAD_FUNCPTR(f) \
60 if((p##f = wine_dlsym(h, #f, NULL, 0)) == NULL) { \
61 close_libsane(h); \
62 ERR("Could not dlsym %s\n", #f); \
63 return NULL; \
64 }
65
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)
80 #undef LOAD_FUNCPTR
81
82 return h;
83 }
84
85 #endif /* SONAME_LIBSANE */
86
87 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
88 {
89 TRACE("%p,%x,%p\n", hinstDLL, fdwReason, lpvReserved);
90
91 switch (fdwReason)
92 {
93 case DLL_PROCESS_ATTACH: {
94 #ifdef SONAME_LIBSANE
95 SANE_Status status;
96 SANE_Int version_code;
97
98 libsane_handle = open_libsane();
99 if (! libsane_handle)
100 return FALSE;
101
102 status = psane_init (&version_code, NULL);
103 #endif
104 SANE_instance = hinstDLL;
105 DisableThreadLibraryCalls(hinstDLL);
106 break;
107 }
108 case DLL_PROCESS_DETACH:
109 #ifdef SONAME_LIBSANE
110 TRACE("calling sane_exit()\n");
111 psane_exit ();
112
113 close_libsane(libsane_handle);
114 libsane_handle = NULL;
115 #endif
116 SANE_instance = NULL;
117 break;
118 }
119
120 return TRUE;
121 }
122
123 #ifdef SONAME_LIBSANE
124 static TW_UINT16 SANE_GetIdentity( pTW_IDENTITY, pTW_IDENTITY);
125 static TW_UINT16 SANE_OpenDS( pTW_IDENTITY, pTW_IDENTITY);
126 #endif
127
128 static TW_UINT16 SANE_SourceControlHandler (
129 pTW_IDENTITY pOrigin,
130 TW_UINT16 DAT,
131 TW_UINT16 MSG,
132 TW_MEMREF pData)
133 {
134 TW_UINT16 twRC = TWRC_SUCCESS;
135
136 switch (DAT)
137 {
138 case DAT_IDENTITY:
139 switch (MSG)
140 {
141 case MSG_CLOSEDS:
142 #ifdef SONAME_LIBSANE
143 psane_close (activeDS.deviceHandle);
144 #else
145 twRC = TWRC_FAILURE;
146 activeDS.twCC = TWCC_CAPUNSUPPORTED;
147 #endif
148 break;
149 case MSG_OPENDS:
150 #ifdef SONAME_LIBSANE
151 twRC = SANE_OpenDS( pOrigin, (pTW_IDENTITY)pData);
152 #else
153 twRC = TWRC_FAILURE;
154 activeDS.twCC = TWCC_CAPUNSUPPORTED;
155 #endif
156 break;
157 case MSG_GET:
158 #ifdef SONAME_LIBSANE
159 twRC = SANE_GetIdentity( pOrigin, (pTW_IDENTITY)pData);
160 #else
161 twRC = TWRC_FAILURE;
162 activeDS.twCC = TWCC_CAPUNSUPPORTED;
163 #endif
164 break;
165 }
166 break;
167 case DAT_CAPABILITY:
168 switch (MSG)
169 {
170 case MSG_GET:
171 twRC = SANE_CapabilityGet (pOrigin, pData);
172 break;
173 case MSG_GETCURRENT:
174 twRC = SANE_CapabilityGetCurrent (pOrigin, pData);
175 break;
176 case MSG_GETDEFAULT:
177 twRC = SANE_CapabilityGetDefault (pOrigin, pData);
178 break;
179 case MSG_QUERYSUPPORT:
180 twRC = SANE_CapabilityQuerySupport (pOrigin, pData);
181 break;
182 case MSG_RESET:
183 twRC = SANE_CapabilityReset (pOrigin, pData);
184 break;
185 case MSG_SET:
186 twRC = SANE_CapabilitySet (pOrigin, pData);
187 break;
188 default:
189 twRC = TWRC_FAILURE;
190 activeDS.twCC = TWCC_CAPBADOPERATION;
191 FIXME("unrecognized opertion triplet\n");
192 break;
193 }
194 break;
195
196 case DAT_EVENT:
197 if (MSG == MSG_PROCESSEVENT)
198 twRC = SANE_ProcessEvent (pOrigin, pData);
199 else
200 {
201 activeDS.twCC = TWCC_CAPBADOPERATION;
202 twRC = TWRC_FAILURE;
203 }
204 break;
205
206 case DAT_PENDINGXFERS:
207 switch (MSG)
208 {
209 case MSG_ENDXFER:
210 twRC = SANE_PendingXfersEndXfer (pOrigin, pData);
211 break;
212 case MSG_GET:
213 twRC = SANE_PendingXfersGet (pOrigin, pData);
214 break;
215 case MSG_RESET:
216 twRC = SANE_PendingXfersReset (pOrigin, pData);
217 break;
218 default:
219 activeDS.twCC = TWCC_CAPBADOPERATION;
220 twRC = TWRC_FAILURE;
221 }
222 break;
223
224 case DAT_SETUPMEMXFER:
225 if (MSG == MSG_GET)
226 twRC = SANE_SetupMemXferGet (pOrigin, pData);
227 else
228 {
229 activeDS.twCC = TWCC_CAPBADOPERATION;
230 twRC = TWRC_FAILURE;
231 }
232 break;
233
234 case DAT_STATUS:
235 if (MSG == MSG_GET)
236 twRC = SANE_GetDSStatus (pOrigin, pData);
237 else
238 {
239 activeDS.twCC = TWCC_CAPBADOPERATION;
240 twRC = TWRC_FAILURE;
241 }
242 break;
243
244 case DAT_USERINTERFACE:
245 switch (MSG)
246 {
247 case MSG_DISABLEDS:
248 twRC = SANE_DisableDSUserInterface (pOrigin, pData);
249 break;
250 case MSG_ENABLEDS:
251 twRC = SANE_EnableDSUserInterface (pOrigin, pData);
252 break;
253 case MSG_ENABLEDSUIONLY:
254 twRC = SANE_EnableDSUIOnly (pOrigin, pData);
255 break;
256 default:
257 activeDS.twCC = TWCC_CAPBADOPERATION;
258 twRC = TWRC_FAILURE;
259 break;
260 }
261 break;
262
263 case DAT_XFERGROUP:
264 switch (MSG)
265 {
266 case MSG_GET:
267 twRC = SANE_XferGroupGet (pOrigin, pData);
268 break;
269 case MSG_SET:
270 twRC = SANE_XferGroupSet (pOrigin, pData);
271 break;
272 default:
273 activeDS.twCC = TWCC_CAPBADOPERATION;
274 twRC = TWRC_FAILURE;
275 break;
276 }
277 break;
278
279 default:
280 WARN("code unsupported: %d\n", DAT);
281 activeDS.twCC = TWCC_CAPUNSUPPORTED;
282 twRC = TWRC_FAILURE;
283 break;
284 }
285
286 return twRC;
287 }
288
289
290 static TW_UINT16 SANE_ImageGroupHandler (
291 pTW_IDENTITY pOrigin,
292 TW_UINT16 DAT,
293 TW_UINT16 MSG,
294 TW_MEMREF pData)
295 {
296 TW_UINT16 twRC = TWRC_SUCCESS;
297
298 switch (DAT)
299 {
300 case DAT_IMAGEINFO:
301 if (MSG == MSG_GET)
302 twRC = SANE_ImageInfoGet (pOrigin, pData);
303 else
304 {
305 activeDS.twCC = TWCC_CAPBADOPERATION;
306 twRC = TWRC_FAILURE;
307 }
308 break;
309
310 case DAT_IMAGELAYOUT:
311 switch (MSG)
312 {
313 case MSG_GET:
314 twRC = SANE_ImageLayoutGet (pOrigin, pData);
315 break;
316 case MSG_GETDEFAULT:
317 twRC = SANE_ImageLayoutGetDefault (pOrigin, pData);
318 break;
319 case MSG_RESET:
320 twRC = SANE_ImageLayoutReset (pOrigin, pData);
321 break;
322 case MSG_SET:
323 twRC = SANE_ImageLayoutSet (pOrigin, pData);
324 break;
325 default:
326 twRC = TWRC_FAILURE;
327 activeDS.twCC = TWCC_CAPBADOPERATION;
328 ERR("unrecognized operation triplet\n");
329 break;
330 }
331 break;
332
333 case DAT_IMAGEMEMXFER:
334 if (MSG == MSG_GET)
335 twRC = SANE_ImageMemXferGet (pOrigin, pData);
336 else
337 {
338 activeDS.twCC = TWCC_CAPBADOPERATION;
339 twRC = TWRC_FAILURE;
340 }
341 break;
342
343 case DAT_IMAGENATIVEXFER:
344 if (MSG == MSG_GET)
345 twRC = SANE_ImageNativeXferGet (pOrigin, pData);
346 else
347 {
348 activeDS.twCC = TWCC_CAPBADOPERATION;
349 twRC = TWRC_FAILURE;
350 }
351 break;
352
353 default:
354 twRC = TWRC_FAILURE;
355 activeDS.twCC = TWCC_CAPUNSUPPORTED;
356 WARN("unsupported DG type %d\n", DAT);
357 break;
358 }
359 return twRC;
360 }
361
362 /* Main entry point for the TWAIN library */
363 TW_UINT16 WINAPI
364 DS_Entry ( pTW_IDENTITY pOrigin,
365 TW_UINT32 DG,
366 TW_UINT16 DAT,
367 TW_UINT16 MSG,
368 TW_MEMREF pData)
369 {
370 TW_UINT16 twRC = TWRC_SUCCESS; /* Return Code */
371
372 TRACE("(DG=%d DAT=%d MSG=%d)\n", DG, DAT, MSG);
373
374 switch (DG)
375 {
376 case DG_CONTROL:
377 twRC = SANE_SourceControlHandler (pOrigin,DAT,MSG,pData);
378 break;
379 case DG_IMAGE:
380 twRC = SANE_ImageGroupHandler (pOrigin,DAT,MSG,pData);
381 break;
382 case DG_AUDIO:
383 WARN("Audio group of controls not implemented yet.\n");
384 twRC = TWRC_FAILURE;
385 activeDS.twCC = TWCC_CAPUNSUPPORTED;
386 break;
387 default:
388 activeDS.twCC = TWCC_BADPROTOCOL;
389 twRC = TWRC_FAILURE;
390 }
391
392 return twRC;
393 }
394
395 #ifdef SONAME_LIBSANE
396 /* Sane returns device names that are longer than the 32 bytes allowed
397 by TWAIN. However, it colon separates them, and the last bit is
398 the most interesting. So we use the last bit, and add a signature
399 to ensure uniqueness */
400 static void copy_sane_short_name(const char *in, char *out, size_t outsize)
401 {
402 const char *p;
403 int signature = 0;
404
405 if (strlen(in) <= outsize - 1)
406 {
407 strcpy(out, in);
408 return;
409 }
410
411 for (p = in; *p; p++)
412 signature += *p;
413
414 p = strrchr(in, ':');
415 if (!p)
416 p = in;
417 else
418 p++;
419
420 if (strlen(p) > outsize - 7 - 1)
421 p += strlen(p) - (outsize - 7 - 1);
422
423 strcpy(out, p);
424 sprintf(out + strlen(out), "(%04X)", signature % 0x10000);
425
426 }
427
428 static const SANE_Device **sane_devlist;
429
430 static void
431 detect_sane_devices(void) {
432 if (sane_devlist && sane_devlist[0]) return;
433 TRACE("detecting sane...\n");
434 if (psane_get_devices (&sane_devlist, SANE_FALSE) != SANE_STATUS_GOOD)
435 return;
436 }
437
438 static TW_UINT16
439 SANE_GetIdentity( pTW_IDENTITY pOrigin, pTW_IDENTITY self) {
440 static int cursanedev = 0;
441
442 detect_sane_devices();
443 if (!sane_devlist[cursanedev])
444 return TWRC_FAILURE;
445 self->ProtocolMajor = TWON_PROTOCOLMAJOR;
446 self->ProtocolMinor = TWON_PROTOCOLMINOR;
447 self->SupportedGroups = DG_CONTROL | DG_IMAGE;
448 copy_sane_short_name(sane_devlist[cursanedev]->name, self->ProductName, sizeof(self->ProductName) - 1);
449 lstrcpynA (self->Manufacturer, sane_devlist[cursanedev]->vendor, sizeof(self->Manufacturer) - 1);
450 lstrcpynA (self->ProductFamily, sane_devlist[cursanedev]->model, sizeof(self->ProductFamily) - 1);
451 cursanedev++;
452
453 if (!sane_devlist[cursanedev] ||
454 !sane_devlist[cursanedev]->model ||
455 !sane_devlist[cursanedev]->vendor ||
456 !sane_devlist[cursanedev]->name
457 )
458 cursanedev = 0; /* wrap to begin */
459 return TWRC_SUCCESS;
460 }
461
462 static TW_UINT16 SANE_OpenDS( pTW_IDENTITY pOrigin, pTW_IDENTITY self) {
463 SANE_Status status;
464 int i;
465
466 detect_sane_devices();
467 if (!sane_devlist[0]) {
468 ERR("No scanners? We should not get to OpenDS?\n");
469 return TWRC_FAILURE;
470 }
471
472 for (i=0; sane_devlist[i] && sane_devlist[i]->model; i++) {
473 TW_STR32 name;
474
475 /* To make string as short as above */
476 lstrcpynA(name, sane_devlist[i]->vendor, sizeof(name)-1);
477 if (self->Manufacturer && *self->Manufacturer && strcmp(name, self->Manufacturer))
478 continue;
479 lstrcpynA(name, sane_devlist[i]->model, sizeof(name)-1);
480 if (self->ProductFamily && *self->ProductFamily && strcmp(name, self->ProductFamily))
481 continue;
482 copy_sane_short_name(sane_devlist[i]->name, name, sizeof(name) - 1);
483 if (self->ProductName && *self->ProductName && strcmp(name, self->ProductName))
484 continue;
485 break;
486 }
487 if (!sane_devlist[i]) {
488 WARN("Scanner not found.\n");
489 return TWRC_FAILURE;
490 }
491 status = psane_open(sane_devlist[i]->name,&activeDS.deviceHandle);
492 if (status == SANE_STATUS_GOOD) {
493 activeDS.twCC = SANE_SaneSetDefaults();
494 if (activeDS.twCC == TWCC_SUCCESS) {
495 activeDS.currentState = 4;
496 return TWRC_SUCCESS;
497 }
498 else
499 psane_close(activeDS.deviceHandle);
500 }
501 else
502 ERR("sane_open(%s): %s\n", sane_devlist[i]->name, psane_strstatus (status));
503 return TWRC_FAILURE;
504 }
505 #endif
506
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.