user32: Fall back to downscaling the big icon for ICON_SMALL2.
[wine.git] / dlls / twain_32 / tests / dsm.c
blobab6e84fd6a87e442cc986d365b67d94ee8afc963
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>
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;
36 BOOL rc;
38 cls.style = 0;
39 cls.lpfnWndProc = DefWindowProcA;
40 cls.cbClsExtra = 0;
41 cls.cbWndExtra = 0;
42 cls.hInstance = GetModuleHandleA(0);
43 cls.hIcon = 0;
44 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
45 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
46 cls.lpszMenuName = NULL;
47 cls.lpszClassName = "TWAIN_dsm_class";
49 rc = RegisterClassA(&cls);
50 ok(rc, "RegisterClassA failed: le=%u\n", GetLastError());
51 return rc;
55 static void get_condition_code(TW_IDENTITY *appid, TW_IDENTITY *source, TW_STATUS *status)
57 TW_UINT16 rc;
58 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_STATUS, MSG_GET, status);
59 ok(rc == TWRC_SUCCESS, "Condition code not available, rc %d\n", rc);
62 static BOOL get_onevalue(TW_HANDLE hcontainer, TW_UINT32 *ret, TW_UINT16 *type)
64 TW_ONEVALUE *onev;
65 onev = GlobalLock(hcontainer);
66 if (onev)
68 *ret = onev->Item;
69 if (type)
70 *type = onev->ItemType;
71 GlobalUnlock(hcontainer);
72 return TRUE;
74 else
75 *ret = 0;
76 return FALSE;
79 static TW_HANDLE alloc_and_set_onevalue(TW_UINT32 val, TW_UINT16 type)
81 TW_HANDLE hcontainer;
82 TW_ONEVALUE *onev;
83 hcontainer = GlobalAlloc(0, sizeof(*onev));
84 if (hcontainer)
86 onev = GlobalLock(hcontainer);
87 if (onev)
89 onev->ItemType = type;
90 onev->Item = val;
91 GlobalUnlock(hcontainer);
93 else
95 GlobalFree(hcontainer);
96 hcontainer = 0;
99 return hcontainer;
102 static void check_get(TW_CAPABILITY *pCapability, TW_INT32 actual_support,
103 TW_UINT32 orig_value, TW_UINT32 default_value, TW_UINT32 *suggested_set_value)
105 void *p;
106 if (suggested_set_value)
107 *suggested_set_value = orig_value + 1;
108 p = GlobalLock(pCapability->hContainer);
109 if (p)
111 if (pCapability->ConType == TWON_ONEVALUE)
113 TW_ONEVALUE *onev = p;
114 ok(onev->Item == orig_value || !(actual_support & TWQC_GETCURRENT), "MSG_GET of 0x%x returned 0x%x, expecting 0x%x\n",
115 pCapability->Cap, onev->Item, orig_value);
116 trace("MSG_GET of 0x%x returned val 0x%x, type %d\n", pCapability->Cap, onev->Item, onev->ItemType);
117 if (suggested_set_value)
118 *suggested_set_value = onev->Item;
120 else if (pCapability->ConType == TWON_ENUMERATION)
122 int i;
123 TW_UINT8 *p8;
124 TW_UINT16 *p16;
125 TW_UINT32 *p32;
126 TW_ENUMERATION *enumv = p;
127 p8 = enumv->ItemList;
128 p16 = (TW_UINT16 *) p8;
129 p32 = (TW_UINT32 *) p8;
130 trace("MSG_GET of 0x%x returned %d items:\n", pCapability->Cap, enumv->NumItems);
131 for (i = 0; i < enumv->NumItems; i++)
133 if (enumv->ItemType == TWTY_UINT8 || enumv->ItemType == TWTY_INT8)
134 trace(" %d: 0x%x\n", i, p8[i]);
135 if (enumv->ItemType == TWTY_UINT16 || enumv->ItemType == TWTY_INT16)
136 trace(" %d: 0x%x\n", i, p16[i]);
137 if (enumv->ItemType == TWTY_UINT32 || enumv->ItemType == TWTY_INT32)
138 trace(" %d: 0x%x\n", i, p32[i]);
140 if (enumv->ItemType == TWTY_UINT16 || enumv->ItemType == TWTY_INT16)
142 ok(p16[enumv->CurrentIndex] == orig_value,
143 "Type 0x%x, values from MSG_GET (0x%x) and MSG_GETCURRENT (0x%x) do not match.\n",
144 pCapability->Cap, p16[enumv->CurrentIndex], orig_value);
145 ok(p16[enumv->DefaultIndex] == default_value,
146 "Type 0x%x, values from MSG_GET (0x%x) and MSG_GETDEFAULT (0x%x) do not match.\n",
147 pCapability->Cap, p16[enumv->DefaultIndex], default_value);
148 if (suggested_set_value)
149 *suggested_set_value = p16[(enumv->CurrentIndex + 1) % enumv->NumItems];
151 if (enumv->ItemType == TWTY_UINT32 || enumv->ItemType == TWTY_INT32)
153 ok(p32[enumv->CurrentIndex] == orig_value,
154 "Type 0x%x, values from MSG_GET (0x%x) and MSG_GETCURRENT (0x%x) do not match.\n",
155 pCapability->Cap, p32[enumv->CurrentIndex], orig_value);
156 ok(p32[enumv->DefaultIndex] == default_value,
157 "Type 0x%x, values from MSG_GET (0x%x) and MSG_GETDEFAULT (0x%x) do not match.\n",
158 pCapability->Cap, p32[enumv->DefaultIndex], default_value);
159 if (suggested_set_value)
160 *suggested_set_value = p32[(enumv->CurrentIndex + 1) % enumv->NumItems];
163 else
164 trace("MSG_GET on type 0x%x returned type 0x%x, which we didn't check.\n", pCapability->Cap, pCapability->ConType);
165 GlobalUnlock(pCapability->hContainer);
169 static void test_onevalue_cap(TW_IDENTITY *appid, TW_IDENTITY *source, TW_UINT16 captype, TW_UINT16 type, TW_INT32 minimum_support)
171 TW_UINT16 rc;
172 TW_UINT16 rtype;
173 TW_STATUS status;
174 TW_CAPABILITY cap;
175 TW_UINT32 orig_value = 0;
176 TW_UINT32 new_value;
177 TW_UINT32 default_value = 0;
178 TW_INT32 actual_support;
180 memset(&cap, 0, sizeof(cap));
181 cap.Cap = captype;
182 cap.ConType = TWON_DONTCARE16;
184 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_QUERYSUPPORT, &cap);
185 get_condition_code(appid, source, &status);
186 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
187 "Error [rc %d|cc %d] doing MSG_QUERYSUPPORT for type 0x%x\n", rc, status.ConditionCode, captype);
188 if (rc != TWRC_SUCCESS)
189 return;
190 ok(get_onevalue(cap.hContainer, (TW_UINT32 *) &actual_support, NULL), "Returned cap.hContainer invalid for QuerySupport on type 0x%x\n", captype);
191 ok((actual_support & minimum_support) == minimum_support,
192 "Error: minimum support 0x%x for type 0x%x, got 0x%x\n", minimum_support,
193 captype, actual_support);
196 if (actual_support & TWQC_GETCURRENT)
198 memset(&cap, 0, sizeof(cap));
199 cap.Cap = captype;
200 cap.ConType = TWON_DONTCARE16;
202 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GETCURRENT, &cap);
203 get_condition_code(appid, source, &status);
204 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
205 "Error [rc %d|cc %d] doing MSG_GETCURRENT for type 0x%x\n", rc, status.ConditionCode, captype);
206 if (rc == TWRC_SUCCESS)
208 ok(get_onevalue(cap.hContainer, &orig_value, &rtype), "Returned cap.hContainer invalid for GETCURRENT on type 0x%x\n", captype);
209 ok(rtype == type, "Returned GETCURRENT type 0x%x for cap 0x%x is not expected 0x%x\n", rtype, captype, type);
210 GlobalFree(cap.hContainer);
214 if (actual_support & TWQC_GETDEFAULT)
216 memset(&cap, 0, sizeof(cap));
217 cap.Cap = captype;
218 cap.ConType = TWON_DONTCARE16;
220 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GETDEFAULT, &cap);
221 get_condition_code(appid, source, &status);
222 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
223 "Error [rc %d|cc %d] doing MSG_GETDEFAULT for type 0x%x\n", rc, status.ConditionCode, captype);
224 if (rc == TWRC_SUCCESS)
226 ok(get_onevalue(cap.hContainer, &default_value, &rtype), "Returned cap.hContainer invalid for GETDEFAULT on type 0x%x\n", captype);
227 ok(rtype == type, "Returned GETDEFAULT type 0x%x for cap 0x%x is not expected 0x%x\n", rtype, captype, type);
228 GlobalFree(cap.hContainer);
232 new_value = orig_value;
233 if (actual_support & TWQC_GET)
235 memset(&cap, 0, sizeof(cap));
236 cap.Cap = captype;
237 cap.ConType = TWON_DONTCARE16;
239 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GET, &cap);
240 get_condition_code(appid, source, &status);
241 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
242 "Error [rc %d|cc %d] doing MSG_GET for type 0x%x\n", rc, status.ConditionCode, captype);
243 check_get(&cap, actual_support, orig_value, default_value, &new_value);
244 if (rc == TWRC_SUCCESS)
245 GlobalFree(cap.hContainer);
248 if (actual_support & TWQC_SET)
250 memset(&cap, 0, sizeof(cap));
251 cap.Cap = captype;
252 cap.ConType = TWON_ONEVALUE;
253 cap.hContainer = alloc_and_set_onevalue(new_value, type);
255 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_SET, &cap);
256 get_condition_code(appid, source, &status);
257 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
258 "Error [rc %d|cc %d] doing MSG_SET for type 0x%x\n", rc, status.ConditionCode, captype);
259 GlobalFree(cap.hContainer);
262 if (actual_support & TWQC_RESET)
264 memset(&cap, 0, sizeof(cap));
265 cap.Cap = captype;
266 cap.ConType = TWON_DONTCARE16;
268 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_RESET, &cap);
269 get_condition_code(appid, source, &status);
270 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
271 "Error [rc %d|cc %d] doing MSG_RESET for type 0x%x\n", rc, status.ConditionCode, captype);
272 if (rc == TWRC_SUCCESS)
273 GlobalFree(cap.hContainer);
277 static void test_resolution(TW_IDENTITY *appid, TW_IDENTITY *source, TW_UINT16 captype, TW_INT32 minimum_support)
279 TW_UINT16 rc;
280 TW_STATUS status;
281 TW_CAPABILITY cap;
282 TW_UINT32 val;
283 TW_UINT16 type;
284 TW_INT32 actual_support;
285 TW_FIX32 orig_value = { 0, 0 };
286 TW_UINT32 new_value = 0;
287 TW_FIX32 default_value = { 0, 0 };
289 memset(&cap, 0, sizeof(cap));
290 cap.Cap = captype;
291 cap.ConType = TWON_DONTCARE16;
293 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_QUERYSUPPORT, &cap);
294 get_condition_code(appid, source, &status);
295 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
296 "Error [rc %d|cc %d] doing MSG_QUERYSUPPORT for type 0x%x\n", rc, status.ConditionCode, captype);
297 if (rc != TWRC_SUCCESS)
298 return;
299 ok(get_onevalue(cap.hContainer, (TW_UINT32 *) &actual_support, NULL), "Returned cap.hContainer invalid for QuerySupport on type 0x%x\n", captype);
300 ok((actual_support & minimum_support) == minimum_support,
301 "Error: minimum support 0x%x for type 0x%x, got 0x%x\n", minimum_support,
302 captype, actual_support);
305 if (actual_support & TWQC_GETCURRENT)
307 memset(&cap, 0, sizeof(cap));
308 cap.Cap = captype;
309 cap.ConType = TWON_DONTCARE16;
311 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GETCURRENT, &cap);
312 get_condition_code(appid, source, &status);
313 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
314 "Error [rc %d|cc %d] doing MSG_GETCURRENT for type 0x%x\n", rc, status.ConditionCode, captype);
315 if (rc == TWRC_SUCCESS)
317 get_onevalue(cap.hContainer, &val, &type);
318 ok(type == TWTY_FIX32, "GETCURRENT for RESOLUTION is not type FIX32, is type %d\n", type);
319 memcpy(&orig_value, &val, sizeof(orig_value));
320 GlobalFree(cap.hContainer);
324 if (actual_support & TWQC_GETDEFAULT)
326 memset(&cap, 0, sizeof(cap));
327 cap.Cap = captype;
328 cap.ConType = TWON_DONTCARE16;
330 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GETDEFAULT, &cap);
331 get_condition_code(appid, source, &status);
332 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
333 "Error [rc %d|cc %d] doing MSG_GETDEFAULT for type 0x%x\n", rc, status.ConditionCode, captype);
334 if (rc == TWRC_SUCCESS)
336 get_onevalue(cap.hContainer, &val, &type);
337 ok(type == TWTY_FIX32, "GETDEFAULT for RESOLUTION is not type FIX32, is type %d\n", type);
338 memcpy(&default_value, &val, sizeof(default_value));
339 GlobalFree(cap.hContainer);
343 if (actual_support & TWQC_GET)
345 memset(&cap, 0, sizeof(cap));
346 cap.Cap = captype;
347 cap.ConType = TWON_DONTCARE16;
349 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GET, &cap);
350 get_condition_code(appid, source, &status);
351 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
352 "Error [rc %d|cc %d] doing MSG_GET for type 0x%x\n", rc, status.ConditionCode, captype);
353 if (rc == TWRC_SUCCESS)
355 TW_RANGE *range;
356 ok(cap.ConType == TWON_RANGE, "MSG_GET for ICAP_[XY]RESOLUTION did not return TWON_RANGE, but %d\n", cap.ConType);
357 range = GlobalLock(cap.hContainer);
358 trace("MSG_GET of 0x%x returned [ItemType %d|MinValue %d|MaxValue %d|StepSize %d|DefaultValue %d|CurrentValue %d]:\n",
359 cap.Cap, range->ItemType, range->MinValue, range->MaxValue, range->StepSize,
360 range->DefaultValue, range->CurrentValue);
361 for (new_value = range->MinValue; new_value < range->MaxValue; new_value += range->StepSize)
362 if (new_value != range->CurrentValue)
363 break;
364 GlobalUnlock(cap.hContainer);
365 GlobalFree(cap.hContainer);
369 if (actual_support & TWQC_SET)
371 memset(&cap, 0, sizeof(cap));
372 cap.Cap = captype;
373 cap.ConType = TWON_ONEVALUE;
374 cap.hContainer = alloc_and_set_onevalue(new_value, TWTY_FIX32);
376 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_SET, &cap);
377 get_condition_code(appid, source, &status);
378 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
379 "Error [rc %d|cc %d] doing MSG_SET for type 0x%x\n", rc, status.ConditionCode, captype);
380 GlobalFree(cap.hContainer);
384 if (actual_support & TWQC_RESET)
386 memset(&cap, 0, sizeof(cap));
387 cap.Cap = captype;
388 cap.ConType = TWON_DONTCARE16;
390 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_RESET, &cap);
391 get_condition_code(appid, source, &status);
392 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
393 "Error [rc %d|cc %d] doing MSG_RESET for type 0x%x\n", rc, status.ConditionCode, captype);
394 if (rc == TWRC_SUCCESS)
395 GlobalFree(cap.hContainer);
399 static void test_physical(TW_IDENTITY *appid, TW_IDENTITY *source, TW_UINT16 captype, TW_INT32 minimum_support)
401 TW_UINT16 rc;
402 TW_STATUS status;
403 TW_CAPABILITY cap;
404 TW_UINT32 val;
405 TW_UINT16 type;
406 TW_INT32 actual_support;
408 memset(&cap, 0, sizeof(cap));
409 cap.Cap = captype;
410 cap.ConType = TWON_DONTCARE16;
412 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_QUERYSUPPORT, &cap);
413 get_condition_code(appid, source, &status);
414 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
415 "Error [rc %d|cc %d] doing MSG_QUERYSUPPORT for type 0x%x\n", rc, status.ConditionCode, captype);
416 if (rc != TWRC_SUCCESS)
417 return;
418 ok(get_onevalue(cap.hContainer, (TW_UINT32 *) &actual_support, NULL), "Returned cap.hContainer invalid for QuerySupport on type 0x%x\n", captype);
419 ok((actual_support & minimum_support) == minimum_support,
420 "Error: minimum support 0x%x for type 0x%x, got 0x%x\n", minimum_support,
421 captype, actual_support);
424 if (actual_support & TWQC_GETCURRENT)
426 memset(&cap, 0, sizeof(cap));
427 cap.Cap = captype;
428 cap.ConType = TWON_DONTCARE16;
430 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GETCURRENT, &cap);
431 get_condition_code(appid, source, &status);
432 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
433 "Error [rc %d|cc %d] doing MSG_GETCURRENT for type 0x%x\n", rc, status.ConditionCode, captype);
434 if (rc == TWRC_SUCCESS)
436 get_onevalue(cap.hContainer, &val, &type);
437 ok(type == TWTY_FIX32, "GETCURRENT for PHYSICALXXX is not type FIX32, is type %d\n", type);
438 GlobalFree(cap.hContainer);
442 if (actual_support & TWQC_GETDEFAULT)
444 memset(&cap, 0, sizeof(cap));
445 cap.Cap = captype;
446 cap.ConType = TWON_DONTCARE16;
448 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GETDEFAULT, &cap);
449 get_condition_code(appid, source, &status);
450 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
451 "Error [rc %d|cc %d] doing MSG_GETDEFAULT for type 0x%x\n", rc, status.ConditionCode, captype);
452 if (rc == TWRC_SUCCESS)
454 get_onevalue(cap.hContainer, &val, &type);
455 ok(type == TWTY_FIX32, "GETDEFAULT for PHYSICALXXX is not type FIX32, is type %d\n", type);
456 GlobalFree(cap.hContainer);
460 if (actual_support & TWQC_GET)
462 memset(&cap, 0, sizeof(cap));
463 cap.Cap = captype;
464 cap.ConType = TWON_DONTCARE16;
466 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GET, &cap);
467 get_condition_code(appid, source, &status);
468 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
469 "Error [rc %d|cc %d] doing MSG_GET for type 0x%x\n", rc, status.ConditionCode, captype);
470 if (rc == TWRC_SUCCESS)
472 get_onevalue(cap.hContainer, &val, &type);
473 ok(type == TWTY_FIX32, "GET for PHYSICALXXX is not type FIX32, is type %d\n", type);
474 trace("GET for Physical type 0x%x returns 0x%x\n", captype, val);
475 GlobalFree(cap.hContainer);
481 static void test_supported_sizes(TW_IDENTITY *appid, TW_IDENTITY *source, TW_INT32 minimum_support)
483 TW_UINT16 rc;
484 TW_STATUS status;
485 TW_CAPABILITY cap;
486 TW_UINT32 val;
487 TW_UINT16 type;
488 TW_INT32 actual_support;
489 TW_UINT32 orig_value = TWSS_NONE;
490 TW_UINT32 default_value = TWSS_NONE;
491 TW_UINT32 new_value = TWSS_NONE;
494 memset(&cap, 0, sizeof(cap));
495 cap.Cap = ICAP_SUPPORTEDSIZES;
496 cap.ConType = TWON_DONTCARE16;
498 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_QUERYSUPPORT, &cap);
499 get_condition_code(appid, source, &status);
500 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
501 "Error [rc %d|cc %d] doing MSG_QUERYSUPPORT for ICAP_SUPPORTEDSIZES\n", rc, status.ConditionCode);
502 if (rc != TWRC_SUCCESS)
503 return;
504 ok(get_onevalue(cap.hContainer, (TW_UINT32 *) &actual_support, NULL), "Returned cap.hContainer invalid for QuerySupport on ICAP_SUPPORTEDSIZES\n");
505 ok((actual_support & minimum_support) == minimum_support,
506 "Error: minimum support 0x%x for ICAP_SUPPORTEDSIZES, got 0x%x\n", minimum_support, actual_support);
508 if (actual_support & TWQC_GETCURRENT)
510 memset(&cap, 0, sizeof(cap));
511 cap.Cap = ICAP_SUPPORTEDSIZES;
512 cap.ConType = TWON_DONTCARE16;
514 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GETCURRENT, &cap);
515 get_condition_code(appid, source, &status);
516 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
517 "Error [rc %d|cc %d] doing MSG_GETCURRENT for ICAP_SUPPORTEDSIZES\n", rc, status.ConditionCode);
518 if (rc == TWRC_SUCCESS)
520 get_onevalue(cap.hContainer, &val, &type);
521 ok(type == TWTY_UINT16, "GETCURRENT for ICAP_SUPPORTEDSIZES is not type UINT16, is type %d\n", type);
522 trace("Current size is %d\n", val);
523 GlobalFree(cap.hContainer);
524 orig_value = val;
528 if (actual_support & TWQC_GETDEFAULT)
530 memset(&cap, 0, sizeof(cap));
531 cap.Cap = ICAP_SUPPORTEDSIZES;
532 cap.ConType = TWON_DONTCARE16;
534 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GETDEFAULT, &cap);
535 get_condition_code(appid, source, &status);
536 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
537 "Error [rc %d|cc %d] doing MSG_GETDEFAULT for ICAP_SUPPORTEDSIZES\n", rc, status.ConditionCode);
538 if (rc == TWRC_SUCCESS)
540 get_onevalue(cap.hContainer, &val, &type);
541 ok(type == TWTY_UINT16, "GETDEFAULT for PHYSICALXXX is not type TWTY_UINT16, is type %d\n", type);
542 trace("Default size is %d\n", val);
543 GlobalFree(cap.hContainer);
544 default_value = val;
548 if (actual_support & TWQC_GET)
550 memset(&cap, 0, sizeof(cap));
551 cap.Cap = ICAP_SUPPORTEDSIZES;
552 cap.ConType = TWON_DONTCARE16;
554 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GET, &cap);
555 get_condition_code(appid, source, &status);
556 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
557 "Error [rc %d|cc %d] doing MSG_GET for ICAP_SUPPORTEDSIZES\n", rc, status.ConditionCode);
558 check_get(&cap, actual_support, orig_value, default_value, &new_value);
561 if (actual_support & TWQC_SET)
563 memset(&cap, 0, sizeof(cap));
564 cap.Cap = ICAP_SUPPORTEDSIZES;
565 cap.ConType = TWON_ONEVALUE;
566 cap.hContainer = alloc_and_set_onevalue(new_value, TWTY_UINT16);
568 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_SET, &cap);
569 get_condition_code(appid, source, &status);
570 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
571 "Error [rc %d|cc %d] doing MSG_SET for ICAP_SUPPORTEDSIZES\n", rc, status.ConditionCode);
572 GlobalFree(cap.hContainer);
576 if (actual_support & TWQC_RESET)
578 memset(&cap, 0, sizeof(cap));
579 cap.Cap = ICAP_SUPPORTEDSIZES;
580 cap.ConType = TWON_DONTCARE16;
582 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_RESET, &cap);
583 get_condition_code(appid, source, &status);
584 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
585 "Error [rc %d|cc %d] doing MSG_RESET for ICAP_SUPPORTEDSIZES\n", rc, status.ConditionCode);
586 if (rc == TWRC_SUCCESS)
587 GlobalFree(cap.hContainer);
591 static void test_imagelayout(TW_IDENTITY *appid, TW_IDENTITY *source)
593 TW_UINT16 rc;
594 TW_STATUS status;
595 TW_IMAGELAYOUT layout;
597 rc = pDSM_Entry(appid, source, DG_IMAGE, DAT_IMAGELAYOUT, MSG_GET, &layout);
598 get_condition_code(appid, source, &status);
599 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
600 "Error [rc %d|cc %d] doing MSG_GET for DG_IMAGE/DAT_IMAGELAYOUT\n", rc, status.ConditionCode);
601 if (rc != TWRC_SUCCESS)
602 return;
603 trace("ImageLayout [Left %x.%x|Top %x.%x|Right %x.%x|Bottom %x.%x|Document %d|Page %d|Frame %d]\n",
604 layout.Frame.Left.Whole, layout.Frame.Left.Frac,
605 layout.Frame.Top.Whole, layout.Frame.Top.Frac,
606 layout.Frame.Right.Whole, layout.Frame.Right.Frac,
607 layout.Frame.Bottom.Whole, layout.Frame.Bottom.Frac,
608 layout.DocumentNumber, layout.PageNumber, layout.FrameNumber);
610 memset(&layout, 0, sizeof(layout));
611 layout.Frame.Left.Whole = 1;
612 layout.Frame.Right.Whole = 2;
613 layout.Frame.Top.Whole = 1;
614 layout.Frame.Bottom.Whole = 2;
615 rc = pDSM_Entry(appid, source, DG_IMAGE, DAT_IMAGELAYOUT, MSG_SET, &layout);
616 get_condition_code(appid, source, &status);
617 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
618 "Error [rc %d|cc %d] doing MSG_SET for DG_IMAGE/DAT_IMAGELAYOUT\n", rc, status.ConditionCode);
619 if (rc != TWRC_SUCCESS)
620 return;
622 rc = pDSM_Entry(appid, source, DG_IMAGE, DAT_IMAGELAYOUT, MSG_GET, &layout);
623 get_condition_code(appid, source, &status);
624 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
625 "Error [rc %d|cc %d] doing MSG_GET for DG_IMAGE/DAT_IMAGELAYOUT\n", rc, status.ConditionCode);
626 if (rc != TWRC_SUCCESS)
627 return;
628 trace("ImageLayout after set [Left %x.%x|Top %x.%x|Right %x.%x|Bottom %x.%x|Document %d|Page %d|Frame %d]\n",
629 layout.Frame.Left.Whole, layout.Frame.Left.Frac,
630 layout.Frame.Top.Whole, layout.Frame.Top.Frac,
631 layout.Frame.Right.Whole, layout.Frame.Right.Frac,
632 layout.Frame.Bottom.Whole, layout.Frame.Bottom.Frac,
633 layout.DocumentNumber, layout.PageNumber, layout.FrameNumber);
637 static void test_single_source(TW_IDENTITY *appid, TW_IDENTITY *source)
639 TW_UINT16 rc;
640 TW_STATUS status;
641 TW_CAPABILITY cap;
642 UINT16 capabilities[CAP_CUSTOMBASE];
644 memset(&cap, 0, sizeof(cap));
645 cap.Cap = CAP_SUPPORTEDCAPS;
646 cap.ConType = TWON_DONTCARE16;
648 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GET, &cap);
649 get_condition_code(appid, source, &status);
650 ok(rc == TWRC_SUCCESS || status.ConditionCode == TWCC_SUCCESS,
651 "Error obtaining CAP_SUPPORTEDCAPS\n");
653 memset(capabilities, 0, sizeof(capabilities));
654 if (rc == TWRC_SUCCESS && cap.ConType == TWON_ARRAY)
656 TW_ARRAY *a;
657 a = GlobalLock(cap.hContainer);
658 if (a)
660 if (a->ItemType == TWTY_UINT16)
662 int i;
663 UINT16 *u = (UINT16 *) a->ItemList;
664 trace("%d Capabilities:\n", a->NumItems);
665 for (i = 0; i < a->NumItems; i++)
666 if (u[i] < sizeof(capabilities) / sizeof(capabilities[0]))
668 capabilities[u[i]] = 1;
669 trace(" %d: 0x%x\n", i, u[i]);
672 GlobalUnlock(cap.hContainer);
676 /* All sources must support: */
677 ok(capabilities[CAP_SUPPORTEDCAPS], "CAP_SUPPORTEDCAPS not supported\n");
678 ok(capabilities[CAP_XFERCOUNT], "CAP_XFERCOUNT not supported\n");
679 if (capabilities[CAP_XFERCOUNT])
680 test_onevalue_cap(appid, source, CAP_XFERCOUNT, TWTY_INT16,
681 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET);
682 ok(capabilities[CAP_UICONTROLLABLE], "CAP_UICONTROLLABLE not supported\n");
683 if (capabilities[CAP_UICONTROLLABLE])
684 test_onevalue_cap(appid, source, CAP_UICONTROLLABLE, TWTY_BOOL, TWQC_GET);
686 if (source->SupportedGroups & DG_IMAGE)
689 Sources that supply image information must support DG_CONTROL / DAT_CAPABILITY /
690 MSG_GET, MSG_GETCURRENT, MSG_GETDEFAULT on:
692 ok(capabilities[ICAP_COMPRESSION], "ICAP_COMPRESSION not supported\n");
693 if (capabilities[ICAP_COMPRESSION])
694 test_onevalue_cap(appid, source, ICAP_COMPRESSION, TWTY_UINT16,
695 TWQC_GET | TWQC_GETDEFAULT | TWQC_GETCURRENT);
696 todo_wine
697 ok(capabilities[ICAP_PLANARCHUNKY], "ICAP_PLANARCHUNKY not supported\n");
698 ok(capabilities[ICAP_PHYSICALHEIGHT], "ICAP_PHYSICALHEIGHT not supported\n");
699 if (capabilities[ICAP_PHYSICALHEIGHT])
700 test_physical(appid, source, ICAP_PHYSICALHEIGHT,
701 TWQC_GET | TWQC_GETDEFAULT | TWQC_GETCURRENT);
702 ok(capabilities[ICAP_PHYSICALWIDTH], "ICAP_PHYSICALWIDTH not supported\n");
703 if (capabilities[ICAP_PHYSICALWIDTH])
704 test_physical(appid, source, ICAP_PHYSICALWIDTH,
705 TWQC_GET | TWQC_GETDEFAULT | TWQC_GETCURRENT);
706 ok(capabilities[ICAP_PIXELFLAVOR], "ICAP_PIXELFLAVOR not supported\n");
707 if (capabilities[ICAP_PIXELFLAVOR])
708 test_onevalue_cap(appid, source, ICAP_PIXELFLAVOR, TWTY_UINT16,
709 TWQC_GET | TWQC_GETDEFAULT | TWQC_GETCURRENT);
712 Sources that supply image information must support DG_CONTROL / DAT_CAPABILITY /
713 MSG_GET, MSG_GETCURRENT, MSG_GETDEFAULT, MSG_RESET and MSG_SET on:
715 ok(capabilities[ICAP_BITDEPTH], "ICAP_BITDEPTH not supported\n");
716 if (capabilities[ICAP_BITDEPTH])
717 test_onevalue_cap(appid, source, ICAP_BITDEPTH, TWTY_UINT16,
718 TWQC_GET | TWQC_GETDEFAULT | TWQC_GETCURRENT );
719 todo_wine
720 ok(capabilities[ICAP_BITORDER], "ICAP_BITORDER not supported\n");
721 ok(capabilities[ICAP_PIXELTYPE], "ICAP_PIXELTYPE not supported\n");
722 if (capabilities[ICAP_PIXELTYPE])
723 test_onevalue_cap(appid, source, ICAP_PIXELTYPE, TWTY_UINT16,
724 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET);
725 ok(capabilities[ICAP_UNITS], "ICAP_UNITS not supported\n");
726 if (capabilities[ICAP_UNITS])
727 test_onevalue_cap(appid, source, ICAP_UNITS, TWTY_UINT16,
728 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET);
729 ok(capabilities[ICAP_XFERMECH], "ICAP_XFERMECH not supported\n");
730 if (capabilities[ICAP_XFERMECH])
731 test_onevalue_cap(appid, source, ICAP_XFERMECH, TWTY_UINT16,
732 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET);
733 ok(capabilities[ICAP_XRESOLUTION], "ICAP_XRESOLUTION not supported\n");
734 if (capabilities[ICAP_XRESOLUTION])
735 test_resolution(appid, source, ICAP_XRESOLUTION,
736 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET);
737 ok(capabilities[ICAP_YRESOLUTION], "ICAP_YRESOLUTION not supported\n");
738 if (capabilities[ICAP_YRESOLUTION])
739 test_resolution(appid, source, ICAP_YRESOLUTION,
740 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET);
742 /* Optional capabilities */
743 if (capabilities[CAP_AUTOFEED])
744 test_onevalue_cap(appid, source, CAP_AUTOFEED, TWTY_BOOL,
745 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET);
746 if (capabilities[CAP_FEEDERENABLED])
747 test_onevalue_cap(appid, source, CAP_FEEDERENABLED, TWTY_BOOL,
748 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET);
749 if (capabilities[ICAP_SUPPORTEDSIZES])
750 test_supported_sizes(appid, source,
751 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET);
753 /* Additional tests */
754 test_imagelayout(appid, source);
759 static void test_sources(TW_IDENTITY *appid)
761 TW_UINT16 rc;
762 TW_IDENTITY source;
763 TW_STATUS status;
764 int scannercount = 0;
766 memset(&source, 0, sizeof(source));
767 rc = pDSM_Entry(appid, NULL, DG_CONTROL, DAT_IDENTITY, MSG_GETFIRST, &source);
768 get_condition_code(appid, NULL, &status);
769 ok( (rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS) ||
770 (rc == TWRC_FAILURE && status.ConditionCode == TWCC_NODS),
771 "Get first invalid condition code, rc %d, cc %d\n", rc, status.ConditionCode);
773 while (rc == TWRC_SUCCESS)
775 scannercount++;
776 trace("[Scanner %d|Version %d.%d(%s)|Protocol %d.%d|SupportedGroups 0x%x|Manufacturer %s|Family %s|ProductName %s]\n",
777 scannercount,
778 source.Version.MajorNum, source.Version.MinorNum, source.Version.Info,
779 source.ProtocolMajor, source.ProtocolMinor, source.SupportedGroups,
780 source.Manufacturer, source.ProductFamily, source.ProductName);
781 memset(&source, 0, sizeof(source));
782 rc = pDSM_Entry(appid, NULL, DG_CONTROL, DAT_IDENTITY, MSG_GETNEXT, &source);
783 get_condition_code(appid, NULL, &status);
784 ok(rc == TWRC_SUCCESS || rc == TWRC_ENDOFLIST, "Get next source failed, rc %d, cc %d\n", rc, status.ConditionCode);
787 memset(&source, 0, sizeof(source));
788 rc = pDSM_Entry(appid, NULL, DG_CONTROL, DAT_IDENTITY, MSG_GETDEFAULT, &source);
789 get_condition_code(appid, NULL, &status);
790 ok( (rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS) ||
791 (rc == TWRC_FAILURE && status.ConditionCode == TWCC_NODS),
792 "Get default invalid condition code, rc %d, cc %d\n", rc, status.ConditionCode);
794 /* A DS might display a Popup during MSG_OPENDS, when the scanner is not connected */
795 if (rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS && winetest_interactive)
797 rc = pDSM_Entry(appid, NULL, DG_CONTROL, DAT_IDENTITY, MSG_OPENDS, &source);
798 get_condition_code(appid, NULL, &status);
800 if (rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS)
802 rc = pDSM_Entry(appid, NULL, DG_CONTROL, DAT_IDENTITY, MSG_CLOSEDS, &source);
803 get_condition_code(appid, NULL, &status);
804 ok(rc == TWRC_SUCCESS, "Close DS Failed, rc %d, cc %d\n", rc, status.ConditionCode);
808 if (winetest_interactive)
810 trace("Interactive, so trying userselect\n");
811 memset(&source, 0, sizeof(source));
812 rc = pDSM_Entry(appid, NULL, DG_CONTROL, DAT_IDENTITY, MSG_USERSELECT, &source);
813 get_condition_code(appid, NULL, &status);
814 ok(rc == TWRC_SUCCESS || rc == TWRC_CANCEL, "Userselect failed, rc %d, cc %d\n", rc, status.ConditionCode);
816 if (rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS)
818 rc = pDSM_Entry(appid, NULL, DG_CONTROL, DAT_IDENTITY, MSG_OPENDS, &source);
819 get_condition_code(appid, NULL, &status);
820 if (rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS)
822 test_single_source(appid, &source);
823 rc = pDSM_Entry(appid, NULL, DG_CONTROL, DAT_IDENTITY, MSG_CLOSEDS, &source);
824 get_condition_code(appid, NULL, &status);
825 ok(rc == TWRC_SUCCESS, "Close DS Failed, rc %d, cc %d\n", rc, status.ConditionCode);
832 START_TEST(dsm)
834 TW_IDENTITY appid;
835 TW_UINT16 rc;
836 HANDLE hwnd;
837 HMODULE htwain;
839 if (!dsm_RegisterWindowClasses())
841 skip("Could not register the test class, skipping tests\n");
842 return;
845 htwain = LoadLibraryA("twain_32.dll");
846 if (! htwain)
848 win_skip("twain_32.dll not available, skipping tests\n");
849 return;
851 pDSM_Entry = (void*)GetProcAddress(htwain, "DSM_Entry");
852 ok(pDSM_Entry != NULL, "Unable to GetProcAddress DSM_Entry\n");
853 if (! pDSM_Entry)
855 win_skip("DSM_Entry not available, skipping tests\n");
856 return;
859 memset(&appid, 0, sizeof(appid));
860 appid.Version.Language = TWLG_ENGLISH_USA;
861 appid.Version.Country = TWCY_USA;
862 appid.ProtocolMajor = TWON_PROTOCOLMAJOR;
863 appid.ProtocolMinor = TWON_PROTOCOLMINOR;
864 appid.SupportedGroups = DG_CONTROL | DG_IMAGE;
866 hwnd = CreateWindowA("TWAIN_dsm_class", "Twain Test", 0, CW_USEDEFAULT, CW_USEDEFAULT,
867 CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, GetModuleHandleA(NULL), NULL);
869 rc = pDSM_Entry(&appid, NULL, DG_CONTROL, DAT_PARENT, MSG_OPENDSM, (TW_MEMREF) &hwnd);
870 ok(rc == TWRC_SUCCESS, "MSG_OPENDSM returned %d\n", rc);
872 test_sources(&appid);
874 rc = pDSM_Entry(&appid, NULL, DG_CONTROL, DAT_PARENT, MSG_CLOSEDSM, (TW_MEMREF) &hwnd);
875 ok(rc == TWRC_SUCCESS, "MSG_CLOSEDSM returned %d\n", rc);
877 DestroyWindow(hwnd);
878 FreeLibrary(htwain);