Infrastructure for handling ICC profiles.
Always load color profiles into memory.
Implement and test GetColorProfileElement and GetColorProfileHeader.
Implement GetColorProfileFromHandle and SetColorProfileHeader.

diff --git a/dlls/mscms/handle.c b/dlls/mscms/handle.c
index c13c46c..8cbce6f 100644
--- a/dlls/mscms/handle.c
+++ b/dlls/mscms/handle.c
@@ -41,15 +41,16 @@
 };
 static CRITICAL_SECTION MSCMS_handle_cs = { &MSCMS_handle_cs_debug, -1, 0, 0, 0, 0 };
 
-/*  A simple structure to tie together Windows file handles and lcms color
- *  profile handles. Windows color profile handles are built from indexes
- *  into an array of these structures. The 'file' field is set to NULL in
- *  case of a memory based profile
+/*  A simple structure to tie together a pointer to an icc profile, an lcms
+ *  color profile handle and a Windows file handle. Windows color profile 
+ *  handles are built from indexes into an array of these structures. If
+ *  the profile is memory based the file handle field is NULL.
  */
 
 struct handlemap
 {
     HANDLE file;
+    icProfile *iccprofile;
     cmsHPROFILE cmsprofile;
 };
 
@@ -57,12 +58,50 @@
 
 static struct handlemap handlemaptable[CMSMAXHANDLES];
 
-HPROFILE MSCMS_cmsprofile2hprofile( cmsHPROFILE cmsprofile )
+HPROFILE MSCMS_handle2hprofile( HANDLE file )
 {
-    HPROFILE ret = NULL;
+    HPROFILE profile = NULL;
     unsigned int i;
 
-    if (!cmsprofile) return ret;
+    if (!file) return NULL;
+
+    EnterCriticalSection( &MSCMS_handle_cs );
+
+    for (i = 0; i <= CMSMAXHANDLES; i++)
+    {
+        if (handlemaptable[i].file == file)
+        {
+            profile = (HPROFILE)(i + 1); goto out;
+        }
+    }
+
+out:
+    LeaveCriticalSection( &MSCMS_handle_cs );
+
+    return profile;
+}
+
+HANDLE MSCMS_hprofile2handle( HPROFILE profile )
+{
+    HANDLE file;
+    unsigned int i;
+
+    EnterCriticalSection( &MSCMS_handle_cs );
+
+    i = (unsigned int)profile - 1;
+    file = handlemaptable[i].file;
+
+    LeaveCriticalSection( &MSCMS_handle_cs );
+
+    return file;
+}
+
+HPROFILE MSCMS_cmsprofile2hprofile( cmsHPROFILE cmsprofile )
+{
+    HPROFILE profile = NULL;
+    unsigned int i;
+
+    if (!cmsprofile) return NULL;
 
     EnterCriticalSection( &MSCMS_handle_cs );
 
@@ -70,70 +109,94 @@
     {
         if (handlemaptable[i].cmsprofile == cmsprofile)
         {
-            ret = (HPROFILE)(i + 1); goto out;
+            profile = (HPROFILE)(i + 1); goto out;
         }
     }
 
 out:
     LeaveCriticalSection( &MSCMS_handle_cs );
 
-    return ret;
+    return profile;
 }
 
 cmsHPROFILE MSCMS_hprofile2cmsprofile( HPROFILE profile )
 {
-    HANDLE ret;
+    cmsHPROFILE cmshprofile;
     unsigned int i;
 
     EnterCriticalSection( &MSCMS_handle_cs );
 
     i = (unsigned int)profile - 1;
-    ret = handlemaptable[i].cmsprofile;
+    cmshprofile = handlemaptable[i].cmsprofile;
 
     LeaveCriticalSection( &MSCMS_handle_cs );
 
-    return ret;
+    return cmshprofile;
 }
 
