diff --git a/dlls/userenv/tests/userenv.c b/dlls/userenv/tests/userenv.c index c96b710a2c7..cd81232930c 100644 --- a/dlls/userenv/tests/userenv.c +++ b/dlls/userenv/tests/userenv.c @@ -283,8 +283,112 @@ static void test_get_profiles_dir(void) expect_gle(ERROR_INSUFFICIENT_BUFFER); } +static void test_get_user_profile_dir(void) +{ + BOOL ret; + DWORD error, len; + HANDLE token; + char *dirA; + WCHAR *dirW; + + if (!GetEnvironmentVariableA( "ALLUSERSPROFILE", NULL, 0 )) + { + win_skip("Skipping tests on NT4\n"); + return; + } + + ret = OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &token ); + ok(ret, "expected success %u\n", GetLastError()); + + SetLastError( 0xdeadbeef ); + ret = GetUserProfileDirectoryA( NULL, NULL, NULL ); + error = GetLastError(); + ok(!ret, "expected failure\n"); + ok(error == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %u\n", error); + + SetLastError( 0xdeadbeef ); + ret = GetUserProfileDirectoryA( token, NULL, NULL ); + error = GetLastError(); + ok(!ret, "expected failure\n"); + ok(error == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %u\n", error); + + dirA = HeapAlloc( GetProcessHeap(), 0, 32 ); + SetLastError( 0xdeadbeef ); + ret = GetUserProfileDirectoryA( token, dirA, NULL ); + error = GetLastError(); + ok(!ret, "expected failure\n"); + ok(error == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %u\n", error); + HeapFree( GetProcessHeap(), 0, dirA ); + + len = 0; + SetLastError( 0xdeadbeef ); + ret = GetUserProfileDirectoryA( token, NULL, &len ); + error = GetLastError(); + ok(!ret, "expected failure\n"); + ok(error == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %u\n", error); + ok(!len, "expected 0, got %u\n", len); + + len = 0; + dirA = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 32 ); + SetLastError( 0xdeadbeef ); + ret = GetUserProfileDirectoryA( token, dirA, &len ); + error = GetLastError(); + ok(!ret, "expected failure\n"); + ok(error == ERROR_INSUFFICIENT_BUFFER, "expected ERROR_INSUFFICIENT_BUFFER, got %u\n", error); + ok(len, "expected len > 0\n"); + HeapFree( GetProcessHeap(), 0, dirA ); + + dirA = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, len ); + SetLastError( 0xdeadbeef ); + ret = GetUserProfileDirectoryA( token, dirA, &len ); + ok(ret, "expected success %u\n", GetLastError()); + ok(len, "expected len > 0\n"); + ok(lstrlenA( dirA ) == len - 1, "length mismatch %d != %d - 1\n", lstrlenA( dirA ), len ); + trace("%s\n", dirA); + HeapFree( GetProcessHeap(), 0, dirA ); + + SetLastError( 0xdeadbeef ); + ret = GetUserProfileDirectoryW( NULL, NULL, NULL ); + error = GetLastError(); + ok(!ret, "expected failure\n"); + todo_wine ok(error == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %u\n", error); + + SetLastError( 0xdeadbeef ); + ret = GetUserProfileDirectoryW( token, NULL, NULL ); + error = GetLastError(); + ok(!ret, "expected failure\n"); + ok(error == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %u\n", error); + + dirW = HeapAlloc( GetProcessHeap(), 0, 32 ); + SetLastError( 0xdeadbeef ); + ret = GetUserProfileDirectoryW( token, dirW, NULL ); + error = GetLastError(); + ok(!ret, "expected failure\n"); + ok(error == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %u\n", error); + HeapFree( GetProcessHeap(), 0, dirW ); + + len = 0; + SetLastError( 0xdeadbeef ); + ret = GetUserProfileDirectoryW( token, NULL, &len ); + error = GetLastError(); + ok(!ret, "expected failure\n"); + ok(error == ERROR_INSUFFICIENT_BUFFER, "expected ERROR_INSUFFICIENT_BUFFER, got %u\n", error); + ok(len, "expected len > 0\n"); + + dirW = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR) ); + SetLastError( 0xdeadbeef ); + ret = GetUserProfileDirectoryW( token, dirW, &len ); + ok(ret, "expected success %u\n", GetLastError()); + ok(len, "expected len > 0\n"); + ok(lstrlenW( dirW ) == len - 1, "length mismatch %d != %d - 1\n", lstrlenW( dirW ), len ); + HeapFree( GetProcessHeap(), 0, dirW ); + + CloseHandle( token ); +} + START_TEST(userenv) { test_create_env(); test_get_profiles_dir(); + test_get_user_profile_dir(); } diff --git a/dlls/userenv/userenv_main.c b/dlls/userenv/userenv_main.c index 42044722f5b..6a2a9538bfc 100644 --- a/dlls/userenv/userenv_main.c +++ b/dlls/userenv/userenv_main.c @@ -26,9 +26,11 @@ #include "winbase.h" #include "winreg.h" #include "winternl.h" +#include "winnls.h" #include "userenv.h" #include "wine/debug.h" +#include "wine/unicode.h" WINE_DEFAULT_DEBUG_CHANNEL( userenv ); @@ -115,15 +117,79 @@ BOOL WINAPI GetDefaultUserProfileDirectoryW( LPWSTR lpProfileDir, LPDWORD lpcchS BOOL WINAPI GetUserProfileDirectoryA( HANDLE hToken, LPSTR lpProfileDir, LPDWORD lpcchSize ) { - FIXME("%p %p %p\n", hToken, lpProfileDir, lpcchSize ); - return FALSE; + BOOL ret; + WCHAR *dirW = NULL; + + TRACE( "%p %p %p\n", hToken, lpProfileDir, lpcchSize ); + + if (!lpProfileDir || !lpcchSize) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + if (!(dirW = HeapAlloc( GetProcessHeap(), 0, *lpcchSize * sizeof(WCHAR) ))) + return FALSE; + + if ((ret = GetUserProfileDirectoryW( hToken, dirW, lpcchSize ))) + WideCharToMultiByte( CP_ACP, 0, dirW, *lpcchSize, lpProfileDir, *lpcchSize, NULL, NULL ); + + HeapFree( GetProcessHeap(), 0, dirW ); + return ret; } BOOL WINAPI GetUserProfileDirectoryW( HANDLE hToken, LPWSTR lpProfileDir, LPDWORD lpcchSize ) { - FIXME("%p %p %p\n", hToken, lpProfileDir, lpcchSize ); - return FALSE; + static const WCHAR slashW[] = {'\\',0}; + TOKEN_USER *t; + WCHAR *userW = NULL, *dirW = NULL; + DWORD len, dir_len, domain_len; + SID_NAME_USE use; + BOOL ret = FALSE; + + TRACE( "%p %p %p\n", hToken, lpProfileDir, lpcchSize ); + + if (!lpcchSize) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + + len = 0; + GetTokenInformation( hToken, TokenUser, NULL, 0, &len ); + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE; + if (!(t = HeapAlloc( GetProcessHeap(), 0, len ))) return FALSE; + if (!GetTokenInformation( hToken, TokenUser, t, len, &len )) goto done; + + len = 0; + LookupAccountSidW( NULL, t->User.Sid, NULL, &len, NULL, &domain_len, NULL ); + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) goto done; + if (!(userW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) goto done; + if (!LookupAccountSidW( NULL, t->User.Sid, userW, &len, NULL, &domain_len, &use )) goto done; + + dir_len = 0; + GetProfilesDirectoryW( NULL, &dir_len ); + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) goto done; + if (!(dirW = HeapAlloc( GetProcessHeap(), 0, (dir_len + 1) * sizeof(WCHAR) ))) goto done; + if (!GetProfilesDirectoryW( dirW, &dir_len )) goto done; + + len += dir_len + 2; + if (*lpcchSize < len) + { + SetLastError( ERROR_INSUFFICIENT_BUFFER ); + *lpcchSize = len; + goto done; + } + strcpyW( lpProfileDir, dirW ); + strcatW( lpProfileDir, slashW ); + strcatW( lpProfileDir, userW ); + *lpcchSize = len; + ret = TRUE; + +done: + HeapFree( GetProcessHeap(), 0, userW ); + HeapFree( GetProcessHeap(), 0, dirW ); + return ret; } static const char ProfileListA[] = "Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList";