RFC: HKCR merge implementation

2013-09-10 Thread George Stephanos
I'm proposing my HKEY_CLASSES_ROOT implementation patches for review. Feel
free to comment.
So far, I've written code for all functions except for the RegEnum family.

General description:

HKCR handles are special. All wine handles have the two lowest bits zero'd.
HKCR handles are masked. 10b specifically.
They have their own table separate from the generic handle table.
An HKCR handle has an HKCU handle and an HKLM handle below it. Access mask
and a string representing the path are also needed
since the handle has to attempt to reopen previously failed openings at
certain stages.

First patch: specially handles HKCR handles WITHOUT affecting the general
behavior. The end result is still the exact same. Patch provides a
foundation for the rest.
Second patch: added path management
Third patch: added HKCU

Here's a quick description of each function:

create_hkcr_struct: allocates the memory needed for the struct, adds it to
the table and gives back a pointer to it
get_hkcr_path: given an HKCR handle and a subkey string, prepares a subkey
string representing the same subkey rooted at HKLM/HKCU.
create_hkcr: RegCreateKeyEx
open_hkcr: RegOpenKeyEx
resolve_hkcr: checks the HKCR handle, tries to reopen previously failed
internal handles, gives back HKCU first if available then HKLM
close_hkcr: deallocates path and struct, removes struct from table.
From 09e5a3c2629ddcc795a69f70b0672f393abd96ed Mon Sep 17 00:00:00 2001
From: George Stephanos 
Date: Sat, 24 Aug 2013 20:30:05 +0200
Subject: [PATCH 1/3] advapi32: HKCR merge: foundation

---
 dlls/advapi32/registry.c   | 249 -
 dlls/advapi32/tests/registry.c |   2 +-
 2 files changed, 248 insertions(+), 3 deletions(-)

diff --git a/dlls/advapi32/registry.c b/dlls/advapi32/registry.c
index c01e125..5768272 100644
--- a/dlls/advapi32/registry.c
+++ b/dlls/advapi32/registry.c
@@ -79,6 +79,29 @@ static const WCHAR * const root_key_names[] =
 static HKEY special_root_keys[NB_SPECIAL_ROOT_KEYS];
 static BOOL hkcu_cache_disabled;
 
+typedef struct {
+HKEY  hklm;
+} opened_hkcr_t;
+
+/* ### */
+
+static CRITICAL_SECTION hkcr_handles_cs;
+static CRITICAL_SECTION_DEBUG hkcr_handles_cs_debug =
+{
+0, 0, &hkcr_handles_cs,
+{ &hkcr_handles_cs_debug.ProcessLocksList, 
&hkcr_handles_cs_debug.ProcessLocksList },
+  0, 0, { (DWORD_PTR)(__FILE__ ": hkcr_handles_cs") }
+};
+static CRITICAL_SECTION hkcr_handles_cs = { &hkcr_handles_cs_debug, -1, 0, 0, 
0, 0 };
+
+/* ### */
+
+static opened_hkcr_t **hkcr_handles;
+static UINT nb_hkcr_handles;
+
+#define HKCR_MASK 2
+#define IS_HKCR(hk) ((UINT_PTR)hk > 0 && ((UINT_PTR)hk & 3) == HKCR_MASK)
+
 static const int is_win64 = (sizeof(void *) > sizeof(int));
 
 /* check if value type needs string conversion (Ansi<->Unicode) */
@@ -224,13 +247,138 @@ static NTSTATUS open_key( HKEY *retkey, ACCESS_MASK 
access, OBJECT_ATTRIBUTES *a
 
 }
 
+static LSTATUS create_hkcr_struct( HKEY *hkey, opened_hkcr_t **hkcr )
+{
+UINT_PTR handle = nb_hkcr_handles, i;
+LSTATUS ret = ERROR_SUCCESS;
+
+EnterCriticalSection( &hkcr_handles_cs );
+
+for (i = 0; i < nb_hkcr_handles; i++)
+{
+if (!hkcr_handles[i])
+{
+handle = i;
+break;
+}
+}
+
+if (handle >= nb_hkcr_handles)
+{
+opened_hkcr_t **new_array;
+if (hkcr_handles)
+new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 
hkcr_handles,
+ (nb_hkcr_handles * 2) * 
sizeof(*new_array) );
+else
+new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
+   16 * sizeof(*new_array) );
+
+if (!new_array)
+{
+ret = ERROR_NOT_ENOUGH_MEMORY;
+goto end;
+}
+hkcr_handles = new_array;
+
+nb_hkcr_handles = !nb_hkcr_handles ? 16 : nb_hkcr_handles * 2;
+}
+
+*hkcr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 
sizeof(opened_hkcr_t) );
+
+if (*hkcr)
+{
+hkcr_handles[handle] = *hkcr;
+*hkey = (HKEY)( handle << 2 | HKCR_MASK );
+}
+else ret = ERROR_NOT_ENOUGH_MEMORY;
+
+end:
+LeaveCriticalSection( &hkcr_handles_cs );
+return ret;
+}
+
+static HKEY resolve_hkcr( HKEY hkey )
+{
+HKEY ret;
+UINT_PTR idx = (UINT_PTR)hkey >> 2;
+opened_hkcr_t *hkcr;
+if (idx <= nb_hkcr_handles)
+{
+EnterCriticalSection( &hkcr_handles_cs );
+hkcr = hkcr_handles[idx];
+
+if (!hkcr)
+{
+LeaveCriticalSection( &hkcr_handles_cs );
+return NULL;
+}
+
+ret = hkcr->hklm;
+
+LeaveCriticalSection( &hkcr_handles_cs );
+return ret;
+}
+return NULL;
+}
+
+static LSTATUS WINAPI create_hkcr

Re: RFC: HKCR merge implementation

