Hiya, Merging part 4. <question> Does anyone object to my moving SHLWAPI_1 & 2 into url.c and moving out the definitions from ordinal.h in there as well? I want to tidy this up because at some point in the not too distant future the ordinal code will get a lot bigger. So it makes sense to me to implement ordinals that are related in the same files (like the MIME ord. functions in url.c), and to split out other ord. groups (gdi/windows/com/ie/perfmon etc) into their own files as well. OK? </question> Cheers, Jon License: X11 ChangeLog: Jon Griffiths <jon_p_griffiths@yahoo.com> +dlls/shlwapi/reg.c,dlls/shlwapi/shlwapi.spec,dlls/shlwapi/test/shreg.c Implementation and test for SHCopyKeyA/W +dlls/shlwapi/url.c Trivial - Make hex digits static const & share them
diff -ur wine/dlls/shlwapi/reg.c wine-develop/dlls/shlwapi/reg.c --- wine/dlls/shlwapi/reg.c Tue Sep 10 21:44:26 2002 +++ wine-develop/dlls/shlwapi/reg.c Fri Sep 13 00:59:10 2002 @@ -1792,3 +1792,135 @@ TRACE("new key is %08x\n", newKey); return newKey; } + + +/************************************************************************* + * SHCopyKeyA [SHLWAPI.@] + * + * 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 + * dwReserved [I] Reserved, must be 0 + * + * RETURNS + * Success: ERROR_SUCCESS. The key is copied to the destination key. + * Failure: A standard windows error code. + * + * NOTES + * If hKeyDst is a key under hKeySrc, this function will misbehave + * (It will loop until out of stack, or the registry is full). + */ +DWORD WINAPI SHCopyKeyA(HKEY hKeyDst, LPCSTR lpszSubKey, HKEY hKeySrc, DWORD dwReserved) +{ + WCHAR szSubKeyW[MAX_PATH]; + + TRACE("(hkey=0x%08x,%s,%0x08x,%ld)\n", hKeyDst, debugstr_a(lpszSubKey), hKeySrc, dwReserved); + + if (lpszSubKey) + MultiByteToWideChar(0, 0, lpszSubKey, -1, szSubKeyW, MAX_PATH); + + return SHCopyKeyW(hKeyDst, lpszSubKey ? szSubKeyW : NULL, hKeySrc, dwReserved); +} + +/************************************************************************* + * SHCopyKeyW [SHLWAPI.@] + * + * See SHCopyKeyA. + */ +DWORD WINAPI SHCopyKeyW(HKEY hKeyDst, LPCWSTR lpszSubKey, HKEY hKeySrc, DWORD dwReserved) +{ + DWORD dwKeyCount = 0, dwValueCount = 0, dwMaxKeyLen = 0; + DWORD dwMaxValueLen = 0, dwMaxDataLen = 0, i; + BYTE buff[1024]; + LPVOID lpBuff = (LPVOID)buff; + WCHAR szName[MAX_PATH], *lpszName = szName; + DWORD dwRet = S_OK; + + TRACE("hkey=0x%08x,%s,%0x08x,%ld)\n", hKeyDst, debugstr_w(lpszSubKey), hKeySrc, dwReserved); + + if(!hKeyDst || !hKeySrc) + dwRet = ERROR_INVALID_PARAMETER; + else + { + /* Open destination key */ + if(lpszSubKey) + dwRet = RegOpenKeyExW(hKeyDst, lpszSubKey, 0, KEY_ALL_ACCESS, &hKeyDst); + + if(dwRet) + hKeyDst = 0; /* Don't close this key since we didn't open it */ + else + { + /* Get details about sub keys and values */ + dwRet = RegQueryInfoKeyW(hKeySrc, NULL, NULL, NULL, &dwKeyCount, &dwMaxKeyLen, + NULL, &dwValueCount, &dwMaxValueLen, &dwMaxDataLen, + NULL, NULL); + if(!dwRet) + { + if (dwMaxValueLen > dwMaxKeyLen) + dwMaxKeyLen = dwMaxValueLen; /* Get max size for key/value names */ + + if (dwMaxKeyLen++ > MAX_PATH - 1) + lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxKeyLen * sizeof(WCHAR)); + + if (dwMaxDataLen > sizeof(buff)) + lpBuff = HeapAlloc(GetProcessHeap(), 0, dwMaxDataLen); + + if (!lpszName || !lpBuff) + dwRet = ERROR_NOT_ENOUGH_MEMORY; + } + } + } + + /* Copy all the sub keys */ + for(i = 0; i < dwKeyCount && !dwRet; i++) + { + HKEY hSubKeySrc, hSubKeyDst; + DWORD dwSize = dwMaxKeyLen; + + dwRet = RegEnumKeyExW(hKeySrc, i, lpszName, &dwSize, NULL, NULL, NULL, NULL); + + if(!dwRet) + { + /* Open source sub key */ + dwRet = RegOpenKeyExW(hKeySrc, lpszName, 0, KEY_READ, &hSubKeySrc); + + if(!dwRet) + { + /* Create destination sub key */ + dwRet = RegCreateKeyW(hKeyDst, lpszName, &hSubKeyDst); + + if(!dwRet) + { + /* Recursively copy keys and values from the sub key */ + dwRet = SHCopyKeyW(hSubKeyDst, NULL, hSubKeySrc, 0); + RegCloseKey(hSubKeyDst); + } + } + RegCloseKey(hSubKeySrc); + } + } + + /* Copy all the values in this key */ + for (i = 0; i < dwValueCount && !dwRet; i++) + { + DWORD dwNameSize = dwMaxKeyLen, dwType, dwLen = dwMaxDataLen; + + dwRet = RegEnumValueW(hKeySrc, i, lpszName, &dwNameSize, NULL, &dwType, buff, &dwLen); + + if (!dwRet) + dwRet = SHSetValueW(hKeyDst, NULL, lpszName, dwType, lpBuff, dwLen); + } + + /* Free buffers if allocated */ + if (lpszName != szName) + HeapFree(GetProcessHeap(), 0, lpszName); + if (lpBuff != buff) + HeapFree(GetProcessHeap(), 0, lpBuff); + + if (lpszSubKey && hKeyDst) + RegCloseKey(hKeyDst); + return dwRet; +} diff -ur wine/dlls/shlwapi/shlwapi.spec wine-develop/dlls/shlwapi/shlwapi.spec --- wine/dlls/shlwapi/shlwapi.spec Tue Sep 10 21:44:26 2002 +++ wine-develop/dlls/shlwapi/shlwapi.spec Tue Sep 10 23:08:57 2002 @@ -705,8 +705,8 @@ @ stdcall PathUndecorateW(wstr) PathUndecorateW @ stub PathUnExpandEnvStringsA @ stub PathUnExpandEnvStringsW -@ stub SHCopyKeyA -@ stub SHCopyKeyW +@ stdcall SHCopyKeyA(long str long long) SHCopyKeyA +@ stdcall SHCopyKeyW(long wstr long long) SHCopyKeyW @ stub SHAutoComplete @ stdcall SHCreateStreamOnFileA(str long ptr) SHCreateStreamOnFileA @ stdcall SHCreateStreamOnFileW(wstr long ptr) SHCreateStreamOnFileW diff -ur wine/dlls/shlwapi/tests/shreg.c wine-develop/dlls/shlwapi/tests/shreg.c --- wine/dlls/shlwapi/tests/shreg.c Sun Aug 11 17:22:24 2002 +++ wine-develop/dlls/shlwapi/tests/shreg.c Fri Sep 13 00:38:53 2002 @@ -28,6 +28,10 @@ #include "winuser.h" #include "shlwapi.h" +// Keys used for testing +#define REG_TEST_KEY "Software\\Wine\\Test" +#define REG_CURRENT_VERSION "Software\\Microsoft\\Windows NT\\CurrentVersion" + static char * sTestpath1 = "%LONGSYSTEMVAR%\\subdir1"; static char * sTestpath2 = "%FOO%\\subdir1"; @@ -45,7 +49,7 @@ SetEnvironmentVariableA("LONGSYSTEMVAR", "bar"); SetEnvironmentVariableA("FOO", "ImARatherLongButIndeedNeededString"); - ok(!RegCreateKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Test", &hKey), "RegCreateKeyA failed"); + ok(!RegCreateKeyA(HKEY_CURRENT_USER, REG_TEST_KEY, &hKey), "RegCreateKeyA failed"); if (hKey) { @@ -71,24 +75,24 @@ strcpy(buf, sEmptyBuffer); dwSize = MAX_PATH; dwType = -1; - ok(! SHGetValueA(HKEY_CURRENT_USER, "Software\\Wine\\Test", "Test1", &dwType, buf, &dwSize), "SHGetValueA failed"); + ok(! SHGetValueA(HKEY_CURRENT_USER, REG_TEST_KEY, "Test1", &dwType, buf, &dwSize), "SHGetValueA failed"); ok( 0 == strcmp(sExpTestpath1, buf), "(%s,%s)", buf, sExpTestpath1); ok( REG_SZ == dwType, "(%lx)", dwType); strcpy(buf, sEmptyBuffer); dwSize = MAX_PATH; dwType = -1; - ok(! SHGetValueA(HKEY_CURRENT_USER, "Software\\Wine\\Test", "Test2", &dwType, buf, &dwSize), "SHGetValueA failed"); + ok(! SHGetValueA(HKEY_CURRENT_USER, REG_TEST_KEY, "Test2", &dwType, buf, &dwSize), "SHGetValueA failed"); ok( 0 == strcmp(sTestpath1, buf) , "(%s)", buf); ok( REG_SZ == dwType , "(%lx)", dwType); } -static void test_SHGetTegPath(void) +static void test_SHGetRegPath(void) { char buf[MAX_PATH]; strcpy(buf, sEmptyBuffer); - ok(! SHRegGetPathA(HKEY_CURRENT_USER, "Software\\Wine\\Test", "Test1", buf, 0), "SHRegGetPathA failed"); + ok(! SHRegGetPathA(HKEY_CURRENT_USER, REG_TEST_KEY, "Test1", buf, 0), "SHRegGetPathA failed"); ok( 0 == strcmp(sExpTestpath1, buf) , "(%s)", buf); } @@ -103,7 +107,7 @@ int nUsedBuffer1; int nUsedBuffer2; - ok(! RegOpenKeyExA(HKEY_CURRENT_USER, "Software\\Wine\\Test", 0, KEY_QUERY_VALUE, &hKey), "test4 RegOpenKey"); + ok(! RegOpenKeyExA(HKEY_CURRENT_USER, REG_TEST_KEY, 0, KEY_QUERY_VALUE, &hKey), "test4 RegOpenKey"); /****** SHQueryValueExA ******/ @@ -189,10 +193,59 @@ RegCloseKey(hKey); } + +static void test_SHCopyKey(void) +{ + HKEY hKeySrc, hKeyDst; + + // Delete existing destination sub keys + hKeyDst = (HKEY)0; + if (!RegOpenKeyA(HKEY_CURRENT_USER, REG_TEST_KEY "\\CopyDestination", &hKeyDst) && hKeyDst) + { + SHDeleteKeyA(hKeyDst, NULL); + RegCloseKey(hKeyDst); + } + + hKeyDst = (HKEY)0; + if (RegCreateKeyA(HKEY_CURRENT_USER, REG_TEST_KEY "\\CopyDestination", &hKeyDst) || !hKeyDst) + { + ok(0, "didn't open dest"); + return; + } + + hKeySrc = (HKEY)0; + if (RegOpenKeyA(HKEY_LOCAL_MACHINE, REG_CURRENT_VERSION, &hKeySrc) || !hKeySrc) + { + ok(0, "didn't open source"); + return; + } + + + ok (!SHCopyKeyA(hKeyDst, NULL, hKeySrc, 0), "failed copy"); + + RegCloseKey(hKeySrc); + RegCloseKey(hKeyDst); + + /* Check we copied the sub keys, i.e. AeDebug from the default wine registry */ + hKeyDst = (HKEY)0; + if (RegOpenKeyA(HKEY_CURRENT_USER, REG_TEST_KEY "\\CopyDestination\\AeDebug", &hKeyDst) || !hKeyDst) + { + ok(0, "didn't open copy"); + return; + } + + /* And the we copied the values too */ + ok(!SHQueryValueExA(hKeyDst, "Debugger", NULL, NULL, NULL, NULL), "SHQueryValueExA failed"); + + RegCloseKey(hKeyDst); +} + + START_TEST(shreg) { create_test_entrys(); test_SHGetValue(); test_SHQUeryValueEx(); - test_SHGetTegPath(); + test_SHGetRegPath(); + test_SHCopyKey(); } diff -ur wine/dlls/shlwapi/url.c wine-develop/dlls/shlwapi/url.c --- wine/dlls/shlwapi/url.c Thu Aug 29 11:14:14 2002 +++ wine-develop/dlls/shlwapi/url.c Sun Sep 8 20:43:19 2002 @@ -56,6 +56,8 @@ USERPASS, } WINE_URL_SCAN_TYPE; +static const CHAR hexDigits[] = "0123456789ABCDEF"; + static const WCHAR fileW[] = {'f','i','l','e','\0'}; static const unsigned char HashDataLookup[256] = { @@ -730,7 +732,6 @@ DWORD needed = 0, ret; BOOL stop_escaping = FALSE; char next[3], *dst = pszEscaped; - char hex[] = "0123456789ABCDEF"; INT len; TRACE("(%s %p %p 0x%08lx)\n", debugstr_a(pszUrl), pszEscaped, @@ -762,8 +763,8 @@ if(URL_NeedEscapeA(*src, dwFlags) && stop_escaping == FALSE) { /* TRACE("escaping %c\n", *src); */ next[0] = '%'; - next[1] = hex[(*src >> 4) & 0xf]; - next[2] = hex[*src & 0xf]; + next[1] = hexDigits[(*src >> 4) & 0xf]; + next[2] = hexDigits[*src & 0xf]; len = 3; } else { /* TRACE("passing %c\n", *src); */ @@ -804,7 +805,6 @@ DWORD needed = 0, ret; BOOL stop_escaping = FALSE; WCHAR next[5], *dst = pszEscaped; - CHAR hex[] = "0123456789ABCDEF"; INT len; TRACE("(%s %p %p 0x%08lx)\n", debugstr_w(pszUrl), pszEscaped, @@ -846,14 +846,14 @@ * the character with 4 hex digits (or even 8), * however, experiments show that native shlwapi escapes * with only 2 hex digits. - * next[1] = hex[(*src >> 12) & 0xf]; - * next[2] = hex[(*src >> 8) & 0xf]; - * next[3] = hex[(*src >> 4) & 0xf]; - * next[4] = hex[*src & 0xf]; + * next[1] = hexDigits[(*src >> 12) & 0xf]; + * next[2] = hexDigits[(*src >> 8) & 0xf]; + * next[3] = hexDigits[(*src >> 4) & 0xf]; + * next[4] = hexDigits[*src & 0xf]; * len = 5; */ - next[1] = hex[(*src >> 4) & 0xf]; - next[2] = hex[*src & 0xf]; + next[1] = hexDigits[(*src >> 4) & 0xf]; + next[2] = hexDigits[*src & 0xf]; len = 3; } else { /* TRACE("passing %c\n", *src); */