[KERNEL32_WINETEST]
authorAmine Khaldi <amine.khaldi@reactos.org>
Sat, 20 Sep 2014 19:35:24 +0000 (19:35 +0000)
committerAmine Khaldi <amine.khaldi@reactos.org>
Sat, 20 Sep 2014 19:35:24 +0000 (19:35 +0000)
* Sync with Wine 1.7.27.
CORE-8540

svn path=/trunk/; revision=64206

rostests/winetests/kernel32/debugger.c
rostests/winetests/kernel32/file.c
rostests/winetests/kernel32/heap.c
rostests/winetests/kernel32/loader.c
rostests/winetests/kernel32/locale.c
rostests/winetests/kernel32/pipe.c
rostests/winetests/kernel32/resource.c
rostests/winetests/kernel32/sync.c
rostests/winetests/kernel32/thread.c
rostests/winetests/kernel32/time.c
rostests/winetests/kernel32/virtual.c

index 011ed5f..a802784 100644 (file)
@@ -718,6 +718,8 @@ static void doChildren(int argc, char **argv)
 
     blackbox.failures = child_failures;
     save_blackbox(blackbox_file, &blackbox, sizeof(blackbox));
+
+    HeapFree(GetProcessHeap(), 0, cmd);
 }
 
 static void test_debug_children(char *name, DWORD flag, BOOL debug_child)
index 883aa57..2e4871c 100755 (executable)
@@ -3959,6 +3959,63 @@ static void test_SetFileValidData(void)
     DeleteFileA(filename);
 }
 
+static void test_WriteFileGather(void)
+{
+    char temp_path[MAX_PATH], filename[MAX_PATH];
+    HANDLE hfile, hiocp1, hiocp2;
+    DWORD ret, size;
+    ULONG_PTR key;
+    FILE_SEGMENT_ELEMENT fse[2];
+    OVERLAPPED ovl, *povl = NULL;
+    SYSTEM_INFO si;
+    LPVOID buf = NULL;
+
+    ret = GetTempPathA( MAX_PATH, temp_path );
+    ok( ret != 0, "GetTempPathA error %d\n", GetLastError() );
+    ok( ret < MAX_PATH, "temp path should fit into MAX_PATH\n" );
+    ret = GetTempFileNameA( temp_path, "wfg", 0, filename );
+    ok( ret != 0, "GetTempFileNameA error %d\n", GetLastError() );
+
+    hfile = CreateFileA( filename, GENERIC_READ | GENERIC_WRITE, 0, 0, CREATE_ALWAYS,
+                         FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED | FILE_ATTRIBUTE_NORMAL, 0 );
+    ok( hfile != INVALID_HANDLE_VALUE, "CreateFile failed err %u\n", GetLastError() );
+    if (hfile == INVALID_HANDLE_VALUE) return;
+
+    hiocp1 = CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, 999, 0 );
+    hiocp2 = CreateIoCompletionPort( hfile, hiocp1, 999, 0 );
+    ok( hiocp2 != 0, "CreateIoCompletionPort failed err %u\n", GetLastError() );
+
+    GetSystemInfo( &si );
+    buf = VirtualAlloc( NULL, si.dwPageSize, MEM_COMMIT, PAGE_READWRITE );
+    ok( buf != NULL, "VirtualAlloc failed err %u\n", GetLastError() );
+
+    memset( &ovl, 0, sizeof(ovl) );
+    memset( fse, 0, sizeof(fse) );
+    fse[0].Buffer = buf;
+    if (!WriteFileGather( hfile, fse, si.dwPageSize, NULL, &ovl ))
+        ok( GetLastError() == ERROR_IO_PENDING, "WriteFileGather failed err %u\n", GetLastError() );
+
+    ret = GetQueuedCompletionStatus( hiocp2, &size, &key, &povl, 1000 );
+    ok( ret, "GetQueuedCompletionStatus failed err %u\n", GetLastError());
+    ok( povl == &ovl, "wrong ovl %p\n", povl );
+
+    memset( &ovl, 0, sizeof(ovl) );
+    memset( fse, 0, sizeof(fse) );
+    fse[0].Buffer = buf;
+    if (!ReadFileScatter( hfile, fse, si.dwPageSize, NULL, &ovl ))
+        ok( GetLastError() == ERROR_IO_PENDING, "ReadFileScatter failed err %u\n", GetLastError() );
+
+    ret = GetQueuedCompletionStatus( hiocp2, &size, &key, &povl, 1000 );
+    ok( ret, "GetQueuedCompletionStatus failed err %u\n", GetLastError());
+    ok( povl == &ovl, "wrong ovl %p\n", povl );
+
+    CloseHandle( hfile );
+    CloseHandle( hiocp1 );
+    CloseHandle( hiocp2 );
+    VirtualFree( buf, 0, MEM_RELEASE );
+    DeleteFileA( filename );
+}
+
 static unsigned file_map_access(unsigned access)
 {
     if (access & GENERIC_READ)    access |= FILE_GENERIC_READ;
@@ -4132,5 +4189,6 @@ START_TEST(file)
     test_GetFileInformationByHandleEx();
     test_OpenFileById();
     test_SetFileValidData();
+    test_WriteFileGather();
     test_file_access();
 }
