Sync to Wine-20050725:
[reactos.git] / reactos / lib / shlwapi / reg.c
index bfd3b33..ccee4a8 100644 (file)
@@ -47,11 +47,12 @@ static const WCHAR szExtensionW[] = { 'E', 'x', 't','e','n','s','i','o','n','\0'
 
 /* internal structure of what the HUSKEY points to */
 typedef struct {
-    HKEY     HKCUkey;                  /* HKEY of opened HKCU key      */
-    HKEY     HKLMkey;                  /* HKEY of opened HKLM key      */
-    HKEY     start;                    /* HKEY of where to start       */
-    WCHAR    key_string[MAX_PATH];     /* additional path from 'start' */
-} Internal_HUSKEY, *LPInternal_HUSKEY;
+    HKEY     HKCUstart; /* Start key in CU hive */
+    HKEY     HKCUkey;   /* Opened key in CU hive */
+    HKEY     HKLMstart; /* Start key in LM hive */
+    HKEY     HKLMkey;   /* Opened key in LM hive */
+    WCHAR    lpszPath[MAX_PATH];
+} SHUSKEY, *LPSHUSKEY;
 
 DWORD   WINAPI SHStringFromGUIDW(REFGUID,LPWSTR,INT);
 HRESULT WINAPI SHRegGetCLSIDKeyW(REFGUID,LPCWSTR,BOOL,BOOL,PHKEY);
