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
31 #include "wine/debug.h"
33 #include "mscms_priv.h"
35 static void basename( LPCWSTR path
, LPWSTR name
)
37 INT i
= lstrlenW( path
);
39 while (i
> 0 && path
[i
- 1] != '\\' && path
[i
- 1] != '/') i
--;
40 lstrcpyW( name
, &path
[i
] );
43 static inline LPWSTR
strdupW( LPCSTR str
)
48 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
49 if ((ret
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) )))
50 MultiByteToWideChar( CP_ACP
, 0, str
, -1, ret
, len
);
55 const char *dbgstr_tag( DWORD tag
)
57 return wine_dbg_sprintf( "'%c%c%c%c'",
58 (char)(tag
>> 24), (char)(tag
>> 16), (char)(tag
>> 8), (char)(tag
) );
61 WINE_DEFAULT_DEBUG_CHANNEL(mscms
);
63 /******************************************************************************
64 * AssociateColorProfileWithDeviceA [MSCMS.@]
66 BOOL WINAPI
AssociateColorProfileWithDeviceA( PCSTR machine
, PCSTR profile
, PCSTR device
)
70 WCHAR
*profileW
, *deviceW
;
72 TRACE( "( %s, %s, %s )\n", debugstr_a(machine
), debugstr_a(profile
), debugstr_a(device
) );
74 if (!profile
|| !device
)
76 SetLastError( ERROR_INVALID_PARAMETER
);
81 SetLastError( ERROR_NOT_SUPPORTED
);
85 len
= MultiByteToWideChar( CP_ACP
, 0, profile
, -1, NULL
, 0 );
86 if (!(profileW
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) ))) return FALSE
;
88 MultiByteToWideChar( CP_ACP
, 0, profile
, -1, profileW
, len
);
90 len
= MultiByteToWideChar( CP_ACP
, 0, device
, -1, NULL
, 0 );
91 if ((deviceW
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) )))
93 MultiByteToWideChar( CP_ACP
, 0, device
, -1, deviceW
, len
);
94 ret
= AssociateColorProfileWithDeviceW( NULL
, profileW
, deviceW
);
97 HeapFree( GetProcessHeap(), 0, profileW
);
98 HeapFree( GetProcessHeap(), 0, deviceW
);
102 static BOOL
set_profile_device_key( PCWSTR file
, const BYTE
*value
, DWORD size
)
104 PROFILEHEADER header
;
107 HKEY icm_key
, class_key
;
108 WCHAR basenameW
[MAX_PATH
], classW
[5];
110 profile
.dwType
= PROFILE_FILENAME
;
111 profile
.pProfileData
= (PVOID
)file
;
112 profile
.cbDataSize
= (lstrlenW( file
) + 1) * sizeof(WCHAR
);
114 /* FIXME is the profile installed? */
115 if (!(handle
= OpenColorProfileW( &profile
, PROFILE_READ
, 0, OPEN_EXISTING
)))
117 SetLastError( ERROR_INVALID_PROFILE
);
120 if (!GetColorProfileHeader( handle
, &header
))
122 CloseColorProfile( handle
);
123 SetLastError( ERROR_INVALID_PROFILE
);
126 RegCreateKeyExW( HKEY_LOCAL_MACHINE
, L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\ICM",
127 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &icm_key
, NULL
);
129 basename( file
, basenameW
);
130 swprintf( classW
, ARRAY_SIZE(classW
), L
"%c%c%c%c",
131 (header
.phClass
>> 24) & 0xff, (header
.phClass
>> 16) & 0xff,
132 (header
.phClass
>> 8) & 0xff, header
.phClass
& 0xff );
134 RegCreateKeyExW( icm_key
, classW
, 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &class_key
, NULL
);
135 if (value
) RegSetValueExW( class_key
, basenameW
, 0, REG_BINARY
, value
, size
);
136 else RegDeleteValueW( class_key
, basenameW
);
138 RegCloseKey( class_key
);
139 RegCloseKey( icm_key
);
140 CloseColorProfile( handle
);
144 /******************************************************************************
145 * AssociateColorProfileWithDeviceW [MSCMS.@]
147 BOOL WINAPI
AssociateColorProfileWithDeviceW( PCWSTR machine
, PCWSTR profile
, PCWSTR device
)
149 static const BYTE dummy_value
[12];
151 TRACE( "( %s, %s, %s )\n", debugstr_w(machine
), debugstr_w(profile
), debugstr_w(device
) );
153 if (!profile
|| !device
)
155 SetLastError( ERROR_INVALID_PARAMETER
);
160 SetLastError( ERROR_NOT_SUPPORTED
);
164 return set_profile_device_key( profile
, dummy_value
, sizeof(dummy_value
) );
167 /******************************************************************************
168 * DisassociateColorProfileFromDeviceA [MSCMS.@]
170 BOOL WINAPI
DisassociateColorProfileFromDeviceA( PCSTR machine
, PCSTR profile
, PCSTR device
)
174 WCHAR
*profileW
, *deviceW
;
176 TRACE( "( %s, %s, %s )\n", debugstr_a(machine
), debugstr_a(profile
), debugstr_a(device
) );
178 if (!profile
|| !device
)
180 SetLastError( ERROR_INVALID_PARAMETER
);
185 SetLastError( ERROR_NOT_SUPPORTED
);
189 len
= MultiByteToWideChar( CP_ACP
, 0, profile
, -1, NULL
, 0 );
190 if (!(profileW
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) ))) return FALSE
;
192 MultiByteToWideChar( CP_ACP
, 0, profile
, -1, profileW
, len
);
194 len
= MultiByteToWideChar( CP_ACP
, 0, device
, -1, NULL
, 0 );
195 if ((deviceW
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) )))
197 MultiByteToWideChar( CP_ACP
, 0, device
, -1, deviceW
, len
);
198 ret
= DisassociateColorProfileFromDeviceW( NULL
, profileW
, deviceW
);
201 HeapFree( GetProcessHeap(), 0, profileW
);
202 HeapFree( GetProcessHeap(), 0, deviceW
);
206 /******************************************************************************
207 * DisassociateColorProfileFromDeviceW [MSCMS.@]
209 BOOL WINAPI
DisassociateColorProfileFromDeviceW( PCWSTR machine
, PCWSTR profile
, PCWSTR device
)
211 TRACE( "( %s, %s, %s )\n", debugstr_w(machine
), debugstr_w(profile
), debugstr_w(device
) );
213 if (!profile
|| !device
)
215 SetLastError( ERROR_INVALID_PARAMETER
);
220 SetLastError( ERROR_NOT_SUPPORTED
);
224 return set_profile_device_key( profile
, NULL
, 0 );
227 /******************************************************************************
228 * GetColorDirectoryA [MSCMS.@]
230 * See GetColorDirectoryW.
232 BOOL WINAPI
GetColorDirectoryA( PCSTR machine
, PSTR buffer
, PDWORD size
)
239 TRACE( "( %p, %p )\n", buffer
, size
);
241 if (machine
|| !size
) return FALSE
;
245 ret
= GetColorDirectoryW( NULL
, NULL
, &sizeW
);
246 *size
= sizeW
/ sizeof(WCHAR
);
250 sizeW
= *size
* sizeof(WCHAR
);
252 bufferW
= HeapAlloc( GetProcessHeap(), 0, sizeW
);
255 if ((ret
= GetColorDirectoryW( NULL
, bufferW
, &sizeW
)))
257 *size
= WideCharToMultiByte( CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
258 len
= WideCharToMultiByte( CP_ACP
, 0, bufferW
, -1, buffer
, *size
, NULL
, NULL
);
259 if (!len
) ret
= FALSE
;
261 else *size
= sizeW
/ sizeof(WCHAR
);
263 HeapFree( GetProcessHeap(), 0, bufferW
);
268 /******************************************************************************
269 * GetColorDirectoryW [MSCMS.@]
271 * Get the directory where color profiles are stored.
274 * machine [I] Name of the machine for which to get the color directory.
275 * Must be NULL, which indicates the local machine.
276 * buffer [I] Buffer to receive the path name.
277 * size [I/O] Size of the buffer in bytes. On return the variable holds
278 * the number of bytes actually needed.
280 BOOL WINAPI
GetColorDirectoryW( PCWSTR machine
, PWSTR buffer
, PDWORD size
)
282 WCHAR colordir
[MAX_PATH
];
285 TRACE( "( %p, %p )\n", buffer
, size
);
287 if (machine
|| !size
) return FALSE
;
289 GetSystemDirectoryW( colordir
, ARRAY_SIZE( colordir
));
290 lstrcatW( colordir
, L
"\\spool\\drivers\\color" );
292 len
= lstrlenW( colordir
) * sizeof(WCHAR
);
294 if (buffer
&& len
<= *size
)
296 lstrcpyW( buffer
, colordir
);
301 SetLastError( ERROR_MORE_DATA
);
306 /******************************************************************************
307 * GetColorProfileElement [MSCMS.@]
309 * Retrieve data for a specified tag type.
312 * profile [I] Handle to a color profile.
313 * type [I] ICC tag type.
314 * offset [I] Offset in bytes to start copying from.
315 * size [I/O] Size of the buffer in bytes. On return the variable holds
316 * the number of bytes actually needed.
317 * buffer [O] Buffer to receive the tag data.
318 * ref [O] Pointer to a BOOL that specifies whether more than one tag
319 * references the data.
325 BOOL WINAPI
GetColorProfileElement( HPROFILE handle
, TAGTYPE type
, DWORD offset
, PDWORD size
,
326 PVOID buffer
, PBOOL ref
)
329 struct profile
*profile
= grab_profile( handle
);
331 TRACE( "( %p, 0x%08x, %d, %p, %p, %p )\n", handle
, type
, offset
, size
, buffer
, ref
);
333 if (!profile
) return FALSE
;
337 release_profile( profile
);
340 ret
= get_tag_data( profile
, type
, offset
, buffer
, size
, ref
);
341 release_profile( profile
);
345 /******************************************************************************
346 * GetColorProfileElementTag [MSCMS.@]
348 * Get the tag type from a color profile by index.
351 * profile [I] Handle to a color profile.
352 * index [I] Index into the tag table of the color profile.
353 * type [O] Pointer to a variable that holds the ICC tag type on return.
360 * The tag table index starts at 1.
361 * Use GetCountColorProfileElements to retrieve a count of tagged elements.
363 BOOL WINAPI
GetColorProfileElementTag( HPROFILE handle
, DWORD index
, PTAGTYPE type
)
366 struct profile
*profile
= grab_profile( handle
);
367 struct tag_entry tag
;
369 TRACE( "( %p, %d, %p )\n", handle
, index
, type
);
371 if (!profile
) return FALSE
;
375 release_profile( profile
);
378 if ((ret
= get_tag_entry( profile
, index
, &tag
))) *type
= tag
.sig
;
379 release_profile( profile
);
383 /******************************************************************************
384 * GetColorProfileFromHandle [MSCMS.@]
386 * Retrieve an ICC color profile by handle.
389 * profile [I] Handle to a color profile.
390 * buffer [O] Buffer to receive the ICC profile.
391 * size [I/O] Size of the buffer in bytes. On return the variable holds the
392 * number of bytes actually needed.
399 * The profile returned will be in big-endian format.
401 BOOL WINAPI
GetColorProfileFromHandle( HPROFILE handle
, PBYTE buffer
, PDWORD size
)
403 struct profile
*profile
= grab_profile( handle
);
404 PROFILEHEADER header
;
406 TRACE( "( %p, %p, %p )\n", handle
, buffer
, size
);
408 if (!profile
) return FALSE
;
412 release_profile( profile
);
415 get_profile_header( profile
, &header
);
417 if (!buffer
|| header
.phSize
> *size
)
419 *size
= header
.phSize
;
420 release_profile( profile
);
424 /* No endian conversion needed */
425 memcpy( buffer
, profile
->data
, profile
->size
);
426 *size
= profile
->size
;
428 release_profile( profile
);
432 /******************************************************************************
433 * GetColorProfileHeader [MSCMS.@]
435 * Retrieve a color profile header by handle.
438 * profile [I] Handle to a color profile.
439 * header [O] Buffer to receive the ICC profile header.
446 * The profile header returned will be adjusted for endianness.
448 BOOL WINAPI
GetColorProfileHeader( HPROFILE handle
, PPROFILEHEADER header
)
450 struct profile
*profile
= grab_profile( handle
);
452 TRACE( "( %p, %p )\n", handle
, header
);
454 if (!profile
) return FALSE
;
458 release_profile( profile
);
461 get_profile_header( profile
, header
);
462 release_profile( profile
);
466 /******************************************************************************
467 * GetCountColorProfileElements [MSCMS.@]
469 * Retrieve the number of elements in a color profile.
472 * profile [I] Handle to a color profile.
473 * count [O] Pointer to a variable which is set to the number of elements
474 * in the color profile.
480 BOOL WINAPI
GetCountColorProfileElements( HPROFILE handle
, PDWORD count
)
482 struct profile
*profile
= grab_profile( handle
);
484 TRACE( "( %p, %p )\n", handle
, count
);
486 if (!profile
) return FALSE
;
490 release_profile( profile
);
493 *count
= get_tag_count( profile
);
494 release_profile( profile
);
498 /******************************************************************************
499 * GetStandardColorSpaceProfileA [MSCMS.@]
501 * See GetStandardColorSpaceProfileW.
503 BOOL WINAPI
GetStandardColorSpaceProfileA( PCSTR machine
, DWORD id
, PSTR profile
, PDWORD size
)
510 TRACE( "( 0x%08x, %p, %p )\n", id
, profile
, size
);
514 SetLastError( ERROR_NOT_SUPPORTED
);
520 SetLastError( ERROR_INVALID_PARAMETER
);
524 sizeW
= *size
* sizeof(WCHAR
);
528 ret
= GetStandardColorSpaceProfileW( NULL
, id
, NULL
, &sizeW
);
529 *size
= sizeW
/ sizeof(WCHAR
);
533 profileW
= HeapAlloc( GetProcessHeap(), 0, sizeW
);
536 if ((ret
= GetStandardColorSpaceProfileW( NULL
, id
, profileW
, &sizeW
)))
538 *size
= WideCharToMultiByte( CP_ACP
, 0, profileW
, -1, NULL
, 0, NULL
, NULL
);
539 len
= WideCharToMultiByte( CP_ACP
, 0, profileW
, -1, profile
, *size
, NULL
, NULL
);
540 if (!len
) ret
= FALSE
;
542 else *size
= sizeW
/ sizeof(WCHAR
);
544 HeapFree( GetProcessHeap(), 0, profileW
);
549 /******************************************************************************
550 * GetStandardColorSpaceProfileW [MSCMS.@]
552 * Retrieve the profile filename for a given standard color space id.
555 * machine [I] Name of the machine for which to get the standard color space.
556 * Must be NULL, which indicates the local machine.
557 * id [I] Id of a standard color space.
558 * profile [O] Buffer to receive the profile filename.
559 * size [I/O] Size of the filename buffer in bytes.
565 BOOL WINAPI
GetStandardColorSpaceProfileW( PCWSTR machine
, DWORD id
, PWSTR profile
, PDWORD size
)
567 WCHAR rgbprofile
[MAX_PATH
];
568 DWORD len
= sizeof(rgbprofile
);
570 TRACE( "( 0x%08x, %p, %p )\n", id
, profile
, size
);
574 SetLastError( ERROR_NOT_SUPPORTED
);
580 SetLastError( ERROR_INVALID_PARAMETER
);
586 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
590 GetColorDirectoryW( machine
, rgbprofile
, &len
);
595 case LCS_WINDOWS_COLOR_SPACE
: /* FIXME */
596 lstrcatW( rgbprofile
, L
"\\srgb color space profile.icm" );
597 len
= lstrlenW( rgbprofile
) * sizeof(WCHAR
);
602 SetLastError( ERROR_MORE_DATA
);
606 lstrcpyW( profile
, rgbprofile
);
610 SetLastError( ERROR_FILE_NOT_FOUND
);
616 static BOOL
header_from_file( LPCWSTR file
, PPROFILEHEADER header
)
620 WCHAR path
[MAX_PATH
];
621 DWORD size
= sizeof(path
);
624 ret
= GetColorDirectoryW( NULL
, path
, &size
);
627 WARN( "Can't retrieve color directory\n" );
630 if (size
+ sizeof(L
"\\") + sizeof(WCHAR
) * lstrlenW( file
) > sizeof(path
))
632 WARN( "Filename too long\n" );
636 lstrcatW( path
, L
"\\" );
637 lstrcatW( path
, file
);
639 profile
.dwType
= PROFILE_FILENAME
;
640 profile
.pProfileData
= path
;
641 profile
.cbDataSize
= lstrlenW( path
) + 1;
643 handle
= OpenColorProfileW( &profile
, PROFILE_READ
, FILE_SHARE_READ
, OPEN_EXISTING
);
646 WARN( "Can't open color profile\n" );
650 ret
= GetColorProfileHeader( handle
, header
);
652 WARN( "Can't retrieve color profile header\n" );
654 CloseColorProfile( handle
);
658 static BOOL
match_profile( PENUMTYPEW rec
, PPROFILEHEADER hdr
)
660 if (rec
->dwFields
& ET_DEVICENAME
)
662 FIXME( "ET_DEVICENAME: %s\n", debugstr_w(rec
->pDeviceName
) );
664 if (rec
->dwFields
& ET_MEDIATYPE
)
666 FIXME( "ET_MEDIATYPE: 0x%08x\n", rec
->dwMediaType
);
668 if (rec
->dwFields
& ET_DITHERMODE
)
670 FIXME( "ET_DITHERMODE: 0x%08x\n", rec
->dwDitheringMode
);
672 if (rec
->dwFields
& ET_RESOLUTION
)
674 FIXME( "ET_RESOLUTION: 0x%08x, 0x%08x\n",
675 rec
->dwResolution
[0], rec
->dwResolution
[1] );
677 if (rec
->dwFields
& ET_DEVICECLASS
)
679 FIXME( "ET_DEVICECLASS: %s\n", dbgstr_tag(rec
->dwMediaType
) );
681 if (rec
->dwFields
& ET_CMMTYPE
)
683 TRACE( "ET_CMMTYPE: %s\n", dbgstr_tag(rec
->dwCMMType
) );
684 if (rec
->dwCMMType
!= hdr
->phCMMType
) return FALSE
;
686 if (rec
->dwFields
& ET_CLASS
)
688 TRACE( "ET_CLASS: %s\n", dbgstr_tag(rec
->dwClass
) );
689 if (rec
->dwClass
!= hdr
->phClass
) return FALSE
;
691 if (rec
->dwFields
& ET_DATACOLORSPACE
)
693 TRACE( "ET_DATACOLORSPACE: %s\n", dbgstr_tag(rec
->dwDataColorSpace
) );
694 if (rec
->dwDataColorSpace
!= hdr
->phDataColorSpace
) return FALSE
;
696 if (rec
->dwFields
& ET_CONNECTIONSPACE
)
698 TRACE( "ET_CONNECTIONSPACE: %s\n", dbgstr_tag(rec
->dwConnectionSpace
) );
699 if (rec
->dwConnectionSpace
!= hdr
->phConnectionSpace
) return FALSE
;
701 if (rec
->dwFields
& ET_SIGNATURE
)
703 TRACE( "ET_SIGNATURE: %s\n", dbgstr_tag(rec
->dwSignature
) );
704 if (rec
->dwSignature
!= hdr
->phSignature
) return FALSE
;
706 if (rec
->dwFields
& ET_PLATFORM
)
708 TRACE( "ET_PLATFORM: %s\n", dbgstr_tag(rec
->dwPlatform
) );
709 if (rec
->dwPlatform
!= hdr
->phPlatform
) return FALSE
;
711 if (rec
->dwFields
& ET_PROFILEFLAGS
)
713 TRACE( "ET_PROFILEFLAGS: 0x%08x\n", rec
->dwProfileFlags
);
714 if (rec
->dwProfileFlags
!= hdr
->phProfileFlags
) return FALSE
;
716 if (rec
->dwFields
& ET_MANUFACTURER
)
718 TRACE( "ET_MANUFACTURER: %s\n", dbgstr_tag(rec
->dwManufacturer
) );
719 if (rec
->dwManufacturer
!= hdr
->phManufacturer
) return FALSE
;
721 if (rec
->dwFields
& ET_MODEL
)
723 TRACE( "ET_MODEL: %s\n", dbgstr_tag(rec
->dwModel
) );
724 if (rec
->dwModel
!= hdr
->phModel
) return FALSE
;
726 if (rec
->dwFields
& ET_ATTRIBUTES
)
728 TRACE( "ET_ATTRIBUTES: 0x%08x, 0x%08x\n",
729 rec
->dwAttributes
[0], rec
->dwAttributes
[1] );
730 if (rec
->dwAttributes
[0] != hdr
->phAttributes
[0] ||
731 rec
->dwAttributes
[1] != hdr
->phAttributes
[1]) return FALSE
;
733 if (rec
->dwFields
& ET_RENDERINGINTENT
)
735 TRACE( "ET_RENDERINGINTENT: 0x%08x\n", rec
->dwRenderingIntent
);
736 if (rec
->dwRenderingIntent
!= hdr
->phRenderingIntent
) return FALSE
;
738 if (rec
->dwFields
& ET_CREATOR
)
740 TRACE( "ET_CREATOR: %s\n", dbgstr_tag(rec
->dwCreator
) );
741 if (rec
->dwCreator
!= hdr
->phCreator
) return FALSE
;
746 /******************************************************************************
747 * EnumColorProfilesA [MSCMS.@]
749 * See EnumColorProfilesW.
751 BOOL WINAPI
EnumColorProfilesA( PCSTR machine
, PENUMTYPEA record
, PBYTE buffer
,
752 PDWORD size
, PDWORD number
)
754 BOOL match
, ret
= FALSE
;
755 char spec
[] = "\\*.icm";
756 char colordir
[MAX_PATH
], glob
[MAX_PATH
], **profiles
= NULL
;
757 DWORD i
, len
= sizeof(colordir
), count
= 0, totalsize
= 0;
758 PROFILEHEADER header
;
759 WIN32_FIND_DATAA data
;
761 WCHAR
*fileW
= NULL
, *deviceW
= NULL
;
764 TRACE( "( %p, %p, %p, %p, %p )\n", machine
, record
, buffer
, size
, number
);
766 if (machine
|| !record
|| !size
||
767 record
->dwSize
!= sizeof(ENUMTYPEA
) ||
768 record
->dwVersion
!= ENUM_TYPE_VERSION
) return FALSE
;
770 ret
= GetColorDirectoryA( machine
, colordir
, &len
);
771 if (!ret
|| len
+ sizeof(spec
) > MAX_PATH
)
773 WARN( "can't retrieve color directory\n" );
777 lstrcpyA( glob
, colordir
);
778 lstrcatA( glob
, spec
);
780 find
= FindFirstFileA( glob
, &data
);
781 if (find
== INVALID_HANDLE_VALUE
) return FALSE
;
783 profiles
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(char *) + 1 );
784 if (!profiles
) goto exit
;
786 memcpy( &recordW
, record
, sizeof(ENUMTYPEA
) );
787 if (record
->pDeviceName
)
789 deviceW
= strdupW( record
->pDeviceName
);
790 if (!(recordW
.pDeviceName
= deviceW
)) goto exit
;
793 fileW
= strdupW( data
.cFileName
);
794 if (!fileW
) goto exit
;
796 ret
= header_from_file( fileW
, &header
);
799 match
= match_profile( &recordW
, &header
);
802 len
= sizeof(char) * (lstrlenA( data
.cFileName
) + 1);
803 profiles
[count
] = HeapAlloc( GetProcessHeap(), 0, len
);
805 if (!profiles
[count
]) goto exit
;
808 TRACE( "matching profile: %s\n", debugstr_a(data
.cFileName
) );
809 lstrcpyA( profiles
[count
], data
.cFileName
);
815 HeapFree( GetProcessHeap(), 0, fileW
);
818 while (FindNextFileA( find
, &data
))
820 fileW
= strdupW( data
.cFileName
);
821 if (!fileW
) goto exit
;
823 ret
= header_from_file( fileW
, &header
);
826 HeapFree( GetProcessHeap(), 0, fileW
);
830 match
= match_profile( &recordW
, &header
);
833 char **tmp
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
834 profiles
, sizeof(char *) * (count
+ 1) );
838 len
= sizeof(char) * (lstrlenA( data
.cFileName
) + 1);
839 profiles
[count
] = HeapAlloc( GetProcessHeap(), 0, len
);
841 if (!profiles
[count
]) goto exit
;
844 TRACE( "matching profile: %s\n", debugstr_a(data
.cFileName
) );
845 lstrcpyA( profiles
[count
], data
.cFileName
);
850 HeapFree( GetProcessHeap(), 0, fileW
);
855 if (buffer
&& *size
>= totalsize
)
857 char *p
= (char *)buffer
;
859 for (i
= 0; i
< count
; i
++)
861 lstrcpyA( p
, profiles
[i
] );
862 p
+= lstrlenA( profiles
[i
] ) + 1;
869 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
874 if (number
) *number
= count
;
877 for (i
= 0; i
< count
; i
++)
878 HeapFree( GetProcessHeap(), 0, profiles
[i
] );
879 HeapFree( GetProcessHeap(), 0, profiles
);
880 HeapFree( GetProcessHeap(), 0, deviceW
);
881 HeapFree( GetProcessHeap(), 0, fileW
);
887 /******************************************************************************
888 * EnumColorProfilesW [MSCMS.@]
890 * Enumerate profiles that match given criteria.
893 * machine [I] Name of the machine for which to enumerate profiles.
894 * Must be NULL, which indicates the local machine.
895 * record [I] Record of criteria that a profile must match.
896 * buffer [O] Buffer to receive a string array of profile filenames.
897 * size [I/O] Size of the filename buffer in bytes.
898 * number [O] Number of filenames copied into buffer.
904 BOOL WINAPI
EnumColorProfilesW( PCWSTR machine
, PENUMTYPEW record
, PBYTE buffer
,
905 PDWORD size
, PDWORD number
)
907 BOOL match
, ret
= FALSE
;
908 WCHAR colordir
[MAX_PATH
], glob
[MAX_PATH
], **profiles
= NULL
;
909 DWORD i
, len
= sizeof(colordir
), count
= 0, totalsize
= 0;
910 PROFILEHEADER header
;
911 WIN32_FIND_DATAW data
;
914 TRACE( "( %p, %p, %p, %p, %p )\n", machine
, record
, buffer
, size
, number
);
916 if (machine
|| !record
|| !size
||
917 record
->dwSize
!= sizeof(ENUMTYPEW
) ||
918 record
->dwVersion
!= ENUM_TYPE_VERSION
) return FALSE
;
920 ret
= GetColorDirectoryW( machine
, colordir
, &len
);
921 if (!ret
|| len
+ ARRAY_SIZE(L
"\\*icm") > MAX_PATH
)
923 WARN( "Can't retrieve color directory\n" );
927 lstrcpyW( glob
, colordir
);
928 lstrcatW( glob
, L
"\\*icm" );
930 find
= FindFirstFileW( glob
, &data
);
931 if (find
== INVALID_HANDLE_VALUE
) return FALSE
;
933 profiles
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WCHAR
*) + 1 );
934 if (!profiles
) goto exit
;
936 ret
= header_from_file( data
.cFileName
, &header
);
939 match
= match_profile( record
, &header
);
942 len
= sizeof(WCHAR
) * (lstrlenW( data
.cFileName
) + 1);
943 profiles
[count
] = HeapAlloc( GetProcessHeap(), 0, len
);
945 if (!profiles
[count
]) goto exit
;
948 TRACE( "matching profile: %s\n", debugstr_w(data
.cFileName
) );
949 lstrcpyW( profiles
[count
], data
.cFileName
);
956 while (FindNextFileW( find
, &data
))
958 ret
= header_from_file( data
.cFileName
, &header
);
961 match
= match_profile( record
, &header
);
964 WCHAR
**tmp
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
965 profiles
, sizeof(WCHAR
*) * (count
+ 1) );
969 len
= sizeof(WCHAR
) * (lstrlenW( data
.cFileName
) + 1);
970 profiles
[count
] = HeapAlloc( GetProcessHeap(), 0, len
);
972 if (!profiles
[count
]) goto exit
;
975 TRACE( "matching profile: %s\n", debugstr_w(data
.cFileName
) );
976 lstrcpyW( profiles
[count
], data
.cFileName
);
984 if (buffer
&& *size
>= totalsize
)
986 WCHAR
*p
= (WCHAR
*)buffer
;
988 for (i
= 0; i
< count
; i
++)
990 lstrcpyW( p
, profiles
[i
] );
991 p
+= lstrlenW( profiles
[i
] ) + 1;
998 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1003 if (number
) *number
= count
;
1006 for (i
= 0; i
< count
; i
++)
1007 HeapFree( GetProcessHeap(), 0, profiles
[i
] );
1008 HeapFree( GetProcessHeap(), 0, profiles
);
1014 /******************************************************************************
1015 * InstallColorProfileA [MSCMS.@]
1017 * See InstallColorProfileW.
1019 BOOL WINAPI
InstallColorProfileA( PCSTR machine
, PCSTR profile
)
1025 TRACE( "( %s )\n", debugstr_a(profile
) );
1027 if (machine
|| !profile
) return FALSE
;
1029 len
= MultiByteToWideChar( CP_ACP
, 0, profile
, -1, NULL
, 0 );
1030 profileW
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
1034 MultiByteToWideChar( CP_ACP
, 0, profile
, -1, profileW
, len
);
1036 ret
= InstallColorProfileW( NULL
, profileW
);
1037 HeapFree( GetProcessHeap(), 0, profileW
);
1042 /******************************************************************************
1043 * InstallColorProfileW [MSCMS.@]
1045 * Install a color profile.
1048 * machine [I] Name of the machine to install the profile on. Must be NULL,
1049 * which indicates the local machine.
1050 * profile [I] Full path name of the profile to install.
1056 BOOL WINAPI
InstallColorProfileW( PCWSTR machine
, PCWSTR profile
)
1058 WCHAR dest
[MAX_PATH
], base
[MAX_PATH
];
1059 DWORD size
= sizeof(dest
);
1061 TRACE( "( %s )\n", debugstr_w(profile
) );
1063 if (machine
|| !profile
) return FALSE
;
1065 if (!GetColorDirectoryW( machine
, dest
, &size
)) return FALSE
;
1067 basename( profile
, base
);
1069 lstrcatW( dest
, L
"\\" );
1070 lstrcatW( dest
, base
);
1072 /* Is source equal to destination? */
1073 if (!wcscmp( profile
, dest
)) return TRUE
;
1075 return CopyFileW( profile
, dest
, TRUE
);
1078 /******************************************************************************
1079 * IsColorProfileTagPresent [MSCMS.@]
1081 * Determine if a given ICC tag type is present in a color profile.
1084 * profile [I] Color profile handle.
1085 * tag [I] ICC tag type.
1086 * present [O] Pointer to a BOOL variable. Set to TRUE if tag type is present,
1093 BOOL WINAPI
IsColorProfileTagPresent( HPROFILE handle
, TAGTYPE type
, PBOOL present
)
1095 struct profile
*profile
= grab_profile( handle
);
1096 struct tag_entry tag
;
1098 TRACE( "( %p, 0x%08x, %p )\n", handle
, type
, present
);
1100 if (!profile
) return FALSE
;
1104 release_profile( profile
);
1107 *present
= get_adjusted_tag( profile
, type
, &tag
);
1108 release_profile( profile
);
1112 /******************************************************************************
1113 * IsColorProfileValid [MSCMS.@]
1115 * Determine if a given color profile is valid.
1118 * profile [I] Color profile handle.
1119 * valid [O] Pointer to a BOOL variable. Set to TRUE if profile is valid,
1126 BOOL WINAPI
IsColorProfileValid( HPROFILE handle
, PBOOL valid
)
1129 struct profile
*profile
= grab_profile( handle
);
1131 TRACE( "( %p, %p )\n", handle
, valid
);
1133 if (!profile
) return FALSE
;
1137 release_profile( profile
);
1140 if (profile
->data
) ret
= *valid
= TRUE
;
1141 release_profile( profile
);
1145 /******************************************************************************
1146 * SetColorProfileElement [MSCMS.@]
1148 * Set data for a specified tag type.
1151 * profile [I] Handle to a color profile.
1152 * type [I] ICC tag type.
1153 * offset [I] Offset in bytes to start copying to.
1154 * size [I/O] Size of the buffer in bytes. On return the variable holds the
1155 * number of bytes actually needed.
1156 * buffer [O] Buffer holding the tag data.
1162 BOOL WINAPI
SetColorProfileElement( HPROFILE handle
, TAGTYPE type
, DWORD offset
, PDWORD size
,
1166 struct profile
*profile
= grab_profile( handle
);
1168 TRACE( "( %p, 0x%08x, %d, %p, %p )\n", handle
, type
, offset
, size
, buffer
);
1170 if (!profile
) return FALSE
;
1172 if (!size
|| !buffer
|| !(profile
->access
& PROFILE_READWRITE
))
1174 release_profile( profile
);
1177 ret
= set_tag_data( profile
, type
, offset
, buffer
, size
);
1178 release_profile( profile
);
1182 /******************************************************************************
1183 * SetColorProfileHeader [MSCMS.@]
1185 * Set header data for a given profile.
1188 * profile [I] Handle to a color profile.
1189 * header [I] Buffer holding the header data.
1195 BOOL WINAPI
SetColorProfileHeader( HPROFILE handle
, PPROFILEHEADER header
)
1197 struct profile
*profile
= grab_profile( handle
);
1199 TRACE( "( %p, %p )\n", handle
, header
);
1201 if (!profile
) return FALSE
;
1203 if (!header
|| !(profile
->access
& PROFILE_READWRITE
))
1205 release_profile( profile
);
1208 set_profile_header( profile
, header
);
1209 release_profile( profile
);
1213 /******************************************************************************
1214 * UninstallColorProfileA [MSCMS.@]
1216 * See UninstallColorProfileW.
1218 BOOL WINAPI
UninstallColorProfileA( PCSTR machine
, PCSTR profile
, BOOL
delete )
1224 TRACE( "( %s, %x )\n", debugstr_a(profile
), delete );
1226 if (machine
|| !profile
) return FALSE
;
1228 len
= MultiByteToWideChar( CP_ACP
, 0, profile
, -1, NULL
, 0 );
1229 profileW
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
1233 MultiByteToWideChar( CP_ACP
, 0, profile
, -1, profileW
, len
);
1235 ret
= UninstallColorProfileW( NULL
, profileW
, delete );
1237 HeapFree( GetProcessHeap(), 0, profileW
);
1242 /******************************************************************************
1243 * UninstallColorProfileW [MSCMS.@]
1245 * Uninstall a color profile.
1248 * machine [I] Name of the machine to uninstall the profile on. Must be NULL,
1249 * which indicates the local machine.
1250 * profile [I] Full path name of the profile to uninstall.
1251 * delete [I] Bool that specifies whether the profile file should be deleted.
1257 BOOL WINAPI
UninstallColorProfileW( PCWSTR machine
, PCWSTR profile
, BOOL
delete )
1259 TRACE( "( %s, %x )\n", debugstr_w(profile
), delete );
1261 if (machine
|| !profile
) return FALSE
;
1263 if (delete) return DeleteFileW( profile
);
1268 static BOOL
profile_AtoW( const PROFILE
*in
, PROFILE
*out
)
1271 if (!in
->pProfileData
) return FALSE
;
1272 len
= MultiByteToWideChar( CP_ACP
, 0, in
->pProfileData
, -1, NULL
, 0 );
1273 if (!(out
->pProfileData
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) ))) return FALSE
;
1274 out
->cbDataSize
= len
* sizeof(WCHAR
);
1275 MultiByteToWideChar( CP_ACP
, 0, in
->pProfileData
, -1, out
->pProfileData
, len
);
1276 out
->dwType
= in
->dwType
;
1280 /******************************************************************************
1281 * OpenColorProfileA [MSCMS.@]
1283 * See OpenColorProfileW.
1285 HPROFILE WINAPI
OpenColorProfileA( PPROFILE profile
, DWORD access
, DWORD sharing
, DWORD creation
)
1287 HPROFILE handle
= NULL
;
1290 TRACE( "( %p, 0x%08x, 0x%08x, 0x%08x )\n", profile
, access
, sharing
, creation
);
1292 if (!profile
|| !profile
->pProfileData
) return NULL
;
1294 /* No AW conversion needed for memory based profiles */
1295 if (profile
->dwType
& PROFILE_MEMBUFFER
)
1296 return OpenColorProfileW( profile
, access
, sharing
, creation
);
1298 if (!profile_AtoW( profile
, &profileW
)) return FALSE
;
1299 handle
= OpenColorProfileW( &profileW
, access
, sharing
, creation
);
1300 HeapFree( GetProcessHeap(), 0, profileW
.pProfileData
);
1304 /******************************************************************************
1305 * OpenColorProfileW [MSCMS.@]
1307 * Open a color profile.
1310 * profile [I] Pointer to a color profile structure.
1311 * access [I] Desired access.
1312 * sharing [I] Sharing mode.
1313 * creation [I] Creation mode.
1316 * Success: Handle to the opened profile.
1320 * Values for access: PROFILE_READ or PROFILE_READWRITE.
1321 * Values for sharing: 0 (no sharing), FILE_SHARE_READ and/or FILE_SHARE_WRITE.
1322 * Values for creation: one of CREATE_NEW, CREATE_ALWAYS, OPEN_EXISTING,
1323 * OPEN_ALWAYS, TRUNCATE_EXISTING.
1324 * Sharing and creation flags are ignored for memory based profiles.
1326 HPROFILE WINAPI
OpenColorProfileW( PPROFILE profile
, DWORD access
, DWORD sharing
, DWORD creation
)
1328 struct profile prof
;
1330 void *cmsprofile
= NULL
;
1332 HANDLE handle
= INVALID_HANDLE_VALUE
;
1335 TRACE( "( %p, 0x%08x, 0x%08x, 0x%08x )\n", profile
, access
, sharing
, creation
);
1337 if (!profile
|| !profile
->pProfileData
) return NULL
;
1339 if (profile
->dwType
== PROFILE_MEMBUFFER
)
1341 /* FIXME: access flags not implemented for memory based profiles */
1343 if (!(data
= HeapAlloc( GetProcessHeap(), 0, profile
->cbDataSize
))) return NULL
;
1344 memcpy( data
, profile
->pProfileData
, profile
->cbDataSize
);
1346 if (lcms_funcs
&& !(cmsprofile
= lcms_funcs
->open_profile( data
, profile
->cbDataSize
)))
1348 HeapFree( GetProcessHeap(), 0, data
);
1351 size
= profile
->cbDataSize
;
1353 else if (profile
->dwType
== PROFILE_FILENAME
)
1355 DWORD read
, flags
= 0;
1357 TRACE( "profile file: %s\n", debugstr_w( profile
->pProfileData
) );
1359 if (access
& PROFILE_READ
) flags
= GENERIC_READ
;
1360 if (access
& PROFILE_READWRITE
) flags
= GENERIC_READ
|GENERIC_WRITE
;
1362 if (!flags
) return NULL
;
1363 if (!sharing
) sharing
= FILE_SHARE_READ
;
1365 if (!PathIsRelativeW( profile
->pProfileData
))
1366 handle
= CreateFileW( profile
->pProfileData
, flags
, sharing
, NULL
, creation
, 0, NULL
);
1371 if (!GetColorDirectoryW( NULL
, NULL
, &size
) && GetLastError() == ERROR_MORE_DATA
)
1373 size
+= (lstrlenW( profile
->pProfileData
) + 2) * sizeof(WCHAR
);
1374 if (!(path
= HeapAlloc( GetProcessHeap(), 0, size
))) return NULL
;
1375 GetColorDirectoryW( NULL
, path
, &size
);
1376 PathAddBackslashW( path
);
1377 lstrcatW( path
, profile
->pProfileData
);
1380 handle
= CreateFileW( path
, flags
, sharing
, NULL
, creation
, 0, NULL
);
1381 HeapFree( GetProcessHeap(), 0, path
);
1383 if (handle
== INVALID_HANDLE_VALUE
)
1385 WARN( "Unable to open color profile %u\n", GetLastError() );
1388 if ((size
= GetFileSize( handle
, NULL
)) == INVALID_FILE_SIZE
)
1390 ERR( "Unable to retrieve size of color profile\n" );
1391 CloseHandle( handle
);
1394 if (!(data
= HeapAlloc( GetProcessHeap(), 0, size
)))
1396 ERR( "Unable to allocate memory for color profile\n" );
1397 CloseHandle( handle
);
1400 if (!ReadFile( handle
, data
, size
, &read
, NULL
) || read
!= size
)
1402 ERR( "Unable to read color profile\n" );
1404 CloseHandle( handle
);
1405 HeapFree( GetProcessHeap(), 0, data
);
1408 if (lcms_funcs
&& !(cmsprofile
= lcms_funcs
->open_profile( data
, size
)))
1410 CloseHandle( handle
);
1411 HeapFree( GetProcessHeap(), 0, data
);
1417 ERR( "Invalid profile type %u\n", profile
->dwType
);
1422 prof
.access
= access
;
1425 prof
.cmsprofile
= cmsprofile
;
1427 if ((hprof
= create_profile( &prof
))) return hprof
;
1429 if (cmsprofile
) lcms_funcs
->close_profile( cmsprofile
);
1430 HeapFree( GetProcessHeap(), 0, data
);
1431 CloseHandle( handle
);
1435 /******************************************************************************
1436 * CloseColorProfile [MSCMS.@]
1438 * Close a color profile.
1441 * profile [I] Handle to the profile.
1447 BOOL WINAPI
CloseColorProfile( HPROFILE profile
)
1449 TRACE( "( %p )\n", profile
);
1450 return close_profile( profile
);
1453 /******************************************************************************
1454 * WcsGetUsePerUserProfiles [MSCMS.@]
1456 BOOL WINAPI
WcsGetUsePerUserProfiles( const WCHAR
* name
, DWORD
class, BOOL
* use_per_user_profile
)
1458 FIXME( "%s %s %p\n", debugstr_w(name
), dbgstr_tag(class), use_per_user_profile
);
1459 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
1463 /******************************************************************************
1464 * WcsEnumColorProfilesSize [MSCMS.@]
1466 BOOL WINAPI
WcsEnumColorProfilesSize( WCS_PROFILE_MANAGEMENT_SCOPE scope
, ENUMTYPEW
*record
, DWORD
*size
)
1468 FIXME( "%d %p %p\n", scope
, record
, size
);
1469 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
1473 /******************************************************************************
1474 * WcsGetDefaultColorProfileSize [MSCMS.@]
1476 BOOL WINAPI
WcsGetDefaultColorProfileSize( WCS_PROFILE_MANAGEMENT_SCOPE scope
, PCWSTR device_name
,
1477 COLORPROFILETYPE type
, COLORPROFILESUBTYPE subtype
,
1478 DWORD profile_id
, PDWORD profile_size
)
1480 FIXME( "%d %s %d %d %d %p\n", scope
, debugstr_w(device_name
), type
, subtype
, profile_id
, profile_size
);
1481 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
1485 /******************************************************************************
1486 * WcsGetDefaultRednderingIntent [MSCMS.@]
1488 BOOL WINAPI
WcsGetDefaultRenderingIntent( WCS_PROFILE_MANAGEMENT_SCOPE scope
, PDWORD intent
)
1490 FIXME( "%d %p\n", scope
, intent
);
1491 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
1495 /******************************************************************************
1496 * WcsOpenColorProfileA [MSCMS.@]
1498 HPROFILE WINAPI
WcsOpenColorProfileA( PROFILE
*cdm
, PROFILE
*camp
, PROFILE
*gmmp
, DWORD access
, DWORD sharing
,
1499 DWORD creation
, DWORD flags
)
1501 PROFILE cdmW
, campW
= {0}, gmmpW
= {0};
1502 HPROFILE ret
= NULL
;
1504 TRACE( "%p, %p, %p, %08x, %08x, %08x, %08x\n", cdm
, camp
, gmmp
, access
, sharing
, creation
, flags
);
1506 if (!cdm
|| !profile_AtoW( cdm
, &cdmW
)) return NULL
;
1507 if (camp
&& !profile_AtoW( camp
, &campW
)) goto done
;
1508 if (gmmp
&& !profile_AtoW( gmmp
, &gmmpW
)) goto done
;
1510 ret
= WcsOpenColorProfileW( &cdmW
, &campW
, &gmmpW
, access
, sharing
, creation
, flags
);
1513 HeapFree( GetProcessHeap(), 0, cdmW
.pProfileData
);
1514 HeapFree( GetProcessHeap(), 0, campW
.pProfileData
);
1515 HeapFree( GetProcessHeap(), 0, gmmpW
.pProfileData
);
1519 /******************************************************************************
1520 * WcsOpenColorProfileW [MSCMS.@]
1522 HPROFILE WINAPI
WcsOpenColorProfileW( PROFILE
*cdm
, PROFILE
*camp
, PROFILE
*gmmp
, DWORD access
, DWORD sharing
,
1523 DWORD creation
, DWORD flags
)
1525 TRACE( "%p, %p, %p, %08x, %08x, %08x, %08x\n", cdm
, camp
, gmmp
, access
, sharing
, creation
, flags
);
1526 FIXME("no support for WCS profiles\n" );
1528 return OpenColorProfileW( cdm
, access
, sharing
, creation
);