user32: Check the DpiScalingVer registry key to enable DPI scaling.
[wine.git] / dlls / sane.ds / sane_main.c
blob7af0a2321ace9ece9658dbf07795c0ff5c7299ee
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 DSMENTRYPROC SANE_dsmentry;
35 #ifdef SONAME_LIBSANE
37 HINSTANCE SANE_instance;
39 static void *libsane_handle;
41 static void close_libsane(void *h)
43 if (h)
44 wine_dlclose(h, NULL, 0);
47 static void *open_libsane(void)
49 void *h;
51 h = wine_dlopen(SONAME_LIBSANE, RTLD_GLOBAL | RTLD_NOW, NULL, 0);
52 if (!h)
54 WARN("dlopen(%s) failed\n", SONAME_LIBSANE);
55 return NULL;
58 #define LOAD_FUNCPTR(f) \
59 if((p##f = wine_dlsym(h, #f, NULL, 0)) == NULL) { \
60 close_libsane(h); \
61 ERR("Could not dlsym %s\n", #f); \
62 return NULL; \
65 LOAD_FUNCPTR(sane_init)
66 LOAD_FUNCPTR(sane_exit)
67 LOAD_FUNCPTR(sane_get_devices)
68 LOAD_FUNCPTR(sane_open)
69 LOAD_FUNCPTR(sane_close)
70 LOAD_FUNCPTR(sane_get_option_descriptor)
71 LOAD_FUNCPTR(sane_control_option)
72 LOAD_FUNCPTR(sane_get_parameters)
73 LOAD_FUNCPTR(sane_start)
74 LOAD_FUNCPTR(sane_read)
75 LOAD_FUNCPTR(sane_cancel)
76 LOAD_FUNCPTR(sane_set_io_mode)
77 LOAD_FUNCPTR(sane_get_select_fd)
78 LOAD_FUNCPTR(sane_strstatus)
79 #undef LOAD_FUNCPTR
81 return h;
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 SANE_Int version_code;
93 libsane_handle = open_libsane();
94 if (! libsane_handle)
95 return FALSE;
97 psane_init (&version_code, NULL);
98 SANE_instance = hinstDLL;
99 DisableThreadLibraryCalls(hinstDLL);
100 break;
102 case DLL_PROCESS_DETACH:
103 if (lpvReserved) break;
104 TRACE("calling sane_exit()\n");
105 psane_exit ();
106 close_libsane(libsane_handle);
107 break;
110 return TRUE;
113 static TW_UINT16 SANE_GetIdentity( pTW_IDENTITY, pTW_IDENTITY);
114 static TW_UINT16 SANE_OpenDS( pTW_IDENTITY, pTW_IDENTITY);
116 #endif /* SONAME_LIBSANE */
118 static TW_UINT16 SANE_SetEntryPoint (pTW_IDENTITY pOrigin, TW_MEMREF pData);
120 static TW_UINT16 SANE_SourceControlHandler (
121 pTW_IDENTITY pOrigin,
122 TW_UINT16 DAT,
123 TW_UINT16 MSG,
124 TW_MEMREF pData)
126 TW_UINT16 twRC = TWRC_SUCCESS;
128 switch (DAT)
130 case DAT_IDENTITY:
131 switch (MSG)
133 case MSG_CLOSEDS:
134 #ifdef SONAME_LIBSANE
135 psane_close (activeDS.deviceHandle);
136 #else
137 twRC = TWRC_FAILURE;
138 activeDS.twCC = TWCC_CAPUNSUPPORTED;
139 #endif
140 break;
141 case MSG_OPENDS:
142 #ifdef SONAME_LIBSANE
143 twRC = SANE_OpenDS( pOrigin, (pTW_IDENTITY)pData);
144 #else
145 twRC = TWRC_FAILURE;
146 activeDS.twCC = TWCC_CAPUNSUPPORTED;
147 #endif
148 break;
149 case MSG_GET:
150 #ifdef SONAME_LIBSANE
151 twRC = SANE_GetIdentity( pOrigin, (pTW_IDENTITY)pData);
152 #else
153 twRC = TWRC_FAILURE;
154 activeDS.twCC = TWCC_CAPUNSUPPORTED;
155 #endif
156 break;
158 break;
159 case DAT_CAPABILITY:
160 switch (MSG)
162 case MSG_GET:
163 twRC = SANE_CapabilityGet (pOrigin, pData);
164 break;
165 case MSG_GETCURRENT:
166 twRC = SANE_CapabilityGetCurrent (pOrigin, pData);
167 break;
168 case MSG_GETDEFAULT:
169 twRC = SANE_CapabilityGetDefault (pOrigin, pData);
170 break;
171 case MSG_QUERYSUPPORT:
172 twRC = SANE_CapabilityQuerySupport (pOrigin, pData);
173 break;
174 case MSG_RESET:
175 twRC = SANE_CapabilityReset (pOrigin, pData);
176 break;
177 case MSG_SET:
178 twRC = SANE_CapabilitySet (pOrigin, pData);
179 break;
180 default:
181 twRC = TWRC_FAILURE;
182 activeDS.twCC = TWCC_CAPBADOPERATION;
183 FIXME("unrecognized operation triplet\n");
184 break;
186 break;
188 case DAT_ENTRYPOINT:
189 if (MSG == MSG_SET)
190 twRC = SANE_SetEntryPoint (pOrigin, pData);
191 else
193 twRC = TWRC_FAILURE;
194 activeDS.twCC = TWCC_CAPBADOPERATION;
195 FIXME("unrecognized operation triplet\n");
197 break;
199 case DAT_EVENT:
200 if (MSG == MSG_PROCESSEVENT)
201 twRC = SANE_ProcessEvent (pOrigin, pData);
202 else
204 activeDS.twCC = TWCC_CAPBADOPERATION;
205 twRC = TWRC_FAILURE;
207 break;
209 case DAT_PENDINGXFERS:
210 switch (MSG)
212 case MSG_ENDXFER:
213 twRC = SANE_PendingXfersEndXfer (pOrigin, pData);
214 break;
215 case MSG_GET:
216 twRC = SANE_PendingXfersGet (pOrigin, pData);
217 break;
218 case MSG_RESET:
219 twRC = SANE_PendingXfersReset (pOrigin, pData);
220 break;
221 default:
222 activeDS.twCC = TWCC_CAPBADOPERATION;
223 twRC = TWRC_FAILURE;
225 break;
227 case DAT_SETUPMEMXFER:
228 if (MSG == MSG_GET)
229 twRC = SANE_SetupMemXferGet (pOrigin, pData);
230 else
232 activeDS.twCC = TWCC_CAPBADOPERATION;
233 twRC = TWRC_FAILURE;
235 break;
237 case DAT_STATUS:
238 if (MSG == MSG_GET)
239 twRC = SANE_GetDSStatus (pOrigin, pData);
240 else
242 activeDS.twCC = TWCC_CAPBADOPERATION;
243 twRC = TWRC_FAILURE;
245 break;
247 case DAT_USERINTERFACE:
248 switch (MSG)
250 case MSG_DISABLEDS:
251 twRC = SANE_DisableDSUserInterface (pOrigin, pData);
252 break;
253 case MSG_ENABLEDS:
254 twRC = SANE_EnableDSUserInterface (pOrigin, pData);
255 break;
256 case MSG_ENABLEDSUIONLY:
257 twRC = SANE_EnableDSUIOnly (pOrigin, pData);
258 break;
259 default:
260 activeDS.twCC = TWCC_CAPBADOPERATION;
261 twRC = TWRC_FAILURE;
262 break;
264 break;
266 case DAT_XFERGROUP:
267 switch (MSG)
269 case MSG_GET:
270 twRC = SANE_XferGroupGet (pOrigin, pData);
271 break;
272 case MSG_SET:
273 twRC = SANE_XferGroupSet (pOrigin, pData);
274 break;
275 default:
276 activeDS.twCC = TWCC_CAPBADOPERATION;
277 twRC = TWRC_FAILURE;
278 break;
280 break;
282 default:
283 WARN("code unsupported: %d\n", DAT);
284 activeDS.twCC = TWCC_CAPUNSUPPORTED;
285 twRC = TWRC_FAILURE;
286 break;
289 return twRC;
293 static TW_UINT16 SANE_ImageGroupHandler (
294 pTW_IDENTITY pOrigin,
295 TW_UINT16 DAT,
296 TW_UINT16 MSG,
297 TW_MEMREF pData)
299 TW_UINT16 twRC = TWRC_SUCCESS;
301 switch (DAT)
303 case DAT_IMAGEINFO:
304 if (MSG == MSG_GET)
305 twRC = SANE_ImageInfoGet (pOrigin, pData);
306 else
308 activeDS.twCC = TWCC_CAPBADOPERATION;
309 twRC = TWRC_FAILURE;
311 break;
313 case DAT_IMAGELAYOUT:
314 switch (MSG)
316 case MSG_GET:
317 twRC = SANE_ImageLayoutGet (pOrigin, pData);
318 break;
319 case MSG_GETDEFAULT:
320 twRC = SANE_ImageLayoutGetDefault (pOrigin, pData);
321 break;
322 case MSG_RESET:
323 twRC = SANE_ImageLayoutReset (pOrigin, pData);
324 break;
325 case MSG_SET:
326 twRC = SANE_ImageLayoutSet (pOrigin, pData);
327 break;
328 default:
329 twRC = TWRC_FAILURE;
330 activeDS.twCC = TWCC_CAPBADOPERATION;
331 ERR("unrecognized operation triplet\n");
332 break;
334 break;
336 case DAT_IMAGEMEMXFER:
337 if (MSG == MSG_GET)
338 twRC = SANE_ImageMemXferGet (pOrigin, pData);
339 else
341 activeDS.twCC = TWCC_CAPBADOPERATION;
342 twRC = TWRC_FAILURE;
344 break;
346 case DAT_IMAGENATIVEXFER:
347 if (MSG == MSG_GET)
348 twRC = SANE_ImageNativeXferGet (pOrigin, pData);
349 else
351 activeDS.twCC = TWCC_CAPBADOPERATION;
352 twRC = TWRC_FAILURE;
354 break;
356 default:
357 twRC = TWRC_FAILURE;
358 activeDS.twCC = TWCC_CAPUNSUPPORTED;
359 WARN("unsupported DG type %d\n", DAT);
360 break;
362 return twRC;
365 /* Main entry point for the TWAIN library */
366 TW_UINT16 WINAPI
367 DS_Entry ( pTW_IDENTITY pOrigin,
368 TW_UINT32 DG,
369 TW_UINT16 DAT,
370 TW_UINT16 MSG,
371 TW_MEMREF pData)
373 TW_UINT16 twRC = TWRC_SUCCESS; /* Return Code */
375 TRACE("(DG=%d DAT=%d MSG=%d)\n", DG, DAT, MSG);
377 switch (DG)
379 case DG_CONTROL:
380 twRC = SANE_SourceControlHandler (pOrigin,DAT,MSG,pData);
381 break;
382 case DG_IMAGE:
383 twRC = SANE_ImageGroupHandler (pOrigin,DAT,MSG,pData);
384 break;
385 case DG_AUDIO:
386 WARN("Audio group of controls not implemented yet.\n");
387 twRC = TWRC_FAILURE;
388 activeDS.twCC = TWCC_CAPUNSUPPORTED;
389 break;
390 default:
391 activeDS.twCC = TWCC_BADPROTOCOL;
392 twRC = TWRC_FAILURE;
395 return twRC;
398 void SANE_Notify (TW_UINT16 message)
400 SANE_dsmentry (&activeDS.identity, &activeDS.appIdentity, DG_CONTROL, DAT_NULL, message, NULL);
403 /* DG_CONTROL/DAT_ENTRYPOINT/MSG_SET */
404 TW_UINT16 SANE_SetEntryPoint (pTW_IDENTITY pOrigin, TW_MEMREF pData)
406 TW_ENTRYPOINT *entry = (TW_ENTRYPOINT*)pData;
408 SANE_dsmentry = entry->DSM_Entry;
410 return TWRC_SUCCESS;
413 #ifdef SONAME_LIBSANE
414 /* Sane returns device names that are longer than the 32 bytes allowed
415 by TWAIN. However, it colon separates them, and the last bit is
416 the most interesting. So we use the last bit, and add a signature
417 to ensure uniqueness */
418 static void copy_sane_short_name(const char *in, char *out, size_t outsize)
420 const char *p;
421 int signature = 0;
423 if (strlen(in) <= outsize - 1)
425 strcpy(out, in);
426 return;
429 for (p = in; *p; p++)
430 signature += *p;
432 p = strrchr(in, ':');
433 if (!p)
434 p = in;
435 else
436 p++;
438 if (strlen(p) > outsize - 7 - 1)
439 p += strlen(p) - (outsize - 7 - 1);
441 strcpy(out, p);
442 sprintf(out + strlen(out), "(%04X)", signature % 0x10000);
446 static const SANE_Device **sane_devlist;
448 static void
449 detect_sane_devices(void) {
450 if (sane_devlist && sane_devlist[0]) return;
451 TRACE("detecting sane...\n");
452 if (psane_get_devices (&sane_devlist, SANE_FALSE) != SANE_STATUS_GOOD)
453 return;
456 static TW_UINT16
457 SANE_GetIdentity( pTW_IDENTITY pOrigin, pTW_IDENTITY self) {
458 static int cursanedev = 0;
460 detect_sane_devices();
461 if (!sane_devlist[cursanedev])
462 return TWRC_FAILURE;
463 self->ProtocolMajor = TWON_PROTOCOLMAJOR;
464 self->ProtocolMinor = TWON_PROTOCOLMINOR;
465 self->SupportedGroups = DG_CONTROL | DG_IMAGE | DF_DS2;
466 copy_sane_short_name(sane_devlist[cursanedev]->name, self->ProductName, sizeof(self->ProductName) - 1);
467 lstrcpynA (self->Manufacturer, sane_devlist[cursanedev]->vendor, sizeof(self->Manufacturer) - 1);
468 lstrcpynA (self->ProductFamily, sane_devlist[cursanedev]->model, sizeof(self->ProductFamily) - 1);
469 cursanedev++;
471 if (!sane_devlist[cursanedev] ||
472 !sane_devlist[cursanedev]->model ||
473 !sane_devlist[cursanedev]->vendor ||
474 !sane_devlist[cursanedev]->name
476 cursanedev = 0; /* wrap to begin */
477 return TWRC_SUCCESS;
480 static TW_UINT16 SANE_OpenDS( pTW_IDENTITY pOrigin, pTW_IDENTITY self) {
481 SANE_Status status;
482 int i;
484 if (SANE_dsmentry == NULL)
486 static const WCHAR twain32W[] = {'t','w','a','i','n','_','3','2',0};
487 HMODULE moddsm = GetModuleHandleW(twain32W);
489 if (moddsm)
490 SANE_dsmentry = (void*)GetProcAddress(moddsm, "DSM_Entry");
492 if (!SANE_dsmentry)
494 ERR("can't find DSM entry point\n");
495 return TWRC_FAILURE;
499 detect_sane_devices();
500 if (!sane_devlist[0]) {
501 ERR("No scanners? We should not get to OpenDS?\n");
502 return TWRC_FAILURE;
505 for (i=0; sane_devlist[i] && sane_devlist[i]->model; i++) {
506 TW_STR32 name;
508 /* To make string as short as above */
509 lstrcpynA(name, sane_devlist[i]->vendor, sizeof(name)-1);
510 if (*self->Manufacturer && strcmp(name, self->Manufacturer))
511 continue;
512 lstrcpynA(name, sane_devlist[i]->model, sizeof(name)-1);
513 if (*self->ProductFamily && strcmp(name, self->ProductFamily))
514 continue;
515 copy_sane_short_name(sane_devlist[i]->name, name, sizeof(name) - 1);
516 if (*self->ProductName && strcmp(name, self->ProductName))
517 continue;
518 break;
520 if (!sane_devlist[i]) {
521 WARN("Scanner not found.\n");
522 return TWRC_FAILURE;
524 status = psane_open(sane_devlist[i]->name,&activeDS.deviceHandle);
525 if (status == SANE_STATUS_GOOD) {
526 activeDS.twCC = SANE_SaneSetDefaults();
527 if (activeDS.twCC == TWCC_SUCCESS) {
528 activeDS.currentState = 4;
529 activeDS.identity.Id = self->Id;
530 activeDS.appIdentity = *pOrigin;
531 return TWRC_SUCCESS;
533 else
534 psane_close(activeDS.deviceHandle);
536 else
537 ERR("sane_open(%s): %s\n", sane_devlist[i]->name, psane_strstatus (status));
538 return TWRC_FAILURE;
540 #endif