2013-09-10 Thread George Stephanos
>
>
>> a couple bitwise nits in your first patch:
>
> +#define HKCR_MASK 2
> +#define IS_HKCR(hk) ((UINT_PTR)hk > 0 && ((UINT_PTR)hk & 3) == HKCR_MASK)
>
> Typically a mask would define all the bits that could be set, and a flag
> would be the particular bit you want to test. Something like:
> #define SPECIAL_HKEY_MASK 3
> #define HKCR_FLAG 2
>
> Also, in the following expression:
> ((UINT_PTR)hk > 0 && ((UINT_PTR)hk & 3)
>
> The second can never be true when the first is false, so you can just drop
> the first.
>

How? isn't 0x8003 < 0 && 0x8003 & 3?
I just realized the UINT_PTR cast forces it to be >0 anyway.


> These suggestions yield:
> #define IS_HKCR(hk) (((UINT_PTR)(hk) & SPECIAL_HKEY_MASK) == HKCR_FLAG)
>

Thanks.


> --Juan
>



RFC: HKCR merge implementation

2013-09-10 Thread George Stephanos
I'm proposing my HKEY_CLASSES_ROOT implementation patches for review. Feel
free to comment.
So far, I've written code for all functions except for the RegEnum family.

General description:

HKCR handles are special. All wine handles have the two lowest bits zero'd.
HKCR handles are masked. 10b specifically.
They have their own table separate from the generic handle table.
An HKCR handle has an HKCU handle and an HKLM handle below it. Access mask
and a string representing the path are also needed
since the handle has to attempt to reopen previously failed openings at
certain stages.

First patch: specially handles HKCR handles WITHOUT affecting the general
behavior. The end result is still the exact same. Patch provides a
foundation for the rest.
Second patch: added path management
Third patch: added HKCU

Here's a quick description of each function:

create_hkcr_struct: allocates the memory needed for the struct, adds it to
the table and gives back a pointer to it
get_hkcr_path: given an HKCR handle and a subkey string, prepares a subkey
string representing the same subkey rooted at HKLM/HKCU.
create_hkcr: RegCreateKeyEx
open_hkcr: RegOpenKeyEx
resolve_hkcr: checks the HKCR handle, tries to reopen previously failed
internal handles, gives back HKCU first if available then HKLM
close_hkcr: deallocates path and struct, removes struct from table.

http://pastie.org/8314658
http://pastie.org/8314662
http://pastie.org/8314663



[PATCH] advapi32: RegDeleteKey tests for merged view of HKCR

2013-06-30 Thread George Stephanos
http://newtestbot.winehq.org/JobDetails.pl?Key=1403
---
 dlls/advapi32/tests/registry.c | 21 +
 1 file changed, 21 insertions(+)

diff --git a/dlls/advapi32/tests/registry.c b/dlls/advapi32/tests/registry.c
index 1784118..4e74a07 100644
--- a/dlls/advapi32/tests/registry.c
+++ b/dlls/advapi32/tests/registry.c
@@ -2341,6 +2341,27 @@ static void test_classesroot(void)
 ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", res);
 ok(!strcmp( buffer, "hkcr" ), "value set to '%s'\n", buffer );
 
+/* delete subkey1 from hkcr (should point at user's classes) */
+res = RegDeleteKey(hkcr, "subkey1");
+ok(res == ERROR_SUCCESS, "RegDeleteKey failed: %d\n", res);
+
+/* confirm key was removed in hkey but not hklm */
+res = RegOpenKeyExA(hkey, "subkey1", 0, KEY_READ, &hkeysub1);
+ok(res == ERROR_FILE_NOT_FOUND, "test key found in user's classes: %d\n", 
res);
+RegCloseKey(hkeysub1);
+res = RegOpenKeyExA(hklm, "subkey1", 0, KEY_READ, &hklmsub1);
+ok(res == ERROR_SUCCESS, "test key not found in hklm: %d\n", res);
+RegCloseKey(hklmsub1);
+
+/* delete subkey1 from hkcr again (which should now point at hklm) */
+res = RegDeleteKey(hkcr, "subkey1");
+ok(res == ERROR_SUCCESS, "RegDeleteKey failed: %d\n", res);
+
+/* confirm hkey was removed in hklm */
+res = RegOpenKeyExA(hklm, "subkey1", 0, KEY_READ, &hklmsub1);
+ok(res == ERROR_FILE_NOT_FOUND, "test key found in hklm: %d\n", res);
+RegCloseKey(hklmsub1);
+
 /* final cleanup */
 delete_key( hkey );
 delete_key( hklm );
-- 
1.8.3.msysgit.0





[PATCH] Tests that prove ntdll has no notion of HKCR.

2013-05-21 Thread George Stephanos
As instructed, I added a few lines to the already written tests that
confirm my claim.

Part of the research of the registry merging project was to determine
where the implementation is going to be written: advapi32, ntdll or
the server itself. The server choice was dismissed since HKCR isn't
stored and rather fetched live. These tests prove that advapi32 calls
that reference HKCR are either pointed there to \REGISTRY\MACHINE or
\REGISTRY\USER and hence, that the merge is to be done in advapi32.

http://newtestbot.winehq.org/JobDetails.pl?Key=976
---
 dlls/advapi32/tests/registry.c | 31 ++-
 1 file changed, 30 insertions(+), 1 deletion(-)

diff --git a/dlls/advapi32/tests/registry.c b/dlls/advapi32/tests/registry.c
index b2483a7..ea61471 100644
--- a/dlls/advapi32/tests/registry.c
+++ b/dlls/advapi32/tests/registry.c
@@ -43,6 +43,7 @@ static DWORD (WINAPI *pRegDeleteTreeA)(HKEY,LPCSTR);
 static DWORD (WINAPI *pRegDeleteKeyExA)(HKEY,LPCSTR,REGSAM,DWORD);
 static BOOL (WINAPI *pIsWow64Process)(HANDLE,PBOOL);
 static NTSTATUS (WINAPI * pNtDeleteKey)(HANDLE);
+static NTSTATUS (WINAPI * pNtQueryKey)(HANDLE,int,PVOID,ULONG,PULONG);
 static NTSTATUS (WINAPI * pRtlFormatCurrentUserKeyPath)(UNICODE_STRING*);
 static NTSTATUS (WINAPI * pRtlFreeUnicodeString)(PUNICODE_STRING);
 
@@ -136,6 +137,7 @@ static void InitFunctionPtrs(void)
 pRtlFormatCurrentUserKeyPath = (void *)GetProcAddress( hntdll, 
"RtlFormatCurrentUserKeyPath" );
 pRtlFreeUnicodeString = (void *)GetProcAddress(hntdll, 
"RtlFreeUnicodeString");
 pNtDeleteKey = (void *)GetProcAddress( hntdll, "NtDeleteKey" );
+pNtQueryKey = (void *)GetProcAddress( hntdll, "NtQueryKey" );
 }
 
 /* delete key and all its subkeys */