index a36c373..d8768da 100755 (executable)
@@ -1127,7 +1127,7 @@ static void test_child_heap( const char *arg )
 
     if (!(heap->flags & HEAP_GROWABLE) || heap->pattern == 0xffeeffee)  /* vista layout */
     {
-        ok( heap->flags == 0, "%s: got heap flags %08x expected 0\n", arg, heap->flags );
+        ok( (heap->flags & ~HEAP_GROWABLE) == 0, "%s: got heap flags %08x\n", arg, heap->flags );
     }
     else if (heap->pattern == 0xeeeeeeee && heap->flags == 0xeeeeeeee)
     {
index e749238..af43779 100644 (file)
@@ -61,8 +61,8 @@ static void (WINAPI *pLdrShutdownProcess)(void);
 static BOOLEAN (WINAPI *pRtlDllShutdownInProgress)(void);
 static NTSTATUS (WINAPI *pNtAllocateVirtualMemory)(HANDLE, PVOID *, ULONG, SIZE_T *, ULONG, ULONG);
 static NTSTATUS (WINAPI *pNtFreeVirtualMemory)(HANDLE, PVOID *, SIZE_T *, ULONG);
-static NTSTATUS (WINAPI *pLdrLockLoaderLock)(ULONG, ULONG *, ULONG *);
-static NTSTATUS (WINAPI *pLdrUnlockLoaderLock)(ULONG, ULONG);
+static NTSTATUS (WINAPI *pLdrLockLoaderLock)(ULONG, ULONG *, ULONG_PTR *);
+static NTSTATUS (WINAPI *pLdrUnlockLoaderLock)(ULONG, ULONG_PTR);
 static void (WINAPI *pRtlAcquirePebLock)(void);
 static void (WINAPI *pRtlReleasePebLock)(void);
 static PVOID    (WINAPI *pResolveDelayLoadedAPI)(PVOID, PCIMAGE_DELAYLOAD_DESCRIPTOR,
@@ -1367,7 +1367,7 @@ static DWORD WINAPI mutex_thread_proc(void *param)
         if (ret == WAIT_OBJECT_0) break;
         else if (ret == WAIT_OBJECT_0 + 1)
         {
-            ULONG loader_lock_magic;
+            ULONG_PTR loader_lock_magic;
             trace("%04u: mutex_thread_proc: Entering loader lock\n", GetCurrentThreadId());
             ret = pLdrLockLoaderLock(0, NULL, &loader_lock_magic);
             ok(!ret, "LdrLockLoaderLock error %#x\n", ret);
index 4d4f9c2..50f6105 100755 (executable)
@@ -93,27 +93,36 @@ static BOOL (WINAPI *pIsValidLocaleName)(LPCWSTR);
 static INT (WINAPI *pCompareStringOrdinal)(const WCHAR *, INT, const WCHAR *, INT, BOOL);
 static INT (WINAPI *pCompareStringEx)(LPCWSTR, DWORD, LPCWSTR, INT, LPCWSTR, INT,
                                       LPNLSVERSIONINFO, LPVOID, LPARAM);
+static INT (WINAPI *pGetGeoInfoA)(GEOID, GEOTYPE, LPSTR, INT, LANGID);
+static INT (WINAPI *pGetGeoInfoW)(GEOID, GEOTYPE, LPWSTR, INT, LANGID);
+static BOOL (WINAPI *pEnumSystemGeoID)(GEOCLASS, GEOID, GEO_ENUMPROC);
 
 static void InitFunctionPointers(void)
 {
   hKernel32 = GetModuleHandleA("kernel32");
-  pEnumSystemLanguageGroupsA = (void*)GetProcAddress(hKernel32, "EnumSystemLanguageGroupsA");
-  pEnumLanguageGroupLocalesA = (void*)GetProcAddress(hKernel32, "EnumLanguageGroupLocalesA");
-  pLocaleNameToLCID = (void*)GetProcAddress(hKernel32, "LocaleNameToLCID");
-  pLCIDToLocaleName = (void*)GetProcAddress(hKernel32, "LCIDToLocaleName");
-  pLCMapStringEx = (void*)GetProcAddress(hKernel32, "LCMapStringEx");
-  pFoldStringA = (void*)GetProcAddress(hKernel32, "FoldStringA");
-  pFoldStringW = (void*)GetProcAddress(hKernel32, "FoldStringW");
-  pIsValidLanguageGroup = (void*)GetProcAddress(hKernel32, "IsValidLanguageGroup");
-  pEnumUILanguagesA = (void*)GetProcAddress(hKernel32, "EnumUILanguagesA");
-  pEnumSystemLocalesEx = (void*)GetProcAddress(hKernel32, "EnumSystemLocalesEx");
-  pIdnToNameprepUnicode = (void*)GetProcAddress(hKernel32, "IdnToNameprepUnicode");
-  pIdnToAscii = (void*)GetProcAddress(hKernel32, "IdnToAscii");
-  pIdnToUnicode = (void*)GetProcAddress(hKernel32, "IdnToUnicode");
-  pGetLocaleInfoEx = (void*)GetProcAddress(hKernel32, "GetLocaleInfoEx");
-  pIsValidLocaleName = (void*)GetProcAddress(hKernel32, "IsValidLocaleName");
-  pCompareStringOrdinal = (void*)GetProcAddress(hKernel32, "CompareStringOrdinal");
-  pCompareStringEx = (void*)GetProcAddress(hKernel32, "CompareStringEx");
+
+#define X(f) p##f = (void*)GetProcAddress(hKernel32, #f)
+  X(EnumSystemLanguageGroupsA);
+  X(EnumLanguageGroupLocalesA);
+  X(LocaleNameToLCID);
+  X(LCIDToLocaleName);
+  X(LCMapStringEx);
+  X(FoldStringA);
+  X(FoldStringW);
+  X(IsValidLanguageGroup);
+  X(EnumUILanguagesA);
+  X(EnumSystemLocalesEx);
+  X(IdnToNameprepUnicode);
+  X(IdnToAscii);
+  X(IdnToUnicode);
+  X(GetLocaleInfoEx);
+  X(IsValidLocaleName);
+  X(CompareStringOrdinal);
+  X(CompareStringEx);
+  X(GetGeoInfoA);
+  X(GetGeoInfoW);
+  X(EnumSystemGeoID);
+#undef X
 }
 
 #define eq(received, expected, label, type) \
@@ -2532,6 +2541,7 @@ static void test_FoldStringW(void)
     0x0C66, /* Telugu */
     0x0CE6, /* Kannada */
     0x0D66, /* Maylayalam */
+    0x0DE6, /* Sinhala Lith */
     0x0E50, /* Thai */
     0x0ED0, /* Laos */
     0x0F20, /* Tibet */
@@ -2563,6 +2573,7 @@ static void test_FoldStringW(void)
     0xA8D0, /* Saurashtra */
     0xA900, /* Kayah Li */
     0xA9D0, /* Javanese */
+    0xA9F0, /* Myanmar Tai Laing */
     0xAA50, /* Cham */
     0xABF0, /* Meetei Mayek */
     0xff10, /* Pliene chasse (?) */
@@ -3059,7 +3070,6 @@ static void test_EnumDateFormatsA(void)
     BOOL ret;
     LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
 
-    trace("EnumDateFormatsA 0\n");
     date_fmt_buf[0] = 0;
     SetLastError(0xdeadbeef);
     ret = EnumDateFormatsA(enum_datetime_procA, lcid, 0);
@@ -3070,7 +3080,7 @@ static void test_EnumDateFormatsA(void)
     else
     {
         ok(ret, "EnumDateFormatsA(0) error %d\n", GetLastError());
-        trace("%s\n", date_fmt_buf);
+        trace("EnumDateFormatsA(0): %s\n", date_fmt_buf);
         /* test the 1st enumerated format */
         if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
         ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
@@ -3078,7 +3088,6 @@ static void test_EnumDateFormatsA(void)
         ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
     }
 
-    trace("EnumDateFormatsA LOCALE_USE_CP_ACP\n");
     date_fmt_buf[0] = 0;
     SetLastError(0xdeadbeef);
     ret = EnumDateFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
@@ -3089,7 +3098,7 @@ static void test_EnumDateFormatsA(void)
     else
     {
         ok(ret, "EnumDateFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
-        trace("%s\n", date_fmt_buf);
+        trace("EnumDateFormatsA(LOCALE_USE_CP_ACP): %s\n", date_fmt_buf);
         /* test the 1st enumerated format */
         if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
         ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
@@ -3097,39 +3106,36 @@ static void test_EnumDateFormatsA(void)
         ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
     }
 
-    trace("EnumDateFormatsA DATE_SHORTDATE\n");
     date_fmt_buf[0] = 0;
     ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_SHORTDATE);
     ok(ret, "EnumDateFormatsA(DATE_SHORTDATE) error %d\n", GetLastError());
-    trace("%s\n", date_fmt_buf);
+    trace("EnumDateFormatsA(DATE_SHORTDATE): %s\n", date_fmt_buf);
     /* test the 1st enumerated format */
     if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
     ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf));
     ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError());
     ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
 
-    trace("EnumDateFormatsA DATE_LONGDATE\n");
     date_fmt_buf[0] = 0;
     ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_LONGDATE);
     ok(ret, "EnumDateFormatsA(DATE_LONGDATE) error %d\n", GetLastError());
-    trace("%s\n", date_fmt_buf);
+    trace("EnumDateFormatsA(DATE_LONGDATE): %s\n", date_fmt_buf);
     /* test the 1st enumerated format */
     if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
     ret = GetLocaleInfoA(lcid, LOCALE_SLONGDATE, buf, sizeof(buf));
     ok(ret, "GetLocaleInfoA(LOCALE_SLONGDATE) error %d\n", GetLastError());
     ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
 
-    trace("EnumDateFormatsA DATE_YEARMONTH\n");
     date_fmt_buf[0] = 0;
     SetLastError(0xdeadbeef);
     ret = EnumDateFormatsA(enum_datetime_procA, lcid, DATE_YEARMONTH);
     if (!ret && (GetLastError() == ERROR_INVALID_FLAGS))
     {
-        skip("DATE_YEARMONTH is only present on W2K and later\n");
+        win_skip("DATE_YEARMONTH is only present on W2K and later\n");
         return;
     }
     ok(ret, "EnumDateFormatsA(DATE_YEARMONTH) error %d\n", GetLastError());
-    trace("%s\n", date_fmt_buf);
+    trace("EnumDateFormatsA(DATE_YEARMONTH): %s\n", date_fmt_buf);
     /* test the 1st enumerated format */
     if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
     ret = GetLocaleInfoA(lcid, LOCALE_SYEARMONTH, buf, sizeof(buf));
@@ -3144,22 +3150,20 @@ static void test_EnumTimeFormatsA(void)
     BOOL ret;
     LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
 
-    trace("EnumTimeFormatsA 0\n");
     date_fmt_buf[0] = 0;
     ret = EnumTimeFormatsA(enum_datetime_procA, lcid, 0);
     ok(ret, "EnumTimeFormatsA(0) error %d\n", GetLastError());
-    trace("%s\n", date_fmt_buf);
+    trace("EnumTimeFormatsA(0): %s\n", date_fmt_buf);
     /* test the 1st enumerated format */
     if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
     ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
     ok(ret, "GetLocaleInfoA(LOCALE_STIMEFORMAT) error %d\n", GetLastError());
     ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf);
 
