sync kernel32_winetest with wine 1.1.23
authorChristoph von Wittich <christoph_vw@reactos.org>
Sat, 6 Jun 2009 16:10:47 +0000 (16:10 +0000)
committerChristoph von Wittich <christoph_vw@reactos.org>
Sat, 6 Jun 2009 16:10:47 +0000 (16:10 +0000)
svn path=/trunk/; revision=41311

15 files changed:
rostests/winetests/kernel32/comm.c
rostests/winetests/kernel32/debugger.c
rostests/winetests/kernel32/directory.c
rostests/winetests/kernel32/drive.c
rostests/winetests/kernel32/file.c
rostests/winetests/kernel32/format_msg.c
rostests/winetests/kernel32/heap.c
rostests/winetests/kernel32/locale.c
rostests/winetests/kernel32/module.c
rostests/winetests/kernel32/path.c
rostests/winetests/kernel32/process.c
rostests/winetests/kernel32/profile.c
rostests/winetests/kernel32/thread.c
rostests/winetests/kernel32/virtual.c
rostests/winetests/kernel32/volume.c

index 99fe505..8cd07ad 100755 (executable)
@@ -571,7 +571,10 @@ static void test_BuildCommDCBW(TEST *ptest, int initial_value, DCB *pexpected_dc
        result = BuildCommDCBW(wide_string, &dcb);
 
        if(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+       {
+               win_skip("BuildCommDCBW is not available\n");
                return;
+       }
 
        /* check results */
        check_result("BuildCommDCBW", ptest, initial_value, result);
@@ -595,7 +598,10 @@ static void test_BuildCommDCBAndTimeoutsW(TEST *ptest, int initial_value, DCB *p
        result = BuildCommDCBAndTimeoutsW(wide_string, &dcb, &timeouts);
 
        if(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+       {
+               win_skip("BuildCommDCBAndTimeoutsW is not available\n");
                return;
+       }
 
        /* check results */
        check_result("BuildCommDCBAndTimeoutsA", ptest, initial_value, result);
index 363dd21..01b77d1 100644 (file)
@@ -282,15 +282,16 @@ static void crash_and_debug(HKEY hkey, const char* argv0, const char* dbgtasks)
         /* If, after attaching to the debuggee, the debugger exits without
          * detaching, then the debuggee gets a special exit code.
          */
-        ok(exit_code == 0xffffffff || /* Win 9x */
-           exit_code == 0x80 || /* NT4 */
-           exit_code == STATUS_DEBUGGER_INACTIVE, /* Win >= XP */
+        ok(exit_code == STATUS_DEBUGGER_INACTIVE ||
+           broken(exit_code == 0xffffffff) || /* Win9x */
+           broken(exit_code == WAIT_ABANDONED), /* NT4, W2K */
            "wrong exit code : %08x\n", exit_code);
     }
     else
-         ok(exit_code == STATUS_ACCESS_VIOLATION ||
-            exit_code == WAIT_ABANDONED, /* win2k3 */
-            "exit code = %08x instead of STATUS_ACCESS_VIOLATION or WAIT_ABANDONED\n", exit_code);
+        ok(exit_code == STATUS_ACCESS_VIOLATION ||
+           broken(exit_code == WAIT_ABANDONED) || /* NT4, W2K, W2K3 */
+           broken(exit_code == 0xffffffff), /* Win9x, WinME */
+           "wrong exit code : %08x\n", exit_code);
     CloseHandle(info.hProcess);
 
     /* ...before the debugger */
@@ -412,8 +413,12 @@ static void test_ExitCode(void)
     crash_and_debug(hkey, test_exe, "dbg,attach,event,code2");
     if (pDebugSetProcessKillOnExit)
         crash_and_debug(hkey, test_exe, "dbg,attach,event,nokill");
+    else
+        win_skip("DebugSetProcessKillOnExit is not available\n");
     if (pDebugActiveProcessStop)
         crash_and_debug(hkey, test_exe, "dbg,attach,event,detach");
+    else
+        win_skip("DebugActiveProcessStop is not available\n");
 
     if (disposition == REG_CREATED_NEW_KEY)
     {
index a0ccd9f..8d1c457 100755 (executable)
@@ -61,8 +61,11 @@ static void test_GetWindowsDirectoryW(void)
     static const WCHAR fooW[] = {'f','o','o',0};
 
     len_with_null = GetWindowsDirectoryW(NULL, 0);
-    if (len_with_null==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
+    if (len_with_null == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+    {
+        win_skip("GetWindowsDirectoryW is not implemented\n");
         return;
+    }
     ok(len_with_null <= MAX_PATH, "should fit into MAX_PATH\n");
 
     lstrcpyW(buf, fooW);
@@ -124,8 +127,11 @@ static void test_GetSystemDirectoryW(void)
     static const WCHAR fooW[] = {'f','o','o',0};
 
     len_with_null = GetSystemDirectoryW(NULL, 0);
-    if (len_with_null==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
+    if (len_with_null == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+    {
+        win_skip("GetSystemDirectoryW is not available\n");
         return;
+    }
     ok(len_with_null <= MAX_PATH, "should fit into MAX_PATH\n");
 
     lstrcpyW(buf, fooW);
@@ -337,8 +343,11 @@ static void test_CreateDirectoryW(void)
     static const WCHAR questionW[] = {'?',0};
 
     ret = CreateDirectoryW(NULL, NULL);
-    if (!ret && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
+    if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+    {
+        win_skip("CreateDirectoryW is not available\n");
         return;
+    }
     ok(ret == FALSE && GetLastError() == ERROR_PATH_NOT_FOUND,
        "should not create NULL path ret %u err %u\n", ret, GetLastError());
 
@@ -441,8 +450,11 @@ static void test_RemoveDirectoryW(void)
     GetTempPathW(MAX_PATH, tmpdir);
     lstrcatW(tmpdir, tmp_dir_name);
     ret = CreateDirectoryW(tmpdir, NULL);
-    if (!ret && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
-      return;
+    if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+    {
+        win_skip("CreateDirectoryW is not available\n");
+        return;
+    }
 
     ok(ret == TRUE, "CreateDirectoryW should always succeed\n");
 
index 98bc126..af1cf7f 100755 (executable)
@@ -39,7 +39,8 @@ static void test_GetDriveTypeA(void)
     for (drive[0] = 'A'; drive[0] <= 'Z'; drive[0]++)
     {
         type = GetDriveTypeA(drive);
-        ok(type > 0 && type <= 6, "not a valid drive %c: type %u\n", drive[0], type);
+        ok(type > DRIVE_UNKNOWN && type <= DRIVE_RAMDISK,
+           "not a valid drive %c: type %u\n", drive[0], type);
 
         if (!(logical_drives & 1))
             ok(type == DRIVE_NO_ROOT_DIR,
@@ -62,12 +63,13 @@ static void test_GetDriveTypeW(void)
     for (drive[0] = 'A'; drive[0] <= 'Z'; drive[0]++)
     {
         type = GetDriveTypeW(drive);
-        if (type == DRIVE_UNKNOWN && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
+        if (type == DRIVE_UNKNOWN && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
         {
-            /* Must be Win9x which doesn't support the Unicode functions */
+            win_skip("GetDriveTypeW is not available on Win9x\n");
             return;
         }
-        ok(type > 0 && type <= 6, "not a valid drive %c: type %u\n", drive[0], type);
+        ok(type > DRIVE_UNKNOWN && type <= DRIVE_RAMDISK,
+           "not a valid drive %c: type %u\n", drive[0], type);
 
         if (!(logical_drives & 1))
             ok(type == DRIVE_NO_ROOT_DIR,
@@ -165,9 +167,9 @@ static void test_GetDiskFreeSpaceW(void)
     static const WCHAR unix_style_root_pathW[] = { '/', 0 };
 
     ret = GetDiskFreeSpaceW(NULL, &sectors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters);
-    if (ret == 0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
+    if (ret == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
     {
-        /* Must be Win9x which doesn't support the Unicode functions */
+        win_skip("GetDiskFreeSpaceW is not available\n");
         return;
     }
     ok(ret, "GetDiskFreeSpaceW error %d\n", GetLastError());
index 89b284d..4ad10eb 100755 (executable)
@@ -26,6 +26,7 @@
 #include <stdarg.h>
 #include <stdlib.h>
 #include <time.h>
+#include <stdio.h>
 
 #include "wine/test.h"
 #include "windef.h"
@@ -36,6 +37,7 @@ static HANDLE (WINAPI *pFindFirstFileExA)(LPCSTR,FINDEX_INFO_LEVELS,LPVOID,FINDE
 static BOOL (WINAPI *pReplaceFileA)(LPCSTR, LPCSTR, LPCSTR, DWORD, LPVOID, LPVOID);
 static BOOL (WINAPI *pReplaceFileW)(LPCWSTR, LPCWSTR, LPCWSTR, DWORD, LPVOID, LPVOID);
 static UINT (WINAPI *pGetSystemWindowsDirectoryA)(LPSTR, UINT);
+static BOOL (WINAPI *pGetVolumeNameForVolumeMountPointA)(LPCSTR, LPSTR, DWORD);
 
 /* keep filename and filenameW the same */
 static const char filename[] = "testfile.xxx";
@@ -52,6 +54,13 @@ static const char sillytext[] =
 "1234 43 4kljf lf &%%%&&&&&& 34 4 34   3############# 33 3 3 3 # 3## 3"
 "sdlkfjasdlkfj a dslkj adsklf  \n  \nasdklf askldfa sdlkf \nsadklf asdklf asdf ";
 
+struct test_list {
+    const char *file;
+    const DWORD err;
+    const DWORD options;
+    const BOOL todo_flag;
+} ;
+
 static void InitFunctionPointers(void)
 {
     HMODULE hkernel32 = GetModuleHandleA("kernel32");
@@ -60,6 +69,7 @@ static void InitFunctionPointers(void)
     pReplaceFileA=(void*)GetProcAddress(hkernel32, "ReplaceFileA");
     pReplaceFileW=(void*)GetProcAddress(hkernel32, "ReplaceFileW");
     pGetSystemWindowsDirectoryA=(void*)GetProcAddress(hkernel32, "GetSystemWindowsDirectoryA");
+    pGetVolumeNameForVolumeMountPointA = (void *) GetProcAddress(hkernel32, "GetVolumeNameForVolumeMountPointA");
 }
 
 static void test__hread( void )
@@ -633,8 +643,11 @@ static void test_CopyFileW(void)
     DWORD ret;
 
     ret = GetTempPathW(MAX_PATH, temp_path);
-    if (ret==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
+    if (ret == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+    {
+        win_skip("GetTempPathW is not available\n");
         return;
+    }
     ok(ret != 0, "GetTempPathW error %d\n", GetLastError());
     ok(ret < MAX_PATH, "temp path should fit into MAX_PATH\n");
 
@@ -657,13 +670,68 @@ static void test_CopyFileW(void)
     ok(ret, "DeleteFileW: error %d\n", GetLastError());
 }
 
+
+/*
+ *   Debugging routine to dump a buffer in a hexdump-like fashion.
+ */
+static void dumpmem(unsigned char* mem, int len) {
+    int x,y;
+    char buf[200];
+    int ln=0;
+
+    for (x=0; x<len; x+=16) {
+        ln += sprintf(buf+ln, "%04x: ",x);
+        for (y=0; y<16; y++) {
+            if ((x+y)>len) {
+                ln += sprintf(buf+ln, "   ");
+            } else {
+                ln += sprintf(buf+ln, "%02hhx ",mem[x+y]);
+            }
+        }
+        ln += sprintf(buf+ln, "- ");
+        for (y=0; y<16; y++) {
+            if ((x+y)<=len) {
+                if (mem[x+y]<32 || mem[x+y]>127) {
+                    ln += sprintf(buf+ln, ".");
+                } else {
+                    ln += sprintf(buf+ln, "%c",mem[x+y]);
+                }
+            }
+        }
+        sprintf(buf+ln, "\n");
+        trace(buf);
+        ln = 0;
+    }
+}
+
 static void test_CreateFileA(void)
 {
     HANDLE hFile;
-    char temp_path[MAX_PATH];
+    char temp_path[MAX_PATH], dirname[MAX_PATH];
     char filename[MAX_PATH];
     static const char prefix[] = "pfx";
-    DWORD ret;
+    char windowsdir[MAX_PATH];
+    char Volume_1[MAX_PATH];
+    unsigned char buffer[512];
+    char directory[] = "removeme";
+    static const char nt_drive[] = "\\\\?\\A:";
+    DWORD i, ret, len;
+    struct test_list p[] = {
+    {"", ERROR_PATH_NOT_FOUND, FILE_ATTRIBUTE_NORMAL, TRUE }, /* dir as file w \ */
+    {"", ERROR_SUCCESS, FILE_FLAG_BACKUP_SEMANTICS, FALSE }, /* dir as dir w \ */
+    {"a", ERROR_FILE_NOT_FOUND, FILE_ATTRIBUTE_NORMAL, FALSE }, /* non-exist file */
+    {"a\\", ERROR_FILE_NOT_FOUND, FILE_ATTRIBUTE_NORMAL, FALSE }, /* non-exist dir */
+    {"removeme", ERROR_ACCESS_DENIED, FILE_ATTRIBUTE_NORMAL, FALSE }, /* exist dir w/o \ */
+    {"removeme\\", ERROR_PATH_NOT_FOUND, FILE_ATTRIBUTE_NORMAL, TRUE }, /* exst dir w \ */
+    {"c:", ERROR_ACCESS_DENIED, FILE_ATTRIBUTE_NORMAL, FALSE }, /* device in file namespace */
+    {"c:", ERROR_SUCCESS, FILE_FLAG_BACKUP_SEMANTICS, FALSE }, /* device in file namespace as dir */
+    {"c:\\", ERROR_PATH_NOT_FOUND, FILE_ATTRIBUTE_NORMAL, TRUE }, /* root dir w \ */
+    {"c:\\", ERROR_SUCCESS, FILE_FLAG_BACKUP_SEMANTICS, FALSE }, /* root dir w \ as dir */
+    {"\\\\?\\c:", ERROR_SUCCESS, FILE_ATTRIBUTE_NORMAL,FALSE }, /* dev namespace drive */
+    {"\\\\?\\c:\\", ERROR_PATH_NOT_FOUND, FILE_ATTRIBUTE_NORMAL, TRUE }, /* dev namespace drive w \ */
+    {NULL, 0, 0, FALSE}
+    };
+    BY_HANDLE_FILE_INFORMATION  Finfo;
 
     ret = GetTempPathA(MAX_PATH, temp_path);
     ok(ret != 0, "GetTempPathA error %d\n", GetLastError());
@@ -707,6 +775,263 @@ static void test_CreateFileA(void)
 
     ret = DeleteFileA(filename);
     ok(ret, "DeleteFileA: error %d\n", GetLastError());
+
+    /* get windows drive letter */
+    ret = GetWindowsDirectory(windowsdir, sizeof(windowsdir));
+    ok(ret < sizeof(windowsdir), "windowsdir is abnormally long!\n");
+    ok(ret != 0, "GetWindowsDirectory: error %d\n", GetLastError());
+
+    /* test error return codes from CreateFile for some cases */
+    ret = GetTempPathA(MAX_PATH, temp_path);
+    ok(ret != 0, "GetTempPathA error %d\n", GetLastError());
+    strcpy(dirname, temp_path);
+    strcat(dirname, directory);
+    ret = CreateDirectory(dirname, NULL);
+    ok( ret, "Createdirectory failed, gle=%d\n", GetLastError() );
+    /* set current drive & directory to known location */
+    SetCurrentDirectoryA( temp_path );
+    i = 0;
+    while (p[i].file)
+    {
+        filename[0] = 0;
+        /* update the drive id in the table entry with the current one */
+        if (p[i].file[1] == ':')
+        {
+            strcpy(filename, p[i].file);
+            filename[0] = windowsdir[0];
+        }
+        else if (p[i].file[0] == '\\' && p[i].file[5] == ':')
+        {
+            strcpy(filename, p[i].file);
+            filename[4] = windowsdir[0];
+        }
+        else
+        {
+            /* prefix the table entry with the current temp directory */
+            strcpy(filename, temp_path);
+            strcat(filename, p[i].file);
+        }
+        hFile = CreateFileA( filename, GENERIC_READ | GENERIC_WRITE,
+                        FILE_SHARE_READ | FILE_SHARE_WRITE,
+                        NULL, OPEN_EXISTING,
+                        p[i].options, NULL );
+        /* if we get ACCESS_DENIED when we do not expect it, assume
+         * no access to the volume
+         */
+        if (hFile == INVALID_HANDLE_VALUE &&
+            GetLastError() == ERROR_ACCESS_DENIED &&
+            p[i].err != ERROR_ACCESS_DENIED)
+        {
+            if (p[i].todo_flag)
+                skip("Either no authority to volume, or is todo_wine for %s err=%d should be %d\n", filename, GetLastError(), p[i].err);
+            else
+                skip("Do not have authority to access volumes. Test for %s skipped\n", filename);
+        }
+        /* otherwise validate results with expectations */
+        else if (p[i].todo_flag)
+            todo_wine ok((hFile == INVALID_HANDLE_VALUE && p[i].err == GetLastError()) ||
+                (hFile != INVALID_HANDLE_VALUE && p[i].err == ERROR_SUCCESS),
+                "CreateFileA failed on %s, hFile %p, err=%u, should be %u\n",
+                filename, hFile, GetLastError(), p[i].err);
+        else
+            ok((hFile == INVALID_HANDLE_VALUE && p[i].err == GetLastError()) ||
+               (hFile != INVALID_HANDLE_VALUE && p[i].err == ERROR_SUCCESS),
+                "CreateFileA failed on %s, hFile %p, err=%u, should be %u\n",
+                filename, hFile, GetLastError(), p[i].err);
+        if (hFile != INVALID_HANDLE_VALUE)
+            CloseHandle( hFile );
+        i++;
+    }
+    ret = RemoveDirectoryA(dirname);
+    ok(ret, "RemoveDirectoryA: error %d\n", GetLastError());
+
+
+    /* test opening directory as a directory */
+    hFile = CreateFileA( temp_path, GENERIC_READ,
+                        FILE_SHARE_READ,
+                        NULL,
+                        OPEN_EXISTING,
+                        FILE_FLAG_BACKUP_SEMANTICS, NULL );
+    ok(hFile != INVALID_HANDLE_VALUE && GetLastError() == ERROR_SUCCESS,
+            "CreateFileA did not work, last error %u on volume <%s>\n",
+             GetLastError(), temp_path );
+
+    if (hFile != INVALID_HANDLE_VALUE)
+    {
+        ret = GetFileInformationByHandle( hFile, &Finfo );
+        if (ret)
+        {
+            ok(Finfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY,
+                "CreateFileA probably did not open temp directory %s correctly\n   file information does not include FILE_ATTRIBUTE_DIRECTORY, actual=0x%08x\n",
+                temp_path, Finfo.dwFileAttributes);
+        }
+        CloseHandle( hFile );
+    }
+
+
+    /* ***  Test opening volumes/devices using drive letter  ***         */
+
+    /* test using drive letter in non-rewrite format without trailing \  */
+    /* this should work                                                  */
+    strcpy(filename, nt_drive);
+    filename[4] = windowsdir[0];
+    hFile = CreateFileA( filename, GENERIC_READ | GENERIC_WRITE,
+                        FILE_SHARE_READ | FILE_SHARE_WRITE,
+                        NULL, OPEN_EXISTING,
+                        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL );
+    if (hFile != INVALID_HANDLE_VALUE || GetLastError() != ERROR_ACCESS_DENIED)
+    {
+        /* if we have adm rights to volume, then try rest of tests */
+        ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA did not open %s, last error=%u\n",
+            filename, GetLastError());
+        if (hFile != INVALID_HANDLE_VALUE)
+        {
+            /* if we opened the volume/device, try to read it. Since it  */
+            /* opened, we should be able to read it.  We don't care about*/
+            /* what the data is at this time.                            */
+            len = 512;
+            ret = ReadFile( hFile, buffer, len, &len, NULL );
+            todo_wine ok(ret, "Failed to read volume, last error %u, %u, for %s\n",
+                GetLastError(), ret, filename);
+            if (ret)
+            {
+                trace("buffer is\n");
+                dumpmem(buffer, 64);
+            }
+            CloseHandle( hFile );
+        }
+
+        /* test using drive letter with trailing \ and in non-rewrite   */
+        /* this should not work                                         */
+        strcpy(filename, nt_drive);
+        filename[4] = windowsdir[0];
+        strcat( filename, "\\" );
+        hFile = CreateFileA( filename, GENERIC_READ | GENERIC_WRITE,
+                        FILE_SHARE_READ | FILE_SHARE_WRITE,
+                        NULL, OPEN_EXISTING,
+                        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL );
+        todo_wine
+        ok(hFile == INVALID_HANDLE_VALUE && GetLastError() == ERROR_PATH_NOT_FOUND,
+            "CreateFileA should have returned ERROR_PATH_NOT_FOUND on %s, but got %u\n",
+            filename, GetLastError());
+        if (hFile != INVALID_HANDLE_VALUE)
+            CloseHandle( hFile );
+
+        /* test using temp path with trailing \ and in non-rewrite as dir */
+        /* this should work                                               */
+        strcpy(filename, nt_drive);
+        filename[4] = 0;
+        strcat( filename, temp_path );
+        hFile = CreateFileA( filename, GENERIC_READ | GENERIC_WRITE,
+                        FILE_SHARE_READ | FILE_SHARE_WRITE,
+                        NULL, OPEN_EXISTING,
+                        FILE_FLAG_BACKUP_SEMANTICS, NULL );
+        ok(hFile != INVALID_HANDLE_VALUE,
+            "CreateFileA should have worked on %s, but got %u\n",
+            filename, GetLastError());
+        if (hFile != INVALID_HANDLE_VALUE)
+            CloseHandle( hFile );
+
+        /* test using drive letter without trailing \ and in device ns  */
+        /* this should work                                             */
+        strcpy(filename, nt_drive);
+        filename[4] = windowsdir[0];
+        filename[2] = '.';
+        hFile = CreateFileA( filename, GENERIC_READ | GENERIC_WRITE,
+                        FILE_SHARE_READ | FILE_SHARE_WRITE,
+                        NULL, OPEN_EXISTING,
+                        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL );
+        ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA did not open %s, last error=%u\n",
+            filename, GetLastError());
+        if (hFile != INVALID_HANDLE_VALUE)
+            CloseHandle( hFile );
+    }
+    else
+        skip("Do not have authority to access volumes. Tests skipped\n");
+
+
+    /* ***  Test opening volumes/devices using GUID  ***           */
+
+    if (pGetVolumeNameForVolumeMountPointA)
+    {
+        strcpy(filename, "c:\\");
+        filename[0] = windowsdir[0];
+        ret = pGetVolumeNameForVolumeMountPointA( filename, Volume_1, MAX_PATH );
+        ok(ret == TRUE, "GetVolumeNameForVolumeMountPointA failed\n");
+        ok(strlen(Volume_1) == 49, "GetVolumeNameForVolumeMountPointA returned wrong length name %s\n", Volume_1);
+
+        /* test the result of opening a unique volume name (GUID)   */
+        /* with the trailing \                                      */
+        /* this should error out                                    */
+        strcpy(filename, Volume_1);
+        hFile = CreateFileA( filename, GENERIC_READ | GENERIC_WRITE,
+                        FILE_SHARE_READ | FILE_SHARE_WRITE,
+                        NULL, OPEN_EXISTING,
+                        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL );
+        todo_wine
+        ok(hFile == INVALID_HANDLE_VALUE,
+            "CreateFileA should not have opened %s, hFile %p\n",
+            filename, hFile);
+        todo_wine
+        ok(hFile == INVALID_HANDLE_VALUE && GetLastError() == ERROR_PATH_NOT_FOUND,
+            "CreateFileA should have returned ERROR_PATH_NOT_FOUND on %s, but got %u\n",
+            filename, GetLastError());
+        if (hFile != INVALID_HANDLE_VALUE)
+            CloseHandle( hFile );
+
+        /* test the result of opening a unique volume name (GUID)   */
+        /* with the temp path string as dir                         */
+        /* this should work                                         */
+        strcpy(filename, Volume_1);
+        strcat(filename, temp_path+3);
+        hFile = CreateFileA( filename, GENERIC_READ | GENERIC_WRITE,
+                        FILE_SHARE_READ | FILE_SHARE_WRITE,
+                        NULL, OPEN_EXISTING,
+                        FILE_FLAG_BACKUP_SEMANTICS, NULL );
+        todo_wine
+        ok(hFile != INVALID_HANDLE_VALUE,
+            "CreateFileA should have opened %s, but got %u\n",
+            filename, GetLastError());
+        if (hFile != INVALID_HANDLE_VALUE)
+            CloseHandle( hFile );
+
+        /* test the result of opening a unique volume name (GUID)   */
+        /* without the trailing \ and in device namespace           */
+        /* this should work                                         */
+        strcpy(filename, Volume_1);
+        filename[2] = '.';
+        filename[48] = 0;
+        hFile = CreateFileA( filename, GENERIC_READ | GENERIC_WRITE,
+                        FILE_SHARE_READ | FILE_SHARE_WRITE,
+                        NULL, OPEN_EXISTING,
+                        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL );
+        if (hFile != INVALID_HANDLE_VALUE || GetLastError() != ERROR_ACCESS_DENIED)
+        {
+            /* if we have adm rights to volume, then try rest of tests */
+            ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA did not open %s, last error=%u\n",
+                filename, GetLastError());
+            if (hFile != INVALID_HANDLE_VALUE)
+            {
+                /* if we opened the volume/device, try to read it. Since it  */
+                /* opened, we should be able to read it.  We don't care about*/
+                /* what the data is at this time.                            */
+                len = 512;
+                ret = ReadFile( hFile, buffer, len, &len, NULL );
+                todo_wine ok(ret, "Failed to read volume, last error %u, %u, for %s\n",
+                    GetLastError(), ret, filename);
+                if (ret)
+                {
+                    trace("buffer is\n");
+                    dumpmem(buffer, 64);
+                }
+                CloseHandle( hFile );
+                       }
+        }
+        else
+            skip("Do not have authority to access volumes. Tests skipped\n");
+    }
+    else
+        win_skip("GetVolumeNameForVolumeMountPointA not found\n");
 }
 
 static void test_CreateFileW(void)
@@ -720,8 +1045,11 @@ static void test_CreateFileW(void)
     DWORD ret;
 
     ret = GetTempPathW(MAX_PATH, temp_path);
-    if (ret==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
+    if (ret == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+    {
+        win_skip("GetTempPathW is not available\n");
         return;
+    }
     ok(ret != 0, "GetTempPathW error %d\n", GetLastError());
     ok(ret < MAX_PATH, "temp path should fit into MAX_PATH\n");
 
@@ -864,8 +1192,11 @@ static void test_DeleteFileW( void )
     static const WCHAR emptyW[]={'\0'};
 
     ret = DeleteFileW(NULL);
-    if (ret==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
+    if (ret == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+    {
+        win_skip("DeleteFileW is not available\n");
         return;
+    }
     ok(!ret && GetLastError() == ERROR_PATH_NOT_FOUND,
        "DeleteFileW(NULL) returned ret=%d error=%d\n",ret,GetLastError());
 
@@ -984,8 +1315,11 @@ static void test_MoveFileW(void)
     DWORD ret;
 
     ret = GetTempPathW(MAX_PATH, temp_path);
-    if (ret==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
+    if (ret == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+    {
+        win_skip("GetTempPathW is not available\n");
         return;
+    }
     ok(ret != 0, "GetTempPathW error %d\n", GetLastError());
     ok(ret < MAX_PATH, "temp path should fit into MAX_PATH\n");
 
@@ -1364,7 +1698,12 @@ static void test_FindFirstFileA(void)
 
     /* try FindFirstFileA on "C:\foo\" */
     SetLastError( 0xdeadbeaf );
-    GetTempFileNameA( buffer, "foo", 0, nonexistent );
+    if (!GetTempFileNameA( buffer, "foo", 0, nonexistent ) && GetLastError() == ERROR_ACCESS_DENIED)
+    {
+        char tmp[MAX_PATH];
+        GetTempPathA( sizeof(tmp), tmp );
+        GetTempFileNameA( tmp, "foo", 0, nonexistent );
+    }
     DeleteFileA( nonexistent );
     strcpy(buffer2, nonexistent);
     strcat(buffer2, "\\");
@@ -2352,8 +2691,11 @@ static void test_ReplaceFileW(void)
     }
 
     ret = GetTempPathW(MAX_PATH, temp_path);
-    if (ret==0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+    if (ret == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+    {
+        win_skip("GetTempPathW is not available\n");
         return;
+    }
     ok(ret != 0, "GetTempPathW error %d\n", GetLastError());
     ok(ret < MAX_PATH, "temp path should fit into MAX_PATH\n");
 
index cbb8b5a..8cdb1e4 100755 (executable)
@@ -1,4 +1,4 @@
-/* Unit test suite for FormatMessageA
+/* Unit test suite for FormatMessageA/W
  *
  * Copyright 2002 Mike McCormack for CodeWeavers
  *
@@ -22,6 +22,7 @@
 #include "wine/test.h"
 #include "windef.h"
 #include "winbase.h"
+#include "winnls.h"
 
 /* #define ok(cond,failstr) if(!(cond)) {printf("line %d : %s\n",__LINE__,failstr);exit(1);} */
 
@@ -38,6 +39,297 @@ static DWORD doit(DWORD flags, LPCVOID src, DWORD msg_id, DWORD lang_id,
     return r;
 }
 
+static DWORD doitW(DWORD flags, LPCVOID src, DWORD msg_id, DWORD lang_id,
+           LPWSTR out, DWORD outsize, ... )
+{
+    va_list list;
+    DWORD r;
+
+    va_start(list, outsize);
+    r = FormatMessageW(flags, src, msg_id,
+        lang_id, out, outsize, &list);
+    va_end(list);
+    return r;
+}
+
+static char buf[1024];
+static const char *debugstr_w(const WCHAR *str)
+{
+    WideCharToMultiByte(CP_ACP, 0, str, -1, buf, sizeof(buf), NULL, NULL);
+    return buf;
+}
+
+static void test_message_from_string_wide(void)
+{
+    static const WCHAR test[]        = {'t','e','s','t',0};
+    static const WCHAR te[]          = {'t','e',0};
+    static const WCHAR st[]          = {'s','t',0};
+    static const WCHAR t[]           = {'t',0};
+    static const WCHAR e[]           = {'e',0};
+    static const WCHAR s[]           = {'s',0};
+    static const WCHAR fmt_1[]       = {'%','1',0};
+    static const WCHAR fmt_12[]      = {'%','1','%','2',0};
+    static const WCHAR fmt_123[]     = {'%','1','%','3','%','2','%','1',0};
+    static const WCHAR fmt_123c[]    = {'%','1','!','c','!','%','2','!','c','!','%','3','!','c','!','%','1','!','c','!',0};
+    static const WCHAR fmt_123lc[]   = {'%','1','!','l','c','!','%','2','!','l','c','!','%','3','!','l','c','!','%','1','!','l','c','!',0};
+    static const WCHAR fmt_123wc[]   = {'%','1','!','w','c','!','%','2','!','w','c','!','%','3','!','w','c','!','%','1','!','w','c','!',0};
+    static const WCHAR fmt_123C[]    = {'%','1','!','C','!','%','2','!','C','!','%','3','!','C','!','%','1','!','C','!',0};
+    static const WCHAR fmt_123d[]    = {'%','1','!','d','!','%','2','!','d','!','%','3','!','d','!',0};
+    static const WCHAR fmt_1s[]      = {'%','1','!','s','!',0};
+    static const WCHAR fmt_s[]       = {'%','!','s','!',0};
+    static const WCHAR fmt_ls[]      = {'%','!','l','s','!',0};
+    static const WCHAR fmt_ws[]      = {'%','!','w','s','!',0};
+    static const WCHAR fmt_S[]       = {'%','!','S','!',0};
+    static const WCHAR fmt_14d[]     = {'%','1','!','4','d','!',0};
+    static const WCHAR fmt_14x[]     = {'%','1','!','4','x','!',0};
+    static const WCHAR fmt_14X[]     = {'%','1','!','4','X','!',0};
+    static const WCHAR fmt_1_4X[]    = {'%','1','!','-','4','X','!',0};
+    static const WCHAR fmt_1_4d[]    = {'%','1','!','-','4','d','!',0};
+    static const WCHAR fmt_2pct[]    = {' ','%','%','%','%',' ',0};
+    static const WCHAR fmt_2dot1d[]  = {' ', '%','.','%','.',' ',' ','%','1','!','d','!',0};
+    static const WCHAR fmt_t0t[]     = {'t','e','s','t','%','0','t','e','s','t',0};
+    static const WCHAR fmt_yah[]     = {'y','a','h','%','!','%','0',' ',' ',' ',0};
+    static const WCHAR fmt_space[]   = {'%',' ','%',' ',' ',' ',0};
+    static const WCHAR fmt_hi_lf[]   = {'h','i','\n',0};
+    static const WCHAR fmt_hi_crlf[] = {'h','i','\r','\n',0};
+    static const WCHAR fmt_cr[]      = {'\r',0};
+    static const WCHAR fmt_crcrlf[]  = {'\r','\r','\n',0};
+    static const WCHAR s_123d[]      = {'1','2','3',0};
+    static const WCHAR s_14d[]       = {' ',' ',' ','1',0};
+    static const WCHAR s_14x[]       = {' ',' ',' ','b',0};
+    static const WCHAR s_14X[]       = {' ',' ',' ','B',0};
+    static const WCHAR s_1_4X[]      = {'B',' ',' ',' ',0};
+    static const WCHAR s_14d2[]      = {' ',' ','1','1',0};
+    static const WCHAR s_1_4d[]      = {'1',' ',' ',' ',0};
+    static const WCHAR s_1AB[]       = {' ','1','A','B',0};
+    static const WCHAR s_2pct[]      = {' ','%','%',' ',0};
+    static const WCHAR s_2dot147[]   = {' ','.','.',' ',' ','4','2','7',0};
+    static const WCHAR s_yah[]       = {'y','a','h','!',0};
+    static const WCHAR s_space[]     = {' ',' ',' ',' ',0};
+    static const WCHAR s_hi_crlf[]   = {'h','i','\r','\n',0};
+    static const WCHAR s_crlf[]      = {'\r','\n',0};
+    static const WCHAR s_crlfcrlf[]  = {'\r','\n','\r','\n',0};
+    static const WCHAR s_hi_sp[]     = {'h','i',' ',0};
+    static const WCHAR s_sp[]        = {' ',0};
+    static const WCHAR s_2sp[]       = {' ',' ',0};
+    WCHAR out[0x100] = {0};
+    DWORD r, error;
+
+    SetLastError(0xdeadbeef);
+    r = FormatMessageW(FORMAT_MESSAGE_FROM_STRING, NULL, 0, 0, NULL, 0, NULL);
+    error = GetLastError();
+    if (!r && error == ERROR_CALL_NOT_IMPLEMENTED)
+    {
+        win_skip("FormatMessageW is not implemented\n");
+        return;
+    }
+
+    /* the basics */
+    r = FormatMessageW(FORMAT_MESSAGE_FROM_STRING, test, 0,
+        0, out, sizeof(out)/sizeof(WCHAR), NULL);
+    ok(!lstrcmpW(test, out), "failed out=[%s]\n", debugstr_w(out));
+    ok(r==4, "failed: r=%d\n", r);
+
+    /* using the format feature */
+    r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_1s, 0,
+        0, out, sizeof(out)/sizeof(WCHAR), test);
+    ok(!lstrcmpW(test, out), "failed out=[%s]\n", debugstr_w(out));
+    ok(r==4,"failed: r=%d\n", r);
+
+    /* no format */
+    r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_1, 0,
+        0, out, sizeof(out)/sizeof(WCHAR), test);
+    ok(!lstrcmpW(test, out), "failed out=[%s]\n", debugstr_w(out));
+    ok(r==4,"failed: r=%d\n", r);
+
+    /* two pieces */
+    r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_12, 0,
+        0, out, sizeof(out)/sizeof(WCHAR), te, st);
+    ok(!lstrcmpW(test, out), "failed out=[%s]\n", debugstr_w(out));
+    ok(r==4,"failed: r=%d\n", r);
+
+    /* three pieces */
+    r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_123, 0,
+        0, out, sizeof(out)/sizeof(WCHAR), t, s, e);
+    ok(!lstrcmpW(test, out), "failed out=[%s]\n", debugstr_w(out));
+    ok(r==4,"failed: r=%d\n", r);
+
+    /* s doesn't seem to work in format strings */
+    r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_s, 0,
+        0, out, sizeof(out)/sizeof(WCHAR), test);
+    ok(!lstrcmpW(&fmt_s[1], out), "failed out=[%s]\n", debugstr_w(out));
+    ok(r==3, "failed: r=%d\n", r);
+
+    /* nor ls */
+    r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_ls, 0,
+        0, out, sizeof(out)/sizeof(WCHAR), test);
+    ok(!lstrcmpW(&fmt_ls[1], out), "failed out=[%s]\n", debugstr_w(out));
+    ok(r==4, "failed: r=%d\n", r);
+
+    /* nor S */
+    r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_S, 0,
+        0, out, sizeof(out)/sizeof(WCHAR), test);
+    ok(!lstrcmpW(&fmt_S[1], out), "failed out=[%s]\n", debugstr_w(out));
+    ok(r==3, "failed: r=%d\n", r);
+
+    /* nor ws */
+    r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_ws, 0,
+        0, out, sizeof(out)/sizeof(WCHAR), test);
+    ok(!lstrcmpW(&fmt_ws[1], out), "failed out=[%s]\n", debugstr_w(out));
+    ok(r==4, "failed: r=%d\n", r);
+
+    /* as characters */
+    r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_123c, 0,
+        0, out, sizeof(out)/sizeof(WCHAR), 't', 'e', 's');
+    ok(!lstrcmpW(test, out), "failed out=[%s]\n", debugstr_w(out));
+    ok(r==4,"failed: r=%d\n", r);
+
+    /* lc is unicode */
+    r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_123lc, 0,
+        0, out, sizeof(out)/sizeof(WCHAR), 't', 'e', 's');
+    ok(!lstrcmpW(test, out), "failed out=[%s]\n", debugstr_w(out));
+    ok(r==4,"failed: r=%d\n", r);
+
+    /* wc is unicode */
+    r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_123wc, 0,
+        0, out, sizeof(out)/sizeof(WCHAR), 't', 'e', 's');
+    ok(!lstrcmpW(test, out), "failed out=[%s]\n", debugstr_w(out));
+    ok(r==4,"failed: r=%d\n", r);
+
+    /* C is unicode */
+    r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_123C, 0,
+        0, out, sizeof(out)/sizeof(WCHAR), 't', 'e', 's');
+    ok(!lstrcmpW(test, out), "failed out=[%s]\n", debugstr_w(out));
+    ok(r==4,"failed: r=%d\n", r);
+
+    /* some numbers */
+    r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_123d, 0,
+        0, out, sizeof(out)/sizeof(WCHAR), 1, 2, 3);
+    ok(!lstrcmpW(s_123d, out), "failed out=[%s]\n", debugstr_w(out));
+    ok(r==3,"failed: r=%d\n", r);
+
+    /* a single digit with some spacing */
+    r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_14d, 0,
+        0, out, sizeof(out)/sizeof(WCHAR), 1);
+    ok(!lstrcmpW(s_14d, out), "failed out=[%s]\n", debugstr_w(out));
+
+    /* a single digit, left justified */
+    r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_1_4d, 0,
+        0, out, sizeof(out)/sizeof(CHAR), 1);
+    ok(!lstrcmpW(s_1_4d, out), "failed out=[%s]\n", debugstr_w(out));
+    ok(r==4,"failed: r=%d\n", r);
+
+    /* two digit decimal number */
+    r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_14d, 0,
+        0, out, sizeof(out)/sizeof(WCHAR), 11);
+    ok(!lstrcmpW(s_14d2, out), "failed out=[%s]\n", debugstr_w(out));
+    ok(r==4,"failed: r=%d\n", r);
+
+    /* a hex number */
+    r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_14x, 0,
+        0, out, sizeof(out)/sizeof(WCHAR), 11);
+    ok(!lstrcmpW(s_14x, out), "failed out=[%s]\n", debugstr_w(out));
+    ok(r==4,"failed: r=%d\n", r);
+
+    /* a hex number, upper case */
+    r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_14X, 0,
+        0, out, sizeof(out)/sizeof(WCHAR), 11);
+    ok(!lstrcmpW(s_14X, out), "failed out=[%s]\n", debugstr_w(out));
+    ok(r==4,"failed: r=%d\n", r);
+
+    /* a hex number, upper case, left justified */
+    r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_1_4X, 0,
+        0, out, sizeof(out)/sizeof(WCHAR), 11);
+    ok(!lstrcmpW(s_1_4X, out), "failed out=[%s]\n", debugstr_w(out));
+    ok(r==4,"failed: r=%d\n", r);
+
+    /* a long hex number, upper case */
+    r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_14X, 0,
+        0, out, sizeof(out)/sizeof(WCHAR), 0x1ab);
+    ok(!lstrcmpW(s_1AB, out), "failed out=[%s]\n", debugstr_w(out));
+    ok(r==4,"failed: r=%d\n", r);
+
+    /* two percent... */
+    r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_2pct, 0,
+        0, out, sizeof(out)/sizeof(WCHAR));
+    ok(!lstrcmpW(s_2pct, out), "failed out=[%s]\n", debugstr_w(out));
+    ok(r==4,"failed: r=%d\n", r);
+
+    /* periods are special cases */
+    r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_2dot1d, 0,
+        0, out, sizeof(out)/sizeof(WCHAR), 0x1ab);
+    ok(!lstrcmpW(s_2dot147, out), "failed out=[%s]\n", debugstr_w(out));
+    ok(r==8,"failed: r=%d\n", r);
+
+    /* %0 ends the line */
+    r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_t0t, 0,
+        0, out, sizeof(out)/sizeof(WCHAR));
+    ok(!lstrcmpW(test, out), "failed out=[%s]\n", debugstr_w(out));
+    ok(r==4,"failed: r=%d\n", r);
+
+    /* %! prints an exclamation */
+    r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_yah, 0,
+        0, out, sizeof(out)/sizeof(WCHAR));
+    ok(!lstrcmpW(s_yah, out), "failed out=[%s]\n", debugstr_w(out));
+    ok(r==4,"failed: r=%d\n", r);
+
+    /* %space */
+    r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_space, 0,
+        0, out, sizeof(out)/sizeof(WCHAR));
+    ok(!lstrcmpW(s_space, out), "failed out=[%s]\n", debugstr_w(out));
+    ok(r==4,"failed: r=%d\n", r);
+
+    /* line feed */
+    r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_hi_lf, 0,
+        0, out, sizeof(out)/sizeof(WCHAR));
+    ok(!lstrcmpW(s_hi_crlf, out), "failed out=[%s]\n", debugstr_w(out));
+    ok(r==4,"failed: r=%d\n", r);
+
+    /* carriage return line feed */
+    r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_hi_crlf, 0,
+        0, out, sizeof(out)/sizeof(WCHAR));
+    ok(!lstrcmpW(s_hi_crlf, out), "failed out=[%s]\n", debugstr_w(out));
+    ok(r==4,"failed: r=%d\n", r);
+
+    /* carriage return */
+    r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_cr, 0,
+        0, out, sizeof(out)/sizeof(WCHAR));
+    ok(!lstrcmpW(s_crlf, out), "failed out=[%s]\n", debugstr_w(out));
+    ok(r==2,"failed: r=%d\n", r);
+
+    /* double carriage return line feed */
+    r = doitW(FORMAT_MESSAGE_FROM_STRING, fmt_crcrlf, 0,
+        0, out, sizeof(out)/sizeof(WCHAR));
+    ok(!lstrcmpW(s_crlfcrlf, out), "failed out=[%s]\n", debugstr_w(out));
+    ok(r==4,"failed: r=%d\n", r);
+
+    /* change of pace... test the low byte of dwflags */
+
+    /* line feed */
+    r = doitW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_MAX_WIDTH_MASK, fmt_hi_lf, 0,
+        0, out, sizeof(out)/sizeof(WCHAR));
+    ok(!lstrcmpW(s_hi_sp, out) || !lstrcmpW(s_hi_crlf, out), "failed out=[%s]\n", debugstr_w(out));
+    ok(r==3 || r==4,"failed: r=%d\n", r);
+
+    /* carriage return line feed */
+    r = doitW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_MAX_WIDTH_MASK, fmt_hi_crlf, 0,
+        0, out, sizeof(out)/sizeof(WCHAR));
+    ok(!lstrcmpW(s_hi_sp, out), "failed out=[%s]\n", debugstr_w(out));
+    ok(r==3,"failed: r=%d\n", r);
+
+    /* carriage return */
+    r = doitW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_MAX_WIDTH_MASK, fmt_cr, 0,
+        0, out, sizeof(out)/sizeof(WCHAR));
+    ok(!lstrcmpW(s_sp, out), "failed out=[%s]\n", debugstr_w(out));
+    ok(r==1,"failed: r=%d\n", r);
+
+    /* double carriage return line feed */
+    r = doitW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_MAX_WIDTH_MASK, fmt_crcrlf, 0,
+        0, out, sizeof(out)/sizeof(WCHAR));
+    ok(!lstrcmpW(s_2sp, out), "failed out=[%s]\n", debugstr_w(out));
+    ok(r==2,"failed: r=%d\n", r);
+}
+
 static void test_message_from_string(void)
 {
     CHAR out[0x100] = {0};
@@ -80,18 +372,48 @@ static void test_message_from_string(void)
     ok(!strcmp("!s!", out),"failed out=[%s]\n",out);
     ok(r==3,"failed: r=%d\n",r);
 
+    /* ls is unicode */
+    r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!ls!", 0,
+        0, out, sizeof(out)/sizeof(CHAR), szwTest);
+    ok(!strcmp("test", out),"failed out=[%s]\n",out);
+    ok(r==4,"failed: r=%d\n",r);
+
     /* S is unicode */
     r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!S!", 0,
         0, out, sizeof(out)/sizeof(CHAR), szwTest);
     ok(!strcmp("test", out),"failed out=[%s]\n",out);
     ok(r==4,"failed: r=%d\n",r);
 
