1 /* 2 * MSCMS - Color Management System for Wine 3 * 4 * Copyright 2004, 2005, 2006, 2008 Hans Leidekker 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include "config.h" 22 #include "wine/debug.h" 23 #include "wine/unicode.h" 24 25 #include <stdarg.h> 26 27 #include "windef.h" 28 #include "winbase.h" 29 #include "winnls.h" 30 #include "wingdi.h" 31 #include "winuser.h" 32 #include "winreg.h" 33 #include "shlwapi.h" 34 #include "icm.h" 35 36 #include "mscms_priv.h" 37 38 static void basename( LPCWSTR path, LPWSTR name ) 39 { 40 INT i = lstrlenW( path ); 41 42 while (i > 0 && path[i - 1] != '\\' && path[i - 1] != '/') i--; 43 lstrcpyW( name, &path[i] ); 44 } 45 46 static inline LPWSTR strdupW( LPCSTR str ) 47 { 48 LPWSTR ret = NULL; 49 if (str) 50 { 51 DWORD len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 ); 52 if ((ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) 53 MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len ); 54 } 55 return ret; 56 } 57 58 const char *dbgstr_tag( DWORD tag ) 59 { 60 return wine_dbg_sprintf( "'%c%c%c%c'", 61 (char)(tag >> 24), (char)(tag >> 16), (char)(tag >> 8), (char)(tag) ); 62 } 63 64 WINE_DEFAULT_DEBUG_CHANNEL(mscms); 65 66 /****************************************************************************** 67 * AssociateColorProfileWithDeviceA [MSCMS.@] 68 */ 69 BOOL WINAPI AssociateColorProfileWithDeviceA( PCSTR machine, PCSTR profile, PCSTR device ) 70 { 71 int len; 72 BOOL ret = FALSE; 73 WCHAR *profileW, *deviceW; 74 75 TRACE( "( %s, %s, %s )\n", debugstr_a(machine), debugstr_a(profile), debugstr_a(device) ); 76 77 if (!profile || !device) 78 { 79 SetLastError( ERROR_INVALID_PARAMETER ); 80 return FALSE; 81 } 82 if (machine) 83 { 84 SetLastError( ERROR_NOT_SUPPORTED ); 85 return FALSE; 86 } 87 88 len = MultiByteToWideChar( CP_ACP, 0, profile, -1, NULL, 0 ); 89 if (!(profileW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE; 90 91 MultiByteToWideChar( CP_ACP, 0, profile, -1, profileW, len ); 92 93 len = MultiByteToWideChar( CP_ACP, 0, device, -1, NULL, 0 ); 94 if ((deviceW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) 95 { 96 MultiByteToWideChar( CP_ACP, 0, device, -1, deviceW, len ); 97 ret = AssociateColorProfileWithDeviceW( NULL, profileW, deviceW ); 98 } 99 100 HeapFree( GetProcessHeap(), 0, profileW ); 101 HeapFree( GetProcessHeap(), 0, deviceW ); 102 return ret; 103 } 104 105 static BOOL set_profile_device_key( PCWSTR file, const BYTE *value, DWORD size ) 106 { 107 static const WCHAR fmtW[] = {'%','c','%','c','%','c','%','c',0}; 108 static const WCHAR icmW[] = {'S','o','f','t','w','a','r','e','\\', 109 'M','i','c','r','o','s','o','f','t','\\', 110 'W','i','n','d','o','w','s',' ','N','T','\\', 111 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', 112 'I','C','M',0}; 113 PROFILEHEADER header; 114 PROFILE profile; 115 HPROFILE handle; 116 HKEY icm_key, class_key; 117 WCHAR basenameW[MAX_PATH], classW[5]; 118 119 profile.dwType = PROFILE_FILENAME; 120 profile.pProfileData = (PVOID)file; 121 profile.cbDataSize = (lstrlenW( file ) + 1) * sizeof(WCHAR); 122 123 /* FIXME is the profile installed? */ 124 if (!(handle = OpenColorProfileW( &profile, PROFILE_READ, 0, OPEN_EXISTING ))) 125 { 126 SetLastError( ERROR_INVALID_PROFILE ); 127 return FALSE; 128 } 129 if (!GetColorProfileHeader( handle, &header )) 130 { 131 CloseColorProfile( handle ); 132 SetLastError( ERROR_INVALID_PROFILE ); 133 return FALSE; 134 } 135 RegCreateKeyExW( HKEY_LOCAL_MACHINE, icmW, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &icm_key, NULL ); 136 137 basename( file, basenameW ); 138 sprintfW( classW, fmtW, (header.phClass >> 24) & 0xff, (header.phClass >> 16) & 0xff, 139 (header.phClass >> 8) & 0xff, header.phClass & 0xff ); 140 141 RegCreateKeyExW( icm_key, classW, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &class_key, NULL ); 142 if (value) RegSetValueExW( class_key, basenameW, 0, REG_BINARY, value, size ); 143 else RegDeleteValueW( class_key, basenameW ); 144 145 RegCloseKey( class_key ); 146 RegCloseKey( icm_key ); 147 CloseColorProfile( handle ); 148 return TRUE; 149 } 150 151 /****************************************************************************** 152 * AssociateColorProfileWithDeviceW [MSCMS.@] 153 */ 154 BOOL WINAPI AssociateColorProfileWithDeviceW( PCWSTR machine, PCWSTR profile, PCWSTR device ) 155 { 156 static const BYTE dummy_value[12]; 157 158 TRACE( "( %s, %s, %s )\n", debugstr_w(machine), debugstr_w(profile), debugstr_w(device) ); 159 160 if (!profile || !device) 161 { 162 SetLastError( ERROR_INVALID_PARAMETER ); 163 return FALSE; 164 } 165 if (machine) 166 { 167 SetLastError( ERROR_NOT_SUPPORTED ); 168 return FALSE; 169 } 170 171 return set_profile_device_key( profile, dummy_value, sizeof(dummy_value) ); 172 } 173 174 /****************************************************************************** 175 * DisassociateColorProfileFromDeviceA [MSCMS.@] 176 */ 177 BOOL WINAPI DisassociateColorProfileFromDeviceA( PCSTR machine, PCSTR profile, PCSTR device ) 178 { 179 int len; 180 BOOL ret = FALSE; 181 WCHAR *profileW, *deviceW; 182 183 TRACE( "( %s, %s, %s )\n", debugstr_a(machine), debugstr_a(profile), debugstr_a(device) ); 184 185 if (!profile || !device) 186 { 187 SetLastError( ERROR_INVALID_PARAMETER ); 188 return FALSE; 189 } 190 if (machine) 191 { 192 SetLastError( ERROR_NOT_SUPPORTED ); 193 return FALSE; 194 } 195 196 len = MultiByteToWideChar( CP_ACP, 0, profile, -1, NULL, 0 ); 197 if (!(profileW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE; 198 199 MultiByteToWideChar( CP_ACP, 0, profile, -1, profileW, len ); 200 201 len = MultiByteToWideChar( CP_ACP, 0, device, -1, NULL, 0 ); 202 if ((deviceW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) 203 { 204 MultiByteToWideChar( CP_ACP, 0, device, -1, deviceW, len ); 205 ret = DisassociateColorProfileFromDeviceW( NULL, profileW, deviceW ); 206 } 207 208 HeapFree( GetProcessHeap(), 0, profileW ); 209 HeapFree( GetProcessHeap(), 0, deviceW ); 210 return ret; 211 } 212 213 /****************************************************************************** 214 * DisassociateColorProfileFromDeviceW [MSCMS.@] 215 */ 216 BOOL WINAPI DisassociateColorProfileFromDeviceW( PCWSTR machine, PCWSTR profile, PCWSTR device ) 217 { 218 TRACE( "( %s, %s, %s )\n", debugstr_w(machine), debugstr_w(profile), debugstr_w(device) ); 219 220 if (!profile || !device) 221 { 222 SetLastError( ERROR_INVALID_PARAMETER ); 223 return FALSE; 224 } 225 if (machine) 226 { 227 SetLastError( ERROR_NOT_SUPPORTED ); 228 return FALSE; 229 } 230 231 return set_profile_device_key( profile, NULL, 0 ); 232 } 233 234 /****************************************************************************** 235 * GetColorDirectoryA [MSCMS.@] 236 * 237 * See GetColorDirectoryW. 238 */ 239 BOOL WINAPI GetColorDirectoryA( PCSTR machine, PSTR buffer, PDWORD size ) 240 { 241 INT len; 242 LPWSTR bufferW; 243 BOOL ret = FALSE; 244 DWORD sizeW; 245 246 TRACE( "( %p, %p )\n", buffer, size ); 247 248 if (machine || !size) return FALSE; 249 250 if (!buffer) 251 { 252 ret = GetColorDirectoryW( NULL, NULL, &sizeW ); 253 *size = sizeW / sizeof(WCHAR); 254 return ret; 255 } 256 257 sizeW = *size * sizeof(WCHAR); 258 259 bufferW = HeapAlloc( GetProcessHeap(), 0, sizeW ); 260 if (bufferW) 261 { 262 if ((ret = GetColorDirectoryW( NULL, bufferW, &sizeW ))) 263 { 264 *size = WideCharToMultiByte( CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL ); 265 len = WideCharToMultiByte( CP_ACP, 0, bufferW, -1, buffer, *size, NULL, NULL ); 266 if (!len) ret = FALSE; 267 } 268 else *size = sizeW / sizeof(WCHAR); 269 270 HeapFree( GetProcessHeap(), 0, bufferW ); 271 } 272 return ret; 273 } 274 275 /****************************************************************************** 276 * GetColorDirectoryW [MSCMS.@] 277 * 278 * Get the directory where color profiles are stored. 279 * 280 * PARAMS 281 * machine [I] Name of the machine for which to get the color directory. 282 * Must be NULL, which indicates the local machine. 283 * buffer [I] Buffer to receive the path name. 284 * size [I/O] Size of the buffer in bytes. On return the variable holds 285 * the number of bytes actually needed. 286 */ 287 BOOL WINAPI GetColorDirectoryW( PCWSTR machine, PWSTR buffer, PDWORD size ) 288 { 289 WCHAR colordir[MAX_PATH]; 290 static const WCHAR colorsubdir[] = 291 {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\','c','o','l','o','r',0}; 292 DWORD len; 293 294 TRACE( "( %p, %p )\n", buffer, size ); 295 296 if (machine || !size) return FALSE; 297 298 GetSystemDirectoryW( colordir, ARRAY_SIZE( colordir )); 299 lstrcatW( colordir, colorsubdir ); 300 301 len = lstrlenW( colordir ) * sizeof(WCHAR); 302 303 if (buffer && len <= *size) 304 { 305 lstrcpyW( buffer, colordir ); 306 *size = len; 307 return TRUE; 308 } 309 310 SetLastError( ERROR_MORE_DATA ); 311 *size = len; 312 return FALSE; 313 } 314 315 /****************************************************************************** 316 * GetColorProfileElement [MSCMS.@] 317 * 318 * Retrieve data for a specified tag type. 319 * 320 * PARAMS 321 * profile [I] Handle to a color profile. 322 * type [I] ICC tag type. 323 * offset [I] Offset in bytes to start copying from. 324 * size [I/O] Size of the buffer in bytes. On return the variable holds 325 * the number of bytes actually needed. 326 * buffer [O] Buffer to receive the tag data. 327 * ref [O] Pointer to a BOOL that specifies whether more than one tag 328 * references the data. 329 * 330 * RETURNS 331 * Success: TRUE 332 * Failure: FALSE 333 */ 334 BOOL WINAPI GetColorProfileElement( HPROFILE handle, TAGTYPE type, DWORD offset, PDWORD size, 335 PVOID buffer, PBOOL ref ) 336 { 337 BOOL ret = FALSE; 338 #ifdef HAVE_LCMS2 339 struct profile *profile = grab_profile( handle ); 340 341 TRACE( "( %p, 0x%08x, %d, %p, %p, %p )\n", handle, type, offset, size, buffer, ref ); 342 343 if (!profile) return FALSE; 344 345 if (!size || !ref) 346 { 347 release_profile( profile ); 348 return FALSE; 349 } 350 if (!get_tag_data( profile, type, offset, buffer, size )) 351 { 352 release_profile( profile ); 353 return FALSE; 354 } 355 ret = get_tag_data( profile, type, offset, buffer, size ); 356 *ref = cmsTagLinkedTo( profile->cmsprofile, type ) != 0; 357 release_profile( profile ); 358 #endif /* HAVE_LCMS2 */ 359 return ret; 360 } 361 362 /****************************************************************************** 363 * GetColorProfileElementTag [MSCMS.@] 364 * 365 * Get the tag type from a color profile by index. 366 * 367 * PARAMS 368 * profile [I] Handle to a color profile. 369 * index [I] Index into the tag table of the color profile. 370 * type [O] Pointer to a variable that holds the ICC tag type on return. 371 * 372 * RETURNS 373 * Success: TRUE 374 * Failure: FALSE 375 * 376 * NOTES 377 * The tag table index starts at 1. 378 * Use GetCountColorProfileElements to retrieve a count of tagged elements. 379 */ 380 BOOL WINAPI GetColorProfileElementTag( HPROFILE handle, DWORD index, PTAGTYPE type ) 381 { 382 BOOL ret = FALSE; 383 #ifdef HAVE_LCMS2 384 struct profile *profile = grab_profile( handle ); 385 cmsInt32Number num_tags; 386 cmsTagSignature sig; 387 388 TRACE( "( %p, %d, %p )\n", handle, index, type ); 389 390 if (!profile) return FALSE; 391 392 if (!type) 393 { 394 release_profile( profile ); 395 return FALSE; 396 } 397 num_tags = cmsGetTagCount( profile->cmsprofile ); 398 if (num_tags < 0 || index > num_tags || index < 1) 399 { 400 release_profile( profile ); 401 return FALSE; 402 } 403 if ((sig = cmsGetTagSignature( profile->cmsprofile, index - 1 ))) 404 { 405 *type = sig; 406 ret = TRUE; 407 } 408 release_profile( profile ); 409 410 #endif /* HAVE_LCMS2 */ 411 return ret; 412 } 413 414 /****************************************************************************** 415 * GetColorProfileFromHandle [MSCMS.@] 416 * 417 * Retrieve an ICC color profile by handle. 418 * 419 * PARAMS 420 * profile [I] Handle to a color profile. 421 * buffer [O] Buffer to receive the ICC profile. 422 * size [I/O] Size of the buffer in bytes. On return the variable holds the 423 * number of bytes actually needed. 424 * 425 * RETURNS 426 * Success: TRUE 427 * Failure: FALSE 428 * 429 * NOTES 430 * The profile returned will be in big-endian format. 431 */ 432 BOOL WINAPI GetColorProfileFromHandle( HPROFILE handle, PBYTE buffer, PDWORD size ) 433 { 434 BOOL ret = FALSE; 435 #ifdef HAVE_LCMS2 436 struct profile *profile = grab_profile( handle ); 437 PROFILEHEADER header; 438 439 TRACE( "( %p, %p, %p )\n", handle, buffer, size ); 440 441 if (!profile) return FALSE; 442 443 if (!size) 444 { 445 release_profile( profile ); 446 return FALSE; 447 } 448 get_profile_header( profile, &header ); 449 450 if (!buffer || header.phSize > *size) 451 { 452 *size = header.phSize; 453 release_profile( profile ); 454 return FALSE; 455 } 456 457 /* No endian conversion needed */ 458 memcpy( buffer, profile->data, profile->size ); 459 *size = profile->size; 460 461 release_profile( profile ); 462 ret = TRUE; 463 464 #endif /* HAVE_LCMS2 */ 465 return ret; 466 } 467 468 /****************************************************************************** 469 * GetColorProfileHeader [MSCMS.@] 470 * 471 * Retrieve a color profile header by handle. 472 * 473 * PARAMS 474 * profile [I] Handle to a color profile. 475 * header [O] Buffer to receive the ICC profile header. 476 * 477 * RETURNS 478 * Success: TRUE 479 * Failure: FALSE 480 * 481 * NOTES 482 * The profile header returned will be adjusted for endianness. 483 */ 484 BOOL WINAPI GetColorProfileHeader( HPROFILE handle, PPROFILEHEADER header ) 485 { 486 #ifdef HAVE_LCMS2 487 struct profile *profile = grab_profile( handle ); 488 489 TRACE( "( %p, %p )\n", handle, header ); 490 491 if (!profile) return FALSE; 492 493 if (!header) 494 { 495 release_profile( profile ); 496 return FALSE; 497 } 498 get_profile_header( profile, header ); 499 release_profile( profile ); 500 return TRUE; 501 502 #else 503 return FALSE; 504 #endif /* HAVE_LCMS2 */ 505 } 506 507 /****************************************************************************** 508 * GetCountColorProfileElements [MSCMS.@] 509 * 510 * Retrieve the number of elements in a color profile. 511 * 512 * PARAMS 513 * profile [I] Handle to a color profile. 514 * count [O] Pointer to a variable which is set to the number of elements 515 * in the color profile. 516 * 517 * RETURNS 518 * Success: TRUE 519 * Failure: FALSE 520 */ 521 BOOL WINAPI GetCountColorProfileElements( HPROFILE handle, PDWORD count ) 522 { 523 BOOL ret = FALSE; 524 #ifdef HAVE_LCMS2 525 struct profile *profile = grab_profile( handle ); 526 cmsInt32Number num_tags; 527 528 TRACE( "( %p, %p )\n", handle, count ); 529 530 if (!profile) return FALSE; 531 532 if (!count) 533 { 534 release_profile( profile ); 535 return FALSE; 536 } 537 if ((num_tags = cmsGetTagCount( profile->cmsprofile )) >= 0) 538 { 539 *count = num_tags; 540 ret = TRUE; 541 } 542 release_profile( profile ); 543 544 #endif /* HAVE_LCMS2 */ 545 return ret; 546 } 547 548 /****************************************************************************** 549 * GetStandardColorSpaceProfileA [MSCMS.@] 550 * 551 * See GetStandardColorSpaceProfileW. 552 */ 553 BOOL WINAPI GetStandardColorSpaceProfileA( PCSTR machine, DWORD id, PSTR profile, PDWORD size ) 554 { 555 INT len; 556 LPWSTR profileW; 557 BOOL ret = FALSE; 558 DWORD sizeW; 559 560 TRACE( "( 0x%08x, %p, %p )\n", id, profile, size ); 561 562 if (machine) 563 { 564 SetLastError( ERROR_NOT_SUPPORTED ); 565 return FALSE; 566 } 567 568 if (!size) 569 { 570 SetLastError( ERROR_INVALID_PARAMETER ); 571 return FALSE; 572 } 573 574 sizeW = *size * sizeof(WCHAR); 575 576 if (!profile) 577 { 578 ret = GetStandardColorSpaceProfileW( NULL, id, NULL, &sizeW ); 579 *size = sizeW / sizeof(WCHAR); 580 return ret; 581 } 582 583 profileW = HeapAlloc( GetProcessHeap(), 0, sizeW ); 584 if (profileW) 585 { 586 if ((ret = GetStandardColorSpaceProfileW( NULL, id, profileW, &sizeW ))) 587 { 588 *size = WideCharToMultiByte( CP_ACP, 0, profileW, -1, NULL, 0, NULL, NULL ); 589 len = WideCharToMultiByte( CP_ACP, 0, profileW, -1, profile, *size, NULL, NULL ); 590 if (!len) ret = FALSE; 591 } 592 else *size = sizeW / sizeof(WCHAR); 593 594 HeapFree( GetProcessHeap(), 0, profileW ); 595 } 596 return ret; 597 } 598 599 /****************************************************************************** 600 * GetStandardColorSpaceProfileW [MSCMS.@] 601 * 602 * Retrieve the profile filename for a given standard color space id. 603 * 604 * PARAMS 605 * machine [I] Name of the machine for which to get the standard color space. 606 * Must be NULL, which indicates the local machine. 607 * id [I] Id of a standard color space. 608 * profile [O] Buffer to receive the profile filename. 609 * size [I/O] Size of the filename buffer in bytes. 610 * 611 * RETURNS 612 * Success: TRUE 613 * Failure: FALSE 614 */ 615 BOOL WINAPI GetStandardColorSpaceProfileW( PCWSTR machine, DWORD id, PWSTR profile, PDWORD size ) 616 { 617 static const WCHAR rgbprofilefile[] = 618 { '\\','s','r','g','b',' ','c','o','l','o','r',' ', 619 's','p','a','c','e',' ','p','r','o','f','i','l','e','.','i','c','m',0 }; 620 WCHAR rgbprofile[MAX_PATH]; 621 DWORD len = sizeof(rgbprofile); 622 623 TRACE( "( 0x%08x, %p, %p )\n", id, profile, size ); 624 625 if (machine) 626 { 627 SetLastError( ERROR_NOT_SUPPORTED ); 628 return FALSE; 629 } 630 631 if (!size) 632 { 633 SetLastError( ERROR_INVALID_PARAMETER ); 634 return FALSE; 635 } 636 637 if (!profile) 638 { 639 SetLastError( ERROR_INSUFFICIENT_BUFFER ); 640 return FALSE; 641 } 642 643 GetColorDirectoryW( machine, rgbprofile, &len ); 644 645 switch (id) 646 { 647 case LCS_sRGB: 648 case LCS_WINDOWS_COLOR_SPACE: /* FIXME */ 649 lstrcatW( rgbprofile, rgbprofilefile ); 650 len = lstrlenW( rgbprofile ) * sizeof(WCHAR); 651 652 if (*size < len) 653 { 654 *size = len; 655 SetLastError( ERROR_MORE_DATA ); 656 return FALSE; 657 } 658 659 lstrcpyW( profile, rgbprofile ); 660 break; 661 662 default: 663 SetLastError( ERROR_FILE_NOT_FOUND ); 664 return FALSE; 665 } 666 return TRUE; 667 } 668 669 static BOOL header_from_file( LPCWSTR file, PPROFILEHEADER header ) 670 { 671 static const WCHAR slash[] = {'\\',0}; 672 BOOL ret; 673 PROFILE profile; 674 WCHAR path[MAX_PATH]; 675 DWORD size = sizeof(path); 676 HANDLE handle; 677 678 ret = GetColorDirectoryW( NULL, path, &size ); 679 if (!ret) 680 { 681 WARN( "Can't retrieve color directory\n" ); 682 return FALSE; 683 } 684 if (size + sizeof(slash) + sizeof(WCHAR) * lstrlenW( file ) > sizeof(path)) 685 { 686 WARN( "Filename too long\n" ); 687 return FALSE; 688 } 689 690 lstrcatW( path, slash ); 691 lstrcatW( path, file ); 692 693 profile.dwType = PROFILE_FILENAME; 694 profile.pProfileData = path; 695 profile.cbDataSize = lstrlenW( path ) + 1; 696 697 handle = OpenColorProfileW( &profile, PROFILE_READ, FILE_SHARE_READ, OPEN_EXISTING ); 698 if (!handle) 699 { 700 WARN( "Can't open color profile\n" ); 701 return FALSE; 702 } 703 704 ret = GetColorProfileHeader( handle, header ); 705 if (!ret) 706 WARN( "Can't retrieve color profile header\n" ); 707 708 CloseColorProfile( handle ); 709 return ret; 710 } 711 712 static BOOL match_profile( PENUMTYPEW rec, PPROFILEHEADER hdr ) 713 { 714 if (rec->dwFields & ET_DEVICENAME) 715 { 716 FIXME( "ET_DEVICENAME: %s\n", debugstr_w(rec->pDeviceName) ); 717 } 718 if (rec->dwFields & ET_MEDIATYPE) 719 { 720 FIXME( "ET_MEDIATYPE: 0x%08x\n", rec->dwMediaType ); 721 } 722 if (rec->dwFields & ET_DITHERMODE) 723 { 724 FIXME( "ET_DITHERMODE: 0x%08x\n", rec->dwDitheringMode ); 725 } 726 if (rec->dwFields & ET_RESOLUTION) 727 { 728 FIXME( "ET_RESOLUTION: 0x%08x, 0x%08x\n", 729 rec->dwResolution[0], rec->dwResolution[1] ); 730 } 731 if (rec->dwFields & ET_DEVICECLASS) 732 { 733 FIXME( "ET_DEVICECLASS: %s\n", dbgstr_tag(rec->dwMediaType) ); 734 } 735 if (rec->dwFields & ET_CMMTYPE) 736 { 737 TRACE( "ET_CMMTYPE: %s\n", dbgstr_tag(rec->dwCMMType) ); 738 if (rec->dwCMMType != hdr->phCMMType) return FALSE; 739 } 740 if (rec->dwFields & ET_CLASS) 741 { 742 TRACE( "ET_CLASS: %s\n", dbgstr_tag(rec->dwClass) ); 743 if (rec->dwClass != hdr->phClass) return FALSE; 744 } 745 if (rec->dwFields & ET_DATACOLORSPACE) 746 { 747 TRACE( "ET_DATACOLORSPACE: %s\n", dbgstr_tag(rec->dwDataColorSpace) ); 748 if (rec->dwDataColorSpace != hdr->phDataColorSpace) return FALSE; 749 } 750 if (rec->dwFields & ET_CONNECTIONSPACE) 751 { 752 TRACE( "ET_CONNECTIONSPACE: %s\n", dbgstr_tag(rec->dwConnectionSpace) ); 753 if (rec->dwConnectionSpace != hdr->phConnectionSpace) return FALSE; 754 } 755 if (rec->dwFields & ET_SIGNATURE) 756 { 757 TRACE( "ET_SIGNATURE: %s\n", dbgstr_tag(rec->dwSignature) ); 758 if (rec->dwSignature != hdr->phSignature) return FALSE; 759 } 760 if (rec->dwFields & ET_PLATFORM) 761 { 762 TRACE( "ET_PLATFORM: %s\n", dbgstr_tag(rec->dwPlatform) ); 763 if (rec->dwPlatform != hdr->phPlatform) return FALSE; 764 } 765 if (rec->dwFields & ET_PROFILEFLAGS) 766 { 767 TRACE( "ET_PROFILEFLAGS: 0x%08x\n", rec->dwProfileFlags ); 768 if (rec->dwProfileFlags != hdr->phProfileFlags) return FALSE; 769 } 770 if (rec->dwFields & ET_MANUFACTURER) 771 { 772 TRACE( "ET_MANUFACTURER: %s\n", dbgstr_tag(rec->dwManufacturer) ); 773 if (rec->dwManufacturer != hdr->phManufacturer) return FALSE; 774 } 775 if (rec->dwFields & ET_MODEL) 776 { 777 TRACE( "ET_MODEL: %s\n", dbgstr_tag(rec->dwModel) ); 778 if (rec->dwModel != hdr->phModel) return FALSE; 779 } 780 if (rec->dwFields & ET_ATTRIBUTES) 781 { 782 TRACE( "ET_ATTRIBUTES: 0x%08x, 0x%08x\n", 783 rec->dwAttributes[0], rec->dwAttributes[1] ); 784 if (rec->dwAttributes[0] != hdr->phAttributes[0] || 785 rec->dwAttributes[1] != hdr->phAttributes[1]) return FALSE; 786 } 787 if (rec->dwFields & ET_RENDERINGINTENT) 788 { 789 TRACE( "ET_RENDERINGINTENT: 0x%08x\n", rec->dwRenderingIntent ); 790 if (rec->dwRenderingIntent != hdr->phRenderingIntent) return FALSE; 791 } 792 if (rec->dwFields & ET_CREATOR) 793 { 794 TRACE( "ET_CREATOR: %s\n", dbgstr_tag(rec->dwCreator) ); 795 if (rec->dwCreator != hdr->phCreator) return FALSE; 796 } 797 return TRUE; 798 } 799 800 /****************************************************************************** 801 * EnumColorProfilesA [MSCMS.@] 802 * 803 * See EnumColorProfilesW. 804 */ 805 BOOL WINAPI EnumColorProfilesA( PCSTR machine, PENUMTYPEA record, PBYTE buffer, 806 PDWORD size, PDWORD number ) 807 { 808 BOOL match, ret = FALSE; 809 char spec[] = "\\*.icm"; 810 char colordir[MAX_PATH], glob[MAX_PATH], **profiles = NULL; 811 DWORD i, len = sizeof(colordir), count = 0, totalsize = 0; 812 PROFILEHEADER header; 813 WIN32_FIND_DATAA data; 814 ENUMTYPEW recordW; 815 WCHAR *fileW = NULL, *deviceW = NULL; 816 HANDLE find; 817 818 TRACE( "( %p, %p, %p, %p, %p )\n", machine, record, buffer, size, number ); 819 820 if (machine || !record || !size || 821 record->dwSize != sizeof(ENUMTYPEA) || 822 record->dwVersion != ENUM_TYPE_VERSION) return FALSE; 823 824 ret = GetColorDirectoryA( machine, colordir, &len ); 825 if (!ret || len + sizeof(spec) > MAX_PATH) 826 { 827 WARN( "can't retrieve color directory\n" ); 828 return FALSE; 829 } 830 831 lstrcpyA( glob, colordir ); 832 lstrcatA( glob, spec ); 833 834 find = FindFirstFileA( glob, &data ); 835 if (find == INVALID_HANDLE_VALUE) return FALSE; 836 837 profiles = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(char *) + 1 ); 838 if (!profiles) goto exit; 839 840 memcpy( &recordW, record, sizeof(ENUMTYPEA) ); 841 if (record->pDeviceName) 842 { 843 deviceW = strdupW( record->pDeviceName ); 844 if (!(recordW.pDeviceName = deviceW)) goto exit; 845 } 846 847 fileW = strdupW( data.cFileName ); 848 if (!fileW) goto exit; 849 850 ret = header_from_file( fileW, &header ); 851 if (ret) 852 { 853 match = match_profile( &recordW, &header ); 854 if (match) 855 { 856 len = sizeof(char) * (lstrlenA( data.cFileName ) + 1); 857 profiles[count] = HeapAlloc( GetProcessHeap(), 0, len ); 858 859 if (!profiles[count]) goto exit; 860 else 861 { 862 TRACE( "matching profile: %s\n", debugstr_a(data.cFileName) ); 863 lstrcpyA( profiles[count], data.cFileName ); 864 totalsize += len; 865 count++; 866 } 867 } 868 } 869 HeapFree( GetProcessHeap(), 0, fileW ); 870 fileW = NULL; 871 872 while (FindNextFileA( find, &data )) 873 { 874 fileW = strdupW( data.cFileName ); 875 if (!fileW) goto exit; 876 877 ret = header_from_file( fileW, &header ); 878 if (!ret) 879 { 880 HeapFree( GetProcessHeap(), 0, fileW ); 881 continue; 882 } 883 884 match = match_profile( &recordW, &header ); 885 if (match) 886 { 887 char **tmp = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 888 profiles, sizeof(char *) * (count + 1) ); 889 if (!tmp) goto exit; 890 else profiles = tmp; 891 892 len = sizeof(char) * (lstrlenA( data.cFileName ) + 1); 893 profiles[count] = HeapAlloc( GetProcessHeap(), 0, len ); 894 895 if (!profiles[count]) goto exit; 896 else 897 { 898 TRACE( "matching profile: %s\n", debugstr_a(data.cFileName) ); 899 lstrcpyA( profiles[count], data.cFileName ); 900 totalsize += len; 901 count++; 902 } 903 } 904 HeapFree( GetProcessHeap(), 0, fileW ); 905 fileW = NULL; 906 } 907 908 totalsize++; 909 if (buffer && *size >= totalsize) 910 { 911 char *p = (char *)buffer; 912 913 for (i = 0; i < count; i++) 914 { 915 lstrcpyA( p, profiles[i] ); 916 p += lstrlenA( profiles[i] ) + 1; 917 } 918 *p = 0; 919 ret = TRUE; 920 } 921 else ret = FALSE; 922 923 *size = totalsize; 924 if (number) *number = count; 925 926 exit: 927 for (i = 0; i < count; i++) 928 HeapFree( GetProcessHeap(), 0, profiles[i] ); 929 HeapFree( GetProcessHeap(), 0, profiles ); 930 HeapFree( GetProcessHeap(), 0, deviceW ); 931 HeapFree( GetProcessHeap(), 0, fileW ); 932 FindClose( find ); 933 934 return ret; 935 } 936 937 /****************************************************************************** 938 * EnumColorProfilesW [MSCMS.@] 939 * 940 * Enumerate profiles that match given criteria. 941 * 942 * PARAMS 943 * machine [I] Name of the machine for which to enumerate profiles. 944 * Must be NULL, which indicates the local machine. 945 * record [I] Record of criteria that a profile must match. 946 * buffer [O] Buffer to receive a string array of profile filenames. 947 * size [I/O] Size of the filename buffer in bytes. 948 * number [O] Number of filenames copied into buffer. 949 * 950 * RETURNS 951 * Success: TRUE 952 * Failure: FALSE 953 */ 954 BOOL WINAPI EnumColorProfilesW( PCWSTR machine, PENUMTYPEW record, PBYTE buffer, 955 PDWORD size, PDWORD number ) 956 { 957 static const WCHAR spec[] = {'\\','*','i','c','m',0}; 958 BOOL match, ret = FALSE; 959 WCHAR colordir[MAX_PATH], glob[MAX_PATH], **profiles = NULL; 960 DWORD i, len = sizeof(colordir), count = 0, totalsize = 0; 961 PROFILEHEADER header; 962 WIN32_FIND_DATAW data; 963 HANDLE find; 964 965 TRACE( "( %p, %p, %p, %p, %p )\n", machine, record, buffer, size, number ); 966 967 if (machine || !record || !size || 968 record->dwSize != sizeof(ENUMTYPEW) || 969 record->dwVersion != ENUM_TYPE_VERSION) return FALSE; 970 971 ret = GetColorDirectoryW( machine, colordir, &len ); 972 if (!ret || len + sizeof(spec) > MAX_PATH) 973 { 974 WARN( "Can't retrieve color directory\n" ); 975 return FALSE; 976 } 977 978 lstrcpyW( glob, colordir ); 979 lstrcatW( glob, spec ); 980 981 find = FindFirstFileW( glob, &data ); 982 if (find == INVALID_HANDLE_VALUE) return FALSE; 983 984 profiles = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WCHAR *) + 1 ); 985 if (!profiles) goto exit; 986 987 ret = header_from_file( data.cFileName, &header ); 988 if (ret) 989 { 990 match = match_profile( record, &header ); 991 if (match) 992 { 993 len = sizeof(WCHAR) * (lstrlenW( data.cFileName ) + 1); 994 profiles[count] = HeapAlloc( GetProcessHeap(), 0, len ); 995 996 if (!profiles[count]) goto exit; 997 else 998 { 999 TRACE( "matching profile: %s\n", debugstr_w(data.cFileName) ); 1000 lstrcpyW( profiles[count], data.cFileName ); 1001 totalsize += len; 1002 count++; 1003 } 1004 } 1005 } 1006 1007 while (FindNextFileW( find, &data )) 1008 { 1009 ret = header_from_file( data.cFileName, &header ); 1010 if (!ret) continue; 1011 1012 match = match_profile( record, &header ); 1013 if (match) 1014 { 1015 WCHAR **tmp = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 1016 profiles, sizeof(WCHAR *) * (count + 1) ); 1017 if (!tmp) goto exit; 1018 else profiles = tmp; 1019 1020 len = sizeof(WCHAR) * (lstrlenW( data.cFileName ) + 1); 1021 profiles[count] = HeapAlloc( GetProcessHeap(), 0, len ); 1022 1023 if (!profiles[count]) goto exit; 1024 else 1025 { 1026 TRACE( "matching profile: %s\n", debugstr_w(data.cFileName) ); 1027 lstrcpyW( profiles[count], data.cFileName ); 1028 totalsize += len; 1029 count++; 1030 } 1031 } 1032 } 1033 1034 totalsize++; 1035 if (buffer && *size >= totalsize) 1036 { 1037 WCHAR *p = (WCHAR *)buffer; 1038 1039 for (i = 0; i < count; i++) 1040 { 1041 lstrcpyW( p, profiles[i] ); 1042 p += lstrlenW( profiles[i] ) + 1; 1043 } 1044 *p = 0; 1045 ret = TRUE; 1046 } 1047 else ret = FALSE; 1048 1049 *size = totalsize; 1050 if (number) *number = count; 1051 1052 exit: 1053 for (i = 0; i < count; i++) 1054 HeapFree( GetProcessHeap(), 0, profiles[i] ); 1055 HeapFree( GetProcessHeap(), 0, profiles ); 1056 FindClose( find ); 1057 1058 return ret; 1059 } 1060 1061 /****************************************************************************** 1062 * InstallColorProfileA [MSCMS.@] 1063 * 1064 * See InstallColorProfileW. 1065 */ 1066 BOOL WINAPI InstallColorProfileA( PCSTR machine, PCSTR profile ) 1067 { 1068 UINT len; 1069 LPWSTR profileW; 1070 BOOL ret = FALSE; 1071 1072 TRACE( "( %s )\n", debugstr_a(profile) ); 1073 1074 if (machine || !profile) return FALSE; 1075 1076 len = MultiByteToWideChar( CP_ACP, 0, profile, -1, NULL, 0 ); 1077 profileW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); 1078 1079 if (profileW) 1080 { 1081 MultiByteToWideChar( CP_ACP, 0, profile, -1, profileW, len ); 1082 1083 ret = InstallColorProfileW( NULL, profileW ); 1084 HeapFree( GetProcessHeap(), 0, profileW ); 1085 } 1086 return ret; 1087 } 1088 1089 /****************************************************************************** 1090 * InstallColorProfileW [MSCMS.@] 1091 * 1092 * Install a color profile. 1093 * 1094 * PARAMS 1095 * machine [I] Name of the machine to install the profile on. Must be NULL, 1096 * which indicates the local machine. 1097 * profile [I] Full path name of the profile to install. 1098 * 1099 * RETURNS 1100 * Success: TRUE 1101 * Failure: FALSE 1102 */ 1103 BOOL WINAPI InstallColorProfileW( PCWSTR machine, PCWSTR profile ) 1104 { 1105 WCHAR dest[MAX_PATH], base[MAX_PATH]; 1106 DWORD size = sizeof(dest); 1107 static const WCHAR slash[] = { '\\', 0 }; 1108 1109 TRACE( "( %s )\n", debugstr_w(profile) ); 1110 1111 if (machine || !profile) return FALSE; 1112 1113 if (!GetColorDirectoryW( machine, dest, &size )) return FALSE; 1114 1115 basename( profile, base ); 1116 1117 lstrcatW( dest, slash ); 1118 lstrcatW( dest, base ); 1119 1120 /* Is source equal to destination? */ 1121 if (!lstrcmpW( profile, dest )) return TRUE; 1122 1123 return CopyFileW( profile, dest, TRUE ); 1124 } 1125 1126 /****************************************************************************** 1127 * IsColorProfileTagPresent [MSCMS.@] 1128 * 1129 * Determine if a given ICC tag type is present in a color profile. 1130 * 1131 * PARAMS 1132 * profile [I] Color profile handle. 1133 * tag [I] ICC tag type. 1134 * present [O] Pointer to a BOOL variable. Set to TRUE if tag type is present, 1135 * FALSE otherwise. 1136 * 1137 * RETURNS 1138 * Success: TRUE 1139 * Failure: FALSE 1140 */ 1141 BOOL WINAPI IsColorProfileTagPresent( HPROFILE handle, TAGTYPE type, PBOOL present ) 1142 { 1143 BOOL ret = FALSE; 1144 #ifdef HAVE_LCMS2 1145 struct profile *profile = grab_profile( handle ); 1146 1147 TRACE( "( %p, 0x%08x, %p )\n", handle, type, present ); 1148 1149 if (!profile) return FALSE; 1150 1151 if (!present) 1152 { 1153 release_profile( profile ); 1154 return FALSE; 1155 } 1156 *present = (cmsIsTag( profile->cmsprofile, type ) != 0); 1157 release_profile( profile ); 1158 ret = TRUE; 1159 1160 #endif /* HAVE_LCMS2 */ 1161 return ret; 1162 } 1163 1164 /****************************************************************************** 1165 * IsColorProfileValid [MSCMS.@] 1166 * 1167 * Determine if a given color profile is valid. 1168 * 1169 * PARAMS 1170 * profile [I] Color profile handle. 1171 * valid [O] Pointer to a BOOL variable. Set to TRUE if profile is valid, 1172 * FALSE otherwise. 1173 * 1174 * RETURNS 1175 * Success: TRUE 1176 * Failure: FALSE 1177 */ 1178 BOOL WINAPI IsColorProfileValid( HPROFILE handle, PBOOL valid ) 1179 { 1180 BOOL ret = FALSE; 1181 #ifdef HAVE_LCMS2 1182 struct profile *profile = grab_profile( handle ); 1183 1184 TRACE( "( %p, %p )\n", handle, valid ); 1185 1186 if (!profile) return FALSE; 1187 1188 if (!valid) 1189 { 1190 release_profile( profile ); 1191 return FALSE; 1192 } 1193 if (profile->data) ret = *valid = TRUE; 1194 release_profile( profile ); 1195 1196 #endif /* HAVE_LCMS2 */ 1197 return ret; 1198 } 1199 1200 /****************************************************************************** 1201 * SetColorProfileElement [MSCMS.@] 1202 * 1203 * Set data for a specified tag type. 1204 * 1205 * PARAMS 1206 * profile [I] Handle to a color profile. 1207 * type [I] ICC tag type. 1208 * offset [I] Offset in bytes to start copying to. 1209 * size [I/O] Size of the buffer in bytes. On return the variable holds the 1210 * number of bytes actually needed. 1211 * buffer [O] Buffer holding the tag data. 1212 * 1213 * RETURNS 1214 * Success: TRUE 1215 * Failure: FALSE 1216 */ 1217 BOOL WINAPI SetColorProfileElement( HPROFILE handle, TAGTYPE type, DWORD offset, PDWORD size, 1218 PVOID buffer ) 1219 { 1220 BOOL ret = FALSE; 1221 #ifdef HAVE_LCMS2 1222 struct profile *profile = grab_profile( handle ); 1223 1224 TRACE( "( %p, 0x%08x, %d, %p, %p )\n", handle, type, offset, size, buffer ); 1225 1226 if (!profile) return FALSE; 1227 1228 if (!size || !buffer || !(profile->access & PROFILE_READWRITE)) 1229 { 1230 release_profile( profile ); 1231 return FALSE; 1232 } 1233 ret = set_tag_data( profile, type, offset, buffer, size ); 1234 release_profile( profile ); 1235 #endif /* HAVE_LCMS2 */ 1236 return ret; 1237 } 1238 1239 /****************************************************************************** 1240 * SetColorProfileHeader [MSCMS.@] 1241 * 1242 * Set header data for a given profile. 1243 * 1244 * PARAMS 1245 * profile [I] Handle to a color profile. 1246 * header [I] Buffer holding the header data. 1247 * 1248 * RETURNS 1249 * Success: TRUE 1250 * Failure: FALSE 1251 */ 1252 BOOL WINAPI SetColorProfileHeader( HPROFILE handle, PPROFILEHEADER header ) 1253 { 1254 #ifdef HAVE_LCMS2 1255 struct profile *profile = grab_profile( handle ); 1256 1257 TRACE( "( %p, %p )\n", handle, header ); 1258 1259 if (!profile) return FALSE; 1260 1261 if (!header || !(profile->access & PROFILE_READWRITE)) 1262 { 1263 release_profile( profile ); 1264 return FALSE; 1265 } 1266 set_profile_header( profile, header ); 1267 release_profile( profile ); 1268 return TRUE; 1269 1270 #else 1271 return FALSE; 1272 #endif /* HAVE_LCMS2 */ 1273 } 1274 1275 /****************************************************************************** 1276 * UninstallColorProfileA [MSCMS.@] 1277 * 1278 * See UninstallColorProfileW. 1279 */ 1280 BOOL WINAPI UninstallColorProfileA( PCSTR machine, PCSTR profile, BOOL delete ) 1281 { 1282 UINT len; 1283 LPWSTR profileW; 1284 BOOL ret = FALSE; 1285 1286 TRACE( "( %s, %x )\n", debugstr_a(profile), delete ); 1287 1288 if (machine || !profile) return FALSE; 1289 1290 len = MultiByteToWideChar( CP_ACP, 0, profile, -1, NULL, 0 ); 1291 profileW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); 1292 1293 if (profileW) 1294 { 1295 MultiByteToWideChar( CP_ACP, 0, profile, -1, profileW, len ); 1296 1297 ret = UninstallColorProfileW( NULL, profileW , delete ); 1298 1299 HeapFree( GetProcessHeap(), 0, profileW ); 1300 } 1301 return ret; 1302 } 1303 1304 /****************************************************************************** 1305 * UninstallColorProfileW [MSCMS.@] 1306 * 1307 * Uninstall a color profile. 1308 * 1309 * PARAMS 1310 * machine [I] Name of the machine to uninstall the profile on. Must be NULL, 1311 * which indicates the local machine. 1312 * profile [I] Full path name of the profile to uninstall. 1313 * delete [I] Bool that specifies whether the profile file should be deleted. 1314 * 1315 * RETURNS 1316 * Success: TRUE 1317 * Failure: FALSE 1318 */ 1319 BOOL WINAPI UninstallColorProfileW( PCWSTR machine, PCWSTR profile, BOOL delete ) 1320 { 1321 TRACE( "( %s, %x )\n", debugstr_w(profile), delete ); 1322 1323 if (machine || !profile) return FALSE; 1324 1325 if (delete) return DeleteFileW( profile ); 1326 1327 return TRUE; 1328 } 1329 1330 /****************************************************************************** 1331 * OpenColorProfileA [MSCMS.@] 1332 * 1333 * See OpenColorProfileW. 1334 */ 1335 HPROFILE WINAPI OpenColorProfileA( PPROFILE profile, DWORD access, DWORD sharing, DWORD creation ) 1336 { 1337 HPROFILE handle = NULL; 1338 1339 TRACE( "( %p, 0x%08x, 0x%08x, 0x%08x )\n", profile, access, sharing, creation ); 1340 1341 if (!profile || !profile->pProfileData) return NULL; 1342 1343 /* No AW conversion needed for memory based profiles */ 1344 if (profile->dwType & PROFILE_MEMBUFFER) 1345 return OpenColorProfileW( profile, access, sharing, creation ); 1346 1347 if (profile->dwType & PROFILE_FILENAME) 1348 { 1349 UINT len; 1350 PROFILE profileW; 1351 1352 profileW.dwType = profile->dwType; 1353 1354 len = MultiByteToWideChar( CP_ACP, 0, profile->pProfileData, -1, NULL, 0 ); 1355 profileW.pProfileData = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); 1356 1357 if (profileW.pProfileData) 1358 { 1359 profileW.cbDataSize = len * sizeof(WCHAR); 1360 MultiByteToWideChar( CP_ACP, 0, profile->pProfileData, -1, profileW.pProfileData, len ); 1361 1362 handle = OpenColorProfileW( &profileW, access, sharing, creation ); 1363 HeapFree( GetProcessHeap(), 0, profileW.pProfileData ); 1364 } 1365 } 1366 return handle; 1367 } 1368 1369 /****************************************************************************** 1370 * OpenColorProfileW [MSCMS.@] 1371 * 1372 * Open a color profile. 1373 * 1374 * PARAMS 1375 * profile [I] Pointer to a color profile structure. 1376 * access [I] Desired access. 1377 * sharing [I] Sharing mode. 1378 * creation [I] Creation mode. 1379 * 1380 * RETURNS 1381 * Success: Handle to the opened profile. 1382 * Failure: NULL 1383 * 1384 * NOTES 1385 * Values for access: PROFILE_READ or PROFILE_READWRITE. 1386 * Values for sharing: 0 (no sharing), FILE_SHARE_READ and/or FILE_SHARE_WRITE. 1387 * Values for creation: one of CREATE_NEW, CREATE_ALWAYS, OPEN_EXISTING, 1388 * OPEN_ALWAYS, TRUNCATE_EXISTING. 1389 * Sharing and creation flags are ignored for memory based profiles. 1390 */ 1391 HPROFILE WINAPI OpenColorProfileW( PPROFILE profile, DWORD access, DWORD sharing, DWORD creation ) 1392 { 1393 #ifdef HAVE_LCMS2 1394 cmsHPROFILE cmsprofile = NULL; 1395 char *data = NULL; 1396 HANDLE handle = INVALID_HANDLE_VALUE; 1397 DWORD size; 1398 1399 TRACE( "( %p, 0x%08x, 0x%08x, 0x%08x )\n", profile, access, sharing, creation ); 1400 1401 if (!profile || !profile->pProfileData) return NULL; 1402 1403 if (profile->dwType == PROFILE_MEMBUFFER) 1404 { 1405 /* FIXME: access flags not implemented for memory based profiles */ 1406 1407 if (!(data = HeapAlloc( GetProcessHeap(), 0, profile->cbDataSize ))) return NULL; 1408 memcpy( data, profile->pProfileData, profile->cbDataSize ); 1409 1410 if (!(cmsprofile = cmsOpenProfileFromMem( data, profile->cbDataSize ))) 1411 { 1412 HeapFree( GetProcessHeap(), 0, data ); 1413 return FALSE; 1414 } 1415 size = profile->cbDataSize; 1416 } 1417 else if (profile->dwType == PROFILE_FILENAME) 1418 { 1419 DWORD read, flags = 0; 1420 1421 TRACE( "profile file: %s\n", debugstr_w( profile->pProfileData ) ); 1422 1423 if (access & PROFILE_READ) flags = GENERIC_READ; 1424 if (access & PROFILE_READWRITE) flags = GENERIC_READ|GENERIC_WRITE; 1425 1426 if (!flags) return NULL; 1427 if (!sharing) sharing = FILE_SHARE_READ; 1428 1429 if (!PathIsRelativeW( profile->pProfileData )) 1430 handle = CreateFileW( profile->pProfileData, flags, sharing, NULL, creation, 0, NULL ); 1431 else 1432 { 1433 WCHAR *path; 1434 1435 if (!GetColorDirectoryW( NULL, NULL, &size ) && GetLastError() == ERROR_MORE_DATA) 1436 { 1437 size += (strlenW( profile->pProfileData ) + 2) * sizeof(WCHAR); 1438 if (!(path = HeapAlloc( GetProcessHeap(), 0, size ))) return NULL; 1439 GetColorDirectoryW( NULL, path, &size ); 1440 PathAddBackslashW( path ); 1441 strcatW( path, profile->pProfileData ); 1442 } 1443 else return NULL; 1444 handle = CreateFileW( path, flags, sharing, NULL, creation, 0, NULL ); 1445 HeapFree( GetProcessHeap(), 0, path ); 1446 } 1447 if (handle == INVALID_HANDLE_VALUE) 1448 { 1449 WARN( "Unable to open color profile %u\n", GetLastError() ); 1450 return NULL; 1451 } 1452 if ((size = GetFileSize( handle, NULL )) == INVALID_FILE_SIZE) 1453 { 1454 ERR( "Unable to retrieve size of color profile\n" ); 1455 CloseHandle( handle ); 1456 return NULL; 1457 } 1458 if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) 1459 { 1460 ERR( "Unable to allocate memory for color profile\n" ); 1461 CloseHandle( handle ); 1462 return NULL; 1463 } 1464 if (!ReadFile( handle, data, size, &read, NULL ) || read != size) 1465 { 1466 ERR( "Unable to read color profile\n" ); 1467 1468 CloseHandle( handle ); 1469 HeapFree( GetProcessHeap(), 0, data ); 1470 return NULL; 1471 } 1472 if (!(cmsprofile = cmsOpenProfileFromMem( data, size ))) 1473 { 1474 CloseHandle( handle ); 1475 HeapFree( GetProcessHeap(), 0, data ); 1476 return NULL; 1477 } 1478 } 1479 else 1480 { 1481 ERR( "Invalid profile type %u\n", profile->dwType ); 1482 return NULL; 1483 } 1484 1485 if (cmsprofile) 1486 { 1487 struct profile profile; 1488 HPROFILE hprof; 1489 1490 profile.file = handle; 1491 profile.access = access; 1492 profile.data = data; 1493 profile.size = size; 1494 profile.cmsprofile = cmsprofile; 1495 1496 if ((hprof = create_profile( &profile ))) return hprof; 1497 HeapFree( GetProcessHeap(), 0, data ); 1498 cmsCloseProfile( cmsprofile ); 1499 } 1500 CloseHandle( handle ); 1501 1502 #endif /* HAVE_LCMS2 */ 1503 return NULL; 1504 } 1505 1506 /****************************************************************************** 1507 * CloseColorProfile [MSCMS.@] 1508 * 1509 * Close a color profile. 1510 * 1511 * PARAMS 1512 * profile [I] Handle to the profile. 1513 * 1514 * RETURNS 1515 * Success: TRUE 1516 * Failure: FALSE 1517 */ 1518 BOOL WINAPI CloseColorProfile( HPROFILE profile ) 1519 { 1520 BOOL ret = FALSE; 1521 #ifdef HAVE_LCMS2 1522 1523 TRACE( "( %p )\n", profile ); 1524 ret = close_profile( profile ); 1525 1526 #endif /* HAVE_LCMS2 */ 1527 return ret; 1528 } 1529 1530 /****************************************************************************** 1531 * WcsGetUsePerUserProfiles [MSCMS.@] 1532 */ 1533 BOOL WINAPI WcsGetUsePerUserProfiles( const WCHAR* name, DWORD class, BOOL* use_per_user_profile ) 1534 { 1535 FIXME( "%s %s %p\n", debugstr_w(name), dbgstr_tag(class), use_per_user_profile ); 1536 SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); 1537 return FALSE; 1538 } 1539 1540 /****************************************************************************** 1541 * WcsEnumColorProfilesSize [MSCMS.@] 1542 */ 1543 BOOL WINAPI WcsEnumColorProfilesSize( WCS_PROFILE_MANAGEMENT_SCOPE scope, ENUMTYPEW *record, DWORD *size ) 1544 { 1545 FIXME( "%d %p %p\n", scope, record, size ); 1546 SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); 1547 return FALSE; 1548 } 1549