Fixes for -Wmissing-declaration and -Wwrite-string warnings.
[wine] / dlls / mscms / profile.c
1 /*
2  * MSCMS - Color Management System for Wine
3  *
4  * Copyright 2004, 2005 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22 #include "wine/debug.h"
23
24 #include <stdarg.h>
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winnls.h"
29 #include "wingdi.h"
30 #include "winuser.h"
31 #include "icm.h"
32
33 #define LCMS_API_FUNCTION(f) extern typeof(f) * p##f;
34 #include "lcms_api.h"
35 #undef LCMS_API_FUNCTION
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 /* FIXME: Get this directory from the registry? */
48 static const WCHAR colorsubdir[] = { '\\','s','y','s','t','e','m','3','2',
49     '\\','s','p','o','o','l','\\','d','r','i','v','e','r','s',
50     '\\','c','o','l','o','r',0 };
51
52 WINE_DEFAULT_DEBUG_CHANNEL(mscms);
53
54 /******************************************************************************
55  * GetColorDirectoryA               [MSCMS.@]
56  *
57  * See GetColorDirectoryW.
58  */
59 BOOL WINAPI GetColorDirectoryA( PCSTR machine, PSTR buffer, PDWORD size )
60 {
61     INT len;
62     LPWSTR bufferW;
63     BOOL ret = FALSE;
64     DWORD sizeW;
65
66     TRACE( "( %p, %p )\n", buffer, size );
67
68     if (machine || !size) return FALSE;
69
70     if (!buffer)
71     {
72         ret = GetColorDirectoryW( NULL, NULL, &sizeW );
73         *size = sizeW / sizeof(WCHAR);
74         return FALSE;
75     }
76
77     sizeW = *size * sizeof(WCHAR);
78
79     bufferW = HeapAlloc( GetProcessHeap(), 0, sizeW );
80
81     if (bufferW)
82     {
83         ret = GetColorDirectoryW( NULL, bufferW, &sizeW );
84         *size = WideCharToMultiByte( CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL );
85
86         if (ret)
87         {
88             len = WideCharToMultiByte( CP_ACP, 0, bufferW, *size, buffer, *size, NULL, NULL );
89             if (!len) ret = FALSE;
90         }
91
92         HeapFree( GetProcessHeap(), 0, bufferW );
93     }
94     return ret;
95 }
96
97 /******************************************************************************
98  * GetColorDirectoryW               [MSCMS.@]
99  *
100  * Get the directory where color profiles are stored.
101  *
102  * PARAMS
103  *  machine  [I]   Name of the machine for which to get the color directory.
104  *                 Must be NULL, which indicates the local machine.
105  *  buffer   [I]   Buffer to receive the path name.
106  *  size     [I/O] Size of the buffer in bytes. On return the variable holds
107  *                 the number of bytes actually needed.
108  */
109 BOOL WINAPI GetColorDirectoryW( PCWSTR machine, PWSTR buffer, PDWORD size )
110 {
111     WCHAR colordir[MAX_PATH];
112     DWORD len;
113
114     TRACE( "( %p, %p )\n", buffer, size );
115
116     if (machine || !size) return FALSE;
117
118     GetWindowsDirectoryW( colordir, sizeof(colordir) / sizeof(WCHAR) );
119     lstrcatW( colordir, colorsubdir );
120
121     len = lstrlenW( colordir ) * sizeof(WCHAR);
122
123     if (len <= *size && buffer)
124     {
125         lstrcpyW( buffer, colordir );
126         *size = len;
127         return TRUE;
128     }
129
130     *size = len;
131     return FALSE;
132 }
133
134 /******************************************************************************
135  * GetColorProfileElement               [MSCMS.@]
136  *
137  * Retrieve data for a specified tag type.
138  *
139  * PARAMS
140  *  profile  [I]   Handle to a color profile.
141  *  type     [I]   ICC tag type. 
142  *  offset   [I]   Offset in bytes to start copying from. 
143  *  size     [I/O] Size of the buffer in bytes. On return the variable holds
144  *                 the number of bytes actually needed.
145  *  buffer   [O]   Buffer to receive the tag data.
146  *  ref      [O]   Pointer to a BOOL that specifies whether more than one tag
147  *                 references the data.
148  *
149  * RETURNS
150  *  Success: TRUE
151  *  Failure: FALSE
152  */
153 BOOL WINAPI GetColorProfileElement( HPROFILE profile, TAGTYPE type, DWORD offset, PDWORD size,
154                                     PVOID buffer, PBOOL ref )
155 {
156     BOOL ret = FALSE;
157 #ifdef HAVE_LCMS_H
158     icProfile *iccprofile = MSCMS_hprofile2iccprofile( profile );
159     DWORD i, count;
160     icTag tag;
161
162     TRACE( "( %p, 0x%08lx, %ld, %p, %p, %p )\n", profile, type, offset, size, buffer, ref );
163
164     if (!iccprofile || !size || !ref) return FALSE;
165     count = MSCMS_get_tag_count( iccprofile );
166
167     for (i = 0; i < count; i++)
168     {
169         MSCMS_get_tag_by_index( iccprofile, i, &tag );
170
171         if (tag.sig == type)
172         {
173             if ((tag.size - offset) > *size || !buffer)
174             {
175                 *size = (tag.size - offset);
176                 return FALSE;
177             }
178
179             MSCMS_get_tag_data( iccprofile, &tag, offset, buffer );
180
181             *ref = FALSE; /* FIXME: calculate properly */
182             return TRUE;
183         }
184     }
185
186 #endif /* HAVE_LCMS_H */
187     return ret;
188 }
189
190 /******************************************************************************
191  * GetColorProfileElementTag               [MSCMS.@]
192  *
193  * Get the tag type from a color profile by index. 
194  *
195  * PARAMS
196  *  profile  [I]   Handle to a color profile.
197  *  index    [I]   Index into the tag table of the color profile.
198  *  type     [O]   Pointer to a variable that holds the ICC tag type on return.
199  *
200  * RETURNS
201  *  Success: TRUE
202  *  Failure: FALSE
203  *
204  * NOTES
205  *  The tag table index starts at 1.
206  *  Use GetCountColorProfileElements to retrieve a count of tagged elements.
207  */
208 BOOL WINAPI GetColorProfileElementTag( HPROFILE profile, DWORD index, PTAGTYPE type )
209 {
210     BOOL ret = FALSE;
211 #ifdef HAVE_LCMS_H
212     icProfile *iccprofile = MSCMS_hprofile2iccprofile( profile );
213     DWORD count;
214     icTag tag;
215
216     TRACE( "( %p, %ld, %p )\n", profile, index, type );
217
218     if (!iccprofile || !type) return FALSE;
219
220     count = MSCMS_get_tag_count( iccprofile );
221     if (index > count || index < 1) return FALSE;
222
223     MSCMS_get_tag_by_index( iccprofile, index - 1, &tag );
224     *type = tag.sig;
225
226     ret = TRUE;
227
228 #endif /* HAVE_LCMS_H */
229     return ret;
230 }
231
232 /******************************************************************************
233  * GetColorProfileFromHandle               [MSCMS.@]
234  *
235  * Retrieve an ICC color profile by handle.
236  *
237  * PARAMS
238  *  profile  [I]   Handle to a color profile.
239  *  buffer   [O]   Buffer to receive the ICC profile.
240  *  size     [I/O] Size of the buffer in bytes. On return the variable holds the
241  *                 number of bytes actually needed.
242  *
243  * RETURNS
244  *  Success: TRUE
245  *  Failure: FALSE
246  *
247  * NOTES
248  *  The profile returned will be in big-endian format.
249  */
250 BOOL WINAPI GetColorProfileFromHandle( HPROFILE profile, PBYTE buffer, PDWORD size )
251 {
252     BOOL ret = FALSE;
253 #ifdef HAVE_LCMS_H
254     icProfile *iccprofile = MSCMS_hprofile2iccprofile( profile );
255     PROFILEHEADER header;
256
257     TRACE( "( %p, %p, %p )\n", profile, buffer, size );
258
259     if (!iccprofile || !size) return FALSE;
260     MSCMS_get_profile_header( iccprofile, &header );
261
262     if (!buffer || header.phSize > *size)
263     {
264         *size = header.phSize;
265         return FALSE;
266     }
267
268     /* No endian conversion needed */
269     memcpy( buffer, iccprofile, header.phSize );
270
271     *size = header.phSize;
272     ret = TRUE;
273
274 #endif /* HAVE_LCMS_H */
275     return ret;
276 }
277
278 /******************************************************************************
279  * GetColorProfileHeader               [MSCMS.@]
280  *
281  * Retrieve a color profile header by handle.
282  *
283  * PARAMS
284  *  profile  [I]   Handle to a color profile.
285  *  header   [O]   Buffer to receive the ICC profile header.
286  *
287  * RETURNS
288  *  Success: TRUE
289  *  Failure: FALSE
290  *
291  * NOTES
292  *  The profile header returned will be adjusted for endianess.
293  */
294 BOOL WINAPI GetColorProfileHeader( HPROFILE profile, PPROFILEHEADER header )
295 {
296     BOOL ret = FALSE;
297 #ifdef HAVE_LCMS_H
298     icProfile *iccprofile = MSCMS_hprofile2iccprofile( profile );
299
300     TRACE( "( %p, %p )\n", profile, header );
301
302     if (!iccprofile || !header) return FALSE;
303
304     MSCMS_get_profile_header( iccprofile, header );
305     return TRUE;
306
307 #endif /* HAVE_LCMS_H */
308     return ret;
309 }
310
311 /******************************************************************************
312  * GetCountColorProfileElements               [MSCMS.@]
313  *
314  * Retrieve the number of elements in a color profile.
315  *
316  * PARAMS
317  *  profile  [I] Handle to a color profile.
318  *  count    [O] Pointer to a variable which is set to the number of elements
319  *               in the color profile.
320  *
321  * RETURNS
322  *  Success: TRUE
323  *  Failure: FALSE
324  */
325 BOOL WINAPI GetCountColorProfileElements( HPROFILE profile, PDWORD count )
326 {
327     BOOL ret = FALSE;
328 #ifdef HAVE_LCMS_H
329     icProfile *iccprofile = MSCMS_hprofile2iccprofile( profile );
330
331     TRACE( "( %p, %p )\n", profile, count );
332
333     if (!iccprofile || !count) return FALSE;
334     *count = MSCMS_get_tag_count( iccprofile );
335     ret = TRUE;
336
337 #endif /* HAVE_LCMS_H */
338     return ret;
339 }
340
341 /******************************************************************************
342  * GetStandardColorSpaceProfileA               [MSCMS.@]
343  *
344  * See GetStandardColorSpaceProfileW.
345  */
346 BOOL WINAPI GetStandardColorSpaceProfileA( PCSTR machine, DWORD id, PSTR profile, PDWORD size )
347 {
348     INT len;
349     LPWSTR profileW;
350     BOOL ret = FALSE;
351     DWORD sizeW;
352
353     TRACE( "( 0x%08lx, %p, %p )\n", id, profile, size );
354
355     if (machine || !size) return FALSE;
356
357     sizeW = *size * sizeof(WCHAR);
358
359     if (!profile)
360     {
361         ret = GetStandardColorSpaceProfileW( NULL, id, NULL, &sizeW );
362         *size = sizeW / sizeof(WCHAR);
363         return FALSE;
364     }
365
366     profileW = HeapAlloc( GetProcessHeap(), 0, sizeW );
367
368     if (profileW)
369     {
370         ret = GetStandardColorSpaceProfileW( NULL, id, profileW, &sizeW );
371         *size = WideCharToMultiByte( CP_ACP, 0, profileW, -1, NULL, 0, NULL, NULL );
372
373         if (ret)
374         {
375             len = WideCharToMultiByte( CP_ACP, 0, profileW, *size, profile, *size, NULL, NULL );
376             if (!len) ret = FALSE;
377         }
378
379         HeapFree( GetProcessHeap(), 0, profileW );
380     }
381     return ret;
382 }
383
384 /******************************************************************************
385  * GetStandardColorSpaceProfileW               [MSCMS.@]
386  *
387  * Retrieve the profile filename for a given standard color space id.
388  *
389  * PARAMS
390  *  machine  [I]   Name of the machine for which to get the standard color space.
391  *                 Must be NULL, which indicates the local machine.
392  *  id       [I]   Id of a standard color space.
393  *  profile  [O]   Buffer to receive the profile filename.
394  *  size     [I/O] Size of the filename buffer in bytes.
395  *
396  * RETURNS
397  *  Success: TRUE
398  *  Failure: FALSE
399  */
400 BOOL WINAPI GetStandardColorSpaceProfileW( PCWSTR machine, DWORD id, PWSTR profile, PDWORD size )
401 {
402     static const WCHAR rgbprofilefile[] = { '\\','s','r','g','b',' ','c','o','l','o','r',' ',
403       's','p','a','c','e',' ','p','r','o','f','i','l','e','.','i','c','m',0 };
404     WCHAR rgbprofile[MAX_PATH];
405     DWORD len;
406
407     TRACE( "( 0x%08lx, %p, %p )\n", id, profile, size );
408
409     if (machine || !size) return FALSE;
410
411     switch (id)
412     {
413         case 0x52474220: /* 'RGB ' */
414             GetWindowsDirectoryW( rgbprofile, sizeof( rgbprofile ) / sizeof( WCHAR ) );
415             lstrcatW( rgbprofile, colorsubdir );
416             lstrcatW( rgbprofile, rgbprofilefile );
417
418             len = lstrlenW( rgbprofile ) * sizeof( WCHAR );
419
420             if (*size < len || !profile)
421             {
422                 *size = len;
423                 return TRUE;
424             }
425
426             lstrcpyW( profile, rgbprofile );
427             break;
428
429         default:
430             return FALSE;
431     }
432
433     return TRUE;
434 }
435
436 /******************************************************************************
437  * InstallColorProfileA               [MSCMS.@]
438  *
439  * See InstallColorProfileW.
440  */
441 BOOL WINAPI InstallColorProfileA( PCSTR machine, PCSTR profile )
442 {
443     UINT len;
444     LPWSTR profileW;
445     BOOL ret = FALSE;
446
447     TRACE( "( %s )\n", debugstr_a(profile) );
448
449     if (machine || !profile) return FALSE;
450
451     len = MultiByteToWideChar( CP_ACP, 0, profile, -1, NULL, 0 );
452     profileW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
453
454     if (profileW)
455     {
456         MultiByteToWideChar( CP_ACP, 0, profile, -1, profileW, len );
457
458         ret = InstallColorProfileW( NULL, profileW );
459         HeapFree( GetProcessHeap(), 0, profileW );
460     }
461     return ret;
462 }
463
464 /******************************************************************************
465  * InstallColorProfileW               [MSCMS.@]
466  *
467  * Install a color profile.
468  *
469  * PARAMS
470  *  machine  [I] Name of the machine to install the profile on. Must be NULL,
471  *               which indicates the local machine.
472  *  profile  [I] Full path name of the profile to install.
473  *
474  * RETURNS
475  *  Success: TRUE
476  *  Failure: FALSE
477  */
478 BOOL WINAPI InstallColorProfileW( PCWSTR machine, PCWSTR profile )
479 {
480     WCHAR dest[MAX_PATH], base[MAX_PATH];
481     DWORD size = sizeof(dest);
482     static const WCHAR slash[] = { '\\', 0 };
483
484     TRACE( "( %s )\n", debugstr_w(profile) );
485
486     if (machine || !profile) return FALSE;
487
488     if (!GetColorDirectoryW( machine, dest, &size )) return FALSE;
489
490     MSCMS_basename( profile, base );
491
492     lstrcatW( dest, slash );
493     lstrcatW( dest, base );
494
495     /* Is source equal to destination? */
496     if (!lstrcmpW( profile, dest )) return TRUE;
497
498     return CopyFileW( profile, dest, TRUE );
499 }
500
501 /******************************************************************************
502  * IsColorProfileTagPresent               [MSCMS.@]
503  *
504  * Determine if a given ICC tag type is present in a color profile.
505  *
506  * PARAMS
507  *  profile  [I] Color profile handle.
508  *  tag      [I] ICC tag type.
509  *  present  [O] Pointer to a BOOL variable. Set to TRUE if tag type is present,
510  *               FALSE otherwise.
511  *
512  * RETURNS
513  *  Success: TRUE
514  *  Failure: FALSE
515  */
516 BOOL WINAPI IsColorProfileTagPresent( HPROFILE profile, TAGTYPE type, PBOOL present )
517 {
518     BOOL ret = FALSE;
519 #ifdef HAVE_LCMS_H
520     icProfile *iccprofile = MSCMS_hprofile2iccprofile( profile );
521     DWORD i, count;
522     icTag tag;
523
524     TRACE( "( %p, 0x%08lx, %p )\n", profile, type, present );
525
526     if (!iccprofile || !present) return FALSE;
527
528     count = MSCMS_get_tag_count( iccprofile );
529
530     for (i = 0; i < count; i++)
531     {
532         MSCMS_get_tag_by_index( iccprofile, i, &tag );
533
534         if (tag.sig == type)
535         {
536             *present = ret = TRUE;
537             break;
538         }
539     }
540
541 #endif /* HAVE_LCMS_H */
542     return ret;
543 }
544
545 /******************************************************************************
546  * IsColorProfileValid               [MSCMS.@]
547  *
548  * Determine if a given color profile is valid.
549  *
550  * PARAMS
551  *  profile  [I] Color profile handle.
552  *  valid    [O] Pointer to a BOOL variable. Set to TRUE if profile is valid,
553  *               FALSE otherwise.
554  *
555  * RETURNS
556  *  Success: TRUE
557  *  Failure: FALSE 
558  */
559 BOOL WINAPI IsColorProfileValid( HPROFILE profile, PBOOL valid )
560 {
561     BOOL ret = FALSE;
562 #ifdef HAVE_LCMS_H
563     icProfile *iccprofile = MSCMS_hprofile2iccprofile( profile );
564
565     TRACE( "( %p, %p )\n", profile, valid );
566
567     if (!valid) return FALSE;
568     if (iccprofile) return *valid = TRUE;
569
570 #endif /* HAVE_LCMS_H */
571     return ret;
572 }
573
574 /******************************************************************************
575  * SetColorProfileElement               [MSCMS.@]
576  *
577  * Set data for a specified tag type.
578  *
579  * PARAMS
580  *  profile  [I]   Handle to a color profile.
581  *  type     [I]   ICC tag type.
582  *  offset   [I]   Offset in bytes to start copying to.
583  *  size     [I/O] Size of the buffer in bytes. On return the variable holds the
584  *                 number of bytes actually needed.
585  *  buffer   [O]   Buffer holding the tag data.
586  *
587  * RETURNS
588  *  Success: TRUE
589  *  Failure: FALSE
590  */
591 BOOL WINAPI SetColorProfileElement( HPROFILE profile, TAGTYPE type, DWORD offset, PDWORD size,
592                                     PVOID buffer )
593 {
594     BOOL ret = FALSE;
595 #ifdef HAVE_LCMS_H
596     icProfile *iccprofile = MSCMS_hprofile2iccprofile( profile );
597     DWORD i, count, access = MSCMS_hprofile2access( profile );
598     icTag tag;
599
600     TRACE( "( %p, 0x%08lx, %ld, %p, %p )\n", profile, type, offset, size, buffer );
601
602     if (!iccprofile || !size || !buffer) return FALSE;
603     if (!(access & PROFILE_READWRITE)) return FALSE;
604
605     count = MSCMS_get_tag_count( iccprofile );
606
607     for (i = 0; i < count; i++)
608     {
609         MSCMS_get_tag_by_index( iccprofile, i, &tag );
610
611         if (tag.sig == type)
612         {
613             if (offset > tag.size) return FALSE;
614
615             MSCMS_set_tag_data( iccprofile, &tag, offset, buffer );
616             return TRUE;
617         }
618     }
619
620 #endif /* HAVE_LCMS_H */
621     return ret;
622 }
623
624 /******************************************************************************
625  * SetColorProfileHeader               [MSCMS.@]
626  *
627  * Set header data for a given profile.
628  *
629  * PARAMS
630  *  profile  [I] Handle to a color profile.
631  *  header   [I] Buffer holding the header data.
632  *
633  * RETURNS
634  *  Success: TRUE
635  *  Failure: FALSE
636  */
637 BOOL WINAPI SetColorProfileHeader( HPROFILE profile, PPROFILEHEADER header )
638 {
639     BOOL ret = FALSE;
640 #ifdef HAVE_LCMS_H
641     icProfile *iccprofile = MSCMS_hprofile2iccprofile( profile );
642     DWORD access = MSCMS_hprofile2access( profile );
643
644     TRACE( "( %p, %p )\n", profile, header );
645
646     if (!iccprofile || !header) return FALSE;
647     if (!(access & PROFILE_READWRITE)) return FALSE;
648
649     MSCMS_set_profile_header( iccprofile, header );
650     return TRUE;
651
652 #endif /* HAVE_LCMS_H */
653     return ret;
654 }
655
656 /******************************************************************************
657  * UninstallColorProfileA               [MSCMS.@]
658  *
659  * See UninstallColorProfileW.
660  */
661 BOOL WINAPI UninstallColorProfileA( PCSTR machine, PCSTR profile, BOOL delete )
662 {
663     UINT len;
664     LPWSTR profileW;
665     BOOL ret = FALSE;
666
667     TRACE( "( %s, %x )\n", debugstr_a(profile), delete );
668
669     if (machine || !profile) return FALSE;
670
671     len = MultiByteToWideChar( CP_ACP, 0, profile, -1, NULL, 0 );
672     profileW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
673
674     if (profileW)
675     {
676         MultiByteToWideChar( CP_ACP, 0, profile, -1, profileW, len );
677
678         ret = UninstallColorProfileW( NULL, profileW , delete );
679
680         HeapFree( GetProcessHeap(), 0, profileW );
681     }
682     return ret;
683 }
684
685 /******************************************************************************
686  * UninstallColorProfileW               [MSCMS.@]
687  *
688  * Uninstall a color profile.
689  *
690  * PARAMS
691  *  machine  [I] Name of the machine to uninstall the profile on. Must be NULL,
692  *               which indicates the local machine.
693  *  profile  [I] Full path name of the profile to uninstall.
694  *  delete   [I] Bool that specifies whether the profile file should be deleted.
695  *
696  * RETURNS
697  *  Success: TRUE
698  *  Failure: FALSE
699  */
700 BOOL WINAPI UninstallColorProfileW( PCWSTR machine, PCWSTR profile, BOOL delete )
701 {
702     TRACE( "( %s, %x )\n", debugstr_w(profile), delete );
703
704     if (machine || !profile) return FALSE;
705
706     if (delete) return DeleteFileW( profile );
707
708     return TRUE;
709 }
710
711 /******************************************************************************
712  * OpenColorProfileA               [MSCMS.@]
713  *
714  * See OpenColorProfileW.
715  */
716 HPROFILE WINAPI OpenColorProfileA( PPROFILE profile, DWORD access, DWORD sharing, DWORD creation )
717 {
718     HPROFILE handle = NULL;
719
720     TRACE( "( %p, 0x%08lx, 0x%08lx, 0x%08lx )\n", profile, access, sharing, creation );
721
722     if (!profile || !profile->pProfileData) return NULL;
723
724     /* No AW conversion needed for memory based profiles */
725     if (profile->dwType & PROFILE_MEMBUFFER)
726         return OpenColorProfileW( profile, access, sharing, creation );
727
728     if (profile->dwType & PROFILE_FILENAME)
729     {
730         UINT len;
731         PROFILE profileW;
732
733         profileW.dwType = profile->dwType;
734  
735         len = MultiByteToWideChar( CP_ACP, 0, profile->pProfileData, -1, NULL, 0 );
736         profileW.pProfileData = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
737
738         if (profileW.pProfileData)
739         {
740             profileW.cbDataSize = len * sizeof(WCHAR);
741             MultiByteToWideChar( CP_ACP, 0, profile->pProfileData, -1, profileW.pProfileData, len );
742
743             handle = OpenColorProfileW( &profileW, access, sharing, creation );
744             HeapFree( GetProcessHeap(), 0, profileW.pProfileData );
745         }
746     }
747     return handle;
748 }
749
750 /******************************************************************************
751  * OpenColorProfileW               [MSCMS.@]
752  *
753  * Open a color profile.
754  *
755  * PARAMS
756  *  profile   [I] Pointer to a color profile structure.
757  *  access    [I] Desired access.
758  *  sharing   [I] Sharing mode.
759  *  creation  [I] Creation mode.
760  *
761  * RETURNS
762  *  Success: Handle to the opened profile.
763  *  Failure: NULL
764  *
765  * NOTES
766  *  Values for access:   PROFILE_READ or PROFILE_READWRITE.
767  *  Values for sharing:  0 (no sharing), FILE_SHARE_READ and/or FILE_SHARE_WRITE.
768  *  Values for creation: one of CREATE_NEW, CREATE_ALWAYS, OPEN_EXISTING,
769  *                       OPEN_ALWAYS, TRUNCATE_EXISTING.
770  *  Sharing and creation flags are ignored for memory based profiles.
771  */
772 HPROFILE WINAPI OpenColorProfileW( PPROFILE profile, DWORD access, DWORD sharing, DWORD creation )
773 {
774 #ifdef HAVE_LCMS_H
775     cmsHPROFILE cmsprofile = NULL;
776     icProfile *iccprofile = NULL;
777     HANDLE handle = NULL;
778     DWORD size;
779
780     TRACE( "( %p, 0x%08lx, 0x%08lx, 0x%08lx )\n", profile, access, sharing, creation );
781
782     if (!profile || !profile->pProfileData) return NULL;
783
784     if (profile->dwType & PROFILE_MEMBUFFER)
785     {
786         FIXME( "access flags not implemented for memory based profiles\n" );
787
788         iccprofile = profile->pProfileData;
789         size = profile->cbDataSize;
790     
791         cmsprofile = cmsOpenProfileFromMem( iccprofile, size );
792     }
793
794     if (profile->dwType & PROFILE_FILENAME)
795     {
796         DWORD read, flags = 0;
797
798         TRACE( "profile file: %s\n", debugstr_w( (WCHAR *)profile->pProfileData ) );
799
800         if (access & PROFILE_READ) flags = GENERIC_READ;
801         if (access & PROFILE_READWRITE) flags = GENERIC_READ|GENERIC_WRITE;
802
803         if (!flags) return NULL;
804
805         handle = CreateFileW( profile->pProfileData, flags, sharing, NULL, creation, 0, NULL );
806         if (handle == INVALID_HANDLE_VALUE)
807         {
808             WARN( "Unable to open color profile\n" );
809             return NULL;
810         }
811
812         if ((size = GetFileSize( handle, NULL )) == INVALID_FILE_SIZE)
813         {
814             ERR( "Unable to retrieve size of color profile\n" );
815             CloseHandle( handle );
816             return NULL;
817         }
818
819         iccprofile = HeapAlloc( GetProcessHeap(), 0, size );
820         if (!iccprofile)
821         {
822             ERR( "Unable to allocate memory for color profile\n" );
823             CloseHandle( handle );
824             return NULL;
825         }
826
827         if (!ReadFile( handle, iccprofile, size, &read, NULL ) || read != size)
828         {
829             ERR( "Unable to read color profile\n" );
830
831             CloseHandle( handle );
832             HeapFree( GetProcessHeap, 0, iccprofile );
833             return NULL;
834         }
835
836         cmsprofile = cmsOpenProfileFromMem( iccprofile, size );
837     }
838
839     if (cmsprofile)
840         return MSCMS_create_hprofile_handle( handle, iccprofile, cmsprofile, access );
841
842 #endif /* HAVE_LCMS_H */
843     return NULL;
844 }
845
846 /******************************************************************************
847  * CloseColorProfile               [MSCMS.@]
848  *
849  * Close a color profile.
850  *
851  * PARAMS
852  *  profile  [I] Handle to the profile.
853  *
854  * RETURNS
855  *  Success: TRUE
856  *  Failure: FALSE
857  */
858 BOOL WINAPI CloseColorProfile( HPROFILE profile )
859 {
860     BOOL ret = FALSE;
861 #ifdef HAVE_LCMS_H
862     icProfile *iccprofile = MSCMS_hprofile2iccprofile( profile );
863     HANDLE file = MSCMS_hprofile2handle( profile );
864     DWORD access = MSCMS_hprofile2access( profile );
865
866     TRACE( "( %p )\n", profile );
867
868     if (file && (access & PROFILE_READWRITE))
869     {
870         DWORD written, size = MSCMS_get_profile_size( iccprofile );
871
872         if (SetFilePointer( file, 0, NULL, FILE_BEGIN ) ||
873             !WriteFile( file, iccprofile, size, &written, NULL ) || written != size)
874             ERR( "Unable to write color profile\n" );
875     }
876
877     ret = cmsCloseProfile( MSCMS_hprofile2cmsprofile( profile ) );
878     HeapFree( GetProcessHeap(), 0, MSCMS_hprofile2iccprofile( profile ) );
879
880     CloseHandle( MSCMS_hprofile2handle( profile ) );
881     MSCMS_destroy_hprofile_handle( profile );
882
883 #endif /* HAVE_LCMS_H */
884     return ret;
885 }