dlls/userenv: fixed stubs GetUserProfileDirectoryW/A (resend)

Andreas Rosenberg andreas.rosenberg at apis.de
Wed Apr 8 10:07:56 CDT 2009


-------------- next part --------------
From 114fbe9015a9b8f106a6800fb1319e2622b93fe0 Mon Sep 17 00:00:00 2001
From: Andreas.Rosenberg <andreas.rosenberg at apis.de>
Date: Wed, 8 Apr 2009 17:04:08 +0200
Subject: dlls/userenv: fixed stubs GetUserProfileDirectoryW/A

---
 dlls/userenv/Makefile.in     |    2 +-
 dlls/userenv/tests/userenv.c |   60 +++++++++++++++
 dlls/userenv/userenv_main.c  |  170 +++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 227 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..a813472 100644
--- a/dlls/userenv/tests/userenv.c
+++ b/dlls/userenv/tests/userenv.c
@@ -272,9 +272,69 @@ 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];
+    CHAR ansiBuffer[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);
+    }
+    /* test wide char API */
+    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);
+
+    /* test Ansi API */
+    sizePath = 0;
+    SetLastError(0xDEADBEEF);
+    r = GetUserProfileDirectoryA(htoken, ansiBuffer, &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(ansiBuffer) / sizeof(CHAR);;
+    SetLastError(0xDEADBEEF);
+    r = GetUserProfileDirectoryA(htoken, ansiBuffer, &sizePath);
+    lastError = GetLastError();
+    expect(TRUE,r);
+    expect(sizeExpected, lstrlenA(ansiBuffer)+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..c56e988 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);
+
+    if ( lpcchSize && lpProfileDir )
+    {
+        wBufLen = *lpcchSize;
+        bufW = HeapAlloc( GetProcessHeap(), 0, wBufLen * sizeof( WCHAR ) );
+    }
+    else
+    {
+        wBufLen = 0;
+    }
+    res = GetUserProfileDirectoryW( hToken, bufW, &wBufLen );
+    if ( res )
+    {
+        WideCharToMultiByte( CP_ACP, 0, bufW, -1, lpProfileDir,
+                                      wBufLen, NULL, NULL );
+        *lpcchSize = wBufLen;
+    }
+    else
+    {
+        if ( lpcchSize )
+            *lpcchSize = wBufLen;
+    }
+
+    HeapFree( GetProcessHeap(), 0, bufW );
+    return res;
 }
 
+/*  _GetAccountNameFromTokenW retrieves the account name for a given token.
+    Is intended for use by GetUserProfileDirectoryW.
+    Currently not called, because LookupAccountSidW returns nothing usable.*/
+
+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



More information about the wine-patches mailing list