+    /* ws is unicode */
+    r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!ws!", 0,
+        0, out, sizeof(out)/sizeof(CHAR), szwTest);
+    ok(!strcmp("test", out),"failed out=[%s]\n",out);
+    ok(r==4,"failed: r=%d\n",r);
+
     /* as characters */
     r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!c!%2!c!%3!c!%1!c!", 0,
         0, out, sizeof(out)/sizeof(CHAR), 't','e','s');
     ok(!strcmp("test", out),"failed out=[%s]\n",out);
     ok(r==4,"failed: r=%d\n",r);
 
+    /* lc is unicode */
+    r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!lc!%2!lc!%3!lc!%1!lc!", 0,
+        0, out, sizeof(out)/sizeof(CHAR), 't','e','s');
+    ok(!strcmp("test", out),"failed out=[%s]\n",out);
+    ok(r==4,"failed: r=%d\n",r);
+
+    /* wc is unicode */
+    r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!wc!%2!wc!%3!wc!%1!wc!", 0,
+        0, out, sizeof(out)/sizeof(CHAR), 't','e','s');
+    ok(!strcmp("test", out),"failed out=[%s]\n",out);
+    ok(r==4,"failed: r=%d\n",r);
+
+    /* C is unicode */
+    r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!C!%2!C!%3!C!%1!C!", 0,
+        0, out, sizeof(out)/sizeof(CHAR), 't','e','s');
+    ok(!strcmp("test", out),"failed out=[%s]\n",out);
+    ok(r==4,"failed: r=%d\n",r);
+
     /* some numbers */
     r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!d!%2!d!%3!d!", 0,
         0, out, sizeof(out)/sizeof(CHAR), 1,2,3);
@@ -182,19 +504,20 @@ static void test_message_from_string(void)
     ok(!strcmp("hi\r\n", out),"failed out=[%s]\n",out);
     ok(r==4,"failed: r=%d\n",r);
 
-    /* carriage return line feed */
+    /* carriage return */
     r = doit(FORMAT_MESSAGE_FROM_STRING, "\r", 0,
         0, out, sizeof(out)/sizeof(CHAR));
     ok(!strcmp("\r\n", out),"failed out=[%s]\n",out);
     ok(r==2,"failed: r=%d\n",r);
 
-    /* carriage return line feed */
+    /* double carriage return line feed */
     r = doit(FORMAT_MESSAGE_FROM_STRING, "\r\r\n", 0,
         0, out, sizeof(out)/sizeof(CHAR));
     ok(!strcmp("\r\n\r\n", out),"failed out=[%s]\n",out);
     ok(r==4,"failed: r=%d\n",r);
 
     /* change of pace... test the low byte of dwflags */
+
     /* line feed */
     r = doit(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_MAX_WIDTH_MASK, "hi\n", 0,
         0, out, sizeof(out)/sizeof(CHAR));
@@ -207,13 +530,13 @@ static void test_message_from_string(void)
     ok(!strcmp("hi ", out),"failed out=[%s]\n",out);
     ok(r==3,"failed: r=%d\n",r);
 
