Implementation and test for SHCopyKeyA/W.
This commit is contained in:
parent
2b54cf91fc
commit
f5b34b5b69
|
@ -1792,3 +1792,135 @@ HKEY WINAPI SHRegDuplicateHKey(HKEY hKey)
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -705,8 +705,8 @@ init SHLWAPI_LibMain
|
|||
@ 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
|
||||
|
|
|
@ -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 @@ static void create_test_entrys(void)
|
|||
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 @@ static void test_SHGetValue(void)
|
|||
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 @@ static void test_SHQUeryValueEx(void)
|
|||
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 @@ static void test_SHQUeryValueEx(void)
|
|||
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();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue