appwiz.cpl: Fix compilation on systems that don't support nameless unions.
[wine.git] / dlls / sane.ds / sane_main.c
blob8c0e39feb3730bf7b81939f346f9b7a9c5952794
1 /*
2 * SANE.DS functions
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
21 #include "config.h"
22 #include "wine/port.h"
24 #include <stdarg.h>
25 #include <stdio.h>
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"
34 WINE_DEFAULT_DEBUG_CHANNEL(twain);
36 HINSTANCE SANE_instance;
38 #ifdef SONAME_LIBSANE
40 static void *libsane_handle;
42 static void close_libsane(void *h)
44 if (h)
45 wine_dlclose(h, NULL, 0);
48 static void *open_libsane(void)
50 void *h;
52 h = wine_dlopen(SONAME_LIBSANE, RTLD_GLOBAL | RTLD_NOW, NULL, 0);
53 if (!h)
55 WARN("dlopen(%s) failed\n", SONAME_LIBSANE);
56 return NULL;
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; \
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
82 return h;
85 #endif /* SONAME_LIBSANE */
87 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
89 TRACE("%p,%x,%p\n", hinstDLL, fdwReason, lpvReserved);
91 switch (fdwReason)
93 case DLL_PROCESS_ATTACH: {
94 #ifdef SONAME_LIBSANE
95 SANE_Status status;
96 SANE_Int version_code;
98 libsane_handle = open_libsane();
99 if (! libsane_handle)
100 return FALSE;
102 status = psane_init (&version_code, NULL);
103 #endif
104 SANE_instance = hinstDLL;
105 DisableThreadLibraryCalls(hinstDLL);
106 break;
108 case DLL_PROCESS_DETACH:
109 #ifdef SONAME_LIBSANE
110 TRACE("calling sane_exit()\n");
111 psane_exit ();
113 close_libsane(libsane_handle);
114 libsane_handle = NULL;
115 #endif
116 SANE_instance = NULL;
117 break;
120 return TRUE;
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
128 static TW_UINT16 SANE_SourceControlHandler (
129 pTW_IDENTITY pOrigin,
130 TW_UINT16 DAT,
131 TW_UINT16 MSG,
132 TW_MEMREF pData)
134 TW_UINT16 twRC = TWRC_SUCCESS;
136 switch (DAT)
138 case DAT_IDENTITY:
139 switch (MSG)
141 case MSG_CLOSEDS:
142 #ifdef SONAME_LIBSANE
143 psane_close (activeDS.deviceHandle);
144 #endif
145 break;
146 case MSG_OPENDS:
147 #ifdef SONAME_LIBSANE
148 twRC = SANE_OpenDS( pOrigin, (pTW_IDENTITY)pData);
149 #else
150 twRC = TWRC_FAILURE;
151 #endif
152 break;
153 case MSG_GET:
154 #ifdef SONAME_LIBSANE
155 twRC = SANE_GetIdentity( pOrigin, (pTW_IDENTITY)pData);
156 #else
157 twRC = TWRC_FAILURE;
158 #endif
159 break;
161 break;
162 case DAT_CAPABILITY:
163 switch (MSG)
165 case MSG_GET:
166 twRC = SANE_CapabilityGet (pOrigin, pData);
167 break;
168 case MSG_GETCURRENT:
169 twRC = SANE_CapabilityGetCurrent (pOrigin, pData);
170 break;
171 case MSG_GETDEFAULT:
172 twRC = SANE_CapabilityGetDefault (pOrigin, pData);
173 break;
174 case MSG_QUERYSUPPORT:
175 twRC = SANE_CapabilityQuerySupport (pOrigin, pData);
176 break;
177 case MSG_RESET:
178 twRC = SANE_CapabilityReset (pOrigin, pData);
179 break;
180 case MSG_SET:
181 twRC = SANE_CapabilitySet (pOrigin, pData);
182 break;
183 default:
184 twRC = TWRC_FAILURE;
185 FIXME("unrecognized opertion triplet\n");
187 break;
189 case DAT_CUSTOMDSDATA:
190 switch (MSG)
192 case MSG_GET:
193 twRC = SANE_CustomDSDataGet (pOrigin, pData);
194 break;
195 case MSG_SET:
196 twRC = SANE_CustomDSDataSet (pOrigin, pData);
197 break;
198 default:
199 break;
201 break;
203 case DAT_FILESYSTEM:
204 switch (MSG)
206 /*case MSG_AUTOMATICCAPTUREDIRECTORY:
207 twRC = SANE_AutomaticCaptureDirectory
208 (pOrigin, pData);
209 break;*/
210 case MSG_CHANGEDIRECTORY:
211 twRC = SANE_ChangeDirectory (pOrigin, pData);
212 break;
213 /*case MSG_COPY:
214 twRC = SANE_FileSystemCopy (pOrigin, pData);
215 break;*/
216 case MSG_CREATEDIRECTORY:
217 twRC = SANE_CreateDirectory (pOrigin, pData);
218 break;
219 case MSG_DELETE:
220 twRC = SANE_FileSystemDelete (pOrigin, pData);
221 break;
222 case MSG_FORMATMEDIA:
223 twRC = SANE_FormatMedia (pOrigin, pData);
224 break;
225 case MSG_GETCLOSE:
226 twRC = SANE_FileSystemGetClose (pOrigin, pData);
227 break;
228 case MSG_GETFIRSTFILE:
229 twRC = SANE_FileSystemGetFirstFile (pOrigin, pData);
230 break;
231 case MSG_GETINFO:
232 twRC = SANE_FileSystemGetInfo (pOrigin, pData);
233 break;
234 case MSG_GETNEXTFILE:
235 twRC = SANE_FileSystemGetNextFile (pOrigin, pData);
236 break;
237 case MSG_RENAME:
238 twRC = SANE_FileSystemRename (pOrigin, pData);
239 break;
240 default:
241 twRC = TWRC_FAILURE;
242 break;
244 break;
246 case DAT_EVENT:
247 if (MSG == MSG_PROCESSEVENT)
248 twRC = SANE_ProcessEvent (pOrigin, pData);
249 else
250 twRC = TWRC_FAILURE;
251 break;
253 case DAT_PASSTHRU:
254 if (MSG == MSG_PASSTHRU)
255 twRC = SANE_PassThrough (pOrigin, pData);
256 else
257 twRC = TWRC_FAILURE;
258 break;
260 case DAT_PENDINGXFERS:
261 switch (MSG)
263 case MSG_ENDXFER:
264 twRC = SANE_PendingXfersEndXfer (pOrigin, pData);
265 break;
266 case MSG_GET:
267 twRC = SANE_PendingXfersGet (pOrigin, pData);
268 break;
269 case MSG_RESET:
270 twRC = SANE_PendingXfersReset (pOrigin, pData);
271 break;
272 /*case MSG_STOPFEEDER:
273 twRC = SANE_PendingXfersStopFeeder (pOrigin, pData);
274 break;*/
275 default:
276 twRC = TWRC_FAILURE;
278 break;
280 case DAT_SETUPFILEXFER:
281 switch (MSG)
283 case MSG_GET:
284 twRC = SANE_SetupFileXferGet (pOrigin, pData);
285 break;
286 case MSG_GETDEFAULT:
287 twRC = SANE_SetupFileXferGetDefault (pOrigin, pData);
288 break;
289 case MSG_RESET:
290 twRC = SANE_SetupFileXferReset (pOrigin, pData);
291 break;
292 case MSG_SET:
293 twRC = SANE_SetupFileXferSet (pOrigin, pData);
294 break;
295 default:
296 twRC = TWRC_FAILURE;
297 break;
299 break;
301 /*case DAT_SETUPFILEXFER2:
302 switch (MSG)
304 case MSG_GET:
305 twRC = SANE_SetupFileXfer2Get (pOrigin, pData);
306 break;
307 case MSG_GETDEFAULT:
308 twRC = SANE_SetupFileXfer2GetDefault (pOrigin, pData);
309 break;
310 case MSG_RESET:
311 twRC = SANE_SetupFileXfer2Reset (pOrigin, pData);
312 break;
313 case MSG_SET:
314 twRC = SANE_SetupFileXfer2Set (pOrigin, pData);
315 break;
317 break;*/
318 case DAT_SETUPMEMXFER:
319 if (MSG == MSG_GET)
320 twRC = SANE_SetupMemXferGet (pOrigin, pData);
321 else
322 twRC = TWRC_FAILURE;
323 break;
325 case DAT_STATUS:
326 if (MSG == MSG_GET)
327 twRC = SANE_GetDSStatus (pOrigin, pData);
328 else
329 twRC = TWRC_FAILURE;
330 break;
332 case DAT_USERINTERFACE:
333 switch (MSG)
335 case MSG_DISABLEDS:
336 twRC = SANE_DisableDSUserInterface (pOrigin, pData);
337 break;
338 case MSG_ENABLEDS:
339 twRC = SANE_EnableDSUserInterface (pOrigin, pData);
340 break;
341 case MSG_ENABLEDSUIONLY:
342 twRC = SANE_EnableDSUIOnly (pOrigin, pData);
343 break;
344 default:
345 twRC = TWRC_FAILURE;
346 break;
348 break;
350 case DAT_XFERGROUP:
351 switch (MSG)
353 case MSG_GET:
354 twRC = SANE_XferGroupGet (pOrigin, pData);
355 break;
356 case MSG_SET:
357 twRC = SANE_XferGroupSet (pOrigin, pData);
358 break;
359 default:
360 twRC = TWRC_FAILURE;
361 break;
363 break;
365 default:
366 FIXME("code unknown: %d\n", DAT);
367 twRC = TWRC_FAILURE;
368 break;
371 return twRC;
375 TW_UINT16 SANE_ImageGroupHandler (
376 pTW_IDENTITY pOrigin,
377 TW_UINT16 DAT,
378 TW_UINT16 MSG,
379 TW_MEMREF pData)
381 TW_UINT16 twRC = TWRC_SUCCESS;
383 switch (DAT)
385 case DAT_CIECOLOR:
386 if (MSG == MSG_GET)
387 twRC = SANE_CIEColorGet (pOrigin, pData);
388 else
389 twRC = TWRC_FAILURE;
390 break;
392 case DAT_EXTIMAGEINFO:
393 if (MSG == MSG_GET)
394 twRC = SANE_ExtImageInfoGet (pOrigin, pData);
395 else
396 twRC = TWRC_FAILURE;
397 break;
399 case DAT_GRAYRESPONSE:
400 switch (MSG)
402 case MSG_RESET:
403 twRC = SANE_GrayResponseReset (pOrigin, pData);
404 break;
405 case MSG_SET:
406 twRC = SANE_GrayResponseSet (pOrigin, pData);
407 break;
408 default:
409 twRC = TWRC_FAILURE;
410 activeDS.twCC = TWCC_BADPROTOCOL;
411 FIXME("unrecognized operation triplet\n");
412 break;
414 break;
415 case DAT_IMAGEFILEXFER:
416 if (MSG == MSG_GET)
417 twRC = SANE_ImageFileXferGet (pOrigin, pData);
418 else
419 twRC = TWRC_FAILURE;
420 break;
422 case DAT_IMAGEINFO:
423 if (MSG == MSG_GET)
424 twRC = SANE_ImageInfoGet (pOrigin, pData);
425 else
426 twRC = TWRC_FAILURE;
427 break;
429 case DAT_IMAGELAYOUT:
430 switch (MSG)
432 case MSG_GET:
433 twRC = SANE_ImageLayoutGet (pOrigin, pData);
434 break;
435 case MSG_GETDEFAULT:
436 twRC = SANE_ImageLayoutGetDefault (pOrigin, pData);
437 break;
438 case MSG_RESET:
439 twRC = SANE_ImageLayoutReset (pOrigin, pData);
440 break;
441 case MSG_SET:
442 twRC = SANE_ImageLayoutSet (pOrigin, pData);
443 break;
444 default:
445 twRC = TWRC_FAILURE;
446 activeDS.twCC = TWCC_BADPROTOCOL;
447 ERR("unrecognized operation triplet\n");
448 break;
450 break;
452 case DAT_IMAGEMEMXFER:
453 if (MSG == MSG_GET)
454 twRC = SANE_ImageMemXferGet (pOrigin, pData);
455 else
456 twRC = TWRC_FAILURE;
457 break;
459 case DAT_IMAGENATIVEXFER:
460 if (MSG == MSG_GET)
461 twRC = SANE_ImageNativeXferGet (pOrigin, pData);
462 else
463 twRC = TWRC_FAILURE;
464 break;
466 case DAT_JPEGCOMPRESSION:
467 switch (MSG)
469 case MSG_GET:
470 twRC = SANE_JPEGCompressionGet (pOrigin, pData);
471 break;
472 case MSG_GETDEFAULT:
473 twRC = SANE_JPEGCompressionGetDefault (pOrigin, pData);
474 break;
475 case MSG_RESET:
476 twRC = SANE_JPEGCompressionReset (pOrigin, pData);
477 break;
478 case MSG_SET:
479 twRC = SANE_JPEGCompressionSet (pOrigin, pData);
480 break;
481 default:
482 twRC = TWRC_FAILURE;
483 activeDS.twCC = TWCC_BADPROTOCOL;
484 WARN("unrecognized operation triplet\n");
485 break;
487 break;
489 case DAT_PALETTE8:
490 switch (MSG)
492 case MSG_GET:
493 twRC = SANE_Palette8Get (pOrigin, pData);
494 break;
495 case MSG_GETDEFAULT:
496 twRC = SANE_Palette8GetDefault (pOrigin, pData);
497 break;
498 case MSG_RESET:
499 twRC = SANE_Palette8Reset (pOrigin, pData);
500 break;
501 case MSG_SET:
502 twRC = SANE_Palette8Set (pOrigin, pData);
503 break;
504 default:
505 twRC = TWRC_FAILURE;
506 activeDS.twCC = TWCC_BADPROTOCOL;
507 WARN("unrecognized operation triplet\n");
509 break;
511 case DAT_RGBRESPONSE:
512 switch (MSG)
514 case MSG_RESET:
515 twRC = SANE_RGBResponseReset (pOrigin, pData);
516 break;
517 case MSG_SET:
518 twRC = SANE_RGBResponseSet (pOrigin, pData);
519 break;
520 default:
521 twRC = TWRC_FAILURE;
522 activeDS.twCC = TWCC_BADPROTOCOL;
523 WARN("unrecognized operation triplet\n");
524 break;
526 break;
528 default:
529 twRC = TWRC_FAILURE;
530 activeDS.twCC = TWCC_BADPROTOCOL;
531 FIXME("unrecognized DG type %d\n", DAT);
533 return twRC;
536 /* Main entry point for the TWAIN library */
537 TW_UINT16 WINAPI
538 DS_Entry ( pTW_IDENTITY pOrigin,
539 TW_UINT32 DG,
540 TW_UINT16 DAT,
541 TW_UINT16 MSG,
542 TW_MEMREF pData)
544 TW_UINT16 twRC = TWRC_SUCCESS; /* Return Code */
546 TRACE("(DG=%ld DAT=%d MSG=%d)\n", DG, DAT, MSG);
548 switch (DG)
550 case DG_CONTROL:
551 twRC = SANE_SourceControlHandler (pOrigin,DAT,MSG,pData);
552 break;
553 case DG_IMAGE:
554 twRC = SANE_ImageGroupHandler (pOrigin,DAT,MSG,pData);
555 break;
556 case DG_AUDIO:
557 FIXME("Audio group of controls not implemented yet.\n");
558 default:
559 activeDS.twCC = TWCC_BADPROTOCOL;
560 twRC = TWRC_FAILURE;
563 return twRC;
566 #ifdef SONAME_LIBSANE
567 /* Sane returns device names that are longer than the 32 bytes allowed
568 by TWAIN. However, it colon separates them, and the last bit is
569 the most interesting. So we use the last bit, and add a signature
570 to ensure uniqueness */
571 static void copy_sane_short_name(const char *in, char *out, size_t outsize)
573 const char *p;
574 int signature = 0;
576 if (strlen(in) <= outsize - 1)
578 strcpy(out, in);
579 return;
582 for (p = in; *p; p++)
583 signature += *p;
585 p = strrchr(in, ':');
586 if (!p)
587 p = in;
588 else
589 p++;
591 if (strlen(p) > outsize - 7 - 1)
592 p += strlen(p) - (outsize - 7 - 1);
594 strcpy(out, p);
595 sprintf(out + strlen(out), "(%04X)", signature % 0x10000);
599 static const SANE_Device **sane_devlist;
601 static void
602 detect_sane_devices(void) {
603 if (sane_devlist && sane_devlist[0]) return;
604 TRACE("detecting sane...\n");
605 if (psane_get_devices (&sane_devlist, SANE_FALSE) != SANE_STATUS_GOOD)
606 return;
609 static TW_UINT16
610 SANE_GetIdentity( pTW_IDENTITY pOrigin, pTW_IDENTITY self) {
611 static int cursanedev = 0;
613 detect_sane_devices();
614 if (!sane_devlist[cursanedev])
615 return TWRC_FAILURE;
616 self->ProtocolMajor = TWON_PROTOCOLMAJOR;
617 self->ProtocolMinor = TWON_PROTOCOLMINOR;
618 copy_sane_short_name(sane_devlist[cursanedev]->name, self->ProductName, sizeof(self->ProductName) - 1);
619 lstrcpynA (self->Manufacturer, sane_devlist[cursanedev]->vendor, sizeof(self->Manufacturer) - 1);
620 lstrcpynA (self->ProductFamily, sane_devlist[cursanedev]->model, sizeof(self->ProductFamily) - 1);
621 cursanedev++;
623 if (!sane_devlist[cursanedev] ||
624 !sane_devlist[cursanedev]->model ||
625 !sane_devlist[cursanedev]->vendor ||
626 !sane_devlist[cursanedev]->name
628 cursanedev = 0; /* wrap to begin */
629 return TWRC_SUCCESS;
632 static TW_UINT16 SANE_OpenDS( pTW_IDENTITY pOrigin, pTW_IDENTITY self) {
633 SANE_Status status;
634 int i;
636 detect_sane_devices();
637 if (!sane_devlist[0]) {
638 ERR("No scanners? We should not get to OpenDS?\n");
639 return TWRC_FAILURE;
642 for (i=0; sane_devlist[i] && sane_devlist[i]->model; i++) {
643 TW_STR32 name;
645 /* To make string as short as above */
646 lstrcpynA(name, sane_devlist[i]->vendor, sizeof(name)-1);
647 if (strcmp(name, self->Manufacturer))
648 continue;
649 lstrcpynA(name, sane_devlist[i]->model, sizeof(name)-1);
650 if (strcmp(name, self->ProductFamily))
651 continue;
652 copy_sane_short_name(sane_devlist[i]->name, name, sizeof(name) - 1);
653 if (strcmp(name, self->ProductName))
654 continue;
655 break;
657 if (!sane_devlist[i]) {
658 FIXME("Scanner not found? Using first one!\n");
659 i=0;
661 status = psane_open(sane_devlist[i]->name,&activeDS.deviceHandle);
662 if (status == SANE_STATUS_GOOD) {
663 activeDS.currentState = 4;
664 activeDS.twCC = TWRC_SUCCESS;
665 return TWRC_SUCCESS;
667 FIXME("sane_open(%s): %s\n", sane_devlist[i]->name, psane_strstatus (status));
668 return TWRC_FAILURE;
670 #endif