-HANDLE MSCMS_hprofile2handle( HPROFILE profile )
+HPROFILE MSCMS_iccprofile2hprofile( icProfile *iccprofile )
 {
-    HANDLE ret;
+    HPROFILE profile = NULL;
     unsigned int i;
 
-    EnterCriticalSection( &MSCMS_handle_cs );
-
-    i = (unsigned int)profile - 1;
-    ret = handlemaptable[i].file;
-
-    LeaveCriticalSection( &MSCMS_handle_cs );
-
-    return ret;
-}
-
-HPROFILE MSCMS_create_hprofile_handle( HANDLE file, cmsHPROFILE cmsprofile )
-{
-    HPROFILE ret = NULL;
-    unsigned int i;
-
-    if (!cmsprofile) return ret;
+    if (!iccprofile) return NULL;
 
     EnterCriticalSection( &MSCMS_handle_cs );
 
     for (i = 0; i <= CMSMAXHANDLES; i++)
     {
-        if (handlemaptable[i].cmsprofile == 0)
+        if (handlemaptable[i].iccprofile == iccprofile)
         {
-            handlemaptable[i].file = file;
-            handlemaptable[i].cmsprofile = cmsprofile;
-
-            ret = (HPROFILE)(i + 1); goto out;
+            profile = (HPROFILE)(i + 1); goto out;
         }
     }
 
 out:
     LeaveCriticalSection( &MSCMS_handle_cs );
 
-    return ret;
+    return profile;
+}
+
+icProfile *MSCMS_hprofile2iccprofile( HPROFILE profile )
+{
+    icProfile *iccprofile;
+    unsigned int i;
+
+    EnterCriticalSection( &MSCMS_handle_cs );
+
+    i = (unsigned int)profile - 1;
+    iccprofile = handlemaptable[i].iccprofile;
+
+    LeaveCriticalSection( &MSCMS_handle_cs );
+
+    return iccprofile;
+}
+
+HPROFILE MSCMS_create_hprofile_handle( HANDLE file, icProfile *iccprofile, cmsHPROFILE cmsprofile )
+{
+    HPROFILE profile = NULL;
+    unsigned int i;
+
+    if (!cmsprofile || !iccprofile) return NULL;
+
+    EnterCriticalSection( &MSCMS_handle_cs );
+
+    for (i = 0; i <= CMSMAXHANDLES; i++)
+    {
+        if (handlemaptable[i].iccprofile == 0)
+        {
+            handlemaptable[i].file = file;
+            handlemaptable[i].iccprofile = iccprofile;
+            handlemaptable[i].cmsprofile = cmsprofile;
+
+            profile = (HPROFILE)(i + 1); goto out;
+        }
+    }
+
+out:
+    LeaveCriticalSection( &MSCMS_handle_cs );
+
+    return profile;
 }
 
 void MSCMS_destroy_hprofile_handle( HPROFILE profile )
diff --git a/dlls/mscms/mscms.spec b/dlls/mscms/mscms.spec
index 075de40..f5dc86c 100644
--- a/dlls/mscms/mscms.spec
+++ b/dlls/mscms/mscms.spec
@@ -20,10 +20,10 @@
 @ stub GetCMMInfo
 @ stdcall GetColorDirectoryA(ptr ptr long)
 @ stdcall GetColorDirectoryW(ptr ptr long)
-@ stub GetColorProfileElement
+@ stdcall GetColorProfileElement(ptr long long ptr ptr ptr)
 @ stdcall GetColorProfileElementTag(ptr long ptr)
-@ stub GetColorProfileFromHandle
-@ stub GetColorProfileHeader
+@ stdcall GetColorProfileFromHandle(ptr ptr ptr)
+@ stdcall GetColorProfileHeader(ptr ptr)
 @ stdcall GetCountColorProfileElements(ptr long)
 @ stub GetNamedProfileInfo
 @ stub GetPS2ColorRenderingDictionary
@@ -49,7 +49,7 @@
 @ stub SetColorProfileElement
 @ stub SetColorProfileElementReference
 @ stub SetColorProfileElementSize
-@ stub SetColorProfileHeader
+@ stdcall SetColorProfileHeader(ptr ptr)
 @ stub SetStandardColorSpaceProfileA
 @ stub SetStandardColorSpaceProfileW
 @ stub SpoolerCopyFileEvent