-    trace("EnumTimeFormatsA LOCALE_USE_CP_ACP\n");
     date_fmt_buf[0] = 0;
     ret = EnumTimeFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP);
     ok(ret, "EnumTimeFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError());
-    trace("%s\n", date_fmt_buf);
+    trace("EnumTimeFormatsA(LOCALE_USE_CP_ACP): %s\n", date_fmt_buf);
     /* test the 1st enumerated format */
     if ((p = strchr(date_fmt_buf, '\n'))) *p = 0;
     ret = GetLocaleInfoA(lcid, LOCALE_STIMEFORMAT, buf, sizeof(buf));
@@ -3182,7 +3186,7 @@ static void test_GetCPInfo(void)
     ret = GetCPInfo(CP_UTF7, &cpinfo);
     if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
     {
-        skip("Codepage CP_UTF7 is not installed/available\n");
+        win_skip("Codepage CP_UTF7 is not installed/available\n");
     }
     else
     {
@@ -3198,7 +3202,7 @@ static void test_GetCPInfo(void)
     ret = GetCPInfo(CP_UTF8, &cpinfo);
     if (!ret && GetLastError() == ERROR_INVALID_PARAMETER)
     {
-        skip("Codepage CP_UTF8 is not installed/available\n");
+        win_skip("Codepage CP_UTF8 is not installed/available\n");
     }
     else
     {
@@ -3279,6 +3283,7 @@ static void test_GetStringTypeW(void)
     static const WCHAR space_special[] = {0x09, 0x0d, 0x85};
 
     WORD types[20];
+    WCHAR ch;
     int i;
 
     memset(types,0,sizeof(types));
@@ -3335,6 +3340,21 @@ static void test_GetStringTypeW(void)
     GetStringTypeW(CT_CTYPE1, space_special, 3, types);
     for (i = 0; i < 3; i++)
         ok(types[i] & C1_SPACE || broken(types[i] == C1_CNTRL) || broken(types[i] == 0), "incorrect types returned for %x -> (%x does not have %x)\n",space_special[i], types[i], C1_SPACE );
+
+    /* surrogate pairs */
+    ch = 0xd800;
+    memset(types, 0, sizeof(types));
+    GetStringTypeW(CT_CTYPE3, &ch, 1, types);
+    if (types[0] == C3_NOTAPPLICABLE)
+        win_skip("C3_HIGHSURROGATE/C3_LOWSURROGATE are not supported.\n");
+    else {
+        ok(types[0] == C3_HIGHSURROGATE, "got %x\n", types[0]);
+
+        ch = 0xdc00;
+        memset(types, 0, sizeof(types));
+        GetStringTypeW(CT_CTYPE3, &ch, 1, types);
+        ok(types[0] == C3_LOWSURROGATE, "got %x\n", types[0]);
+    }
 }
 
 static void test_IdnToNameprepUnicode(void)
@@ -3829,6 +3849,153 @@ static void test_CompareStringOrdinal(void)
     ok(ret == CSTR_LESS_THAN, "Got %u, expected %u\n", ret, CSTR_LESS_THAN);
 }
 
+static void test_GetGeoInfo(void)
+{
+    char buffA[20];
+    INT ret;
+
+    if (!pGetGeoInfoA)
+    {
+        win_skip("GetGeoInfo is not available.\n");
+        return;
+    }
+
+    /* unassigned id */
+    SetLastError(0xdeadbeef);
+    ret = pGetGeoInfoA(344, GEO_ISO2, NULL, 0, 0);
+    ok(ret == 0, "got %d\n", ret);
+    ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d\n", GetLastError());
+
+    ret = pGetGeoInfoA(203, GEO_ISO2, NULL, 0, 0);
+    ok(ret == 3, "got %d\n", ret);
+
+    ret = pGetGeoInfoA(203, GEO_ISO3, NULL, 0, 0);
+    ok(ret == 4, "got %d\n", ret);
+
+    ret = pGetGeoInfoA(203, GEO_ISO2, buffA, 3, 0);
+    ok(ret == 3, "got %d\n", ret);
+    ok(!strcmp(buffA, "RU"), "got %s\n", buffA);
+
+    /* buffer pointer not NULL, length is 0 - return required length */
+    buffA[0] = 'a';
+    SetLastError(0xdeadbeef);
+    ret = pGetGeoInfoA(203, GEO_ISO2, buffA, 0, 0);
+    ok(ret == 3, "got %d\n", ret);
+    ok(buffA[0] == 'a', "got %c\n", buffA[0]);
+
+    ret = pGetGeoInfoA(203, GEO_ISO3, buffA, 4, 0);
+    ok(ret == 4, "got %d\n", ret);
+    ok(!strcmp(buffA, "RUS"), "got %s\n", buffA);
+
+    /* shorter buffer */
+    SetLastError(0xdeadbeef);
+    buffA[1] = buffA[2] = 0;
+    ret = pGetGeoInfoA(203, GEO_ISO2, buffA, 2, 0);
+    ok(ret == 0, "got %d\n", ret);
+    ok(!strcmp(buffA, "RU"), "got %s\n", buffA);
+    ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d\n", GetLastError());
+
+    /* GEO_NATION returns GEOID in a string form */
+    buffA[0] = 0;
+    ret = pGetGeoInfoA(203, GEO_NATION, buffA, 20, 0);
+    ok(ret == 4, "got %d\n", ret);
+    ok(!strcmp(buffA, "203"), "got %s\n", buffA);
+
+    /* GEO_PARENT */
+    buffA[0] = 0;
+    ret = pGetGeoInfoA(203, GEO_PARENT, buffA, 20, 0);
+    if (ret == 0)
+        win_skip("GEO_PARENT not supported.\n");
+    else
+    {
+        ok(ret == 6, "got %d\n", ret);
+        ok(!strcmp(buffA, "47609"), "got %s\n", buffA);
+    }
+
+    buffA[0] = 0;
+    ret = pGetGeoInfoA(203, GEO_ISO_UN_NUMBER, buffA, 20, 0);
+    if (ret == 0)
+        win_skip("GEO_ISO_UN_NUMBER not supported.\n");
+    else
+    {
+        ok(ret == 4, "got %d\n", ret);
+        ok(!strcmp(buffA, "643"), "got %s\n", buffA);
+    }
+
+    /* try invalid type value */
+    SetLastError(0xdeadbeef);
+    ret = pGetGeoInfoA(203, GEO_PARENT + 1, NULL, 0, 0);
+    ok(ret == 0, "got %d\n", ret);
+    ok(GetLastError() == ERROR_INVALID_FLAGS, "got %d\n", GetLastError());
+}
+
+static int geoidenum_count;
+static BOOL CALLBACK test_geoid_enumproc(GEOID geoid)
+{
+    INT ret = pGetGeoInfoA(geoid, GEO_ISO2, NULL, 0, 0);
+    ok(ret == 3, "got %d for %d\n", ret, geoid);
+    /* valid geoid starts at 2 */
+    ok(geoid >= 2, "got geoid %d\n", geoid);
+
+    return geoidenum_count++ < 5;
+}
+
+static BOOL CALLBACK test_geoid_enumproc2(GEOID geoid)
+{
+    geoidenum_count++;
+    return TRUE;
+}
+
+static void test_EnumSystemGeoID(void)
+{
+    BOOL ret;
+
+    if (!pEnumSystemGeoID)
+    {
+        win_skip("EnumSystemGeoID is not available.\n");
+        return;
+    }
+
+    SetLastError(0xdeadbeef);
+    ret = pEnumSystemGeoID(GEOCLASS_NATION, 0, NULL);
+    ok(!ret, "got %d\n", ret);
+    ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
+    ret = pEnumSystemGeoID(GEOCLASS_NATION+1, 0, test_geoid_enumproc);
+    ok(!ret, "got %d\n", ret);
+    ok(GetLastError() == ERROR_INVALID_FLAGS, "got %d\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
+    ret = pEnumSystemGeoID(GEOCLASS_NATION+1, 0, NULL);
+    ok(!ret, "got %d\n", ret);
+    ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d\n", GetLastError());
+
+    ret = pEnumSystemGeoID(GEOCLASS_NATION, 0, test_geoid_enumproc);
+    ok(ret, "got %d\n", ret);
+
+    /* only first level is enumerated, not the whole hierarchy */
+    geoidenum_count = 0;
+    ret = pEnumSystemGeoID(GEOCLASS_NATION, 39070, test_geoid_enumproc2);
+    if (ret == 0)
+        win_skip("Parent GEOID is not supported in EnumSystemGeoID.\n");
+    else
+        ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count);
+
+    geoidenum_count = 0;
+    ret = pEnumSystemGeoID(GEOCLASS_REGION, 39070, test_geoid_enumproc2);
+    if (ret == 0)
+        win_skip("GEOCLASS_REGION is not supported in EnumSystemGeoID.\n");
+    else
+    {
+        ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count);
+
+        geoidenum_count = 0;
+        ret = pEnumSystemGeoID(GEOCLASS_REGION, 0, test_geoid_enumproc2);
+        ok(ret && geoidenum_count > 0, "got %d, count %d\n", ret, geoidenum_count);
+    }
+}
+
 START_TEST(locale)
 {
   InitFunctionPointers();
@@ -3864,6 +4031,8 @@ START_TEST(locale)
   test_IdnToUnicode();
   test_IsValidLocaleName();
   test_CompareStringOrdinal();
+  test_GetGeoInfo();
+  test_EnumSystemGeoID();
   /* this requires collation table patch to make it MS compatible */
   if (0) test_sorting();
 }
