user/tests: Add lparam to all HCBT_MINMAX hook messages.
[wine] / dlls / sane.ds / sane_main.c
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #include <stdarg.h>
24 #include <stdio.h>
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "twain.h"
29 #include "sane_i.h"
30 #include "wine/debug.h"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(twain);
33
34 HINSTANCE SANE_instance;
35
36 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
37 {
38     TRACE("%p,%lx,%p\n", hinstDLL, fdwReason, lpvReserved);
39
40     switch (fdwReason)
41     {
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;
51         }
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;
59     }
60
61     return TRUE;
62 }
63
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
68
69 TW_UINT16 SANE_SourceControlHandler (
70            pTW_IDENTITY pOrigin,
71            TW_UINT16    DAT,
72            TW_UINT16    MSG,
73            TW_MEMREF    pData)
74 {
75     TW_UINT16 twRC = TWRC_SUCCESS;
76
77     switch (DAT)
78     {
79         case DAT_IDENTITY:
80             switch (MSG)
81             {
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;
101             }
102             break;
103         case DAT_CAPABILITY:
104             switch (MSG)
105             {
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");
127             }
128             break;
129
130         case DAT_CUSTOMDSDATA:
131             switch (MSG)
132             {
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;
141             }
142             break;
143
144         case DAT_FILESYSTEM:
145             switch (MSG)
146             {
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;
184             }
185             break;
186
187         case DAT_EVENT:
188             if (MSG == MSG_PROCESSEVENT)
189                 twRC = SANE_ProcessEvent (pOrigin, pData);
190             else
191                 twRC = TWRC_FAILURE;
192             break;
193
194         case DAT_PASSTHRU:
195             if (MSG == MSG_PASSTHRU)
196                 twRC = SANE_PassThrough (pOrigin, pData);
197             else
198                 twRC = TWRC_FAILURE;
199             break;
200
201         case DAT_PENDINGXFERS:
202             switch (MSG)
203             {
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;
218             }
219             break;
220
221         case DAT_SETUPFILEXFER:
222             switch (MSG)
223             {
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;
239             }
240             break;
241
242         /*case DAT_SETUPFILEXFER2:
243             switch (MSG)
244             {
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;
257             }
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;
265
266         case DAT_STATUS:
267             if (MSG == MSG_GET)
268                 twRC = SANE_GetDSStatus (pOrigin, pData);
269             else
270                 twRC = TWRC_FAILURE;
271             break;
272
273         case DAT_USERINTERFACE:
274             switch (MSG)
275             {
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;
288             }
289             break;
290
291         case DAT_XFERGROUP:
292             switch (MSG)
293             {
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;
303             }
304             break;
305
306         default:
307             FIXME("code unknown: %d\n", DAT);
308             twRC = TWRC_FAILURE;
309             break;
310     }
311
312     return twRC;
313 }
314
315
316 TW_UINT16 SANE_ImageGroupHandler (
317            pTW_IDENTITY pOrigin,
318            TW_UINT16    DAT,
319            TW_UINT16    MSG,
320            TW_MEMREF    pData)
321 {
322     TW_UINT16 twRC = TWRC_SUCCESS;
323
324     switch (DAT)
325     {
326         case DAT_CIECOLOR:
327             if (MSG == MSG_GET)
328                 twRC = SANE_CIEColorGet (pOrigin, pData);
329             else
330                 twRC = TWRC_FAILURE;
331             break;
332
333         case DAT_EXTIMAGEINFO:
334             if (MSG == MSG_GET)
335                 twRC = SANE_ExtImageInfoGet (pOrigin, pData);
336             else
337                 twRC = TWRC_FAILURE;
338             break;
339
340         case DAT_GRAYRESPONSE:
341             switch (MSG)
342             {
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;
354             }
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;
362
363         case DAT_IMAGEINFO:
364             if (MSG == MSG_GET)
365                 twRC = SANE_ImageInfoGet (pOrigin, pData);
366             else
367                 twRC = TWRC_FAILURE;
368             break;
369
370         case DAT_IMAGELAYOUT:
371             switch (MSG)
372             {
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;
390             }
391             break;
392
393         case DAT_IMAGEMEMXFER:
394             if (MSG == MSG_GET)
395                 twRC = SANE_ImageMemXferGet (pOrigin, pData);
396             else
397                 twRC = TWRC_FAILURE;
398             break;
399
400         case DAT_IMAGENATIVEXFER:
401             if (MSG == MSG_GET)
402                 twRC = SANE_ImageNativeXferGet (pOrigin, pData);
403             else
404                 twRC = TWRC_FAILURE;
405             break;
406
407         case DAT_JPEGCOMPRESSION:
408             switch (MSG)
409             {
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;
427             }
428             break;
429
430         case DAT_PALETTE8:
431             switch (MSG)
432             {
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");
449             }
450             break;
451
452         case DAT_RGBRESPONSE:
453             switch (MSG)
454             {
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;
466             }
467             break;
468
469         default:
470             twRC = TWRC_FAILURE;
471             activeDS.twCC = TWCC_BADPROTOCOL;
472             FIXME("unrecognized DG type %d\n", DAT);
473     }
474     return twRC;
475 }
476
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)
484 {
485     TW_UINT16 twRC = TWRC_SUCCESS;  /* Return Code */
486
487     TRACE("(DG=%ld DAT=%d MSG=%d)\n", DG, DAT, MSG);
488
489     switch (DG)
490     {
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;
502     }
503
504     return twRC;
505 }
506
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)
513 {
514     const char *p;
515     int  signature = 0;
516
517     if (strlen(in) <= outsize - 1)
518     {
519         strcpy(out, in);
520         return;
521     }
522
523     for (p = in; *p; p++)
524         signature += *p;
525
526     p = strrchr(in, ':');
527     if (!p)
528         p = in;
529     else
530         p++;
531
532     if (strlen(p) > outsize - 7 - 1)
533         p += strlen(p) - (outsize - 7 - 1);
534
535     strcpy(out, p);
536     sprintf(out + strlen(out), "(%04X)", signature % 0x10000);
537
538 }
539
540 static const SANE_Device **sane_devlist;
541
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;
548 }
549
550 static TW_UINT16
551 SANE_GetIdentity( pTW_IDENTITY pOrigin, pTW_IDENTITY self) {
552     static int cursanedev = 0;
553
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++;
563
564     if (!sane_devlist[cursanedev]               ||
565         !sane_devlist[cursanedev]->model        ||
566         !sane_devlist[cursanedev]->vendor       ||
567         !sane_devlist[cursanedev]->name
568     )
569         cursanedev = 0; /* wrap to begin */
570     return TWRC_SUCCESS;
571 }
572
573 static TW_UINT16 SANE_OpenDS( pTW_IDENTITY pOrigin, pTW_IDENTITY self) {
574     SANE_Status status;
575     int i;
576
577     detect_sane_devices();
578     if (!sane_devlist[0]) {
579         ERR("No scanners? We should not get to OpenDS?\n");
580         return TWRC_FAILURE;
581     }
582
583     for (i=0; sane_devlist[i] && sane_devlist[i]->model; i++) {
584         TW_STR32 name;
585
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;
597     }
598     if (!sane_devlist[i]) {
599         FIXME("Scanner not found? Using first one!\n");
600         i=0;
601     }
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;
607     }
608     FIXME("sane_open(%s): %s\n", sane_devlist[i]->name, sane_strstatus (status));
609     return TWRC_FAILURE;
610 }
611 #endif