@@ -2099,10 +2101,12 @@ static void test_redirection(void)
 
 static void test_classesroot(void)
 {
+static const WCHAR reg_user[] = { 
'\\','R','E','G','I','S','T','R','Y','\\','U','S','E','R',0 };
+static const WCHAR reg_machine[] = { 
'\\','R','E','G','I','S','T','R','Y','\\','M','A','C','H','I','N','E',0 };
 HKEY hkey, hklm, hkcr, hkeysub1, hklmsub1, hkcrsub1, hklmsub2, hkcrsub2;
 DWORD size = 8;
 DWORD type = REG_SZ;
-static CHAR buffer[8];
+static CHAR buffer[100*sizeof(WCHAR)];
 LONG res;
 
 /* create a key in the user's classes */
@@ -2132,6 +2136,11 @@ static void test_classesroot(void)
 RegCloseKey( hkey );
 return;
 }
+pNtQueryKey( hkcr, 3 /*KeyNameInformation*/, buffer, 
sizeof(buffer)/sizeof(buffer[0]), (ULONG*)&res );
+todo_wine ok( CompareStringW( LOCALE_INVARIANT, NORM_IGNORECASE, 
+(WCHAR*)(&buffer)+2, sizeof(reg_user)/sizeof(reg_user[0]), 
+reg_user, sizeof(reg_user)/sizeof(reg_user[0]) ) == CSTR_EQUAL,
+"key not from \\REGISTRY\\USER\n");
 
 /* set a value in user's classes */
 res = RegSetValueExA(hkey, "val1", 0, REG_SZ, (const BYTE *)"user", 
sizeof("user"));
@@ -2200,6 +2209,11 @@ static void test_classesroot(void)
 RegCloseKey( hklm );
 return;
 }
+pNtQueryKey( hkcr, 3 /*KeyNameInformation*/, buffer, 
sizeof(buffer)/sizeof(buffer[0]), (ULONG*)&res );
+todo_wine ok( CompareStringW( LOCALE_INVARIANT, NORM_IGNORECASE, 
+(WCHAR*)(&buffer)+2, sizeof(reg_user)/sizeof(reg_user[0]), 
+reg_user, sizeof(reg_user)/sizeof(reg_user[0]) ) == CSTR_EQUAL,
+"key not from \\REGISTRY\\USER\n");
 
 /* set a value in hklm classes */
 res = RegSetValueExA(hklm, "val2", 0, REG_SZ, (const BYTE *)"hklm", 
sizeof("hklm"));
@@ -2227,6 +2241,11 @@ static void test_classesroot(void)
  KEY_QUERY_VALUE|KEY_SET_VALUE, &hkcr );
 ok(res == ERROR_SUCCESS,
"test key not found in hkcr: %d\n", res);
+pNtQueryKey( hkcr, 3 /*KeyNameInformation*/, buffer, 
sizeof(buffer)/sizeof(buffer[0]), (ULONG*)&res );
+todo_wine ok( CompareStringW( LOCALE_INVARIANT, NORM_IGNORECASE, 
+(WCHAR*)(&buffer)+2, sizeof(reg_user)/sizeof(reg_user[0]), 
+reg_user, sizeof(reg_user)/sizeof(reg_user[0]) ) == CSTR_EQUAL,
+"key not from \\REGISTRY\\USER\n");
 
 /* set a value in user's classes */
 res = RegSetValueExA(hkey, "val2", 0, REG_SZ, (const BYTE *)"user", 
sizeof("user"));
@@ -2267,6 +2286,11 @@ static void test_classesroot(void)
 /* try to open that subkey in hkcr */
 res = RegOpenKeyExA( hkcr, "subkey1", 0, KEY_QUERY_VALUE|KEY_SET_VALUE, 
&hkcrsub1 );
 ok(res == ERROR_SUCCESS, "test key not found in hkcr: %d\n", res);