diff --git a/dlls/mscms/mscms_priv.h b/dlls/mscms/mscms_priv.h
index d5bc570..8a96cbc 100644
--- a/dlls/mscms/mscms_priv.h
+++ b/dlls/mscms/mscms_priv.h
@@ -25,7 +25,7 @@
 #ifdef HAVE_LCMS_H
 
 /*  These basic Windows types are defined in lcms.h when compiling on
- *  a non-Windows platforms (why?), so they would normally not conflict
+ *  a non-Windows platform (why?), so they would normally not conflict
  *  with anything included earlier. But since we are building Wine they
  *  most certainly will have been defined before we include lcms.h.
  *  The preprocessor comes to the rescue.
@@ -68,11 +68,14 @@
 #define DWORD   DWORD
 #define LPDWORD LPDWORD
 
+extern HPROFILE MSCMS_handle2hprofile( HANDLE file );
 extern HPROFILE MSCMS_cmsprofile2hprofile( cmsHPROFILE cmsprofile );
-extern cmsHPROFILE MSCMS_hprofile2cmsprofile( HPROFILE profile );
+extern HPROFILE MSCMS_iccprofile2hprofile( icProfile *iccprofile );
 extern HANDLE MSCMS_hprofile2handle( HPROFILE profile );
+extern cmsHPROFILE MSCMS_hprofile2cmsprofile( HPROFILE profile );
+extern icProfile *MSCMS_hprofile2iccprofile( HPROFILE profile );
 
-extern HPROFILE MSCMS_create_hprofile_handle( HANDLE file, cmsHPROFILE cmsprofile );
+extern HPROFILE MSCMS_create_hprofile_handle( HANDLE file, icProfile *iccprofile, cmsHPROFILE cmsprofile );
 extern void MSCMS_destroy_hprofile_handle( HPROFILE profile );
 
 #endif /* HAVE_LCMS_H */
diff --git a/dlls/mscms/profile.c b/dlls/mscms/profile.c
index 7535e3d..61da583 100644
--- a/dlls/mscms/profile.c
+++ b/dlls/mscms/profile.c
@@ -44,6 +44,144 @@
     lstrcpyW( name, &path[i] );
 }
 
