[PATCH] Tests that prove ntdll has no notion of HKCR.
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 BYTE *)hklm, sizeof(hklm)); @@ -2326,6 +2350,11 @@
Re: [PATCH] Tests that prove ntdll has no notion of HKCR.
Hi George, 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' }; Almost, but these have to be NULL terminated, i.e. +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 }; --Juan
Re: [PATCH] Tests that prove ntdll has no notion of HKCR.
George Stephanos gaf.stepha...@gmail.com 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.
Re: [PATCH] Tests that prove ntdll has no notion of HKCR.
On Sun, May 19, 2013 at 8:20 AM, Dmitry Timoshkov dmi...@baikal.ru wrote: George Stephanos gaf.stepha...@gmail.com 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.
[PATCH] Tests that prove ntdll has no notion of HKCR.
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]) ), +key not from \\REGISTRY\\MACHINE\n); res =
Re: [PATCH] Tests that prove ntdll has no notion of HKCR.
George Stephanos gaf.stepha...@gmail.com wrote: 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. Then CompareStringA/W would better work for you. -- Dmitry.
[PATCH] Tests that prove ntdll has no notion of HKCR.
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 *)hklm, sizeof(hklm)); @@ -2326,6 +2350,11 @@
Re: [PATCH] Tests that prove ntdll has no notion of HKCR.
Hi George, (consider subscribing to wine-devel so your emails don't get stuck in moderation.) On Sat, May 11, 2013 at 7:43 AM, George Stephanos gaf.stepha...@gmail.comwrote: 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. +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. Welcome to Wine development :) --Juan
Re: [PATCH] Tests that prove ntdll has no notion of HKCR.
On Sat, May 18, 2013 at 11:57 PM, Juan Lang juan.l...@gmail.com 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 gaf.stepha...@gmail.com 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
Re: [PATCH] Tests that prove ntdll has no notion of HKCR.
(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
Re: [PATCH] Tests that prove ntdll has no notion of HKCR.
On Sun, May 19, 2013 at 2:24 AM, Juan Lang juan.l...@gmail.com 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.
[PATCH] Tests that prove ntdll has no notion of HKCR.
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