+pNtQueryKey( hkcrsub1, 3 /*KeyNameInformation*/, buffer, 
sizeof(buffer)/sizeof(buffer[0]), (ULONG*)&res );
+ok( CompareStringW( LOCALE_INVARIANT, NORM_IGNORECASE, 
+(WCHAR*)(&buffer)+2, sizeof(reg_machine)/sizeof(reg_machine[0]), 
+reg_machine, sizeof(reg_machine)/sizeof(reg_machine[0]) ) == 
CSTR_EQUAL,
+"key not from \\REGISTRY\\MACHINE\n");
 
 /* set a value in hklm classes */
 res = RegSetValueExA(hklmsub1, "subval1", 0, REG_SZ, (const 

[PATCH] Tests that prove ntdll has no notion of HKCR.

2013-05-19 Thread George Stephanos
As instructed, I added a few lines to the already written tests that
confirm my claim.

Part of the research of the registry merging project was to determine
where the implementation is going to be written: advapi32, ntdll or
the server itself. The server choice was dismissed since HKCR isn't
stored and rather fetched live. These tests prove that advapi32 calls
that reference HKCR are either pointed there to \REGISTRY\MACHINE or
\REGISTRY\USER and hence, that the merge is to be done in advapi32.

http://newtestbot.winehq.org/JobDetails.pl?Key=976
---
 dlls/advapi32/tests/registry.c | 31 ++-
 1 file changed, 30 insertions(+), 1 deletion(-)

diff --git a/dlls/advapi32/tests/registry.c b/dlls/advapi32/tests/registry.c
index b2483a7..d006de9 100644
--- a/dlls/advapi32/tests/registry.c
+++ b/dlls/advapi32/tests/registry.c
@@ -43,6 +43,7 @@ static DWORD (WINAPI *pRegDeleteTreeA)(HKEY,LPCSTR);
 static DWORD (WINAPI *pRegDeleteKeyExA)(HKEY,LPCSTR,REGSAM,DWORD);
 static BOOL (WINAPI *pIsWow64Process)(HANDLE,PBOOL);
 static NTSTATUS (WINAPI * pNtDeleteKey)(HANDLE);
+static NTSTATUS (WINAPI * pNtQueryKey)(HANDLE,int,PVOID,ULONG,PULONG);
 static NTSTATUS (WINAPI * pRtlFormatCurrentUserKeyPath)(UNICODE_STRING*);
 static NTSTATUS (WINAPI * pRtlFreeUnicodeString)(PUNICODE_STRING);
 
@@ -136,6 +137,7 @@ static void InitFunctionPtrs(void)
 pRtlFormatCurrentUserKeyPath = (void *)GetProcAddress( hntdll, 
"RtlFormatCurrentUserKeyPath" );
 pRtlFreeUnicodeString = (void *)GetProcAddress(hntdll, 
"RtlFreeUnicodeString");
 pNtDeleteKey = (void *)GetProcAddress( hntdll, "NtDeleteKey" );
+pNtQueryKey = (void *)GetProcAddress( hntdll, "NtQueryKey" );
 }
 
 /* delete key and all its subkeys */
@@ -2099,10 +2101,12 @@ static void test_redirection(void)
 
 static void test_classesroot(void)
 {
+static const WCHAR reg_user[] = { 
'\\','R','E','G','I','S','T','R','Y','\\','U','S','E','R' };
+static const WCHAR reg_machine[] = { 
'\\','R','E','G','I','S','T','R','Y','\\','M','A','C','H','I','N','E' };
 HKEY hkey, hklm, hkcr, hkeysub1, hklmsub1, hkcrsub1, hklmsub2, hkcrsub2;
 DWORD size = 8;
 DWORD type = REG_SZ;
-static CHAR buffer[8];
+static CHAR buffer[100*sizeof(WCHAR)];
 LONG res;
 
 /* create a key in the user's classes */
@@ -2132,6 +2136,11 @@ static void test_classesroot(void)
 RegCloseKey( hkey );
 return;
 }
+pNtQueryKey( hkcr, 3 /*KeyNameInformation*/, buffer, 
sizeof(buffer)/sizeof(buffer[0]), (ULONG*)&res );
+todo_wine ok( CompareStringW( LOCALE_INVARIANT, NORM_IGNORECASE, 
+(WCHAR*)(&buffer)+2, sizeof(reg_user)/sizeof(reg_user[0]), 
+reg_user, sizeof(reg_user)/sizeof(reg_user[0]) ) == CSTR_EQUAL,
+"key not from \\REGISTRY\\USER\n");
 
 /* set a value in user's classes */
 res = RegSetValueExA(hkey, "val1", 0, REG_SZ, (const BYTE *)"user", 
sizeof("user"));
@@ -2200,6 +2209,11 @@ static void test_classesroot(void)
 RegCloseKey( hklm );
 return;
 }
+pNtQueryKey( hkcr, 3 /*KeyNameInformation*/, buffer, 
sizeof(buffer)/sizeof(buffer[0]), (ULONG*)&res );
+todo_wine ok( CompareStringW( LOCALE_INVARIANT, NORM_IGNORECASE, 
+(WCHAR*)(&buffer)+2, sizeof(reg_user)/sizeof(reg_user[0]), 
+reg_user, sizeof(reg_user)/sizeof(reg_user[0]) ) == CSTR_EQUAL,
+"key not from \\REGISTRY\\USER\n");
 
 /* set a value in hklm classes */
 res = RegSetValueExA(hklm, "val2", 0, REG_SZ, (const BYTE *)"hklm", 
sizeof("hklm"));
@@ -2227,6 +2241,11 @@ static void test_classesroot(void)
  KEY_QUERY_VALUE|KEY_SET_VALUE, &hkcr );
 ok(res == ERROR_SUCCESS,
"test key not found in hkcr: %d\n", res);
+pNtQueryKey( hkcr, 3 /*KeyNameInformation*/, buffer, 
sizeof(buffer)/sizeof(buffer[0]), (ULONG*)&res );
+todo_wine ok( CompareStringW( LOCALE_INVARIANT, NORM_IGNORECASE, 
+(WCHAR*)(&buffer)+2, sizeof(reg_user)/sizeof(reg_user[0]), 
+reg_user, sizeof(reg_user)/sizeof(reg_user[0]) ) == CSTR_EQUAL,
+"key not from \\REGISTRY\\USER\n");
 
 /* set a value in user's classes */
 res = RegSetValueExA(hkey, "val2", 0, REG_SZ, (const BYTE *)"user", 
sizeof("user"));
@@ -2267,6 +2286,11 @@ static void test_classesroot(void)
 /* try to open that subkey in hkcr */
 res = RegOpenKeyExA( hkcr, "subkey1", 0, KEY_QUERY_VALUE|KEY_SET_VALUE, 
&hkcrsub1 );
 ok(res == ERROR_SUCCESS, "test key not found in hkcr: %d\n", res);
