winepulse v17: Fix winmm tests
[wine/multimedia.git] / dlls / sane.ds / sane_main.c
blob1c73252ab62dd96f4152476d0be95da0ea739845
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 "sane_i.h"
28 #include "wine/debug.h"
29 #include "wine/library.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(twain);
33 HINSTANCE SANE_instance;
35 #ifdef SONAME_LIBSANE
37 static void *libsane_handle;
39 static void close_libsane(void *h)
41 if (h)
42 wine_dlclose(h, NULL, 0);
45 static void *open_libsane(void)
47 void *h;
49 h = wine_dlopen(SONAME_LIBSANE, RTLD_GLOBAL | RTLD_NOW, NULL, 0);
50 if (!h)
52 WARN("dlopen(%s) failed\n", SONAME_LIBSANE);
53 return NULL;
56 #define LOAD_FUNCPTR(f) \
57 if((p##f = wine_dlsym(h, #f, NULL, 0)) == NULL) { \
58 close_libsane(h); \
59 ERR("Could not dlsym %s\n", #f); \
60 return NULL; \
63 LOAD_FUNCPTR(sane_init)
64 LOAD_FUNCPTR(sane_exit)
65 LOAD_FUNCPTR(sane_get_devices)
66 LOAD_FUNCPTR(sane_open)
67 LOAD_FUNCPTR(sane_close)
68 LOAD_FUNCPTR(sane_get_option_descriptor)
69 LOAD_FUNCPTR(sane_control_option)
70 LOAD_FUNCPTR(sane_get_parameters)
71 LOAD_FUNCPTR(sane_start)
72 LOAD_FUNCPTR(sane_read)
73 LOAD_FUNCPTR(sane_cancel)
74 LOAD_FUNCPTR(sane_set_io_mode)
75 LOAD_FUNCPTR(sane_get_select_fd)
76 LOAD_FUNCPTR(sane_strstatus)
77 #undef LOAD_FUNCPTR
79 return h;
82 #endif /* SONAME_LIBSANE */
84 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
86 TRACE("%p,%x,%p\n", hinstDLL, fdwReason, lpvReserved);
88 switch (fdwReason)
90 case DLL_PROCESS_ATTACH: {
91 #ifdef SONAME_LIBSANE
92 SANE_Int version_code;
94 libsane_handle = open_libsane();
95 if (! libsane_handle)
96 return FALSE;
98 psane_init (&version_code, NULL);
99 #endif
100 SANE_instance = hinstDLL;
101 DisableThreadLibraryCalls(hinstDLL);
102 break;
104 case DLL_PROCESS_DETACH:
105 #ifdef SONAME_LIBSANE
106 TRACE("calling sane_exit()\n");
107 psane_exit ();
109 close_libsane(libsane_handle);
110 libsane_handle = NULL;
111 #endif
112 SANE_instance = NULL;
113 break;
116 return TRUE;
119 #ifdef SONAME_LIBSANE
120 static TW_UINT16 SANE_GetIdentity( pTW_IDENTITY, pTW_IDENTITY);
121 static TW_UINT16 SANE_OpenDS( pTW_IDENTITY, pTW_IDENTITY);
122 #endif
124 static TW_UINT16 SANE_SourceControlHandler (
125 pTW_IDENTITY pOrigin,
126 TW_UINT16 DAT,
127 TW_UINT16 MSG,
128 TW_MEMREF pData)
130 TW_UINT16 twRC = TWRC_SUCCESS;
132 switch (DAT)
134 case DAT_IDENTITY:
135 switch (MSG)
137 case MSG_CLOSEDS:
138 #ifdef SONAME_LIBSANE
139 psane_close (activeDS.deviceHandle);
140 #else
141 twRC = TWRC_FAILURE;
142 activeDS.twCC = TWCC_CAPUNSUPPORTED;
143 #endif
144 break;
145 case MSG_OPENDS:
146 #ifdef SONAME_LIBSANE
147 twRC = SANE_OpenDS( pOrigin, (pTW_IDENTITY)pData);
148 #else
149 twRC = TWRC_FAILURE;
150 activeDS.twCC = TWCC_CAPUNSUPPORTED;
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 activeDS.twCC = TWCC_CAPUNSUPPORTED;
159 #endif
160 break;
162 break;
163 case DAT_CAPABILITY:
164 switch (MSG)
166 case MSG_GET:
167 twRC = SANE_CapabilityGet (pOrigin, pData);
168 break;
169 case MSG_GETCURRENT:
170 twRC = SANE_CapabilityGetCurrent (pOrigin, pData);
171 break;
172 case MSG_GETDEFAULT:
173 twRC = SANE_CapabilityGetDefault (pOrigin, pData);
174 break;
175 case MSG_QUERYSUPPORT:
176 twRC = SANE_CapabilityQuerySupport (pOrigin, pData);
177 break;
178 case MSG_RESET:
179 twRC = SANE_CapabilityReset (pOrigin, pData);
180 break;
181 case MSG_SET:
182 twRC = SANE_CapabilitySet (pOrigin, pData);
183 break;
184 default:
185 twRC = TWRC_FAILURE;
186 activeDS.twCC = TWCC_CAPBADOPERATION;
187 FIXME("unrecognized opertion triplet\n");
188 break;
190 break;
192 case DAT_EVENT:
193 if (MSG == MSG_PROCESSEVENT)
194 twRC = SANE_ProcessEvent (pOrigin, pData);
195 else
197 activeDS.twCC = TWCC_CAPBADOPERATION;
198 twRC = TWRC_FAILURE;
200 break;
202 case DAT_PENDINGXFERS:
203 switch (MSG)
205 case MSG_ENDXFER:
206 twRC = SANE_PendingXfersEndXfer (pOrigin, pData);
207 break;
208 case MSG_GET:
209 twRC = SANE_PendingXfersGet (pOrigin, pData);
210 break;
211 case MSG_RESET:
212 twRC = SANE_PendingXfersReset (pOrigin, pData);
213 break;
214 default:
215 activeDS.twCC = TWCC_CAPBADOPERATION;
216 twRC = TWRC_FAILURE;
218 break;
220 case DAT_SETUPMEMXFER:
221 if (MSG == MSG_GET)
222 twRC = SANE_SetupMemXferGet (pOrigin, pData);
223 else
225 activeDS.twCC = TWCC_CAPBADOPERATION;
226 twRC = TWRC_FAILURE;
228 break;
230 case DAT_STATUS:
231 if (MSG == MSG_GET)
232 twRC = SANE_GetDSStatus (pOrigin, pData);
233 else
235 activeDS.twCC = TWCC_CAPBADOPERATION;
236 twRC = TWRC_FAILURE;
238 break;
240 case DAT_USERINTERFACE:
241 switch (MSG)
243 case MSG_DISABLEDS:
244 twRC = SANE_DisableDSUserInterface (pOrigin, pData);
245 break;
246 case MSG_ENABLEDS:
247 twRC = SANE_EnableDSUserInterface (pOrigin, pData);
248 break;
249 case MSG_ENABLEDSUIONLY:
250 twRC = SANE_EnableDSUIOnly (pOrigin, pData);
251 break;
252 default:
253 activeDS.twCC = TWCC_CAPBADOPERATION;
254 twRC = TWRC_FAILURE;
255 break;
257 break;
259 case DAT_XFERGROUP:
260 switch (MSG)
262 case MSG_GET:
263 twRC = SANE_XferGroupGet (pOrigin, pData);
264 break;
265 case MSG_SET:
266 twRC = SANE_XferGroupSet (pOrigin, pData);
267 break;
268 default:
269 activeDS.twCC = TWCC_CAPBADOPERATION;
270 twRC = TWRC_FAILURE;
271 break;
273 break;
275 default:
276 WARN("code unsupported: %d\n", DAT);
277 activeDS.twCC = TWCC_CAPUNSUPPORTED;
278 twRC = TWRC_FAILURE;
279 break;
282 return twRC;
286 static TW_UINT16 SANE_ImageGroupHandler (
287 pTW_IDENTITY pOrigin,
288 TW_UINT16 DAT,
289 TW_UINT16 MSG,
290 TW_MEMREF pData)
292 TW_UINT16 twRC = TWRC_SUCCESS;
294 switch (DAT)
296 case DAT_IMAGEINFO:
297 if (MSG == MSG_GET)
298 twRC = SANE_ImageInfoGet (pOrigin, pData);
299 else
301 activeDS.twCC = TWCC_CAPBADOPERATION;
302 twRC = TWRC_FAILURE;
304 break;
306 case DAT_IMAGELAYOUT:
307 switch (MSG)
309 case MSG_GET:
310 twRC = SANE_ImageLayoutGet (pOrigin, pData);
311 break;
312 case MSG_GETDEFAULT:
313 twRC = SANE_ImageLayoutGetDefault (pOrigin, pData);
314 break;
315 case MSG_RESET:
316 twRC = SANE_ImageLayoutReset (pOrigin, pData);
317 break;
318 case MSG_SET:
319 twRC = SANE_ImageLayoutSet (pOrigin, pData);
320 break;
321 default:
322 twRC = TWRC_FAILURE;
323 activeDS.twCC = TWCC_CAPBADOPERATION;
324 ERR("unrecognized operation triplet\n");
325 break;
327 break;
329 case DAT_IMAGEMEMXFER:
330 if (MSG == MSG_GET)
331 twRC = SANE_ImageMemXferGet (pOrigin, pData);
332 else
334 activeDS.twCC = TWCC_CAPBADOPERATION;
335 twRC = TWRC_FAILURE;
337 break;
339 case DAT_IMAGENATIVEXFER:
340 if (MSG == MSG_GET)
341 twRC = SANE_ImageNativeXferGet (pOrigin, pData);
342 else
344 activeDS.twCC = TWCC_CAPBADOPERATION;
345 twRC = TWRC_FAILURE;
347 break;
349 default:
350 twRC = TWRC_FAILURE;
351 activeDS.twCC = TWCC_CAPUNSUPPORTED;
352 WARN("unsupported DG type %d\n", DAT);
353 break;
355 return twRC;
358 /* Main entry point for the TWAIN library */
359 TW_UINT16 WINAPI
360 DS_Entry ( pTW_IDENTITY pOrigin,
361 TW_UINT32 DG,
362 TW_UINT16 DAT,
363 TW_UINT16 MSG,
364 TW_MEMREF pData)
366 TW_UINT16 twRC = TWRC_SUCCESS; /* Return Code */
368 TRACE("(DG=%d DAT=%d MSG=%d)\n", DG, DAT, MSG);
370 switch (DG)
372 case DG_CONTROL:
373 twRC = SANE_SourceControlHandler (pOrigin,DAT,MSG,pData);
374 break;
375 case DG_IMAGE:
376 twRC = SANE_ImageGroupHandler (pOrigin,DAT,MSG,pData);
377 break;
378 case DG_AUDIO:
379 WARN("Audio group of controls not implemented yet.\n");
380 twRC = TWRC_FAILURE;
381 activeDS.twCC = TWCC_CAPUNSUPPORTED;
382 break;
383 default:
384 activeDS.twCC = TWCC_BADPROTOCOL;
385 twRC = TWRC_FAILURE;
388 return twRC;
391 #ifdef SONAME_LIBSANE
392 /* Sane returns device names that are longer than the 32 bytes allowed
393 by TWAIN. However, it colon separates them, and the last bit is
394 the most interesting. So we use the last bit, and add a signature
395 to ensure uniqueness */
396 static void copy_sane_short_name(const char *in, char *out, size_t outsize)
398 const char *p;
399 int signature = 0;
401 if (strlen(in) <= outsize - 1)
403 strcpy(out, in);
404 return;
407 for (p = in; *p; p++)
408 signature += *p;
410 p = strrchr(in, ':');
411 if (!p)
412 p = in;
413 else
414 p++;
416 if (strlen(p) > outsize - 7 - 1)
417 p += strlen(p) - (outsize - 7 - 1);
419 strcpy(out, p);
420 sprintf(out + strlen(out), "(%04X)", signature % 0x10000);
424 static const SANE_Device **sane_devlist;
426 static void
427 detect_sane_devices(void) {
428 if (sane_devlist && sane_devlist[0]) return;
429 TRACE("detecting sane...\n");
430 if (psane_get_devices (&sane_devlist, SANE_FALSE) != SANE_STATUS_GOOD)
431 return;
434 static TW_UINT16
435 SANE_GetIdentity( pTW_IDENTITY pOrigin, pTW_IDENTITY self) {
436 static int cursanedev = 0;
438 detect_sane_devices();
439 if (!sane_devlist[cursanedev])
440 return TWRC_FAILURE;
441 self->ProtocolMajor = TWON_PROTOCOLMAJOR;
442 self->ProtocolMinor = TWON_PROTOCOLMINOR;
443 self->SupportedGroups = DG_CONTROL | DG_IMAGE;
444 copy_sane_short_name(sane_devlist[cursanedev]->name, self->ProductName, sizeof(self->ProductName) - 1);
445 lstrcpynA (self->Manufacturer, sane_devlist[cursanedev]->vendor, sizeof(self->Manufacturer) - 1);
446 lstrcpynA (self->ProductFamily, sane_devlist[cursanedev]->model, sizeof(self->ProductFamily) - 1);
447 cursanedev++;
449 if (!sane_devlist[cursanedev] ||
450 !sane_devlist[cursanedev]->model ||
451 !sane_devlist[cursanedev]->vendor ||
452 !sane_devlist[cursanedev]->name
454 cursanedev = 0; /* wrap to begin */
455 return TWRC_SUCCESS;
458 static TW_UINT16 SANE_OpenDS( pTW_IDENTITY pOrigin, pTW_IDENTITY self) {
459 SANE_Status status;
460 int i;
462 detect_sane_devices();
463 if (!sane_devlist[0]) {
464 ERR("No scanners? We should not get to OpenDS?\n");
465 return TWRC_FAILURE;
468 for (i=0; sane_devlist[i] && sane_devlist[i]->model; i++) {
469 TW_STR32 name;
471 /* To make string as short as above */
472 lstrcpynA(name, sane_devlist[i]->vendor, sizeof(name)-1);
473 if (*self->Manufacturer && strcmp(name, self->Manufacturer))
474 continue;
475 lstrcpynA(name, sane_devlist[i]->model, sizeof(name)-1);
476 if (*self->ProductFamily && strcmp(name, self->ProductFamily))
477 continue;
478 copy_sane_short_name(sane_devlist[i]->name, name, sizeof(name) - 1);
479 if (*self->ProductName && strcmp(name, self->ProductName))
480 continue;
481 break;
483 if (!sane_devlist[i]) {
484 WARN("Scanner not found.\n");
485 return TWRC_FAILURE;
487 status = psane_open(sane_devlist[i]->name,&activeDS.deviceHandle);
488 if (status == SANE_STATUS_GOOD) {
489 activeDS.twCC = SANE_SaneSetDefaults();
490 if (activeDS.twCC == TWCC_SUCCESS) {
491 activeDS.currentState = 4;
492 return TWRC_SUCCESS;
494 else
495 psane_close(activeDS.deviceHandle);
497 else
498 ERR("sane_open(%s): %s\n", sane_devlist[i]->name, psane_strstatus (status));
499 return TWRC_FAILURE;
501 #endif