index b192f96..3f89086 100755 (executable)
@@ -43,6 +43,72 @@ static void CALLBACK user_apc(ULONG_PTR param)
     user_apc_ran = TRUE;
 }
 
+
+enum rpcThreadOp
+{
+    RPC_READFILE
+};
+
+struct rpcThreadArgs
+{
+    ULONG_PTR returnValue;
+    DWORD lastError;
+    enum rpcThreadOp op;
+    ULONG_PTR args[5];
+};
+
+static DWORD CALLBACK rpcThreadMain(LPVOID arg)
+{
+    struct rpcThreadArgs *rpcargs = (struct rpcThreadArgs *)arg;
+    trace("rpcThreadMain starting\n");
+    SetLastError( rpcargs->lastError );
+
+    switch (rpcargs->op)
+    {
+        case RPC_READFILE:
+            rpcargs->returnValue = (ULONG_PTR)ReadFile( (HANDLE)rpcargs->args[0],         /* hFile */
+                                                        (LPVOID)rpcargs->args[1],         /* buffer */
+                                                        (DWORD)rpcargs->args[2],          /* bytesToRead */
+                                                        (LPDWORD)rpcargs->args[3],        /* bytesRead */
+                                                        (LPOVERLAPPED)rpcargs->args[4] ); /* overlapped */
+            break;
+
+        default:
+            SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
+            rpcargs->returnValue = 0;
+            break;
+    }
+
+    rpcargs->lastError = GetLastError();
+    trace("rpcThreadMain returning\n");
+    return 0;
+}
+
+/* Runs ReadFile(...) from a different thread */
+static BOOL RpcReadFile(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead, LPOVERLAPPED overlapped)
+{
+    struct rpcThreadArgs rpcargs;
+    HANDLE thread;
+    DWORD threadId;
+
+    rpcargs.returnValue = 0;
+    rpcargs.lastError = GetLastError();
+    rpcargs.op = RPC_READFILE;
+    rpcargs.args[0] = (ULONG_PTR)hFile;
+    rpcargs.args[1] = (ULONG_PTR)buffer;
+    rpcargs.args[2] = (ULONG_PTR)bytesToRead;
+    rpcargs.args[3] = (ULONG_PTR)bytesRead;
+    rpcargs.args[4] = (ULONG_PTR)overlapped;
+
+    thread = CreateThread(NULL, 0, rpcThreadMain, (void *)&rpcargs, 0, &threadId);
+    ok(thread != NULL, "CreateThread failed. %d\n", GetLastError());
+    ok(WaitForSingleObject(thread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed with %d.\n", GetLastError());
+    CloseHandle(thread);
+
+    SetLastError(rpcargs.lastError);
+    return (BOOL)rpcargs.returnValue;
+}
+
 static void test_CreateNamedPipe(int pipemode)
 {
     HANDLE hnp;
@@ -60,6 +126,12 @@ static void test_CreateNamedPipe(int pipemode)
         trace("test_CreateNamedPipe starting in byte mode\n");
     else
         trace("test_CreateNamedPipe starting in message mode\n");
+
+    /* Wait for non existing pipe */
+    ret = WaitNamedPipeA(PIPENAME, 2000);
+    ok(ret == 0, "WaitNamedPipe returned %d for non existing pipe\n", ret);
+    ok(GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %u\n", GetLastError());
+
     /* Bad parameter checks */
     hnp = CreateNamedPipeA("not a named pipe", PIPE_ACCESS_DUPLEX, pipemode | PIPE_WAIT,
         /* nMaxInstances */ 1,
@@ -121,6 +193,21 @@ static void test_CreateNamedPipe(int pipemode)
         /* Make sure we can read and write a few bytes in both directions */
         memset(ibuf, 0, sizeof(ibuf));
         ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile\n");
+        ok(written == sizeof(obuf), "write file len\n");
+        ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
+        ok(readden == sizeof(obuf), "read got %d bytes\n", readden);
+        ok(memcmp(obuf, ibuf, written) == 0, "content check\n");
+
+        memset(ibuf, 0, sizeof(ibuf));
+        ok(WriteFile(hFile, obuf2, sizeof(obuf2), &written, NULL), "WriteFile\n");
+        ok(written == sizeof(obuf2), "write file len\n");
+        ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
+        ok(readden == sizeof(obuf2), "read got %d bytes\n", readden);
+        ok(memcmp(obuf2, ibuf, written) == 0, "content check\n");
+
+        /* Now the same again, but with an additional call to PeekNamedPipe */
+        memset(ibuf, 0, sizeof(ibuf));
+        ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile\n");
         ok(written == sizeof(obuf), "write file len 1\n");
         ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, NULL), "Peek\n");
         ok(readden == sizeof(obuf), "peek 1 got %d bytes\n", readden);
@@ -139,6 +226,65 @@ static void test_CreateNamedPipe(int pipemode)
         ok(readden == sizeof(obuf2), "read 2 got %d bytes\n", readden);
         ok(memcmp(obuf2, ibuf, written) == 0, "content 2 check\n");
 
+        /* Test how ReadFile behaves when the buffer is not big enough for the whole message */
+        memset(ibuf, 0, sizeof(ibuf));
+        ok(WriteFile(hnp, obuf2, sizeof(obuf2), &written, NULL), "WriteFile\n");
+        ok(written == sizeof(obuf2), "write file len\n");
+        ok(ReadFile(hFile, ibuf, 4, &readden, NULL), "ReadFile\n");
+        ok(readden == 4, "read got %d bytes\n", readden);
+        ok(ReadFile(hFile, ibuf + 4, sizeof(ibuf) - 4, &readden, NULL), "ReadFile\n");
+        ok(readden == sizeof(obuf2) - 4, "read got %d bytes\n", readden);
+        ok(memcmp(obuf2, ibuf, written) == 0, "content check\n");
+
+        memset(ibuf, 0, sizeof(ibuf));
+        ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile\n");
+        ok(written == sizeof(obuf), "write file len\n");
+        if (pipemode == PIPE_TYPE_BYTE)
+        {
+            ok(ReadFile(hnp, ibuf, 4, &readden, NULL), "ReadFile\n");
+        }
+        else
+        {
+            SetLastError(0xdeadbeef);
+            todo_wine
+            ok(!ReadFile(hnp, ibuf, 4, &readden, NULL), "ReadFile\n");
+            todo_wine
+            ok(GetLastError() == ERROR_MORE_DATA, "wrong error\n");
+        }
+        ok(readden == 4, "read got %d bytes\n", readden);
+        ok(ReadFile(hnp, ibuf + 4, sizeof(ibuf) - 4, &readden, NULL), "ReadFile\n");
+        ok(readden == sizeof(obuf) - 4, "read got %d bytes\n", readden);
+        ok(memcmp(obuf, ibuf, written) == 0, "content check\n");
+
+        /* Similar to above, but use a read buffer size small enough to read in three parts */
+        memset(ibuf, 0, sizeof(ibuf));
+        ok(WriteFile(hFile, obuf2, sizeof(obuf2), &written, NULL), "WriteFile\n");
+        ok(written == sizeof(obuf2), "write file len\n");
+        if (pipemode == PIPE_TYPE_BYTE)
+        {
+            ok(ReadFile(hnp, ibuf, 4, &readden, NULL), "ReadFile\n");
+            ok(readden == 4, "read got %d bytes\n", readden);
+            ok(ReadFile(hnp, ibuf + 4, 4, &readden, NULL), "ReadFile\n");
+        }
+        else
+        {
+            SetLastError(0xdeadbeef);
+            todo_wine
+            ok(!ReadFile(hnp, ibuf, 4, &readden, NULL), "ReadFile\n");
+            todo_wine
+            ok(GetLastError() == ERROR_MORE_DATA, "wrong error\n");
+            ok(readden == 4, "read got %d bytes\n", readden);
+            SetLastError(0xdeadbeef);
+            todo_wine
+            ok(!ReadFile(hnp, ibuf + 4, 4, &readden, NULL), "ReadFile\n");
+            todo_wine
+            ok(GetLastError() == ERROR_MORE_DATA, "wrong error\n");
+        }
+        ok(readden == 4, "read got %d bytes\n", readden);
+        ok(ReadFile(hnp, ibuf + 8, sizeof(ibuf) - 8, &readden, NULL), "ReadFile\n");
+        ok(readden == sizeof(obuf2) - 8, "read got %d bytes\n", readden);
+        ok(memcmp(obuf2, ibuf, written) == 0, "content check\n");
+
         /* Test reading of multiple writes */
         memset(ibuf, 0, sizeof(ibuf));
         ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile3a\n");
@@ -147,20 +293,13 @@ static void test_CreateNamedPipe(int pipemode)
         ok(written == sizeof(obuf2), "write file len 3b\n");
         ok(PeekNamedPipe(hFile, ibuf, sizeof(ibuf), &readden, &avail, NULL), "Peek3\n");
         if (pipemode == PIPE_TYPE_BYTE) {
-            if (readden != sizeof(obuf))  /* Linux only returns the first message */
-                ok(readden == sizeof(obuf) + sizeof(obuf2), "peek3 got %d bytes\n", readden);
-            else
-                todo_wine ok(readden == sizeof(obuf) + sizeof(obuf2), "peek3 got %d bytes\n", readden);
+            todo_wine ok(readden == sizeof(obuf) + sizeof(obuf2), "peek3 got %d bytes\n", readden);
         }
         else
         {
-            if (readden != sizeof(obuf) + sizeof(obuf2))  /* MacOS returns both messages */
-                ok(readden == sizeof(obuf), "peek3 got %d bytes\n", readden);
-            else
-                todo_wine ok(readden == sizeof(obuf), "peek3 got %d bytes\n", readden);
+            ok(readden == sizeof(obuf), "peek3 got %d bytes\n", readden);
         }
-        if (avail != sizeof(obuf)) /* older Linux kernels only return the first write here */
-            ok(avail == sizeof(obuf) + sizeof(obuf2), "peek3 got %d bytes available\n", avail);
+        ok(avail == sizeof(obuf) + sizeof(obuf2), "peek3 got %d bytes available\n", avail);
         pbuf = ibuf;
         ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "pipe content 3a check\n");
         if (pipemode == PIPE_TYPE_BYTE && readden >= sizeof(obuf)+sizeof(obuf2)) {
@@ -182,21 +321,13 @@ static void test_CreateNamedPipe(int pipemode)
         ok(written == sizeof(obuf2), "write file len 4b\n");
         ok(PeekNamedPipe(hnp, ibuf, sizeof(ibuf), &readden, &avail, NULL), "Peek4\n");
         if (pipemode == PIPE_TYPE_BYTE) {
-            if (readden != sizeof(obuf))  /* Linux only returns the first message */
-                /* should return all 23 bytes */
-                ok(readden == sizeof(obuf) + sizeof(obuf2), "peek4 got %d bytes\n", readden);
-            else
-                todo_wine ok(readden == sizeof(obuf) + sizeof(obuf2), "peek4 got %d bytes\n", readden);
+            todo_wine ok(readden == sizeof(obuf) + sizeof(obuf2), "peek4 got %d bytes\n", readden);
         }
         else
         {
-            if (readden != sizeof(obuf) + sizeof(obuf2))  /* MacOS returns both messages */
-                ok(readden == sizeof(obuf), "peek4 got %d bytes\n", readden);
-            else
-                todo_wine ok(readden == sizeof(obuf), "peek4 got %d bytes\n", readden);
+            ok(readden == sizeof(obuf), "peek4 got %d bytes\n", readden);
         }
-        if (avail != sizeof(obuf)) /* older Linux kernels only return the first write here */
-            ok(avail == sizeof(obuf) + sizeof(obuf2), "peek4 got %d bytes available\n", avail);
+        ok(avail == sizeof(obuf) + sizeof(obuf2), "peek4 got %d bytes available\n", avail);
         pbuf = ibuf;
         ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "pipe content 4a check\n");
         if (pipemode == PIPE_TYPE_BYTE && readden >= sizeof(obuf)+sizeof(obuf2)) {
@@ -227,9 +358,7 @@ static void test_CreateNamedPipe(int pipemode)
             ok(!SetNamedPipeHandleState(hFile, &lpmode, NULL, NULL), "Change mode\n");
         }
         else {
-            todo_wine {
-                ok(SetNamedPipeHandleState(hFile, &lpmode, NULL, NULL), "Change mode\n");
-            }
+            ok(SetNamedPipeHandleState(hFile, &lpmode, NULL, NULL), "Change mode\n");
         
             memset(ibuf, 0, sizeof(ibuf));
             ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile5a\n");
@@ -237,14 +366,8 @@ static void test_CreateNamedPipe(int pipemode)
             ok(WriteFile(hnp, obuf2, sizeof(obuf2), &written, NULL), " WriteFile5b\n");
             ok(written == sizeof(obuf2), "write file len 3b\n");
             ok(PeekNamedPipe(hFile, ibuf, sizeof(ibuf), &readden, &avail, NULL), "Peek5\n");
-            if (readden != sizeof(obuf) + sizeof(obuf2))  /* MacOS returns both writes */
-                ok(readden == sizeof(obuf), "peek5 got %d bytes\n", readden);
-            else
-                todo_wine ok(readden == sizeof(obuf), "peek5 got %d bytes\n", readden);
-            if (avail != sizeof(obuf)) /* older Linux kernels only return the first write here */
-                ok(avail == sizeof(obuf) + sizeof(obuf2), "peek5 got %d bytes available\n", avail);
-            else
-                todo_wine ok(avail == sizeof(obuf) + sizeof(obuf2), "peek5 got %d bytes available\n", avail);
+            ok(readden == sizeof(obuf), "peek5 got %d bytes\n", readden);
+            ok(avail == sizeof(obuf) + sizeof(obuf2), "peek5 got %d bytes available\n", avail);
             pbuf = ibuf;
             ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 5a check\n");
             ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
@@ -253,7 +376,9 @@ static void test_CreateNamedPipe(int pipemode)
             }
             pbuf = ibuf;
             ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 5a check\n");
-    
+            if (readden <= sizeof(obuf))
+                ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
+
             /* Multiple writes in the reverse direction */
             /* the write of obuf2 from write4 should still be in the buffer */
             ok(PeekNamedPipe(hnp, ibuf, sizeof(ibuf), &readden, &avail, NULL), "Peek6a\n");
@@ -273,12 +398,8 @@ static void test_CreateNamedPipe(int pipemode)
             ok(WriteFile(hFile, obuf2, sizeof(obuf2), &written, NULL), " WriteFile6b\n");
             ok(written == sizeof(obuf2), "write file len 6b\n");
             ok(PeekNamedPipe(hnp, ibuf, sizeof(ibuf), &readden, &avail, NULL), "Peek6\n");
-            if (readden != sizeof(obuf) + sizeof(obuf2))  /* MacOS returns both writes */
-                ok(readden == sizeof(obuf), "peek6 got %d bytes\n", readden);
-            else
-                todo_wine ok(readden == sizeof(obuf), "peek6 got %d bytes\n", readden);
-            if (avail != sizeof(obuf)) /* older Linux kernels only return the first write here */
-                ok(avail == sizeof(obuf) + sizeof(obuf2), "peek6b got %d bytes available\n", avail);
+            ok(readden == sizeof(obuf), "peek6 got %d bytes\n", readden);
+            ok(avail == sizeof(obuf) + sizeof(obuf2), "peek6b got %d bytes available\n", avail);
             pbuf = ibuf;
             ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 6a check\n");
             ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
@@ -287,6 +408,129 @@ static void test_CreateNamedPipe(int pipemode)
             }
             pbuf = ibuf;
             ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 6a check\n");
+            if (readden <= sizeof(obuf))
+                ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
+
+            /* Test how ReadFile behaves when the buffer is not big enough for the whole message */
+            memset(ibuf, 0, sizeof(ibuf));
+            ok(WriteFile(hnp, obuf2, sizeof(obuf2), &written, NULL), "WriteFile 7\n");
+            ok(written == sizeof(obuf2), "write file len 7\n");
+            SetLastError(0xdeadbeef);
+            todo_wine
+            ok(!ReadFile(hFile, ibuf, 4, &readden, NULL), "ReadFile 7\n");
+            todo_wine
+            ok(GetLastError() == ERROR_MORE_DATA, "wrong error 7\n");
+            ok(readden == 4, "read got %d bytes 7\n", readden);
+            ok(ReadFile(hFile, ibuf + 4, sizeof(ibuf) - 4, &readden, NULL), "ReadFile 7\n");
+            ok(readden == sizeof(obuf2) - 4, "read got %d bytes 7\n", readden);
+            ok(memcmp(obuf2, ibuf, written) == 0, "content check 7\n");
+
+            memset(ibuf, 0, sizeof(ibuf));
+            ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile 8\n");
+            ok(written == sizeof(obuf), "write file len 8\n");
+            SetLastError(0xdeadbeef);
+            todo_wine
+            ok(!ReadFile(hnp, ibuf, 4, &readden, NULL), "ReadFile 8\n");
+            todo_wine
+            ok(GetLastError() == ERROR_MORE_DATA, "wrong error 8\n");
+            ok(readden == 4, "read got %d bytes 8\n", readden);
+            ok(ReadFile(hnp, ibuf + 4, sizeof(ibuf) - 4, &readden, NULL), "ReadFile 8\n");
+            ok(readden == sizeof(obuf) - 4, "read got %d bytes 8\n", readden);
+            ok(memcmp(obuf, ibuf, written) == 0, "content check 8\n");
+
+            /* The following test shows that when doing a partial read of a message, the rest
+             * is still in the pipe, and can be received from a second thread. This shows
+             * especially that the content is _not_ stored in thread-local-storage until it is
+             * completely transmitted. The same method works even across multiple processes. */
+            memset(ibuf, 0, sizeof(ibuf));
+            ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile 9\n");
+            ok(written == sizeof(obuf), "write file len 9\n");
+            ok(WriteFile(hnp, obuf2, sizeof(obuf2), &written, NULL), "WriteFile 9\n");
+            ok(written == sizeof(obuf2), "write file len 9\n");
+            SetLastError(0xdeadbeef);
+            todo_wine
+            ok(!ReadFile(hFile, ibuf, 4, &readden, NULL), "ReadFile 9\n");
+            todo_wine
+            ok(GetLastError() == ERROR_MORE_DATA, "wrong error 9\n");
+            ok(readden == 4, "read got %d bytes 9\n", readden);
+            SetLastError(0xdeadbeef);
+            ret = RpcReadFile(hFile, ibuf + 4, 4, &readden, NULL);
+            todo_wine
+            ok(!ret, "RpcReadFile 9\n");
+            todo_wine
+            ok(GetLastError() == ERROR_MORE_DATA, "wrong error 9\n");
+            ok(readden == 4, "read got %d bytes 9\n", readden);
+            ret = RpcReadFile(hFile, ibuf + 8, sizeof(ibuf), &readden, NULL);
+            ok(ret, "RpcReadFile 9\n");
+            todo_wine
+            ok(readden == sizeof(obuf) - 8, "read got %d bytes 9\n", readden);
+            ok(memcmp(obuf, ibuf, sizeof(obuf)) == 0, "content check 9\n");
+            if (readden <= sizeof(obuf) - 8) /* blocks forever if second part was already received */
+            {
+                memset(ibuf, 0, sizeof(ibuf));
+                SetLastError(0xdeadbeef);
+                ret = RpcReadFile(hFile, ibuf, 4, &readden, NULL);
+                ok(!ret, "RpcReadFile 9\n");
+                todo_wine
+                ok(GetLastError() == ERROR_MORE_DATA, "wrong error 9\n");
+                ok(readden == 4, "read got %d bytes 9\n", readden);
+                SetLastError(0xdeadbeef);
+                todo_wine
+                ok(!ReadFile(hFile, ibuf + 4, 4, &readden, NULL), "ReadFile 9\n");
+                todo_wine
+                ok(GetLastError() == ERROR_MORE_DATA, "wrong error 9\n");
+                ok(readden == 4, "read got %d bytes 9\n", readden);
+                ret = RpcReadFile(hFile, ibuf + 8, sizeof(ibuf), &readden, NULL);
+                ok(ret, "RpcReadFile 9\n");
+                ok(readden == sizeof(obuf2) - 8, "read got %d bytes 9\n", readden);
+                ok(memcmp(obuf2, ibuf, sizeof(obuf2)) == 0, "content check 9\n");
+            }
+
+            /* Now the reverse direction */
+            memset(ibuf, 0, sizeof(ibuf));
+            ok(WriteFile(hFile, obuf2, sizeof(obuf2), &written, NULL), "WriteFile 10\n");
+            ok(written == sizeof(obuf2), "write file len 10\n");
+            ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile 10\n");
+            ok(written == sizeof(obuf), "write file len 10\n");
+            SetLastError(0xdeadbeef);
+            todo_wine
+            ok(!ReadFile(hnp, ibuf, 4, &readden, NULL), "ReadFile 10\n");
+            todo_wine
+            ok(GetLastError() == ERROR_MORE_DATA, "wrong error 10\n");
+            ok(readden == 4, "read got %d bytes 10\n", readden);
+            SetLastError(0xdeadbeef);
+            ret = RpcReadFile(hnp, ibuf + 4, 4, &readden, NULL);
+            todo_wine
+            ok(!ret, "RpcReadFile 10\n");
+            todo_wine
+            ok(GetLastError() == ERROR_MORE_DATA, "wrong error 10\n");
+            ok(readden == 4, "read got %d bytes 10\n", readden);
+            ret = RpcReadFile(hnp, ibuf + 8, sizeof(ibuf), &readden, NULL);
+            ok(ret, "RpcReadFile 10\n");
+            todo_wine
+            ok(readden == sizeof(obuf2) - 8, "read got %d bytes 10\n", readden);
+            ok(memcmp(obuf2, ibuf, sizeof(obuf2)) == 0, "content check 10\n");
+            if (readden <= sizeof(obuf2) - 8) /* blocks forever if second part was already received */
+            {
+                memset(ibuf, 0, sizeof(ibuf));
+                SetLastError(0xdeadbeef);
+                ret = RpcReadFile(hnp, ibuf, 4, &readden, NULL);
+                ok(!ret, "RpcReadFile 10\n");
+                todo_wine
+                ok(GetLastError() == ERROR_MORE_DATA, "wrong error 10\n");
+                ok(readden == 4, "read got %d bytes 10\n", readden);
+                SetLastError(0xdeadbeef);
+                todo_wine
+                ok(!ReadFile(hnp, ibuf + 4, 4, &readden, NULL), "ReadFile 10\n");
+                todo_wine
+                ok(GetLastError() == ERROR_MORE_DATA, "wrong error 10\n");
+                ok(readden == 4, "read got %d bytes 10\n", readden);
+                ret = RpcReadFile(hnp, ibuf + 8, sizeof(ibuf), &readden, NULL);
+                ok(ret, "RpcReadFile 10\n");
+                ok(readden == sizeof(obuf) - 8, "read got %d bytes 10\n", readden);
+                ok(memcmp(obuf, ibuf, sizeof(obuf)) == 0, "content check 10\n");
+            }
+
         }
 
         /* Picky conformance tests */
