shlwapi: Implement PathUnExpandEnvStrings.
This commit is contained in:
parent
c1a5b06d49
commit
7513b58329
|
@ -58,6 +58,21 @@ static fnpIsNetDrive pIsNetDrive;
|
|||
|
||||
HRESULT WINAPI SHGetWebFolderFilePathW(LPCWSTR,LPWSTR,DWORD);
|
||||
|
||||
static inline WCHAR* heap_strdupAtoW(LPCSTR str)
|
||||
{
|
||||
WCHAR *ret = NULL;
|
||||
|
||||
if (str)
|
||||
{
|
||||
DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
|
||||
ret = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
|
||||
if (ret)
|
||||
MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* PathAppendA [SHLWAPI.@]
|
||||
*
|
||||
|
@ -4040,18 +4055,61 @@ VOID WINAPI PathUndecorateW(LPWSTR lpszPath)
|
|||
* strings.
|
||||
*
|
||||
* PARAMS
|
||||
* pszPath [I] Buffer containing the path to unexpand.
|
||||
* pszBuf [O] Buffer to receive the unexpanded path.
|
||||
* cchBuf [I] Size of pszBuf in characters.
|
||||
* path [I] Buffer containing the path to unexpand.
|
||||
* buffer [O] Buffer to receive the unexpanded path.
|
||||
* buf_len [I] Size of pszBuf in characters.
|
||||
*
|
||||
* RETURNS
|
||||
* Success: TRUE
|
||||
* Failure: FALSE
|
||||
*/
|
||||
BOOL WINAPI PathUnExpandEnvStringsA(LPCSTR pszPath, LPSTR pszBuf, UINT cchBuf)
|
||||
BOOL WINAPI PathUnExpandEnvStringsA(LPCSTR path, LPSTR buffer, UINT buf_len)
|
||||
{
|
||||
FIXME("(%s,%s,0x%08x)\n", debugstr_a(pszPath), debugstr_a(pszBuf), cchBuf);
|
||||
return FALSE;
|
||||
WCHAR bufferW[MAX_PATH], *pathW;
|
||||
DWORD len;
|
||||
BOOL ret;
|
||||
|
||||
TRACE("(%s, %p, %d)\n", debugstr_a(path), buffer, buf_len);
|
||||
|
||||
pathW = heap_strdupAtoW(path);
|
||||
if (!pathW) return FALSE;
|
||||
|
||||
ret = PathUnExpandEnvStringsW(pathW, bufferW, MAX_PATH);
|
||||
HeapFree(GetProcessHeap(), 0, pathW);
|
||||
if (!ret) return FALSE;
|
||||
|
||||
len = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
|
||||
if (buf_len < len + 1) return FALSE;
|
||||
|
||||
WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, buf_len, NULL, NULL);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static const WCHAR allusersprofileW[] = {'%','A','L','L','U','S','E','R','S','P','R','O','F','I','L','E','%',0};
|
||||
static const WCHAR appdataW[] = {'%','A','P','P','D','A','T','A','%',0};
|
||||
static const WCHAR computernameW[] = {'%','C','O','M','P','U','T','E','R','N','A','M','E','%',0};
|
||||
static const WCHAR programfilesW[] = {'%','P','r','o','g','r','a','m','F','i','l','e','s','%',0};
|
||||
static const WCHAR systemrootW[] = {'%','S','y','s','t','e','m','R','o','o','t','%',0};
|
||||
static const WCHAR systemdriveW[] = {'%','S','y','s','t','e','m','D','r','i','v','e','%',0};
|
||||
static const WCHAR userprofileW[] = {'%','U','S','E','R','P','R','O','F','I','L','E','%',0};
|
||||
|
||||
struct envvars_map
|
||||
{
|
||||
const WCHAR *var;
|
||||
UINT varlen;
|
||||
WCHAR path[MAX_PATH];
|
||||
DWORD len;
|
||||
};
|
||||
|
||||
static void init_envvars_map(struct envvars_map *map)
|
||||
{
|
||||
while (map->var)
|
||||
{
|
||||
map->len = ExpandEnvironmentStringsW(map->var, map->path, sizeof(map->path)/sizeof(WCHAR));
|
||||
/* exclude null from length */
|
||||
if (map->len) map->len--;
|
||||
map++;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
|
@ -4059,10 +4117,51 @@ BOOL WINAPI PathUnExpandEnvStringsA(LPCSTR pszPath, LPSTR pszBuf, UINT cchBuf)
|
|||
*
|
||||
* Unicode version of PathUnExpandEnvStringsA.
|
||||
*/
|
||||
BOOL WINAPI PathUnExpandEnvStringsW(LPCWSTR pszPath, LPWSTR pszBuf, UINT cchBuf)
|
||||
BOOL WINAPI PathUnExpandEnvStringsW(LPCWSTR path, LPWSTR buffer, UINT buf_len)
|
||||
{
|
||||
FIXME("(%s,%s,0x%08x)\n", debugstr_w(pszPath), debugstr_w(pszBuf), cchBuf);
|
||||
return FALSE;
|
||||
static struct envvars_map null_var = {NULL, 0, {0}, 0};
|
||||
struct envvars_map *match = &null_var, *cur;
|
||||
struct envvars_map envvars[] = {
|
||||
{ allusersprofileW, sizeof(allusersprofileW)/sizeof(WCHAR) },
|
||||
{ appdataW, sizeof(appdataW)/sizeof(WCHAR) },
|
||||
{ computernameW, sizeof(computernameW)/sizeof(WCHAR) },
|
||||
{ programfilesW, sizeof(programfilesW)/sizeof(WCHAR) },
|
||||
{ systemrootW, sizeof(systemrootW)/sizeof(WCHAR) },
|
||||
{ systemdriveW, sizeof(systemdriveW)/sizeof(WCHAR) },
|
||||
{ userprofileW, sizeof(userprofileW)/sizeof(WCHAR) },
|
||||
{ NULL }
|
||||
};
|
||||
DWORD pathlen;
|
||||
UINT needed;
|
||||
|
||||
TRACE("(%s, %p, %d)\n", debugstr_w(path), buffer, buf_len);
|
||||
|
||||
pathlen = strlenW(path);
|
||||
init_envvars_map(envvars);
|
||||
cur = envvars;
|
||||
while (cur->var)
|
||||
{
|
||||
/* path can't contain expanded value or value wasn't retrieved */
|
||||
if (cur->len == 0 || cur->len > pathlen || strncmpiW(cur->path, path, cur->len))
|
||||
{
|
||||
cur++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cur->len > match->len)
|
||||
match = cur;
|
||||
cur++;
|
||||
}
|
||||
|
||||
/* 'varlen' includes NULL termination char */
|
||||
needed = match->varlen + pathlen - match->len;
|
||||
if (match->len == 0 || needed > buf_len) return FALSE;
|
||||
|
||||
strcpyW(buffer, match->var);
|
||||
strcatW(buffer, &path[match->len]);
|
||||
TRACE("ret %s\n", debugstr_w(buffer));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
|
|
|
@ -34,6 +34,8 @@ static HRESULT (WINAPI *pPathCreateFromUrlA)(LPCSTR, LPSTR, LPDWORD, DWORD);
|
|||
static HRESULT (WINAPI *pPathCreateFromUrlW)(LPCWSTR, LPWSTR, LPDWORD, DWORD);
|
||||
static HRESULT (WINAPI *pPathCreateFromUrlAlloc)(LPCWSTR, LPWSTR*, DWORD);
|
||||
static BOOL (WINAPI *pPathAppendA)(LPSTR, LPCSTR);
|
||||
static BOOL (WINAPI *pPathUnExpandEnvStringsA)(LPCSTR, LPSTR, UINT);
|
||||
static BOOL (WINAPI *pPathUnExpandEnvStringsW)(LPCWSTR, LPWSTR, UINT);
|
||||
|
||||
/* ################ */
|
||||
|
||||
|
@ -1452,7 +1454,136 @@ static void test_PathGetDriveNumber(void)
|
|||
ok(ret == -1, "got %d\n", ret);
|
||||
}
|
||||
|
||||
/* ################ */
|
||||
static void test_PathUnExpandEnvStrings(void)
|
||||
{
|
||||
static const WCHAR sysrootW[] = {'%','S','y','s','t','e','m','R','o','o','t','%',0};
|
||||
static const WCHAR sysdriveW[] = {'%','S','y','s','t','e','m','D','r','i','v','e','%',0};
|
||||
static const WCHAR nonpathW[] = {'p','a','t','h',0};
|
||||
static const char sysrootA[] = "%SystemRoot%";
|
||||
static const char sysdriveA[] = "%SystemDrive%";
|
||||
WCHAR pathW[MAX_PATH], buffW[MAX_PATH], sysdrvW[3];
|
||||
char path[MAX_PATH], buff[MAX_PATH], sysdrvA[3], envvarA[10];
|
||||
BOOL ret;
|
||||
UINT len;
|
||||
|
||||
if (!pPathUnExpandEnvStringsA || !pPathUnExpandEnvStringsW)
|
||||
{
|
||||
win_skip("PathUnExpandEnvStrings not available\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* something that can't be represented with env var */
|
||||
strcpy(path, "somepath_name");
|
||||
strcpy(buff, "xx");
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = pPathUnExpandEnvStringsA(path, buff, sizeof(buff));
|
||||
ok(!ret && GetLastError() == 0xdeadbeef, "got %d, error %d\n", ret, GetLastError());
|
||||
ok(buff[0] == 'x', "wrong return string %s\n", buff);
|
||||
|
||||
len = GetSystemDirectoryA(path, MAX_PATH);
|
||||
ok(len > 0, "failed to get sysdir\n");
|
||||
|
||||
sysdrvA[0] = path[0];
|
||||
strcpy(&sysdrvA[1], ":");
|
||||
|
||||
/* buffer size is not enough */
|
||||
strcpy(buff, "xx");
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = pPathUnExpandEnvStringsA(path, buff, 5);
|
||||
ok(!ret && GetLastError() == 0xdeadbeef, "got %d\n", ret);
|
||||
ok(buff[0] == 'x', "wrong return string %s\n", buff);
|
||||
|
||||
/* buffer size is enough to hold variable name only */
|
||||
strcpy(buff, "xx");
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = pPathUnExpandEnvStringsA(path, buff, sizeof(sysrootA));
|
||||
ok(!ret && GetLastError() == 0xdeadbeef, "got %d, error %d\n", ret, GetLastError());
|
||||
ok(buff[0] == 'x', "wrong return string %s\n", buff);
|
||||
|
||||
/* enough size */
|
||||
buff[0] = 0;
|
||||
ret = pPathUnExpandEnvStringsA(path, buff, sizeof(buff));
|
||||
ok(ret, "got %d\n", ret);
|
||||
ok(!strncmp(buff, sysrootA, sizeof(sysrootA)-1), "wrong return string %s\n", buff);
|
||||
|
||||
/* expanded value occurs multiple times */
|
||||
/* for drive C: it's unexpands it like 'C:C:' -> '%SystemDrive%C:' */
|
||||
buff[0] = 0;
|
||||
strcpy(path, sysdrvA);
|
||||
strcat(path, sysdrvA);
|
||||
ret = pPathUnExpandEnvStringsA(path, buff, sizeof(buff));
|
||||
ok(ret, "got %d\n", ret);
|
||||
/* expected string */
|
||||
strcpy(path, sysdriveA);
|
||||
strcat(path, sysdrvA);
|
||||
ok(!strcmp(buff, path), "wrong unexpanded string %s, expected %s\n", buff, path);
|
||||
|
||||
/* now with altered variable */
|
||||
ret = GetEnvironmentVariableA("SystemDrive", envvarA, sizeof(envvarA));
|
||||
ok(ret, "got %d\n", ret);
|
||||
|
||||
ret = SetEnvironmentVariableA("SystemDrive", "WW");
|
||||
ok(ret, "got %d\n", ret);
|
||||
|
||||
/* variables are not cached */
|
||||
strcpy(path, sysdrvA);
|
||||
strcat(path, sysdrvA);
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = pPathUnExpandEnvStringsA(path, buff, sizeof(buff));
|
||||
ok(!ret && GetLastError() == 0xdeadbeef, "got %d, error %d\n", ret, GetLastError());
|
||||
|
||||
ret = SetEnvironmentVariableA("SystemDrive", envvarA);
|
||||
ok(ret, "got %d\n", ret);
|
||||
|
||||
/* PathUnExpandEnvStringsW */
|
||||
|
||||
/* something that can't be represented with env var */
|
||||
lstrcpyW(pathW, nonpathW);
|
||||
buffW[0] = 'x'; buffW[1] = 0;
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = pPathUnExpandEnvStringsW(pathW, buffW, sizeof(buffW)/sizeof(WCHAR));
|
||||
ok(!ret && GetLastError() == 0xdeadbeef, "got %d, error %d\n", ret, GetLastError());
|
||||
ok(buffW[0] == 'x', "wrong return string %s\n", wine_dbgstr_w(buffW));
|
||||
|
||||
len = GetSystemDirectoryW(pathW, MAX_PATH);
|
||||
ok(len > 0, "failed to get sysdir\n");
|
||||
|
||||
sysdrvW[0] = pathW[0];
|
||||
sysdrvW[1] = ':';
|
||||
sysdrvW[2] = 0;
|
||||
|
||||
/* buffer size is not enough */
|
||||
buffW[0] = 'x'; buffW[1] = 0;
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = pPathUnExpandEnvStringsW(pathW, buffW, 5);
|
||||
ok(!ret && GetLastError() == 0xdeadbeef, "got %d, error %d\n", ret, GetLastError());
|
||||
ok(buffW[0] == 'x', "wrong return string %s\n", wine_dbgstr_w(buffW));
|
||||
|
||||
/* buffer size is enough to hold variable name only */
|
||||
buffW[0] = 'x'; buffW[1] = 0;
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = pPathUnExpandEnvStringsW(pathW, buffW, sizeof(sysrootW)/sizeof(WCHAR));
|
||||
ok(!ret && GetLastError() == 0xdeadbeef, "got %d, error %d\n", ret, GetLastError());
|
||||
ok(buffW[0] == 'x', "wrong return string %s\n", wine_dbgstr_w(buffW));
|
||||
|
||||
/* enough size */
|
||||
buffW[0] = 0;
|
||||
ret = pPathUnExpandEnvStringsW(pathW, buffW, sizeof(buffW)/sizeof(WCHAR));
|
||||
ok(ret, "got %d\n", ret);
|
||||
ok(!memcmp(buffW, sysrootW, sizeof(sysrootW) - sizeof(WCHAR)), "wrong return string %s\n", wine_dbgstr_w(buffW));
|
||||
|
||||
/* expanded value occurs multiple times */
|
||||
/* for drive C: it's unexpands it like 'C:C:' -> '%SystemDrive%C:' */
|
||||
buffW[0] = 0;
|
||||
lstrcpyW(pathW, sysdrvW);
|
||||
lstrcatW(pathW, sysdrvW);
|
||||
ret = pPathUnExpandEnvStringsW(pathW, buffW, sizeof(buff)/sizeof(WCHAR));
|
||||
ok(ret, "got %d\n", ret);
|
||||
/* expected string */
|
||||
lstrcpyW(pathW, sysdriveW);
|
||||
lstrcatW(pathW, sysdrvW);
|
||||
ok(!lstrcmpW(buffW, pathW), "wrong unexpanded string %s, expected %s\n", wine_dbgstr_w(buffW), wine_dbgstr_w(pathW));
|
||||
}
|
||||
|
||||
START_TEST(path)
|
||||
{
|
||||
|
@ -1471,6 +1602,8 @@ START_TEST(path)
|
|||
pPathIsValidCharA = (void*)GetProcAddress(hShlwapi, (LPSTR)455);
|
||||
pPathIsValidCharW = (void*)GetProcAddress(hShlwapi, (LPSTR)456);
|
||||
pPathAppendA = (void*)GetProcAddress(hShlwapi, "PathAppendA");
|
||||
pPathUnExpandEnvStringsA = (void*)GetProcAddress(hShlwapi, "PathUnExpandEnvStringsA");
|
||||
pPathUnExpandEnvStringsW = (void*)GetProcAddress(hShlwapi, "PathUnExpandEnvStringsW");
|
||||
|
||||
test_PathSearchAndQualify();
|
||||
test_PathCreateFromUrl();
|
||||
|
@ -1492,4 +1625,5 @@ START_TEST(path)
|
|||
test_PathCommonPrefixA();
|
||||
test_PathUnquoteSpaces();
|
||||
test_PathGetDriveNumber();
|
||||
test_PathUnExpandEnvStrings();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue