sync rostests to r44455
[reactos.git] / rostests / winetests / kernel32 / virtual.c
index dad82f6..aeb4f38 100755 (executable)
@@ -32,6 +32,8 @@
 static HINSTANCE hkernel32;
 static LPVOID (WINAPI *pVirtualAllocEx)(HANDLE, LPVOID, SIZE_T, DWORD, DWORD);
 static BOOL   (WINAPI *pVirtualFreeEx)(HANDLE, LPVOID, SIZE_T, DWORD);
+static UINT   (WINAPI *pGetWriteWatch)(DWORD,LPVOID,SIZE_T,LPVOID*,ULONG_PTR*,ULONG*);
+static UINT   (WINAPI *pResetWriteWatch)(LPVOID,SIZE_T);
 
 /* ############################### */
 
@@ -55,7 +57,7 @@ static void test_VirtualAllocEx(void)
 {
     const unsigned int alloc_size = 1<<15;
     char *src, *dst;
-    unsigned long bytes_written = 0, bytes_read = 0, i;
+    SIZE_T bytes_written = 0, bytes_read = 0, i;
     void *addr1, *addr2;
     BOOL b;
     DWORD old_prot;
@@ -64,7 +66,7 @@ static void test_VirtualAllocEx(void)
 
     /* not exported in all windows-versions  */
     if ((!pVirtualAllocEx) || (!pVirtualFreeEx)) {
-        skip("VirtualAllocEx not found\n");
+        win_skip("Virtual{Alloc,Free}Ex not available\n");
         return;
     }
 
@@ -76,14 +78,14 @@ static void test_VirtualAllocEx(void)
                            PAGE_EXECUTE_READWRITE);
     if (!addr1 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
     {   /* Win9x */
-        skip("VirtualAllocEx not implemented\n");
+        win_skip("VirtualAllocEx not implemented\n");
         TerminateProcess(hProcess, 0);
         CloseHandle(hProcess);
         return;
     }
 
-    src = HeapAlloc( GetProcessHeap(), 0, alloc_size );
-    dst = HeapAlloc( GetProcessHeap(), 0, alloc_size );
+    src = VirtualAlloc( NULL, alloc_size, MEM_COMMIT, PAGE_READWRITE );
+    dst = VirtualAlloc( NULL, alloc_size, MEM_COMMIT, PAGE_READWRITE );
     for (i = 0; i < alloc_size; i++)
         src[i] = i & 0xff;
 
@@ -94,11 +96,40 @@ static void test_VirtualAllocEx(void)
     b = ReadProcessMemory(hProcess, addr1, dst, alloc_size, &bytes_read);
     ok(b && (bytes_read == alloc_size), "%lu bytes read\n", bytes_read);
     ok(!memcmp(src, dst, alloc_size), "Data from remote process differs\n");
+
+    /* test invalid source buffers */
+
+    b = VirtualProtect( src + 0x2000, 0x2000, PAGE_NOACCESS, &old_prot );
+    ok( b, "VirtualProtect failed error %u\n", GetLastError() );
+    b = WriteProcessMemory(hProcess, addr1, src, alloc_size, &bytes_written);
+    ok( !b, "WriteProcessMemory succeeded\n" );
+    ok( GetLastError() == ERROR_NOACCESS ||
+        GetLastError() == ERROR_PARTIAL_COPY, /* vista */
+        "wrong error %u\n", GetLastError() );
+    ok( bytes_written == 0, "%lu bytes written\n", bytes_written );
+    b = ReadProcessMemory(hProcess, addr1, src, alloc_size, &bytes_read);
+    ok( !b, "ReadProcessMemory succeeded\n" );
+    ok( GetLastError() == ERROR_NOACCESS, "wrong error %u\n", GetLastError() );
+    ok( bytes_read == 0, "%lu bytes written\n", bytes_read );
+
+    b = VirtualProtect( src, 0x2000, PAGE_NOACCESS, &old_prot );
+    ok( b, "VirtualProtect failed error %u\n", GetLastError() );
+    b = WriteProcessMemory(hProcess, addr1, src, alloc_size, &bytes_written);
+    ok( !b, "WriteProcessMemory succeeded\n" );
+    ok( GetLastError() == ERROR_NOACCESS ||
+        GetLastError() == ERROR_PARTIAL_COPY, /* vista */
+        "wrong error %u\n", GetLastError() );
+    ok( bytes_written == 0, "%lu bytes written\n", bytes_written );
+    b = ReadProcessMemory(hProcess, addr1, src, alloc_size, &bytes_read);
+    ok( !b, "ReadProcessMemory succeeded\n" );
+    ok( GetLastError() == ERROR_NOACCESS, "wrong error %u\n", GetLastError() );
+    ok( bytes_read == 0, "%lu bytes written\n", bytes_read );
+
     b = pVirtualFreeEx(hProcess, addr1, 0, MEM_RELEASE);
     ok(b != 0, "VirtualFreeEx, error %u\n", GetLastError());
 
-    HeapFree( GetProcessHeap(), 0, src );
-    HeapFree( GetProcessHeap(), 0, dst );
+    VirtualFree( src, 0, MEM_FREE );
+    VirtualFree( dst, 0, MEM_FREE );
 
     /*
      * The following tests parallel those in test_VirtualAlloc()
@@ -253,6 +284,66 @@ static void test_VirtualAlloc(void)
     ok(old_prot == PAGE_READONLY,
         "wrong old protection: got %04x instead of PAGE_READONLY\n", old_prot);
 
+    ok(VirtualQuery(addr1, &info, sizeof(info)) == sizeof(info),
+        "VirtualQuery failed\n");
+    ok(info.RegionSize == 0x1000, "%lx != 0x1000\n", info.RegionSize);
+    ok(info.State == MEM_COMMIT, "%x != MEM_COMMIT\n", info.State);
+    ok(info.Protect == PAGE_READWRITE, "%x != PAGE_READWRITE\n", info.Protect);
+    memset( addr1, 0x55, 20 );
+    ok( *(DWORD *)addr1 == 0x55555555, "wrong data %x\n", *(DWORD *)addr1 );
+
+    addr2 = VirtualAlloc( addr1, 0x1000, MEM_RESET, PAGE_NOACCESS );
+    ok( addr2 == addr1 || broken( !addr2 && GetLastError() == ERROR_INVALID_PARAMETER), /* win9x */
+        "VirtualAlloc failed err %u\n", GetLastError() );
+    ok( *(DWORD *)addr1 == 0x55555555 || *(DWORD *)addr1 == 0, "wrong data %x\n", *(DWORD *)addr1 );
+    if (addr2)
+    {
+        ok(VirtualQuery(addr1, &info, sizeof(info)) == sizeof(info),
+           "VirtualQuery failed\n");
+        ok(info.RegionSize == 0x1000, "%lx != 0x1000\n", info.RegionSize);
+        ok(info.State == MEM_COMMIT, "%x != MEM_COMMIT\n", info.State);
+        ok(info.Protect == PAGE_READWRITE, "%x != PAGE_READWRITE\n", info.Protect);
+
+        addr2 = VirtualAlloc( (char *)addr1 + 0x1000, 0x1000, MEM_RESET, PAGE_NOACCESS );
+        ok( (char *)addr2 == (char *)addr1 + 0x1000, "VirtualAlloc failed\n" );
+
+        ok(VirtualQuery(addr2, &info, sizeof(info)) == sizeof(info),
+           "VirtualQuery failed\n");
+        ok(info.RegionSize == 0xf000, "%lx != 0xf000\n", info.RegionSize);
+        ok(info.State == MEM_RESERVE, "%x != MEM_RESERVE\n", info.State);
+        ok(info.Protect == 0, "%x != 0\n", info.Protect);
+
+        addr2 = VirtualAlloc( (char *)addr1 + 0xf000, 0x2000, MEM_RESET, PAGE_NOACCESS );
+        ok( !addr2, "VirtualAlloc failed\n" );
+        ok( GetLastError() == ERROR_INVALID_ADDRESS, "wrong error %u\n", GetLastError() );
+    }
+
+    /* invalid protection values */
+    SetLastError(0xdeadbeef);
+    addr2 = VirtualAlloc(NULL, 0x1000, MEM_RESERVE, 0);
+    ok(!addr2, "VirtualAlloc succeeded\n");
+    ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
+    addr2 = VirtualAlloc(NULL, 0x1000, MEM_COMMIT, 0);
+    ok(!addr2, "VirtualAlloc succeeded\n");
+    ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
+    addr2 = VirtualAlloc(addr1, 0x1000, MEM_COMMIT, PAGE_READONLY | PAGE_EXECUTE);
+    ok(!addr2, "VirtualAlloc succeeded\n");
+    ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
+    ok(!VirtualProtect(addr1, 0x1000, PAGE_READWRITE | PAGE_EXECUTE_WRITECOPY, &old_prot),
+       "VirtualProtect succeeded\n");
+    ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
+    ok(!VirtualProtect(addr1, 0x1000, 0, &old_prot), "VirtualProtect succeeded\n");
+    ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
     ok(!VirtualFree(addr1, 0x10000, 0), "VirtualFree should fail with type 0\n");
     ok(GetLastError() == ERROR_INVALID_PARAMETER,
         "got %d, expected ERROR_INVALID_PARAMETER\n", GetLastError());
@@ -270,8 +361,9 @@ static void test_VirtualAlloc(void)
 static void test_MapViewOfFile(void)
 {
     static const char testfile[] = "testfile.xxx";
-    HANDLE file, mapping;
-    void *ptr, *ptr2;
+    const char *name;
+    HANDLE file, mapping, map2;
+    void *ptr, *ptr2, *addr;
     MEMORY_BASIC_INFORMATION info;
     BOOL ret;
 
@@ -307,6 +399,39 @@ static void test_MapViewOfFile(void)
     ptr = MapViewOfFile( mapping, FILE_MAP_WRITE, 0, 0, 4096 );
     ok( ptr != NULL, "MapViewOfFile FILE_MAP_WRITE error %u\n", GetLastError() );
     UnmapViewOfFile( ptr );
+
+    ret = DuplicateHandle( GetCurrentProcess(), mapping, GetCurrentProcess(), &map2,
+                           FILE_MAP_READ|FILE_MAP_WRITE, FALSE, 0 );
+    ok( ret, "DuplicateHandle failed error %u\n", GetLastError());
+    ptr = MapViewOfFile( map2, FILE_MAP_WRITE, 0, 0, 4096 );
+    ok( ptr != NULL, "MapViewOfFile FILE_MAP_WRITE error %u\n", GetLastError() );
+    UnmapViewOfFile( ptr );
+    CloseHandle( map2 );
+
+    ret = DuplicateHandle( GetCurrentProcess(), mapping, GetCurrentProcess(), &map2,
+                           FILE_MAP_READ, FALSE, 0 );
+    ok( ret, "DuplicateHandle failed error %u\n", GetLastError());
+    ptr = MapViewOfFile( map2, FILE_MAP_WRITE, 0, 0, 4096 );
+    if (!ptr)
+    {
+        ok( GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() );
+        CloseHandle( map2 );
+        ret = DuplicateHandle( GetCurrentProcess(), mapping, GetCurrentProcess(), &map2, 0, FALSE, 0 );
+        ok( ret, "DuplicateHandle failed error %u\n", GetLastError());
+        ptr = MapViewOfFile( map2, 0, 0, 0, 4096 );
+        ok( !ptr, "MapViewOfFile succeeded\n" );
+        ok( GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() );
+        CloseHandle( map2 );
+        ret = DuplicateHandle( GetCurrentProcess(), mapping, GetCurrentProcess(), &map2,
+                               FILE_MAP_READ, FALSE, 0 );
+        ok( ret, "DuplicateHandle failed error %u\n", GetLastError());
+        ptr = MapViewOfFile( map2, 0, 0, 0, 4096 );
+        ok( ptr != NULL, "MapViewOfFile NO_ACCESS error %u\n", GetLastError() );
+    }
+    else win_skip( "no access checks on win9x\n" );
+
+    UnmapViewOfFile( ptr );
+    CloseHandle( map2 );
     CloseHandle( mapping );
 
     /* read-only mapping */
@@ -450,16 +575,24 @@ static void test_MapViewOfFile(void)
     DeleteFileA( testfile );
 
     SetLastError(0xdeadbeef);
-    file = CreateFileMapping( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, "Global\\Foo");
+    name = "Local\\Foo";
+    file = CreateFileMapping( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, name );
+    /* nt4 doesn't have Local\\ */
+    if (!file && GetLastError() == ERROR_PATH_NOT_FOUND)
+    {
+        name = "Foo";
+        file = CreateFileMapping( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, name );
+    }
     ok( file != 0, "CreateFileMapping PAGE_READWRITE error %u\n", GetLastError() );
 
     SetLastError(0xdeadbeef);
-    mapping = OpenFileMapping( FILE_MAP_READ, FALSE, "Global\\Foo" );
+    mapping = OpenFileMapping( FILE_MAP_READ, FALSE, name );
     ok( mapping != 0, "OpenFileMapping FILE_MAP_READ error %u\n", GetLastError() );
     SetLastError(0xdeadbeef);
     ptr = MapViewOfFile( mapping, FILE_MAP_WRITE, 0, 0, 0 );
-todo_wine ok( !ptr, "MapViewOfFile FILE_MAP_WRITE should fail\n" );
-todo_wine ok( GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() );
+    if (!ptr)
+    {
+        ok( GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() );
     SetLastError(0xdeadbeef);
     ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
     ok( ptr != NULL, "MapViewOfFile FILE_MAP_READ error %u\n", GetLastError() );
@@ -468,20 +601,23 @@ todo_wine ok( GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLast
         "VirtualQuery error %u\n", GetLastError() );
     ok( info.BaseAddress == ptr, "%p != %p\n", info.BaseAddress, ptr );
     ok( info.AllocationBase == ptr, "%p != %p\n", info.AllocationBase, ptr );
-todo_wine ok( info.AllocationProtect == PAGE_READONLY, "%x != PAGE_READONLY\n", info.AllocationProtect );
+        ok( info.AllocationProtect == PAGE_READONLY, "%x != PAGE_READONLY\n", info.AllocationProtect );
     ok( info.RegionSize == 4096, "%lx != 4096\n", info.RegionSize );
     ok( info.State == MEM_COMMIT, "%x != MEM_COMMIT\n", info.State );
-todo_wine ok( info.Protect == PAGE_READONLY, "%x != PAGE_READONLY\n", info.Protect );
+        ok( info.Protect == PAGE_READONLY, "%x != PAGE_READONLY\n", info.Protect );
+    }
+    else win_skip( "no access checks on win9x\n" );
     UnmapViewOfFile( ptr );
     CloseHandle( mapping );
 
     SetLastError(0xdeadbeef);
-    mapping = OpenFileMapping( FILE_MAP_WRITE, FALSE, "Global\\Foo" );
+    mapping = OpenFileMapping( FILE_MAP_WRITE, FALSE, name );
     ok( mapping != 0, "OpenFileMapping FILE_MAP_WRITE error %u\n", GetLastError() );
     SetLastError(0xdeadbeef);
     ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
-todo_wine ok( !ptr, "MapViewOfFile FILE_MAP_READ should fail\n" );
-todo_wine ok( GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() );
+    if (!ptr)
+    {
+        ok( GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() );
     SetLastError(0xdeadbeef);
     ptr = MapViewOfFile( mapping, FILE_MAP_WRITE, 0, 0, 0 );
     ok( ptr != NULL, "MapViewOfFile FILE_MAP_WRITE error %u\n", GetLastError() );
@@ -494,6 +630,8 @@ todo_wine ok( GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLast
     ok( info.RegionSize == 4096, "%lx != 4096\n", info.RegionSize );
     ok( info.State == MEM_COMMIT, "%x != MEM_COMMIT\n", info.State );
     ok( info.Protect == PAGE_READWRITE, "%x != PAGE_READWRITE\n", info.Protect );
+    }
+    else win_skip( "no access checks on win9x\n" );
     UnmapViewOfFile( ptr );
     CloseHandle( mapping );
 
@@ -506,56 +644,128 @@ todo_wine ok( GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLast
     ptr = MapViewOfFile(mapping, FILE_MAP_WRITE, 0, 0, 0);
     ok(ptr != NULL, "MapViewOfFile failed with error %d\n", GetLastError());
 
+    ptr2 = MapViewOfFile(mapping, FILE_MAP_WRITE, 0, 0, 0);
+    /* on NT ptr != ptr2 but on Win9x ptr == ptr2 */
+    ok(ptr2 != NULL, "MapViewOfFile failed with error %d\n", GetLastError());
+    trace("mapping same section resulted in views %p and %p\n", ptr, ptr2);
+
     ret = VirtualQuery(ptr, &info, sizeof(info));
     ok(ret, "VirtualQuery failed with error %d\n", GetLastError());
     ok(info.BaseAddress == ptr, "BaseAddress should have been %p but was %p instead\n", ptr, info.BaseAddress);
     ok(info.AllocationBase == ptr, "AllocationBase should have been %p but was %p instead\n", ptr, info.AllocationBase);
-    ok(info.AllocationProtect == PAGE_READWRITE, "AllocationProtect should have been PAGE_READWRITE but was 0x%x\n", info.AllocationProtect);
     ok(info.RegionSize == MAPPING_SIZE, "RegionSize should have been 0x%x but was 0x%x\n", MAPPING_SIZE, (unsigned int)info.RegionSize);
-todo_wine
     ok(info.State == MEM_RESERVE, "State should have been MEM_RESERVE instead of 0x%x\n", info.State);
-todo_wine
+    if (info.Type == MEM_PRIVATE)  /* win9x is different for uncommitted mappings */
+    {
+        ok(info.AllocationProtect == PAGE_NOACCESS,
+           "AllocationProtect should have been PAGE_NOACCESS but was 0x%x\n", info.AllocationProtect);
+        ok(info.Protect == PAGE_NOACCESS,
+           "Protect should have been PAGE_NOACCESS instead of 0x%x\n", info.Protect);
+    }
+    else
+    {
+        ok(info.AllocationProtect == PAGE_READWRITE,
+           "AllocationProtect should have been PAGE_READWRITE but was 0x%x\n", info.AllocationProtect);
     ok(info.Protect == 0, "Protect should have been 0 instead of 0x%x\n", info.Protect);
     ok(info.Type == MEM_MAPPED, "Type should have been MEM_MAPPED instead of 0x%x\n", info.Type);
+    }
 
-    ptr = VirtualAlloc(ptr, 0x10000, MEM_COMMIT, PAGE_READWRITE);
+    if (ptr != ptr2)
+    {
+        ret = VirtualQuery(ptr2, &info, sizeof(info));
+        ok(ret, "VirtualQuery failed with error %d\n", GetLastError());
+        ok(info.BaseAddress == ptr2,
+           "BaseAddress should have been %p but was %p instead\n", ptr2, info.BaseAddress);
+        ok(info.AllocationBase == ptr2,
+           "AllocationBase should have been %p but was %p instead\n", ptr2, info.AllocationBase);
+        ok(info.AllocationProtect == PAGE_READWRITE,
+           "AllocationProtect should have been PAGE_READWRITE but was 0x%x\n", info.AllocationProtect);
+        ok(info.RegionSize == MAPPING_SIZE,
+           "RegionSize should have been 0x%x but was 0x%x\n", MAPPING_SIZE, (unsigned int)info.RegionSize);
+        ok(info.State == MEM_RESERVE,
+           "State should have been MEM_RESERVE instead of 0x%x\n", info.State);
+        ok(info.Protect == 0,
+           "Protect should have been 0 instead of 0x%x\n", info.Protect);
+        ok(info.Type == MEM_MAPPED,
+           "Type should have been MEM_MAPPED instead of 0x%x\n", info.Type);
+    }
+
+    ptr = VirtualAlloc(ptr, 0x10000, MEM_COMMIT, PAGE_READONLY);
     ok(ptr != NULL, "VirtualAlloc failed with error %d\n", GetLastError());
 
     ret = VirtualQuery(ptr, &info, sizeof(info));
     ok(ret, "VirtualQuery failed with error %d\n", GetLastError());
     ok(info.BaseAddress == ptr, "BaseAddress should have been %p but was %p instead\n", ptr, info.BaseAddress);
     ok(info.AllocationBase == ptr, "AllocationBase should have been %p but was %p instead\n", ptr, info.AllocationBase);
-    ok(info.AllocationProtect == PAGE_READWRITE, "AllocationProtect should have been PAGE_READWRITE but was 0x%x\n", info.AllocationProtect);
-todo_wine
     ok(info.RegionSize == 0x10000, "RegionSize should have been 0x10000 but was 0x%x\n", (unsigned int)info.RegionSize);
     ok(info.State == MEM_COMMIT, "State should have been MEM_RESERVE instead of 0x%x\n", info.State);
-    ok(info.Protect == PAGE_READWRITE, "Protect should have been 0 instead of 0x%x\n", info.Protect);
+    ok(info.Protect == PAGE_READONLY, "Protect should have been 0 instead of 0x%x\n", info.Protect);
+    if (info.Type == MEM_PRIVATE)  /* win9x is different for uncommitted mappings */
+    {
+        ok(info.AllocationProtect == PAGE_NOACCESS,
+           "AllocationProtect should have been PAGE_NOACCESS but was 0x%x\n", info.AllocationProtect);
+    }
+    else
+    {
+        ok(info.AllocationProtect == PAGE_READWRITE,
+           "AllocationProtect should have been PAGE_READWRITE but was 0x%x\n", info.AllocationProtect);
     ok(info.Type == MEM_MAPPED, "Type should have been MEM_MAPPED instead of 0x%x\n", info.Type);
-
-    ptr2 = MapViewOfFile(mapping, FILE_MAP_WRITE, 0, 0, 0);
-    /* on NT ptr != ptr2 but on Win9x ptr == ptr2 */
-    ok(ptr2 != NULL, "MapViewOfFile failed with error %d\n", GetLastError());
-    trace("mapping same section resulted in views %p and %p\n", ptr, ptr2);
+    }
 
     /* shows that the VirtualAlloc above affects the mapping, not just the
      * virtual memory in this process - it also affects all other processes
      * with a view of the mapping, but that isn't tested here */
+    if (ptr != ptr2)
+    {
     ret = VirtualQuery(ptr2, &info, sizeof(info));
     ok(ret, "VirtualQuery failed with error %d\n", GetLastError());
-    ok(info.BaseAddress == ptr2, "BaseAddress should have been %p but was %p instead\n", ptr2, info.BaseAddress);
-    ok(info.AllocationBase == ptr2, "AllocationBase should have been %p but was %p instead\n", ptr2, info.AllocationBase);
-    ok(info.AllocationProtect == PAGE_READWRITE, "AllocationProtect should have been PAGE_READWRITE but was 0x%x\n", info.AllocationProtect);
-todo_wine
-    ok(info.RegionSize == 0x10000, "RegionSize should have been 0x10000 but was 0x%x\n", (unsigned int)info.RegionSize);
-    ok(info.State == MEM_COMMIT, "State should have been MEM_RESERVE instead of 0x%x\n", info.State);
-    ok(info.Protect == PAGE_READWRITE, "Protect should have been 0 instead of 0x%x\n", info.Protect);
+        ok(info.BaseAddress == ptr2,
+           "BaseAddress should have been %p but was %p instead\n", ptr2, info.BaseAddress);
+        ok(info.AllocationBase == ptr2,
+           "AllocationBase should have been %p but was %p instead\n", ptr2, info.AllocationBase);
+        ok(info.AllocationProtect == PAGE_READWRITE,
+           "AllocationProtect should have been PAGE_READWRITE but was 0x%x\n", info.AllocationProtect);
+        ok(info.RegionSize == 0x10000,
+           "RegionSize should have been 0x10000 but was 0x%x\n", (unsigned int)info.RegionSize);
+        ok(info.State == MEM_COMMIT,
+           "State should have been MEM_RESERVE instead of 0x%x\n", info.State);
+        ok(info.Protect == PAGE_READWRITE,
+           "Protect should have been 0 instead of 0x%x\n", info.Protect);
     ok(info.Type == MEM_MAPPED, "Type should have been MEM_MAPPED instead of 0x%x\n", info.Type);
+    }
+
+    addr = VirtualAlloc( ptr, MAPPING_SIZE, MEM_RESET, PAGE_READONLY );
+    ok( addr == ptr || broken(!addr && GetLastError() == ERROR_INVALID_PARAMETER), /* win9x */
+        "VirtualAlloc failed with error %u\n", GetLastError() );
+
+    ret = VirtualFree( ptr, 0x10000, MEM_DECOMMIT );
+    ok( !ret || broken(ret) /* win9x */, "VirtualFree succeeded\n" );
+    if (!ret)
+        ok( GetLastError() == ERROR_INVALID_PARAMETER, "VirtualFree failed with %u\n", GetLastError() );
 
     ret = UnmapViewOfFile(ptr2);
     ok(ret, "UnmapViewOfFile failed with error %d\n", GetLastError());
     ret = UnmapViewOfFile(ptr);
     ok(ret, "UnmapViewOfFile failed with error %d\n", GetLastError());
     CloseHandle(mapping);
+
+    addr = VirtualAlloc(NULL, 0x10000, MEM_COMMIT, PAGE_READONLY );
+    ok( addr != NULL, "VirtualAlloc failed with error %u\n", GetLastError() );
+
+    SetLastError(0xdeadbeef);
+    ok( !UnmapViewOfFile(addr), "UnmapViewOfFile should fail on VirtualAlloc mem\n" );
+    ok( GetLastError() == ERROR_INVALID_ADDRESS,
+        "got %u, expected ERROR_INVALID_ADDRESS\n", GetLastError());
+    SetLastError(0xdeadbeef);
+    ok( !UnmapViewOfFile((char *)addr + 0x3000), "UnmapViewOfFile should fail on VirtualAlloc mem\n" );
+    ok( GetLastError() == ERROR_INVALID_ADDRESS,
+        "got %u, expected ERROR_INVALID_ADDRESS\n", GetLastError());
+    SetLastError(0xdeadbeef);
+    ok( !UnmapViewOfFile((void *)0xdeadbeef), "UnmapViewOfFile should fail on VirtualAlloc mem\n" );
+    ok( GetLastError() == ERROR_INVALID_ADDRESS,
+       "got %u, expected ERROR_INVALID_ADDRESS\n", GetLastError());
+
+    ok( VirtualFree(addr, 0, MEM_RELEASE), "VirtualFree failed\n" );
 }
 
 static DWORD (WINAPI *pNtMapViewOfSection)( HANDLE handle, HANDLE process, PVOID *addr_ptr,
@@ -582,7 +792,7 @@ static void test_NtMapViewOfSection(void)
     pNtUnmapViewOfSection = (void *)GetProcAddress( GetModuleHandle("ntdll.dll"), "NtUnmapViewOfSection" );
     if (!pNtMapViewOfSection || !pNtUnmapViewOfSection)
     {
-        skip( "NtMapViewOfSection not found\n" );
+        win_skip( "NtMapViewOfSection not available\n" );
         return;
     }
 
@@ -622,6 +832,46 @@ static void test_NtMapViewOfSection(void)
     CloseHandle(hProcess);
 }
 
+static void test_CreateFileMapping(void)
+{
+    HANDLE handle, handle2;
+
+    /* test case sensitivity */
+
+    SetLastError(0xdeadbeef);
+    handle = CreateFileMappingA( INVALID_HANDLE_VALUE, NULL, SEC_COMMIT | PAGE_READWRITE, 0, 0x1000,
+                                 "Wine Test Mapping");
+    ok( handle != NULL, "CreateFileMapping failed with error %u\n", GetLastError());
+    ok( GetLastError() == 0, "wrong error %u\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
+    handle2 = CreateFileMappingA( INVALID_HANDLE_VALUE, NULL, SEC_COMMIT | PAGE_READWRITE, 0, 0x1000,
+                                  "Wine Test Mapping");
+    ok( handle2 != NULL, "CreateFileMapping failed with error %d\n", GetLastError());
+    ok( GetLastError() == ERROR_ALREADY_EXISTS, "wrong error %u\n", GetLastError());
+    CloseHandle( handle2 );
+
+    SetLastError(0xdeadbeef);
+    handle2 = CreateFileMappingA( INVALID_HANDLE_VALUE, NULL, SEC_COMMIT | PAGE_READWRITE, 0, 0x1000,
+                                 "WINE TEST MAPPING");
+    ok( handle2 != NULL, "CreateFileMapping failed with error %d\n", GetLastError());
+    ok( GetLastError() == 0, "wrong error %u\n", GetLastError());
+    CloseHandle( handle2 );
+
+    SetLastError(0xdeadbeef);
+    handle2 = OpenFileMappingA( FILE_MAP_ALL_ACCESS, FALSE, "Wine Test Mapping");
+    ok( handle2 != NULL, "OpenFileMapping failed with error %d\n", GetLastError());
+    CloseHandle( handle2 );
+
+    SetLastError(0xdeadbeef);
+    handle2 = OpenFileMappingA( FILE_MAP_ALL_ACCESS, FALSE, "WINE TEST MAPPING");
+    ok( !handle2, "OpenFileMapping succeeded\n");
+    ok( GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_INVALID_NAME /* win9x */,
+        "wrong error %u\n", GetLastError());
+
+    CloseHandle( handle );
+}
+
 static void test_BadPtr(void)
 {
     void *ptr = (void*)1;
@@ -631,6 +881,306 @@ static void test_BadPtr(void)
     ok(IsBadCodePtr(ptr),"IsBadCodePtr(1) failed.\n");
 }
 
+static void test_write_watch(void)
+{
+    char *base;
+    DWORD ret, size, old_prot;
+    MEMORY_BASIC_INFORMATION info;
+    void *results[64];
+    ULONG_PTR count;
+    ULONG pagesize;
+
+    if (!pGetWriteWatch || !pResetWriteWatch)
+    {
+        win_skip( "GetWriteWatch not supported\n" );
+        return;
+    }
+
+    size = 0x10000;
+    base = VirtualAlloc( 0, size, MEM_RESERVE | MEM_COMMIT | MEM_WRITE_WATCH, PAGE_READWRITE );
+    if (!base &&
+        (GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_NOT_SUPPORTED))
+    {
+        win_skip( "MEM_WRITE_WATCH not supported\n" );
+        return;
+    }
+    ok( base != NULL, "VirtualAlloc failed %u\n", GetLastError() );
+    ret = VirtualQuery( base, &info, sizeof(info) );
+    ok(ret, "VirtualQuery failed %u\n", GetLastError());
+    ok( info.BaseAddress == base, "BaseAddress %p instead of %p\n", info.BaseAddress, base );
+    ok( info.AllocationProtect == PAGE_READWRITE, "wrong AllocationProtect %x\n", info.AllocationProtect );
+    ok( info.RegionSize == size, "wrong RegionSize 0x%lx\n", info.RegionSize );
+    ok( info.State == MEM_COMMIT, "wrong State 0x%x\n", info.State );
+    ok( info.Protect == PAGE_READWRITE, "wrong Protect 0x%x\n", info.Protect );
+    ok( info.Type == MEM_PRIVATE, "wrong Type 0x%x\n", info.Type );
+
+    count = 64;
+    SetLastError( 0xdeadbeef );
+    ret = pGetWriteWatch( 0, NULL, size, results, &count, &pagesize );
+    ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret );
+    ok( GetLastError() == ERROR_INVALID_PARAMETER ||
+        broken( GetLastError() == 0xdeadbeef ), /* win98 */
+        "wrong error %u\n", GetLastError() );
+
+    SetLastError( 0xdeadbeef );
+    ret = pGetWriteWatch( 0, GetModuleHandle(0), size, results, &count, &pagesize );
+    if (ret)
+    {
+        ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret );
+        ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
+    }
+    else  /* win98 */
+    {
+        ok( count == 0, "wrong count %lu\n", count );
+    }
+
+    ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize );
+    ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
+    ok( count == 0, "wrong count %lu\n", count );
+
+    base[pagesize + 1] = 0x44;
+
+    count = 64;
+    ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize );
+    ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
+    ok( count == 1, "wrong count %lu\n", count );
+    ok( results[0] == base + pagesize, "wrong result %p\n", results[0] );
+
+    count = 64;
+    ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
+    ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
+    ok( count == 1, "wrong count %lu\n", count );
+    ok( results[0] == base + pagesize, "wrong result %p\n", results[0] );
+
+    count = 64;
+    ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize );
+    ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
+    ok( count == 0, "wrong count %lu\n", count );
+
+    base[2*pagesize + 3] = 0x11;
+    base[4*pagesize + 8] = 0x11;
+
+    count = 64;
+    ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize );
+    ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
+    ok( count == 2, "wrong count %lu\n", count );
+    ok( results[0] == base + 2*pagesize, "wrong result %p\n", results[0] );
+    ok( results[1] == base + 4*pagesize, "wrong result %p\n", results[1] );
+
+    count = 64;
+    ret = pGetWriteWatch( 0, base + 3*pagesize, 2*pagesize, results, &count, &pagesize );
+    ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
+    ok( count == 1, "wrong count %lu\n", count );
+    ok( results[0] == base + 4*pagesize, "wrong result %p\n", results[0] );
+
+    ret = pResetWriteWatch( base, 3*pagesize );
+    ok( !ret, "pResetWriteWatch failed %u\n", GetLastError() );
+
+    count = 64;
+    ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize );
+    ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
+    ok( count == 1, "wrong count %lu\n", count );
+    ok( results[0] == base + 4*pagesize, "wrong result %p\n", results[0] );
+
+    *(DWORD *)(base + 2*pagesize - 2) = 0xdeadbeef;
+
+    count = 64;
+    ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize );
+    ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
+    ok( count == 3, "wrong count %lu\n", count );
+    ok( results[0] == base + pagesize, "wrong result %p\n", results[0] );
+    ok( results[1] == base + 2*pagesize, "wrong result %p\n", results[1] );
+    ok( results[2] == base + 4*pagesize, "wrong result %p\n", results[2] );
+
+    count = 1;
+    ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize );
+    ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
+    ok( count == 1, "wrong count %lu\n", count );
+    ok( results[0] == base + pagesize, "wrong result %p\n", results[0] );
+
+    count = 64;
+    ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize );
+    ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
+    ok( count == 2, "wrong count %lu\n", count );
+    ok( results[0] == base + 2*pagesize, "wrong result %p\n", results[0] );
+    ok( results[1] == base + 4*pagesize, "wrong result %p\n", results[1] );
+
+    /* changing protections doesn't affect watches */
+
+    ret = VirtualProtect( base, 3*pagesize, PAGE_READONLY, &old_prot );
+    ok( ret, "VirtualProtect failed error %u\n", GetLastError() );
+    ok( old_prot == PAGE_READWRITE, "wrong old prot %x\n", old_prot );
+
+    ret = VirtualQuery( base, &info, sizeof(info) );
+    ok(ret, "VirtualQuery failed %u\n", GetLastError());
+    ok( info.BaseAddress == base, "BaseAddress %p instead of %p\n", info.BaseAddress, base );
+    ok( info.RegionSize == 3*pagesize, "wrong RegionSize 0x%lx\n", info.RegionSize );
+    ok( info.State == MEM_COMMIT, "wrong State 0x%x\n", info.State );
+    ok( info.Protect == PAGE_READONLY, "wrong Protect 0x%x\n", info.Protect );
+
+    ret = VirtualProtect( base, 3*pagesize, PAGE_READWRITE, &old_prot );
+    ok( ret, "VirtualProtect failed error %u\n", GetLastError() );
+    ok( old_prot == PAGE_READONLY, "wrong old prot %x\n", old_prot );
+
+    count = 64;
+    ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize );
+    ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
+    ok( count == 2, "wrong count %lu\n", count );
+    ok( results[0] == base + 2*pagesize, "wrong result %p\n", results[0] );
+    ok( results[1] == base + 4*pagesize, "wrong result %p\n", results[1] );
+
+    ret = VirtualQuery( base, &info, sizeof(info) );
+    ok(ret, "VirtualQuery failed %u\n", GetLastError());
+    ok( info.BaseAddress == base, "BaseAddress %p instead of %p\n", info.BaseAddress, base );
+    ok( info.RegionSize == size, "wrong RegionSize 0x%lx\n", info.RegionSize );
+    ok( info.State == MEM_COMMIT, "wrong State 0x%x\n", info.State );
+    ok( info.Protect == PAGE_READWRITE, "wrong Protect 0x%x\n", info.Protect );
+
+    /* some invalid parameter tests */
+
+    SetLastError( 0xdeadbeef );
+    count = 0;
+    ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize );
+    if (ret)
+    {
+        ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret );
+        ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
+
+        SetLastError( 0xdeadbeef );
+        ret = pGetWriteWatch( 0, base, size, results, NULL, &pagesize );
+        ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret );
+        ok( GetLastError() == ERROR_NOACCESS, "wrong error %u\n", GetLastError() );
+
+        SetLastError( 0xdeadbeef );
+        count = 64;
+        ret = pGetWriteWatch( 0, base, size, results, &count, NULL );
+        ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret );
+        ok( GetLastError() == ERROR_NOACCESS, "wrong error %u\n", GetLastError() );
+
+        SetLastError( 0xdeadbeef );
+        count = 64;
+        ret = pGetWriteWatch( 0, base, size, NULL, &count, &pagesize );
+        ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret );
+        ok( GetLastError() == ERROR_NOACCESS, "wrong error %u\n", GetLastError() );
+
+        SetLastError( 0xdeadbeef );
+        count = 0;
+        ret = pGetWriteWatch( 0, base, size, NULL, &count, &pagesize );
+        ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret );
+        ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
+
+        SetLastError( 0xdeadbeef );
+        count = 64;
+        ret = pGetWriteWatch( 0xdeadbeef, base, size, results, &count, &pagesize );
+        ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret );
+        ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
+
+        SetLastError( 0xdeadbeef );
+        count = 64;
+        ret = pGetWriteWatch( 0, base, 0, results, &count, &pagesize );
+        ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret );
+        ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
+
+        SetLastError( 0xdeadbeef );
+        count = 64;
+        ret = pGetWriteWatch( 0, base, size * 2, results, &count, &pagesize );
+        ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret );
+        ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
+
+        SetLastError( 0xdeadbeef );
+        count = 64;
+        ret = pGetWriteWatch( 0, base + size - pagesize, pagesize + 1, results, &count, &pagesize );
+        ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret );
+        ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
+
+        SetLastError( 0xdeadbeef );
+        ret = pResetWriteWatch( base, 0 );
+        ok( ret == ~0u, "ResetWriteWatch succeeded %u\n", ret );
+        ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
+
+        SetLastError( 0xdeadbeef );
+        ret = pResetWriteWatch( GetModuleHandle(0), size );
+        ok( ret == ~0u, "ResetWriteWatch succeeded %u\n", ret );
+        ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
+    }
+    else  /* win98 is completely different */
+    {
+        SetLastError( 0xdeadbeef );
+        count = 64;
+        ret = pGetWriteWatch( 0, base, size, NULL, &count, &pagesize );
+        ok( ret == ERROR_INVALID_PARAMETER, "GetWriteWatch succeeded %u\n", ret );
+        ok( GetLastError() == 0xdeadbeef, "wrong error %u\n", GetLastError() );
+
+        count = 0;
+        ret = pGetWriteWatch( 0, base, size, NULL, &count, &pagesize );
+        ok( !ret, "GetWriteWatch failed %u\n", ret );
+
+        count = 64;
+        ret = pGetWriteWatch( 0xdeadbeef, base, size, results, &count, &pagesize );
+        ok( !ret, "GetWriteWatch failed %u\n", ret );
+
+        count = 64;
+        ret = pGetWriteWatch( 0, base, 0, results, &count, &pagesize );
+        ok( !ret, "GetWriteWatch failed %u\n", ret );
+
+        ret = pResetWriteWatch( base, 0 );
+        ok( !ret, "ResetWriteWatch failed %u\n", ret );
+
+        ret = pResetWriteWatch( GetModuleHandle(0), size );
+        ok( !ret, "ResetWriteWatch failed %u\n", ret );
+    }
+
+    VirtualFree( base, 0, MEM_FREE );
+
+    base = VirtualAlloc( 0, size, MEM_RESERVE | MEM_WRITE_WATCH, PAGE_READWRITE );
+    ok( base != NULL, "VirtualAlloc failed %u\n", GetLastError() );
+    VirtualFree( base, 0, MEM_FREE );
+
+    base = VirtualAlloc( 0, size, MEM_WRITE_WATCH, PAGE_READWRITE );
+    ok( !base, "VirtualAlloc succeeded\n" );
+    ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
+
+    /* initial protect doesn't matter */
+
+    base = VirtualAlloc( 0, size, MEM_RESERVE | MEM_WRITE_WATCH, PAGE_NOACCESS );
+    ok( base != NULL, "VirtualAlloc failed %u\n", GetLastError() );
+    base = VirtualAlloc( base, size, MEM_COMMIT, PAGE_NOACCESS );
+    ok( base != NULL, "VirtualAlloc failed %u\n", GetLastError() );
+
+    count = 64;
+    ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize );
+    ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
+    ok( count == 0, "wrong count %lu\n", count );
+
+    ret = VirtualProtect( base, 6*pagesize, PAGE_READWRITE, &old_prot );
+    ok( ret, "VirtualProtect failed error %u\n", GetLastError() );
+    ok( old_prot == PAGE_NOACCESS, "wrong old prot %x\n", old_prot );
+
+    base[5*pagesize + 200] = 3;
+
+    ret = VirtualProtect( base, 6*pagesize, PAGE_NOACCESS, &old_prot );
+    ok( ret, "VirtualProtect failed error %u\n", GetLastError() );
+    ok( old_prot == PAGE_READWRITE, "wrong old prot %x\n", old_prot );
+
+    count = 64;
+    ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize );
+    ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
+    ok( count == 1, "wrong count %lu\n", count );
+    ok( results[0] == base + 5*pagesize, "wrong result %p\n", results[0] );
+
+    ret = VirtualFree( base, size, MEM_DECOMMIT );
+    ok( ret, "VirtualFree failed %u\n", GetLastError() );
+
+    count = 64;
+    ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize );
+    ok( !ret, "GetWriteWatch failed %u\n", GetLastError() );
+    ok( count == 1 || broken(count == 0), /* win98 */
+        "wrong count %lu\n", count );
+    if (count) ok( results[0] == base + 5*pagesize, "wrong result %p\n", results[0] );
+
+    VirtualFree( base, 0, MEM_FREE );
+}
+
 START_TEST(virtual)
 {
     int argc;
@@ -662,10 +1212,14 @@ START_TEST(virtual)
     hkernel32 = GetModuleHandleA("kernel32.dll");
     pVirtualAllocEx = (void *) GetProcAddress(hkernel32, "VirtualAllocEx");
     pVirtualFreeEx = (void *) GetProcAddress(hkernel32, "VirtualFreeEx");
+    pGetWriteWatch = (void *) GetProcAddress(hkernel32, "GetWriteWatch");
+    pResetWriteWatch = (void *) GetProcAddress(hkernel32, "ResetWriteWatch");
 
     test_VirtualAllocEx();
     test_VirtualAlloc();
     test_MapViewOfFile();
     test_NtMapViewOfSection();
+    test_CreateFileMapping();
     test_BadPtr();
+    test_write_watch();
 }