+pNtQueryKey( hkcrsub1, 3 /*KeyNameInformation*/, buffer, 
sizeof(buffer)/sizeof(buffer[0]), (ULONG*)&res );
+ok( CompareStringW( LOCALE_INVARIANT, NORM_IGNORECASE, 
+(WCHAR*)(&buffer)+2, sizeof(reg_machine)/sizeof(reg_machine[0]), 
+reg_machine, sizeof(reg_machine)/sizeof(reg_machine[0]) ) == 
CSTR_EQUAL,
+"key not from \\REGISTRY\\MACHINE\n");
 
 /* set a value in hklm classes */
 res = RegSetValueExA(hklmsub1, "subval1", 0, REG_SZ, (const BYTE

[PATCH] Tests that prove ntdll has no notion of HKCR.

2013-05-19 Thread George Stephanos
As instructed, I added a few lines to the already written tests that
confirm my claim.

Part of the research of the registry merging project was to determine
where the implementation is going to be written: advapi32, ntdll or
the server itself. The server choice was dismissed since HKCR isn't
stored and rather fetched live. These tests prove that advapi32 calls
that reference HKCR are either pointed there to \REGISTRY\MACHINE or
\REGISTRY\USER and hence, that the merge is to be done in advapi32.

http://newtestbot.winehq.org/JobDetails.pl?Key=976
---
 dlls/advapi32/tests/registry.c | 21 -
 1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/dlls/advapi32/tests/registry.c b/dlls/advapi32/tests/registry.c
index b2483a7..0113639 100644
--- a/dlls/advapi32/tests/registry.c
+++ b/dlls/advapi32/tests/registry.c
@@ -43,6 +43,7 @@ static DWORD (WINAPI *pRegDeleteTreeA)(HKEY,LPCSTR);
 static DWORD (WINAPI *pRegDeleteKeyExA)(HKEY,LPCSTR,REGSAM,DWORD);
 static BOOL (WINAPI *pIsWow64Process)(HANDLE,PBOOL);
 static NTSTATUS (WINAPI * pNtDeleteKey)(HANDLE);
+static NTSTATUS (WINAPI * pNtQueryKey)(HANDLE,int,PVOID,ULONG,PULONG);
 static NTSTATUS (WINAPI * pRtlFormatCurrentUserKeyPath)(UNICODE_STRING*);
 static NTSTATUS (WINAPI * pRtlFreeUnicodeString)(PUNICODE_STRING);
 
@@ -136,6 +137,7 @@ static void InitFunctionPtrs(void)
 pRtlFormatCurrentUserKeyPath = (void *)GetProcAddress( hntdll, 
"RtlFormatCurrentUserKeyPath" );
 pRtlFreeUnicodeString = (void *)GetProcAddress(hntdll, 
"RtlFreeUnicodeString");
 pNtDeleteKey = (void *)GetProcAddress( hntdll, "NtDeleteKey" );
+pNtQueryKey = (void *)GetProcAddress( hntdll, "NtQueryKey" );
 }
 
 /* delete key and all its subkeys */
@@ -2099,10 +2101,12 @@ static void test_redirection(void)
 
 static void test_classesroot(void)
 {
+static const WCHAR reg_user[] = { 
'\\','R','E','G','I','S','T','R','Y','\\','U','S','E','R' };
+static const WCHAR reg_machine[] = { 
'\\','R','E','G','I','S','T','R','Y','\\','M','A','C','H','I','N','E' };
 HKEY hkey, hklm, hkcr, hkeysub1, hklmsub1, hkcrsub1, hklmsub2, hkcrsub2;
 DWORD size = 8;
 DWORD type = REG_SZ;
-static CHAR buffer[8];
+static CHAR buffer[100*sizeof(WCHAR)];
 LONG res;
 
 /* create a key in the user's classes */
@@ -2132,6 +2136,9 @@ static void test_classesroot(void)
 RegCloseKey( hkey );
 return;
 }
+pNtQueryKey( hkcr, 3 /*KeyNameInformation*/, buffer, 
sizeof(buffer)/sizeof(buffer[0]), (ULONG*)&res );
+todo_wine ok( !memcmp( (WCHAR*)(&buffer)+2, reg_user, 
sizeof(reg_user)/sizeof(reg_user[0]) ),
+"key not from \\REGISTRY\\USER\n");
 
 /* set a value in user's classes */
 res = RegSetValueExA(hkey, "val1", 0, REG_SZ, (const BYTE *)"user", 
sizeof("user"));
@@ -2200,6 +2207,9 @@ static void test_classesroot(void)
 RegCloseKey( hklm );
 return;
 }
+pNtQueryKey( hkcr, 3 /*KeyNameInformation*/, buffer, 
sizeof(buffer)/sizeof(buffer[0]), (ULONG*)&res );
+todo_wine ok( !memcmp( (WCHAR*)(&buffer)+2, reg_user, 
sizeof(reg_user)/sizeof(reg_user[0]) ),
+"key not from \\REGISTRY\\USER\n");
 
 /* set a value in hklm classes */
 res = RegSetValueExA(hklm, "val2", 0, REG_SZ, (const BYTE *)"hklm", 
sizeof("hklm"));
@@ -2227,6 +2237,9 @@ static void test_classesroot(void)
  KEY_QUERY_VALUE|KEY_SET_VALUE, &hkcr );
 ok(res == ERROR_SUCCESS,
"test key not found in hkcr: %d\n", res);
+pNtQueryKey( hkcr, 3 /*KeyNameInformation*/, buffer, 
sizeof(buffer)/sizeof(buffer[0]), (ULONG*)&res );
+todo_wine ok( !memcmp( (WCHAR*)(&buffer)+2, reg_user, 
sizeof(reg_user)/sizeof(reg_user[0]) ),
+"key not from \\REGISTRY\\USER\n");
 
 /* set a value in user's classes */
 res = RegSetValueExA(hkey, "val2", 0, REG_SZ, (const BYTE *)"user", 
sizeof("user"));
@@ -2267,6 +2280,9 @@ static void test_classesroot(void)
 /* try to open that subkey in hkcr */
 res = RegOpenKeyExA( hkcr, "subkey1", 0, KEY_QUERY_VALUE|KEY_SET_VALUE, 
&hkcrsub1 );
 ok(res == ERROR_SUCCESS, "test key not found in hkcr: %d\n", res);
+pNtQueryKey( hkcrsub1, 3 /*KeyNameInformation*/, buffer, 
sizeof(buffer)/sizeof(buffer[0]), (ULONG*)&res );
+ok( !memcmp( (WCHAR*)(&buffer)+2, reg_machine, 
sizeof(reg_machine)/sizeof(reg_machine[0]) ),
+"key not from \\REGISTRY\\MACHINE\n");
 
 /* set a value in hklm classes */
 res = RegSetValueExA(hklmsub1, "subval1", 0, REG_SZ, (const BYTE *)"hklm", 
sizeof("hklm"));
@@ -2326,6 +2342,9 @@ static void test_classesroot(void)
 /* new subkey in hkcr */
 if (RegCreateKeyExA( hkcr, "subkey2", 0, NULL, 0,
  KEY_QUERY_VALUE|KEY_SET_VALUE, NULL, &hkcrsub2, NULL 
)) return;
+pNtQueryKey( hkcrsub2, 3 /*KeyNameInformation*/, buffer, 
sizeof(buffer)/sizeof(buffer[0]), (ULONG*)&res );
+ok( !memcmp( (WCHAR*)(&buffer)+2, reg_machine, 
sizeof(reg_machine)/sizeof(reg_machine[0]) ),

Re: [PATCH] Tests that prove ntdll has no notion of HKCR.

2013-05-19 Thread George Stephanos
On Sun, May 19, 2013 at 8:20 AM, Dmitry Timoshkov  wrote:

> George Stephanos  wrote:
>
> > > Ah, well, strcmp comes from the C library your compiler uses. wcsncmp
> can
> > > only come from msvcrt. When compiling for Wine, this can result in
> mixing C
> > > runtime libraries, and hilarity can result.
> ...
> > Perhaps I could just use memcmp?
>
> Use lstrcmpW/lstrcmpiW for unicode string comparisons, and
> lstrcmpA/lstrcmpiA
> for ANSI strings (you can't use glibc ones because of locale differencies),
> they are kernel32 exports, and exist in all Windows versions.
>
> --
> Dmitry.
>

Well I do need the functions to be boundable by length, or else I'd need to
do some copying.
I'm going to post the updated patch with memcmp until a better solution
comes up.



Re: [PATCH] Tests that prove ntdll has no notion of HKCR.

2013-05-18 Thread George Stephanos
On Sun, May 19, 2013 at 2:24 AM, Juan Lang  wrote:

> (consider subscribing to wine-devel so your emails don't get stuck in
>>> moderation.)
>>>
>> Hmm but I am already!
>>
>
> Ok, that's strange. Maybe I just got it late.
>
>
>>  I think Alexandre will object to using msvcrt functions (wcsncmp in
>>> this case), but I don't have a straightforward alternative yet.
>>>
>> strcmp is already used. What's the difference?
>>
>
> Ah, well, strcmp comes from the C library your compiler uses. wcsncmp can
> only come from msvcrt. When compiling for Wine, this can result in mixing C
> runtime libraries, and hilarity can result.
>
> Say, do these tests work on Wine? If not, you'll want to mark them with
> todo_wine, i.e. todo_wine ok(...).
> --Juan
>

Perhaps I could just use memcmp?
Only the \REGISTRY\USER portion of these tests don't work on wine. Marked.



Re: [PATCH] Tests that prove ntdll has no notion of HKCR.

2013-05-18 Thread George Stephanos
On Sat, May 18, 2013 at 11:57 PM, Juan Lang  wrote:

> Hi George,
> (consider subscribing to wine-devel so your emails don't get stuck in
> moderation.)
>
Hmm but I am already!

>
>
> On Sat, May 11, 2013 at 7:43 AM, George Stephanos  > wrote:
>
>> As instructed, I added a few lines to the already written tests that
>> confirm my claim.
>>
>> Part of the research of the registry merging project was to determine
>> where the implementation is going to be written: advapi32, ntdll or
>> the server itself. The server choice was dismissed since HKCR isn't
>> stored and rather fetched live. These tests prove that advapi32 calls
>> that reference HKCR are either pointed there to \REGISTRY\MACHINE or
>> \REGISTRY\USER and hence, that the merge is to be done in advapi32.
>>
>> http://newtestbot.winehq.org/JobDetails.pl?Key=976
>> ---
>>  dlls/advapi32/tests/registry.c | 18 ++
>>  1 file changed, 18 insertions(+)
>>
>> diff --git a/dlls/advapi32/tests/registry.c
>> b/dlls/advapi32/tests/registry.c
>> index b2483a7..8437e4d 100644
>> --- a/dlls/advapi32/tests/registry.c
>> +++ b/dlls/advapi32/tests/registry.c
>> @@ -43,6 +43,7 @@ static DWORD (WINAPI *pRegDeleteTreeA)(HKEY,LPCSTR);
>>  static DWORD (WINAPI *pRegDeleteKeyExA)(HKEY,LPCSTR,REGSAM,DWORD);
>>  static BOOL (WINAPI *pIsWow64Process)(HANDLE,PBOOL);
>>  static NTSTATUS (WINAPI * pNtDeleteKey)(HANDLE);
>> +static NTSTATUS (WINAPI * pNtQueryKey)(HANDLE,int,PVOID,ULONG,PULONG);
>>  static NTSTATUS (WINAPI * pRtlFormatCurrentUserKeyPath)(UNICODE_STRING*);
>>  static NTSTATUS (WINAPI * pRtlFreeUnicodeString)(PUNICODE_STRING);
>>
>> @@ -136,6 +137,7 @@ static void InitFunctionPtrs(void)
>>  pRtlFormatCurrentUserKeyPath = (void *)GetProcAddress( hntdll,
>> "RtlFormatCurrentUserKeyPath" );
>>  pRtlFreeUnicodeString = (void *)GetProcAddress(hntdll,
>> "RtlFreeUnicodeString");
>>  pNtDeleteKey = (void *)GetProcAddress( hntdll, "NtDeleteKey" );
>> +pNtQueryKey = (void *)GetProcAddress( hntdll, "NtQueryKey" );
>>  }
>>
>>  /* delete key and all its subkeys */
>> @@ -2104,6 +2106,7 @@ static void test_classesroot(void)
>>  DWORD type = REG_SZ;
>>  static CHAR buffer[8];
>>  LONG res;
>> +void *buf = malloc(300*sizeof(wchar_t));
>>
>
> You could just allocate a buffer on the stack. 300 is probably overkill,
> 100 looks like it would do it. You want to use WCHAR rather than wchar_t.
>
>  /* create a key in the user's classes */
>>  if (!RegOpenKeyA( HKEY_CURRENT_USER,
>> "Software\\Classes\\WineTestCls", &hkey ))
>> @@ -2132,6 +2135,9 @@ static void test_classesroot(void)
>>  RegCloseKey( hkey );
>>  return;
>>  }
>> +pNtQueryKey( hkcr, 3 /*KeyNameInformation*/, buf,
>> 500*sizeof(wchar_t), (ULONG*)&res );
>>
>
> Not that this will actually overflow, but you specify 500, but only
> allocated 300. A straightforward way to accomplish agreement is to use
> sizeof(buf) / sizeof(buf[0]) as the size, if it's not dynamically allocated.
>
This slipped :|

>
>
>> +ok( wcsncmp((wchar_t*)buf+2, L"\\REGISTRY\\USER", 14) == 0,
>> +"key not from \\REGISTRY\\USER\n");
>>
>
> Using L"" constructs isn't portable, you'll need to declare these the
> tedious way you'll find in other Wine tests:
> static const WCHAR reg_user[] = { '\\','R',''E,'G','I','S','T','R',Y',
> etc. Then you can use the sizeof(reg_user) / sizeof(reg_user[0]) trick to
> specify the length.
> I think Alexandre will object to using msvcrt functions (wcsncmp in this
> case), but I don't have a straightforward alternative yet.
>
strcmp is already used. What's the difference?

>
> Welcome to Wine development :)
>
:)