+#ifdef HAVE_LCMS_H
+static BOOL MSCMS_cpu_is_little_endian()
+{
+    long l = 1;
+    void *p = &l;
+    char b = *(char *)p;
+
+    return b ? TRUE : FALSE;
+}
+
+static void MSCMS_endian_swap16( BYTE *byte )
+{
+    BYTE tmp;
+
+    tmp = byte[0];
+    byte[0] = byte[1];
+    byte[1] = tmp;
+}
+
+static void MSCMS_endian_swap32( BYTE *byte )
+{
+    BYTE tmp1, tmp2;
+
+    tmp1 = *byte++;
+    tmp2 = *byte++;
+
+    *(byte - 1) = *byte;
+    *byte++ = tmp2;
+    *(byte - 3) = *byte;
+    *byte = tmp1;
+}
+
+static void MSCMS_adjust_endianess32( BYTE *byte )
+{
+    if (MSCMS_cpu_is_little_endian())
+        MSCMS_endian_swap32( byte );
+}
+
+static void MSCMS_get_profile_header( icProfile *iccprofile, PROFILEHEADER *header )
+{
+    memcpy( header, iccprofile, sizeof(PROFILEHEADER) );
+
+    /* ICC format is big-endian, swap bytes if necessary */ 
+
+    if (MSCMS_cpu_is_little_endian())
+    {
+        MSCMS_endian_swap32( (BYTE *)&header->phSize );
+        MSCMS_endian_swap32( (BYTE *)&header->phCMMType );
+        MSCMS_endian_swap32( (BYTE *)&header->phVersion );
+        MSCMS_endian_swap32( (BYTE *)&header->phClass );
+        MSCMS_endian_swap32( (BYTE *)&header->phDataColorSpace );
+        MSCMS_endian_swap32( (BYTE *)&header->phConnectionSpace );
+
+        MSCMS_endian_swap32( (BYTE *)&header->phDateTime[0] );
+        MSCMS_endian_swap32( (BYTE *)&header->phDateTime[1] );
+        MSCMS_endian_swap32( (BYTE *)&header->phDateTime[2] );
+
+        MSCMS_endian_swap32( (BYTE *)&header->phSignature );
+        MSCMS_endian_swap32( (BYTE *)&header->phPlatform );
+        MSCMS_endian_swap32( (BYTE *)&header->phProfileFlags );
+        MSCMS_endian_swap32( (BYTE *)&header->phManufacturer );
+        MSCMS_endian_swap32( (BYTE *)&header->phModel );
+
+        MSCMS_endian_swap32( (BYTE *)&header->phAttributes[0] );
+        MSCMS_endian_swap32( (BYTE *)&header->phAttributes[1] );
+
+        MSCMS_endian_swap32( (BYTE *)&header->phRenderingIntent );
+        MSCMS_endian_swap32( (BYTE *)&header->phIlluminant );
+        MSCMS_endian_swap32( (BYTE *)&header->phCreator );
+    }
+}
+
+static void MSCMS_set_profile_header( icProfile *iccprofile, PROFILEHEADER *header )
+{
+    icHeader *iccheader = (icHeader *)iccprofile;
+
+    memcpy( iccprofile, header, sizeof(PROFILEHEADER) );
+
+    /* ICC format is big-endian, swap bytes if necessary */
+
+    if (MSCMS_cpu_is_little_endian())
+    {
+        MSCMS_endian_swap32( (BYTE *)&iccheader->size );
+        MSCMS_endian_swap32( (BYTE *)&iccheader->cmmId );
+        MSCMS_endian_swap32( (BYTE *)&iccheader->version );
+        MSCMS_endian_swap32( (BYTE *)&iccheader->deviceClass );
+        MSCMS_endian_swap32( (BYTE *)&iccheader->colorSpace );
+        MSCMS_endian_swap32( (BYTE *)&iccheader->pcs );
+
+        MSCMS_endian_swap16( (BYTE *)&iccheader->date.year );
+        MSCMS_endian_swap16( (BYTE *)&iccheader->date.month );
+        MSCMS_endian_swap16( (BYTE *)&iccheader->date.day );
+        MSCMS_endian_swap16( (BYTE *)&iccheader->date.hours );
+        MSCMS_endian_swap16( (BYTE *)&iccheader->date.minutes );
+        MSCMS_endian_swap16( (BYTE *)&iccheader->date.seconds );
+
+        MSCMS_endian_swap32( (BYTE *)&iccheader->magic );
+        MSCMS_endian_swap32( (BYTE *)&iccheader->platform );
+        MSCMS_endian_swap32( (BYTE *)&iccheader->flags );
+        MSCMS_endian_swap32( (BYTE *)&iccheader->manufacturer );
+        MSCMS_endian_swap32( (BYTE *)&iccheader->model );
+
+        MSCMS_endian_swap32( (BYTE *)&iccheader->attributes[0] );
+        MSCMS_endian_swap32( (BYTE *)&iccheader->attributes[1] );
+
+        MSCMS_endian_swap32( (BYTE *)&iccheader->renderingIntent );
+        MSCMS_endian_swap32( (BYTE *)&iccheader->illuminant );
+        MSCMS_endian_swap32( (BYTE *)&iccheader->creator );
+    }
+}
+
+static DWORD MSCMS_get_tag_count( icProfile *iccprofile )
+{
+    DWORD count = iccprofile->count;
+
+    MSCMS_adjust_endianess32( (BYTE *)&count );
+    return count;
+}
+
+static void MSCMS_get_tag_by_index( icProfile *iccprofile, DWORD index, icTag *tag )
+{
+    icTag *tmp = (icTag *)&iccprofile->data + (index * sizeof(icTag));
+
+    tag->sig = tmp->sig;
+    tag->offset = tmp->offset;
+    tag->size = tmp->size;
+
+    MSCMS_adjust_endianess32( (BYTE *)&tag->sig );
+    MSCMS_adjust_endianess32( (BYTE *)&tag->offset );
+    MSCMS_adjust_endianess32( (BYTE *)&tag->size );
+}
+
+static void MSCMS_get_tag_data( icProfile *iccprofile, icTag *tag, DWORD offset, void *buffer )
+{
+    memcpy( buffer, (char *)iccprofile + tag->offset + offset, tag->size - offset );
+}
+#endif /* HAVE_LCMS_H */
+
 WINE_DEFAULT_DEBUG_CHANNEL(mscms);
 
 /******************************************************************************
@@ -117,6 +255,43 @@
     return FALSE;
 }
 
+BOOL WINAPI GetColorProfileElement( HPROFILE profile, TAGTYPE type, DWORD offset, PDWORD size,
+                                    PVOID buffer, PBOOL ref )
+{
+    BOOL ret = FALSE;
+#ifdef HAVE_LCMS_H
+    icProfile *iccprofile = MSCMS_hprofile2iccprofile( profile );
+    DWORD i, count;
+    icTag tag;
+
+    TRACE( "( %p, 0x%08lx, %ld, %p, %p, %p )\n", profile, type, offset, size, buffer, ref );
+
+    if (!iccprofile || !ref) return FALSE;
+    count = MSCMS_get_tag_count( iccprofile );
+
+    for (i = 0; i < count; i++)
+    {
+        MSCMS_get_tag_by_index( iccprofile, i, &tag );
+
+        if (tag.sig == type)
+        {
+            if ((tag.size - offset) > *size || !buffer)
+            {
+                *size = (tag.size - offset);
+                return FALSE;
+            }
+
+            MSCMS_get_tag_data( iccprofile, &tag, offset, buffer );
+
+            *ref = FALSE; /* FIXME: calculate properly */
+            return TRUE;
+        }
+    }
+
+#endif /* HAVE_LCMS_H */
+    return ret;
+}
+
 /******************************************************************************
  * GetColorProfileElementTag               [MSCMS.@]
  *
@@ -135,20 +310,69 @@
  *  The tag table index starts at 1.
  *  Use GetCountColorProfileElements to retrieve a count of tagged elements.
  */