@@ -1656,11 +1900,9 @@ static void test_NamedPipeHandleState(void)
         /* lpSecurityAttrib */ NULL);
     ok(server != INVALID_HANDLE_VALUE, "cf failed\n");
     ret = GetNamedPipeHandleStateA(server, NULL, NULL, NULL, NULL, NULL, 0);
-    todo_wine
     ok(ret, "GetNamedPipeHandleState failed: %d\n", GetLastError());
     ret = GetNamedPipeHandleStateA(server, &state, &instances, NULL, NULL, NULL,
         0);
-    todo_wine
     ok(ret, "GetNamedPipeHandleState failed: %d\n", GetLastError());
     if (ret)
     {
@@ -1681,7 +1923,6 @@ static void test_NamedPipeHandleState(void)
     state = PIPE_READMODE_MESSAGE;
     SetLastError(0xdeadbeef);
     ret = SetNamedPipeHandleState(server, &state, NULL, NULL);
-    todo_wine
     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
        "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
 
@@ -1691,13 +1932,11 @@ static void test_NamedPipeHandleState(void)
 
     state = PIPE_READMODE_BYTE;
     ret = SetNamedPipeHandleState(client, &state, NULL, NULL);
-    todo_wine
     ok(ret, "SetNamedPipeHandleState failed: %d\n", GetLastError());
     /* A byte-mode pipe client can't be changed to message mode, either. */
     state = PIPE_READMODE_MESSAGE;
     SetLastError(0xdeadbeef);
     ret = SetNamedPipeHandleState(server, &state, NULL, NULL);
-    todo_wine
     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
        "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
 
@@ -1713,11 +1952,9 @@ static void test_NamedPipeHandleState(void)
         /* lpSecurityAttrib */ NULL);
     ok(server != INVALID_HANDLE_VALUE, "cf failed\n");
     ret = GetNamedPipeHandleStateA(server, NULL, NULL, NULL, NULL, NULL, 0);
