twain_32/tests: Enable compilation with long types.
[wine.git] / dlls / twain_32 / tests / dsm.c
blobf12110c664bfe5970a7a1fb6f39351898009347e
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=%lu\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
76 *ret = 0;
77 if (type) *type = 0;
79 return FALSE;
82 static TW_HANDLE alloc_and_set_onevalue(TW_UINT32 val, TW_UINT16 type)
84 TW_HANDLE hcontainer;
85 TW_ONEVALUE *onev;
86 hcontainer = GlobalAlloc(0, sizeof(*onev));
87 if (hcontainer)
89 onev = GlobalLock(hcontainer);
90 if (onev)
92 onev->ItemType = type;
93 onev->Item = val;
94 GlobalUnlock(hcontainer);
96 else
98 GlobalFree(hcontainer);
99 hcontainer = 0;
102 return hcontainer;
105 static void check_get(TW_CAPABILITY *pCapability, TW_INT32 actual_support,
106 TW_UINT32 orig_value, TW_UINT32 default_value, TW_UINT32 *suggested_set_value)
108 void *p;
109 if (suggested_set_value)
110 *suggested_set_value = orig_value + 1;
111 p = GlobalLock(pCapability->hContainer);
112 if (p)
114 if (pCapability->ConType == TWON_ONEVALUE)
116 TW_ONEVALUE *onev = p;
117 ok(onev->Item == orig_value || !(actual_support & TWQC_GETCURRENT), "MSG_GET of 0x%x returned 0x%lx, expecting 0x%lx\n",
118 pCapability->Cap, onev->Item, orig_value);
119 trace("MSG_GET of 0x%x returned val 0x%lx, type %d\n", pCapability->Cap, onev->Item, onev->ItemType);
120 if (suggested_set_value)
121 *suggested_set_value = onev->Item;
123 else if (pCapability->ConType == TWON_ENUMERATION)
125 int i;
126 TW_UINT8 *p8;
127 TW_UINT16 *p16;
128 TW_UINT32 *p32;
129 TW_ENUMERATION *enumv = p;
130 p8 = enumv->ItemList;
131 p16 = (TW_UINT16 *) p8;
132 p32 = (TW_UINT32 *) p8;
133 trace("MSG_GET of 0x%x returned %ld items:\n", pCapability->Cap, enumv->NumItems);
134 for (i = 0; i < enumv->NumItems; i++)
136 if (enumv->ItemType == TWTY_UINT8 || enumv->ItemType == TWTY_INT8)
137 trace(" %d: 0x%x\n", i, p8[i]);
138 if (enumv->ItemType == TWTY_UINT16 || enumv->ItemType == TWTY_INT16)
139 trace(" %d: 0x%x\n", i, p16[i]);
140 if (enumv->ItemType == TWTY_UINT32 || enumv->ItemType == TWTY_INT32)
141 trace(" %d: 0x%lx\n", i, p32[i]);
143 if (enumv->ItemType == TWTY_UINT16 || enumv->ItemType == TWTY_INT16)
145 ok(p16[enumv->CurrentIndex] == orig_value,
146 "Type 0x%x, values from MSG_GET (0x%x) and MSG_GETCURRENT (0x%lx) do not match.\n",
147 pCapability->Cap, p16[enumv->CurrentIndex], orig_value);
148 ok(p16[enumv->DefaultIndex] == default_value,
149 "Type 0x%x, values from MSG_GET (0x%x) and MSG_GETDEFAULT (0x%lx) do not match.\n",
150 pCapability->Cap, p16[enumv->DefaultIndex], default_value);
151 if (suggested_set_value)
152 *suggested_set_value = p16[(enumv->CurrentIndex + 1) % enumv->NumItems];
154 if (enumv->ItemType == TWTY_UINT32 || enumv->ItemType == TWTY_INT32)
156 ok(p32[enumv->CurrentIndex] == orig_value,
157 "Type 0x%x, values from MSG_GET (0x%lx) and MSG_GETCURRENT (0x%lx) do not match.\n",
158 pCapability->Cap, p32[enumv->CurrentIndex], orig_value);
159 ok(p32[enumv->DefaultIndex] == default_value,
160 "Type 0x%x, values from MSG_GET (0x%lx) and MSG_GETDEFAULT (0x%lx) do not match.\n",
161 pCapability->Cap, p32[enumv->DefaultIndex], default_value);
162 if (suggested_set_value)
163 *suggested_set_value = p32[(enumv->CurrentIndex + 1) % enumv->NumItems];
166 else
167 trace("MSG_GET on type 0x%x returned type 0x%x, which we didn't check.\n", pCapability->Cap, pCapability->ConType);
168 GlobalUnlock(pCapability->hContainer);
172 static void test_onevalue_cap(TW_IDENTITY *appid, TW_IDENTITY *source, TW_UINT16 captype, TW_UINT16 type, TW_INT32 minimum_support)
174 TW_UINT16 rc;
175 TW_UINT16 rtype;
176 TW_STATUS status;
177 TW_CAPABILITY cap;
178 TW_UINT32 orig_value = 0;
179 TW_UINT32 new_value;
180 TW_UINT32 default_value = 0;
181 TW_INT32 actual_support;
183 memset(&cap, 0, sizeof(cap));
184 cap.Cap = captype;
185 cap.ConType = TWON_DONTCARE16;
187 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_QUERYSUPPORT, &cap);
188 get_condition_code(appid, source, &status);
189 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
190 "Error [rc %d|cc %d] doing MSG_QUERYSUPPORT for type 0x%x\n", rc, status.ConditionCode, captype);
191 if (rc != TWRC_SUCCESS)
192 return;
193 ok(get_onevalue(cap.hContainer, (TW_UINT32 *) &actual_support, NULL), "Returned cap.hContainer invalid for QuerySupport on type 0x%x\n", captype);
194 ok((actual_support & minimum_support) == minimum_support,
195 "Error: minimum support 0x%lx for type 0x%x, got 0x%lx\n", minimum_support,
196 captype, actual_support);
199 if (actual_support & TWQC_GETCURRENT)
201 memset(&cap, 0, sizeof(cap));
202 cap.Cap = captype;
203 cap.ConType = TWON_DONTCARE16;
205 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GETCURRENT, &cap);
206 get_condition_code(appid, source, &status);
207 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
208 "Error [rc %d|cc %d] doing MSG_GETCURRENT for type 0x%x\n", rc, status.ConditionCode, captype);
209 if (rc == TWRC_SUCCESS)
211 ok(get_onevalue(cap.hContainer, &orig_value, &rtype), "Returned cap.hContainer invalid for GETCURRENT on type 0x%x\n", captype);
212 ok(rtype == type, "Returned GETCURRENT type 0x%x for cap 0x%x is not expected 0x%x\n", rtype, captype, type);
213 GlobalFree(cap.hContainer);
217 if (actual_support & TWQC_GETDEFAULT)
219 memset(&cap, 0, sizeof(cap));
220 cap.Cap = captype;
221 cap.ConType = TWON_DONTCARE16;
223 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GETDEFAULT, &cap);
224 get_condition_code(appid, source, &status);
225 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
226 "Error [rc %d|cc %d] doing MSG_GETDEFAULT for type 0x%x\n", rc, status.ConditionCode, captype);
227 if (rc == TWRC_SUCCESS)
229 ok(get_onevalue(cap.hContainer, &default_value, &rtype), "Returned cap.hContainer invalid for GETDEFAULT on type 0x%x\n", captype);
230 ok(rtype == type, "Returned GETDEFAULT type 0x%x for cap 0x%x is not expected 0x%x\n", rtype, captype, type);
231 GlobalFree(cap.hContainer);
235 new_value = orig_value;
236 if (actual_support & TWQC_GET)
238 memset(&cap, 0, sizeof(cap));
239 cap.Cap = captype;
240 cap.ConType = TWON_DONTCARE16;
242 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GET, &cap);
243 get_condition_code(appid, source, &status);
244 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
245 "Error [rc %d|cc %d] doing MSG_GET for type 0x%x\n", rc, status.ConditionCode, captype);
246 check_get(&cap, actual_support, orig_value, default_value, &new_value);
247 if (rc == TWRC_SUCCESS)
248 GlobalFree(cap.hContainer);
251 if (actual_support & TWQC_SET)
253 memset(&cap, 0, sizeof(cap));
254 cap.Cap = captype;
255 cap.ConType = TWON_ONEVALUE;
256 cap.hContainer = alloc_and_set_onevalue(new_value, type);
258 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_SET, &cap);
259 get_condition_code(appid, source, &status);
260 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
261 "Error [rc %d|cc %d] doing MSG_SET for type 0x%x\n", rc, status.ConditionCode, captype);
262 GlobalFree(cap.hContainer);
265 if (actual_support & TWQC_RESET)
267 memset(&cap, 0, sizeof(cap));
268 cap.Cap = captype;
269 cap.ConType = TWON_DONTCARE16;
271 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_RESET, &cap);
272 get_condition_code(appid, source, &status);
273 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
274 "Error [rc %d|cc %d] doing MSG_RESET for type 0x%x\n", rc, status.ConditionCode, captype);
275 if (rc == TWRC_SUCCESS)
276 GlobalFree(cap.hContainer);
280 static void test_resolution(TW_IDENTITY *appid, TW_IDENTITY *source, TW_UINT16 captype, TW_INT32 minimum_support)
282 TW_UINT16 rc;
283 TW_STATUS status;
284 TW_CAPABILITY cap;
285 TW_UINT32 val;
286 TW_UINT16 type;
287 TW_INT32 actual_support;
288 TW_FIX32 orig_value = { 0, 0 };
289 TW_UINT32 new_value = 0;
290 TW_FIX32 default_value = { 0, 0 };
292 memset(&cap, 0, sizeof(cap));
293 cap.Cap = captype;
294 cap.ConType = TWON_DONTCARE16;
296 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_QUERYSUPPORT, &cap);
297 get_condition_code(appid, source, &status);
298 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
299 "Error [rc %d|cc %d] doing MSG_QUERYSUPPORT for type 0x%x\n", rc, status.ConditionCode, captype);
300 if (rc != TWRC_SUCCESS)
301 return;
302 ok(get_onevalue(cap.hContainer, (TW_UINT32 *) &actual_support, NULL), "Returned cap.hContainer invalid for QuerySupport on type 0x%x\n", captype);
303 ok((actual_support & minimum_support) == minimum_support,
304 "Error: minimum support 0x%lx for type 0x%x, got 0x%lx\n", minimum_support,
305 captype, actual_support);
308 if (actual_support & TWQC_GETCURRENT)
310 memset(&cap, 0, sizeof(cap));
311 cap.Cap = captype;
312 cap.ConType = TWON_DONTCARE16;
314 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GETCURRENT, &cap);
315 get_condition_code(appid, source, &status);
316 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
317 "Error [rc %d|cc %d] doing MSG_GETCURRENT for type 0x%x\n", rc, status.ConditionCode, captype);
318 if (rc == TWRC_SUCCESS)
320 get_onevalue(cap.hContainer, &val, &type);
321 ok(type == TWTY_FIX32, "GETCURRENT for RESOLUTION is not type FIX32, is type %d\n", type);
322 memcpy(&orig_value, &val, sizeof(orig_value));
323 GlobalFree(cap.hContainer);
327 if (actual_support & TWQC_GETDEFAULT)
329 memset(&cap, 0, sizeof(cap));
330 cap.Cap = captype;
331 cap.ConType = TWON_DONTCARE16;
333 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GETDEFAULT, &cap);
334 get_condition_code(appid, source, &status);
335 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
336 "Error [rc %d|cc %d] doing MSG_GETDEFAULT for type 0x%x\n", rc, status.ConditionCode, captype);
337 if (rc == TWRC_SUCCESS)
339 get_onevalue(cap.hContainer, &val, &type);
340 ok(type == TWTY_FIX32, "GETDEFAULT for RESOLUTION is not type FIX32, is type %d\n", type);
341 memcpy(&default_value, &val, sizeof(default_value));
342 GlobalFree(cap.hContainer);
346 if (actual_support & TWQC_GET)
348 memset(&cap, 0, sizeof(cap));
349 cap.Cap = captype;
350 cap.ConType = TWON_DONTCARE16;
352 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GET, &cap);
353 get_condition_code(appid, source, &status);
354 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
355 "Error [rc %d|cc %d] doing MSG_GET for type 0x%x\n", rc, status.ConditionCode, captype);
356 if (rc == TWRC_SUCCESS)
358 TW_RANGE *range;
359 ok(cap.ConType == TWON_RANGE, "MSG_GET for ICAP_[XY]RESOLUTION did not return TWON_RANGE, but %d\n", cap.ConType);
360 range = GlobalLock(cap.hContainer);
361 trace("MSG_GET of 0x%x returned [ItemType %d|MinValue %ld|MaxValue %ld|StepSize %ld|DefaultValue %ld|CurrentValue %ld]:\n",
362 cap.Cap, range->ItemType, range->MinValue, range->MaxValue, range->StepSize,
363 range->DefaultValue, range->CurrentValue);
364 for (new_value = range->MinValue; new_value < range->MaxValue; new_value += range->StepSize)
365 if (new_value != range->CurrentValue)
366 break;
367 GlobalUnlock(cap.hContainer);
368 GlobalFree(cap.hContainer);
372 if (actual_support & TWQC_SET)
374 memset(&cap, 0, sizeof(cap));
375 cap.Cap = captype;
376 cap.ConType = TWON_ONEVALUE;
377 cap.hContainer = alloc_and_set_onevalue(new_value, TWTY_FIX32);
379 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_SET, &cap);
380 get_condition_code(appid, source, &status);
381 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
382 "Error [rc %d|cc %d] doing MSG_SET for type 0x%x\n", rc, status.ConditionCode, captype);
383 GlobalFree(cap.hContainer);
387 if (actual_support & TWQC_RESET)
389 memset(&cap, 0, sizeof(cap));
390 cap.Cap = captype;
391 cap.ConType = TWON_DONTCARE16;
393 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_RESET, &cap);
394 get_condition_code(appid, source, &status);
395 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
396 "Error [rc %d|cc %d] doing MSG_RESET for type 0x%x\n", rc, status.ConditionCode, captype);
397 if (rc == TWRC_SUCCESS)
398 GlobalFree(cap.hContainer);
402 static void test_physical(TW_IDENTITY *appid, TW_IDENTITY *source, TW_UINT16 captype, TW_INT32 minimum_support)
404 TW_UINT16 rc;
405 TW_STATUS status;
406 TW_CAPABILITY cap;
407 TW_UINT32 val;
408 TW_UINT16 type;
409 TW_INT32 actual_support;
411 memset(&cap, 0, sizeof(cap));
412 cap.Cap = captype;
413 cap.ConType = TWON_DONTCARE16;
415 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_QUERYSUPPORT, &cap);
416 get_condition_code(appid, source, &status);
417 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
418 "Error [rc %d|cc %d] doing MSG_QUERYSUPPORT for type 0x%x\n", rc, status.ConditionCode, captype);
419 if (rc != TWRC_SUCCESS)
420 return;
421 ok(get_onevalue(cap.hContainer, (TW_UINT32 *) &actual_support, NULL), "Returned cap.hContainer invalid for QuerySupport on type 0x%x\n", captype);
422 ok((actual_support & minimum_support) == minimum_support,
423 "Error: minimum support 0x%lx for type 0x%x, got 0x%lx\n", minimum_support,
424 captype, actual_support);
427 if (actual_support & TWQC_GETCURRENT)
429 memset(&cap, 0, sizeof(cap));
430 cap.Cap = captype;
431 cap.ConType = TWON_DONTCARE16;
433 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GETCURRENT, &cap);
434 get_condition_code(appid, source, &status);
435 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
436 "Error [rc %d|cc %d] doing MSG_GETCURRENT for type 0x%x\n", rc, status.ConditionCode, captype);
437 if (rc == TWRC_SUCCESS)
439 get_onevalue(cap.hContainer, &val, &type);
440 ok(type == TWTY_FIX32, "GETCURRENT for PHYSICALXXX is not type FIX32, is type %d\n", type);
441 GlobalFree(cap.hContainer);
445 if (actual_support & TWQC_GETDEFAULT)
447 memset(&cap, 0, sizeof(cap));
448 cap.Cap = captype;
449 cap.ConType = TWON_DONTCARE16;
451 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GETDEFAULT, &cap);
452 get_condition_code(appid, source, &status);
453 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
454 "Error [rc %d|cc %d] doing MSG_GETDEFAULT for type 0x%x\n", rc, status.ConditionCode, captype);
455 if (rc == TWRC_SUCCESS)
457 get_onevalue(cap.hContainer, &val, &type);
458 ok(type == TWTY_FIX32, "GETDEFAULT for PHYSICALXXX is not type FIX32, is type %d\n", type);
459 GlobalFree(cap.hContainer);
463 if (actual_support & TWQC_GET)
465 memset(&cap, 0, sizeof(cap));
466 cap.Cap = captype;
467 cap.ConType = TWON_DONTCARE16;
469 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GET, &cap);
470 get_condition_code(appid, source, &status);
471 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
472 "Error [rc %d|cc %d] doing MSG_GET for type 0x%x\n", rc, status.ConditionCode, captype);
473 if (rc == TWRC_SUCCESS)
475 get_onevalue(cap.hContainer, &val, &type);
476 ok(type == TWTY_FIX32, "GET for PHYSICALXXX is not type FIX32, is type %d\n", type);
477 trace("GET for Physical type 0x%x returns 0x%lx\n", captype, val);
478 GlobalFree(cap.hContainer);
484 static void test_supported_sizes(TW_IDENTITY *appid, TW_IDENTITY *source, TW_INT32 minimum_support)
486 TW_UINT16 rc;
487 TW_STATUS status;
488 TW_CAPABILITY cap;
489 TW_UINT32 val;
490 TW_UINT16 type;
491 TW_INT32 actual_support;
492 TW_UINT32 orig_value = TWSS_NONE;
493 TW_UINT32 default_value = TWSS_NONE;
494 TW_UINT32 new_value = TWSS_NONE;
497 memset(&cap, 0, sizeof(cap));
498 cap.Cap = ICAP_SUPPORTEDSIZES;
499 cap.ConType = TWON_DONTCARE16;
501 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_QUERYSUPPORT, &cap);
502 get_condition_code(appid, source, &status);
503 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
504 "Error [rc %d|cc %d] doing MSG_QUERYSUPPORT for ICAP_SUPPORTEDSIZES\n", rc, status.ConditionCode);
505 if (rc != TWRC_SUCCESS)
506 return;
507 ok(get_onevalue(cap.hContainer, (TW_UINT32 *) &actual_support, NULL), "Returned cap.hContainer invalid for QuerySupport on ICAP_SUPPORTEDSIZES\n");
508 ok((actual_support & minimum_support) == minimum_support,
509 "Error: minimum support 0x%lx for ICAP_SUPPORTEDSIZES, got 0x%lx\n", minimum_support, actual_support);
511 if (actual_support & TWQC_GETCURRENT)
513 memset(&cap, 0, sizeof(cap));
514 cap.Cap = ICAP_SUPPORTEDSIZES;
515 cap.ConType = TWON_DONTCARE16;
517 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GETCURRENT, &cap);
518 get_condition_code(appid, source, &status);
519 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
520 "Error [rc %d|cc %d] doing MSG_GETCURRENT for ICAP_SUPPORTEDSIZES\n", rc, status.ConditionCode);
521 if (rc == TWRC_SUCCESS)
523 get_onevalue(cap.hContainer, &val, &type);
524 ok(type == TWTY_UINT16, "GETCURRENT for ICAP_SUPPORTEDSIZES is not type UINT16, is type %d\n", type);
525 trace("Current size is %ld\n", val);
526 GlobalFree(cap.hContainer);
527 orig_value = val;
531 if (actual_support & TWQC_GETDEFAULT)
533 memset(&cap, 0, sizeof(cap));
534 cap.Cap = ICAP_SUPPORTEDSIZES;
535 cap.ConType = TWON_DONTCARE16;
537 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GETDEFAULT, &cap);
538 get_condition_code(appid, source, &status);
539 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
540 "Error [rc %d|cc %d] doing MSG_GETDEFAULT for ICAP_SUPPORTEDSIZES\n", rc, status.ConditionCode);
541 if (rc == TWRC_SUCCESS)
543 get_onevalue(cap.hContainer, &val, &type);
544 ok(type == TWTY_UINT16, "GETDEFAULT for PHYSICALXXX is not type TWTY_UINT16, is type %d\n", type);
545 trace("Default size is %ld\n", val);
546 GlobalFree(cap.hContainer);
547 default_value = val;
551 if (actual_support & TWQC_GET)
553 memset(&cap, 0, sizeof(cap));
554 cap.Cap = ICAP_SUPPORTEDSIZES;
555 cap.ConType = TWON_DONTCARE16;
557 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GET, &cap);
558 get_condition_code(appid, source, &status);
559 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
560 "Error [rc %d|cc %d] doing MSG_GET for ICAP_SUPPORTEDSIZES\n", rc, status.ConditionCode);
561 check_get(&cap, actual_support, orig_value, default_value, &new_value);
564 if (actual_support & TWQC_SET)
566 memset(&cap, 0, sizeof(cap));
567 cap.Cap = ICAP_SUPPORTEDSIZES;
568 cap.ConType = TWON_ONEVALUE;
569 cap.hContainer = alloc_and_set_onevalue(new_value, TWTY_UINT16);
571 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_SET, &cap);
572 get_condition_code(appid, source, &status);
573 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
574 "Error [rc %d|cc %d] doing MSG_SET for ICAP_SUPPORTEDSIZES\n", rc, status.ConditionCode);
575 GlobalFree(cap.hContainer);
579 if (actual_support & TWQC_RESET)
581 memset(&cap, 0, sizeof(cap));
582 cap.Cap = ICAP_SUPPORTEDSIZES;
583 cap.ConType = TWON_DONTCARE16;
585 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_RESET, &cap);
586 get_condition_code(appid, source, &status);
587 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
588 "Error [rc %d|cc %d] doing MSG_RESET for ICAP_SUPPORTEDSIZES\n", rc, status.ConditionCode);
589 if (rc == TWRC_SUCCESS)
590 GlobalFree(cap.hContainer);
594 static void test_imagelayout(TW_IDENTITY *appid, TW_IDENTITY *source)
596 TW_UINT16 rc;
597 TW_STATUS status;
598 TW_IMAGELAYOUT layout;
600 rc = pDSM_Entry(appid, source, DG_IMAGE, DAT_IMAGELAYOUT, MSG_GET, &layout);
601 get_condition_code(appid, source, &status);
602 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
603 "Error [rc %d|cc %d] doing MSG_GET for DG_IMAGE/DAT_IMAGELAYOUT\n", rc, status.ConditionCode);
604 if (rc != TWRC_SUCCESS)
605 return;
606 trace("ImageLayout [Left %x.%x|Top %x.%x|Right %x.%x|Bottom %x.%x|Document %ld|Page %ld|Frame %ld]\n",
607 layout.Frame.Left.Whole, layout.Frame.Left.Frac,
608 layout.Frame.Top.Whole, layout.Frame.Top.Frac,
609 layout.Frame.Right.Whole, layout.Frame.Right.Frac,
610 layout.Frame.Bottom.Whole, layout.Frame.Bottom.Frac,
611 layout.DocumentNumber, layout.PageNumber, layout.FrameNumber);
613 memset(&layout, 0, sizeof(layout));
614 layout.Frame.Left.Whole = 1;
615 layout.Frame.Right.Whole = 2;
616 layout.Frame.Top.Whole = 1;
617 layout.Frame.Bottom.Whole = 2;
618 rc = pDSM_Entry(appid, source, DG_IMAGE, DAT_IMAGELAYOUT, MSG_SET, &layout);
619 get_condition_code(appid, source, &status);
620 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
621 "Error [rc %d|cc %d] doing MSG_SET for DG_IMAGE/DAT_IMAGELAYOUT\n", rc, status.ConditionCode);
622 if (rc != TWRC_SUCCESS)
623 return;
625 rc = pDSM_Entry(appid, source, DG_IMAGE, DAT_IMAGELAYOUT, MSG_GET, &layout);
626 get_condition_code(appid, source, &status);
627 ok(rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS,
628 "Error [rc %d|cc %d] doing MSG_GET for DG_IMAGE/DAT_IMAGELAYOUT\n", rc, status.ConditionCode);
629 if (rc != TWRC_SUCCESS)
630 return;
631 trace("ImageLayout after set [Left %x.%x|Top %x.%x|Right %x.%x|Bottom %x.%x|Document %ld|Page %ld|Frame %ld]\n",
632 layout.Frame.Left.Whole, layout.Frame.Left.Frac,
633 layout.Frame.Top.Whole, layout.Frame.Top.Frac,
634 layout.Frame.Right.Whole, layout.Frame.Right.Frac,
635 layout.Frame.Bottom.Whole, layout.Frame.Bottom.Frac,
636 layout.DocumentNumber, layout.PageNumber, layout.FrameNumber);
640 static void test_single_source(TW_IDENTITY *appid, TW_IDENTITY *source)
642 TW_UINT16 rc;
643 TW_STATUS status;
644 TW_CAPABILITY cap;
645 UINT16 capabilities[CAP_CUSTOMBASE];
647 memset(&cap, 0, sizeof(cap));
648 cap.Cap = CAP_SUPPORTEDCAPS;
649 cap.ConType = TWON_DONTCARE16;
651 rc = pDSM_Entry(appid, source, DG_CONTROL, DAT_CAPABILITY, MSG_GET, &cap);
652 get_condition_code(appid, source, &status);
653 ok(rc == TWRC_SUCCESS || status.ConditionCode == TWCC_SUCCESS,
654 "Error obtaining CAP_SUPPORTEDCAPS\n");
656 memset(capabilities, 0, sizeof(capabilities));
657 if (rc == TWRC_SUCCESS && cap.ConType == TWON_ARRAY)
659 TW_ARRAY *a;
660 a = GlobalLock(cap.hContainer);
661 if (a)
663 if (a->ItemType == TWTY_UINT16)
665 int i;
666 UINT16 *u = (UINT16 *) a->ItemList;
667 trace("%ld Capabilities:\n", a->NumItems);
668 for (i = 0; i < a->NumItems; i++)
669 if (u[i] < ARRAY_SIZE(capabilities))
671 capabilities[u[i]] = 1;
672 trace(" %d: 0x%x\n", i, u[i]);
675 GlobalUnlock(cap.hContainer);
679 /* All sources must support: */
680 ok(capabilities[CAP_SUPPORTEDCAPS], "CAP_SUPPORTEDCAPS not supported\n");
681 ok(capabilities[CAP_XFERCOUNT], "CAP_XFERCOUNT not supported\n");
682 if (capabilities[CAP_XFERCOUNT])
683 test_onevalue_cap(appid, source, CAP_XFERCOUNT, TWTY_INT16,
684 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET);
685 ok(capabilities[CAP_UICONTROLLABLE], "CAP_UICONTROLLABLE not supported\n");
686 if (capabilities[CAP_UICONTROLLABLE])
687 test_onevalue_cap(appid, source, CAP_UICONTROLLABLE, TWTY_BOOL, TWQC_GET);
689 if (source->SupportedGroups & DG_IMAGE)
692 Sources that supply image information must support DG_CONTROL / DAT_CAPABILITY /
693 MSG_GET, MSG_GETCURRENT, MSG_GETDEFAULT on:
695 ok(capabilities[ICAP_COMPRESSION], "ICAP_COMPRESSION not supported\n");
696 if (capabilities[ICAP_COMPRESSION])
697 test_onevalue_cap(appid, source, ICAP_COMPRESSION, TWTY_UINT16,
698 TWQC_GET | TWQC_GETDEFAULT | TWQC_GETCURRENT);
699 todo_wine
700 ok(capabilities[ICAP_PLANARCHUNKY], "ICAP_PLANARCHUNKY not supported\n");
701 ok(capabilities[ICAP_PHYSICALHEIGHT], "ICAP_PHYSICALHEIGHT not supported\n");
702 if (capabilities[ICAP_PHYSICALHEIGHT])
703 test_physical(appid, source, ICAP_PHYSICALHEIGHT,
704 TWQC_GET | TWQC_GETDEFAULT | TWQC_GETCURRENT);
705 ok(capabilities[ICAP_PHYSICALWIDTH], "ICAP_PHYSICALWIDTH not supported\n");
706 if (capabilities[ICAP_PHYSICALWIDTH])
707 test_physical(appid, source, ICAP_PHYSICALWIDTH,
708 TWQC_GET | TWQC_GETDEFAULT | TWQC_GETCURRENT);
709 ok(capabilities[ICAP_PIXELFLAVOR], "ICAP_PIXELFLAVOR not supported\n");
710 if (capabilities[ICAP_PIXELFLAVOR])
711 test_onevalue_cap(appid, source, ICAP_PIXELFLAVOR, TWTY_UINT16,
712 TWQC_GET | TWQC_GETDEFAULT | TWQC_GETCURRENT);
715 Sources that supply image information must support DG_CONTROL / DAT_CAPABILITY /
716 MSG_GET, MSG_GETCURRENT, MSG_GETDEFAULT, MSG_RESET and MSG_SET on:
718 ok(capabilities[ICAP_BITDEPTH], "ICAP_BITDEPTH not supported\n");
719 if (capabilities[ICAP_BITDEPTH])
720 test_onevalue_cap(appid, source, ICAP_BITDEPTH, TWTY_UINT16,
721 TWQC_GET | TWQC_GETDEFAULT | TWQC_GETCURRENT );
722 todo_wine
723 ok(capabilities[ICAP_BITORDER], "ICAP_BITORDER not supported\n");
724 ok(capabilities[ICAP_PIXELTYPE], "ICAP_PIXELTYPE not supported\n");
725 if (capabilities[ICAP_PIXELTYPE])
726 test_onevalue_cap(appid, source, ICAP_PIXELTYPE, TWTY_UINT16,
727 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET);
728 ok(capabilities[ICAP_UNITS], "ICAP_UNITS not supported\n");
729 if (capabilities[ICAP_UNITS])
730 test_onevalue_cap(appid, source, ICAP_UNITS, TWTY_UINT16,
731 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET);
732 ok(capabilities[ICAP_XFERMECH], "ICAP_XFERMECH not supported\n");
733 if (capabilities[ICAP_XFERMECH])
734 test_onevalue_cap(appid, source, ICAP_XFERMECH, TWTY_UINT16,
735 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET);
736 ok(capabilities[ICAP_XRESOLUTION], "ICAP_XRESOLUTION not supported\n");
737 if (capabilities[ICAP_XRESOLUTION])
738 test_resolution(appid, source, ICAP_XRESOLUTION,
739 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET);
740 ok(capabilities[ICAP_YRESOLUTION], "ICAP_YRESOLUTION not supported\n");
741 if (capabilities[ICAP_YRESOLUTION])
742 test_resolution(appid, source, ICAP_YRESOLUTION,
743 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET);
745 /* Optional capabilities */
746 if (capabilities[CAP_AUTOFEED])
747 test_onevalue_cap(appid, source, CAP_AUTOFEED, TWTY_BOOL,
748 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET);
749 if (capabilities[CAP_FEEDERENABLED])
750 test_onevalue_cap(appid, source, CAP_FEEDERENABLED, TWTY_BOOL,
751 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET);
752 if (capabilities[ICAP_SUPPORTEDSIZES])
753 test_supported_sizes(appid, source,
754 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET);
756 /* Additional tests */
757 test_imagelayout(appid, source);
762 static void test_sources(TW_IDENTITY *appid)
764 TW_UINT16 rc;
765 TW_IDENTITY source;
766 TW_STATUS status;
767 int scannercount = 0;
769 memset(&source, 0, sizeof(source));
770 rc = pDSM_Entry(appid, NULL, DG_CONTROL, DAT_IDENTITY, MSG_GETFIRST, &source);
771 get_condition_code(appid, NULL, &status);
772 ok( (rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS) ||
773 (rc == TWRC_FAILURE && status.ConditionCode == TWCC_NODS),
774 "Get first invalid condition code, rc %d, cc %d\n", rc, status.ConditionCode);
776 while (rc == TWRC_SUCCESS)
778 scannercount++;
779 trace("[Scanner %d|Version %d.%d(%s)|Protocol %d.%d|SupportedGroups 0x%lx|Manufacturer %s|Family %s|ProductName %s]\n",
780 scannercount,
781 source.Version.MajorNum, source.Version.MinorNum, source.Version.Info,
782 source.ProtocolMajor, source.ProtocolMinor, source.SupportedGroups,
783 source.Manufacturer, source.ProductFamily, source.ProductName);
784 memset(&source, 0, sizeof(source));
785 rc = pDSM_Entry(appid, NULL, DG_CONTROL, DAT_IDENTITY, MSG_GETNEXT, &source);
786 get_condition_code(appid, NULL, &status);
787 ok(rc == TWRC_SUCCESS || rc == TWRC_ENDOFLIST, "Get next source failed, rc %d, cc %d\n", rc, status.ConditionCode);
790 memset(&source, 0, sizeof(source));
791 rc = pDSM_Entry(appid, NULL, DG_CONTROL, DAT_IDENTITY, MSG_GETDEFAULT, &source);
792 get_condition_code(appid, NULL, &status);
793 ok( (rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS) ||
794 (rc == TWRC_FAILURE && status.ConditionCode == TWCC_NODS),
795 "Get default invalid condition code, rc %d, cc %d\n", rc, status.ConditionCode);
797 /* A DS might display a Popup during MSG_OPENDS, when the scanner is not connected */
798 if (rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS && winetest_interactive)
800 rc = pDSM_Entry(appid, NULL, DG_CONTROL, DAT_IDENTITY, MSG_OPENDS, &source);
801 get_condition_code(appid, NULL, &status);
803 if (rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS)
805 rc = pDSM_Entry(appid, NULL, DG_CONTROL, DAT_IDENTITY, MSG_CLOSEDS, &source);
806 get_condition_code(appid, NULL, &status);
807 ok(rc == TWRC_SUCCESS, "Close DS Failed, rc %d, cc %d\n", rc, status.ConditionCode);
811 if (winetest_interactive)
813 trace("Interactive, so trying userselect\n");
814 memset(&source, 0, sizeof(source));
815 rc = pDSM_Entry(appid, NULL, DG_CONTROL, DAT_IDENTITY, MSG_USERSELECT, &source);
816 get_condition_code(appid, NULL, &status);
817 ok(rc == TWRC_SUCCESS || rc == TWRC_CANCEL, "Userselect failed, rc %d, cc %d\n", rc, status.ConditionCode);
819 if (rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS)
821 rc = pDSM_Entry(appid, NULL, DG_CONTROL, DAT_IDENTITY, MSG_OPENDS, &source);
822 get_condition_code(appid, NULL, &status);
823 if (rc == TWRC_SUCCESS && status.ConditionCode == TWCC_SUCCESS)
825 test_single_source(appid, &source);
826 rc = pDSM_Entry(appid, NULL, DG_CONTROL, DAT_IDENTITY, MSG_CLOSEDS, &source);
827 get_condition_code(appid, NULL, &status);
828 ok(rc == TWRC_SUCCESS, "Close DS Failed, rc %d, cc %d\n", rc, status.ConditionCode);
835 START_TEST(dsm)
837 TW_IDENTITY appid;
838 TW_UINT16 rc;
839 HANDLE hwnd;
840 HMODULE htwain;
842 if (!dsm_RegisterWindowClasses())
844 skip("Could not register the test class, skipping tests\n");
845 return;
848 htwain = LoadLibraryA("twain_32.dll");
849 if (! htwain)
851 win_skip("twain_32.dll not available, skipping tests\n");
852 return;
854 pDSM_Entry = (void*)GetProcAddress(htwain, "DSM_Entry");
855 ok(pDSM_Entry != NULL, "Unable to GetProcAddress DSM_Entry\n");
856 if (! pDSM_Entry)
858 win_skip("DSM_Entry not available, skipping tests\n");
859 return;
862 memset(&appid, 0, sizeof(appid));
863 appid.Version.Language = TWLG_ENGLISH_USA;
864 appid.Version.Country = TWCY_USA;
865 appid.ProtocolMajor = TWON_PROTOCOLMAJOR;
866 appid.ProtocolMinor = TWON_PROTOCOLMINOR;
867 appid.SupportedGroups = DG_CONTROL | DG_IMAGE;
869 hwnd = CreateWindowA("TWAIN_dsm_class", "Twain Test", 0, CW_USEDEFAULT, CW_USEDEFAULT,
870 CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, GetModuleHandleA(NULL), NULL);
872 rc = pDSM_Entry(&appid, NULL, DG_CONTROL, DAT_PARENT, MSG_OPENDSM, (TW_MEMREF) &hwnd);
873 ok(rc == TWRC_SUCCESS, "MSG_OPENDSM returned %d\n", rc);
875 test_sources(&appid);
877 rc = pDSM_Entry(&appid, NULL, DG_CONTROL, DAT_PARENT, MSG_CLOSEDSM, (TW_MEMREF) &hwnd);
878 ok(rc == TWRC_SUCCESS, "MSG_CLOSEDSM returned %d\n", rc);
880 DestroyWindow(hwnd);
881 FreeLibrary(htwain);