wrc: Clean output files when aborting on an error or signal.
[wine/multimedia.git] / dlls / sane.ds / sane_main.c
blob521e30c7faf6fd2fdb30751414a9893a194586fd
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"
23 #include <stdarg.h>
24 #include <stdio.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "twain.h"
29 #include "sane_i.h"
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(twain);
34 HINSTANCE SANE_instance;
36 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
38 TRACE("%p,%lx,%p\n", hinstDLL, fdwReason, lpvReserved);
40 switch (fdwReason)
42 case DLL_PROCESS_ATTACH: {
43 #ifdef HAVE_SANE
44 SANE_Status status;
45 SANE_Int version_code;
46 status = sane_init (&version_code, NULL);
47 #endif
48 SANE_instance = hinstDLL;
49 DisableThreadLibraryCalls(hinstDLL);
50 break;
52 case DLL_PROCESS_DETACH:
53 #ifdef HAVE_SANE
54 FIXME("calling sane_Exit()\n");
55 sane_exit ();
56 #endif
57 SANE_instance = NULL;
58 break;
61 return TRUE;
64 #ifdef HAVE_SANE
65 static TW_UINT16 SANE_GetIdentity( pTW_IDENTITY, pTW_IDENTITY);
66 static TW_UINT16 SANE_OpenDS( pTW_IDENTITY, pTW_IDENTITY);
67 #endif
69 TW_UINT16 SANE_SourceControlHandler (
70 pTW_IDENTITY pOrigin,
71 TW_UINT16 DAT,
72 TW_UINT16 MSG,
73 TW_MEMREF pData)
75 TW_UINT16 twRC = TWRC_SUCCESS;
77 switch (DAT)
79 case DAT_IDENTITY:
80 switch (MSG)
82 case MSG_CLOSEDS:
83 #ifdef HAVE_SANE
84 sane_close (activeDS.deviceHandle);
85 #endif
86 break;
87 case MSG_OPENDS:
88 #ifdef HAVE_SANE
89 twRC = SANE_OpenDS( pOrigin, (pTW_IDENTITY)pData);
90 #else
91 twRC = TWRC_FAILURE;
92 #endif
93 break;
94 case MSG_GET:
95 #ifdef HAVE_SANE
96 twRC = SANE_GetIdentity( pOrigin, (pTW_IDENTITY)pData);
97 #else
98 twRC = TWRC_FAILURE;
99 #endif
100 break;
102 break;
103 case DAT_CAPABILITY:
104 switch (MSG)
106 case MSG_GET:
107 twRC = SANE_CapabilityGet (pOrigin, pData);
108 break;
109 case MSG_GETCURRENT:
110 twRC = SANE_CapabilityGetCurrent (pOrigin, pData);
111 break;
112 case MSG_GETDEFAULT:
113 twRC = SANE_CapabilityGetDefault (pOrigin, pData);
114 break;
115 case MSG_QUERYSUPPORT:
116 twRC = SANE_CapabilityQuerySupport (pOrigin, pData);
117 break;
118 case MSG_RESET:
119 twRC = SANE_CapabilityReset (pOrigin, pData);
120 break;
121 case MSG_SET:
122 twRC = SANE_CapabilitySet (pOrigin, pData);
123 break;
124 default:
125 twRC = TWRC_FAILURE;
126 FIXME("unrecognized opertion triplet\n");
128 break;
130 case DAT_CUSTOMDSDATA:
131 switch (MSG)
133 case MSG_GET:
134 twRC = SANE_CustomDSDataGet (pOrigin, pData);
135 break;
136 case MSG_SET:
137 twRC = SANE_CustomDSDataSet (pOrigin, pData);
138 break;
139 default:
140 break;
142 break;
144 case DAT_FILESYSTEM:
145 switch (MSG)
147 /*case MSG_AUTOMATICCAPTUREDIRECTORY:
148 twRC = SANE_AutomaticCaptureDirectory
149 (pOrigin, pData);
150 break;*/
151 case MSG_CHANGEDIRECTORY:
152 twRC = SANE_ChangeDirectory (pOrigin, pData);
153 break;
154 /*case MSG_COPY:
155 twRC = SANE_FileSystemCopy (pOrigin, pData);
156 break;*/
157 case MSG_CREATEDIRECTORY:
158 twRC = SANE_CreateDirectory (pOrigin, pData);
159 break;
160 case MSG_DELETE:
161 twRC = SANE_FileSystemDelete (pOrigin, pData);
162 break;
163 case MSG_FORMATMEDIA:
164 twRC = SANE_FormatMedia (pOrigin, pData);
165 break;
166 case MSG_GETCLOSE:
167 twRC = SANE_FileSystemGetClose (pOrigin, pData);
168 break;
169 case MSG_GETFIRSTFILE:
170 twRC = SANE_FileSystemGetFirstFile (pOrigin, pData);
171 break;
172 case MSG_GETINFO:
173 twRC = SANE_FileSystemGetInfo (pOrigin, pData);
174 break;
175 case MSG_GETNEXTFILE:
176 twRC = SANE_FileSystemGetNextFile (pOrigin, pData);
177 break;
178 case MSG_RENAME:
179 twRC = SANE_FileSystemRename (pOrigin, pData);
180 break;
181 default:
182 twRC = TWRC_FAILURE;
183 break;
185 break;
187 case DAT_EVENT:
188 if (MSG == MSG_PROCESSEVENT)
189 twRC = SANE_ProcessEvent (pOrigin, pData);
190 else
191 twRC = TWRC_FAILURE;
192 break;
194 case DAT_PASSTHRU:
195 if (MSG == MSG_PASSTHRU)
196 twRC = SANE_PassThrough (pOrigin, pData);
197 else
198 twRC = TWRC_FAILURE;
199 break;
201 case DAT_PENDINGXFERS:
202 switch (MSG)
204 case MSG_ENDXFER:
205 twRC = SANE_PendingXfersEndXfer (pOrigin, pData);
206 break;
207 case MSG_GET:
208 twRC = SANE_PendingXfersGet (pOrigin, pData);
209 break;
210 case MSG_RESET:
211 twRC = SANE_PendingXfersReset (pOrigin, pData);
212 break;
213 /*case MSG_STOPFEEDER:
214 twRC = SANE_PendingXfersStopFeeder (pOrigin, pData);
215 break;*/
216 default:
217 twRC = TWRC_FAILURE;
219 break;
221 case DAT_SETUPFILEXFER:
222 switch (MSG)
224 case MSG_GET:
225 twRC = SANE_SetupFileXferGet (pOrigin, pData);
226 break;
227 case MSG_GETDEFAULT:
228 twRC = SANE_SetupFileXferGetDefault (pOrigin, pData);
229 break;
230 case MSG_RESET:
231 twRC = SANE_SetupFileXferReset (pOrigin, pData);
232 break;
233 case MSG_SET:
234 twRC = SANE_SetupFileXferSet (pOrigin, pData);
235 break;
236 default:
237 twRC = TWRC_FAILURE;
238 break;
240 break;
242 /*case DAT_SETUPFILEXFER2:
243 switch (MSG)
245 case MSG_GET:
246 twRC = SANE_SetupFileXfer2Get (pOrigin, pData);
247 break;
248 case MSG_GETDEFAULT:
249 twRC = SANE_SetupFileXfer2GetDefault (pOrigin, pData);
250 break;
251 case MSG_RESET:
252 twRC = SANE_SetupFileXfer2Reset (pOrigin, pData);
253 break;
254 case MSG_SET:
255 twRC = SANE_SetupFileXfer2Set (pOrigin, pData);
256 break;
258 break;*/
259 case DAT_SETUPMEMXFER:
260 if (MSG == MSG_GET)
261 twRC = SANE_SetupMemXferGet (pOrigin, pData);
262 else
263 twRC = TWRC_FAILURE;
264 break;
266 case DAT_STATUS:
267 if (MSG == MSG_GET)
268 twRC = SANE_GetDSStatus (pOrigin, pData);
269 else
270 twRC = TWRC_FAILURE;
271 break;
273 case DAT_USERINTERFACE:
274 switch (MSG)
276 case MSG_DISABLEDS:
277 twRC = SANE_DisableDSUserInterface (pOrigin, pData);
278 break;
279 case MSG_ENABLEDS:
280 twRC = SANE_EnableDSUserInterface (pOrigin, pData);
281 break;
282 case MSG_ENABLEDSUIONLY:
283 twRC = SANE_EnableDSUIOnly (pOrigin, pData);
284 break;
285 default:
286 twRC = TWRC_FAILURE;
287 break;
289 break;
291 case DAT_XFERGROUP:
292 switch (MSG)
294 case MSG_GET:
295 twRC = SANE_XferGroupGet (pOrigin, pData);
296 break;
297 case MSG_SET:
298 twRC = SANE_XferGroupSet (pOrigin, pData);
299 break;
300 default:
301 twRC = TWRC_FAILURE;
302 break;
304 break;
306 default:
307 FIXME("code unknown: %d\n", DAT);
308 twRC = TWRC_FAILURE;
309 break;
312 return twRC;
316 TW_UINT16 SANE_ImageGroupHandler (
317 pTW_IDENTITY pOrigin,
318 TW_UINT16 DAT,
319 TW_UINT16 MSG,
320 TW_MEMREF pData)
322 TW_UINT16 twRC = TWRC_SUCCESS;
324 switch (DAT)
326 case DAT_CIECOLOR:
327 if (MSG == MSG_GET)
328 twRC = SANE_CIEColorGet (pOrigin, pData);
329 else
330 twRC = TWRC_FAILURE;
331 break;
333 case DAT_EXTIMAGEINFO:
334 if (MSG == MSG_GET)
335 twRC = SANE_ExtImageInfoGet (pOrigin, pData);
336 else
337 twRC = TWRC_FAILURE;
338 break;
340 case DAT_GRAYRESPONSE:
341 switch (MSG)
343 case MSG_RESET:
344 twRC = SANE_GrayResponseReset (pOrigin, pData);
345 break;
346 case MSG_SET:
347 twRC = SANE_GrayResponseSet (pOrigin, pData);
348 break;
349 default:
350 twRC = TWRC_FAILURE;
351 activeDS.twCC = TWCC_BADPROTOCOL;
352 FIXME("unrecognized operation triplet\n");
353 break;
355 break;
356 case DAT_IMAGEFILEXFER:
357 if (MSG == MSG_GET)
358 twRC = SANE_ImageFileXferGet (pOrigin, pData);
359 else
360 twRC = TWRC_FAILURE;
361 break;
363 case DAT_IMAGEINFO:
364 if (MSG == MSG_GET)
365 twRC = SANE_ImageInfoGet (pOrigin, pData);
366 else
367 twRC = TWRC_FAILURE;
368 break;
370 case DAT_IMAGELAYOUT:
371 switch (MSG)
373 case MSG_GET:
374 twRC = SANE_ImageLayoutGet (pOrigin, pData);
375 break;
376 case MSG_GETDEFAULT:
377 twRC = SANE_ImageLayoutGetDefault (pOrigin, pData);
378 break;
379 case MSG_RESET:
380 twRC = SANE_ImageLayoutReset (pOrigin, pData);
381 break;
382 case MSG_SET:
383 twRC = SANE_ImageLayoutSet (pOrigin, pData);
384 break;
385 default:
386 twRC = TWRC_FAILURE;
387 activeDS.twCC = TWCC_BADPROTOCOL;
388 ERR("unrecognized operation triplet\n");
389 break;
391 break;
393 case DAT_IMAGEMEMXFER:
394 if (MSG == MSG_GET)
395 twRC = SANE_ImageMemXferGet (pOrigin, pData);
396 else
397 twRC = TWRC_FAILURE;
398 break;
400 case DAT_IMAGENATIVEXFER:
401 if (MSG == MSG_GET)
402 twRC = SANE_ImageNativeXferGet (pOrigin, pData);
403 else
404 twRC = TWRC_FAILURE;
405 break;
407 case DAT_JPEGCOMPRESSION:
408 switch (MSG)
410 case MSG_GET:
411 twRC = SANE_JPEGCompressionGet (pOrigin, pData);
412 break;
413 case MSG_GETDEFAULT:
414 twRC = SANE_JPEGCompressionGetDefault (pOrigin, pData);
415 break;
416 case MSG_RESET:
417 twRC = SANE_JPEGCompressionReset (pOrigin, pData);
418 break;
419 case MSG_SET:
420 twRC = SANE_JPEGCompressionSet (pOrigin, pData);
421 break;
422 default:
423 twRC = TWRC_FAILURE;
424 activeDS.twCC = TWCC_BADPROTOCOL;
425 WARN("unrecognized operation triplet\n");
426 break;
428 break;
430 case DAT_PALETTE8:
431 switch (MSG)
433 case MSG_GET:
434 twRC = SANE_Palette8Get (pOrigin, pData);
435 break;
436 case MSG_GETDEFAULT:
437 twRC = SANE_Palette8GetDefault (pOrigin, pData);
438 break;
439 case MSG_RESET:
440 twRC = SANE_Palette8Reset (pOrigin, pData);
441 break;
442 case MSG_SET:
443 twRC = SANE_Palette8Set (pOrigin, pData);
444 break;
445 default:
446 twRC = TWRC_FAILURE;
447 activeDS.twCC = TWCC_BADPROTOCOL;
448 WARN("unrecognized operation triplet\n");
450 break;
452 case DAT_RGBRESPONSE:
453 switch (MSG)
455 case MSG_RESET:
456 twRC = SANE_RGBResponseReset (pOrigin, pData);
457 break;
458 case MSG_SET:
459 twRC = SANE_RGBResponseSet (pOrigin, pData);
460 break;
461 default:
462 twRC = TWRC_FAILURE;
463 activeDS.twCC = TWCC_BADPROTOCOL;
464 WARN("unrecognized operation triplet\n");
465 break;
467 break;
469 default:
470 twRC = TWRC_FAILURE;
471 activeDS.twCC = TWCC_BADPROTOCOL;
472 FIXME("unrecognized DG type %d\n", DAT);
474 return twRC;
477 /* Main entry point for the TWAIN library */
478 TW_UINT16 WINAPI
479 DS_Entry ( pTW_IDENTITY pOrigin,
480 TW_UINT32 DG,
481 TW_UINT16 DAT,
482 TW_UINT16 MSG,
483 TW_MEMREF pData)
485 TW_UINT16 twRC = TWRC_SUCCESS; /* Return Code */
487 TRACE("(DG=%ld DAT=%d MSG=%d)\n", DG, DAT, MSG);
489 switch (DG)
491 case DG_CONTROL:
492 twRC = SANE_SourceControlHandler (pOrigin,DAT,MSG,pData);
493 break;
494 case DG_IMAGE:
495 twRC = SANE_ImageGroupHandler (pOrigin,DAT,MSG,pData);
496 break;
497 case DG_AUDIO:
498 FIXME("Audio group of controls not implemented yet.\n");
499 default:
500 activeDS.twCC = TWCC_BADPROTOCOL;
501 twRC = TWRC_FAILURE;
504 return twRC;
507 #ifdef HAVE_SANE
508 /* Sane returns device names that are longer than the 32 bytes allowed
509 by TWAIN. However, it colon separates them, and the last bit is
510 the most interesting. So we use the last bit, and add a signature
511 to ensure uniqueness */
512 static void copy_sane_short_name(const char *in, char *out, size_t outsize)
514 const char *p;
515 int signature = 0;
517 if (strlen(in) <= outsize - 1)
519 strcpy(out, in);
520 return;
523 for (p = in; *p; p++)
524 signature += *p;
526 p = strrchr(in, ':');
527 if (!p)
528 p = in;
529 else
530 p++;
532 if (strlen(p) > outsize - 7 - 1)
533 p += strlen(p) - (outsize - 7 - 1);
535 strcpy(out, p);
536 sprintf(out + strlen(out), "(%04X)", signature % 0x10000);
540 static const SANE_Device **sane_devlist;
542 static void
543 detect_sane_devices() {
544 if (sane_devlist && sane_devlist[0]) return;
545 TRACE("detecting sane...\n");
546 if (sane_get_devices (&sane_devlist, SANE_FALSE) != SANE_STATUS_GOOD)
547 return;
550 static TW_UINT16
551 SANE_GetIdentity( pTW_IDENTITY pOrigin, pTW_IDENTITY self) {
552 static int cursanedev = 0;
554 detect_sane_devices();
555 if (!sane_devlist[cursanedev])
556 return TWRC_FAILURE;
557 self->ProtocolMajor = TWON_PROTOCOLMAJOR;
558 self->ProtocolMinor = TWON_PROTOCOLMINOR;
559 copy_sane_short_name(sane_devlist[cursanedev]->name, self->ProductName, sizeof(self->ProductName) - 1);
560 lstrcpynA (self->Manufacturer, sane_devlist[cursanedev]->vendor, sizeof(self->Manufacturer) - 1);
561 lstrcpynA (self->ProductFamily, sane_devlist[cursanedev]->model, sizeof(self->ProductFamily) - 1);
562 cursanedev++;
564 if (!sane_devlist[cursanedev] ||
565 !sane_devlist[cursanedev]->model ||
566 !sane_devlist[cursanedev]->vendor ||
567 !sane_devlist[cursanedev]->name
569 cursanedev = 0; /* wrap to begin */
570 return TWRC_SUCCESS;
573 static TW_UINT16 SANE_OpenDS( pTW_IDENTITY pOrigin, pTW_IDENTITY self) {
574 SANE_Status status;
575 int i;
577 detect_sane_devices();
578 if (!sane_devlist[0]) {
579 ERR("No scanners? We should not get to OpenDS?\n");
580 return TWRC_FAILURE;
583 for (i=0; sane_devlist[i] && sane_devlist[i]->model; i++) {
584 TW_STR32 name;
586 /* To make string as short as above */
587 lstrcpynA(name, sane_devlist[i]->vendor, sizeof(name)-1);
588 if (strcmp(name, self->Manufacturer))
589 continue;
590 lstrcpynA(name, sane_devlist[i]->model, sizeof(name)-1);
591 if (strcmp(name, self->ProductFamily))
592 continue;
593 copy_sane_short_name(sane_devlist[i]->name, name, sizeof(name) - 1);
594 if (strcmp(name, self->ProductName))
595 continue;
596 break;
598 if (!sane_devlist[i]) {
599 FIXME("Scanner not found? Using first one!\n");
600 i=0;
602 status = sane_open(sane_devlist[i]->name,&activeDS.deviceHandle);
603 if (status == SANE_STATUS_GOOD) {
604 activeDS.currentState = 4;
605 activeDS.twCC = TWRC_SUCCESS;
606 return TWRC_SUCCESS;
608 FIXME("sane_open(%s): %s\n", sane_devlist[i]->name, sane_strstatus (status));
609 return TWRC_FAILURE;
611 #endif