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