-    todo_wine
     ok(ret, "GetNamedPipeHandleState failed: %d\n", GetLastError());
     ret = GetNamedPipeHandleStateA(server, &state, &instances, NULL, NULL, NULL,
         0);
-    todo_wine
     ok(ret, "GetNamedPipeHandleState failed: %d\n", GetLastError());
     if (ret)
     {
@@ -1729,7 +1966,6 @@ static void test_NamedPipeHandleState(void)
      */
     state = PIPE_READMODE_BYTE;
     ret = SetNamedPipeHandleState(server, &state, NULL, NULL);
-    todo_wine
     ok(ret, "SetNamedPipeHandleState failed: %d\n", GetLastError());
 
     client = CreateFileA(PIPENAME, GENERIC_READ|GENERIC_WRITE, 0, NULL,
@@ -1738,13 +1974,11 @@ static void test_NamedPipeHandleState(void)
 
     state = PIPE_READMODE_MESSAGE;
     ret = SetNamedPipeHandleState(client, &state, NULL, NULL);
-    todo_wine
     ok(ret, "SetNamedPipeHandleState failed: %d\n", GetLastError());
     /* A message-mode pipe client can also be changed to byte mode.
      */
     state = PIPE_READMODE_BYTE;
     ret = SetNamedPipeHandleState(client, &state, NULL, NULL);
-    todo_wine
     ok(ret, "SetNamedPipeHandleState failed: %d\n", GetLastError());
 
     CloseHandle(client);
@@ -1851,6 +2085,14 @@ static void test_readfileex_pending(void)
 
     wait = WaitForSingleObjectEx(event, 0, TRUE);
     ok(wait == WAIT_IO_COMPLETION || wait == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", wait);
+    if (wait == WAIT_TIMEOUT)
+    {
+        ret = ReadFile(client, read_buf, sizeof(read_buf), &num_bytes, NULL);
+        ok(ret == TRUE, "ReadFile failed\n");
+        ok(completion_called == 0, "completion routine called during ReadFile\n");
+        wait = WaitForSingleObjectEx(event, 0, TRUE);
+        ok(wait == WAIT_IO_COMPLETION || wait == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", wait);
+    }
 
     ok(completion_called == 1, "completion routine not called\n");
     ok(completion_errorcode == 0, "completion called with error %x\n", completion_errorcode);
index f94fed6..43551fa 100644 (file)
@@ -394,6 +394,7 @@ static void check_exe( const sec_verify *verify )
     int i;
     IMAGE_DOS_HEADER *dos;
     IMAGE_NT_HEADERS *nt;
+    IMAGE_OPTIONAL_HEADER *opt;
     IMAGE_SECTION_HEADER *sec;
     IMAGE_RESOURCE_DIRECTORY *dir;
     HANDLE file, mapping;
@@ -415,6 +416,7 @@ static void check_exe( const sec_verify *verify )
         goto end;
 
     nt = (void*) ((BYTE*) dos + dos->e_lfanew);
+    opt = &nt->OptionalHeader;
     sec = (void*) &nt[1];
 
     for(i = 0; i < max_sections; i++)
@@ -444,6 +446,10 @@ static void check_exe( const sec_verify *verify )
                 verify->NumberOfNamedEntries, dir->NumberOfNamedEntries);
         ok( dir->NumberOfIdEntries == verify->NumberOfIdEntries, "NumberOfIdEntries should be %d instead of %d\n",
                 verify->NumberOfIdEntries, dir->NumberOfIdEntries);
+
+        ok(opt->DataDirectory[IMAGE_FILE_RESOURCE_DIRECTORY].VirtualAddress == sec[verify->rsrc_section].VirtualAddress,
+                "VirtualAddress in optional header should be %d instead of %d\n",
+                sec[verify->rsrc_section].VirtualAddress, opt->DataDirectory[IMAGE_FILE_RESOURCE_DIRECTORY].VirtualAddress);
     }
 
 end:
index 674e2ec..4ef5084 100755 (executable)
@@ -24,8 +24,9 @@
 #include <stdio.h>
 #include <windef.h>
 #include <winbase.h>
+#include <winternl.h>
 
-#include "wine/test.h"
+#include <wine/test.h>
 
 static BOOL   (WINAPI *pChangeTimerQueueTimer)(HANDLE, HANDLE, ULONG, ULONG);
 static HANDLE (WINAPI *pCreateTimerQueue)(void);
@@ -55,6 +56,7 @@ static VOID   (WINAPI *pReleaseSRWLockExclusive)(PSRWLOCK);
 static VOID   (WINAPI *pReleaseSRWLockShared)(PSRWLOCK);
 static BOOLEAN (WINAPI *pTryAcquireSRWLockExclusive)(PSRWLOCK);
 static BOOLEAN (WINAPI *pTryAcquireSRWLockShared)(PSRWLOCK);
+static NTSTATUS (WINAPI *pNtWaitForMultipleObjects)(ULONG,const HANDLE*,BOOLEAN,BOOLEAN,const LARGE_INTEGER*);
 
 static void test_signalandwait(void)
 {
@@ -1153,15 +1155,32 @@ static void test_WaitForMultipleObjects(void)
     }
 
     /* a manual-reset event remains signaled, an auto-reset event is cleared */
-    r = WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, maxevents, 0, 0);
+    r = WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, maxevents, FALSE, 0);
     ok( r == WAIT_OBJECT_0, "should signal lowest handle first, got %d\n", r);
