push eb25bf65c4616aa55a810ed5c29198b1a080b208
[wine/hacks.git] / dlls / sane.ds / sane_main.c
bloba873d6c12567214db9ab9dd03e28ae176dcb55cb
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 #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;
166 break;
167 case DAT_CAPABILITY:
168 switch (MSG)
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;
194 break;
196 case DAT_EVENT:
197 if (MSG == MSG_PROCESSEVENT)
198 twRC = SANE_ProcessEvent (pOrigin, pData);
199 else
201 activeDS.twCC = TWCC_CAPBADOPERATION;
202 twRC = TWRC_FAILURE;
204 break;
206 case DAT_PENDINGXFERS:
207 switch (MSG)
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;
222 break;
224 case DAT_SETUPMEMXFER:
225 if (MSG == MSG_GET)
226 twRC = SANE_SetupMemXferGet (pOrigin, pData);
227 else
229 activeDS.twCC = TWCC_CAPBADOPERATION;
230 twRC = TWRC_FAILURE;
232 break;
234 case DAT_STATUS:
235 if (MSG == MSG_GET)
236 twRC = SANE_GetDSStatus (pOrigin, pData);
237 else
239 activeDS.twCC = TWCC_CAPBADOPERATION;
240 twRC = TWRC_FAILURE;
242 break;
244 case DAT_USERINTERFACE:
245 switch (MSG)
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;
261 break;
263 case DAT_XFERGROUP:
264 switch (MSG)
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;
277 break;
279 default:
280 WARN("code unsupported: %d\n", DAT);
281 activeDS.twCC = TWCC_CAPUNSUPPORTED;
282 twRC = TWRC_FAILURE;
283 break;
286 return twRC;
290 static TW_UINT16 SANE_ImageGroupHandler (
291 pTW_IDENTITY pOrigin,
292 TW_UINT16 DAT,
293 TW_UINT16 MSG,
294 TW_MEMREF pData)
296 TW_UINT16 twRC = TWRC_SUCCESS;
298 switch (DAT)
300 case DAT_IMAGEINFO:
301 if (MSG == MSG_GET)
302 twRC = SANE_ImageInfoGet (pOrigin, pData);
303 else
305 activeDS.twCC = TWCC_CAPBADOPERATION;
306 twRC = TWRC_FAILURE;
308 break;
310 case DAT_IMAGELAYOUT:
311 switch (MSG)
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;
331 break;
333 case DAT_IMAGEMEMXFER:
334 if (MSG == MSG_GET)
335 twRC = SANE_ImageMemXferGet (pOrigin, pData);
336 else
338 activeDS.twCC = TWCC_CAPBADOPERATION;
339 twRC = TWRC_FAILURE;
341 break;
343 case DAT_IMAGENATIVEXFER:
344 if (MSG == MSG_GET)
345 twRC = SANE_ImageNativeXferGet (pOrigin, pData);
346 else
348 activeDS.twCC = TWCC_CAPBADOPERATION;
349 twRC = TWRC_FAILURE;
351 break;
353 default:
354 twRC = TWRC_FAILURE;
355 activeDS.twCC = TWCC_CAPUNSUPPORTED;
356 WARN("unsupported DG type %d\n", DAT);
357 break;
359 return twRC;
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)
370 TW_UINT16 twRC = TWRC_SUCCESS; /* Return Code */
372 TRACE("(DG=%d DAT=%d MSG=%d)\n", DG, DAT, MSG);
374 switch (DG)
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;
392 return twRC;
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)
402 const char *p;
403 int signature = 0;
405 if (strlen(in) <= outsize - 1)
407 strcpy(out, in);
408 return;
411 for (p = in; *p; p++)
412 signature += *p;
414 p = strrchr(in, ':');
415 if (!p)
416 p = in;
417 else
418 p++;
420 if (strlen(p) > outsize - 7 - 1)
421 p += strlen(p) - (outsize - 7 - 1);
423 strcpy(out, p);
424 sprintf(out + strlen(out), "(%04X)", signature % 0x10000);
428 static const SANE_Device **sane_devlist;
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;
438 static TW_UINT16
439 SANE_GetIdentity( pTW_IDENTITY pOrigin, pTW_IDENTITY self) {
440 static int cursanedev = 0;
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++;
453 if (!sane_devlist[cursanedev] ||
454 !sane_devlist[cursanedev]->model ||
455 !sane_devlist[cursanedev]->vendor ||
456 !sane_devlist[cursanedev]->name
458 cursanedev = 0; /* wrap to begin */
459 return TWRC_SUCCESS;
462 static TW_UINT16 SANE_OpenDS( pTW_IDENTITY pOrigin, pTW_IDENTITY self) {
463 SANE_Status status;
464 int i;
466 detect_sane_devices();
467 if (!sane_devlist[0]) {
468 ERR("No scanners? We should not get to OpenDS?\n");
469 return TWRC_FAILURE;
472 for (i=0; sane_devlist[i] && sane_devlist[i]->model; i++) {
473 TW_STR32 name;
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;
487 if (!sane_devlist[i]) {
488 WARN("Scanner not found.\n");
489 return TWRC_FAILURE;
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;
498 else
499 psane_close(activeDS.deviceHandle);
501 else
502 ERR("sane_open(%s): %s\n", sane_devlist[i]->name, psane_strstatus (status));
503 return TWRC_FAILURE;
505 #endif