> --Juan
>



[PATCH] Tests that prove ntdll has no notion of HKCR.

2013-05-17 Thread George Stephanos
As instructed, I added a few lines to the already written tests that
confirm my claim.

Part of the research of the registry merging project was to determine
where the implementation is going to be written: advapi32, ntdll or
the server itself. The server choice was dismissed since HKCR isn't
stored and rather fetched live. These tests prove that advapi32 calls
that reference HKCR are either pointed there to \REGISTRY\MACHINE or
\REGISTRY\USER and hence, that the merge is to be done in advapi32.

http://newtestbot.winehq.org/JobDetails.pl?Key=976
---
 dlls/advapi32/tests/registry.c | 18 ++
 1 file changed, 18 insertions(+)

diff --git a/dlls/advapi32/tests/registry.c b/dlls/advapi32/tests/registry.c
index b2483a7..8437e4d 100644
--- a/dlls/advapi32/tests/registry.c
+++ b/dlls/advapi32/tests/registry.c
@@ -43,6 +43,7 @@ static DWORD (WINAPI *pRegDeleteTreeA)(HKEY,LPCSTR);
 static DWORD (WINAPI *pRegDeleteKeyExA)(HKEY,LPCSTR,REGSAM,DWORD);
 static BOOL (WINAPI *pIsWow64Process)(HANDLE,PBOOL);
 static NTSTATUS (WINAPI * pNtDeleteKey)(HANDLE);
+static NTSTATUS (WINAPI * pNtQueryKey)(HANDLE,int,PVOID,ULONG,PULONG);
 static NTSTATUS (WINAPI * pRtlFormatCurrentUserKeyPath)(UNICODE_STRING*);
 static NTSTATUS (WINAPI * pRtlFreeUnicodeString)(PUNICODE_STRING);
 
@@ -136,6 +137,7 @@ static void InitFunctionPtrs(void)
 pRtlFormatCurrentUserKeyPath = (void *)GetProcAddress( hntdll, 
"RtlFormatCurrentUserKeyPath" );
 pRtlFreeUnicodeString = (void *)GetProcAddress(hntdll, 
"RtlFreeUnicodeString");
 pNtDeleteKey = (void *)GetProcAddress( hntdll, "NtDeleteKey" );
+pNtQueryKey = (void *)GetProcAddress( hntdll, "NtQueryKey" );
 }
 
 /* delete key and all its subkeys */
@@ -2104,6 +2106,7 @@ static void test_classesroot(void)
 DWORD type = REG_SZ;
 static CHAR buffer[8];
 LONG res;
+void *buf = malloc(300*sizeof(wchar_t));
 
 /* create a key in the user's classes */
 if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Classes\\WineTestCls", 
&hkey ))
@@ -2132,6 +2135,9 @@ static void test_classesroot(void)
 RegCloseKey( hkey );
 return;
 }
+pNtQueryKey( hkcr, 3 /*KeyNameInformation*/, buf, 500*sizeof(wchar_t), 
(ULONG*)&res );
+ok( wcsncmp((wchar_t*)buf+2, L"\\REGISTRY\\USER", 14) == 0,
+"key not from \\REGISTRY\\USER\n");
 
 /* set a value in user's classes */
 res = RegSetValueExA(hkey, "val1", 0, REG_SZ, (const BYTE *)"user", 
sizeof("user"));
@@ -2200,6 +2206,9 @@ static void test_classesroot(void)
 RegCloseKey( hklm );
 return;
 }
+pNtQueryKey( hkcr, 3 /*KeyNameInformation*/, buf, 500*sizeof(wchar_t), 
(ULONG*)&res );
+ok( wcsncmp( (wchar_t*)buf+2, L"\\REGISTRY\\USER", 14) == 0,
+"key not from \\REGISTRY\\USER\n");
 
 /* set a value in hklm classes */
 res = RegSetValueExA(hklm, "val2", 0, REG_SZ, (const BYTE *)"hklm", 
sizeof("hklm"));
@@ -2227,6 +2236,9 @@ static void test_classesroot(void)
  KEY_QUERY_VALUE|KEY_SET_VALUE, &hkcr );
 ok(res == ERROR_SUCCESS,
"test key not found in hkcr: %d\n", res);
+pNtQueryKey( hkcr, 3 /*KeyNameInformation*/, buf, 500*sizeof(wchar_t), 
(ULONG*)&res );
+ok( wcsncmp( (wchar_t*)buf+2, L"\\REGISTRY\\USER", 14) == 0,
+"key not from \\REGISTRY\\USER\n");
 
 /* set a value in user's classes */
 res = RegSetValueExA(hkey, "val2", 0, REG_SZ, (const BYTE *)"user", 
sizeof("user"));
@@ -2267,6 +2279,9 @@ static void test_classesroot(void)
 /* try to open that subkey in hkcr */
 res = RegOpenKeyExA( hkcr, "subkey1", 0, KEY_QUERY_VALUE|KEY_SET_VALUE, 
&hkcrsub1 );
 ok(res == ERROR_SUCCESS, "test key not found in hkcr: %d\n", res);
+pNtQueryKey( hkcrsub1, 3 /*KeyNameInformation*/, buf, 500*sizeof(wchar_t), 
(ULONG*)&res );
+ok( wcsncmp( (wchar_t*)buf+2, L"\\REGISTRY\\MACHINE", 17) == 0,
+"key created in hkcr not found in \\REGISTRY\\MACHINE\n");
 
 /* set a value in hklm classes */
 res = RegSetValueExA(hklmsub1, "subval1", 0, REG_SZ, (const BYTE *)"hklm", 
sizeof("hklm"));
@@ -2326,6 +2341,9 @@ static void test_classesroot(void)
 /* new subkey in hkcr */
 if (RegCreateKeyExA( hkcr, "subkey2", 0, NULL, 0,
  KEY_QUERY_VALUE|KEY_SET_VALUE, NULL, &hkcrsub2, NULL 
)) return;
+pNtQueryKey( hkcrsub2, 3 /*KeyNameInformation*/, buf, 256*sizeof(wchar_t), 
(ULONG*)&res );
+ok( wcsncmp( (wchar_t*)buf+2, L"\\REGISTRY\\MACHINE", 17) == 0,
+"key not found in \\REGISTRY\\MACHINE");
 res = RegSetValueExA(hkcrsub2, "subval1", 0, REG_SZ, (const BYTE *)"hkcr", 
sizeof("hkcr"));
 ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, 
