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 } 880