-    r = WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, maxevents, 0, 0);
+    r = WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, maxevents, FALSE, 0);
     ok( r == WAIT_OBJECT_0, "should signal handle #0 first, got %d\n", r);
     ok(ResetEvent(maxevents[0]), "ResetEvent\n");
     for (i=1; i<MAXIMUM_WAIT_OBJECTS; i++)
     {
         /* the lowest index is checked first and remaining events are untouched */
-        r = WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, maxevents, 0, 0);
+        r = WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, maxevents, FALSE, 0);
+        ok( r == WAIT_OBJECT_0+i, "should signal handle #%d first, got %d\n", i, r);
+    }
+
+    /* run same test with Nt* call */
+    for (i=0; i<MAXIMUM_WAIT_OBJECTS; i++)
+        SetEvent(maxevents[i]);
+
+    /* a manual-reset event remains signaled, an auto-reset event is cleared */
+    r = pNtWaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, maxevents, TRUE, FALSE, NULL);
+    ok( r == WAIT_OBJECT_0, "should signal lowest handle first, got %d\n", r);
+    r = pNtWaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, maxevents, TRUE, FALSE, NULL);
+    ok( r == WAIT_OBJECT_0, "should signal handle #0 first, got %d\n", r);
+    ok(ResetEvent(maxevents[0]), "ResetEvent\n");
+    for (i=1; i<MAXIMUM_WAIT_OBJECTS; i++)
+    {
+        /* the lowest index is checked first and remaining events are untouched */
+        r = pNtWaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, maxevents, TRUE, FALSE, NULL);
         ok( r == WAIT_OBJECT_0+i, "should signal handle #%d first, got %d\n", i, r);
     }
 