-    /* carriage return line feed */
+    /* carriage return */
     r = doit(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_MAX_WIDTH_MASK, "\r", 0,
         0, out, sizeof(out)/sizeof(CHAR));
     ok(!strcmp(" ", out),"failed out=[%s]\n",out);
     ok(r==1,"failed: r=%d\n",r);
 
-    /* carriage return line feed */
+    /* double carriage return line feed */
     r = doit(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_MAX_WIDTH_MASK, "\r\r\n", 0,
         0, out, sizeof(out)/sizeof(CHAR));
     ok(!strcmp("  ", out),"failed out=[%s]\n",out);
@@ -248,5 +571,6 @@ static void test_message_null_buffer(void)
 START_TEST(format_msg)
 {
     test_message_from_string();
+    test_message_from_string_wide();
     test_message_null_buffer();
 }
index 39517cc..19b4106 100755 (executable)
@@ -362,9 +362,58 @@ static void test_heap(void)
     GlobalFree(gbl);
 }
 
+static void test_obsolete_flags(void)
+{
+    static struct {
+        UINT flags;
+        UINT globalflags;
+    } test_global_flags[] = {
+        {GMEM_FIXED | GMEM_NOTIFY, 0},
+        {GMEM_FIXED | GMEM_DISCARDABLE, 0},
+        {GMEM_MOVEABLE | GMEM_NOTIFY, 0},
+        {GMEM_MOVEABLE | GMEM_DDESHARE, GMEM_DDESHARE},
+        {GMEM_MOVEABLE | GMEM_NOT_BANKED, 0},
+        {GMEM_MOVEABLE | GMEM_NODISCARD, 0},
+        {GMEM_MOVEABLE | GMEM_DISCARDABLE, GMEM_DISCARDABLE},
+        {GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_DISCARDABLE | GMEM_LOWER | GMEM_NOCOMPACT | GMEM_NODISCARD |
+         GMEM_NOT_BANKED | GMEM_NOTIFY, GMEM_DDESHARE | GMEM_DISCARDABLE},
+    };
+
+    unsigned int i;
+    HGLOBAL gbl;
+    UINT resultflags;
+
+    UINT (WINAPI *pGlobalFlags)(HGLOBAL);
+
+    pGlobalFlags = (void *) GetProcAddress(GetModuleHandleA("kernel32"), "GlobalFlags");
+
+    if (!pGlobalFlags)
+    {
+        win_skip("GlobalFlags is not available\n");
+        return;
+    }
+
+    for (i = 0; i < sizeof(test_global_flags)/sizeof(test_global_flags[0]); i++)
+    {
+        gbl = GlobalAlloc(test_global_flags[i].flags, 4);
+        ok(gbl != NULL, "GlobalAlloc failed\n");
+
+        SetLastError(MAGIC_DEAD);
+        resultflags = pGlobalFlags(gbl);
+
+        ok( resultflags == test_global_flags[i].globalflags ||
+            broken(resultflags == (test_global_flags[i].globalflags & ~GMEM_DDESHARE)), /* win9x */
+            "%u: expected 0x%08x, but returned 0x%08x with %d\n",
+            i, test_global_flags[i].globalflags, resultflags, GetLastError() );
+
+        GlobalFree(gbl);
+    }
+}
+
 START_TEST(heap)
 {
     test_heap();
+    test_obsolete_flags();
 
     /* Test both short and very long blocks */
     test_sized_HeapAlloc(1);
index e88e182..8a56100 100755 (executable)
@@ -118,25 +118,77 @@ static void InitFunctionPointers(void)
 static void test_GetLocaleInfoA(void)
 {
   int ret;
+  int len;
   LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
   char buffer[BUFFER_SIZE];
+  char expected[BUFFER_SIZE];
 
   ok(lcid == 0x409, "wrong LCID calculated - %d\n", lcid);
 
+  /* en, ar and zh use SUBLANG_NEUTRAL, but GetLocaleInfo assume SUBLANG_DEFAULT */
+  memset(expected, 0, COUNTOF(expected));
+  len = GetLocaleInfoA(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
+  SetLastError(0xdeadbeef);
+  memset(buffer, 0, COUNTOF(buffer));
+  ret = GetLocaleInfoA(LANG_ENGLISH, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
+  ok((ret == len) && !lstrcmpA(buffer, expected),
+      "got %d with '%s' (expected %d with '%s')\n",
+      ret, buffer, len, expected);
+
+  memset(expected, 0, COUNTOF(expected));
+  len = GetLocaleInfoA(MAKELANGID(LANG_ARABIC, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
+  if (len) {
+      SetLastError(0xdeadbeef);
+      memset(buffer, 0, COUNTOF(buffer));
+      ret = GetLocaleInfoA(LANG_ARABIC, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
+      ok((ret == len) && !lstrcmpA(buffer, expected),
+          "got %d with '%s' (expected %d with '%s')\n",
+          ret, buffer, len, expected);
+  }
+  else
+      win_skip("LANG_ARABIC not installed\n");
+
+  memset(expected, 0, COUNTOF(expected));
+  len = GetLocaleInfoA(MAKELANGID(LANG_CHINESE, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
+  if (len) {
+      SetLastError(0xdeadbeef);
+      memset(buffer, 0, COUNTOF(buffer));
+      ret = GetLocaleInfoA(LANG_CHINESE, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
+      ok((ret == len) && !lstrcmpA(buffer, expected),
+          "got %d with '%s' (expected %d with '%s')\n",
+          ret, buffer, len, expected);
+  }
+  else
+      win_skip("LANG_CHINESE not installed\n");
+
+  /* SUBLANG_DEFAULT is required for mlang.dll, but optional for GetLocaleInfo */
+  memset(expected, 0, COUNTOF(expected));
+  len = GetLocaleInfoA(MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), LOCALE_SLANGUAGE, expected, COUNTOF(expected));
+  SetLastError(0xdeadbeef);
+  memset(buffer, 0, COUNTOF(buffer));
+  ret = GetLocaleInfoA(LANG_GERMAN, LOCALE_SLANGUAGE, buffer, COUNTOF(buffer));
+  ok((ret == len) && !lstrcmpA(buffer, expected),
+      "got %d with '%s' (expected %d with '%s')\n",
+      ret, buffer, len, expected);
+
+
   /* HTMLKit and "Font xplorer lite" expect GetLocaleInfoA to
    * partially fill the buffer even if it is too short. See bug 637.
    */
-  SetLastError(0); memset(buffer, 0, COUNTOF(buffer));
+  SetLastError(0xdeadbeef);
+  memset(buffer, 0, COUNTOF(buffer));
   ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 0);
   ok(ret == 7 && !buffer[0], "Expected len=7, got %d\n", ret);
 
-  SetLastError(0); memset(buffer, 0, COUNTOF(buffer));
+  SetLastError(0xdeadbeef);
+  memset(buffer, 0, COUNTOF(buffer));
   ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 3);
   ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
       "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
   ok(!strcmp(buffer, "Mon"), "Expected 'Mon', got '%s'\n", buffer);
 
-  SetLastError(0); memset(buffer, 0, COUNTOF(buffer));
+  SetLastError(0xdeadbeef);
+  memset(buffer, 0, COUNTOF(buffer));
   ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 10);
   ok(ret == 7, "Expected ret == 7, got %d, error %d\n", ret, GetLastError());
   ok(!strcmp(buffer, "Monday"), "Expected 'Monday', got '%s'\n", buffer);
@@ -432,7 +484,10 @@ static void test_GetDateFormatW(void)
   ret = GetDateFormatW(LOCALE_SYSTEM_DEFAULT, DATE_LONGDATE, NULL,
                        input, buffer, COUNTOF(buffer));
   if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
-      return;
+  {
+    win_skip("GetDateFormatW is not implemented\n");
+    return;
+  }
   ok(!ret && GetLastError() == ERROR_INVALID_FLAGS,
      "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
   EXPECT_EQW;
@@ -1631,8 +1686,11 @@ static void test_FoldStringA(void)
   /* MAP_FOLDDIGITS */
   SetLastError(0);
   ret = pFoldStringA(MAP_FOLDDIGITS, digits_src, -1, dst, 256);
-  if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
+  if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+  {
+    win_skip("FoldStringA is not implemented\n");
     return;
+  }
   ok(ret == 4, "Expected ret == 4, got %d, error %d\n", ret, GetLastError());
   ok(strcmp(dst, digits_dst) == 0,
      "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", digits_dst, dst);
index 73d7946..374a18e 100755 (executable)
@@ -249,10 +249,24 @@ static void testLoadLibraryEx(void)
     SetLastError(0xdeadbeef);
     hmodule = LoadLibraryExA("testfile.dll", hfile, 0);
     ok(hmodule == 0, "Expected 0, got %p\n", hmodule);
-    ok(GetLastError() == ERROR_SHARING_VIOLATION ||
-       GetLastError() == ERROR_INVALID_PARAMETER || /* win2k3 */
-       GetLastError() == ERROR_FILE_NOT_FOUND, /* win9x */
-       "Unexpected last error, got %d\n", GetLastError());
+    todo_wine
+    {
+        ok(GetLastError() == ERROR_SHARING_VIOLATION ||
+           GetLastError() == ERROR_INVALID_PARAMETER || /* win2k3 */
+           GetLastError() == ERROR_FILE_NOT_FOUND, /* win9x */
+           "Unexpected last error, got %d\n", GetLastError());
+    }
+
+    SetLastError(0xdeadbeef);
+    hmodule = LoadLibraryExA("testfile.dll", (HANDLE)0xdeadbeef, 0);
+    ok(hmodule == 0, "Expected 0, got %p\n", hmodule);
+    todo_wine
+    {
+        ok(GetLastError() == ERROR_SHARING_VIOLATION ||
+           GetLastError() == ERROR_INVALID_PARAMETER || /* win2k3 */
+           GetLastError() == ERROR_FILE_NOT_FOUND, /* win9x */
+           "Unexpected last error, got %d\n", GetLastError());
+    }
 
     /* try to open a file that is locked */
     SetLastError(0xdeadbeef);
@@ -304,6 +318,12 @@ static void testLoadLibraryEx(void)
        GetLastError() == ERROR_SUCCESS, /* win9x */
        "Expected 0xdeadbeef or ERROR_SUCCESS, got %d\n", GetLastError());
 
+    /* try invalid file handle */
+    SetLastError(0xdeadbeef);
+    hmodule = LoadLibraryExA(path, (HANDLE)0xdeadbeef, 0);
+    if (!hmodule)  /* succeeds on xp and older */
+        ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError());
+
     CloseHandle(hmodule);
 
     /* load kernel32.dll with no path */
index 20ee453..de26fc9 100755 (executable)
@@ -878,8 +878,11 @@ static void test_GetTempPathW(char* tmp_dir)
 
     lstrcpyW(buf, fooW);
     len = GetTempPathW(MAX_PATH, buf);
-    if (len==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
+    if (len == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+    {
+        win_skip("GetTempPathW is not available\n");
         return;
+    }
     ok(lstrcmpiW(buf, tmp_dirW) == 0, "GetTempPathW returned an incorrect temporary path\n");
     ok(len == lstrlenW(buf), "returned length should be equal to the length of string\n");
 
index 2b07450..1a57d5b 100755 (executable)
@@ -388,7 +388,7 @@ static void     doChild(const char* file, const char* option)
         ret = SetConsoleCP(1252);
         if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
         {
-            win_skip("Setting the codepage is not implemented");
+            win_skip("Setting the codepage is not implemented\n");
         }
         else
         {
@@ -927,6 +927,72 @@ static void test_CommandLine(void)
     okChildStringWA("Arguments", "CommandLineW", buffer2);
     release_memory();
     assert(DeleteFileA(resfile) != 0);
+
+    if (0) /* Test crashes on NT-based Windows. */
+    {
+        /* Test NULL application name and command line parameters. */
+        SetLastError(0xdeadbeef);
+        ret = CreateProcessA(NULL, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
+        ok(!ret, "CreateProcessA unexpectedly succeeded\n");
+        ok(GetLastError() == ERROR_INVALID_PARAMETER,
+           "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+    }
+
+    buffer[0] = '\0';
+
+    /* Test empty application name parameter. */
+    SetLastError(0xdeadbeef);
+    ret = CreateProcessA(buffer, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
+    ok(!ret, "CreateProcessA unexpectedly succeeded\n");
+    ok(GetLastError() == ERROR_PATH_NOT_FOUND ||
+       broken(GetLastError() == ERROR_FILE_NOT_FOUND) /* Win9x/WinME */ ||
+       broken(GetLastError() == ERROR_ACCESS_DENIED) /* Win98 */,
+       "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
+
+    buffer2[0] = '\0';
+
+    /* Test empty application name and command line parameters. */
+    SetLastError(0xdeadbeef);
+    ret = CreateProcessA(buffer, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
+    ok(!ret, "CreateProcessA unexpectedly succeeded\n");
+    ok(GetLastError() == ERROR_PATH_NOT_FOUND ||
+       broken(GetLastError() == ERROR_FILE_NOT_FOUND) /* Win9x/WinME */ ||
+       broken(GetLastError() == ERROR_ACCESS_DENIED) /* Win98 */,
+       "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
+
+    /* Test empty command line parameter. */
+    SetLastError(0xdeadbeef);
+    ret = CreateProcessA(NULL, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
+    ok(!ret, "CreateProcessA unexpectedly succeeded\n");
+    ok(GetLastError() == ERROR_FILE_NOT_FOUND ||
+       GetLastError() == ERROR_PATH_NOT_FOUND /* NT4 */ ||
+       GetLastError() == ERROR_BAD_PATHNAME /* Win98 */,
+       "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
+
+    strcpy(buffer, "doesnotexist.exe");
+    strcpy(buffer2, "does not exist.exe");
+
+    /* Test nonexistent application name. */
+    SetLastError(0xdeadbeef);
+    ret = CreateProcessA(buffer, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
+    ok(!ret, "CreateProcessA unexpectedly succeeded\n");
+    ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
+    ret = CreateProcessA(buffer2, NULL, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
+    ok(!ret, "CreateProcessA unexpectedly succeeded\n");
+    ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
+
+    /* Test nonexistent command line parameter. */
+    SetLastError(0xdeadbeef);
+    ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
+    ok(!ret, "CreateProcessA unexpectedly succeeded\n");
+    ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
+    ret = CreateProcessA(NULL, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info);
+    ok(!ret, "CreateProcessA unexpectedly succeeded\n");
+    ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
 }
 
 static void test_Directory(void)
index fbf5d24..b9a71d3 100755 (executable)
@@ -822,18 +822,12 @@ static void test_GetPrivateProfileString(const char *content, const char *descri
     DeleteFileA(filename);
 }
 
-static DWORD timeout = 0;
-
 static BOOL check_binary_file_data(LPCSTR path, const VOID *data, DWORD size)
 {
     HANDLE file;
     CHAR buf[MAX_PATH];
     BOOL ret;
 
-    /* Sleep() is needed on Win9x and WinME */
-    if (timeout)
-        Sleep(timeout);
-
     file = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
     if (file == INVALID_HANDLE_VALUE)
       return FALSE;
@@ -864,6 +858,19 @@ static void test_WritePrivateProfileString(void)
     CHAR path[MAX_PATH];
     CHAR temp[MAX_PATH];
 
+    SetLastError(0xdeadbeef);
+    ret = WritePrivateProfileStringW(NULL, NULL, NULL, NULL);
+    if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+    {
+        /* Win9x/WinME needs (variable) timeouts between tests and even long timeouts don't
+         * guarantee a correct result.
+         * Win9x/WinMe also produces different ini files where there is always a newline before
+         * a section start (except for the first one).
+         */
+        win_skip("WritePrivateProfileString on Win9x/WinME is hard to test reliably\n");
+        return;
+    }
+
     GetTempPathA(MAX_PATH, temp);
     GetTempFileNameA(temp, "wine", 0, path);
     DeleteFileA(path);
@@ -878,8 +885,6 @@ static void test_WritePrivateProfileString(void)
        broken(GetLastError() == ERROR_INVALID_PARAMETER) || /* NT4 */
        broken(GetLastError() == 0xdeadbeef), /* Win9x and WinME */
        "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
-    if (GetLastError() == 0xdeadbeef)
-        timeout = 1000;
     ok(GetFileAttributesA(path) == INVALID_FILE_ATTRIBUTES,
        "Expected path to not exist\n");
 
index c1d65c1..2c699b4 100755 (executable)
@@ -693,7 +693,10 @@ static VOID test_thread_priority(void)
    SetLastError(0xdeadbeef);
    rc=pGetThreadPriorityBoost(curthread,&disabled);
    if (rc==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
-     return; /* WinME */
+   {
+      win_skip("GetThreadPriorityBoost is not implemented on WinME\n");
+      return;
+   }
 
    todo_wine
      ok(rc!=0,"error=%d\n",GetLastError());
@@ -755,7 +758,10 @@ static VOID test_GetThreadTimes(void)
 /* GetThreadTimes should set all of the parameters passed to it */
      error=GetThreadTimes(thread,&creationTime,&exitTime,
                           &kernelTime,&userTime);
-     if (error!=0 || GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED) {
+
+     if (error == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+       win_skip("GetThreadTimes is not implemented\n");
+     else {
        ok(error!=0,"GetThreadTimes failed\n");
        ok(creationTime.dwLowDateTime!=99 || creationTime.dwHighDateTime!=99,
           "creationTime was invalid\n");
index 5bea009..e665f0f 100755 (executable)
@@ -328,7 +328,7 @@ static void test_MapViewOfFile(void)
 {
     static const char testfile[] = "testfile.xxx";
     const char *name;
-    HANDLE file, mapping;
+    HANDLE file, mapping, map2;
     void *ptr, *ptr2;
     MEMORY_BASIC_INFORMATION info;
     BOOL ret;
@@ -365,6 +365,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 */
index 19fc6f0..2c25465 100644 (file)
@@ -67,7 +67,8 @@ static void test_query_dos_deviceA(void)
     }
 
     for (;drivestr[0] <= 'z'; drivestr[0]++) {
-        ret = QueryDosDeviceA( drivestr, buffer, buflen);
+        /* Older W2K fails with ERROR_INSUFFICIENT_BUFFER when buflen is > 32767 */
+        ret = QueryDosDeviceA( drivestr, buffer, buflen - 1);
         if(ret) {
             for (p = buffer; *p; p++) *p = toupper(*p);
             if (strstr(buffer, "HARDDISK") || strstr(buffer, "RAMDISK")) found = TRUE;
@@ -114,7 +115,8 @@ static void test_GetVolumeNameForVolumeMountPointA(void)
 {
     BOOL ret;
     char volume[MAX_PATH], path[] = "c:\\";
-    DWORD len = sizeof(volume);
+    DWORD len = sizeof(volume), reti;
+    char temp_path[MAX_PATH];
 
     /* not present before w2k */
     if (!pGetVolumeNameForVolumeMountPointA) {
@@ -122,8 +124,15 @@ static void test_GetVolumeNameForVolumeMountPointA(void)
         return;
     }
 
+    reti = GetTempPathA(MAX_PATH, temp_path);
+    ok(reti != 0, "GetTempPathA error %d\n", GetLastError());
+    ok(reti < MAX_PATH, "temp path should fit into MAX_PATH\n");
+
     ret = pGetVolumeNameForVolumeMountPointA(path, volume, 0);
     ok(ret == FALSE, "GetVolumeNameForVolumeMountPointA succeeded\n");
+    ok(GetLastError() == ERROR_FILENAME_EXCED_RANGE ||
+        GetLastError() == ERROR_INVALID_PARAMETER, /* Vista */
+        "wrong error, last=%d\n", GetLastError());
 
     if (0) { /* these crash on XP */
     ret = pGetVolumeNameForVolumeMountPointA(path, NULL, len);
@@ -135,6 +144,43 @@ static void test_GetVolumeNameForVolumeMountPointA(void)
 
     ret = pGetVolumeNameForVolumeMountPointA(path, volume, len);
     ok(ret == TRUE, "GetVolumeNameForVolumeMountPointA failed\n");
+    ok(!strncmp( volume, "\\\\?\\Volume{", 11),
+        "GetVolumeNameForVolumeMountPointA failed to return valid string <%s>\n",
+        volume);
+
+    /* test with too small buffer */
+    ret = pGetVolumeNameForVolumeMountPointA(path, volume, 10);
+    ok(ret == FALSE && GetLastError() == ERROR_FILENAME_EXCED_RANGE,
+            "GetVolumeNameForVolumeMountPointA failed, wrong error returned, was %d, should be ERROR_FILENAME_EXCED_RANGE\n",
+             GetLastError());
+
+    /* Try on a arbitrary directory */
+    ret = pGetVolumeNameForVolumeMountPointA(temp_path, volume, len);
+    ok(ret == FALSE && GetLastError() == ERROR_NOT_A_REPARSE_POINT,
+        "GetVolumeNameForVolumeMountPointA failed on %s, last=%d\n",
+        temp_path, GetLastError());
+
+    /* Try on a non-existent dos drive */
+    path[2] = 0;
+    for (;path[0] <= 'z'; path[0]++) {
+        ret = QueryDosDeviceA( path, volume, len);
+        if(!ret) break;
+    }
+    if (path[0] <= 'z')
+    {
+        path[2] = '\\';
+        ret = pGetVolumeNameForVolumeMountPointA(path, volume, len);
+        ok(ret == FALSE && GetLastError() == ERROR_FILE_NOT_FOUND,
+            "GetVolumeNameForVolumeMountPointA failed on %s, last=%d\n",
+            path, GetLastError());
+
+        /* Try without trailing \ and on a non-existent dos drive  */
+        path[2] = 0;
+        ret = pGetVolumeNameForVolumeMountPointA(path, volume, len);
+        ok(ret == FALSE && GetLastError() == ERROR_INVALID_NAME,
+            "GetVolumeNameForVolumeMountPointA failed on %s, last=%d\n",
+            path, GetLastError());
+    }
 }
 
 static void test_GetVolumeNameForVolumeMountPointW(void)
@@ -151,6 +197,9 @@ static void test_GetVolumeNameForVolumeMountPointW(void)
 
     ret = pGetVolumeNameForVolumeMountPointW(path, volume, 0);
     ok(ret == FALSE, "GetVolumeNameForVolumeMountPointA succeeded\n");
+    ok(GetLastError() == ERROR_FILENAME_EXCED_RANGE ||
+        GetLastError() == ERROR_INVALID_PARAMETER, /* Vista */
+        "wrong error, last=%d\n", GetLastError());
 
     if (0) { /* these crash on XP */
     ret = pGetVolumeNameForVolumeMountPointW(path, NULL, len);
@@ -340,7 +389,6 @@ static void test_enum_vols(void)
     /* get the unique volume name for the windows drive  */
     ret = pGetVolumeNameForVolumeMountPointA( path, Volume_1, MAX_PATH );
     ok(ret == TRUE, "GetVolumeNameForVolumeMountPointA failed\n");
-todo_wine
     ok(strlen(Volume_1) == 49, "GetVolumeNameForVolumeMountPointA returned wrong length name %s\n", Volume_1);
 
     /* get first unique volume name of list  */
@@ -358,7 +406,6 @@ todo_wine
             break;
         }
     } while (pFindNextVolumeA( hFind, Volume_2, MAX_PATH ));
-todo_wine
     ok(found, "volume name %s not found by Find[First/Next]Volume\n", Volume_1);
     pFindVolumeClose( hFind );
 }