-BOOL WINAPI GetColorProfileElementTag( HPROFILE profile, DWORD index, PTAGTYPE tag )
+BOOL WINAPI GetColorProfileElementTag( HPROFILE profile, DWORD index, PTAGTYPE type )
 {
     BOOL ret = FALSE;
 #ifdef HAVE_LCMS_H
-    LCMSICCPROFILE *cmsprofile = (LCMSICCPROFILE *)MSCMS_hprofile2cmsprofile( profile );
+    icProfile *iccprofile = MSCMS_hprofile2iccprofile( profile );
+    DWORD count;
+    icTag tag;
 
-    TRACE( "( %p, %ld, %p )\n", profile, index, tag );
+    TRACE( "( %p, %ld, %p )\n", profile, index, type );
 
-    if (cmsprofile)
+    if (!iccprofile) return FALSE;
+
+    count = MSCMS_get_tag_count( iccprofile );
+    if (index > count) return FALSE;
+
+    MSCMS_get_tag_by_index( iccprofile, index - 1, &tag );
+    *type = tag.sig;
+
+    ret = TRUE;
+
+#endif /* HAVE_LCMS_H */
+    return ret;
+}
+
+BOOL WINAPI GetColorProfileFromHandle( HPROFILE profile, PBYTE buffer, PDWORD size )
+{
+    BOOL ret = FALSE;
+#ifdef HAVE_LCMS_H
+    icProfile *iccprofile = MSCMS_hprofile2iccprofile( profile );
+    PROFILEHEADER header;
+
+    TRACE( "( %p, %p, %p )\n", profile, buffer, size );
+
+    if (!iccprofile) return FALSE;
+    MSCMS_get_profile_header( profile, &header );
+
+    if (!buffer || header.phSize > *size)
     {
-        *tag = cmsprofile->TagNames[index - 1];
-        ret = TRUE;
+        *size = header.phSize;
+        return FALSE;
     }
 
+    /* FIXME: no endian conversion */
+    memcpy( buffer, iccprofile, header.phSize );
+    ret = TRUE;
+
+#endif /* HAVE_LCMS_H */
+    return ret;
+}
+
+BOOL WINAPI GetColorProfileHeader( HPROFILE profile, PPROFILEHEADER header )
+{
+    BOOL ret = FALSE;
+#ifdef HAVE_LCMS_H
+    icProfile *iccprofile = MSCMS_hprofile2iccprofile( profile );
+
+    TRACE( "( %p, %p )\n", profile, header );
+
+    if (!iccprofile || !header) return FALSE;
+
+    MSCMS_get_profile_header( iccprofile, header );
+    return TRUE;
+
 #endif /* HAVE_LCMS_H */
     return ret;
 }
