From acb4bf2dc4ecbd56fa54dfcbd8be2b270929d865 Mon Sep 17 00:00:00 2001 From: Andreas.Rosenberg Date: Mon, 30 Mar 2009 10:19:50 +0200 Subject: dlls/userenv: fixed stubs GetUserProfileDirectoryW/A --- dlls/userenv/Makefile.in | 2 +- dlls/userenv/tests/userenv.c | 40 ++++++++++ dlls/userenv/userenv_main.c | 170 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 207 insertions(+), 5 deletions(-) diff --git a/dlls/userenv/Makefile.in b/dlls/userenv/Makefile.in index 07bba8f..4e2f6fd 100644 --- a/dlls/userenv/Makefile.in +++ b/dlls/userenv/Makefile.in @@ -3,7 +3,7 @@ TOPOBJDIR = ../.. SRCDIR = @srcdir@ VPATH = @srcdir@ MODULE = userenv.dll -IMPORTS = kernel32 ntdll +IMPORTS = kernel32 ntdll advapi32 IMPORTLIB = userenv C_SRCS = \ diff --git a/dlls/userenv/tests/userenv.c b/dlls/userenv/tests/userenv.c index d782d2f..98e6b25 100644 --- a/dlls/userenv/tests/userenv.c +++ b/dlls/userenv/tests/userenv.c @@ -272,9 +272,49 @@ static void test_create_env(void) expect(TRUE, r); r = get_env(env[3], "WINE_XYZZY", &st); expect(TRUE, r); + CloseHandle(htok); +} + +void test_profile_dir() +{ + BOOL r; + DWORD lastError, sizePath, sizeExpected; + HANDLE htoken; + WCHAR buffer[MAX_PATH]; + + r = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY|TOKEN_DUPLICATE, &htoken); + expect(TRUE, r); + + if ( 0 ) + { + SetLastError(0xDEADBEEF); + r = GetUserProfileDirectoryW(htoken, NULL, NULL); /* crashes on NT4 */ + lastError = GetLastError(); + expect(FALSE, r); + expect(lastError, ERROR_INVALID_PARAMETER); + } + + sizePath = 0; + SetLastError(0xDEADBEEF); + r = GetUserProfileDirectoryW(htoken, buffer, &sizePath); + lastError = GetLastError(); + expect(FALSE, r); + expect(lastError, ERROR_INSUFFICIENT_BUFFER); + ok(sizePath > 0, "Expected (sizePath>0), got %d\n", sizePath); + + sizeExpected = sizePath; + sizePath = sizeof(buffer) / sizeof(WCHAR);; + SetLastError(0xDEADBEEF); + r = GetUserProfileDirectoryW(htoken, buffer, &sizePath); + lastError = GetLastError(); + expect(TRUE,r); + expect(sizeExpected, lstrlenW(buffer)+1); + expect(0xDEADBEEF, lastError); + CloseHandle(htoken); } START_TEST(userenv) { test_create_env(); + test_profile_dir(); } diff --git a/dlls/userenv/userenv_main.c b/dlls/userenv/userenv_main.c index 1eaaa71..a4e21c9 100644 --- a/dlls/userenv/userenv_main.c +++ b/dlls/userenv/userenv_main.c @@ -27,9 +27,33 @@ #include "winreg.h" #include "winternl.h" #include "userenv.h" +#include "lmcons.h" +#include "winreg.h" +#include "winnls.h" #include "wine/debug.h" +static const WCHAR profile_pathname[] = { + 'S', 'o', 'f', 't', 'w', 'a', 'r', 'e', '\\', + 'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', 't', '\\', + 'W', 'i', 'n', 'd', 'o', 'w', 's', ' ', 'N', 'T', '\\', + 'C', 'u', 'r', 'r', 'e', 'n', 't', 'V', 'e', 'r', 's', 'i', 'o', 'n', '\\', + 'P', 'r', 'o', 'f', 'i', 'l', 'e', 'L', 'i', 's', 't', + 0 }; + +static const WCHAR profile_subkey[] = { + 'P', 'r', 'o', 'f', 'i', 'l', 'e', 'L', 'i', 's', 't', + 0 }; + +static const WCHAR profile_keyname[] = { + 'P', 'r', 'o', 'f', 'i', 'l', 'e', 's', 'D', 'i', 'r','e', 'c', 't', 'o', 'r', 'y', + 0 }; + +static const WCHAR backslash[] = { + '\\', + 0 }; + + WINE_DEFAULT_DEBUG_CHANNEL( userenv ); BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) @@ -92,15 +116,153 @@ BOOL WINAPI ExpandEnvironmentStringsForUserW( HANDLE hToken, LPCWSTR lpSrc, BOOL WINAPI GetUserProfileDirectoryA( HANDLE hToken, LPSTR lpProfileDir, LPDWORD lpcchSize ) { - FIXME("%p %p %p\n", hToken, lpProfileDir, lpcchSize ); - return FALSE; + LPWSTR bufW = NULL; + DWORD wBufLen; + BOOL res; + + TRACE("%p %p %p\n", hToken, lpProfileDir, lpcchSize); + /* profile specific tokens not supported, so hToken ignored */ + + if ( lpcchSize && lpProfileDir ) + { + wBufLen = *lpcchSize; + bufW = HeapAlloc( GetProcessHeap(), 0, wBufLen * sizeof( WCHAR ) ); + } + else + { /* We need this to get the buffer size */ + wBufLen = 0; + } + res = GetUserProfileDirectoryW( hToken, bufW, &wBufLen ); + if ( res ) + { + if ( lpcchSize && lpcchSize ) + { + WideCharToMultiByte( CP_ACP, 0, bufW, -1, lpProfileDir, + wBufLen, NULL, NULL ); + *lpcchSize = wBufLen; + } + else + { /* get the length */ + if ( lpcchSize ) + *lpcchSize = wBufLen; + } + } + + HeapFree( GetProcessHeap(), 0, bufW ); + return res; } +BOOL WINAPI _GetAccountNameFromTokenW( HANDLE hToken, LPWSTR lpUserName, + LPDWORD lpchSize) +{ + BOOL retValue = FALSE; + PTOKEN_USER ptiUser = NULL; + DWORD cbti = 0, cbDomain = 0, cbUser = 0, lastError; + SID_NAME_USE snu; + LPWSTR lpDomain; + + if ( !lpchSize ) + return FALSE; + + /* get size of token user structure, this will modify lastError, + but this function must keep it intact. */ + lastError = GetLastError(); + GetTokenInformation( hToken, TokenUser, NULL, 0, &cbti ); + + ptiUser = (PTOKEN_USER) HeapAlloc( GetProcessHeap(), 0, cbti ); + if ( ptiUser ) + { + if ( GetTokenInformation( hToken, TokenUser, ptiUser, cbti, &cbti ) ) + { + retValue = LookupAccountSidW( NULL, ptiUser->User.Sid, NULL, &cbUser, + NULL, &cbDomain, &snu ); + *lpchSize = cbUser; + if ( lpUserName ) + { + lpDomain = HeapAlloc( GetProcessHeap(), 0, ( cbDomain * sizeof(WCHAR) ) ); + retValue = LookupAccountSidW( NULL, ptiUser->User.Sid, lpUserName, &cbUser, + lpDomain, &cbDomain, &snu ); + HeapFree( GetProcessHeap(), 0, lpDomain ); + } + } + HeapFree( GetProcessHeap(), 0, ptiUser ); + } + /* restore lastError */ + if ( retValue ) + SetLastError(lastError); + + return retValue; +} + + BOOL WINAPI GetUserProfileDirectoryW( HANDLE hToken, LPWSTR lpProfileDir, LPDWORD lpcchSize ) { - FIXME("%p %p %p\n", hToken, lpProfileDir, lpcchSize ); - return FALSE; + WCHAR *pUserName; + LONG res; + DWORD sizePathBytes=0, sizePath=0, sizeName=0, lastError; + HKEY keyProfileDir; + BOOL retValue = FALSE; + + TRACE( "%p %p %p\n", hToken, debugstr_w(lpProfileDir), lpcchSize ); + + if ( !lpcchSize ) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + + lastError = GetLastError(); + res = RegOpenKeyExW( HKEY_LOCAL_MACHINE, profile_pathname, 0L, KEY_QUERY_VALUE, &keyProfileDir ); + if (res == ERROR_SUCCESS ) + { + /* modifies error state */ + res = RegGetValueW( keyProfileDir, NULL, profile_keyname, RRF_RT_ANY, + NULL, NULL, &sizePathBytes ); /* RegGetValue expects pcbData in bytes */ + + if ( res == ERROR_SUCCESS ) + { + sizePath = sizePathBytes / sizeof( WCHAR ); + + /* _GetAccountNameFromTokenW expects lpnSize in chars */ + /* _GetAccountNameFromTokenW is a wrapper for LookupAccountSidW, + which retrieves the user name associated with a process token. + Currently it returns the string 'INTERACTIVE', which is a bug. + If this is fixed, _GetAccountNameFromTokenW may be used + instead of GetUserNameW */ + /* res = _GetAccountNameFromTokenW( hToken, NULL, &sizeName ); */ + + FIXME("LookupAccountSidW broken, using GetUserName instead\n"); + + res = GetUserNameW( NULL, &sizeName ); + if ( res && !lpProfileDir || ( *lpcchSize < sizeName + sizePath ) ) + { + *lpcchSize = sizeName + sizePath; + lastError = ERROR_INSUFFICIENT_BUFFER; + } + else + { + res = RegGetValueW( keyProfileDir, NULL, profile_keyname, RRF_RT_ANY, + NULL, lpProfileDir, &sizePathBytes ); + if ( res == ERROR_SUCCESS ) + { + lstrcatW( lpProfileDir, backslash ); + pUserName = lpProfileDir + sizePath; + /* see comment for LookupAccountSidW above */ + /* res = _GetAccountNameFromTokenW( hToken, pUserName, &sizeName ); */ + res = GetUserNameW( pUserName, &sizeName ); + if ( res ) + { + *lpcchSize = sizeName + sizePath; + retValue = TRUE; + } + } + } + } + RegCloseKey( keyProfileDir ); + } + SetLastError(lastError); + return retValue; } BOOL WINAPI GetProfilesDirectoryA( LPSTR lpProfilesDir, LPDWORD lpcchSize ) -- 1.5.2.4