GetLastError());
 
-- 
1.8.1.msysgit.1





Re: GSoC proposal

2013-05-17 Thread George Stephanos
You're right about RegOpenUserClassesRoot(). It'll just serve as another
way to RegOpenKeyEx(HKEY_CLASSES_ROOT) for now because wine doesn't yet
support multiple NT users.

For the list.. it's very strange. I've tested on my side and it does seem
that there's no difference whatsoever. But then what why would they
specifically mention those keys on the page?



Re: GSoC proposal

2013-05-17 Thread George Stephanos
As we know already from [1], the merge is going to happen according to
certain rules.
The list at the end of the page signifies which subkeys are going to be
*merged* from HKLM\Software\Classes\subkey and HKCU\Software\Classes\subkey
and not simply linked to.

Now there's a comment on the article that says that list is stored in a
key. That lead me into thinking that the list is dynamic and should be
determined at runtime using that key. However that key doesn't exist on my
Win8 box or the web even.
Should I just assume the list is static and build my tests/code according
to it? Is there something I'm missing?

[1] -
http://msdn.microsoft.com/en-us/library/windows/desktop/ms724498(v=vs.85).aspx


On Wed, May 8, 2013 at 1:26 AM, George Stephanos wrote:

> I'm done. Sorry for the font massacre. They're not changing :|
>
>
> On Tue, May 7, 2013 at 6:45 PM, Juan Lang  wrote:
>
>> I'll leave it open till tomorrow (my time.) Thanks,
>> --Juan
>>
>>
>> On Tue, May 7, 2013 at 9:44 AM, Juan Lang  wrote:
>>
>>> Oh, hang on, I just flipped it so you can modify it.
>>>
>>>
>>> On Tue, May 7, 2013 at 9:43 AM, Juan Lang  wrote:
>>>
>>>> I think you can add more of a timeline in a response. Will that work?
>>>> --Juan
>>>>
>>>>
>>>> On Tue, May 7, 2013 at 9:40 AM, George Stephanos <
>>>> gaf.stepha...@gmail.com> wrote:
>>>>
>>>>> I had responded already but yes I'm a little bit shallow on the
>>>>> timeline details. Alright.
>>>>>  Could you give me permission to modify the proposal?
>>>>>
>>>>
>>>>
>>>
>>
>



GSoC proposal

2013-05-02 Thread George Stephanos
Hello wine-devel!

This is my proposal as a student for Google Summer of Code 2013.
I'm George Stephanos from the "Arab Academy for Science and Technology"
situated in Egypt. gsteph on #winehackers
I'm currently about to finish my second semester as a BSc in CS.

Previous Experience:
I haven't developed for Wine before though I've always been a big fan of
the project.
I'm fairly good with C/C++ and Python and I think I have enough Win32 API
experience. I've previously developed small WinSock, DirectX and classic
GUI applications (with and without MFC).
I'm a freelancer. I've worked (alone) on around 25-30 projects rating 4+/5
in each.
I've enrolled in Google Code-In 2010 and 2011 (which is basically GSoC for
high school students) writing lots of ARM assembly code for VideoLAN
(#x264dev on freenode). In 2011, I would have ranked 12th if not for an
issue that occurred between VideoLAN and Google.

Proposal:
I've read your ideas page and the only registry task [1] has particularly
caught my attention.
I'm aware of what I need to do. I've read [2], [3] and [4].
I haven't yet browsed the Wine tree at all and I'll probably be missing
implementation strategies but that'll hopefully be worked out with my
mentor.

[1] -
http://wiki.winehq.org/SummerOfCode?#head-40e316e01066b5a129cd65073fa4b89dd227fd89
[2] - http://bugs.winehq.org/show_bug.cgi?id=14771
[3] -
http://msdn.microsoft.com/en-us/library/windows/desktop/ms724475(v=vs.85).aspx
[4] -
http://msdn.microsoft.com/en-us/library/windows/desktop/ms724498(v=vs.85).aspx

Tell me if you need more information.
Hope you consider me!

Thanks,
George



GSoC proposal

2013-05-01 Thread George Stephanos
Hello wine-devel!

This is my proposal as a student for Google Summer of Code 2013.
I'm George Stephanos from the "Arab Academy for Science and Technology"
situated in Egypt. gsteph on #winehackers
I'm currently about to finish my second semester as a BSc in CS.

Previous Experience:
I haven't developed for Wine before though I've always been a big fan of
the project.
I'm fairly good with C/C++ and Python and I think I have enough Win32 API
experience. I've previously developed small WinSock, DirectX and classic
GUI applications (with and without MFC).
I'm a freelancer. I've worked (alone) on around 25-30 projects rating 4+/5
in each.
I've enrolled in Google Code-In 2010 and 2011 (which is basically GSoC for
high school students) writing lots of ARM assembly code for VideoLAN
(#x264dev on freenode). In 2011, I would have ranked 12th if not for an
issue that occurred between VideoLAN and Google.

Proposal:
I've read your ideas page and the only registry task [1] has particularly
caught my attention.
I'm aware of what I need to do. I've read [2], [3] and [4].
I haven't yet browsed the Wine tree at all and I'll probably be missing
implementation strategies but that'll hopefully be worked out with my
mentor.

[1] -
http://wiki.winehq.org/SummerOfCode?#head-40e316e01066b5a129cd65073fa4b89dd227fd89
[2] - http://bugs.winehq.org/show_bug.cgi?id=14771
[3] -
http://msdn.microsoft.com/en-us/library/windows/desktop/ms724475(v=vs.85).aspx
[4] -
http://msdn.microsoft.com/en-us/library/windows/desktop/ms724498(v=vs.85).aspx

Tell me if you need more information.
Hope you consider me!

Thanks,
George