@@ -68,7 +69,7 @@ HRESULT WINAPI SHRegGetCLSIDKeyW(REFGUID,LPCWSTR,BOOL,BOOL,PHKEY);
 static HKEY WINAPI REG_GetHKEYFromHUSKEY(HUSKEY hUSKey, BOOL which)
 {
         HKEY test = (HKEY) hUSKey;
-        LPInternal_HUSKEY mihk = (LPInternal_HUSKEY) hUSKey;
+        LPSHUSKEY mihk = (LPSHUSKEY) hUSKey;
 
        if ((test == HKEY_CLASSES_ROOT)        ||
            (test == HKEY_CURRENT_CONFIG)      ||
@@ -89,72 +90,29 @@ static HKEY WINAPI REG_GetHKEYFromHUSKEY(HUSKEY hUSKey, BOOL which)
 /*************************************************************************
  * SHRegOpenUSKeyA     [SHLWAPI.@]
  *
- * Opens a user-specific registry key
+ * Open a user-specific registry key.
+ *
+ * PARAMS
+ *  Path           [I] Key name to open
+ *  AccessType     [I] Access type
+ *  hRelativeUSKey [I] Relative user key
+ *  phNewUSKey     [O] Destination for created key
+ *  fIgnoreHKCU    [I] TRUE=Don't check HKEY_CURRENT_USER
  *
  * RETURNS
  *  Success: ERROR_SUCCESS
  *  Failure: An error code from RegOpenKeyExA().
  */
-LONG WINAPI SHRegOpenUSKeyA(
-        LPCSTR Path, /* [I] Key name to open */
-        REGSAM AccessType, /* [I] Access type */
-        HUSKEY hRelativeUSKey, /* [I] Relative user key */
-        PHUSKEY phNewUSKey, /* [O] Destination for created key */
-        BOOL fIgnoreHKCU)  /* [I] TRUE=Don't check HKEY_CURRENT_USER */
+LONG WINAPI SHRegOpenUSKeyA(LPCSTR Path, REGSAM AccessType, HUSKEY hRelativeUSKey,
+                            PHUSKEY phNewUSKey, BOOL fIgnoreHKCU)
 {
-    HKEY openHKCUkey=0;
-    HKEY openHKLMkey=0;
-    LONG ret2, ret1 = ~ERROR_SUCCESS;
-    LPInternal_HUSKEY ihky;
-
-    TRACE("(%s, 0x%lx, 0x%lx, %p, %s)\n", debugstr_a(Path),
-         (LONG)AccessType, (LONG)hRelativeUSKey, phNewUSKey,
-         (fIgnoreHKCU) ? "Ignoring HKCU" : "Process HKCU then HKLM");
-
-    /* now create the internal version of HUSKEY */
-    ihky = (LPInternal_HUSKEY)HeapAlloc(GetProcessHeap(), 0 ,
-                                       sizeof(Internal_HUSKEY));
-    MultiByteToWideChar(0, 0, Path, -1, ihky->key_string,
-                       sizeof(ihky->key_string)-1);
-
-    if (hRelativeUSKey) {
-       openHKCUkey = ((LPInternal_HUSKEY)hRelativeUSKey)->HKCUkey;
-       openHKLMkey = ((LPInternal_HUSKEY)hRelativeUSKey)->HKLMkey;
-    }
-    else {
-       openHKCUkey = HKEY_CURRENT_USER;
-       openHKLMkey = HKEY_LOCAL_MACHINE;
-    }
+    WCHAR szPath[MAX_PATH];
 
-    ihky->HKCUkey = 0;
-    ihky->HKLMkey = 0;
-    if (!fIgnoreHKCU) {
-       ret1 = RegOpenKeyExA(openHKCUkey, Path,
-                            0, AccessType, &ihky->HKCUkey);
-       /* if successful, then save real starting point */
-       if (ret1 != ERROR_SUCCESS)
-           ihky->HKCUkey = 0;
-    }
-    ret2 = RegOpenKeyExA(openHKLMkey, Path,
-                        0, AccessType, &ihky->HKLMkey);
-    if (ret2 != ERROR_SUCCESS)
-       ihky->HKLMkey = 0;
-
-    if ((ret1 != ERROR_SUCCESS) || (ret2 != ERROR_SUCCESS))
-       TRACE("one or more opens failed: HKCU=%ld HKLM=%ld\n", ret1, ret2);
-
-    /* if all attempts have failed then bail */
-    if ((ret1 != ERROR_SUCCESS) && (ret2 != ERROR_SUCCESS)) {
-       HeapFree(GetProcessHeap(), 0, ihky);
-       if (phNewUSKey)
-           *phNewUSKey = NULL;
-       return ret2;
-    }
+    if (Path)
+      MultiByteToWideChar(CP_ACP, 0, Path, -1, szPath, MAX_PATH);
 
-    TRACE("HUSKEY=%p\n", ihky);
-    if (phNewUSKey)
-       *phNewUSKey = (HUSKEY)ihky;
-    return ERROR_SUCCESS;
+    return SHRegOpenUSKeyW(Path ? szPath : NULL, AccessType, hRelativeUSKey,
+                           phNewUSKey, fIgnoreHKCU);
 }
 
 /*************************************************************************
@@ -162,64 +120,61 @@ LONG WINAPI SHRegOpenUSKeyA(
  *
  * See SHRegOpenUSKeyA.
  */
-LONG WINAPI SHRegOpenUSKeyW(
-        LPCWSTR Path,
-        REGSAM AccessType,
-        HUSKEY hRelativeUSKey,
-        PHUSKEY phNewUSKey,
-        BOOL fIgnoreHKCU)
+LONG WINAPI SHRegOpenUSKeyW(LPCWSTR Path, REGSAM AccessType, HUSKEY hRelativeUSKey,
+                            PHUSKEY phNewUSKey, BOOL fIgnoreHKCU)
 {
-    HKEY openHKCUkey=0;
-    HKEY openHKLMkey=0;
     LONG ret2, ret1 = ~ERROR_SUCCESS;
-    LPInternal_HUSKEY ihky;
+    LPSHUSKEY hKey;
 
-    TRACE("(%s, 0x%lx, 0x%lx, %p, %s)\n", debugstr_w(Path),
-         (LONG)AccessType, (LONG)hRelativeUSKey, phNewUSKey,
-         (fIgnoreHKCU) ? "Ignoring HKCU" : "Process HKCU then HKLM");
+    TRACE("(%s,0x%lx,%p,%p,%d)\n", debugstr_w(Path),(LONG)AccessType,
+          hRelativeUSKey, phNewUSKey, fIgnoreHKCU);
 
-    /* now create the internal version of HUSKEY */
-    ihky = (LPInternal_HUSKEY)HeapAlloc(GetProcessHeap(), 0 ,
-                                       sizeof(Internal_HUSKEY));
-    lstrcpynW(ihky->key_string, Path, sizeof(ihky->key_string));
+    if (phNewUSKey)
+        *phNewUSKey = NULL;
+
+    /* Create internal HUSKEY */
+    hKey = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*hKey));
+    lstrcpynW(hKey->lpszPath, Path, sizeof(hKey->lpszPath));
+
+    if (hRelativeUSKey)
+    {
+        hKey->HKCUstart = SHRegDuplicateHKey(REG_GetHKEYFromHUSKEY(hRelativeUSKey, REG_HKCU));
+        hKey->HKLMstart = SHRegDuplicateHKey(REG_GetHKEYFromHUSKEY(hRelativeUSKey, REG_HKLM));
 
-    if (hRelativeUSKey) {
-       openHKCUkey = ((LPInternal_HUSKEY)hRelativeUSKey)->HKCUkey;
-       openHKLMkey = ((LPInternal_HUSKEY)hRelativeUSKey)->HKLMkey;
+        /* FIXME: if either of these keys is NULL, create the start key from
+         *        the relative keys start+path
+         */
     }
-    else {
-       openHKCUkey = HKEY_CURRENT_USER;
-       openHKLMkey = HKEY_LOCAL_MACHINE;
+    else
+    {
+        hKey->HKCUstart = HKEY_CURRENT_USER;
+        hKey->HKLMstart = HKEY_LOCAL_MACHINE;
     }
 
-    ihky->HKCUkey = 0;
-    ihky->HKLMkey = 0;
-    if (!fIgnoreHKCU) {
-       ret1 = RegOpenKeyExW(openHKCUkey, Path,
-                           0, AccessType, &ihky->HKCUkey);
-       /* if successful, then save real starting point */
-       if (ret1 != ERROR_SUCCESS)
-           ihky->HKCUkey = 0;
+    if (!fIgnoreHKCU)
+    {
+        ret1 = RegOpenKeyExW(hKey->HKCUstart, hKey->lpszPath, 0, AccessType, &hKey->HKCUkey);
+        if (ret1)
+            hKey->HKCUkey = 0;
     }
-    ret2 = RegOpenKeyExW(openHKLMkey, Path,
-                       0, AccessType, &ihky->HKLMkey);
-    if (ret2 != ERROR_SUCCESS)
-       ihky->HKLMkey = 0;
-
-    if ((ret1 != ERROR_SUCCESS) || (ret2 != ERROR_SUCCESS))
-       TRACE("one or more opens failed: HKCU=%ld HKLM=%ld\n", ret1, ret2);
-
-    /* if all attempts have failed then bail */
-    if ((ret1 != ERROR_SUCCESS) && (ret2 != ERROR_SUCCESS)) {
-       HeapFree(GetProcessHeap(), 0, ihky);
-       if (phNewUSKey)
-           *phNewUSKey = NULL;
-       return ret2;
+
+    ret2 = RegOpenKeyExW(hKey->HKLMstart, hKey->lpszPath, 0, AccessType, &hKey->HKLMkey);
+    if (ret2)
+        hKey->HKLMkey = 0;
+
+    if (ret1 || ret2)
+        TRACE("one or more opens failed: HKCU=%ld HKLM=%ld\n", ret1, ret2);
+
+    if (ret1 && ret2)
+    {
+        /* Neither open succeeded: fail */
+        SHRegCloseUSKey(hKey);
+        return ret2;
     }
 
-    TRACE("HUSKEY=0x%08lx\n", (LONG)ihky);
+    TRACE("HUSKEY=%p\n", hKey);
     if (phNewUSKey)
-       *phNewUSKey = (HUSKEY)ihky;
+        *phNewUSKey = (HUSKEY)hKey;
     return ERROR_SUCCESS;
 }
 
@@ -232,20 +187,169 @@ LONG WINAPI SHRegOpenUSKeyW(
  *  Success: ERROR_SUCCESS
  *  Failure: An error code from RegCloseKey().
  */
-DWORD WINAPI SHRegCloseUSKey(
+LONG WINAPI SHRegCloseUSKey(
         HUSKEY hUSKey) /* [I] Key to close */
 {
-    LPInternal_HUSKEY mihk = (LPInternal_HUSKEY)hUSKey;
+    LPSHUSKEY hKey = (LPSHUSKEY)hUSKey;
     LONG ret = ERROR_SUCCESS;
 
-    if (mihk->HKCUkey)
-       ret = RegCloseKey(mihk->HKCUkey);
-    if (mihk->HKLMkey)
-       ret = RegCloseKey(mihk->HKLMkey);
-    HeapFree(GetProcessHeap(), 0, mihk);
+    if (hKey->HKCUkey)
+        ret = RegCloseKey(hKey->HKCUkey);
+    if (hKey->HKCUstart && hKey->HKCUstart != HKEY_CURRENT_USER)
+        ret = RegCloseKey(hKey->HKCUstart);
+    if (hKey->HKLMkey)
+        ret = RegCloseKey(hKey->HKLMkey);
+    if (hKey->HKLMstart && hKey->HKLMstart != HKEY_LOCAL_MACHINE)
+        ret = RegCloseKey(hKey->HKCUstart);
+
+    HeapFree(GetProcessHeap(), 0, hKey);
     return ret;
 }
 
+/*************************************************************************
+ * SHRegCreateUSKeyA  [SHLWAPI.@]
+ *
+ * Create or open a user-specific registry key.
+ * 
+ * PARAMS
+ *  pszPath        [I] Key name to create or open.
+ *  samDesired     [I] Wanted security access.
+ *  hRelativeUSKey [I] Base path if pszPath is relative. NULL otherwise.
+ *  phNewUSKey     [O] Receives a handle to the new or openened key.
+ *  dwFlags        [I] Base key under which the key should be opened.
+ *
+ * RETURNS
+ *  Success: ERROR_SUCCESS
+ *  Failure: Nonzero error code from winerror.h
+ */
+LONG WINAPI SHRegCreateUSKeyA(LPCSTR pszPath, REGSAM samDesired, HUSKEY hRelativeUSKey,
+                              PHUSKEY phNewUSKey, DWORD dwFlags)
+{
+    FIXME("(%s, 0x%08lx, %p, %p, 0x%08lx) stub\n", debugstr_a(pszPath), samDesired,
+          hRelativeUSKey, phNewUSKey, dwFlags);
+    return ERROR_SUCCESS;
+}
+
+/*************************************************************************
+ * SHRegCreateUSKeyW  [SHLWAPI.@]
+ *
+ * See SHRegCreateUSKeyA.
+ */
+LONG WINAPI SHRegCreateUSKeyW(LPCWSTR pszPath, REGSAM samDesired, HUSKEY hRelativeUSKey,
+                              PHUSKEY phNewUSKey, DWORD dwFlags)
+{
+    FIXME("(%s, 0x%08lx, %p, %p, 0x%08lx) stub\n", debugstr_w(pszPath), samDesired,
+          hRelativeUSKey, phNewUSKey, dwFlags);
+    return ERROR_SUCCESS;
+}
+
+/*************************************************************************
+ * SHRegDeleteEmptyUSKeyA  [SHLWAPI.@]
+ *
+ * Delete an empty user-specific registry key.
+ *
+ * PARAMS
+ *  hUSKey      [I] Handle to an open registry key.
+ *  pszValue    [I] Empty key name.
+ *  delRegFlags [I] Flag that specifies the base from which to delete 
+ *                  the key.
+ *
+ * RETURNS
+ *  Success: ERROR_SUCCESS
+ *  Failure: Nonzero error code from winerror.h
+ */
+LONG WINAPI SHRegDeleteEmptyUSKeyA(HUSKEY hUSKey, LPCSTR pszValue, SHREGDEL_FLAGS delRegFlags)
+{
+    FIXME("(%p, %s, 0x%08x) stub\n", hUSKey, debugstr_a(pszValue), delRegFlags);
+    return ERROR_SUCCESS;
+}
+
+/*************************************************************************
+ * SHRegDeleteEmptyUSKeyW  [SHLWAPI.@]
+ *
+ * See SHRegDeleteEmptyUSKeyA.
+ */
+LONG WINAPI SHRegDeleteEmptyUSKeyW(HUSKEY hUSKey, LPCWSTR pszValue, SHREGDEL_FLAGS delRegFlags)
+{
+    FIXME("(%p, %s, 0x%08x) stub\n", hUSKey, debugstr_w(pszValue), delRegFlags);
+    return ERROR_SUCCESS;
+}
+
+/*************************************************************************
+ * SHRegDeleteUSValueA  [SHLWAPI.@]
+ *
+ * Delete a user-specific registry value.
+ *
+ * PARAMS
+ *  hUSKey      [I] Handle to an open registry key.
+ *  pszValue    [I] Specifies the value to delete.
+ *  delRegFlags [I] Flag that specifies the base of the key from which to
+ *                  delete the value.
+ *
+ * RETURNS
+ *  Success: ERROR_SUCCESS
+ *  Failure: Nonzero error code from winerror.h
+ */
+LONG WINAPI SHRegDeleteUSValueA(HUSKEY hUSKey, LPCSTR pszValue, SHREGDEL_FLAGS delRegFlags)
+{
+    FIXME("(%p, %s, 0x%08x) stub\n", hUSKey, debugstr_a(pszValue), delRegFlags);
+    return ERROR_SUCCESS;
+}
+
+/*************************************************************************
+ * SHRegDeleteUSValueW  [SHLWAPI.@]
+ *
+ * See SHRegDeleteUSValueA.
+ */
+LONG WINAPI SHRegDeleteUSValueW(HUSKEY hUSKey, LPCWSTR pszValue, SHREGDEL_FLAGS delRegFlags)
+{
+    FIXME("(%p, %s, 0x%08x) stub\n", hUSKey, debugstr_w(pszValue), delRegFlags);
+    return ERROR_SUCCESS;
+}
+
+/*************************************************************************
+ * SHRegEnumUSValueA  [SHLWAPI.@]
+ *
+ * Enumerate values of a specified registry key.
+ *
+ * PARAMS
+ *  hUSKey           [I]   Handle to an open registry key.
+ *  dwIndex          [I]   Index of the value to be retrieved.
+ *  pszValueName     [O]   Buffer to receive the value name.
+ *  pcchValueNameLen [I]   Size of pszValueName in characters.
+ *  pdwType          [O]   Receives data type of the value.
+ *  pvData           [O]   Receives value data. May be NULL.
+ *  pcbData          [I/O] Size of pvData in bytes.
+ *  enumRegFlags     [I]   Flag that specifies the base key under which to
+ *                         enumerate values.
+ *
+ * RETURNS
+ *  Success: ERROR_SUCCESS
+ *  Failure: Nonzero error code from winerror.h
+ */
+LONG WINAPI SHRegEnumUSValueA(HUSKEY hUSKey, DWORD dwIndex, LPSTR pszValueName,
+                              LPDWORD pcchValueNameLen, LPDWORD pdwType, LPVOID pvData,
+                              LPDWORD pcbData, SHREGENUM_FLAGS enumRegFlags)
+{
+    FIXME("(%p, 0x%08lx, %s, %p, %p, %p, %p, 0x%08x) stub\n", hUSKey, dwIndex,
+          debugstr_a(pszValueName), pcchValueNameLen, pdwType, pvData, pcbData, enumRegFlags);
+    return ERROR_INVALID_FUNCTION;
+}
+
+/*************************************************************************
+ * SHRegEnumUSValueW  [SHLWAPI.@]
+ *
+ * See SHRegEnumUSValueA.
+ */
+LONG WINAPI SHRegEnumUSValueW(HUSKEY hUSKey, DWORD dwIndex, LPWSTR pszValueName,
+                              LPDWORD pcchValueNameLen, LPDWORD pdwType, LPVOID pvData,
+                              LPDWORD pcbData, SHREGENUM_FLAGS enumRegFlags)
+{
+    FIXME("(%p, 0x%08lx, %s, %p, %p, %p, %p, 0x%08x) stub\n", hUSKey, dwIndex,
+          debugstr_w(pszValueName), pcchValueNameLen, pdwType, pvData, pcbData, enumRegFlags);
+    return ERROR_INVALID_FUNCTION;
+}
+
 /*************************************************************************
  *      SHRegQueryUSValueA     [SHLWAPI.@]
  *
@@ -429,6 +533,14 @@ LONG WINAPI SHRegGetUSValueW(
  *
  * Set a user-specific registry value.
  *
+ * PARAMS
+ *  pszSubKey [I] Name of key to set the value in
+ *  pszValue  [I] Name of value under pszSubKey to set the value in
+ *  dwType    [I] Type of the value
+ *  pvData    [I] Data to set as the value
+ *  cbData    [I] length of pvData
+ *  dwFlags   [I] SHREGSET_ flags from "shlwapi.h"
+ *
  * RETURNS
  *  Success: ERROR_SUCCESS
  *  Failure: An error code from SHRegOpenUSKeyA() or SHRegWriteUSValueA(), or
@@ -437,31 +549,29 @@ LONG WINAPI SHRegGetUSValueW(
  * NOTES
  *   This function opens pszSubKey, sets the value, and then closes the key.
  */
-LONG WINAPI SHRegSetUSValueA(
-       LPCSTR pszSubKey, /* [I] Name of key to set the value in */
-       LPCSTR pszValue, /* [I] Name of value under pszSubKey to set the value in */
-       DWORD  dwType, /* [I] Type of the value */
-       LPVOID pvData, /* [I] Data to set as the value */
-       DWORD  cbData, /* [I] length of pvData */
-       DWORD  dwFlags) /* [I] SHREGSET_ flags from "shlwapi.h" */
+LONG WINAPI SHRegSetUSValueA(LPCSTR pszSubKey, LPCSTR pszValue, DWORD dwType,
+                             LPVOID pvData, DWORD cbData, DWORD dwFlags)
 {
-        HUSKEY myhuskey;
-       LONG   ret;
-       BOOL   ignoreHKCU;
+  BOOL ignoreHKCU = TRUE;
+  HUSKEY hkey;
+  LONG ret;
 
-        if (!pvData) return ERROR_INVALID_FUNCTION;
-       TRACE("key '%s', value '%s', datalen %ld\n",
-             debugstr_a(pszSubKey), debugstr_a(pszValue), cbData);
+  TRACE("(%s,%s,%ld,%p,%ld,0x%08lx\n", debugstr_a(pszSubKey), debugstr_a(pszValue),
+        dwType, pvData, cbData, dwFlags);
 
-       ignoreHKCU = ((dwFlags == SHREGSET_HKLM) || (dwFlags == SHREGSET_FORCE_HKLM));
+  if (!pvData)
+    return ERROR_INVALID_FUNCTION;
 
-       ret = SHRegOpenUSKeyA(pszSubKey, 0x1, 0, &myhuskey, ignoreHKCU);
-       if (ret == ERROR_SUCCESS) {
-         ret = SHRegWriteUSValueA(myhuskey, pszValue, dwType, pvData,
-                                  cbData, dwFlags);
-           SHRegCloseUSKey(myhuskey);
-       }
-       return ret;
+  if (dwFlags & SHREGSET_HKCU || dwFlags & SHREGSET_FORCE_HKCU)
+    ignoreHKCU = FALSE;
+
+  ret = SHRegOpenUSKeyA(pszSubKey, KEY_ALL_ACCESS, 0, &hkey, ignoreHKCU);
+  if (ret == ERROR_SUCCESS)
+  {
+    ret = SHRegWriteUSValueA(hkey, pszValue, dwType, pvData, cbData, dwFlags);
+    SHRegCloseUSKey(hkey);
+  }
+  return ret;
 }
 
 /*************************************************************************
@@ -469,31 +579,29 @@ LONG WINAPI SHRegSetUSValueA(
  *
  * See SHRegSetUSValueA.
  */
-LONG WINAPI SHRegSetUSValueW(
-       LPCWSTR pszSubKey,
-       LPCWSTR pszValue,
-       DWORD   dwType,
-       LPVOID  pvData,
-       DWORD   cbData,
-       DWORD   dwFlags)
+LONG WINAPI SHRegSetUSValueW(LPCWSTR pszSubKey, LPCWSTR pszValue, DWORD dwType,
+                             LPVOID pvData, DWORD cbData, DWORD dwFlags)
 {
-        HUSKEY myhuskey;
-       LONG   ret;
-       BOOL   ignoreHKCU;
+  BOOL ignoreHKCU = TRUE;
+  HUSKEY hkey;
+  LONG ret;
 
-        if (!pvData) return ERROR_INVALID_FUNCTION;
-       TRACE("key '%s', value '%s', datalen %ld\n",
-             debugstr_w(pszSubKey), debugstr_w(pszValue), cbData);
+  TRACE("(%s,%s,%ld,%p,%ld,0x%08lx\n", debugstr_w(pszSubKey), debugstr_w(pszValue),
+        dwType, pvData, cbData, dwFlags);
 
-       ignoreHKCU = ((dwFlags == SHREGSET_HKLM) || (dwFlags == SHREGSET_FORCE_HKLM));
+  if (!pvData)
+    return ERROR_INVALID_FUNCTION;
 
-       ret = SHRegOpenUSKeyW(pszSubKey, 0x1, 0, &myhuskey, ignoreHKCU);
-       if (ret == ERROR_SUCCESS) {
-         ret = SHRegWriteUSValueW(myhuskey, pszValue, dwType, pvData,
-                                  cbData, dwFlags);
-           SHRegCloseUSKey(myhuskey);
-       }
-       return ret;
+  if (dwFlags & SHREGSET_HKCU || dwFlags & SHREGSET_FORCE_HKCU)
+    ignoreHKCU = FALSE;
+
+  ret = SHRegOpenUSKeyW(pszSubKey, KEY_ALL_ACCESS, 0, &hkey, ignoreHKCU);
+  if (ret == ERROR_SUCCESS)
+  {
+    ret = SHRegWriteUSValueW(hkey, pszValue, dwType, pvData, cbData, dwFlags);
+    SHRegCloseUSKey(hkey);
+  }
+  return ret;
 }
 
 /*************************************************************************
@@ -634,7 +742,7 @@ BOOL WINAPI SHRegGetBoolUSValueW(
  *  Success: ERROR_SUCCESS
  *  Failure: An error code from RegQueryInfoKeyA().
  */
-DWORD WINAPI SHRegQueryInfoUSKeyA(
+LONG WINAPI SHRegQueryInfoUSKeyA(
        HUSKEY hUSKey, /* [I] Key to query */
        LPDWORD pcSubKeys, /* [O] Destination for number of sub keys */
        LPDWORD pcchMaxSubKeyLen, /* [O] Destination for the length of the biggest sub key name */
@@ -675,7 +783,7 @@ DWORD WINAPI SHRegQueryInfoUSKeyA(
  *
  * See SHRegQueryInfoUSKeyA.
  */
-DWORD WINAPI SHRegQueryInfoUSKeyW(
+LONG WINAPI SHRegQueryInfoUSKeyW(
        HUSKEY hUSKey,
        LPDWORD pcSubKeys,
        LPDWORD pcchMaxSubKeyLen,
@@ -720,7 +828,7 @@ DWORD WINAPI SHRegQueryInfoUSKeyW(
  *  Success: ERROR_SUCCESS
  *  Failure: An error code from RegEnumKeyExA().
  */
-DWORD WINAPI SHRegEnumUSKeyA(
+LONG WINAPI SHRegEnumUSKeyA(
        HUSKEY hUSKey,                 /* [in] Key to enumerate */
        DWORD dwIndex,                 /* [in] Index within hUSKey */
        LPSTR pszName,                 /* [out] Name of the enumerated value */
@@ -755,7 +863,7 @@ DWORD WINAPI SHRegEnumUSKeyA(
  *
  * See SHRegEnumUSKeyA.
  */
-DWORD WINAPI SHRegEnumUSKeyW(
+LONG WINAPI SHRegEnumUSKeyW(
        HUSKEY hUSKey,
        DWORD dwIndex,
        LPWSTR pszName,
@@ -801,31 +909,22 @@ DWORD WINAPI SHRegEnumUSKeyW(
  *
  * RETURNS
  *  Success: ERROR_SUCCESS.
- *  Failure: An error code from RegSetValueExA().
+ *  Failure: ERROR_INVALID_PARAMETER, if any parameter is invalid, otherwise
+ *           an error code from RegSetValueExA().
+ *
+ * NOTES
+ *  dwFlags must have at least SHREGSET_FORCE_HKCU or SHREGSET_FORCE_HKLM set.
  */
 LONG  WINAPI SHRegWriteUSValueA(HUSKEY hUSKey, LPCSTR pszValue, DWORD dwType,
-                               LPVOID pvData, DWORD cbData, DWORD dwFlags)
+                                LPVOID pvData, DWORD cbData, DWORD dwFlags)
 {
-    HKEY dokey;
-
-    TRACE("(%p,%s,%ld,%p,%ld,%ld)\n",
-             hUSKey, debugstr_a(pszValue), dwType, pvData, cbData, dwFlags);
-
-    if ((dwFlags & SHREGSET_FORCE_HKCU) &&
-           (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
-       RegSetValueExA(dokey, pszValue, 0, dwType, pvData, cbData);
-    }
-
-    if ((dwFlags & SHREGSET_FORCE_HKLM) &&
-           (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
-       RegSetValueExA(dokey, pszValue, 0, dwType, pvData, cbData);
-    }
+    WCHAR szValue[MAX_PATH];
 
-    if (dwFlags & (SHREGSET_FORCE_HKCU | SHREGSET_FORCE_HKLM))
-       return ERROR_SUCCESS;
+    if (pszValue)
+      MultiByteToWideChar(CP_ACP, 0, pszValue, -1, szValue, MAX_PATH);
 
-    FIXME("SHREGSET_HKCU or SHREGSET_HKLM not supported\n");
-    return ERROR_SUCCESS;
+    return SHRegWriteUSValueW(hUSKey, pszValue ? szValue : NULL, dwType,
+                               pvData, cbData, dwFlags);
 }
 
 /*************************************************************************
@@ -834,28 +933,72 @@ LONG  WINAPI SHRegWriteUSValueA(HUSKEY hUSKey, LPCSTR pszValue, DWORD dwType,
  * See SHRegWriteUSValueA.
  */
 LONG  WINAPI SHRegWriteUSValueW(HUSKEY hUSKey, LPCWSTR pszValue, DWORD dwType,
-                               LPVOID pvData, DWORD cbData, DWORD dwFlags)
+                                LPVOID pvData, DWORD cbData, DWORD dwFlags)
 {
-    HKEY dokey;
+    DWORD dummy;
+    LPSHUSKEY hKey = (LPSHUSKEY)hUSKey;
+    LONG ret = ERROR_SUCCESS;
 
-    TRACE("(%p,%s,%ld,%p,%ld,%ld)\n",
-             hUSKey, debugstr_w(pszValue), dwType, pvData, cbData, dwFlags);
+    TRACE("(%p,%s,%ld,%p,%ld,%ld)\n", hUSKey, debugstr_w(pszValue),
+          dwType, pvData, cbData, dwFlags);
 
-    if ((dwFlags & SHREGSET_FORCE_HKCU) &&
-           (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) {
-       RegSetValueExW(dokey, pszValue, 0, dwType, pvData, cbData);
-    }
+    if (!hUSKey || IsBadWritePtr(hUSKey, sizeof(SHUSKEY)) ||
+        !(dwFlags & (SHREGSET_FORCE_HKCU|SHREGSET_FORCE_HKLM)))
+        return ERROR_INVALID_PARAMETER;
 
-    if ((dwFlags & SHREGSET_FORCE_HKLM) &&
-           (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) {
-       RegSetValueExW(dokey, pszValue, 0, dwType, pvData, cbData);
+    if (dwFlags & (SHREGSET_FORCE_HKCU|SHREGSET_HKCU))
+    {
+        if (!hKey->HKCUkey)
+        {
+            /* Create the key */
+            ret = RegCreateKeyW(hKey->HKCUstart, hKey->lpszPath, &hKey->HKCUkey);
+            TRACE("Creating HKCU key, ret = %ld\n", ret);
+            if (ret && (dwFlags & (SHREGSET_FORCE_HKCU)))
+            {
+                hKey->HKCUkey = 0;
+                return ret;
+            }
+        }
+
+        if (!ret)
+        {
+            if ((dwFlags & SHREGSET_FORCE_HKCU) ||
+                RegQueryValueExW(hKey->HKCUkey, pszValue, NULL, NULL, NULL, &dummy))
+            {
+                /* Doesn't exist or we are forcing: Write value */
+                ret = RegSetValueExW(hKey->HKCUkey, pszValue, 0, dwType, pvData, cbData);
+                TRACE("Writing HKCU value, ret = %ld\n", ret);
+            }
+        }
     }
 
-    if (dwFlags & (SHREGSET_FORCE_HKCU | SHREGSET_FORCE_HKLM))
-       return ERROR_SUCCESS;
+    if (dwFlags & (SHREGSET_FORCE_HKLM|SHREGSET_HKLM))
+    {
+        if (!hKey->HKLMkey)
+        {
+            /* Create the key */
+            ret = RegCreateKeyW(hKey->HKLMstart, hKey->lpszPath, &hKey->HKLMkey);
+            TRACE("Creating HKLM key, ret = %ld\n", ret);
+            if (ret && (dwFlags & (SHREGSET_FORCE_HKLM)))
+            {
+                hKey->HKLMkey = 0;
+                return ret;
+            }
+        }
 
-    FIXME("SHREGSET_HKCU or SHREGSET_HKLM not supported\n");
-    return ERROR_SUCCESS;
+        if (!ret)
+        {
+            if ((dwFlags & SHREGSET_FORCE_HKLM) ||
+                RegQueryValueExW(hKey->HKLMkey, pszValue, NULL, NULL, NULL, &dummy))
+            {
+                /* Doesn't exist or we are forcing: Write value */
+                ret = RegSetValueExW(hKey->HKLMkey, pszValue, 0, dwType, pvData, cbData);
+                TRACE("Writing HKLM value, ret = %ld\n", ret);
+            }
+        }
+    }
+
+    return ret;
 }
 
 /*************************************************************************
@@ -1048,13 +1191,13 @@ DWORD WINAPI SHSetValueA(HKEY hKey, LPCSTR lpszSubKey, LPCSTR lpszValue,
 {
   DWORD dwRet = ERROR_SUCCESS, dwDummy;
   HKEY  hSubKey;
-  char  szEmpty[] = "";
+  static const char  szEmpty[] = { '\0' };
 
   TRACE("(hkey=%p,%s,%s,%ld,%p,%ld)\n", hKey, debugstr_a(lpszSubKey),
           debugstr_a(lpszValue), dwType, pvData, cbData);
 
   if (lpszSubKey && *lpszSubKey)
-    dwRet = RegCreateKeyExA(hKey, lpszSubKey, 0, szEmpty,
+    dwRet = RegCreateKeyExA(hKey, lpszSubKey, 0, (LPSTR)szEmpty,
                             0, KEY_SET_VALUE, NULL, &hSubKey, &dwDummy);
   else
     hSubKey = hKey;
@@ -1077,13 +1220,13 @@ DWORD WINAPI SHSetValueW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue,
 {
   DWORD dwRet = ERROR_SUCCESS, dwDummy;
   HKEY  hSubKey;
-  WCHAR szEmpty[] = { '\0' };
+  static const WCHAR szEmpty[] = { '\0' };
 
   TRACE("(hkey=%p,%s,%s,%ld,%p,%ld)\n", hKey, debugstr_w(lpszSubKey),
         debugstr_w(lpszValue), dwType, pvData, cbData);
 
   if (lpszSubKey && *lpszSubKey)
-    dwRet = RegCreateKeyExW(hKey, lpszSubKey, 0, szEmpty,
+    dwRet = RegCreateKeyExW(hKey, lpszSubKey, 0, (LPWSTR)szEmpty,
                             0, KEY_SET_VALUE, NULL, &hSubKey, &dwDummy);
   else
     hSubKey = hKey;
@@ -1104,8 +1247,8 @@ DWORD WINAPI SHSetValueW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue,
  * RETURNS
  *  The result of calling RegQueryInfoKeyA().
  */
-DWORD WINAPI SHQueryInfoKeyA(HKEY hKey, LPDWORD pwSubKeys, LPDWORD pwSubKeyMax,
-                             LPDWORD pwValues, LPDWORD pwValueMax)
+LONG WINAPI SHQueryInfoKeyA(HKEY hKey, LPDWORD pwSubKeys, LPDWORD pwSubKeyMax,
+                            LPDWORD pwValues, LPDWORD pwValueMax)
 {
   TRACE("(hkey=%p,%p,%p,%p,%p)\n", hKey, pwSubKeys, pwSubKeyMax,
         pwValues, pwValueMax);
@@ -1118,8 +1261,8 @@ DWORD WINAPI SHQueryInfoKeyA(HKEY hKey, LPDWORD pwSubKeys, LPDWORD pwSubKeyMax,
  *
  * See SHQueryInfoKeyA.
  */
-DWORD WINAPI SHQueryInfoKeyW(HKEY hKey, LPDWORD pwSubKeys, LPDWORD pwSubKeyMax,
-                             LPDWORD pwValues, LPDWORD pwValueMax)
+LONG WINAPI SHQueryInfoKeyW(HKEY hKey, LPDWORD pwSubKeys, LPDWORD pwSubKeyMax,
+                            LPDWORD pwValues, LPDWORD pwValueMax)
 {
   TRACE("(hkey=%p,%p,%p,%p,%p)\n", hKey, pwSubKeys, pwSubKeyMax,
         pwValues, pwValueMax);
@@ -1157,12 +1300,12 @@ DWORD WINAPI SHQueryInfoKeyW(HKEY hKey, LPDWORD pwSubKeys, LPDWORD pwSubKeyMax,
  *
  *   REG_EXPAND_SZ:
  *     case-1: the unexpanded string is smaller than the expanded one
- *       subcase-1: the buffer is to small to hold the unexpanded string:
+ *       subcase-1: the buffer is too small to hold the unexpanded string:
  *          function fails and returns the size of the unexpanded string.
  *
- *       subcase-2: buffer is to small to hold the expanded string:
+ *       subcase-2: buffer is too small to hold the expanded string:
  *          the function return success (!!) and the result is truncated
- *         *** This is clearly a error in the native implementation. ***
+ *         *** This is clearly an error in the native implementation. ***
  *
  *     case-2: the unexpanded string is bigger than the expanded one
  *       The buffer must have enough space to hold the unexpanded
@@ -1189,7 +1332,7 @@ DWORD WINAPI SHQueryValueExA( HKEY hKey, LPCSTR lpszValue,
     /* Expand type REG_EXPAND_SZ into REG_SZ */
     LPSTR szData;
 
-    /* If the caller didn't supply a buffer or the buffer is to small we have
+    /* If the caller didn't supply a buffer or the buffer is too small we have
      * to allocate our own
      */
     if ((!pvData) || (dwRet == ERROR_MORE_DATA) )
@@ -1197,7 +1340,7 @@ DWORD WINAPI SHQueryValueExA( HKEY hKey, LPCSTR lpszValue,
       char cNull = '\0';
       nBytesToAlloc = (!pvData || (dwRet == ERROR_MORE_DATA)) ? dwUnExpDataLen : *pcbData;
 
-      szData = (LPSTR) LocalAlloc(GMEM_ZEROINIT, nBytesToAlloc);
+      szData = (LPSTR) LocalAlloc(LMEM_ZEROINIT, nBytesToAlloc);
       RegQueryValueExA (hKey, lpszValue, lpReserved, NULL, (LPBYTE)szData, &nBytesToAlloc);
       dwExpDataLen = ExpandEnvironmentStringsA(szData, &cNull, 1);
       dwUnExpDataLen = max(nBytesToAlloc, dwExpDataLen);
@@ -1205,8 +1348,8 @@ DWORD WINAPI SHQueryValueExA( HKEY hKey, LPCSTR lpszValue,
     }
     else
     {
-      nBytesToAlloc = lstrlenA(pvData) * sizeof (CHAR);
-      szData = (LPSTR) LocalAlloc(GMEM_ZEROINIT, nBytesToAlloc + 1);
+      nBytesToAlloc = (lstrlenA(pvData)+1) * sizeof (CHAR);
+      szData = (LPSTR) LocalAlloc(LMEM_ZEROINIT, nBytesToAlloc );
       lstrcpyA(szData, pvData);
       dwExpDataLen = ExpandEnvironmentStringsA(szData, pvData, *pcbData / sizeof(CHAR));
       if (dwExpDataLen > *pcbData) dwRet = ERROR_MORE_DATA;
@@ -1258,7 +1401,7 @@ DWORD WINAPI SHQueryValueExW(HKEY hKey, LPCWSTR lpszValue,
       WCHAR cNull = '\0';
       nBytesToAlloc = (!pvData || (dwRet == ERROR_MORE_DATA)) ? dwUnExpDataLen : *pcbData;
 
-      szData = (LPWSTR) LocalAlloc(GMEM_ZEROINIT, nBytesToAlloc);
+      szData = (LPWSTR) LocalAlloc(LMEM_ZEROINIT, nBytesToAlloc);
       RegQueryValueExW (hKey, lpszValue, lpReserved, NULL, (LPBYTE)szData, &nBytesToAlloc);
       dwExpDataLen = ExpandEnvironmentStringsW(szData, &cNull, 1);
       dwUnExpDataLen = max(nBytesToAlloc, dwExpDataLen);
@@ -1266,8 +1409,8 @@ DWORD WINAPI SHQueryValueExW(HKEY hKey, LPCWSTR lpszValue,
     }
     else
     {
-      nBytesToAlloc = lstrlenW(pvData) * sizeof(WCHAR);
-      szData = (LPWSTR) LocalAlloc(GMEM_ZEROINIT, nBytesToAlloc + 1);
+      nBytesToAlloc = (lstrlenW(pvData) + 1) * sizeof(WCHAR);
+      szData = (LPWSTR) LocalAlloc(LMEM_ZEROINIT, nBytesToAlloc );
       lstrcpyW(szData, pvData);
       dwExpDataLen = ExpandEnvironmentStringsW(szData, pvData, *pcbData/sizeof(WCHAR) );
       if (dwExpDataLen > *pcbData) dwRet = ERROR_MORE_DATA;
@@ -1299,7 +1442,7 @@ DWORD WINAPI SHQueryValueExW(HKEY hKey, LPCWSTR lpszValue,
  */
 DWORD WINAPI SHDeleteKeyA(HKEY hKey, LPCSTR lpszSubKey)
 {
-  DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
+  DWORD dwRet, dwMaxSubkeyLen = 0, dwSize;
   CHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
   HKEY hSubKey = 0;
 
@@ -1308,8 +1451,8 @@ DWORD WINAPI SHDeleteKeyA(HKEY hKey, LPCSTR lpszSubKey)
   dwRet = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
   if(!dwRet)
   {
-    /* Find how many subkeys there are */
-    dwRet = RegQueryInfoKeyA(hSubKey, NULL, NULL, NULL, &dwKeyCount,
+    /* Find the maximum subkey length so that we can allocate a buffer */
+    dwRet = RegQueryInfoKeyA(hSubKey, NULL, NULL, NULL, NULL,
                              &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
     if(!dwRet)
     {
@@ -1322,14 +1465,15 @@ DWORD WINAPI SHDeleteKeyA(HKEY hKey, LPCSTR lpszSubKey)
         dwRet = ERROR_NOT_ENOUGH_MEMORY;
       else
       {
-        /* Recursively delete all the subkeys */
-        for(i = 0; i < dwKeyCount && !dwRet; i++)
+        while (dwRet == ERROR_SUCCESS)
         {
           dwSize = dwMaxSubkeyLen;
-          dwRet = RegEnumKeyExA(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
-          if(!dwRet)
+          dwRet = RegEnumKeyExA(hSubKey, 0, lpszName, &dwSize, NULL, NULL, NULL, NULL);
+          if (dwRet == ERROR_SUCCESS || dwRet == ERROR_MORE_DATA)
             dwRet = SHDeleteKeyA(hSubKey, lpszName);
         }
+        if (dwRet == ERROR_NO_MORE_ITEMS)
+          dwRet = ERROR_SUCCESS;
         if (lpszName != szNameBuf)
           HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
       }
@@ -1593,8 +1737,8 @@ DWORD WINAPI SHDeleteValueW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue)
  *   Success: ERROR_SUCCESS. lpszSubKey and pwLen are updated.
  *   Failure: An error code from RegEnumKeyExA().
  */
-DWORD WINAPI SHEnumKeyExA(HKEY hKey, DWORD dwIndex, LPSTR lpszSubKey,
-                          LPDWORD pwLen)
+LONG WINAPI SHEnumKeyExA(HKEY hKey, DWORD dwIndex, LPSTR lpszSubKey,
+                         LPDWORD pwLen)
 {
   TRACE("(hkey=%p,%ld,%s,%p)\n", hKey, dwIndex, debugstr_a(lpszSubKey), pwLen);
 
@@ -1606,8 +1750,8 @@ DWORD WINAPI SHEnumKeyExA(HKEY hKey, DWORD dwIndex, LPSTR lpszSubKey,
  *
  * See SHEnumKeyExA.
  */
-DWORD WINAPI SHEnumKeyExW(HKEY hKey, DWORD dwIndex, LPWSTR lpszSubKey,
-                          LPDWORD pwLen)
+LONG WINAPI SHEnumKeyExW(HKEY hKey, DWORD dwIndex, LPWSTR lpszSubKey,
+                         LPDWORD pwLen)
 {
   TRACE("(hkey=%p,%ld,%s,%p)\n", hKey, dwIndex, debugstr_w(lpszSubKey), pwLen);
 
@@ -1632,9 +1776,9 @@ DWORD WINAPI SHEnumKeyExW(HKEY hKey, DWORD dwIndex, LPWSTR lpszSubKey,
  *   Success: ERROR_SUCCESS. Output parameters are updated.
  *   Failure: An error code from RegEnumValueA().
  */
-DWORD WINAPI SHEnumValueA(HKEY hKey, DWORD dwIndex, LPSTR lpszValue,
-                          LPDWORD pwLen, LPDWORD pwType,
-                          LPVOID pvData, LPDWORD pcbData)
+LONG WINAPI SHEnumValueA(HKEY hKey, DWORD dwIndex, LPSTR lpszValue,
+                         LPDWORD pwLen, LPDWORD pwType,
+                         LPVOID pvData, LPDWORD pcbData)
 {
   TRACE("(hkey=%p,%ld,%s,%p,%p,%p,%p)\n", hKey, dwIndex,
         debugstr_a(lpszValue), pwLen, pwType, pvData, pcbData);
@@ -1648,9 +1792,9 @@ DWORD WINAPI SHEnumValueA(HKEY hKey, DWORD dwIndex, LPSTR lpszValue,
  *
  * See SHEnumValueA.
  */
-DWORD WINAPI SHEnumValueW(HKEY hKey, DWORD dwIndex, LPWSTR lpszValue,
-                          LPDWORD pwLen, LPDWORD pwType,
-                          LPVOID pvData, LPDWORD pcbData)
+LONG WINAPI SHEnumValueW(HKEY hKey, DWORD dwIndex, LPWSTR lpszValue,
+                         LPDWORD pwLen, LPDWORD pwType,
+                         LPVOID pvData, LPDWORD pcbData)
 {
   TRACE("(hkey=%p,%ld,%s,%p,%p,%p,%p)\n", hKey, dwIndex,
         debugstr_w(lpszValue), pwLen, pwType, pvData, pcbData);
@@ -1833,6 +1977,77 @@ BOOL WINAPI GetMIMETypeSubKeyW(LPCWSTR lpszType, LPWSTR lpszBuffer, DWORD dwLen)
   return FALSE;
 }
 
+/*************************************************************************
+ * @   [SHLWAPI.330]
+ *
+ * Get the file extension for a given Mime type.
+ *
+ * PARAMS
+ *  lpszType [I] Mime type to get the file extension for
+ *  lpExt    [O] Destination for the resulting extension
+ *  iLen     [I] Length of lpExt in characters
+ *
+ * RETURNS
+ *  Success: TRUE. lpExt contains the file extension.
+ *  Failure: FALSE, if any parameter is invalid or the extension cannot be
+ *           retrieved. If iLen > 0, lpExt is set to an empty string.
+ *
+ * NOTES
+ *  - The extension returned in lpExt always has a leading '.' character, even
+ *  if the registry Mime database entry does not.
+ *  - iLen must be long enough for the file extension for this function to succeed.
+ */
+BOOL WINAPI MIME_GetExtensionA(LPCSTR lpszType, LPSTR lpExt, INT iLen)
+{
+  char szSubKey[MAX_PATH];
+  DWORD dwlen = iLen - 1, dwType;
+  BOOL bRet = FALSE;
+
+  if (iLen > 0 && lpExt)
+    *lpExt = '\0';
+
+  if (lpszType && lpExt && iLen > 2 &&
+      GetMIMETypeSubKeyA(lpszType, szSubKey, MAX_PATH) &&
+      !SHGetValueA(HKEY_CLASSES_ROOT, szSubKey, szExtensionA, &dwType, lpExt + 1, &dwlen) &&
+      lpExt[1])
+  {
+    if (lpExt[1] == '.')
+      memmove(lpExt, lpExt + 1, strlen(lpExt + 1) + 1);
+    else
+      *lpExt = '.'; /* Supply a '.' */
+    bRet = TRUE;
+  }
+  return bRet;
+}
+
+/*************************************************************************
+ * @   [SHLWAPI.331]
+ *
+ * Unicode version of MIME_GetExtensionA.
+ */
+BOOL WINAPI MIME_GetExtensionW(LPCWSTR lpszType, LPWSTR lpExt, INT iLen)
+{
+  WCHAR szSubKey[MAX_PATH];
+  DWORD dwlen = iLen - 1, dwType;
+  BOOL bRet = FALSE;
+
+  if (iLen > 0 && lpExt)
+    *lpExt = '\0';
+
+  if (lpszType && lpExt && iLen > 2 &&
+      GetMIMETypeSubKeyW(lpszType, szSubKey, MAX_PATH) &&
+      !SHGetValueW(HKEY_CLASSES_ROOT, szSubKey, szExtensionW, &dwType, lpExt + 1, &dwlen) &&
+      lpExt[1])
+  {
+    if (lpExt[1] == '.')
+      memmove(lpExt, lpExt + 1, (strlenW(lpExt + 1) + 1) * sizeof(WCHAR));
+    else
+      *lpExt = '.'; /* Supply a '.' */
+    bRet = TRUE;
+  }
+  return bRet;
+}
+
 /*************************************************************************
  * @   [SHLWAPI.324]
  *
@@ -1967,9 +2182,9 @@ HKEY WINAPI SHRegDuplicateHKey(HKEY hKey)
  * Copy a key and its values/sub keys to another location.
  *
  * PARAMS
- *  hKeyDst    [I] Destination key
- *  lpszSubKey [I] Sub key under hKeyDst, or NULL to use hKeyDst directly
  *  hKeySrc    [I] Source key to copy from
+ *  lpszSrcSubKey [I] Sub key under hKeySrc, or NULL to use hKeySrc directly
+ *  hKeyDst    [I] Destination key
  *  dwReserved [I] Reserved, must be 0
  *
  * RETURNS
@@ -1981,16 +2196,16 @@ HKEY WINAPI SHRegDuplicateHKey(HKEY hKey)
  *  (It will loop until out of stack, or the registry is full). This
  *  bug is present in Win32 also.
  */
-DWORD WINAPI SHCopyKeyA(HKEY hKeyDst, LPCSTR lpszSubKey, HKEY hKeySrc, DWORD dwReserved)
+DWORD WINAPI SHCopyKeyA(HKEY hKeySrc, LPCSTR lpszSrcSubKey, HKEY hKeyDst, DWORD dwReserved)
 {
   WCHAR szSubKeyW[MAX_PATH];
 
-  TRACE("(hkey=%p,%s,%p08x,%ld)\n", hKeyDst, debugstr_a(lpszSubKey), hKeySrc, dwReserved);
+  TRACE("(hkey=%p,%s,%p08x,%ld)\n", hKeySrc, debugstr_a(lpszSrcSubKey), hKeyDst, dwReserved);
 
-  if (lpszSubKey)
-    MultiByteToWideChar(0, 0, lpszSubKey, -1, szSubKeyW, MAX_PATH);
+  if (lpszSrcSubKey)
+    MultiByteToWideChar(0, 0, lpszSrcSubKey, -1, szSubKeyW, MAX_PATH);
 
-  return SHCopyKeyW(hKeyDst, lpszSubKey ? szSubKeyW : NULL, hKeySrc, dwReserved);
+  return SHCopyKeyW(hKeySrc, lpszSrcSubKey ? szSubKeyW : NULL, hKeyDst, dwReserved);
 }
 
 /*************************************************************************
@@ -1998,7 +2213,7 @@ DWORD WINAPI SHCopyKeyA(HKEY hKeyDst, LPCSTR lpszSubKey, HKEY hKeySrc, DWORD dwR
  *
  * See SHCopyKeyA.
  */
-DWORD WINAPI SHCopyKeyW(HKEY hKeyDst, LPCWSTR lpszSubKey, HKEY hKeySrc, DWORD dwReserved)
+DWORD WINAPI SHCopyKeyW(HKEY hKeySrc, LPCWSTR lpszSrcSubKey, HKEY hKeyDst, DWORD dwReserved)
 {
   DWORD dwKeyCount = 0, dwValueCount = 0, dwMaxKeyLen = 0;
   DWORD  dwMaxValueLen = 0, dwMaxDataLen = 0, i;
@@ -2007,18 +2222,18 @@ DWORD WINAPI SHCopyKeyW(HKEY hKeyDst, LPCWSTR lpszSubKey, HKEY hKeySrc, DWORD dw
   WCHAR szName[MAX_PATH], *lpszName = szName;
   DWORD dwRet = S_OK;
 
-  TRACE("hkey=%p,%s,%p08x,%ld)\n", hKeyDst, debugstr_w(lpszSubKey), hKeySrc, dwReserved);
+  TRACE("hkey=%p,%s,%p08x,%ld)\n", hKeySrc, debugstr_w(lpszSrcSubKey), hKeyDst, dwReserved);
 
   if(!hKeyDst || !hKeySrc)
     dwRet = ERROR_INVALID_PARAMETER;
   else
   {
-    /* Open destination key */
-    if(lpszSubKey)
-      dwRet = RegOpenKeyExW(hKeyDst, lpszSubKey, 0, KEY_ALL_ACCESS, &hKeyDst);
+    /* Open source key */
+    if(lpszSrcSubKey)
+      dwRet = RegOpenKeyExW(hKeySrc, lpszSrcSubKey, 0, KEY_ALL_ACCESS, &hKeySrc);
 
     if(dwRet)
-      hKeyDst = 0; /* Don't close this key since we didn't open it */
+      hKeyDst = NULL; /* Don't close this key since we didn't open it */
     else
     {
       /* Get details about sub keys and values */
@@ -2063,7 +2278,7 @@ DWORD WINAPI SHCopyKeyW(HKEY hKeyDst, LPCWSTR lpszSubKey, HKEY hKeySrc, DWORD dw
         if(!dwRet)
         {
           /* Recursively copy keys and values from the sub key */
-          dwRet = SHCopyKeyW(hSubKeyDst, NULL, hSubKeySrc, 0);
+          dwRet = SHCopyKeyW(hSubKeySrc, NULL, hSubKeyDst, 0);
           RegCloseKey(hSubKeyDst);
         }
       }
@@ -2088,7 +2303,7 @@ DWORD WINAPI SHCopyKeyW(HKEY hKeyDst, LPCWSTR lpszSubKey, HKEY hKeySrc, DWORD dw
   if (lpBuff != buff)
     HeapFree(GetProcessHeap(), 0, lpBuff);
 
-  if (lpszSubKey && hKeyDst)
+  if (lpszSrcSubKey && hKeyDst)
     RegCloseKey(hKeyDst);
   return dwRet;
 }
@@ -2113,7 +2328,7 @@ DWORD WINAPI SHCopyKeyW(HKEY hKeyDst, LPCWSTR lpszSubKey, HKEY hKeySrc, DWORD dw
  */
 int WINAPI SHRegGetIntW(HKEY hKey, LPCWSTR lpszValue, int iDefault)
 {
-  TRACE("(%p,%s,%d)", hKey, debugstr_w(lpszValue), iDefault);
+  TRACE("(%p,%s,%d)\n", hKey, debugstr_w(lpszValue), iDefault);
 
   if (hKey)
   {