@@ -2117,7 +2136,7 @@ static DWORD WINAPI srwlock_base_thread3(LPVOID x)
 {
     /* seq 15 */
     while (srwlock_seq < 15) Sleep(1);
-    Sleep(50); /* some delay, such that thread2 can try to acquire a second exclusive lock */
+    Sleep(50); /* some delay, so that thread2 can try to acquire a second exclusive lock */
     if (InterlockedIncrement(&srwlock_seq) != 16)
         InterlockedIncrement(&srwlock_base_errors.wrong_execution_order);
 
@@ -2287,6 +2306,8 @@ static void test_srwlock_example(void)
 START_TEST(sync)
 {
     HMODULE hdll = GetModuleHandleA("kernel32.dll");
+    HMODULE hntdll = GetModuleHandleA("ntdll.dll");
+
     pChangeTimerQueueTimer = (void*)GetProcAddress(hdll, "ChangeTimerQueueTimer");
     pCreateTimerQueue = (void*)GetProcAddress(hdll, "CreateTimerQueue");
     pCreateTimerQueueTimer = (void*)GetProcAddress(hdll, "CreateTimerQueueTimer");
@@ -2312,6 +2333,7 @@ START_TEST(sync)
     pReleaseSRWLockShared = (void *)GetProcAddress(hdll, "ReleaseSRWLockShared");
     pTryAcquireSRWLockExclusive = (void *)GetProcAddress(hdll, "TryAcquireSRWLockExclusive");
     pTryAcquireSRWLockShared = (void *)GetProcAddress(hdll, "TryAcquireSRWLockShared");
+    pNtWaitForMultipleObjects = (void *)GetProcAddress(hntdll, "NtWaitForMultipleObjects");
 
     test_signalandwait();
     test_mutex();
index 58e71ce..bbfa0d1 100755 (executable)
@@ -1576,6 +1576,7 @@ static void test_thread_actctx(void)
     b = pGetCurrentActCtx(&handle);
     ok(b, "GetCurentActCtx failed: %u\n", GetLastError());
     ok(handle != 0, "no active context\n");
+    pReleaseActCtx(handle);
 
     param.handle = NULL;
     b = pGetCurrentActCtx(&param.handle);
@@ -1588,6 +1589,7 @@ static void test_thread_actctx(void)
     ret = WaitForSingleObject(thread, 1000);
     ok(ret == WAIT_OBJECT_0, "wait timeout\n");
     ok(param.thread_context == context, "got wrong thread context %p, %p\n", param.thread_context, context);
+    pReleaseActCtx(param.thread_context);
     CloseHandle(thread);
 
     /* similar test for CreateRemoteThread() */
@@ -1598,8 +1600,11 @@ static void test_thread_actctx(void)
     ret = WaitForSingleObject(thread, 1000);
     ok(ret == WAIT_OBJECT_0, "wait timeout\n");
     ok(param.thread_context == context, "got wrong thread context %p, %p\n", param.thread_context, context);
+    pReleaseActCtx(param.thread_context);
     CloseHandle(thread);
 
+    pReleaseActCtx(param.handle);
+
     b = pDeactivateActCtx(0, cookie);
     ok(b, "DeactivateActCtx failed: %u\n", GetLastError());
     pReleaseActCtx(context);
index 0cc4485..55d4be9 100755 (executable)
@@ -667,7 +667,7 @@ static void test_GetCalendarInfo(void)
     char bufferA[20];
     WCHAR bufferW[20];
     DWORD val1, val2;
-    int ret;
+    int ret, ret2;
 
     if (!pGetCalendarInfoA || !pGetCalendarInfoW)
     {
@@ -716,6 +716,21 @@ static void test_GetCalendarInfo(void)
     ret = pGetCalendarInfoW( 0x0409, CAL_GREGORIAN, CAL_ITWODIGITYEARMAX, NULL, 0, NULL );
     ok( ret, "GetCalendarInfoW failed err %u\n", GetLastError() );
     ok( ret == 5, "wrong size %u\n", ret );
+
+    ret = pGetCalendarInfoA( LANG_SYSTEM_DEFAULT, CAL_GREGORIAN, CAL_SDAYNAME1,
+                             bufferA, sizeof(bufferA), NULL);
+    ok( ret, "GetCalendarInfoA failed err %u\n", GetLastError() );
+    ret2 = pGetCalendarInfoA( LANG_SYSTEM_DEFAULT, CAL_GREGORIAN, CAL_SDAYNAME1,
+                              bufferA, 0, NULL);
+    ok( ret2, "GetCalendarInfoA failed err %u\n", GetLastError() );
+    ok( ret == ret2, "got %d, expected %d\n", ret2, ret );
+
+    ret2 = pGetCalendarInfoW( LANG_SYSTEM_DEFAULT, CAL_GREGORIAN, CAL_SDAYNAME1,
+                              bufferW, sizeof(bufferW), NULL);
+    ok( ret2, "GetCalendarInfoW failed err %u\n", GetLastError() );
+    ret2 = WideCharToMultiByte( CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL );
+    ok( ret == ret2, "got %d, expected %d\n", ret, ret2 );
+
 }
 
 START_TEST(time)
index 0d417a6..2caaa6c 100755 (executable)
@@ -2447,7 +2447,7 @@ todo_wine
     DeleteFileA(file_name);
 }
 
-static void test_shared_memory(int is_child)
+static void test_shared_memory(BOOL is_child)
 {
     HANDLE mapping;
     LONG *p;
@@ -2489,6 +2489,51 @@ static void test_shared_memory(int is_child)
     CloseHandle(mapping);
 }
 
+static void test_shared_memory_ro(BOOL is_child, DWORD child_access)
+{
+    HANDLE mapping;
+    LONG *p;
+
+    SetLastError(0xdeadbef);
+    mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, "winetest_virtual.c_ro");
+    ok(mapping != 0, "CreateFileMapping error %d\n", GetLastError());
+    if (is_child)
+        ok(GetLastError() == ERROR_ALREADY_EXISTS, "expected ERROR_ALREADY_EXISTS, got %d\n", GetLastError());
+
+    SetLastError(0xdeadbef);
+    p = MapViewOfFile(mapping, is_child ? child_access : FILE_MAP_READ, 0, 0, 4096);
+    ok(p != NULL, "MapViewOfFile error %d\n", GetLastError());
+
+    if (is_child)
+    {
+        *p = 0xdeadbeef;
+    }
+    else
+    {
+        char **argv;
+        char cmdline[MAX_PATH];
+        PROCESS_INFORMATION pi;
+        STARTUPINFOA si = { sizeof(si) };
+        DWORD ret;
+
+        winetest_get_mainargs(&argv);
+        sprintf(cmdline, "\"%s\" virtual sharedmemro %x", argv[0], child_access);
+        ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
+        ok(ret, "CreateProcess(%s) error %d\n", cmdline, GetLastError());
+        winetest_wait_child_process(pi.hProcess);
+        CloseHandle(pi.hThread);
+        CloseHandle(pi.hProcess);
+
+        if(child_access & FILE_MAP_WRITE)
+            ok(*p == 0xdeadbeef, "*p = %x, expected 0xdeadbeef\n", *p);
+        else
+            ok(!*p, "*p = %x, expected 0\n", *p);
+    }
+
+    UnmapViewOfFile(p);
+    CloseHandle(mapping);
+}
+
 START_TEST(virtual)
 {
     int argc;
@@ -2504,7 +2549,19 @@ START_TEST(virtual)
         }
         if (!strcmp(argv[2], "sharedmem"))
         {
-            test_shared_memory(1);
+            test_shared_memory(TRUE);
+            return;
+        }
+        if (!strcmp(argv[2], "sharedmemro"))
+        {
+            if(!winetest_interactive)
+            {
+                skip("CORE-8541: Skipping test_shared_memory_ro(TRUE, strtol(argv[3], NULL, 16))\n");
+            }
+            else
+            {
+                test_shared_memory_ro(TRUE, strtol(argv[3], NULL, 16));
+            }
             return;
         }
         while (1)
@@ -2532,7 +2589,10 @@ START_TEST(virtual)
     pNtMapViewOfSection = (void *)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtMapViewOfSection");
     pNtUnmapViewOfSection = (void *)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtUnmapViewOfSection");
 
-    test_shared_memory(0);
+    test_shared_memory(FALSE);
+    test_shared_memory_ro(FALSE, FILE_MAP_READ|FILE_MAP_WRITE);
+    test_shared_memory_ro(FALSE, FILE_MAP_COPY);
+    test_shared_memory_ro(FALSE, FILE_MAP_COPY|FILE_MAP_WRITE);
     test_mapping();
     test_CreateFileMapping_protection();
     test_VirtualAlloc_protection();