1e9764dccb01c541a36394e52034cab9ae6e5a08
[reactos.git] / modules / rostests / winetests / twain_32 / dsm.c
1 /* Unit test suite for Twain DSM functions
2 *
3 * Copyright 2009 Jeremy White, CodeWeavers, Inc.
4 *
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.
9 *
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.
14 *
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
18 *
19 */
20 #include <stdarg.h>
21
22 #include "windef.h"
23 #include "winbase.h"
24 #include "wingdi.h"
25 #include "winerror.h"
26 #include "winuser.h"
27 #include "twain.h"
28
29 #include "wine/test.h"
30
31 static DSMENTRYPROC pDSM_Entry;
32
33 static BOOL dsm_RegisterWindowClasses(void)
34 {
35 WNDCLASSA cls;
36 BOOL rc;
37
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";
48
49 rc = RegisterClassA(&cls);
50 ok(rc, "RegisterClassA failed: le=%u\n", GetLastError());
51 return rc;
52 }
53
54
55 static void get_condition_code(TW_IDENTITY *appid, TW_IDENTITY *source, TW_STATUS *status)
56 {
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);
60 }
61
62 static BOOL get_onevalue(TW_HANDLE hcontainer, TW_UINT32 *ret, TW_UINT16 *type)
63 {
64 TW_ONEVALUE *onev;
65 onev = GlobalLock(hcontainer);
66 if (onev)
67 {
68 *ret = onev->Item;
69 if (type)
70 *type = onev->ItemType;
71 GlobalUnlock(hcontainer);
72 return TRUE;
73 }
74 else
75 *ret = 0;
76 return FALSE;
77 }
78
79 static TW_HANDLE alloc_and_set_onevalue(TW_UINT32 val, TW_UINT16 type)
80 {
81 TW_HANDLE hcontainer;
82 TW_ONEVALUE *onev;
83 hcontainer = GlobalAlloc(0, sizeof(*onev));
84 if (hcontainer)
85 {
86 onev = GlobalLock(hcontainer);
87 if (onev)
88 {
89 onev->ItemType = type;
90 onev->Item = val;
91 GlobalUnlock(hcontainer);
92 }
93 else
94 {
95 GlobalFree(hcontainer);
96 hcontainer = 0;
97 }
98 }
99 return hcontainer;
100 }
101
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)
104 {
105 void *p;
106 if (suggested_set_value)
107 *suggested_set_value = orig_value + 1;
108 p = GlobalLock(pCapability->hContainer);
109 if (p)
110 {
111 if (pCapability->ConType == TWON_ONEVALUE)
112 {
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;
119 }
120 else if (pCapability->ConType == TWON_ENUMERATION)
121 {
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++)
132 {
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]);
139 }
140 if (enumv->ItemType == TWTY_UINT16 || enumv->ItemType == TWTY_INT16)
141 {
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];
150 }
151 if (enumv->ItemType == TWTY_UINT32 || enumv->ItemType == TWTY_INT32)
152 {
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];
161 }
162 }
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);
166 }
167 }
168
169 static void test_onevalue_cap(TW_IDENTITY *appid, TW_IDENTITY *source, TW_UINT16 captype, TW_UINT16 type, TW_INT32 minimum_support)
170 {
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;
179
180 memset(&cap, 0, sizeof(cap));
181 cap.Cap = captype;
182 cap.ConType = TWON_DONTCARE16;
183
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);
194
195
196 if (actual_support & TWQC_GETCURRENT)
197 {
198 memset(&cap, 0, sizeof(cap));
199 cap.Cap = captype;
200 cap.ConType = TWON_DONTCARE16;
201
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)
207 {
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);
211 }
212 }
213
214 if (actual_support & TWQC_GETDEFAULT)
215 {
216 memset(&cap, 0, sizeof(cap));
217 cap.Cap = captype;
218 cap.ConType = TWON_DONTCARE16;
219
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)
225 {
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);
229 }
230 }
231
232 new_value = orig_value;
233 if (actual_support & TWQC_GET)
234 {
235 memset(&cap, 0, sizeof(cap));
236 cap.Cap = captype;
237 cap.ConType = TWON_DONTCARE16;
238
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);
246 }
247
248 if (actual_support & TWQC_SET)
249 {
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);
254
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);
260 }
261
262 if (actual_support & TWQC_RESET)
263 {
264 memset(&cap, 0, sizeof(cap));
265 cap.Cap = captype;
266 cap.ConType = TWON_DONTCARE16;
267
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);
274 }
275 }
276
277 static void test_resolution(TW_IDENTITY *appid, TW_IDENTITY *source, TW_UINT16 captype, TW_INT32 minimum_support)
278 {
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 };
288
289 memset(&cap, 0, sizeof(cap));
290 cap.Cap = captype;
291 cap.ConType = TWON_DONTCARE16;
292
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);
303
304
305 if (actual_support & TWQC_GETCURRENT)
306 {
307 memset(&cap, 0, sizeof(cap));
308 cap.Cap = captype;
309 cap.ConType = TWON_DONTCARE16;
310
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)
316 {
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);
321 }
322 }
323
324 if (actual_support & TWQC_GETDEFAULT)
325 {
326 memset(&cap, 0, sizeof(cap));
327 cap.Cap = captype;
328 cap.ConType = TWON_DONTCARE16;
329
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)
335 {
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);
340 }
341 }
342
343 if (actual_support & TWQC_GET)
344 {
345 memset(&cap, 0, sizeof(cap));
346 cap.Cap = captype;
347 cap.ConType = TWON_DONTCARE16;
348
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)
354 {
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);
366 }
367 }
368
369 if (actual_support & TWQC_SET)
370 {
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);
375
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);
381
382 }
383
384 if (actual_support & TWQC_RESET)
385 {
386 memset(&cap, 0, sizeof(cap));
387 cap.Cap = captype;
388 cap.ConType = TWON_DONTCARE16;
389
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);
396 }
397 }
398
399 static void test_physical(TW_IDENTITY *appid, TW_IDENTITY *source, TW_UINT16 captype, TW_INT32 minimum_support)
400 {
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;
407
408 memset(&cap, 0, sizeof(cap));
409 cap.Cap = captype;
410 cap.ConType = TWON_DONTCARE16;
411
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);
422
423
424 if (actual_support & TWQC_GETCURRENT)
425 {
426 memset(&cap, 0, sizeof(cap));
427 cap.Cap = captype;
428 cap.ConType = TWON_DONTCARE16;
429
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)
435 {
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);
439 }
440 }
441
442 if (actual_support & TWQC_GETDEFAULT)
443 {
444 memset(&cap, 0, sizeof(cap));
445 cap.Cap = captype;
446 cap.ConType = TWON_DONTCARE16;
447
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)
453 {
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);
457 }
458 }
459
460 if (actual_support & TWQC_GET)
461 {
462 memset(&cap, 0, sizeof(cap));
463 cap.Cap = captype;
464 cap.ConType = TWON_DONTCARE16;
465
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)
471 {
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);
476 }
477 }
478
479 }
480
481 static void test_supported_sizes(TW_IDENTITY *appid, TW_IDENTITY *source, TW_INT32 minimum_support)
482 {
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;
492
493
494 memset(&cap, 0, sizeof(cap));
495 cap.Cap = ICAP_SUPPORTEDSIZES;
496 cap.ConType = TWON_DONTCARE16;
497
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);
507
508 if (actual_support & TWQC_GETCURRENT)
509 {
510 memset(&cap, 0, sizeof(cap));
511 cap.Cap = ICAP_SUPPORTEDSIZES;
512 cap.ConType = TWON_DONTCARE16;
513
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)
519 {
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;
525 }
526 }
527
528 if (actual_support & TWQC_GETDEFAULT)
529 {
530 memset(&cap, 0, sizeof(cap));
531 cap.Cap = ICAP_SUPPORTEDSIZES;
532 cap.ConType = TWON_DONTCARE16;
533
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)
539 {
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;
545 }
546 }
547
548 if (actual_support & TWQC_GET)
549 {
550 memset(&cap, 0, sizeof(cap));
551 cap.Cap = ICAP_SUPPORTEDSIZES;
552 cap.ConType = TWON_DONTCARE16;
553
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);
559 }
560
561 if (actual_support & TWQC_SET)
562 {
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);
567
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);
573
574 }
575
576 if (actual_support & TWQC_RESET)
577 {
578 memset(&cap, 0, sizeof(cap));
579 cap.Cap = ICAP_SUPPORTEDSIZES;
580 cap.ConType = TWON_DONTCARE16;
581
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);
588 }
589 }
590
591 static void test_imagelayout(TW_IDENTITY *appid, TW_IDENTITY *source)
592 {
593 TW_UINT16 rc;
594 TW_STATUS status;
595 TW_IMAGELAYOUT layout;
596
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);
609
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;
621
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);
634 }
635
636
637 static void test_single_source(TW_IDENTITY *appid, TW_IDENTITY *source)
638 {
639 TW_UINT16 rc;
640 TW_STATUS status;
641 TW_CAPABILITY cap;
642 UINT16 capabilities[CAP_CUSTOMBASE];
643
644 memset(&cap, 0, sizeof(cap));
645 cap.Cap = CAP_SUPPORTEDCAPS;
646 cap.ConType = TWON_DONTCARE16;
647
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");
652
653 memset(capabilities, 0, sizeof(capabilities));
654 if (rc == TWRC_SUCCESS && cap.ConType == TWON_ARRAY)
655 {
656 TW_ARRAY *a;
657 a = GlobalLock(cap.hContainer);
658 if (a)
659 {
660 if (a->ItemType == TWTY_UINT16)
661 {
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] < ARRAY_SIZE(capabilities))
667 {
668 capabilities[u[i]] = 1;
669 trace(" %d: 0x%x\n", i, u[i]);
670 }
671 }
672 GlobalUnlock(cap.hContainer);
673 }
674 }
675
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);
685
686 if (source->SupportedGroups & DG_IMAGE)
687 {
688 /*
689 Sources that supply image information must support DG_CONTROL / DAT_CAPABILITY /
690 MSG_GET, MSG_GETCURRENT, MSG_GETDEFAULT on:
691 */
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);
710
711 /*
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:
714 */
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);
741
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);
752
753 /* Additional tests */
754 test_imagelayout(appid, source);
755
756 }
757 }
758
759 static void test_sources(TW_IDENTITY *appid)
760 {
761 TW_UINT16 rc;
762 TW_IDENTITY source;
763 TW_STATUS status;
764 int scannercount = 0;
765
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);
772
773 while (rc == TWRC_SUCCESS)
774 {
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);
785 }
786
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);
793
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)
796 {
797 rc = pDSM_Entry(appid, NULL, DG_CONTROL, DAT_IDENTITY, MSG_OPENDS, &source);
798 get_condition_code(appid, NULL, &status);
799
800 if (rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS)
801 {
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);
805 }
806 }
807
808 if (winetest_interactive)
809 {
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);
815
816 if (rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS)
817 {
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)
821 {
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);
826 }
827 }
828 }
829
830 }
831
832 START_TEST(dsm)
833 {
834 TW_IDENTITY appid;
835 TW_UINT16 rc;
836 HANDLE hwnd;
837 HMODULE htwain;
838
839 if (!dsm_RegisterWindowClasses())
840 {
841 skip("Could not register the test class, skipping tests\n");
842 return;
843 }
844
845 htwain = LoadLibraryA("twain_32.dll");
846 if (! htwain)
847 {
848 win_skip("twain_32.dll not available, skipping tests\n");
849 return;
850 }
851 pDSM_Entry = (void*)GetProcAddress(htwain, "DSM_Entry");
852 ok(pDSM_Entry != NULL, "Unable to GetProcAddress DSM_Entry\n");
853 if (! pDSM_Entry)
854 {
855 win_skip("DSM_Entry not available, skipping tests\n");
856 return;
857 }
858
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;
865
866 hwnd = CreateWindowA("TWAIN_dsm_class", "Twain Test", 0, CW_USEDEFAULT, CW_USEDEFAULT,
867 CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, GetModuleHandleA(NULL), NULL);
868
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);
871
872 test_sources(&appid);
873
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);
876
877 DestroyWindow(hwnd);
878 FreeLibrary(htwain);
879 }