push 8079c4124d1355f652d7dbd6f1862eb95d83e2de
[wine/hacks.git] / dlls / twain_32 / tests / dsm.c
blob4218f25fe1b881b485534bd5e4fb4b87a9592aa0
1 /* Unit test suite for Twain DSM functions
3 * Copyright 2009 Jeremy White, CodeWeavers, Inc.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include <stdarg.h>
21 #include <assert.h>
22 #include "windef.h"
23 #include "winbase.h"
24 #include "wingdi.h"
25 #include "winerror.h"
26 #include "winuser.h"
27 #include "twain.h"
29 #include "wine/test.h"
31 static DSMENTRYPROC pDSM_Entry;
33 static BOOL dsm_RegisterWindowClasses(void)
35 WNDCLASSA cls;
37 cls.style = 0;
38 cls.lpfnWndProc = DefWindowProc;
39 cls.cbClsExtra = 0;
40 cls.cbWndExtra = 0;
41 cls.hInstance = GetModuleHandleA(0);
42 cls.hIcon = 0;
43 cls.hCursor = LoadCursorA(0, IDC_ARROW);
44 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
45 cls.lpszMenuName = NULL;
46 cls.lpszClassName = "TWAIN_dsm_class";
47 if (!RegisterClassA(&cls)) return FALSE;
49 return TRUE;
53 static void get_condition_code(TW_IDENTITY *appid, TW_IDENTITY *source, TW_STATUS *status)
55 TW_UINT16 rc;
56 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_STATUS, MSG_GET, status);
57 ok(rc == TWRC_SUCCESS, "Condition code not available, rc %d\n", rc);
60 static BOOL get_onevalue(TW_HANDLE hcontainer, TW_UINT32 *ret, TW_UINT16 *type)
62 TW_ONEVALUE *onev;
63 onev = GlobalLock(hcontainer);
64 if (onev)
66 *ret = onev->Item;
67 if (type)
68 *type = onev->ItemType;
69 GlobalUnlock(hcontainer);
70 return TRUE;
72 return FALSE;
75 static TW_HANDLE alloc_and_set_onevalue(TW_UINT32 val, TW_UINT16 type)
77 TW_HANDLE hcontainer;
78 TW_ONEVALUE *onev;
79 hcontainer = GlobalAlloc(0, sizeof(*onev));
80 if (hcontainer)
82 onev = GlobalLock(hcontainer);
83 if (onev)
85 onev->ItemType = type;
86 onev->Item = val;
87 GlobalUnlock(hcontainer);
89 else
91 GlobalFree(hcontainer);
92 hcontainer = 0;
95 return hcontainer;
98 static void check_get(TW_CAPABILITY *pCapability, TW_INT32 actual_support,
99 TW_UINT32 orig_value, TW_UINT32 default_value, TW_UINT32 *suggested_set_value)
101 void *p;
102 if (suggested_set_value)
103 *suggested_set_value = orig_value + 1;
104 p = GlobalLock(pCapability->hContainer);
105 if (p)
107 if (pCapability->ConType == TWON_ONEVALUE)
109 TW_ONEVALUE *onev = p;
110 ok(onev->Item == orig_value || !(actual_support & TWQC_GETCURRENT), "MSG_GET of 0x%x returned 0x%x, expecting 0x%x\n",
111 pCapability->Cap, onev->Item, orig_value);
112 trace("MSG_GET of 0x%x returned val 0x%x, type %d\n", pCapability->Cap, onev->Item, onev->ItemType);
113 if (suggested_set_value)
114 *suggested_set_value = onev->Item;
116 else if (pCapability->ConType == TWON_ENUMERATION)
118 int i;
119 TW_UINT8 *p8;
120 TW_UINT16 *p16;
121 TW_UINT32 *p32;
122 TW_ENUMERATION *enumv = p;
123 p8 = enumv->ItemList;
124 p16 = (TW_UINT16 *) p8;
125 p32 = (TW_UINT32 *) p8;
126 trace("MSG_GET of 0x%x returned %d items:\n", pCapability->Cap, enumv->NumItems);
127 for (i = 0; i < enumv->NumItems; i++)
129 if (enumv->ItemType == TWTY_UINT8 || enumv->ItemType == TWTY_INT8)
130 trace(" %d: 0x%x\n", i, p8[i]);
131 if (enumv->ItemType == TWTY_UINT16 || enumv->ItemType == TWTY_INT16)
132 trace(" %d: 0x%x\n", i, p16[i]);
133 if (enumv->ItemType == TWTY_UINT32 || enumv->ItemType == TWTY_INT32)
134 trace(" %d: 0x%x\n", i, p32[i]);
136 if (enumv->ItemType == TWTY_UINT16 || enumv->ItemType == TWTY_INT16)
138 ok(p16[enumv->CurrentIndex] == orig_value,
139 "Type 0x%x, values from MSG_GET (0x%x) and MSG_GETCURRENT (0x%x) do not match.\n",
140 pCapability->Cap, p16[enumv->CurrentIndex], orig_value);
141 ok(p16[enumv->DefaultIndex] == default_value,
142 "Type 0x%x, values from MSG_GET (0x%x) and MSG_GETDEFAULT (0x%x) do not match.\n",
143 pCapability->Cap, p16[enumv->DefaultIndex], default_value);
144 if (suggested_set_value)
145 *suggested_set_value = p16[(enumv->CurrentIndex + 1) % enumv->NumItems];
147 if (enumv->ItemType == TWTY_UINT32 || enumv->ItemType == TWTY_INT32)
149 ok(p32[enumv->CurrentIndex] == orig_value,
150 "Type 0x%x, values from MSG_GET (0x%x) and MSG_GETCURRENT (0x%x) do not match.\n",
151 pCapability->Cap, p32[enumv->CurrentIndex], orig_value);
152 ok(p32[enumv->DefaultIndex] == default_value,
153 "Type 0x%x, values from MSG_GET (0x%x) and MSG_GETDEFAULT (0x%x) do not match.\n",
154 pCapability->Cap, p32[enumv->DefaultIndex], default_value);
155 if (suggested_set_value)
156 *suggested_set_value = p32[(enumv->CurrentIndex + 1) % enumv->NumItems];
159 else
160 trace("MSG_GET on type 0x%x returned type 0x%x, which we didn't check.\n", pCapability->Cap, pCapability->ConType);
161 GlobalUnlock(pCapability->hContainer);
165 static void test_onevalue_cap(TW_IDENTITY *appid, TW_IDENTITY *source, TW_UINT16 captype, TW_UINT16 type, TW_INT32 minimum_support)
167 TW_UINT16 rc;
168 TW_UINT16 rtype;
169 TW_STATUS status;
170 TW_CAPABILITY cap;
171 TW_UINT32 orig_value = 0;
172 TW_UINT32 new_value;
173 TW_UINT32 default_value = 0;
174 TW_INT32 actual_support;
176 memset(&cap, 0, sizeof(cap));
177 cap.Cap = captype;
178 cap.ConType = TWON_DONTCARE16;
180 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_QUERYSUPPORT, &cap);
181 get_condition_code(appid, source, &status);
182 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
183 "Error [rc %d|cc %d] doing MSG_QUERYSUPPORT for type 0x%x\n", rc, status.ConditionCode, captype);
184 if (rc != TWRC_SUCCESS)
185 return;
186 ok(get_onevalue(cap.hContainer, (TW_UINT32 *) &actual_support, NULL), "Returned cap.hContainer invalid for QuerySupport on type 0x%x\n", captype);
187 ok((actual_support & minimum_support) == minimum_support,
188 "Error: minimum support 0x%x for type 0x%x, got 0x%x\n", minimum_support,
189 captype, actual_support);
192 if (actual_support & TWQC_GETCURRENT)
194 memset(&cap, 0, sizeof(cap));
195 cap.Cap = captype;
196 cap.ConType = TWON_DONTCARE16;
198 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GETCURRENT, &cap);
199 get_condition_code(appid, source, &status);
200 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
201 "Error [rc %d|cc %d] doing MSG_GETCURRENT for type 0x%x\n", rc, status.ConditionCode, captype);
202 if (rc == TWRC_SUCCESS)
204 ok(get_onevalue(cap.hContainer, &orig_value, &rtype), "Returned cap.hContainer invalid for GETCURRENT on type 0x%x\n", captype);
205 ok(rtype == type, "Returned GETCURRENT type 0x%x for cap 0x%x is not expected 0x%x\n", rtype, captype, type);
206 GlobalFree(cap.hContainer);
210 if (actual_support & TWQC_GETDEFAULT)
212 memset(&cap, 0, sizeof(cap));
213 cap.Cap = captype;
214 cap.ConType = TWON_DONTCARE16;
216 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GETDEFAULT, &cap);
217 get_condition_code(appid, source, &status);
218 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
219 "Error [rc %d|cc %d] doing MSG_GETDEFAULT for type 0x%x\n", rc, status.ConditionCode, captype);
220 if (rc == TWRC_SUCCESS)
222 ok(get_onevalue(cap.hContainer, &default_value, &rtype), "Returned cap.hContainer invalid for GETDEFAULT on type 0x%x\n", captype);
223 ok(rtype == type, "Returned GETDEFAULT type 0x%x for cap 0x%x is not expected 0x%x\n", rtype, captype, type);
224 GlobalFree(cap.hContainer);
228 new_value = orig_value;
229 if (actual_support & TWQC_GET)
231 memset(&cap, 0, sizeof(cap));
232 cap.Cap = captype;
233 cap.ConType = TWON_DONTCARE16;
235 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GET, &cap);
236 get_condition_code(appid, source, &status);
237 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
238 "Error [rc %d|cc %d] doing MSG_GET for type 0x%x\n", rc, status.ConditionCode, captype);
239 check_get(&cap, actual_support, orig_value, default_value, &new_value);
240 if (rc == TWRC_SUCCESS)
241 GlobalFree(cap.hContainer);
244 if (actual_support & TWQC_SET)
246 memset(&cap, 0, sizeof(cap));
247 cap.Cap = captype;
248 cap.ConType = TWON_ONEVALUE;
249 cap.hContainer = alloc_and_set_onevalue(new_value, type);
251 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_SET, &cap);
252 get_condition_code(appid, source, &status);
253 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
254 "Error [rc %d|cc %d] doing MSG_SET for type 0x%x\n", rc, status.ConditionCode, captype);
255 GlobalFree(cap.hContainer);
258 if (actual_support & TWQC_RESET)
260 memset(&cap, 0, sizeof(cap));
261 cap.Cap = captype;
262 cap.ConType = TWON_DONTCARE16;
264 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_RESET, &cap);
265 get_condition_code(appid, source, &status);
266 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
267 "Error [rc %d|cc %d] doing MSG_RESET for type 0x%x\n", rc, status.ConditionCode, captype);
268 if (rc == TWRC_SUCCESS)
269 GlobalFree(cap.hContainer);
273 static void test_resolution(TW_IDENTITY *appid, TW_IDENTITY *source, TW_UINT16 captype, TW_INT32 minimum_support)
275 TW_UINT16 rc;
276 TW_STATUS status;
277 TW_CAPABILITY cap;
278 TW_UINT32 val;
279 TW_UINT16 type;
280 TW_INT32 actual_support;
281 TW_FIX32 orig_value = { 0, 0 };
282 TW_UINT32 new_value = 0;
283 TW_FIX32 default_value = { 0, 0 };
285 memset(&cap, 0, sizeof(cap));
286 cap.Cap = captype;
287 cap.ConType = TWON_DONTCARE16;
289 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_QUERYSUPPORT, &cap);
290 get_condition_code(appid, source, &status);
291 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
292 "Error [rc %d|cc %d] doing MSG_QUERYSUPPORT for type 0x%x\n", rc, status.ConditionCode, captype);
293 if (rc != TWRC_SUCCESS)
294 return;
295 ok(get_onevalue(cap.hContainer, (TW_UINT32 *) &actual_support, NULL), "Returned cap.hContainer invalid for QuerySupport on type 0x%x\n", captype);
296 ok((actual_support & minimum_support) == minimum_support,
297 "Error: minimum support 0x%x for type 0x%x, got 0x%x\n", minimum_support,
298 captype, actual_support);
301 if (actual_support & TWQC_GETCURRENT)
303 memset(&cap, 0, sizeof(cap));
304 cap.Cap = captype;
305 cap.ConType = TWON_DONTCARE16;
307 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GETCURRENT, &cap);
308 get_condition_code(appid, source, &status);
309 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
310 "Error [rc %d|cc %d] doing MSG_GETCURRENT for type 0x%x\n", rc, status.ConditionCode, captype);
311 if (rc == TWRC_SUCCESS)
313 get_onevalue(cap.hContainer, &val, &type);
314 ok(type == TWTY_FIX32, "GETCURRENT for RESOLUTION is not type FIX32, is type %d\n", type);
315 memcpy(&orig_value, &val, sizeof(orig_value));
316 GlobalFree(cap.hContainer);
320 if (actual_support & TWQC_GETDEFAULT)
322 memset(&cap, 0, sizeof(cap));
323 cap.Cap = captype;
324 cap.ConType = TWON_DONTCARE16;
326 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GETDEFAULT, &cap);
327 get_condition_code(appid, source, &status);
328 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
329 "Error [rc %d|cc %d] doing MSG_GETDEFAULT for type 0x%x\n", rc, status.ConditionCode, captype);
330 if (rc == TWRC_SUCCESS)
332 ok(type == TWTY_FIX32, "GETDEFAULT for RESOLUTION is not type FIX32, is type %d\n", type);
333 memcpy(&default_value, &val, sizeof(default_value));
334 GlobalFree(cap.hContainer);
338 if (actual_support & TWQC_GET)
340 memset(&cap, 0, sizeof(cap));
341 cap.Cap = captype;
342 cap.ConType = TWON_DONTCARE16;
344 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GET, &cap);
345 get_condition_code(appid, source, &status);
346 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
347 "Error [rc %d|cc %d] doing MSG_GET for type 0x%x\n", rc, status.ConditionCode, captype);
348 if (rc == TWRC_SUCCESS)
350 TW_RANGE *range;
351 ok(cap.ConType == TWON_RANGE, "MSG_GET for ICAP_[XY]RESOLUTION did not return TWON_RANGE, but %d\n", cap.ConType);
352 range = GlobalLock(cap.hContainer);
353 trace("MSG_GET of 0x%x returned [ItemType %d|MinValue %d|MaxValue %d|StepSize %d|DefaultValue %d|CurrentValue %d]:\n",
354 cap.Cap, range->ItemType, range->MinValue, range->MaxValue, range->StepSize,
355 range->DefaultValue, range->CurrentValue);
356 for (new_value = range->MinValue; new_value < range->MaxValue; new_value += range->StepSize)
357 if (new_value != range->CurrentValue)
358 break;
359 GlobalUnlock(cap.hContainer);
360 GlobalFree(cap.hContainer);
364 if (actual_support & TWQC_SET)
366 memset(&cap, 0, sizeof(cap));
367 cap.Cap = captype;
368 cap.ConType = TWON_ONEVALUE;
369 cap.hContainer = alloc_and_set_onevalue(new_value, TWTY_FIX32);
371 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_SET, &cap);
372 get_condition_code(appid, source, &status);
373 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
374 "Error [rc %d|cc %d] doing MSG_SET for type 0x%x\n", rc, status.ConditionCode, captype);
375 GlobalFree(cap.hContainer);
379 if (actual_support & TWQC_RESET)
381 memset(&cap, 0, sizeof(cap));
382 cap.Cap = captype;
383 cap.ConType = TWON_DONTCARE16;
385 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_RESET, &cap);
386 get_condition_code(appid, source, &status);
387 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
388 "Error [rc %d|cc %d] doing MSG_RESET for type 0x%x\n", rc, status.ConditionCode, captype);
389 if (rc == TWRC_SUCCESS)
390 GlobalFree(cap.hContainer);
394 static void test_physical(TW_IDENTITY *appid, TW_IDENTITY *source, TW_UINT16 captype, TW_INT32 minimum_support)
396 TW_UINT16 rc;
397 TW_STATUS status;
398 TW_CAPABILITY cap;
399 TW_UINT32 val;
400 TW_UINT16 type;
401 TW_INT32 actual_support;
403 memset(&cap, 0, sizeof(cap));
404 cap.Cap = captype;
405 cap.ConType = TWON_DONTCARE16;
407 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_QUERYSUPPORT, &cap);
408 get_condition_code(appid, source, &status);
409 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
410 "Error [rc %d|cc %d] doing MSG_QUERYSUPPORT for type 0x%x\n", rc, status.ConditionCode, captype);
411 if (rc != TWRC_SUCCESS)
412 return;
413 ok(get_onevalue(cap.hContainer, (TW_UINT32 *) &actual_support, NULL), "Returned cap.hContainer invalid for QuerySupport on type 0x%x\n", captype);
414 ok((actual_support & minimum_support) == minimum_support,
415 "Error: minimum support 0x%x for type 0x%x, got 0x%x\n", minimum_support,
416 captype, actual_support);
419 if (actual_support & TWQC_GETCURRENT)
421 memset(&cap, 0, sizeof(cap));
422 cap.Cap = captype;
423 cap.ConType = TWON_DONTCARE16;
425 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GETCURRENT, &cap);
426 get_condition_code(appid, source, &status);
427 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
428 "Error [rc %d|cc %d] doing MSG_GETCURRENT for type 0x%x\n", rc, status.ConditionCode, captype);
429 if (rc == TWRC_SUCCESS)
431 get_onevalue(cap.hContainer, &val, &type);
432 ok(type == TWTY_FIX32, "GETCURRENT for PHYSICALXXX is not type FIX32, is type %d\n", type);
433 GlobalFree(cap.hContainer);
437 if (actual_support & TWQC_GETDEFAULT)
439 memset(&cap, 0, sizeof(cap));
440 cap.Cap = captype;
441 cap.ConType = TWON_DONTCARE16;
443 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GETDEFAULT, &cap);
444 get_condition_code(appid, source, &status);
445 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
446 "Error [rc %d|cc %d] doing MSG_GETDEFAULT for type 0x%x\n", rc, status.ConditionCode, captype);
447 if (rc == TWRC_SUCCESS)
449 get_onevalue(cap.hContainer, &val, &type);
450 ok(type == TWTY_FIX32, "GETDEFAULT for PHYSICALXXX is not type FIX32, is type %d\n", type);
451 GlobalFree(cap.hContainer);
455 if (actual_support & TWQC_GET)
457 memset(&cap, 0, sizeof(cap));
458 cap.Cap = captype;
459 cap.ConType = TWON_DONTCARE16;
461 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GET, &cap);
462 get_condition_code(appid, source, &status);
463 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
464 "Error [rc %d|cc %d] doing MSG_GET for type 0x%x\n", rc, status.ConditionCode, captype);
465 if (rc == TWRC_SUCCESS)
467 get_onevalue(cap.hContainer, &val, &type);
468 ok(type == TWTY_FIX32, "GET for PHYSICALXXX is not type FIX32, is type %d\n", type);
469 trace("GET for Physical type 0x%x returns 0x%x\n", captype, val);
470 GlobalFree(cap.hContainer);
476 static void test_supported_sizes(TW_IDENTITY *appid, TW_IDENTITY *source, TW_INT32 minimum_support)
478 TW_UINT16 rc;
479 TW_STATUS status;
480 TW_CAPABILITY cap;
481 TW_UINT32 val;
482 TW_UINT16 type;
483 TW_INT32 actual_support;
484 TW_UINT32 orig_value;
485 TW_UINT32 default_value;
486 TW_UINT32 new_value = TWSS_NONE;
489 memset(&cap, 0, sizeof(cap));
490 cap.Cap = ICAP_SUPPORTEDSIZES;
491 cap.ConType = TWON_DONTCARE16;
493 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_QUERYSUPPORT, &cap);
494 get_condition_code(appid, source, &status);
495 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
496 "Error [rc %d|cc %d] doing MSG_QUERYSUPPORT for ICAP_SUPPORTEDSIZES\n", rc, status.ConditionCode);
497 if (rc != TWRC_SUCCESS)
498 return;
499 ok(get_onevalue(cap.hContainer, (TW_UINT32 *) &actual_support, NULL), "Returned cap.hContainer invalid for QuerySupport on ICAP_SUPPORTEDSIZES\n");
500 ok((actual_support & minimum_support) == minimum_support,
501 "Error: minimum support 0x%x for ICAP_SUPPORTEDSIZES, got 0x%x\n", minimum_support, actual_support);
503 if (actual_support & TWQC_GETCURRENT)
505 memset(&cap, 0, sizeof(cap));
506 cap.Cap = ICAP_SUPPORTEDSIZES;
507 cap.ConType = TWON_DONTCARE16;
509 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GETCURRENT, &cap);
510 get_condition_code(appid, source, &status);
511 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
512 "Error [rc %d|cc %d] doing MSG_GETCURRENT for ICAP_SUPPORTEDSIZES\n", rc, status.ConditionCode);
513 if (rc == TWRC_SUCCESS)
515 get_onevalue(cap.hContainer, &val, &type);
516 ok(type == TWTY_UINT16, "GETCURRENT for ICAP_SUPPORTEDSIZES is not type UINT16, is type %d\n", type);
517 trace("Current size is %d\n", val);
518 GlobalFree(cap.hContainer);
519 orig_value = val;
523 if (actual_support & TWQC_GETDEFAULT)
525 memset(&cap, 0, sizeof(cap));
526 cap.Cap = ICAP_SUPPORTEDSIZES;
527 cap.ConType = TWON_DONTCARE16;
529 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GETDEFAULT, &cap);
530 get_condition_code(appid, source, &status);
531 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
532 "Error [rc %d|cc %d] doing MSG_GETDEFAULT for ICAP_SUPPORTEDSIZES\n", rc, status.ConditionCode);
533 if (rc == TWRC_SUCCESS)
535 get_onevalue(cap.hContainer, &val, &type);
536 ok(type == TWTY_UINT16, "GETDEFAULT for PHYSICALXXX is not type TWTY_UINT16, is type %d\n", type);
537 trace("Default size is %d\n", val);
538 GlobalFree(cap.hContainer);
539 default_value = val;
543 if (actual_support & TWQC_GET)
545 memset(&cap, 0, sizeof(cap));
546 cap.Cap = ICAP_SUPPORTEDSIZES;
547 cap.ConType = TWON_DONTCARE16;
549 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GET, &cap);
550 get_condition_code(appid, source, &status);
551 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
552 "Error [rc %d|cc %d] doing MSG_GET for ICAP_SUPPORTEDSIZES\n", rc, status.ConditionCode);
553 check_get(&cap, actual_support, orig_value, default_value, &new_value);
556 if (actual_support & TWQC_SET)
558 memset(&cap, 0, sizeof(cap));
559 cap.Cap = ICAP_SUPPORTEDSIZES;
560 cap.ConType = TWON_ONEVALUE;
561 cap.hContainer = alloc_and_set_onevalue(new_value, TWTY_UINT16);
563 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_SET, &cap);
564 get_condition_code(appid, source, &status);
565 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
566 "Error [rc %d|cc %d] doing MSG_SET for ICAP_SUPPORTEDSIZES\n", rc, status.ConditionCode);
567 GlobalFree(cap.hContainer);
571 if (actual_support & TWQC_RESET)
573 memset(&cap, 0, sizeof(cap));
574 cap.Cap = ICAP_SUPPORTEDSIZES;
575 cap.ConType = TWON_DONTCARE16;
577 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_RESET, &cap);
578 get_condition_code(appid, source, &status);
579 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
580 "Error [rc %d|cc %d] doing MSG_RESET for ICAP_SUPPORTEDSIZES\n", rc, status.ConditionCode);
581 if (rc == TWRC_SUCCESS)
582 GlobalFree(cap.hContainer);
587 static void test_single_source(TW_IDENTITY *appid, TW_IDENTITY *source)
589 TW_UINT16 rc;
590 TW_STATUS status;
591 TW_CAPABILITY cap;
592 UINT16 capabilities[CAP_CUSTOMBASE];
594 memset(&cap, 0, sizeof(cap));
595 cap.Cap = CAP_SUPPORTEDCAPS;
596 cap.ConType = TWON_DONTCARE16;
598 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GET, &cap);
599 get_condition_code(appid, source, &status);
600 ok(rc == TWRC_SUCCESS || status.ConditionCode == TWCC_SUCCESS,
601 "Error obtaining CAP_SUPPORTEDCAPS\n");
603 memset(capabilities, 0, sizeof(capabilities));
604 if (rc == TWRC_SUCCESS && cap.ConType == TWON_ARRAY)
606 TW_ARRAY *a;
607 a = GlobalLock(cap.hContainer);
608 if (a)
610 if (a->ItemType == TWTY_UINT16)
612 int i;
613 UINT16 *u = (UINT16 *) a->ItemList;
614 trace("%d Capabilities:\n", a->NumItems);
615 for (i = 0; i < a->NumItems; i++)
616 if (u[i] < sizeof(capabilities) / sizeof(capabilities[0]))
618 capabilities[u[i]] = 1;
619 trace(" %d: 0x%x\n", i, u[i]);
622 GlobalUnlock(cap.hContainer);
626 /* For Twain 1.6, all sources must support: */
627 ok(capabilities[CAP_SUPPORTEDCAPS], "CAP_SUPPORTEDCAPS not supported\n");
628 ok(capabilities[CAP_XFERCOUNT], "CAP_XFERCOUNT not supported\n");
629 if (capabilities[CAP_XFERCOUNT])
630 test_onevalue_cap(appid, source, CAP_XFERCOUNT, TWTY_INT16,
631 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET);
632 ok(capabilities[CAP_UICONTROLLABLE], "CAP_UICONTROLLABLE not supported\n");
633 if (capabilities[CAP_UICONTROLLABLE])
634 test_onevalue_cap(appid, source, CAP_UICONTROLLABLE, TWTY_BOOL, TWQC_GET);
636 if (source->SupportedGroups & DG_IMAGE)
638 /* For Twain 1.6:
639 Sources that supply image information must support DG_CONTROL / DAT_CAPABILITY /
640 MSG_GET, MSG_GETCURRENT, MSG_GETDEFAULT on:
642 ok(capabilities[ICAP_COMPRESSION], "ICAP_COMPRESSION not supported\n");
643 if (capabilities[ICAP_COMPRESSION])
644 test_onevalue_cap(appid, source, ICAP_COMPRESSION, TWTY_UINT16,
645 TWQC_GET | TWQC_GETDEFAULT | TWQC_GETCURRENT);
646 todo_wine
647 ok(capabilities[ICAP_PLANARCHUNKY], "ICAP_PLANARCHUNKY not supported\n");
648 ok(capabilities[ICAP_PHYSICALHEIGHT], "ICAP_PHYSICALHEIGHT not supported\n");
649 if (capabilities[ICAP_PHYSICALHEIGHT])
650 test_physical(appid, source, ICAP_PHYSICALHEIGHT,
651 TWQC_GET | TWQC_GETDEFAULT | TWQC_GETCURRENT);
652 ok(capabilities[ICAP_PHYSICALWIDTH], "ICAP_PHYSICALWIDTH not supported\n");
653 if (capabilities[ICAP_PHYSICALWIDTH])
654 test_physical(appid, source, ICAP_PHYSICALWIDTH,
655 TWQC_GET | TWQC_GETDEFAULT | TWQC_GETCURRENT);
656 ok(capabilities[ICAP_PIXELFLAVOR], "ICAP_PIXELFLAVOR not supported\n");
657 if (capabilities[ICAP_PIXELFLAVOR])
658 test_onevalue_cap(appid, source, ICAP_PIXELFLAVOR, TWTY_UINT16,
659 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET);
661 /* For Twain 1.6:
662 Sources that supply image information must support DG_CONTROL / DAT_CAPABILITY /
663 MSG_GET, MSG_GETCURRENT, MSG_GETDEFAULT, MSG_RESET and MSG_SET on:
665 ok(capabilities[ICAP_BITDEPTH], "ICAP_BITDEPTH not supported\n");
666 if (capabilities[ICAP_BITDEPTH])
667 test_onevalue_cap(appid, source, ICAP_BITDEPTH, TWTY_UINT16,
668 TWQC_GET | TWQC_GETDEFAULT | TWQC_GETCURRENT );
669 todo_wine
670 ok(capabilities[ICAP_BITORDER], "ICAP_BITORDER not supported\n");
671 ok(capabilities[ICAP_PIXELTYPE], "ICAP_PIXELTYPE not supported\n");
672 if (capabilities[ICAP_PIXELTYPE])
673 test_onevalue_cap(appid, source, ICAP_PIXELTYPE, TWTY_UINT16,
674 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET);
675 ok(capabilities[ICAP_UNITS], "ICAP_UNITS not supported\n");
676 if (capabilities[ICAP_UNITS])
677 test_onevalue_cap(appid, source, ICAP_UNITS, TWTY_UINT16,
678 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET);
679 ok(capabilities[ICAP_XFERMECH], "ICAP_XFERMECH not supported\n");
680 if (capabilities[ICAP_XFERMECH])
681 test_onevalue_cap(appid, source, ICAP_XFERMECH, TWTY_UINT16,
682 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET);
683 ok(capabilities[ICAP_XRESOLUTION], "ICAP_XRESOLUTION not supported\n");
684 if (capabilities[ICAP_XRESOLUTION])
685 test_resolution(appid, source, ICAP_XRESOLUTION,
686 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET);
687 ok(capabilities[ICAP_YRESOLUTION], "ICAP_YRESOLUTION not supported\n");
688 if (capabilities[ICAP_YRESOLUTION])
689 test_resolution(appid, source, ICAP_YRESOLUTION,
690 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET);
692 /* Optional capabilities */
693 if (capabilities[CAP_AUTOFEED])
694 test_onevalue_cap(appid, source, CAP_AUTOFEED, TWTY_BOOL,
695 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET);
696 if (capabilities[CAP_FEEDERENABLED])
697 test_onevalue_cap(appid, source, CAP_FEEDERENABLED, TWTY_BOOL,
698 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET);
699 if (capabilities[ICAP_SUPPORTEDSIZES])
700 test_supported_sizes(appid, source,
701 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET);
706 static void test_sources(TW_IDENTITY *appid)
708 TW_UINT16 rc;
709 TW_IDENTITY source;
710 TW_STATUS status;
711 int scannercount = 0;
713 memset(&source, 0, sizeof(source));
714 rc = pDSM_Entry(appid, NULL, DG_CONTROL, DAT_IDENTITY, MSG_GETFIRST, &source);
715 get_condition_code(appid, NULL, &status);
716 ok( (rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS) ||
717 (rc == TWRC_FAILURE && status.ConditionCode == TWCC_NODS),
718 "Get first invalid condition code, rc %d, cc %d\n", rc, status.ConditionCode);
720 while (rc == TWRC_SUCCESS)
722 scannercount++;
723 trace("[Scanner %d|Version %d.%d(%s)|Protocol %d.%d|SupportedGroups 0x%x|Manufacturer %s|Family %s|ProductName %s]\n",
724 scannercount,
725 source.Version.MajorNum, source.Version.MinorNum, source.Version.Info,
726 source.ProtocolMajor, source.ProtocolMinor, source.SupportedGroups,
727 source.Manufacturer, source.ProductFamily, source.ProductName);
728 memset(&source, 0, sizeof(source));
729 rc = pDSM_Entry(appid, NULL, DG_CONTROL, DAT_IDENTITY, MSG_GETNEXT, &source);
730 get_condition_code(appid, NULL, &status);
731 ok(rc == TWRC_SUCCESS || rc == TWRC_ENDOFLIST, "Get next source failed, rc %d, cc %d\n", rc, status.ConditionCode);
734 memset(&source, 0, sizeof(source));
735 rc = pDSM_Entry(appid, NULL, DG_CONTROL, DAT_IDENTITY, MSG_GETDEFAULT, &source);
736 get_condition_code(appid, NULL, &status);
737 ok( (rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS) ||
738 (rc == TWRC_FAILURE && status.ConditionCode == TWCC_NODS),
739 "Get default invalid condition code, rc %d, cc %d\n", rc, status.ConditionCode);
741 if (rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS)
743 rc = pDSM_Entry(appid, NULL, DG_CONTROL, DAT_IDENTITY, MSG_OPENDS, &source);
744 get_condition_code(appid, NULL, &status);
746 if (rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS)
748 rc = pDSM_Entry(appid, NULL, DG_CONTROL, DAT_IDENTITY, MSG_CLOSEDS, &source);
749 get_condition_code(appid, NULL, &status);
750 ok(rc == TWRC_SUCCESS, "Close DS Failed, rc %d, cc %d\n", rc, status.ConditionCode);
754 if (winetest_interactive)
756 trace("Interactive, so trying userselect\n");
757 memset(&source, 0, sizeof(source));
758 rc = pDSM_Entry(appid, NULL, DG_CONTROL, DAT_IDENTITY, MSG_USERSELECT, &source);
759 get_condition_code(appid, NULL, &status);
760 ok(rc == TWRC_SUCCESS || rc == TWRC_CANCEL, "Userselect failed, rc %d, cc %d\n", rc, status.ConditionCode);
762 if (rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS)
764 rc = pDSM_Entry(appid, NULL, DG_CONTROL, DAT_IDENTITY, MSG_OPENDS, &source);
765 get_condition_code(appid, NULL, &status);
766 if (rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS)
768 test_single_source(appid, &source);
769 rc = pDSM_Entry(appid, NULL, DG_CONTROL, DAT_IDENTITY, MSG_CLOSEDS, &source);
770 get_condition_code(appid, NULL, &status);
771 ok(rc == TWRC_SUCCESS, "Close DS Failed, rc %d, cc %d\n", rc, status.ConditionCode);
778 START_TEST(dsm)
780 TW_IDENTITY appid;
781 TW_UINT16 rc;
782 HANDLE hwnd;
783 HMODULE htwain;
785 if (!dsm_RegisterWindowClasses()) assert(0);
787 htwain = LoadLibraryA("twain_32.dll");
788 if (! htwain)
790 win_skip("twain_32.dll not available, skipping tests\n");
791 return;
793 pDSM_Entry = (void*)GetProcAddress(htwain, "DSM_Entry");
794 ok(pDSM_Entry != NULL, "Unable to GetProcAddress DSM_Entry\n");
795 if (! pDSM_Entry)
797 win_skip("DSM_Entry not available, skipping tests\n");
798 return;
801 memset(&appid, 0, sizeof(appid));
802 appid.Version.Language = TWLG_ENGLISH_USA;
803 appid.Version.Country = TWCY_USA;
804 appid.ProtocolMajor = TWON_PROTOCOLMAJOR;
805 appid.ProtocolMinor = TWON_PROTOCOLMINOR;
806 appid.SupportedGroups = DG_CONTROL | DG_IMAGE;
808 hwnd = CreateWindow("TWAIN_dsm_class", "Twain Test", 0,
809 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
810 NULL, NULL, GetModuleHandleA(0), NULL);
812 rc = pDSM_Entry(&appid, NULL, DG_CONTROL, DAT_PARENT, MSG_OPENDSM, (TW_MEMREF) &hwnd);
813 ok(rc == TWRC_SUCCESS, "MSG_OPENDSM returned %d\n", rc);
815 test_sources(&appid);
817 rc = pDSM_Entry(&appid, NULL, DG_CONTROL, DAT_PARENT, MSG_CLOSEDSM, (TW_MEMREF) &hwnd);
818 ok(rc == TWRC_SUCCESS, "MSG_CLOSEDSM returned %d\n", rc);
820 DestroyWindow(hwnd);
821 FreeLibrary(htwain);