@@ -171,15 +395,13 @@
 {
     BOOL ret = FALSE;
 #ifdef HAVE_LCMS_H
-    LCMSICCPROFILE *cmsprofile = (LCMSICCPROFILE *)MSCMS_hprofile2cmsprofile( profile );
+    icProfile *iccprofile = MSCMS_hprofile2iccprofile( profile );
 
     TRACE( "( %p, %p )\n", profile, count );
 
-    if (cmsprofile)
-    {
-        *count = cmsprofile->TagCount;
-        ret = TRUE;
-    }
+    if (!count) return FALSE;
+    *count = MSCMS_get_tag_count( iccprofile );
+    ret = TRUE;
 
 #endif /* HAVE_LCMS_H */
     return ret;
@@ -307,6 +529,8 @@
 
     TRACE( "( %p, 0x%08lx, %p )\n", profile, tag, present );
 
+    if (!present) return FALSE;
+
 #ifdef HAVE_LCMS_H
     ret = cmsIsTag( MSCMS_hprofile2cmsprofile( profile ), tag );
 
@@ -330,9 +554,34 @@
  */
 BOOL WINAPI IsColorProfileValid( HPROFILE profile, PBOOL valid )
 {
-    FIXME( "( %p, %p ) stub\n", profile, valid );
+    BOOL ret = FALSE;
+#ifdef HAVE_LCMS_H
+    icProfile *iccprofile = MSCMS_hprofile2iccprofile( profile );
 
-    return *valid = TRUE; 
+    TRACE( "( %p, %p )\n", profile, valid );
+
+    if (!valid) return FALSE;
+    if (iccprofile) return *valid = TRUE;
+
+#endif /* HAVE_LCMS_H */
+    return ret;
+}
+
+BOOL WINAPI SetColorProfileHeader( HPROFILE profile, PPROFILEHEADER header )
+{
+    BOOL ret = FALSE;
+#ifdef HAVE_LCMS_H
+    icProfile *iccprofile = MSCMS_hprofile2iccprofile( profile );
+
+    TRACE( "( %p, %p )\n", profile, header );
+
+    if (!iccprofile || !header) return FALSE;
+
+    MSCMS_set_profile_header( iccprofile, header );
+    return TRUE;
+
+#endif /* HAVE_LCMS_H */
+    return ret;
 }
 
 /******************************************************************************
@@ -385,8 +634,7 @@
 
     if (machine || !profile) return FALSE;
 
-    if (delete)
-        return DeleteFileW( profile );
+    if (delete) return DeleteFileW( profile );
 
     return TRUE;
 }
@@ -450,12 +698,15 @@
  *  Values for sharing:  0 (no sharing), FILE_SHARE_READ and/or FILE_SHARE_WRITE.
  *  Values for creation: one of CREATE_NEW, CREATE_ALWAYS, OPEN_EXISTING,
  *                       OPEN_ALWAYS, TRUNCATE_EXISTING.
+ *  Sharing and creation flags are ignored for memory based profiles.
  */
 HPROFILE WINAPI OpenColorProfileW( PPROFILE profile, DWORD access, DWORD sharing, DWORD creation )
 {
 #ifdef HAVE_LCMS_H
     cmsHPROFILE cmsprofile = NULL;
+    icProfile *iccprofile = NULL;
     HANDLE handle = NULL;
+    DWORD size;
 
     TRACE( "( %p, 0x%08lx, 0x%08lx, 0x%08lx )\n", profile, access, sharing, creation );
 
@@ -463,15 +714,19 @@
 
     if (profile->dwType & PROFILE_MEMBUFFER)
     {
-        FIXME( "Memory based profile not yet supported.\n" ); return NULL;
+        FIXME( "access flags not implemented for memory based profiles\n" );
+
+        iccprofile = profile->pProfileData;
+        size = profile->cbDataSize;
+    
+        cmsprofile = cmsOpenProfileFromMem( iccprofile, size );
     }
 
     if (profile->dwType & PROFILE_FILENAME)
     {
-        char *unixname;
-        DWORD flags = 0;
+        DWORD read, flags = 0;
 
-        TRACE("profile file: %s\n", debugstr_w( (WCHAR *)profile->pProfileData ));
+        TRACE( "profile file: %s\n", debugstr_w( (WCHAR *)profile->pProfileData ) );
 
         if (access & PROFILE_READ) flags = GENERIC_READ;
         if (access & PROFILE_READWRITE) flags = GENERIC_READ|GENERIC_WRITE;
@@ -479,18 +734,41 @@
         if (!flags) return NULL;
 
         handle = CreateFileW( profile->pProfileData, flags, sharing, NULL, creation, 0, NULL );
-        if (handle == INVALID_HANDLE_VALUE) return NULL;
-
-        unixname = wine_get_unix_file_name( (WCHAR *)profile->pProfileData );
-
-        if (unixname)
+        if (handle == INVALID_HANDLE_VALUE)
         {
-            cmsprofile = cmsOpenProfileFromFile( unixname, flags & GENERIC_READ ? "r" : "w" );
-            HeapFree( GetProcessHeap(), 0, unixname );
+            WARN( "Unable to open color profile\n" );
+            return NULL;
         }
+
+        if ((size = GetFileSize( handle, NULL )) == INVALID_FILE_SIZE)
+        {
+            ERR( "Unable to retrieve size of color profile\n" );
+            CloseHandle( handle );
+            return NULL;
+        }
+
+        iccprofile = (icProfile *)HeapAlloc( GetProcessHeap(), 0, size );
+        if (!iccprofile)
+        {
+            ERR( "Unable to allocate memory for color profile\n" );
+            CloseHandle( handle );
+            return NULL;
+        }
+
+        if (!ReadFile( handle, iccprofile, size, &read, NULL ) || read != size)
+        {
+            ERR( "Unable to read color profile\n" );
+
+            CloseHandle( handle );
+            HeapFree( GetProcessHeap, 0, iccprofile );
+            return NULL;
+        }
+
+        cmsprofile = cmsOpenProfileFromMem( iccprofile, size );
     }
 
-    if (cmsprofile) return MSCMS_create_hprofile_handle( handle, cmsprofile );
+    if (cmsprofile)
+        return MSCMS_create_hprofile_handle( handle, iccprofile, cmsprofile );
 
 #endif /* HAVE_LCMS_H */
     return NULL;
@@ -510,16 +788,18 @@
  */
 BOOL WINAPI CloseColorProfile( HPROFILE profile )
 {
-    BOOL ret1, ret2 = FALSE;
+    BOOL ret = FALSE;
 
     TRACE( "( %p )\n", profile );
 
 #ifdef HAVE_LCMS_H
-    ret1 = cmsCloseProfile( MSCMS_hprofile2cmsprofile( profile ) );
-    ret2 = CloseHandle( MSCMS_hprofile2handle( profile ) );
+    ret = cmsCloseProfile( MSCMS_hprofile2cmsprofile( profile ) );
+
+    HeapFree( GetProcessHeap(), 0, MSCMS_hprofile2iccprofile( profile ) );
+    CloseHandle( MSCMS_hprofile2handle( profile ) );
 
     MSCMS_destroy_hprofile_handle( profile );
 
 #endif /* HAVE_LCMS_H */
-    return ret1 && ret2;
+    return ret;
 }
diff --git a/dlls/mscms/tests/profile.c b/dlls/mscms/tests/profile.c
index 52c5ac4..5770539 100644
--- a/dlls/mscms/tests/profile.c
+++ b/dlls/mscms/tests/profile.c
@@ -144,6 +144,46 @@
     ok( ret, "GetColorDirectoryW() failed (%ld)\n", GetLastError() );
 }
 
+static void test_GetColorProfileElement()
+{
+    if (standardprofile)
+    {
+        PROFILE profile;
+        HPROFILE handle;
+        BOOL ret, ref;
+        DWORD size;
+        TAGTYPE tag = 0x63707274;  /* 'cprt' */
+        static char buffer[51];
+        static char expect[] =
+            { 0x74, 0x65, 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x43, 0x6f, 0x70,
+              0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x63, 0x29, 0x20,
+              0x31, 0x39, 0x39, 0x38, 0x20, 0x48, 0x65, 0x77, 0x6c, 0x65, 0x74,
+              0x74, 0x2d, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x72, 0x64, 0x20, 0x43,
+              0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x00 };
+
+        profile.dwType = PROFILE_FILENAME;
+        profile.pProfileData = standardprofile;
+        profile.cbDataSize = strlen(standardprofile);
+
+        handle = OpenColorProfileA( &profile, PROFILE_READ, 0, OPEN_EXISTING );
+        ok( handle != NULL, "OpenColorProfileA() failed (%ld)\n", GetLastError() );
+
+        size = 0;
+
+        ret = GetColorProfileElement( handle, tag, 0, &size, NULL, &ref );
+        ok( !ret, "GetColorProfileElement() succeeded (%ld)\n", GetLastError() );
+
+        size = sizeof(buffer);
+
+        ret = GetColorProfileElement( handle, tag, 0, &size, buffer, &ref );
+        ok( ret, "GetColorProfileElement() failed (%ld)\n", GetLastError() );
+
+        ok( !memcmp( buffer, expect, sizeof(expect) ), "Unexpected tag data\n" );
+
+        CloseColorProfile( handle );
+    }
+}
+
 static void test_GetColorProfileElementTag()
 {
     if (standardprofile)
@@ -162,7 +202,39 @@
         ok( handle != NULL, "OpenColorProfileA() failed (%ld)\n", GetLastError() );
 
         ret = GetColorProfileElementTag( handle, index, &tag );
-        ok( ret && tag == expect, "GetColorProfileElementTag() failed (%ld)\n", GetLastError() );
+        ok( ret && tag == expect, "GetColorProfileElementTag() failed (%ld) 0x%08lx\n",
+            GetLastError(), tag );
+
+        CloseColorProfile( handle );
+    }
+}
+
+static void test_GetColorProfileHeader()
+{
+    if (testprofile)
+    {
+        PROFILE profile;
+        HPROFILE handle;
+        BOOL ret;
+        static PROFILEHEADER header;
+        static PROFILEHEADER expect =
+            { 0x00000c48, 0x4c696e6f, 0x02100000, 0x6d6e7472, 0x52474220, 0x58595a20,
+              { 0x07ce0002, 0x00090006, 0x61637370 }, 0x61637370, 0x4d534654, 0x00000000,
+              0x49454320, 0x73524742, { 0x00000000, 0x00000000 }, 0x00000000, { 0x0000f6d6,
+              0x00000100, 0x2dd30000 }, 0x48502020 };
+
+        profile.dwType = PROFILE_FILENAME;
+        profile.pProfileData = testprofile;
+        profile.cbDataSize = strlen(testprofile);
+
+        handle = OpenColorProfileA( &profile, PROFILE_READ, 0, OPEN_EXISTING );
+        ok( handle != NULL, "OpenColorProfileA() failed (%ld)\n", GetLastError() );
+
+        ret = GetColorProfileHeader( handle, &header );
+        ok( ret, "GetColorProfileHeader() failed (%ld)\n", GetLastError() );
+
+        ok( memcmp( &header, &expect, FIELD_OFFSET(PROFILEHEADER, phReserved) ),
+            "Unexpected header data\n" );
 
         CloseColorProfile( handle );
     }
@@ -549,7 +621,10 @@
     test_GetColorDirectoryA();
     test_GetColorDirectoryW();
 
+    test_GetColorProfileElement();
     test_GetColorProfileElementTag();
+
+    test_GetColorProfileHeader();
     test_GetCountColorProfileElements();
 
     test_InstallColorProfileA();
diff --git a/include/icm.h b/include/icm.h
index c55abb8..3edabd2 100644
--- a/include/icm.h
+++ b/include/icm.h
@@ -87,7 +87,7 @@
     DWORD phProfileFlags;
     DWORD phManufacturer;
     DWORD phModel;
-    DWORD phAttributes;
+    DWORD phAttributes[2];
     DWORD phRenderingIntent;
     CIEXYZ phIlluminant;
     DWORD phCreator;
@@ -160,6 +160,7 @@
 #define    GetColorDirectory WINELIB_NAME_AW(GetColorDirectory)
 BOOL       WINAPI GetColorProfileElement(HPROFILE,TAGTYPE,DWORD,PDWORD,PVOID,PBOOL);
 BOOL       WINAPI GetColorProfileElementTag(HPROFILE,DWORD,PTAGTYPE);
+BOOL       WINAPI GetColorProfileHeader(HPROFILE,PPROFILEHEADER);
 BOOL       WINAPI GetCountColorProfileElements(HPROFILE,PDWORD);
 BOOL       WINAPI GetStandardColorSpaceProfileA(PCSTR,DWORD,PSTR,PDWORD);
 BOOL       WINAPI GetStandardColorSpaceProfileW(PCWSTR,DWORD,PWSTR,PDWORD);
@@ -172,6 +173,7 @@
 HPROFILE   WINAPI OpenColorProfileA(PPROFILE,DWORD,DWORD,DWORD);
 HPROFILE   WINAPI OpenColorProfileW(PPROFILE,DWORD,DWORD,DWORD);
 #define    OpenColorProfile WINELIB_NAME_AW(OpenColorProfile)
+BOOL       WINAPI SetColorProfileHeader(HPROFILE,PPROFILEHEADER);
 BOOL       WINAPI SetupColorMatchingA(PCOLORMATCHSETUPA);
 BOOL       WINAPI SetupColorMatchingW(PCOLORMATCHSETUPW);
 #define    SetupColorMatching WINELIB_NAME_AW(SetupColorMatching)