2 * MSCMS - Color Management System for Wine
4 * Copyright 2004, 2005, 2006, 2008 Hans Leidekker
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.
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.
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
32 #include "wine/debug.h"
34 #include "mscms_priv.h"
36 static void basename( const WCHAR
*path
, WCHAR
*name
)
38 int i
= lstrlenW( path
);
39 while (i
> 0 && path
[i
- 1] != '\\' && path
[i
- 1] != '/') i
--;
40 lstrcpyW( name
, &path
[i
] );
43 static inline WCHAR
*strdupW( const char *str
)
48 int len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
49 if ((ret
= malloc( len
* sizeof(WCHAR
) ))) MultiByteToWideChar( CP_ACP
, 0, str
, -1, ret
, len
);
54 const char *dbgstr_tag( DWORD tag
)
56 return wine_dbg_sprintf( "'%c%c%c%c'",
57 (char)(tag
>> 24), (char)(tag
>> 16), (char)(tag
>> 8), (char)(tag
) );
60 WINE_DEFAULT_DEBUG_CHANNEL(mscms
);
62 /******************************************************************************
63 * AssociateColorProfileWithDeviceA [MSCMS.@]
65 BOOL WINAPI
AssociateColorProfileWithDeviceA( PCSTR machine
, PCSTR profile
, PCSTR device
)
69 WCHAR
*profileW
, *deviceW
;
71 TRACE( "( %s, %s, %s )\n", debugstr_a(machine
), debugstr_a(profile
), debugstr_a(device
) );
73 if (!profile
|| !device
)
75 SetLastError( ERROR_INVALID_PARAMETER
);
80 SetLastError( ERROR_NOT_SUPPORTED
);
84 len
= MultiByteToWideChar( CP_ACP
, 0, profile
, -1, NULL
, 0 );
85 if (!(profileW
= malloc( len
* sizeof(WCHAR
) ))) return FALSE
;
87 MultiByteToWideChar( CP_ACP
, 0, profile
, -1, profileW
, len
);
89 len
= MultiByteToWideChar( CP_ACP
, 0, device
, -1, NULL
, 0 );
90 if ((deviceW
= malloc( len
* sizeof(WCHAR
) )))
92 MultiByteToWideChar( CP_ACP
, 0, device
, -1, deviceW
, len
);
93 ret
= AssociateColorProfileWithDeviceW( NULL
, profileW
, deviceW
);
101 static BOOL
set_profile_device_key( PCWSTR file
, const BYTE
*value
, DWORD size
)
103 PROFILEHEADER header
;
106 HKEY icm_key
, class_key
;
107 WCHAR basenameW
[MAX_PATH
], classW
[5];
109 profile
.dwType
= PROFILE_FILENAME
;
110 profile
.pProfileData
= (PVOID
)file
;
111 profile
.cbDataSize
= (lstrlenW( file
) + 1) * sizeof(WCHAR
);
113 /* FIXME is the profile installed? */
114 if (!(handle
= OpenColorProfileW( &profile
, PROFILE_READ
, 0, OPEN_EXISTING
)))
116 SetLastError( ERROR_INVALID_PROFILE
);
119 if (!GetColorProfileHeader( handle
, &header
))
121 CloseColorProfile( handle
);
122 SetLastError( ERROR_INVALID_PROFILE
);
125 RegCreateKeyExW( HKEY_LOCAL_MACHINE
, L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\ICM",
126 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &icm_key
, NULL
);
128 basename( file
, basenameW
);
129 swprintf( classW
, ARRAY_SIZE(classW
), L
"%c%c%c%c",
130 (header
.phClass
>> 24) & 0xff, (header
.phClass
>> 16) & 0xff,
131 (header
.phClass
>> 8) & 0xff, header
.phClass
& 0xff );
133 RegCreateKeyExW( icm_key
, classW
, 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &class_key
, NULL
);
134 if (value
) RegSetValueExW( class_key
, basenameW
, 0, REG_BINARY
, value
, size
);
135 else RegDeleteValueW( class_key
, basenameW
);
137 RegCloseKey( class_key
);
138 RegCloseKey( icm_key
);
139 CloseColorProfile( handle
);
143 /******************************************************************************
144 * AssociateColorProfileWithDeviceW [MSCMS.@]
146 BOOL WINAPI
AssociateColorProfileWithDeviceW( PCWSTR machine
, PCWSTR profile
, PCWSTR device
)
148 static const BYTE dummy_value
[12];
150 TRACE( "( %s, %s, %s )\n", debugstr_w(machine
), debugstr_w(profile
), debugstr_w(device
) );
152 if (!profile
|| !device
)
154 SetLastError( ERROR_INVALID_PARAMETER
);
159 SetLastError( ERROR_NOT_SUPPORTED
);
163 return set_profile_device_key( profile
, dummy_value
, sizeof(dummy_value
) );
166 /******************************************************************************
167 * DisassociateColorProfileFromDeviceA [MSCMS.@]
169 BOOL WINAPI
DisassociateColorProfileFromDeviceA( PCSTR machine
, PCSTR profile
, PCSTR device
)
173 WCHAR
*profileW
, *deviceW
;
175 TRACE( "( %s, %s, %s )\n", debugstr_a(machine
), debugstr_a(profile
), debugstr_a(device
) );
177 if (!profile
|| !device
)
179 SetLastError( ERROR_INVALID_PARAMETER
);
184 SetLastError( ERROR_NOT_SUPPORTED
);
188 len
= MultiByteToWideChar( CP_ACP
, 0, profile
, -1, NULL
, 0 );
189 if (!(profileW
= malloc( len
* sizeof(WCHAR
) ))) return FALSE
;
191 MultiByteToWideChar( CP_ACP
, 0, profile
, -1, profileW
, len
);
193 len
= MultiByteToWideChar( CP_ACP
, 0, device
, -1, NULL
, 0 );
194 if ((deviceW
= malloc( len
* sizeof(WCHAR
) )))
196 MultiByteToWideChar( CP_ACP
, 0, device
, -1, deviceW
, len
);
197 ret
= DisassociateColorProfileFromDeviceW( NULL
, profileW
, deviceW
);
205 /******************************************************************************
206 * DisassociateColorProfileFromDeviceW [MSCMS.@]
208 BOOL WINAPI
DisassociateColorProfileFromDeviceW( PCWSTR machine
, PCWSTR profile
, PCWSTR device
)
210 TRACE( "( %s, %s, %s )\n", debugstr_w(machine
), debugstr_w(profile
), debugstr_w(device
) );
212 if (!profile
|| !device
)
214 SetLastError( ERROR_INVALID_PARAMETER
);
219 SetLastError( ERROR_NOT_SUPPORTED
);
223 return set_profile_device_key( profile
, NULL
, 0 );
226 /******************************************************************************
227 * GetColorDirectoryA [MSCMS.@]
229 * See GetColorDirectoryW.
231 BOOL WINAPI
GetColorDirectoryA( PCSTR machine
, PSTR buffer
, PDWORD size
)
238 TRACE( "( %p, %p )\n", buffer
, size
);
240 if (machine
|| !size
) return FALSE
;
244 ret
= GetColorDirectoryW( NULL
, NULL
, &sizeW
);
245 *size
= sizeW
/ sizeof(WCHAR
);
249 sizeW
= *size
* sizeof(WCHAR
);
251 if ((bufferW
= malloc( sizeW
)))
253 if ((ret
= GetColorDirectoryW( NULL
, bufferW
, &sizeW
)))
255 *size
= WideCharToMultiByte( CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
256 len
= WideCharToMultiByte( CP_ACP
, 0, bufferW
, -1, buffer
, *size
, NULL
, NULL
);
257 if (!len
) ret
= FALSE
;
259 else *size
= sizeW
/ sizeof(WCHAR
);
265 /******************************************************************************
266 * GetColorDirectoryW [MSCMS.@]
268 * Get the directory where color profiles are stored.
271 * machine [I] Name of the machine for which to get the color directory.
272 * Must be NULL, which indicates the local machine.
273 * buffer [I] Buffer to receive the path name.
274 * size [I/O] Size of the buffer in bytes. On return the variable holds
275 * the number of bytes actually needed.
277 BOOL WINAPI
GetColorDirectoryW( PCWSTR machine
, PWSTR buffer
, PDWORD size
)
279 WCHAR colordir
[MAX_PATH
];
282 TRACE( "( %p, %p )\n", buffer
, size
);
284 if (machine
|| !size
) return FALSE
;
286 GetSystemDirectoryW( colordir
, ARRAY_SIZE( colordir
));
287 lstrcatW( colordir
, L
"\\spool\\drivers\\color" );
289 len
= lstrlenW( colordir
) * sizeof(WCHAR
);
291 if (buffer
&& len
<= *size
)
293 lstrcpyW( buffer
, colordir
);
298 SetLastError( ERROR_MORE_DATA
);
303 /******************************************************************************
304 * GetColorProfileElement [MSCMS.@]
306 * Retrieve data for a specified tag type.
309 * profile [I] Handle to a color profile.
310 * type [I] ICC tag type.
311 * offset [I] Offset in bytes to start copying from.
312 * size [I/O] Size of the buffer in bytes. On return the variable holds
313 * the number of bytes actually needed.
314 * buffer [O] Buffer to receive the tag data.
315 * ref [O] Pointer to a BOOL that specifies whether more than one tag
316 * references the data.
322 BOOL WINAPI
GetColorProfileElement( HPROFILE handle
, TAGTYPE type
, DWORD offset
, PDWORD size
,
323 PVOID buffer
, PBOOL ref
)
326 struct profile
*profile
= (struct profile
*)grab_object( handle
, OBJECT_TYPE_PROFILE
);
328 TRACE( "( %p, %#lx, %lu, %p, %p, %p )\n", handle
, type
, offset
, size
, buffer
, ref
);
330 if (!profile
) return FALSE
;
334 release_object( &profile
->hdr
);
337 ret
= get_tag_data( profile
, type
, offset
, buffer
, size
, ref
);
338 release_object( &profile
->hdr
);
342 /******************************************************************************
343 * GetColorProfileElementTag [MSCMS.@]
345 * Get the tag type from a color profile by index.
348 * profile [I] Handle to a color profile.
349 * index [I] Index into the tag table of the color profile.
350 * type [O] Pointer to a variable that holds the ICC tag type on return.
357 * The tag table index starts at 1.
358 * Use GetCountColorProfileElements to retrieve a count of tagged elements.
360 BOOL WINAPI
GetColorProfileElementTag( HPROFILE handle
, DWORD index
, PTAGTYPE type
)
363 struct profile
*profile
= (struct profile
*)grab_object( handle
, OBJECT_TYPE_PROFILE
);
364 struct tag_entry tag
;
366 TRACE( "( %p, %lu, %p )\n", handle
, index
, type
);
368 if (!profile
) return FALSE
;
372 release_object( &profile
->hdr
);
375 if ((ret
= get_tag_entry( profile
, index
, &tag
))) *type
= tag
.sig
;
376 release_object( &profile
->hdr
);
380 /******************************************************************************
381 * GetColorProfileFromHandle [MSCMS.@]
383 * Retrieve an ICC color profile by handle.
386 * profile [I] Handle to a color profile.
387 * buffer [O] Buffer to receive the ICC profile.
388 * size [I/O] Size of the buffer in bytes. On return the variable holds the
389 * number of bytes actually needed.
396 * The profile returned will be in big-endian format.
398 BOOL WINAPI
GetColorProfileFromHandle( HPROFILE handle
, PBYTE buffer
, PDWORD size
)
400 struct profile
*profile
= (struct profile
*)grab_object( handle
, OBJECT_TYPE_PROFILE
);
401 PROFILEHEADER header
;
403 TRACE( "( %p, %p, %p )\n", handle
, buffer
, size
);
405 if (!profile
) return FALSE
;
409 release_object( &profile
->hdr
);
412 get_profile_header( profile
, &header
);
414 if (!buffer
|| header
.phSize
> *size
)
416 *size
= header
.phSize
;
417 release_object( &profile
->hdr
);
421 /* No endian conversion needed */
422 memcpy( buffer
, profile
->data
, profile
->size
);
423 *size
= profile
->size
;
425 release_object( &profile
->hdr
);
429 /******************************************************************************
430 * GetColorProfileHeader [MSCMS.@]
432 * Retrieve a color profile header by handle.
435 * profile [I] Handle to a color profile.
436 * header [O] Buffer to receive the ICC profile header.
443 * The profile header returned will be adjusted for endianness.
445 BOOL WINAPI
GetColorProfileHeader( HPROFILE handle
, PPROFILEHEADER header
)
447 struct profile
*profile
= (struct profile
*)grab_object( handle
, OBJECT_TYPE_PROFILE
);
449 TRACE( "( %p, %p )\n", handle
, header
);
451 if (!profile
) return FALSE
;
455 release_object( &profile
->hdr
);
458 get_profile_header( profile
, header
);
459 release_object( &profile
->hdr
);
463 /******************************************************************************
464 * GetCountColorProfileElements [MSCMS.@]
466 * Retrieve the number of elements in a color profile.
469 * profile [I] Handle to a color profile.
470 * count [O] Pointer to a variable which is set to the number of elements
471 * in the color profile.
477 BOOL WINAPI
GetCountColorProfileElements( HPROFILE handle
, PDWORD count
)
479 struct profile
*profile
= (struct profile
*)grab_object( handle
, OBJECT_TYPE_PROFILE
);
481 TRACE( "( %p, %p )\n", handle
, count
);
483 if (!profile
) return FALSE
;
487 release_object( &profile
->hdr
);
490 *count
= get_tag_count( profile
);
491 release_object( &profile
->hdr
);
495 /******************************************************************************
496 * GetStandardColorSpaceProfileA [MSCMS.@]
498 * See GetStandardColorSpaceProfileW.
500 BOOL WINAPI
GetStandardColorSpaceProfileA( PCSTR machine
, DWORD id
, PSTR profile
, PDWORD size
)
507 TRACE( "( %#lx, %p, %p )\n", id
, profile
, size
);
511 SetLastError( ERROR_NOT_SUPPORTED
);
517 SetLastError( ERROR_INVALID_PARAMETER
);
521 sizeW
= *size
* sizeof(WCHAR
);
525 ret
= GetStandardColorSpaceProfileW( NULL
, id
, NULL
, &sizeW
);
526 *size
= sizeW
/ sizeof(WCHAR
);
530 if ((profileW
= malloc( sizeW
)))
532 if ((ret
= GetStandardColorSpaceProfileW( NULL
, id
, profileW
, &sizeW
)))
534 *size
= WideCharToMultiByte( CP_ACP
, 0, profileW
, -1, NULL
, 0, NULL
, NULL
);
535 len
= WideCharToMultiByte( CP_ACP
, 0, profileW
, -1, profile
, *size
, NULL
, NULL
);
536 if (!len
) ret
= FALSE
;
538 else *size
= sizeW
/ sizeof(WCHAR
);
544 /******************************************************************************
545 * GetStandardColorSpaceProfileW [MSCMS.@]
547 * Retrieve the profile filename for a given standard color space id.
550 * machine [I] Name of the machine for which to get the standard color space.
551 * Must be NULL, which indicates the local machine.
552 * id [I] Id of a standard color space.
553 * profile [O] Buffer to receive the profile filename.
554 * size [I/O] Size of the filename buffer in bytes.
560 BOOL WINAPI
GetStandardColorSpaceProfileW( PCWSTR machine
, DWORD id
, PWSTR profile
, PDWORD size
)
562 WCHAR rgbprofile
[MAX_PATH
];
563 DWORD len
= sizeof(rgbprofile
);
565 TRACE( "( %#lx, %p, %p )\n", id
, profile
, size
);
569 SetLastError( ERROR_NOT_SUPPORTED
);
575 SetLastError( ERROR_INVALID_PARAMETER
);
581 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
585 GetColorDirectoryW( machine
, rgbprofile
, &len
);
590 case LCS_WINDOWS_COLOR_SPACE
: /* FIXME */
591 lstrcatW( rgbprofile
, L
"\\srgb color space profile.icm" );
592 len
= lstrlenW( rgbprofile
) * sizeof(WCHAR
);
597 SetLastError( ERROR_MORE_DATA
);
601 lstrcpyW( profile
, rgbprofile
);
605 SetLastError( ERROR_FILE_NOT_FOUND
);
611 static BOOL
header_from_file( LPCWSTR file
, PPROFILEHEADER header
)
615 WCHAR path
[MAX_PATH
];
616 DWORD size
= sizeof(path
);
619 ret
= GetColorDirectoryW( NULL
, path
, &size
);
622 WARN( "Can't retrieve color directory\n" );
625 if (size
+ sizeof(L
"\\") + sizeof(WCHAR
) * lstrlenW( file
) > sizeof(path
))
627 WARN( "Filename too long\n" );
631 lstrcatW( path
, L
"\\" );
632 lstrcatW( path
, file
);
634 profile
.dwType
= PROFILE_FILENAME
;
635 profile
.pProfileData
= path
;
636 profile
.cbDataSize
= lstrlenW( path
) + 1;
638 handle
= OpenColorProfileW( &profile
, PROFILE_READ
, FILE_SHARE_READ
, OPEN_EXISTING
);
641 WARN( "Can't open color profile\n" );
645 ret
= GetColorProfileHeader( handle
, header
);
647 WARN( "Can't retrieve color profile header\n" );
649 CloseColorProfile( handle
);
653 static BOOL
match_profile( PENUMTYPEW rec
, PPROFILEHEADER hdr
)
655 if (rec
->dwFields
& ET_DEVICENAME
)
657 FIXME( "ET_DEVICENAME: %s\n", debugstr_w(rec
->pDeviceName
) );
659 if (rec
->dwFields
& ET_MEDIATYPE
)
661 FIXME( "ET_MEDIATYPE: %#lx\n", rec
->dwMediaType
);
663 if (rec
->dwFields
& ET_DITHERMODE
)
665 FIXME( "ET_DITHERMODE: %#lx\n", rec
->dwDitheringMode
);
667 if (rec
->dwFields
& ET_RESOLUTION
)
669 FIXME( "ET_RESOLUTION: %#lx, %#lx\n",
670 rec
->dwResolution
[0], rec
->dwResolution
[1] );
672 if (rec
->dwFields
& ET_DEVICECLASS
)
674 FIXME( "ET_DEVICECLASS: %s\n", dbgstr_tag(rec
->dwMediaType
) );
676 if (rec
->dwFields
& ET_CMMTYPE
)
678 TRACE( "ET_CMMTYPE: %s\n", dbgstr_tag(rec
->dwCMMType
) );
679 if (rec
->dwCMMType
!= hdr
->phCMMType
) return FALSE
;
681 if (rec
->dwFields
& ET_CLASS
)
683 TRACE( "ET_CLASS: %s\n", dbgstr_tag(rec
->dwClass
) );
684 if (rec
->dwClass
!= hdr
->phClass
) return FALSE
;
686 if (rec
->dwFields
& ET_DATACOLORSPACE
)
688 TRACE( "ET_DATACOLORSPACE: %s\n", dbgstr_tag(rec
->dwDataColorSpace
) );
689 if (rec
->dwDataColorSpace
!= hdr
->phDataColorSpace
) return FALSE
;
691 if (rec
->dwFields
& ET_CONNECTIONSPACE
)
693 TRACE( "ET_CONNECTIONSPACE: %s\n", dbgstr_tag(rec
->dwConnectionSpace
) );
694 if (rec
->dwConnectionSpace
!= hdr
->phConnectionSpace
) return FALSE
;
696 if (rec
->dwFields
& ET_SIGNATURE
)
698 TRACE( "ET_SIGNATURE: %s\n", dbgstr_tag(rec
->dwSignature
) );
699 if (rec
->dwSignature
!= hdr
->phSignature
) return FALSE
;
701 if (rec
->dwFields
& ET_PLATFORM
)
703 TRACE( "ET_PLATFORM: %s\n", dbgstr_tag(rec
->dwPlatform
) );
704 if (rec
->dwPlatform
!= hdr
->phPlatform
) return FALSE
;
706 if (rec
->dwFields
& ET_PROFILEFLAGS
)
708 TRACE( "ET_PROFILEFLAGS: %#lx\n", rec
->dwProfileFlags
);
709 if (rec
->dwProfileFlags
!= hdr
->phProfileFlags
) return FALSE
;
711 if (rec
->dwFields
& ET_MANUFACTURER
)
713 TRACE( "ET_MANUFACTURER: %s\n", dbgstr_tag(rec
->dwManufacturer
) );
714 if (rec
->dwManufacturer
!= hdr
->phManufacturer
) return FALSE
;
716 if (rec
->dwFields
& ET_MODEL
)
718 TRACE( "ET_MODEL: %s\n", dbgstr_tag(rec
->dwModel
) );
719 if (rec
->dwModel
!= hdr
->phModel
) return FALSE
;
721 if (rec
->dwFields
& ET_ATTRIBUTES
)
723 TRACE( "ET_ATTRIBUTES: %#lx, %#lx\n",
724 rec
->dwAttributes
[0], rec
->dwAttributes
[1] );
725 if (rec
->dwAttributes
[0] != hdr
->phAttributes
[0] ||
726 rec
->dwAttributes
[1] != hdr
->phAttributes
[1]) return FALSE
;
728 if (rec
->dwFields
& ET_RENDERINGINTENT
)
730 TRACE( "ET_RENDERINGINTENT: %#lx\n", rec
->dwRenderingIntent
);
731 if (rec
->dwRenderingIntent
!= hdr
->phRenderingIntent
) return FALSE
;
733 if (rec
->dwFields
& ET_CREATOR
)
735 TRACE( "ET_CREATOR: %s\n", dbgstr_tag(rec
->dwCreator
) );
736 if (rec
->dwCreator
!= hdr
->phCreator
) return FALSE
;
741 /******************************************************************************
742 * EnumColorProfilesA [MSCMS.@]
744 * See EnumColorProfilesW.
746 BOOL WINAPI
EnumColorProfilesA( PCSTR machine
, PENUMTYPEA record
, PBYTE buffer
,
747 PDWORD size
, PDWORD number
)
749 BOOL match
, ret
= FALSE
;
750 char spec
[] = "\\*.icm";
751 char colordir
[MAX_PATH
], glob
[MAX_PATH
], **profiles
= NULL
;
752 DWORD i
, len
= sizeof(colordir
), count
= 0, totalsize
= 0;
753 PROFILEHEADER header
;
754 WIN32_FIND_DATAA data
;
756 WCHAR
*fileW
= NULL
, *deviceW
= NULL
;
759 TRACE( "( %p, %p, %p, %p, %p )\n", machine
, record
, buffer
, size
, number
);
761 if (machine
|| !record
|| !size
||
762 record
->dwSize
!= sizeof(ENUMTYPEA
) ||
763 record
->dwVersion
!= ENUM_TYPE_VERSION
) return FALSE
;
765 ret
= GetColorDirectoryA( machine
, colordir
, &len
);
766 if (!ret
|| len
+ sizeof(spec
) > MAX_PATH
)
768 WARN( "can't retrieve color directory\n" );
772 lstrcpyA( glob
, colordir
);
773 lstrcatA( glob
, spec
);
775 find
= FindFirstFileA( glob
, &data
);
776 if (find
== INVALID_HANDLE_VALUE
) return FALSE
;
778 if (!(profiles
= calloc( 1, sizeof(char *) + 1 ))) goto exit
;
780 memcpy( &recordW
, record
, sizeof(ENUMTYPEA
) );
781 if (record
->pDeviceName
)
783 deviceW
= strdupW( record
->pDeviceName
);
784 if (!(recordW
.pDeviceName
= deviceW
)) goto exit
;
787 if (!(fileW
= strdupW( data
.cFileName
))) goto exit
;
789 if ((ret
= header_from_file( fileW
, &header
)))
791 if ((match
= match_profile( &recordW
, &header
)))
793 len
= sizeof(char) * (lstrlenA( data
.cFileName
) + 1);
794 if (!(profiles
[count
] = malloc( len
))) goto exit
;
797 TRACE( "matching profile: %s\n", debugstr_a(data
.cFileName
) );
798 lstrcpyA( profiles
[count
], data
.cFileName
);
807 while (FindNextFileA( find
, &data
))
809 if (!(fileW
= strdupW( data
.cFileName
))) goto exit
;
810 if (!(ret
= header_from_file( fileW
, &header
)))
816 if ((match
= match_profile( &recordW
, &header
)))
818 char **tmp
= realloc( profiles
, sizeof(char *) * (count
+ 1) );
822 len
= sizeof(char) * (lstrlenA( data
.cFileName
) + 1);
823 if (!(profiles
[count
] = malloc( len
))) goto exit
;
826 TRACE( "matching profile: %s\n", debugstr_a(data
.cFileName
) );
827 lstrcpyA( profiles
[count
], data
.cFileName
);
837 if (buffer
&& *size
>= totalsize
)
839 char *p
= (char *)buffer
;
841 for (i
= 0; i
< count
; i
++)
843 lstrcpyA( p
, profiles
[i
] );
844 p
+= lstrlenA( profiles
[i
] ) + 1;
851 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
856 if (number
) *number
= count
;
859 for (i
= 0; i
< count
; i
++) free( profiles
[i
] );
868 /******************************************************************************
869 * EnumColorProfilesW [MSCMS.@]
871 * Enumerate profiles that match given criteria.
874 * machine [I] Name of the machine for which to enumerate profiles.
875 * Must be NULL, which indicates the local machine.
876 * record [I] Record of criteria that a profile must match.
877 * buffer [O] Buffer to receive a string array of profile filenames.
878 * size [I/O] Size of the filename buffer in bytes.
879 * number [O] Number of filenames copied into buffer.
885 BOOL WINAPI
EnumColorProfilesW( PCWSTR machine
, PENUMTYPEW record
, PBYTE buffer
,
886 PDWORD size
, PDWORD number
)
888 BOOL match
, ret
= FALSE
;
889 WCHAR colordir
[MAX_PATH
], glob
[MAX_PATH
], **profiles
= NULL
;
890 DWORD i
, len
= sizeof(colordir
), count
= 0, totalsize
= 0;
891 PROFILEHEADER header
;
892 WIN32_FIND_DATAW data
;
895 TRACE( "( %p, %p, %p, %p, %p )\n", machine
, record
, buffer
, size
, number
);
897 if (machine
|| !record
|| !size
||
898 record
->dwSize
!= sizeof(ENUMTYPEW
) ||
899 record
->dwVersion
!= ENUM_TYPE_VERSION
) return FALSE
;
901 ret
= GetColorDirectoryW( machine
, colordir
, &len
);
902 if (!ret
|| len
+ ARRAY_SIZE(L
"\\*icm") > MAX_PATH
)
904 WARN( "Can't retrieve color directory\n" );
908 lstrcpyW( glob
, colordir
);
909 lstrcatW( glob
, L
"\\*icm" );
911 find
= FindFirstFileW( glob
, &data
);
912 if (find
== INVALID_HANDLE_VALUE
) return FALSE
;
914 if (!(profiles
= calloc( 1, sizeof(WCHAR
*) + 1 ))) goto exit
;
916 if ((ret
= header_from_file( data
.cFileName
, &header
)))
918 if ((match
= match_profile( record
, &header
)))
920 len
= sizeof(WCHAR
) * (lstrlenW( data
.cFileName
) + 1);
921 if (!(profiles
[count
] = malloc( len
))) goto exit
;
924 TRACE( "matching profile: %s\n", debugstr_w(data
.cFileName
) );
925 lstrcpyW( profiles
[count
], data
.cFileName
);
932 while (FindNextFileW( find
, &data
))
934 if (!(ret
= header_from_file( data
.cFileName
, &header
))) continue;
936 if ((match
= match_profile( record
, &header
)))
938 WCHAR
**tmp
= realloc( profiles
, sizeof(WCHAR
*) * (count
+ 1) );
942 len
= sizeof(WCHAR
) * (lstrlenW( data
.cFileName
) + 1);
943 if (!(profiles
[count
] = malloc( len
))) goto exit
;
946 TRACE( "matching profile: %s\n", debugstr_w(data
.cFileName
) );
947 lstrcpyW( profiles
[count
], data
.cFileName
);
955 if (buffer
&& *size
>= totalsize
)
957 WCHAR
*p
= (WCHAR
*)buffer
;
959 for (i
= 0; i
< count
; i
++)
961 lstrcpyW( p
, profiles
[i
] );
962 p
+= lstrlenW( profiles
[i
] ) + 1;
969 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
974 if (number
) *number
= count
;
977 for (i
= 0; i
< count
; i
++) free( profiles
[i
] );
984 /******************************************************************************
985 * InstallColorProfileA [MSCMS.@]
987 * See InstallColorProfileW.
989 BOOL WINAPI
InstallColorProfileA( PCSTR machine
, PCSTR profile
)
995 TRACE( "( %s )\n", debugstr_a(profile
) );
997 if (machine
|| !profile
) return FALSE
;
999 len
= MultiByteToWideChar( CP_ACP
, 0, profile
, -1, NULL
, 0 );
1000 if ((profileW
= malloc( len
* sizeof(WCHAR
) )))
1002 MultiByteToWideChar( CP_ACP
, 0, profile
, -1, profileW
, len
);
1003 ret
= InstallColorProfileW( NULL
, profileW
);
1009 /******************************************************************************
1010 * InstallColorProfileW [MSCMS.@]
1012 * Install a color profile.
1015 * machine [I] Name of the machine to install the profile on. Must be NULL,
1016 * which indicates the local machine.
1017 * profile [I] Full path name of the profile to install.
1023 BOOL WINAPI
InstallColorProfileW( PCWSTR machine
, PCWSTR profile
)
1025 WCHAR dest
[MAX_PATH
], base
[MAX_PATH
];
1026 DWORD size
= sizeof(dest
);
1028 TRACE( "( %s )\n", debugstr_w(profile
) );
1030 if (machine
|| !profile
) return FALSE
;
1032 if (!GetColorDirectoryW( machine
, dest
, &size
)) return FALSE
;
1034 basename( profile
, base
);
1035 lstrcatW( dest
, L
"\\" );
1036 lstrcatW( dest
, base
);
1038 /* Is source equal to destination? */
1039 if (!wcscmp( profile
, dest
)) return TRUE
;
1041 return CopyFileW( profile
, dest
, TRUE
);
1044 /******************************************************************************
1045 * IsColorProfileTagPresent [MSCMS.@]
1047 * Determine if a given ICC tag type is present in a color profile.
1050 * profile [I] Color profile handle.
1051 * tag [I] ICC tag type.
1052 * present [O] Pointer to a BOOL variable. Set to TRUE if tag type is present,
1059 BOOL WINAPI
IsColorProfileTagPresent( HPROFILE handle
, TAGTYPE type
, PBOOL present
)
1061 struct profile
*profile
= (struct profile
*)grab_object( handle
, OBJECT_TYPE_PROFILE
);
1062 struct tag_entry tag
;
1064 TRACE( "( %p, %#lx, %p )\n", handle
, type
, present
);
1066 if (!profile
) return FALSE
;
1070 release_object( &profile
->hdr
);
1073 *present
= get_adjusted_tag( profile
, type
, &tag
);
1074 release_object( &profile
->hdr
);
1078 /******************************************************************************
1079 * IsColorProfileValid [MSCMS.@]
1081 * Determine if a given color profile is valid.
1084 * profile [I] Color profile handle.
1085 * valid [O] Pointer to a BOOL variable. Set to TRUE if profile is valid,
1092 BOOL WINAPI
IsColorProfileValid( HPROFILE handle
, PBOOL valid
)
1094 struct profile
*profile
= (struct profile
*)grab_object( handle
, OBJECT_TYPE_PROFILE
);
1096 TRACE( "( %p, %p )\n", handle
, valid
);
1098 if (!profile
) return FALSE
;
1102 release_object( &profile
->hdr
);
1105 *valid
= !!profile
->data
;
1106 release_object( &profile
->hdr
);
1110 /******************************************************************************
1111 * SetColorProfileElement [MSCMS.@]
1113 * Set data for a specified tag type.
1116 * profile [I] Handle to a color profile.
1117 * type [I] ICC tag type.
1118 * offset [I] Offset in bytes to start copying to.
1119 * size [I/O] Size of the buffer in bytes. On return the variable holds the
1120 * number of bytes actually needed.
1121 * buffer [O] Buffer holding the tag data.
1127 BOOL WINAPI
SetColorProfileElement( HPROFILE handle
, TAGTYPE type
, DWORD offset
, PDWORD size
,
1131 struct profile
*profile
= (struct profile
*)grab_object( handle
, OBJECT_TYPE_PROFILE
);
1133 TRACE( "( %p, %#lx, %lu, %p, %p )\n", handle
, type
, offset
, size
, buffer
);
1135 if (!profile
) return FALSE
;
1137 if (!size
|| !buffer
|| !(profile
->access
& PROFILE_READWRITE
))
1139 release_object( &profile
->hdr
);
1142 ret
= set_tag_data( profile
, type
, offset
, buffer
, size
);
1143 release_object( &profile
->hdr
);
1147 /******************************************************************************
1148 * SetColorProfileHeader [MSCMS.@]
1150 * Set header data for a given profile.
1153 * profile [I] Handle to a color profile.
1154 * header [I] Buffer holding the header data.
1160 BOOL WINAPI
SetColorProfileHeader( HPROFILE handle
, PPROFILEHEADER header
)
1162 struct profile
*profile
= (struct profile
*)grab_object( handle
, OBJECT_TYPE_PROFILE
);
1164 TRACE( "( %p, %p )\n", handle
, header
);
1166 if (!profile
) return FALSE
;
1168 if (!header
|| !(profile
->access
& PROFILE_READWRITE
))
1170 release_object( &profile
->hdr
);
1173 set_profile_header( profile
, header
);
1174 release_object( &profile
->hdr
);
1178 /******************************************************************************
1179 * UninstallColorProfileA [MSCMS.@]
1181 * See UninstallColorProfileW.
1183 BOOL WINAPI
UninstallColorProfileA( PCSTR machine
, PCSTR profile
, BOOL
delete )
1189 TRACE( "( %s, %x )\n", debugstr_a(profile
), delete );
1191 if (machine
|| !profile
) return FALSE
;
1193 len
= MultiByteToWideChar( CP_ACP
, 0, profile
, -1, NULL
, 0 );
1194 if ((profileW
= malloc( len
* sizeof(WCHAR
) )))
1196 MultiByteToWideChar( CP_ACP
, 0, profile
, -1, profileW
, len
);
1197 ret
= UninstallColorProfileW( NULL
, profileW
, delete );
1203 /******************************************************************************
1204 * UninstallColorProfileW [MSCMS.@]
1206 * Uninstall a color profile.
1209 * machine [I] Name of the machine to uninstall the profile on. Must be NULL,
1210 * which indicates the local machine.
1211 * profile [I] Full path name of the profile to uninstall.
1212 * delete [I] Bool that specifies whether the profile file should be deleted.
1218 BOOL WINAPI
UninstallColorProfileW( PCWSTR machine
, PCWSTR profile
, BOOL
delete )
1220 TRACE( "( %s, %x )\n", debugstr_w(profile
), delete );
1222 if (machine
|| !profile
) return FALSE
;
1224 if (delete) return DeleteFileW( profile
);
1228 static BOOL
profile_AtoW( const PROFILE
*in
, PROFILE
*out
)
1231 if (!in
->pProfileData
) return FALSE
;
1232 len
= MultiByteToWideChar( CP_ACP
, 0, in
->pProfileData
, -1, NULL
, 0 );
1233 if (!(out
->pProfileData
= malloc( len
* sizeof(WCHAR
) ))) return FALSE
;
1234 out
->cbDataSize
= len
* sizeof(WCHAR
);
1235 MultiByteToWideChar( CP_ACP
, 0, in
->pProfileData
, -1, out
->pProfileData
, len
);
1236 out
->dwType
= in
->dwType
;
1240 /******************************************************************************
1241 * OpenColorProfileA [MSCMS.@]
1243 * See OpenColorProfileW.
1245 HPROFILE WINAPI
OpenColorProfileA( PPROFILE profile
, DWORD access
, DWORD sharing
, DWORD creation
)
1247 HPROFILE handle
= NULL
;
1250 TRACE( "( %p, %#lx, %#lx, %#lx )\n", profile
, access
, sharing
, creation
);
1252 if (!profile
|| !profile
->pProfileData
) return NULL
;
1254 /* No AW conversion needed for memory based profiles */
1255 if (profile
->dwType
& PROFILE_MEMBUFFER
)
1256 return OpenColorProfileW( profile
, access
, sharing
, creation
);
1258 if (!profile_AtoW( profile
, &profileW
)) return FALSE
;
1259 handle
= OpenColorProfileW( &profileW
, access
, sharing
, creation
);
1260 free( profileW
.pProfileData
);
1264 void close_profile( struct object
*obj
)
1266 struct profile
*profile
= (struct profile
*)obj
;
1268 if (profile
->file
!= INVALID_HANDLE_VALUE
)
1270 if (profile
->access
& PROFILE_READWRITE
)
1273 if (SetFilePointer( profile
->file
, 0, NULL
, FILE_BEGIN
) ||
1274 !WriteFile( profile
->file
, profile
->data
, profile
->size
, &count
, NULL
) || count
!= profile
->size
)
1276 ERR( "Unable to write color profile\n" );
1279 CloseHandle( profile
->file
);
1282 if (profile
->cmsprofile
) cmsCloseProfile( profile
->cmsprofile
);
1283 free( profile
->data
);
1286 /******************************************************************************
1287 * OpenColorProfileW [MSCMS.@]
1289 * Open a color profile.
1292 * profile [I] Pointer to a color profile structure.
1293 * access [I] Desired access.
1294 * sharing [I] Sharing mode.
1295 * creation [I] Creation mode.
1298 * Success: Handle to the opened profile.
1302 * Values for access: PROFILE_READ or PROFILE_READWRITE.
1303 * Values for sharing: 0 (no sharing), FILE_SHARE_READ and/or FILE_SHARE_WRITE.
1304 * Values for creation: one of CREATE_NEW, CREATE_ALWAYS, OPEN_EXISTING,
1305 * OPEN_ALWAYS, TRUNCATE_EXISTING.
1306 * Sharing and creation flags are ignored for memory based profiles.
1308 HPROFILE WINAPI
OpenColorProfileW( PPROFILE profile
, DWORD access
, DWORD sharing
, DWORD creation
)
1310 struct profile
*prof
;
1312 cmsHPROFILE cmsprofile
;
1314 HANDLE handle
= INVALID_HANDLE_VALUE
;
1317 TRACE( "( %p, %#lx, %#lx, %#lx )\n", profile
, access
, sharing
, creation
);
1319 if (!profile
|| !profile
->pProfileData
) return NULL
;
1321 if (profile
->dwType
== PROFILE_MEMBUFFER
)
1323 /* FIXME: access flags not implemented for memory based profiles */
1325 if (!(data
= malloc( profile
->cbDataSize
))) return NULL
;
1326 memcpy( data
, profile
->pProfileData
, profile
->cbDataSize
);
1328 if (!(cmsprofile
= cmsOpenProfileFromMem( data
, profile
->cbDataSize
)))
1333 size
= profile
->cbDataSize
;
1335 else if (profile
->dwType
== PROFILE_FILENAME
)
1337 DWORD read
, flags
= 0;
1339 TRACE( "profile file: %s\n", debugstr_w( profile
->pProfileData
) );
1341 if (access
& PROFILE_READ
) flags
= GENERIC_READ
;
1342 if (access
& PROFILE_READWRITE
) flags
= GENERIC_READ
|GENERIC_WRITE
;
1344 if (!flags
) return NULL
;
1345 if (!sharing
) sharing
= FILE_SHARE_READ
;
1347 if (!PathIsRelativeW( profile
->pProfileData
))
1348 handle
= CreateFileW( profile
->pProfileData
, flags
, sharing
, NULL
, creation
, 0, NULL
);
1353 if (!GetColorDirectoryW( NULL
, NULL
, &size
) && GetLastError() == ERROR_MORE_DATA
)
1355 size
+= (lstrlenW( profile
->pProfileData
) + 2) * sizeof(WCHAR
);
1356 if (!(path
= malloc( size
))) return NULL
;
1357 GetColorDirectoryW( NULL
, path
, &size
);
1358 PathAddBackslashW( path
);
1359 lstrcatW( path
, profile
->pProfileData
);
1362 handle
= CreateFileW( path
, flags
, sharing
, NULL
, creation
, 0, NULL
);
1365 if (handle
== INVALID_HANDLE_VALUE
)
1367 WARN( "Unable to open color profile %lu\n", GetLastError() );
1370 if ((size
= GetFileSize( handle
, NULL
)) == INVALID_FILE_SIZE
)
1372 ERR( "Unable to retrieve size of color profile\n" );
1373 CloseHandle( handle
);
1376 if (!(data
= malloc( size
)))
1378 ERR( "Unable to allocate memory for color profile\n" );
1379 CloseHandle( handle
);
1382 if (!ReadFile( handle
, data
, size
, &read
, NULL
) || read
!= size
)
1384 ERR( "Unable to read color profile\n" );
1385 CloseHandle( handle
);
1389 if (!(cmsprofile
= cmsOpenProfileFromMem( data
, size
)))
1391 CloseHandle( handle
);
1398 ERR( "Invalid profile type %lu\n", profile
->dwType
);
1402 if ((prof
= calloc( 1, sizeof(*prof
) )))
1404 prof
->hdr
.type
= OBJECT_TYPE_PROFILE
;
1405 prof
->hdr
.close
= close_profile
;
1406 prof
->file
= handle
;
1407 prof
->access
= access
;
1410 prof
->cmsprofile
= cmsprofile
;
1411 if ((ret
= alloc_handle( &prof
->hdr
))) return ret
;
1415 cmsCloseProfile( cmsprofile
);
1417 CloseHandle( handle
);
1421 /******************************************************************************
1422 * CloseColorProfile [MSCMS.@]
1424 * Close a color profile.
1427 * profile [I] Handle to the profile.
1433 BOOL WINAPI
CloseColorProfile( HPROFILE handle
)
1435 struct profile
*profile
= (struct profile
*)grab_object( handle
, OBJECT_TYPE_PROFILE
);
1437 TRACE( "( %p )\n", handle
);
1439 if (!profile
) return FALSE
;
1440 free_handle( handle
);
1441 release_object( &profile
->hdr
);
1445 /******************************************************************************
1446 * WcsGetUsePerUserProfiles [MSCMS.@]
1448 BOOL WINAPI
WcsGetUsePerUserProfiles( const WCHAR
* name
, DWORD
class, BOOL
* use_per_user_profile
)
1450 FIXME( "%s %s %p\n", debugstr_w(name
), dbgstr_tag(class), use_per_user_profile
);
1451 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
1455 /******************************************************************************
1456 * WcsEnumColorProfilesSize [MSCMS.@]
1458 BOOL WINAPI
WcsEnumColorProfilesSize( WCS_PROFILE_MANAGEMENT_SCOPE scope
, ENUMTYPEW
*record
, DWORD
*size
)
1460 FIXME( "%d %p %p\n", scope
, record
, size
);
1461 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
1465 /******************************************************************************
1466 * WcsGetDefaultColorProfileSize [MSCMS.@]
1468 BOOL WINAPI
WcsGetDefaultColorProfileSize( WCS_PROFILE_MANAGEMENT_SCOPE scope
, PCWSTR device_name
,
1469 COLORPROFILETYPE type
, COLORPROFILESUBTYPE subtype
,
1470 DWORD profile_id
, PDWORD profile_size
)
1472 FIXME( "%d, %s, %d, %d, %lu, %p\n", scope
, debugstr_w(device_name
), type
, subtype
, profile_id
, profile_size
);
1473 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
1477 /******************************************************************************
1478 * WcsGetDefaultRednderingIntent [MSCMS.@]
1480 BOOL WINAPI
WcsGetDefaultRenderingIntent( WCS_PROFILE_MANAGEMENT_SCOPE scope
, PDWORD intent
)
1482 FIXME( "%d %p\n", scope
, intent
);
1483 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
1487 /******************************************************************************
1488 * WcsOpenColorProfileA [MSCMS.@]
1490 HPROFILE WINAPI
WcsOpenColorProfileA( PROFILE
*cdm
, PROFILE
*camp
, PROFILE
*gmmp
, DWORD access
, DWORD sharing
,
1491 DWORD creation
, DWORD flags
)
1493 PROFILE cdmW
, campW
= {0}, gmmpW
= {0};
1494 HPROFILE ret
= NULL
;
1496 TRACE( "%p, %p, %p, %#lx, %#lx, %#lx, %#lx\n", cdm
, camp
, gmmp
, access
, sharing
, creation
, flags
);
1498 if (!cdm
|| !profile_AtoW( cdm
, &cdmW
)) return NULL
;
1499 if (camp
&& !profile_AtoW( camp
, &campW
)) goto done
;
1500 if (gmmp
&& !profile_AtoW( gmmp
, &gmmpW
)) goto done
;
1502 ret
= WcsOpenColorProfileW( &cdmW
, &campW
, &gmmpW
, access
, sharing
, creation
, flags
);
1505 free( cdmW
.pProfileData
);
1506 free( campW
.pProfileData
);
1507 free( gmmpW
.pProfileData
);
1511 /******************************************************************************
1512 * WcsOpenColorProfileW [MSCMS.@]
1514 HPROFILE WINAPI
WcsOpenColorProfileW( PROFILE
*cdm
, PROFILE
*camp
, PROFILE
*gmmp
, DWORD access
, DWORD sharing
,
1515 DWORD creation
, DWORD flags
)
1517 TRACE( "%p, %p, %p, %#lx, %#lx, %#lx, %#lx\n", cdm
, camp
, gmmp
, access
, sharing
, creation
, flags
);
1518 FIXME("no support for WCS profiles\n" );
1520 return OpenColorProfileW( cdm
, access
, sharing
, creation
);