winetest_end_todo(platform))
#define todo_wine todo("wine")
+#ifdef NONAMELESSUNION
+# define U(x) (x).u
+# define U1(x) (x).u1
+# define U2(x) (x).u2
+# define U3(x) (x).u3
+# define U4(x) (x).u4
+# define U5(x) (x).u5
+# define U6(x) (x).u6
+# define U7(x) (x).u7
+# define U8(x) (x).u8
+#else
+# define U(x) (x)
+# define U1(x) (x)
+# define U2(x) (x)
+# define U3(x) (x)
+# define U4(x) (x)
+# define U5(x) (x)
+# define U6(x) (x)
+# define U7(x) (x)
+# define U8(x) (x)
+#endif
+
+#ifdef NONAMELESSSTRUCT
+# define S(x) (x).s
+# define S1(x) (x).s1
+# define S2(x) (x).s2
+# define S3(x) (x).s3
+# define S4(x) (x).s4
+# define S5(x) (x).s5
+#else
+# define S(x) (x)
+# define S1(x) (x)
+# define S2(x) (x)
+# define S3(x) (x)
+# define S4(x) (x)
+# define S5(x) (x)
+#endif
/************************************************************************/
/* Below is the implementation of the various functions, to be included
#include "windef.h"
#include "winbase.h"
#include "winerror.h"
+#include "winuser.h"
+
+#define DOUBLE(x) (WCHAR)((x<<8)|(x))
static const WCHAR foobarW[] = {'f','o','o','b','a','r',0};
static const WCHAR FOOBARW[] = {'F','O','O','B','A','R',0};
static const WCHAR _foobarW[] = {'_','f','o','o','b','a','r',0};
+static void do_initA(char* tmp, const char* pattern, int len)
+{
+ const char* p = pattern;
+
+ while (len--)
+ {
+ *tmp++ = *p++;
+ if (!*p) p = pattern;
+ }
+ *tmp = '\0';
+}
+
+static void do_initW(WCHAR* tmp, const char* pattern, int len)
+{
+ const char* p = pattern;
+
+ while (len--)
+ {
+ *tmp++ = *p++;
+ if (!*p) p = pattern;
+ }
+ *tmp = '\0';
+}
+
+static void print_integral( WCHAR* buffer, int atom )
+{
+ BOOL first = TRUE;
+
+#define X(v) { if (atom >= v) {*buffer++ = '0' + atom / v; first = FALSE; } else if (!first || v == 1) *buffer++ = '0'; atom %= v; }
+ *buffer++ = '#';
+ X(10000);
+ X(1000);
+ X(100);
+ X(10);
+ X(1);
+ *buffer = '\0';
+#undef X
+}
+
static BOOL unicode_OS;
static void test_add_atom(void)
int i;
UINT len;
static const WCHAR resultW[] = {'f','o','o','b','a','r',0,'.','.','.'};
+ char in[257], out[257];
+ WCHAR inW[257], outW[257];
ATOM atom = GlobalAddAtomA( "foobar" );
}
else
ok( !len, "bad length %d\n", len );
+
+ SetLastError(0xdeadbeef);
+ len = GlobalGetAtomNameA( (ATOM)i, buf, 2);
+ if (!len) /* the NT way */
+ {
+ ok(GetLastError() == (i ? ERROR_MORE_DATA : ERROR_INVALID_PARAMETER) ||
+ GetLastError() == 0xdeadbeef, /* the Win 9x way */
+ "wrong error conditions %lu for %u\n", GetLastError(), i);
+ }
+ else /* the Win 9x way */
+ {
+ ok(GetLastError() == 0xdeadbeef,
+ "wrong error conditions %lu for %u\n", GetLastError(), i);
+ }
+ }
+
+ memset( buf, '.', sizeof(buf) );
+ len = GlobalGetAtomNameA( atom, buf, 6 );
+ ok( len == 0, "bad length %d\n", len );
+ ok( !memcmp( buf, "fooba\0....", 10 ), "bad buffer contents\n");
+ if (unicode_OS)
+ {
+ static const WCHAR resW[] = {'f','o','o','b','a','r','.','.','.','.'};
+ for (len = 0; len < 10; len++) bufW[len] = '.';
+ SetLastError(0xdeadbeef);
+ len = GlobalGetAtomNameW( atom, bufW, 6 );
+ ok( len && GetLastError() == 0xdeadbeef, "GlobalGetAtomNameW failed\n" );
+ ok( len == lstrlenW(foobarW), "bad length %d\n", len );
+ ok( !memcmp( bufW, resW, 10*sizeof(WCHAR) ), "bad buffer contents\n" );
+ }
+
+ /* test string limits & overflow */
+ do_initA(in, "abcdefghij", 255);
+ atom = GlobalAddAtomA(in);
+ ok(atom, "couldn't add atom for %s\n", in);
+ len = GlobalGetAtomNameA(atom, out, sizeof(out));
+ ok(len == 255, "length mismatch (%u instead of 255)\n", len);
+ for (i = 0; i < 255; i++)
+ {
+ ok(out[i] == "abcdefghij"[i % 10], "wrong string at %i (%c instead of %c)\n", i, out[i], "abcdefghij"[i % 10]);
+ }
+ ok(out[255] == '\0', "wrong end of string\n");
+ memset(out, '.', sizeof(out));
+ SetLastError(0xdeadbeef);
+ len = GlobalGetAtomNameA(atom, out, 10);
+ if (!len) /* the NT way */
+ {
+ ok(GetLastError() == ERROR_MORE_DATA, "wrong error code (%lu instead of %lu)\n", GetLastError(), (DWORD)ERROR_MORE_DATA);
+ }
+ else /* the Win9x way */
+ {
+ ok(GetLastError() == 0xdeadbeef, "wrong error code (%lu instead of %u)\n", GetLastError(), 0xdeadbeef);
+ }
+ for (i = 0; i < 9; i++)
+ {
+ ok(out[i] == "abcdefghij"[i % 10], "wrong string at %i (%c instead of %c)\n", i, out[i], "abcdefghij"[i % 10]);
+ }
+ ok(out[9] == '\0', "wrong end of string\n");
+ ok(out[10] == '.', "wrote after end of buf\n");
+ do_initA(in, "abcdefghij", 256);
+ atom = GlobalAddAtomA(in);
+ ok(!atom, "succeeded\n");
+ if (unicode_OS)
+ {
+ /* test integral atoms */
+ for (i = 0; i <= 0xbfff; i++)
+ {
+ memset(outW, 'a', sizeof(outW));
+ len = GlobalGetAtomNameW( (ATOM)i, outW, 10 );
+ if (i)
+ {
+ WCHAR res[20];
+
+ ok( (len > 1) && (len < 7), "bad length %d\n", len );
+ print_integral( res, i );
+ memset( res + lstrlenW(res) + 1, 'a', 10 * sizeof(WCHAR));
+ ok( !memcmp( res, outW, 10 * sizeof(WCHAR) ), "bad buffer contents for %d\n", i );
+ }
+ else
+ ok( !len, "bad length %d\n", len );
+
+ memset(outW, '.', sizeof(outW));
+ SetLastError(0xdeadbeef);
+ len = GlobalGetAtomNameW( (ATOM)i, outW, 1);
+ if (i)
+ {
+ /* len == 0 with ERROR_MORE_DATA is on NT3.51 */
+ ok(len == 1 || (len == 0 && GetLastError() == ERROR_MORE_DATA),
+ "0x%04x: got %u with %ld (excepted '1' or '0' with " \
+ "ERROR_MORE_DATA)\n", i, len, GetLastError());
+ ok(outW[1] == DOUBLE('.'), "buffer overwrite\n");
+ }
+ else ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "0 badly handled\n");
+ }
+
+ do_initW(inW, "abcdefghij", 255);
+ atom = GlobalAddAtomW(inW);
+ ok(atom, "couldn't add atom for %s\n", in);
+ len = GlobalGetAtomNameW(atom, outW, sizeof(outW));
+ ok(len == 255, "length mismatch (%u instead of 255)\n", len);
+ for (i = 0; i < 255; i++)
+ {
+ ok(outW[i] == "abcdefghij"[i % 10], "wrong string at %i (%c instead of %c)\n", i, outW[i], "abcdefghij"[i % 10]);
+ }
+ ok(outW[255] == '\0', "wrong end of string\n");
+ memset(outW, '.', sizeof(outW));
+ len = GlobalGetAtomNameW(atom, outW, 10);
+ ok(len == 10, "succeeded\n");
+ for (i = 0; i < 10; i++)
+ {
+ ok(outW[i] == "abcdefghij"[i % 10], "wrong string at %i (%c instead of %c)\n", i, outW[i], "abcdefghij"[i % 10]);
+ }
+ ok(outW[10] == DOUBLE('.'), "wrote after end of buf\n");
+ do_initW(inW, "abcdefghij", 256);
+ atom = GlobalAddAtomW(inW);
+ ok(!atom, "succeeded\n");
+ ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error code\n");
}
}
static void test_local_get_atom_name(void)
{
- char buf[10];
- WCHAR bufW[10];
+ char buf[10], in[257], out[257];
+ WCHAR bufW[10], inW[257], outW[257];
int i;
UINT len;
static const WCHAR resultW[] = {'f','o','o','b','a','r',0,'.','.','.'};
ok( !memcmp( bufW, resultW, 10*sizeof(WCHAR) ), "bad buffer contents\n" );
}
+ /* Get the name of the atom we added above */
+ memset( buf, '.', sizeof(buf) );
+ len = GetAtomNameA( atom, buf, 6 );
+ ok( len == 5, "bad length %d\n", len );
+ ok( !memcmp( buf, "fooba\0....", 10 ), "bad buffer contents\n" );
+
+ /* Repeat, unicode-style */
+ if (unicode_OS)
+ {
+ WCHAR resW[] = {'f','o','o','b','a','\0','.','.','.','.'};
+ for (i = 0; i < 10; i++) bufW[i] = '.';
+ SetLastError( 0xdeadbeef );
+ len = GetAtomNameW( atom, bufW, 6 );
+ ok( len && GetLastError() == 0xdeadbeef, "GlobalGetAtomNameW failed\n" );
+ ok( len == 5, "bad length %d\n", len );
+ ok( !memcmp( bufW, resW, 10*sizeof(WCHAR) ), "bad buffer contents\n" );
+ }
+
/* Check error code returns */
memset(buf, '.', 10);
ok( !GetAtomNameA( atom, buf, 0 ), "succeeded\n" );
if (i)
{
char res[20];
- ok( (len > 1) && (len < 7), "bad length %d\n", len );
+ ok( (len > 1) && (len < 7), "bad length %d for %s\n", len, buf );
sprintf( res, "#%d", i );
memset( res + strlen(res) + 1, 'a', 10 );
ok( !memcmp( res, buf, 10 ), "bad buffer contents %s\n", buf );
}
else
ok( !len, "bad length %d\n", len );
+
+ len = GetAtomNameA( (ATOM)i, buf, 1);
+ ok(!len, "succeed with %u for %u\n", len, i);
+
+ /* ERROR_MORE_DATA is on nt3.51 sp5 */
+ if (i)
+ ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER ||
+ GetLastError() == ERROR_MORE_DATA ||
+ GetLastError() == 0xdeadbeef, /* the Win 9x way */
+ "wrong error conditions %lu for %u\n", GetLastError(), i);
+ else
+ ok(GetLastError() == ERROR_INVALID_PARAMETER ||
+ GetLastError() == ERROR_MORE_DATA ||
+ GetLastError() == 0xdeadbeef, /* the Win 9x way */
+ "wrong error conditions %lu for %u\n", GetLastError(), i);
+ }
+ /* test string limits & overflow */
+ do_initA(in, "abcdefghij", 255);
+ atom = AddAtomA(in);
+ ok(atom, "couldn't add atom for %s\n", in);
+ len = GetAtomNameA(atom, out, sizeof(out));
+ ok(len == 255, "length mismatch (%u instead of 255)\n", len);
+ for (i = 0; i < 255; i++)
+ {
+ ok(out[i] == "abcdefghij"[i % 10], "wrong string at %i (%c instead of %c)\n", i, out[i], "abcdefghij"[i % 10]);
+ }
+ ok(out[255] == '\0', "wrong end of string\n");
+ memset(out, '.', sizeof(out));
+ len = GetAtomNameA(atom, out, 10);
+ ok(len == 9, "succeeded %d\n", len);
+ for (i = 0; i < 9; i++)
+ {
+ ok(out[i] == "abcdefghij"[i % 10], "wrong string at %i (%c instead of %c)\n", i, out[i], "abcdefghij"[i % 10]);
+ }
+ ok(out[9] == '\0', "wrong end of string\n");
+ ok(out[10] == '.', "buffer overwrite\n");
+ do_initA(in, "abcdefghij", 256);
+ atom = AddAtomA(in);
+ ok(!atom, "succeeded\n");
+
+ /* ERROR_MORE_DATA is on nt3.51 sp5 */
+ ok(GetLastError() == ERROR_INVALID_PARAMETER ||
+ GetLastError() == ERROR_MORE_DATA ||
+ GetLastError() == 0xdeadbeef, /* the Win 9x way */
+ "wrong error code (%lu)\n", GetLastError());
+
+ if (unicode_OS)
+ {
+ /* test integral atoms */
+ for (i = 0; i <= 0xbfff; i++)
+ {
+ memset(outW, 'a', sizeof(outW));
+ len = GetAtomNameW( (ATOM)i, outW, 10 );
+ if (i)
+ {
+ WCHAR res[20];
+
+ ok( (len > 1) && (len < 7), "bad length %d\n", len );
+ print_integral( res, i );
+ memset( res + lstrlenW(res) + 1, 'a', 10 * sizeof(WCHAR));
+ ok( !memcmp( res, outW, 10 * sizeof(WCHAR) ), "bad buffer contents for %d\n", i );
+ }
+ else
+ ok( !len, "bad length %d\n", len );
+
+ len = GetAtomNameW( (ATOM)i, outW, 1);
+ ok(!len, "succeed with %u for %u\n", len, i);
+
+ /* ERROR_MORE_DATA is on nt3.51 sp5 */
+ ok(GetLastError() == ERROR_MORE_DATA ||
+ GetLastError() == (i ? ERROR_INSUFFICIENT_BUFFER : ERROR_INVALID_PARAMETER),
+ "wrong error conditions %lu for %u\n", GetLastError(), i);
+ }
+ do_initW(inW, "abcdefghij", 255);
+ atom = AddAtomW(inW);
+ ok(atom, "couldn't add atom for %s\n", in);
+ len = GetAtomNameW(atom, outW, sizeof(outW));
+ ok(len == 255, "length mismatch (%u instead of 255)\n", len);
+ for (i = 0; i < 255; i++)
+ {
+ ok(outW[i] == "abcdefghij"[i % 10], "wrong string at %i (%c instead of %c)\n", i, outW[i], "abcdefghij"[i % 10]);
+ }
+ ok(outW[255] == '\0', "wrong end of string\n");
+ memset(outW, '.', sizeof(outW));
+ len = GetAtomNameW(atom, outW, 10);
+ ok(len == 9, "succeeded %d\n", len);
+ for (i = 0; i < 9; i++)
+ {
+ ok(outW[i] == "abcdefghij"[i % 10], "wrong string at %i (%c instead of %c)\n", i, outW[i], "abcdefghij"[i % 10]);
+ }
+ ok(outW[9] == '\0', "wrong end of string\n");
+ ok(outW[10] == DOUBLE('.'), "buffer overwrite\n");
+ do_initW(inW, "abcdefghij", 256);
+ atom = AddAtomW(inW);
+ ok(!atom, "succeeded\n");
+
+ /* ERROR_MORE_DATA is on nt3.51 sp5 */
+ ok(GetLastError() == ERROR_INVALID_PARAMETER ||
+ GetLastError() == ERROR_MORE_DATA,
+ "wrong error code (%lu)\n", GetLastError());
}
}
}
}
-
START_TEST(atom)
{
test_add_atom();
* Tests for file change notification functions
*
* Copyright (c) 2004 Hans Leidekker
+ * Copyright 2006 Mike McCormack for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
#include <stdarg.h>
#include <stdio.h>
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
#include "wine/test.h"
#include <windef.h>
#include <winbase.h>
+#include <winternl.h>
static DWORD CALLBACK NotificationThread(LPVOID arg)
{
lstrcpyA(dirname1, filename1);
lstrcatA(dirname1, "dir");
+ lstrcpyA(dirname2, dirname1);
+ lstrcatA(dirname2, "new");
+
ret = CreateDirectoryA(dirname1, NULL);
ok(ret, "CreateDirectoryA error: %ld\n", GetLastError());
- /* What if we remove the directory we registered notification for? */
+ /* What if we move the directory we registered notification for? */
thread = StartNotificationThread(dirname1, FALSE, FILE_NOTIFY_CHANGE_DIR_NAME);
- ret = RemoveDirectoryA(dirname1);
+ ret = MoveFileA(dirname1, dirname2);
+ ok(ret, "MoveFileA error: %ld\n", GetLastError());
+ ok(FinishNotificationThread(thread), "Missed notification\n");
+
+ /* What if we remove the directory we registered notification for? */
+ thread = StartNotificationThread(dirname2, FALSE, FILE_NOTIFY_CHANGE_DIR_NAME);
+ ret = RemoveDirectoryA(dirname2);
ok(ret, "RemoveDirectoryA error: %ld\n", GetLastError());
/* win98 and win2k behave differently here */
ok(ret, "CreateDirectoryA error: %ld\n", GetLastError());
ok(FinishNotificationThread(thread), "Missed notification\n");
- lstrcpyA(dirname2, dirname1);
- lstrcatA(dirname2, "new");
-
/* Rename a directory */
thread = StartNotificationThread(workdir, FALSE, FILE_NOTIFY_CHANGE_DIR_NAME);
ret = MoveFileA(dirname1, dirname2);
ok(ret, "RemoveDirectoryA error: %ld\n", GetLastError());
}
+/* this test concentrates more on the wait behaviour of the handle */
+static void test_ffcn(void)
+{
+ DWORD filter;
+ HANDLE handle;
+ LONG r;
+ WCHAR path[MAX_PATH], subdir[MAX_PATH];
+ static const WCHAR szBoo[] = { '\\','b','o','o',0 };
+ static const WCHAR szHoo[] = { '\\','h','o','o',0 };
+
+ r = GetTempPathW( MAX_PATH, path );
+ ok( r != 0, "temp path failed\n");
+ if (!r)
+ return;
+
+ lstrcatW( path, szBoo );
+ lstrcpyW( subdir, path );
+ lstrcatW( subdir, szHoo );
+
+ RemoveDirectoryW( subdir );
+ RemoveDirectoryW( path );
+
+ r = CreateDirectoryW(path, NULL);
+ ok( r == TRUE, "failed to create directory\n");
+
+ filter = FILE_NOTIFY_CHANGE_FILE_NAME;
+ filter |= FILE_NOTIFY_CHANGE_DIR_NAME;
+
+ handle = FindFirstChangeNotificationW( path, 1, filter);
+ ok( handle != INVALID_HANDLE_VALUE, "invalid handle\n");
+
+ r = WaitForSingleObject( handle, 0 );
+ ok( r == STATUS_TIMEOUT, "should time out\n");
+
+ r = CreateDirectoryW( subdir, NULL );
+ ok( r == TRUE, "failed to create subdir\n");
+
+ r = WaitForSingleObject( handle, 0 );
+ ok( r == WAIT_OBJECT_0, "should be ready\n");
+
+ r = WaitForSingleObject( handle, 0 );
+ ok( r == WAIT_OBJECT_0, "should be ready\n");
+
+ r = FindNextChangeNotification(handle);
+ ok( r == TRUE, "find next failed\n");
+
+ r = WaitForSingleObject( handle, 0 );
+ ok( r == STATUS_TIMEOUT, "should time out\n");
+
+ r = RemoveDirectoryW( subdir );
+ ok( r == TRUE, "failed to remove subdir\n");
+
+ r = WaitForSingleObject( handle, 0 );
+ ok( r == WAIT_OBJECT_0, "should be ready\n");
+
+ r = WaitForSingleObject( handle, 0 );
+ ok( r == WAIT_OBJECT_0, "should be ready\n");
+
+ r = FindNextChangeNotification(handle);
+ ok( r == TRUE, "find next failed\n");
+
+ r = FindNextChangeNotification(handle);
+ ok( r == TRUE, "find next failed\n");
+
+ r = FindCloseChangeNotification(handle);
+ ok( r == TRUE, "should succeed\n");
+
+ r = RemoveDirectoryW( path );
+ ok( r == TRUE, "failed to remove dir\n");
+}
+
+typedef BOOL (WINAPI *fnReadDirectoryChangesW)(HANDLE,LPVOID,DWORD,BOOL,DWORD,
+ LPDWORD,LPOVERLAPPED,LPOVERLAPPED_COMPLETION_ROUTINE);
+fnReadDirectoryChangesW pReadDirectoryChangesW;
+
+static void test_readdirectorychanges(void)
+{
+ HANDLE hdir;
+ char buffer[0x1000];
+ DWORD fflags, filter = 0, r, dwCount;
+ OVERLAPPED ov;
+ WCHAR path[MAX_PATH], subdir[MAX_PATH], subsubdir[MAX_PATH];
+ static const WCHAR szBoo[] = { '\\','b','o','o',0 };
+ static const WCHAR szHoo[] = { '\\','h','o','o',0 };
+ static const WCHAR szGa[] = { '\\','h','o','o','\\','g','a',0 };
+ PFILE_NOTIFY_INFORMATION pfni;
+
+ if (!pReadDirectoryChangesW)
+ return;
+
+ r = GetTempPathW( MAX_PATH, path );
+ ok( r != 0, "temp path failed\n");
+ if (!r)
+ return;
+
+ lstrcatW( path, szBoo );
+ lstrcpyW( subdir, path );
+ lstrcatW( subdir, szHoo );
+
+ lstrcpyW( subsubdir, path );
+ lstrcatW( subsubdir, szGa );
+
+ RemoveDirectoryW( subsubdir );
+ RemoveDirectoryW( subdir );
+ RemoveDirectoryW( path );
+
+ r = CreateDirectoryW(path, NULL);
+ ok( r == TRUE, "failed to create directory\n");
+
+ SetLastError(0xd0b00b00);
+ r = pReadDirectoryChangesW(NULL,NULL,0,FALSE,0,NULL,NULL,NULL);
+ ok(GetLastError()==ERROR_INVALID_PARAMETER,"last error wrong\n");
+ ok(r==FALSE, "should return false\n");
+
+ fflags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED;
+ hdir = CreateFileW(path, GENERIC_READ|SYNCHRONIZE|FILE_LIST_DIRECTORY,
+ FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
+ OPEN_EXISTING, fflags, NULL);
+ ok( hdir != INVALID_HANDLE_VALUE, "failed to open directory\n");
+
+ ov.hEvent = CreateEvent( NULL, 1, 0, NULL );
+
+ SetLastError(0xd0b00b00);
+ r = pReadDirectoryChangesW(hdir,NULL,0,FALSE,0,NULL,NULL,NULL);
+ ok(GetLastError()==ERROR_INVALID_PARAMETER,"last error wrong\n");
+ ok(r==FALSE, "should return false\n");
+
+ SetLastError(0xd0b00b00);
+ r = pReadDirectoryChangesW(hdir,NULL,0,FALSE,0,NULL,&ov,NULL);
+ ok(GetLastError()==ERROR_INVALID_PARAMETER,"last error wrong\n");
+ ok(r==FALSE, "should return false\n");
+
+ filter = FILE_NOTIFY_CHANGE_FILE_NAME;
+ filter |= FILE_NOTIFY_CHANGE_DIR_NAME;
+ filter |= FILE_NOTIFY_CHANGE_ATTRIBUTES;
+ filter |= FILE_NOTIFY_CHANGE_SIZE;
+ filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
+ filter |= FILE_NOTIFY_CHANGE_LAST_ACCESS;
+ filter |= FILE_NOTIFY_CHANGE_CREATION;
+ filter |= FILE_NOTIFY_CHANGE_SECURITY;
+
+ SetLastError(0xd0b00b00);
+ ov.Internal = 0;
+ ov.InternalHigh = 0;
+ memset( buffer, 0, sizeof buffer );
+
+ r = pReadDirectoryChangesW(hdir,buffer,sizeof buffer,FALSE,-1,NULL,&ov,NULL);
+ ok(GetLastError()==ERROR_INVALID_PARAMETER,"last error wrong\n");
+ ok(r==FALSE, "should return false\n");
+
+ r = pReadDirectoryChangesW(hdir,buffer,sizeof buffer,FALSE,0,NULL,&ov,NULL);
+ ok(GetLastError()==ERROR_INVALID_PARAMETER,"last error wrong\n");
+ ok(r==FALSE, "should return false\n");
+
+ r = pReadDirectoryChangesW(hdir,buffer,sizeof buffer,TRUE,filter,NULL,&ov,NULL);
+ ok(r==TRUE, "should return true\n");
+
+ r = WaitForSingleObject( ov.hEvent, 10 );
+ ok( r == STATUS_TIMEOUT, "should timeout\n" );
+
+ r = CreateDirectoryW( subdir, NULL );
+ ok( r == TRUE, "failed to create directory\n");
+
+ r = WaitForSingleObject( ov.hEvent, INFINITE );
+ ok( r == WAIT_OBJECT_0, "event should be ready\n" );
+
+ ok( ov.Internal == STATUS_SUCCESS, "ov.Internal wrong\n");
+ ok( ov.InternalHigh == 0x12, "ov.InternalHigh wrong\n");
+
+ pfni = (PFILE_NOTIFY_INFORMATION) buffer;
+ ok( pfni->NextEntryOffset == 0, "offset wrong\n" );
+ ok( pfni->Action == FILE_ACTION_ADDED, "action wrong\n" );
+ ok( pfni->FileNameLength == 6, "len wrong\n" );
+ ok( !memcmp(pfni->FileName,&szHoo[1],6), "name wrong\n" );
+
+ ResetEvent(ov.hEvent);
+ SetLastError(0xd0b00b00);
+ r = pReadDirectoryChangesW(hdir,buffer,sizeof buffer,FALSE,0,NULL,NULL,NULL);
+ ok(GetLastError()==ERROR_INVALID_PARAMETER,"last error wrong\n");
+ ok(r==FALSE, "should return false\n");
+
+ r = pReadDirectoryChangesW(hdir,buffer,sizeof buffer,FALSE,0,NULL,&ov,NULL);
+ ok(GetLastError()==ERROR_INVALID_PARAMETER,"last error wrong\n");
+ ok(r==FALSE, "should return false\n");
+
+ filter = FILE_NOTIFY_CHANGE_SIZE;
+
+ SetEvent(ov.hEvent);
+ ov.Internal = 1;
+ ov.InternalHigh = 1;
+ S(U(ov)).Offset = 0;
+ S(U(ov)).OffsetHigh = 0;
+ memset( buffer, 0, sizeof buffer );
+ r = pReadDirectoryChangesW(hdir,buffer,sizeof buffer,FALSE,filter,NULL,&ov,NULL);
+ ok(r==TRUE, "should return true\n");
+
+ ok( ov.Internal == STATUS_PENDING, "ov.Internal wrong\n");
+ ok( ov.InternalHigh == 1, "ov.InternalHigh wrong\n");
+
+ r = WaitForSingleObject( ov.hEvent, 0 );
+ ok( r == STATUS_TIMEOUT, "should timeout\n" );
+
+ r = RemoveDirectoryW( subdir );
+ ok( r == TRUE, "failed to remove directory\n");
+
+ r = WaitForSingleObject( ov.hEvent, INFINITE );
+ ok( r == WAIT_OBJECT_0, "should be ready\n" );
+
+ ok( ov.Internal == STATUS_SUCCESS, "ov.Internal wrong\n");
+ ok( ov.InternalHigh == 0x12, "ov.InternalHigh wrong\n");
+
+ r = GetOverlappedResult( hdir, &ov, &dwCount, TRUE );
+ ok( r == TRUE, "getoverlappedresult failed\n");
+ ok( dwCount == 0x12, "count wrong\n");
+
+ pfni = (PFILE_NOTIFY_INFORMATION) buffer;
+ ok( pfni->NextEntryOffset == 0, "offset wrong\n" );
+ ok( pfni->Action == FILE_ACTION_REMOVED, "action wrong\n" );
+ ok( pfni->FileNameLength == 6, "len wrong\n" );
+ ok( !memcmp(pfni->FileName,&szHoo[1],6), "name wrong\n" );
+
+ /* what happens if the buffer is too small? */
+ r = pReadDirectoryChangesW(hdir,buffer,0x10,FALSE,filter,NULL,&ov,NULL);
+ ok(r==TRUE, "should return true\n");
+
+ r = CreateDirectoryW( subdir, NULL );
+ ok( r == TRUE, "failed to create directory\n");
+
+ r = WaitForSingleObject( ov.hEvent, INFINITE );
+ ok( r == WAIT_OBJECT_0, "should be ready\n" );
+
+ ok( ov.Internal == STATUS_NOTIFY_ENUM_DIR, "ov.Internal wrong\n");
+ ok( ov.InternalHigh == 0, "ov.InternalHigh wrong\n");
+
+ /* test the recursive watch */
+ r = pReadDirectoryChangesW(hdir,buffer,sizeof buffer,FALSE,filter,NULL,&ov,NULL);
+ ok(r==TRUE, "should return true\n");
+
+ r = CreateDirectoryW( subsubdir, NULL );
+ ok( r == TRUE, "failed to create directory\n");
+
+ r = WaitForSingleObject( ov.hEvent, INFINITE );
+ ok( r == WAIT_OBJECT_0, "should be ready\n" );
+
+ ok( ov.Internal == STATUS_SUCCESS, "ov.Internal wrong\n");
+ ok( ov.InternalHigh == 0x18, "ov.InternalHigh wrong\n");
+
+ pfni = (PFILE_NOTIFY_INFORMATION) buffer;
+ ok( pfni->NextEntryOffset == 0, "offset wrong\n" );
+ ok( pfni->Action == FILE_ACTION_ADDED, "action wrong\n" );
+ ok( pfni->FileNameLength == 0x0c, "len wrong\n" );
+ ok( !memcmp(pfni->FileName,&szGa[1],6), "name wrong\n" );
+
+ r = RemoveDirectoryW( subsubdir );
+ ok( r == TRUE, "failed to remove directory\n");
+
+ ov.Internal = 1;
+ ov.InternalHigh = 1;
+ r = pReadDirectoryChangesW(hdir,buffer,sizeof buffer,FALSE,filter,NULL,&ov,NULL);
+ ok(r==TRUE, "should return true\n");
+
+ r = RemoveDirectoryW( subdir );
+ ok( r == TRUE, "failed to remove directory\n");
+
+ r = WaitForSingleObject( ov.hEvent, INFINITE );
+ ok( r == WAIT_OBJECT_0, "should be ready\n" );
+
+ pfni = (PFILE_NOTIFY_INFORMATION) buffer;
+ ok( pfni->NextEntryOffset == 0, "offset wrong\n" );
+ ok( pfni->Action == FILE_ACTION_REMOVED, "action wrong\n" );
+ ok( pfni->FileNameLength == 0x0c, "len wrong\n" );
+ ok( !memcmp(pfni->FileName,&szGa[1],6), "name wrong\n" );
+
+ ok( ov.Internal == STATUS_SUCCESS, "ov.Internal wrong\n");
+ ok( ov.InternalHigh == 0x18, "ov.InternalHigh wrong\n");
+
+ CloseHandle(hdir);
+
+ r = RemoveDirectoryW( path );
+ ok( r == TRUE, "failed to remove directory\n");
+}
+
+/* show the behaviour when a null buffer is passed */
+static void test_readdirectorychanges_null(void)
+{
+ NTSTATUS r;
+ HANDLE hdir;
+ char buffer[0x1000];
+ DWORD fflags, filter = 0;
+ OVERLAPPED ov;
+ WCHAR path[MAX_PATH], subdir[MAX_PATH];
+ static const WCHAR szBoo[] = { '\\','b','o','o',0 };
+ static const WCHAR szHoo[] = { '\\','h','o','o',0 };
+ PFILE_NOTIFY_INFORMATION pfni;
+
+ if (!pReadDirectoryChangesW)
+ return;
+
+ r = GetTempPathW( MAX_PATH, path );
+ ok( r != 0, "temp path failed\n");
+ if (!r)
+ return;
+
+ lstrcatW( path, szBoo );
+ lstrcpyW( subdir, path );
+ lstrcatW( subdir, szHoo );
+
+ RemoveDirectoryW( subdir );
+ RemoveDirectoryW( path );
+
+ r = CreateDirectoryW(path, NULL);
+ ok( r == TRUE, "failed to create directory\n");
+
+ fflags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED;
+ hdir = CreateFileW(path, GENERIC_READ|SYNCHRONIZE|FILE_LIST_DIRECTORY,
+ FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
+ OPEN_EXISTING, fflags, NULL);
+ ok( hdir != INVALID_HANDLE_VALUE, "failed to open directory\n");
+
+ ov.hEvent = CreateEvent( NULL, 1, 0, NULL );
+
+ filter = FILE_NOTIFY_CHANGE_FILE_NAME;
+ filter |= FILE_NOTIFY_CHANGE_DIR_NAME;
+
+ SetLastError(0xd0b00b00);
+ ov.Internal = 0;
+ ov.InternalHigh = 0;
+ memset( buffer, 0, sizeof buffer );
+
+ r = pReadDirectoryChangesW(hdir,NULL,0,FALSE,filter,NULL,&ov,NULL);
+ ok(r==TRUE, "should return true\n");
+
+ r = WaitForSingleObject( ov.hEvent, 0 );
+ ok( r == STATUS_TIMEOUT, "should timeout\n" );
+
+ r = CreateDirectoryW( subdir, NULL );
+ ok( r == TRUE, "failed to create directory\n");
+
+ r = WaitForSingleObject( ov.hEvent, 0 );
+ ok( r == WAIT_OBJECT_0, "event should be ready\n" );
+
+ ok( ov.Internal == STATUS_NOTIFY_ENUM_DIR, "ov.Internal wrong\n");
+ ok( ov.InternalHigh == 0, "ov.InternalHigh wrong\n");
+
+ ov.Internal = 0;
+ ov.InternalHigh = 0;
+ S(U(ov)).Offset = 0;
+ S(U(ov)).OffsetHigh = 0;
+ memset( buffer, 0, sizeof buffer );
+
+ r = pReadDirectoryChangesW(hdir,buffer,sizeof buffer,FALSE,filter,NULL,&ov,NULL);
+ ok(r==TRUE, "should return true\n");
+
+ r = WaitForSingleObject( ov.hEvent, 0 );
+ ok( r == STATUS_TIMEOUT, "should timeout\n" );
+
+ r = RemoveDirectoryW( subdir );
+ ok( r == TRUE, "failed to remove directory\n");
+
+ r = WaitForSingleObject( ov.hEvent, INFINITE );
+ ok( r == WAIT_OBJECT_0, "should be ready\n" );
+
+ ok( ov.Internal == STATUS_NOTIFY_ENUM_DIR, "ov.Internal wrong\n");
+ ok( ov.InternalHigh == 0, "ov.InternalHigh wrong\n");
+
+ pfni = (PFILE_NOTIFY_INFORMATION) buffer;
+ ok( pfni->NextEntryOffset == 0, "offset wrong\n" );
+
+ CloseHandle(hdir);
+
+ r = RemoveDirectoryW( path );
+ ok( r == TRUE, "failed to remove directory\n");
+}
+
+static void test_readdirectorychanges_filedir(void)
+{
+ NTSTATUS r;
+ HANDLE hdir, hfile;
+ char buffer[0x1000];
+ DWORD fflags, filter = 0;
+ OVERLAPPED ov;
+ WCHAR path[MAX_PATH], subdir[MAX_PATH], file[MAX_PATH];
+ static const WCHAR szBoo[] = { '\\','b','o','o',0 };
+ static const WCHAR szHoo[] = { '\\','h','o','o',0 };
+ static const WCHAR szFoo[] = { '\\','f','o','o',0 };
+ PFILE_NOTIFY_INFORMATION pfni;
+
+ r = GetTempPathW( MAX_PATH, path );
+ ok( r != 0, "temp path failed\n");
+ if (!r)
+ return;
+
+ lstrcatW( path, szBoo );
+ lstrcpyW( subdir, path );
+ lstrcatW( subdir, szHoo );
+
+ lstrcpyW( file, path );
+ lstrcatW( file, szFoo );
+
+ DeleteFileW( file );
+ RemoveDirectoryW( subdir );
+ RemoveDirectoryW( path );
+
+ r = CreateDirectoryW(path, NULL);
+ ok( r == TRUE, "failed to create directory\n");
+
+ fflags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED;
+ hdir = CreateFileW(path, GENERIC_READ|SYNCHRONIZE|FILE_LIST_DIRECTORY,
+ FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
+ OPEN_EXISTING, fflags, NULL);
+ ok( hdir != INVALID_HANDLE_VALUE, "failed to open directory\n");
+
+ ov.hEvent = CreateEvent( NULL, 0, 0, NULL );
+
+ filter = FILE_NOTIFY_CHANGE_FILE_NAME;
+
+ r = pReadDirectoryChangesW(hdir,buffer,sizeof buffer,TRUE,filter,NULL,&ov,NULL);
+ ok(r==TRUE, "should return true\n");
+
+ r = WaitForSingleObject( ov.hEvent, 10 );
+ ok( r == WAIT_TIMEOUT, "should timeout\n" );
+
+ r = CreateDirectoryW( subdir, NULL );
+ ok( r == TRUE, "failed to create directory\n");
+
+ hfile = CreateFileW( file, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL );
+ ok( hfile != INVALID_HANDLE_VALUE, "failed to create file\n");
+ ok( CloseHandle(hfile), "failed toc lose file\n");
+
+ r = WaitForSingleObject( ov.hEvent, INFINITE );
+ ok( r == WAIT_OBJECT_0, "event should be ready\n" );
+
+ ok( ov.Internal == STATUS_SUCCESS, "ov.Internal wrong\n");
+ ok( ov.InternalHigh == 0x12, "ov.InternalHigh wrong\n");
+
+ pfni = (PFILE_NOTIFY_INFORMATION) buffer;
+ ok( pfni->NextEntryOffset == 0, "offset wrong\n" );
+ ok( pfni->Action == FILE_ACTION_ADDED, "action wrong\n" );
+ ok( pfni->FileNameLength == 6, "len wrong\n" );
+ ok( !memcmp(pfni->FileName,&szFoo[1],6), "name wrong\n" );
+
+ r = DeleteFileW( file );
+ ok( r == TRUE, "failed to delete file\n");
+
+ r = RemoveDirectoryW( subdir );
+ ok( r == TRUE, "failed to remove directory\n");
+
+ CloseHandle(hdir);
+
+ r = RemoveDirectoryW( path );
+ ok( r == TRUE, "failed to remove directory\n");
+}
+
START_TEST(change)
{
+ HMODULE hkernel32 = GetModuleHandle("kernel32");
+ pReadDirectoryChangesW = (fnReadDirectoryChangesW)
+ GetProcAddress(hkernel32, "ReadDirectoryChangesW");
+
test_FindFirstChangeNotification();
+ test_ffcn();
+ test_readdirectorychanges();
+ test_readdirectorychanges_null();
+ test_readdirectorychanges_filedir();
}
#include "winbase.h"
#include "winnls.h"
+static void test_null_source(void)
+{
+ int len;
+ DWORD GLE;
+
+ SetLastError(0);
+ len = WideCharToMultiByte(CP_ACP, 0, NULL, 0, NULL, 0, NULL, NULL);
+ GLE = GetLastError();
+ ok(!len && GLE == ERROR_INVALID_PARAMETER,
+ "WideCharToMultiByte returned %d with GLE=%ld (expected 0 with ERROR_INVALID_PARAMETER)\n",
+ len, GLE);
+}
+
/* lstrcmpW is not supported on Win9x! */
static int mylstrcmpW(const WCHAR* str1, const WCHAR* str2)
{
START_TEST(codepage)
{
+ test_null_source();
test_negative_source_length();
test_overlapped_buffers();
}
#define LOOPBACK_DTR_DSR FALSE /* Sub-D 9: Short 4-6 */
#define LOOPBACK_DTR_RING FALSE /* Sub-D 9: Short 4-9 */
#define LOOPBACK_DTR_DCD FALSE /* Sub-D 9: Short 4-1 */
-
-/* SETBREAK seems to give instable results, MSDN mentions possible problems
- * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcedebug5/\
- * html/wce50conSerialPortDriverTest.asp
- * but perhaps it's only a programming error, that causes it... */
-#define BROKEN_SETBREAK TRUE
+/* Many Linux serial drivers have the TIOCM_LOOP flag in the TIOCM_SET ioctl
+ * available. For the 8250 this is equivalent to TXD->RXD, OUT2->DCD,
+ * OUT1->RI, RTS->CTS and DTR->DSR
+ */
typedef struct
{
HANDLE hcom = INVALID_HANDLE_VALUE;
char port_name[] = "COMx";
static BOOL shown = FALSE;
+ DWORD errors;
+ COMSTAT comstat;
/* Try to find a port */
for(port_name[3] = '1'; port_name[3] <= '9'; port_name[3]++)
trace("Found Com port %s. Connected devices may disturbe results\n", port_name);
/*shown = TRUE; */
}
+ if (hcom != INVALID_HANDLE_VALUE)
+ {
+ ok(ClearCommError(hcom,&errors,&comstat), "Unexpected errors on open\n");
+ ok(comstat.cbInQue == 0, "Unexpected %ld chars in InQueue\n",comstat.cbInQue);
+ ok(comstat.cbOutQue == 0, "Still pending %ld charcters in OutQueue\n", comstat.cbOutQue);
+ ok(errors == 0, "Unexpected errors 0x%08lx\n", errors);
+ }
return hcom;
}
dcb.BaudRate = FASTBAUD;
dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
+ dcb.fRtsControl=RTS_CONTROL_ENABLE;
+ dcb.fDtrControl=DTR_CONTROL_ENABLE;
dcb.StopBits = ONESTOPBIT;
ok(SetCommState(hcom, &dcb), "SetCommState failed\n");
res = ReadFile(hcom, rbuf, sizeof(rbuf), &read, NULL);
LastError = GetLastError();
after = GetTickCount();
- todo_wine ok( res == TRUE, "A timed-out read should return TRUE\n");
- todo_wine ok( LastError == 0xdeadbeef, "err=%ld\n", LastError);
+ ok( res == TRUE, "A timed-out read should return TRUE\n");
+ ok( LastError == 0xdeadbeef, "err=%ld\n", LastError);
timediff = after - before;
ok( timediff > TIMEOUT>>2 && timediff < TIMEOUT *2,
"Unexpected TimeOut %ld, expected %d\n", timediff, TIMEOUT);
{
DCB dcb;
COMMTIMEOUTS timeouts;
- char tbuf[]="Some Characters\n";
+ char tbuf[]="test_waittxempty";
DWORD before, after, written, timediff, evtmask = 0;
BOOL res_write, res;
DWORD baud = SLOWBAUD;
+ trace("test_waittxempty\n");
/* set a low baud rate to have ample time*/
ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
dcb.BaudRate = baud;
dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
+ dcb.fRtsControl=RTS_CONTROL_ENABLE;
+ dcb.fDtrControl=DTR_CONTROL_ENABLE;
dcb.StopBits = ONESTOPBIT;
ok(SetCommState(hcom, &dcb), "SetCommState failed\n");
res = WaitCommEvent(hcom, &evtmask, NULL);
after = GetTickCount();
- todo_wine ok(res == TRUE, "WaitCommEvent failed\n");
- todo_wine ok(evtmask == EV_TXEMPTY,
+ ok(res == TRUE, "WaitCommEvent failed\n");
+ ok((evtmask & EV_TXEMPTY),
"WaitCommEvent: Unexpected EvtMask 0x%08lx, expected 0x%08x\n",
evtmask, EV_TXEMPTY);
nearly return immediate,
while on wine the most time is spent here
*/
-
}
/* A new open handle should not return error or have bytes in the Queues */
COMSTAT lpStat;
ok(ClearCommError(hcom, &errors, &lpStat), "ClearCommError failed\n");
- ok(lpStat.cbInQue == 0, "Unexpected %ld Bytes in InQueue\n", lpStat.cbInQue);
- ok(lpStat.cbOutQue == 0, "Unexpected %ld Bytes in OutQueue\n", lpStat.cbOutQue);
+ ok(lpStat.cbInQue == 0, "Unexpected %ld chars in InQueue\n", lpStat.cbInQue);
+ ok(lpStat.cbOutQue == 0, "Unexpected %ld chars in OutQueue\n", lpStat.cbOutQue);
ok(errors == 0, "ClearCommErrors: Unexpected error 0x%08lx\n", errors);
+ trace("test_ClearCommErrors done\n");
+}
+
+static void test_non_pending_errors(HANDLE hcom)
+{
+ DCB dcb;
+ DWORD err;
+
+ ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
+ dcb.ByteSize = 255; /* likely bogus */
+ ok(!SetCommState(hcom, &dcb), "SetCommState should have failed\n");
+ ok(ClearCommError(hcom, &err, NULL), "ClearCommError should succeed\n");
+ ok(!(err & CE_MODE), "ClearCommError shouldn't set CE_MODE byte in this case (%lx)\n", err);
}
/**/
DCB dcb;
COMMTIMEOUTS timeouts;
char rbuf[32];
- DWORD before, after, diff, read, written, evtmask=0;
+ DWORD before, after, diff, read, read1, written, evtmask=0, i;
BOOL res;
- char tbuf[]="Some Characters\n";
+ char tbuf[]="test_LoopbackRead";
+ trace("Starting test_LoopbackRead\n");
ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
dcb.BaudRate = FASTBAUD;
dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
+ dcb.fRtsControl=RTS_CONTROL_ENABLE;
+ dcb.fDtrControl=DTR_CONTROL_ENABLE;
dcb.StopBits = ONESTOPBIT;
ok(SetCommState(hcom, &dcb), "SetCommState failed\n");
ok(SetCommMask(hcom, EV_TXEMPTY), "SetCommMask failed\n");
+ before = GetTickCount();
ok(WriteFile(hcom,tbuf,sizeof(tbuf),&written, NULL), "WriteFile failed\n");
+ after = GetTickCount();
ok(written == sizeof(tbuf),"WriteFile %ld bytes written, expected %d\n",
written, sizeof(tbuf));
+ diff = after -before;
/* make sure all bytes are written, so Readfile will succeed in one call*/
- todo_wine ok(WaitCommEvent(hcom, &evtmask, NULL), "WaitCommEvent failed\n");
- todo_wine ok(evtmask == EV_TXEMPTY,
+ ok(WaitCommEvent(hcom, &evtmask, NULL), "WaitCommEvent failed\n");
+ before = GetTickCount();
+ ok(evtmask == EV_TXEMPTY,
"WaitCommEvent: Unexpected EvtMask 0x%08lx, expected 0x%08x\n",
evtmask, EV_TXEMPTY);
+ trace("Write %ld ms WaitCommEvent EV_TXEMPTY %ld ms\n", diff, before- after);
read=0;
- todo_wine ok(ReadFile(hcom, rbuf, sizeof(rbuf), &read, NULL), "Readfile failed\n");
- todo_wine ok(read == sizeof(tbuf),"ReadFile read %ld bytes, expected %d\n", read, sizeof(tbuf));
+ ok(ReadFile(hcom, rbuf, sizeof(rbuf), &read, NULL), "Readfile failed\n");
+ ok(read == sizeof(tbuf),"ReadFile read %ld bytes, expected %d \"%s\"\n", read, sizeof(tbuf),rbuf);
- /* Now do the same withe a slow Baud rate.
- On XP, nothing should change, as WriteFile only returns
- after all Bytes have gone to the physical line
+ /* Now do the same withe a slower Baud rate.
+ As we request more characters then written, we will hit the timeout
*/
ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
dcb.BaudRate = 9600;
dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
+ dcb.fRtsControl=RTS_CONTROL_ENABLE;
+ dcb.fDtrControl=DTR_CONTROL_ENABLE;
dcb.StopBits = ONESTOPBIT;
ok(SetCommState(hcom, &dcb), "SetCommState failed\n");
ok(written == sizeof(tbuf),"WriteFile %ld bytes written, expected %d\n",
written, sizeof(tbuf));
- todo_wine ok(WaitCommEvent(hcom, &evtmask, NULL), "WaitCommEvent failed\n");
- todo_wine ok(evtmask == EV_RXCHAR, "WaitCommEvent: Unexpected EvtMask 0x%08lx, expected 0x%08x\n",
+ trace("WaitCommEventEV_RXCHAR\n");
+ ok(WaitCommEvent(hcom, &evtmask, NULL), "WaitCommEvent failed\n");
+ ok(evtmask == EV_RXCHAR, "WaitCommEvent: Unexpected EvtMask 0x%08lx, expected 0x%08x\n",
evtmask, EV_RXCHAR);
before = GetTickCount();
res = ReadFile(hcom, rbuf, sizeof(rbuf), &read, NULL);
after = GetTickCount();
- todo_wine ok(res, "Readfile failed\n");
- todo_wine ok(read == sizeof(tbuf),"ReadFile read %ld bytes, expected %d\n", read, sizeof(tbuf));
+ ok(res, "Readfile failed\n");
+ ok(read == sizeof(tbuf),"ReadFile read %ld bytes, expected %d\n", read, sizeof(tbuf));
diff = after - before;
trace("Readfile for %d chars with %d avail took %ld ms\n",
sizeof(rbuf), sizeof(tbuf), diff);
ok( (diff > TIMEOUT - TIMEDELTA) && (diff < TIMEOUT + TIMEDELTA),
"Timedout Wait took %ld ms, expected around %d\n", diff, TIMEOUT);
+
+ /* now do a plain read with slow speed
+ * This will result in several low level reads and a timeout to happen
+ */
+ dcb.BaudRate = SLOWBAUD;
+ ok(SetCommState(hcom, &dcb), "SetCommState failed\n");
+ ok(WriteFile(hcom,tbuf,sizeof(tbuf),&written, NULL), "WriteFile failed\n");
+ before = GetTickCount();
+ read = 0;
+ read1 =0;
+ i=0;
+ do
+ {
+ res = ReadFile(hcom, rbuf+read, sizeof(rbuf-read), &read1, NULL);
+ ok(res, "Readfile failed\n");
+ read += read1;
+ i++;
+ }
+ while ((read < sizeof(tbuf)) && (i <10));
+ after = GetTickCount();
+ ok( read == sizeof(tbuf),"ReadFile read %ld bytes, expected %d\n", read, sizeof(tbuf));
+ trace("Plain Read for %d char at %d baud took %ld ms\n", sizeof(tbuf), SLOWBAUD, after-before);
+
}
static void test_LoopbackCtsRts(HANDLE hcom)
{
ok(EscapeCommFunction(hcom, SETRTS), "EscapeCommFunction failed to set RTS\n");
ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
- todo_wine ok ((ModemStat & MS_CTS_ON) == MS_CTS_ON,
+ ok ((ModemStat & MS_CTS_ON) == MS_CTS_ON,
"CTS didn't react: 0x%04lx, expected 0x%04lx\n",
ModemStat, (defaultStat | MS_CTS_ON));
ok(EscapeCommFunction(hcom, CLRRTS), "EscapeCommFunction failed to clear RTS\n");
{
ok(EscapeCommFunction(hcom, SETDTR), "EscapeCommFunction failed to set DTR\n");
ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
- todo_wine ok ((ModemStat & MS_RLSD_ON) == MS_RLSD_ON,
+ ok ((ModemStat & MS_RLSD_ON) == MS_RLSD_ON,
"RLSD didn't react: 0x%04lx, expected 0x%04lx\n",
ModemStat, (defaultStat | MS_RLSD_ON));
ok(EscapeCommFunction(hcom, CLRDTR), "EscapeCommFunction failed to clear DTR\n");
ModemStat, (defaultStat & ~MS_DSR_ON));
ok(EscapeCommFunction(hcom, SETDTR), "EscapeCommFunction failed to clear DTR\n");
ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
- todo_wine ok (ModemStat == defaultStat, "Failed to restore DSR: 0x%04lx, expected 0x%04lx\n",
+ ok (ModemStat == defaultStat, "Failed to restore DSR: 0x%04lx, expected 0x%04lx\n",
ModemStat, defaultStat);
}
else
{
ok(EscapeCommFunction(hcom, SETDTR), "EscapeCommFunction failed to set DTR\n");
ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
- todo_wine ok ((ModemStat & MS_DSR_ON) == MS_DSR_ON,
+ ok ((ModemStat & MS_DSR_ON) == MS_DSR_ON,
"CTS didn't react: 0x%04lx,expected 0x%04lx\n",
ModemStat, (defaultStat | MS_DSR_ON));
ok(EscapeCommFunction(hcom, CLRDTR), "EscapeCommFunction failed to clear DTR\n");
{
ok(EscapeCommFunction(hcom, SETDTR), "EscapeCommFunction failed to set DTR\n");
ok(GetCommModemStatus(hcom, &ModemStat), "GetCommModemStatus failed\n");
- todo_wine ok ((ModemStat & MS_RING_ON) == MS_RING_ON,
+ ok ((ModemStat & MS_RING_ON) == MS_RING_ON,
"RING didn't react: 0x%04lx,expected 0x%04lx\n",
ModemStat, (defaultStat | MS_RING_ON));
ok(EscapeCommFunction(hcom, CLRDTR), "EscapeCommFunction failed to clear DTR\n");
}
/*
- Set up a WaitCommEvent for anything in the receive buffer,
- then write to TX to put a character
- into the RX buffer via the Loopback
+ * Set up a WaitCommEvent for anything in the receive buffer,
+ * then write to TX to put a character
+ * into the RX buffer
+ * Need Loopback TX->RX
*/
static void test_WaitRx(HANDLE hcom)
overlapped_w.hEvent = hComWriteEvent;
before = GetTickCount();
- todo_wine {success_wait = WaitCommEvent(hcom, &evtmask, &overlapped);}
+ {success_wait = WaitCommEvent(hcom, &evtmask, &overlapped);}
err_wait = GetLastError();
after = GetTickCount();
trace("Success 0x%08lx err 0x%08lx evtmask 0x%08lx\n", success_wait, err_wait, evtmask);
- todo_wine ok(success_wait || err_wait == ERROR_IO_PENDING, "overlapped WaitCommEvent failed\n");
+ ok(success_wait || err_wait == ERROR_IO_PENDING, "overlapped WaitCommEvent failed\n");
trace("overlapped WriteCommEvent returned.\n");
success_write= WriteFile(hcom, "X", 1, &written, &overlapped_w);
trace("Success 0x%08lx err 0x%08lx evtmask 0x%08lx diff1 %ld, diff2 %ld\n",
success_wait, err_wait, evtmask, after-before, after1-before);
- todo_wine ok(evtmask & EV_RXCHAR, "Detect EV_RXCHAR: 0x%08lx, expected 0x%08x\n",
+ ok(evtmask & EV_RXCHAR, "Detect EV_RXCHAR: 0x%08lx, expected 0x%08x\n",
evtmask, EV_RXCHAR);
diff = after1 - before;
ok ((diff > (TIMEOUT>>1) -TIMEDELTA) && (diff < (TIMEOUT>>1) + TIMEDELTA),
return 0;
}
+/*
+ * Wait for a change in CTS
+ * Needs Loopback from DTR to CTS
+ */
static void test_WaitCts(HANDLE hcom)
{
DCB dcb;
DWORD alarmThreadId, before, after, after1, diff, success, err, written, evtmask=0;
ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
+ dcb.fRtsControl=RTS_CONTROL_ENABLE;
+ dcb.fDtrControl=DTR_CONTROL_ENABLE;
+ ok(SetCommState(hcom, &dcb), "SetCommState failed\n");
if (dcb.fDtrControl == RTS_CONTROL_DISABLE)
{
trace("RTS_CONTROL_HANDSHAKE is set, so don't manipulate DTR\n");
ok(hComPortEvent != 0, "CreateEvent failed\n");
args[3] = (DWORD) hComPortEvent;
alarmThread = CreateThread(NULL, 0, toggle_ctlLine, (void *) &args, 0, &alarmThreadId);
- Sleep(100);
+ /* Wait a minimum to let the thread start up */
+ Sleep(10);
trace("Thread created\n");
ok(alarmThread !=0 , "CreateThread Failed\n");
after = GetTickCount();
trace("Success 0x%08lx err 0x%08lx evtmask 0x%08lx\n", success, err, evtmask);
- todo_wine ok(success || err == ERROR_IO_PENDING, "overlapped WaitCommEvent failed\n");
+ ok(success || err == ERROR_IO_PENDING, "overlapped WaitCommEvent failed\n");
trace("overlapped WriteCommEvent returned.\n");
if (!success && (err == ERROR_IO_PENDING))
- todo_wine ok(WaitForSingleObjectEx(hComPortEvent, TIMEOUT, TRUE) == 0,
- "wait hComPortEvent failed\n");
+ ok(WaitForSingleObjectEx(hComPortEvent, TIMEOUT, TRUE) == 0,
+ "WaitCts hComPortEvent failed\n");
success = GetOverlappedResult(hcom, &overlapped, &written, FALSE);
err = GetLastError();
after1 = GetTickCount();
trace("Success 0x%08lx err 0x%08lx evtmask 0x%08lx diff1 %ld, diff2 %ld\n",
success, err, evtmask, after-before, after1-before);
- todo_wine ok(evtmask & EV_CTS, "Failed to detect EV_CTS: 0x%08lx, expected 0x%08x\n",
+ ok(evtmask & EV_CTS, "Failed to detect EV_CTS: 0x%08lx, expected 0x%08x\n",
evtmask, EV_CTS);
ok(GetCommModemStatus(hcom, &evtmask), "GetCommModemStatus failed\n");
if(defaultStat & MS_CTS_ON)
- todo_wine ok((evtmask & MS_CTS_ON) == 0,"CTS didn't change state!\n");
+ ok((evtmask & MS_CTS_ON) == 0,"CTS didn't change state!\n");
else
- todo_wine ok((evtmask & MS_CTS_ON), "CTS didn't change state!\n");
+ ok((evtmask & MS_CTS_ON), "CTS didn't change state!\n");
diff = after1 - before;
- todo_wine ok ((diff > (TIMEOUT>>1) -TIMEDELTA) && (diff < (TIMEOUT>>1) + TIMEDELTA),
+ ok ((diff > (TIMEOUT>>1) -TIMEDELTA) && (diff < (TIMEOUT>>1) + TIMEDELTA),
"Unexpected time %ld, expected around %d\n", diff, TIMEOUT>>1);
/*restore RTS Settings*/
args[1] = CLRRTS;
}
+/* Change the Comm Mask while a Wait is going on
+ WaitCommevent should return with a EVTMASK set to zero
+*/
+static DWORD CALLBACK reset_CommMask(LPVOID arg)
+{
+ DWORD *args = (DWORD *) arg;
+ DWORD timeout = args[0];
+ HANDLE hcom = (HANDLE) args[1];
+
+ trace(" Changing CommMask on the fly for handle %p after timeout %ld\n",
+ hcom, timeout);
+ Sleep(timeout);
+ ok(SetCommMask(hcom, 0),"SetCommMask %p failed\n", hcom);
+ trace("SetCommMask changed\n");
+ return 0;
+}
+
+/* Set up a Wait for a change on CTS. We don't toggle any line, but we
+ reset the CommMask and expect the wait to return with a mask of 0
+ No special port connections needed
+*/
+static void test_AbortWaitCts(HANDLE hcom)
+{
+ DCB dcb;
+ OVERLAPPED overlapped;
+ HANDLE hComPortEvent;
+ HANDLE alarmThread;
+ DWORD args[2];
+ DWORD alarmThreadId, before, after, after1, diff, success, err, written, evtmask=0;
+
+ ok(GetCommState(hcom, &dcb), "GetCommState failed\n");
+ if (dcb.fDtrControl == RTS_CONTROL_DISABLE)
+ {
+ trace("RTS_CONTROL_HANDSHAKE is set, so don't manipulate DTR\n");
+ return;
+ }
+ args[0]= TIMEOUT >>1;
+ args[1]=(DWORD) hcom;
+
+ trace("test_AbortWaitCts timeout %ld handle 0x%08lx\n",args[0], args[1]);
+
+ ok(SetCommMask(hcom, EV_CTS), "SetCommMask failed\n");
+ hComPortEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
+ ok(hComPortEvent != 0, "CreateEvent failed\n");
+ alarmThread = CreateThread(NULL, 0, reset_CommMask, (void *) &args, 0, &alarmThreadId);
+ /* Wait a minimum to let the thread start up */
+ Sleep(10);
+ trace("Thread created\n");
+ ok(alarmThread !=0 , "CreateThread Failed\n");
+
+ ZeroMemory( &overlapped, sizeof(overlapped));
+ overlapped.hEvent = hComPortEvent;
+ before = GetTickCount();
+ success = WaitCommEvent(hcom, &evtmask, &overlapped);
+ err = GetLastError();
+ after = GetTickCount();
+
+ trace("Success 0x%08lx err 0x%08lx evtmask 0x%08lx\n", success, err, evtmask);
+ ok(success || err == ERROR_IO_PENDING, "overlapped WaitCommEvent failed\n");
+ trace("overlapped WriteCommEvent returned.\n");
+ if (!success && (err == ERROR_IO_PENDING))
+ ok(WaitForSingleObjectEx(hComPortEvent, TIMEOUT, TRUE) == 0,
+ "AbortWaitCts hComPortEvent failed\n");
+ success = GetOverlappedResult(hcom, &overlapped, &written, FALSE);
+ err = GetLastError();
+ after1 = GetTickCount();
+ trace("Success 0x%08lx err 0x%08lx evtmask 0x%08lx diff1 %ld, diff2 %ld\n",
+ success, err, evtmask, after-before, after1-before);
+
+ ok(evtmask == 0, "Incorect EventMask 0x%08lx returned on Wait aborted bu SetCommMask, expected 0x%08x\n",
+ evtmask, 0);
+ ok(GetCommModemStatus(hcom, &evtmask), "GetCommModemStatus failed\n");
+ diff = after1 - before;
+ ok ((diff > (TIMEOUT>>1) -TIMEDELTA) && (diff < (TIMEOUT>>1) + TIMEDELTA),
+ "Unexpected time %ld, expected around %d\n", diff, TIMEOUT>>1);
+
+}
+
+/*
+ * Wait for a change in DSR
+ * Needs Loopback from DTR to DSR
+ */
static void test_WaitDsr(HANDLE hcom)
{
DCB dcb;
after = GetTickCount();
trace("Success 0x%08lx err 0x%08lx evtmask 0x%08lx\n", success, err, evtmask);
- todo_wine ok(success || err == ERROR_IO_PENDING, "overlapped WaitCommEvent failed\n");
+ ok(success || err == ERROR_IO_PENDING, "overlapped WaitCommEvent failed\n");
trace("overlapped WriteCommEvent returned.\n");
if (!success && (err == ERROR_IO_PENDING))
- todo_wine ok(WaitForSingleObjectEx(hComPortEvent, TIMEOUT, TRUE) == 0,
+ ok(WaitForSingleObjectEx(hComPortEvent, TIMEOUT, TRUE) == 0,
"wait hComPortEvent failed\n");
success = GetOverlappedResult(hcom, &overlapped, &written, FALSE);
err = GetLastError();
trace("Success 0x%08lx err 0x%08lx evtmask 0x%08lx diff1 %ld, diff2 %ld\n",
success, err, evtmask, after-before, after1-before);
- todo_wine ok(evtmask & EV_DSR, "Failed to detect EV_DSR: 0x%08lx, expected 0x%08x\n",
- evtmask, EV_CTS);
+ ok(evtmask & EV_DSR, "Failed to detect EV_DSR: 0x%08lx, expected 0x%08x\n",
+ evtmask, EV_DSR);
ok(GetCommModemStatus(hcom, &evtmask), "GetCommModemStatus failed\n");
if(defaultStat & MS_DSR_ON)
- todo_wine ok((evtmask & MS_DSR_ON) == 0,"DTR didn't change state!\n");
+ ok((evtmask & MS_DSR_ON) == 0,"DTR didn't change state!\n");
else
- todo_wine ok((evtmask & MS_DSR_ON), "DTR didn't change state!\n");
+ ok((evtmask & MS_DSR_ON), "DTR didn't change state!\n");
diff = after1 - before;
- todo_wine ok ((diff > (TIMEOUT>>1) -TIMEDELTA) && (diff < (TIMEOUT>>1) + TIMEDELTA),
+ ok ((diff > (TIMEOUT>>1) -TIMEDELTA) && (diff < (TIMEOUT>>1) + TIMEDELTA),
"Unexpected time %ld, expected around %d\n", diff, TIMEOUT>>1);
/*restore RTS Settings*/
args[1] = CLRDTR;
}
+/*
+ * Wait for a Ring
+ * Needs Loopback from DTR to RING
+ */
static void test_WaitRing(HANDLE hcom)
{
DCB dcb;
after = GetTickCount();
trace("Success 0x%08lx err 0x%08lx evtmask 0x%08lx\n", success, err, evtmask);
- todo_wine ok(success || err == ERROR_IO_PENDING, "overlapped WaitCommEvent failed\n");
+ ok(success || err == ERROR_IO_PENDING, "overlapped WaitCommEvent failed\n");
trace("overlapped WriteCommEvent returned.\n");
if (!success && (err == ERROR_IO_PENDING))
- todo_wine ok(WaitForSingleObjectEx(hComPortEvent, TIMEOUT, TRUE) == 0,
+ ok(WaitForSingleObjectEx(hComPortEvent, TIMEOUT, TRUE) == 0,
"wait hComPortEvent failed\n");
success = GetOverlappedResult(hcom, &overlapped, &written, FALSE);
err = GetLastError();
trace("Success 0x%08lx err 0x%08lx evtmask 0x%08lx diff1 %ld, diff2 %ld\n",
success, err, evtmask, after-before, after1-before);
- todo_wine ok(evtmask & EV_RING, "Failed to detect EV_RING: 0x%08lx, expected 0x%08x\n",
+ ok(evtmask & EV_RING, "Failed to detect EV_RING: 0x%08lx, expected 0x%08x\n",
evtmask, EV_CTS);
ok(GetCommModemStatus(hcom, &evtmask), "GetCommModemStatus failed\n");
if(defaultStat & MS_RING_ON)
- todo_wine ok((evtmask & MS_RING_ON) == 0,"DTR didn't change state!\n");
+ ok((evtmask & MS_RING_ON) == 0,"DTR didn't change state!\n");
else
- todo_wine ok((evtmask & MS_RING_ON), "DTR didn't change state!\n");
+ ok((evtmask & MS_RING_ON), "DTR didn't change state!\n");
diff = after1 - before;
- todo_wine ok ((diff > (TIMEOUT>>1) -TIMEDELTA) && (diff < (TIMEOUT>>1) + TIMEDELTA),
+ ok ((diff > (TIMEOUT>>1) -TIMEDELTA) && (diff < (TIMEOUT>>1) + TIMEDELTA),
"Unexpected time %ld, expected around %d\n", diff, TIMEOUT>>1);
/*restore RTS Settings*/
else
args[1] = CLRDTR;
}
-
+/*
+ * Wait for a change in DCD
+ * Needs Loopback from DTR to DCD
+ */
static void test_WaitDcd(HANDLE hcom)
{
DCB dcb;
after = GetTickCount();
trace("Success 0x%08lx err 0x%08lx evtmask 0x%08lx\n", success, err, evtmask);
- todo_wine ok(success || err == ERROR_IO_PENDING, "overlapped WaitCommEvent failed\n");
+ ok(success || err == ERROR_IO_PENDING, "overlapped WaitCommEvent failed\n");
trace("overlapped WriteCommEvent returned.\n");
if (!success && (err == ERROR_IO_PENDING))
- todo_wine ok(WaitForSingleObjectEx(hComPortEvent, TIMEOUT, TRUE) == 0,
+ ok(WaitForSingleObjectEx(hComPortEvent, TIMEOUT, TRUE) == 0,
"wait hComPortEvent failed\n");
success = GetOverlappedResult(hcom, &overlapped, &written, FALSE);
err = GetLastError();
trace("Success 0x%08lx err 0x%08lx evtmask 0x%08lx diff1 %ld, diff2 %ld\n",
success, err, evtmask, after-before, after1-before);
- todo_wine ok(evtmask & EV_RLSD, "Failed to detect EV_RLSD: 0x%08lx, expected 0x%08x\n",
+ ok(evtmask & EV_RLSD, "Failed to detect EV_RLSD: 0x%08lx, expected 0x%08x\n",
evtmask, EV_CTS);
ok(GetCommModemStatus(hcom, &evtmask), "GetCommModemStatus failed\n");
if(defaultStat & MS_RLSD_ON)
- todo_wine ok((evtmask & MS_RLSD_ON) == 0,"DTR didn't change state!\n");
+ ok((evtmask & MS_RLSD_ON) == 0,"DTR didn't change state!\n");
else
- todo_wine ok((evtmask & MS_RLSD_ON), "DTR didn't change state!\n");
+ ok((evtmask & MS_RLSD_ON), "DTR didn't change state!\n");
diff = after1 - before;
- todo_wine ok ((diff > (TIMEOUT>>1) -TIMEDELTA) && (diff < (TIMEOUT>>1) + TIMEDELTA),
+ ok ((diff > (TIMEOUT>>1) -TIMEDELTA) && (diff < (TIMEOUT>>1) + TIMEDELTA),
"Unexpected time %ld, expected around %d\n", diff, TIMEOUT>>1);
/*restore RTS Settings*/
args[1] = CLRDTR;
}
+/*
+ Set Break after timeout
+*/
+static DWORD CALLBACK set_CommBreak(LPVOID arg)
+{
+ DWORD *args = (DWORD *) arg;
+ DWORD timeout = args[0];
+ HANDLE hcom = (HANDLE) args[1];
+
+ trace("SetCommBreak for handle %p after timeout %ld\n",
+ hcom, timeout);
+ Sleep(timeout);
+ ok(SetCommBreak(hcom),"SetCommBreak %p failed\n", hcom);
+ trace("SetCommBreak done\n");
+ return 0;
+}
+
/*
- Set the Break status after the given timeout to the given state
+ Wait for the Break condition (TX resp. RX active)
+ Needs Loopback TX-RX
*/
static void test_WaitBreak(HANDLE hcom)
{
OVERLAPPED overlapped;
HANDLE hComPortEvent;
- DWORD before, after, after1, diff, success, err, written, evtmask=0;
+ HANDLE alarmThread;
+ DWORD args[2];
+ DWORD alarmThreadId, before, after, after1, diff, success, err, written, evtmask=0;
ok(SetCommMask(hcom, EV_BREAK), "SetCommMask failed\n");
hComPortEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
ok(hComPortEvent != 0, "CreateEvent failed\n");
+ trace("test_WaitBreak\n");
+ args[0]= TIMEOUT >>1;
+ args[1]=(DWORD) hcom;
+ alarmThread = CreateThread(NULL, 0, set_CommBreak, (void *) &args, 0, &alarmThreadId);
+ /* Wait a minimum to let the thread start up */
+ Sleep(10);
+ trace("Thread created\n");
+ ok(alarmThread !=0 , "CreateThread Failed\n");
+
ZeroMemory( &overlapped, sizeof(overlapped));
overlapped.hEvent = hComPortEvent;
before = GetTickCount();
ok(success || err == ERROR_IO_PENDING, "overlapped WaitCommEvent failed\n");
trace("overlapped WriteCommEvent returned.\n");
- Sleep(TIMEOUT >>1);
-
- ok(SetCommBreak(hcom), "SetCommBreak err 0x%08lx\n", GetLastError());
- trace("Break set\n");
- ok(ClearCommError(hcom, &err, NULL),"ClearCommError err 0x%08lx\n", GetLastError());
- ok((err & CE_BREAK)!= 0, "Break condition should be reported\n");
- ok(ClearCommBreak(hcom), "ClearCommBreak err 0x%08lx\n", GetLastError());
- trace("Break cleared\n");
- ok(ClearCommError(hcom, &err, NULL),"ClearCommError err 0x%08lx\n", GetLastError());
- ok((err & CE_BREAK)== 0, "Break should be cleared now\n");
-
if (!success && (err == ERROR_IO_PENDING))
ok(WaitForSingleObjectEx(hComPortEvent, TIMEOUT, TRUE) == 0,
"wait hComPortEvent res 0x%08lx\n", GetLastError());
ok ((diff > (TIMEOUT>>1) -TIMEDELTA) && (diff < (TIMEOUT>>1) + TIMEDELTA),
"Unexpected time %ld, expected around %d\n", diff, TIMEOUT>>1);
+ ok(ClearCommBreak(hcom), "ClearCommBreak failed\n");
}
START_TEST(comm)
{
HANDLE hcom;
- /* use variabel and not #define to compile the code */
+ /* use variables and not #define to compile the code */
BOOL loopback_txd_rxd = LOOPBACK_TXD_RXD;
BOOL loopback_rts_cts = LOOPBACK_CTS_RTS;
BOOL loopback_dtr_dsr = LOOPBACK_DTR_DSR;
BOOL loopback_dtr_ring = LOOPBACK_DTR_RING;
BOOL loopback_dtr_dcd = LOOPBACK_DTR_DCD;
- BOOL broken_setbreak = BROKEN_SETBREAK;
-#if 1
test_BuildCommDCB();
hcom = test_OpenComm(FALSE);
if (hcom != INVALID_HANDLE_VALUE)
hcom = test_OpenComm(FALSE);
if (hcom != INVALID_HANDLE_VALUE)
{
+ Sleep(200); /* Give the laster character of test_waittxempty to drop into the receiver */
test_ClearCommErrors(hcom);
CloseHandle(hcom);
}
+ hcom = test_OpenComm(FALSE);
+ if (hcom != INVALID_HANDLE_VALUE)
+ {
+ test_non_pending_errors(hcom);
+ CloseHandle(hcom);
+ }
if((loopback_txd_rxd) && ((hcom = test_OpenComm(FALSE))!=INVALID_HANDLE_VALUE))
{
test_LoopbackRead(hcom);
test_LoopbackDtrDcd(hcom);
CloseHandle(hcom);
}
-#endif
if((loopback_txd_rxd) && ((hcom = test_OpenComm(TRUE))!=INVALID_HANDLE_VALUE))
{
test_WaitRx(hcom);
CloseHandle(hcom);
}
-#if 1
if((loopback_rts_cts) && ((hcom = test_OpenComm(TRUE))!=INVALID_HANDLE_VALUE))
{
test_WaitCts(hcom);
CloseHandle(hcom);
}
+ if((hcom = test_OpenComm(TRUE))!=INVALID_HANDLE_VALUE)
+ {
+ test_AbortWaitCts(hcom);
+ CloseHandle(hcom);
+ }
if((loopback_dtr_dsr) && ((hcom = test_OpenComm(TRUE))!=INVALID_HANDLE_VALUE))
{
test_WaitDsr(hcom);
test_WaitDcd(hcom);
CloseHandle(hcom);
}
- if(!broken_setbreak && (hcom = test_OpenComm(TRUE))!=INVALID_HANDLE_VALUE)
+ if(loopback_txd_rxd && (hcom = test_OpenComm(TRUE))!=INVALID_HANDLE_VALUE)
{
test_WaitBreak(hcom);
CloseHandle(hcom);
}
-#endif
}
#endif
ok(WaitForSingleObject(mch_event, 3000) == WAIT_OBJECT_0, "event sending didn't work\n");
CloseHandle(mch_event);
+
+ /* Turning off ctrl-c handling doesn't work on win9x such way ... */
ok(SetConsoleCtrlHandler(NULL, TRUE), "Couldn't turn off ctrl-c handling\n");
mch_event = CreateEventA(NULL, TRUE, FALSE, NULL);
mch_count = 0;
- ok(GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0), "Couldn't send ctrl-c event\n");
+ if(!(GetVersion() & 0x80000000))
+ /* ... and next line leads to an unhandled exception on 9x. Avoid it on 9x. */
+ ok(GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0), "Couldn't send ctrl-c event\n");
ok(WaitForSingleObject(mch_event, 3000) == WAIT_TIMEOUT && mch_count == 0, "Event shouldn't have been sent\n");
CloseHandle(mch_event);
ok(SetConsoleCtrlHandler(mch, FALSE), "Couldn't remove handler\n");
/* first, we detach and open a fresh console to play with */
FreeConsole();
- AllocConsole();
+ ok(AllocConsole(), "Couldn't alloc console\n");
hConIn = CreateFileA("CONIN$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
hConOut = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
/* will test line scrolling at the bottom of the screen */
/* testBottomScroll(); */
/* will test all the scrolling operations */
- /* this one is disabled for now, Wine's result are way too bad */
testScroll(hConOut, sbi.dwSize);
/* will test sb creation / modification... */
/* testScreenBuffer() */
#include "winbase.h"
#include "winerror.h"
+static DWORD (WINAPI *pGetDiskFreeSpaceExA)(LPCSTR, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER);
+
static void test_GetDriveTypeA(void)
{
char drive[] = "?:\\";
"GetDiskFreeSpaceA(%s): ret=%d GetLastError=%ld\n",
drive, ret, GetLastError());
else
+ {
ok(ret ||
(!ret && (GetLastError() == ERROR_NOT_READY || GetLastError() == ERROR_INVALID_DRIVE)),
"GetDiskFreeSpaceA(%s): ret=%d GetLastError=%ld\n",
drive, ret, GetLastError());
+ if( GetVersion() & 0x80000000)
+ /* win3.0 thru winME */
+ ok( total_clusters <= 65535,
+ "total clusters is %ld > 65535\n", total_clusters);
+ else if (pGetDiskFreeSpaceExA) {
+ /* NT, 2k, XP : GetDiskFreeSpace shoud be accurate */
+ ULARGE_INTEGER totEx, tot, d;
+
+ tot.QuadPart = sectors_per_cluster;
+ tot.QuadPart = (tot.QuadPart * bytes_per_sector) * total_clusters;
+ ret = pGetDiskFreeSpaceExA( drive, &d, &totEx, NULL);
+ ok( ret || (!ret && ERROR_NOT_READY == GetLastError()),
+ "GetDiskFreeSpaceExA( %s ) failed. GetLastError=%ld\n", drive, GetLastError());
+ ok( bytes_per_sector == 0 || /* empty cd rom drive */
+ totEx.QuadPart <= tot.QuadPart,
+ "GetDiskFreeSpaceA should report at least as much bytes on disk %s as GetDiskFreeSpaceExA\n", drive);
+ }
+ }
}
logical_drives >>= 1;
}
START_TEST(drive)
{
+ HANDLE hkernel32 = GetModuleHandleA("kernel32");
+ pGetDiskFreeSpaceExA = (void *) GetProcAddress(hkernel32, "GetDiskFreeSpaceExA");
+
test_GetDriveTypeA();
test_GetDriveTypeW();
ok(done == sizeof(buf), "expected number of bytes written %lu\n", done);
memset(&ov, 0, sizeof(ov));
- ov.Offset = PATTERN_OFFSET;
- ov.OffsetHigh = 0;
+ S(U(ov)).Offset = PATTERN_OFFSET;
+ S(U(ov)).OffsetHigh = 0;
rc=WriteFile(hFile, pattern, sizeof(pattern), &done, &ov);
/* Win 9x does not support the overlapped I/O on files */
if (rc || GetLastError()!=ERROR_INVALID_PARAMETER) {
ok(SetFilePointer(hFile, 0, NULL, FILE_CURRENT) == (PATTERN_OFFSET + sizeof(pattern)),
"expected file offset %d\n", PATTERN_OFFSET + sizeof(pattern));
- ov.Offset = sizeof(buf) * 2;
- ov.OffsetHigh = 0;
+ S(U(ov)).Offset = sizeof(buf) * 2;
+ S(U(ov)).OffsetHigh = 0;
ret = WriteFile(hFile, pattern, sizeof(pattern), &done, &ov);
ok( ret, "WriteFile error %ld\n", GetLastError());
ok(done == sizeof(pattern), "expected number of bytes written %lu\n", done);
memset(buf, 0, sizeof(buf));
memset(&ov, 0, sizeof(ov));
- ov.Offset = PATTERN_OFFSET;
- ov.OffsetHigh = 0;
+ S(U(ov)).Offset = PATTERN_OFFSET;
+ S(U(ov)).OffsetHigh = 0;
rc=ReadFile(hFile, buf, sizeof(pattern), &done, &ov);
/* Win 9x does not support the overlapped I/O on files */
if (rc || GetLastError()!=ERROR_INVALID_PARAMETER) {
ok( !UnlockFile( handle, 10, 0, 20, 0 ), "UnlockFile 10,20 again succeeded\n" );
ok( UnlockFile( handle, 5, 0, 5, 0 ), "UnlockFile 5,5 failed\n" );
- overlapped.Offset = 100;
- overlapped.OffsetHigh = 0;
+ S(U(overlapped)).Offset = 100;
+ S(U(overlapped)).OffsetHigh = 0;
overlapped.hEvent = 0;
lockfileex_capable = dll_capable("kernel32", "LockFileEx");
}
/* overlapping shared locks are OK */
- overlapped.Offset = 150;
+ S(U(overlapped)).Offset = 150;
limited_UnLockFile || ok( LockFileEx( handle, 0, 0, 100, 0, &overlapped ), "LockFileEx 150,100 failed\n" );
/* but exclusive is not */
{
if (!UnlockFileEx( handle, 0, 100, 0, &overlapped ))
{ /* UnLockFile is capable. */
- overlapped.Offset = 100;
+ S(U(overlapped)).Offset = 100;
ok( !UnlockFileEx( handle, 0, 100, 0, &overlapped ),
"UnlockFileEx 150,100 again succeeded\n" );
}
if (!access1 || !access2) return 1;
if ((access1 & GENERIC_READ) && !(sharing2 & FILE_SHARE_READ)) return 0;
if ((access1 & GENERIC_WRITE) && !(sharing2 & FILE_SHARE_WRITE)) return 0;
+ if ((access1 & DELETE) && !(sharing2 & FILE_SHARE_DELETE)) return 0;
if ((access2 & GENERIC_READ) && !(sharing1 & FILE_SHARE_READ)) return 0;
if ((access2 & GENERIC_WRITE) && !(sharing1 & FILE_SHARE_WRITE)) return 0;
+ if ((access2 & DELETE) && !(sharing1 & FILE_SHARE_DELETE)) return 0;
return 1;
}
static void test_file_sharing(void)
{
- static const DWORD access_modes[4] = { 0, GENERIC_READ, GENERIC_WRITE, GENERIC_READ|GENERIC_WRITE };
- static const DWORD sharing_modes[4] = { 0, FILE_SHARE_READ, FILE_SHARE_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE };
+ static const DWORD access_modes[] =
+ { 0, GENERIC_READ, GENERIC_WRITE, GENERIC_READ|GENERIC_WRITE,
+ DELETE, GENERIC_READ|DELETE, GENERIC_WRITE|DELETE, GENERIC_READ|GENERIC_WRITE|DELETE };
+ static const DWORD sharing_modes[] =
+ { 0, FILE_SHARE_READ,
+ FILE_SHARE_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
+ FILE_SHARE_DELETE, FILE_SHARE_READ|FILE_SHARE_DELETE,
+ FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE };
int a1, s1, a2, s2;
int ret;
HANDLE h, h2;
}
CloseHandle( h );
- for (a1 = 0; a1 < 4; a1++)
+ for (a1 = 0; a1 < sizeof(access_modes)/sizeof(access_modes[0]); a1++)
{
- for (s1 = 0; s1 < 4; s1++)
+ for (s1 = 0; s1 < sizeof(sharing_modes)/sizeof(sharing_modes[0]); s1++)
{
h = CreateFileA( filename, access_modes[a1], sharing_modes[s1],
NULL, OPEN_EXISTING, 0, 0 );
ok(0,"couldn't create file \"%s\" (err=%ld)\n",filename,GetLastError());
return;
}
- for (a2 = 0; a2 < 4; a2++)
+ for (a2 = 0; a2 < sizeof(access_modes)/sizeof(access_modes[0]); a2++)
{
- for (s2 = 0; s2 < 4; s2++)
+ for (s2 = 0; s2 < sizeof(sharing_modes)/sizeof(sharing_modes[0]); s2++)
{
SetLastError(0xdeadbeef);
h2 = CreateFileA( filename, access_modes[a2], sharing_modes[s2],
HANDLE hFile;
LPVOID lpBuffer = HeapAlloc(GetProcessHeap(), 0, 4096);
OVERLAPPED ovl;
- ovl.Offset = 0;
- ovl.OffsetHigh = 0;
+ S(U(ovl)).Offset = 0;
+ S(U(ovl)).OffsetHigh = 0;
ovl.hEvent = hSem;
completion_count = 0;
szFile[0] = '\0';
/*printf("Offset = %ld, result = %s\n", ovl.Offset, res ? "TRUE" : "FALSE");*/
if (!res)
break;
- ovl.Offset += 4096;
+ S(U(ovl)).Offset += 4096;
/* i/o completion routine only called if ReadFileEx returned success.
* we only care about violations of this rule so undo what should have
* been done */
bytes == 10, /* Win9x */
"bytes = %ld\n", bytes);
+ /* make sure the file contains data */
+ WriteFile(hFile, "this is the test data", 21, &bytes, NULL);
+ SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
+
SetLastError(12345678);
bytes = 12345678;
ret = ReadFile(hFile, NULL, 0, &bytes, NULL);
ok( ret, "DeleteFileA: error %ld\n", GetLastError());
}
+static void test_OpenFile_exists(void)
+{
+ HFILE hFile;
+ OFSTRUCT ofs;
+
+ static const char *file = "\\winver.exe";
+ char buff[MAX_PATH];
+ UINT length;
+
+ length = GetSystemDirectoryA(buff, MAX_PATH);
+
+ if ((length + lstrlen(file) < MAX_PATH))
+ {
+ lstrcat(buff, file);
+
+ hFile = OpenFile(buff, &ofs, OF_EXIST);
+ ok( hFile == TRUE, "%s not found : %ld\n", buff, GetLastError());
+ }
+
+ hFile = OpenFile(".\\foo-bar-foo.baz", &ofs, OF_EXIST);
+ ok( hFile == HFILE_ERROR, "hFile != HFILE_ERROR : %ld\n", GetLastError());
+}
+
+static void test_overlapped(void)
+{
+ OVERLAPPED ov;
+ DWORD r, result;
+
+ /* GetOverlappedResult crashes if the 2nd or 3rd param are NULL */
+
+ memset( &ov, 0, sizeof ov );
+ result = 1;
+ r = GetOverlappedResult(0, &ov, &result, 0);
+ ok( r == TRUE, "should return false\n");
+ ok( result == 0, "result wrong\n");
+
+ result = 0;
+ ov.Internal = 0;
+ ov.InternalHigh = 0xabcd;
+ r = GetOverlappedResult(0, &ov, &result, 0);
+ ok( r == TRUE, "should return false\n");
+ ok( result == 0xabcd, "result wrong\n");
+
+ SetLastError( 0xb00 );
+ result = 0;
+ ov.Internal = STATUS_INVALID_HANDLE;
+ ov.InternalHigh = 0xabcd;
+ r = GetOverlappedResult(0, &ov, &result, 0);
+ ok (GetLastError() == ERROR_INVALID_HANDLE, "error wrong\n");
+ ok( r == FALSE, "should return false\n");
+ ok( result == 0xabcd, "result wrong\n");
+
+ result = 0;
+ ov.Internal = STATUS_PENDING;
+ ov.InternalHigh = 0xabcd;
+ r = GetOverlappedResult(0, &ov, &result, 0);
+ todo_wine {
+ ok (GetLastError() == ERROR_IO_INCOMPLETE, "error wrong\n");
+ }
+ ok( r == FALSE, "should return false\n");
+ ok( result == 0, "result wrong\n");
+
+ ov.hEvent = CreateEvent( NULL, 1, 1, NULL );
+ ov.Internal = STATUS_PENDING;
+ ov.InternalHigh = 0xabcd;
+ r = GetOverlappedResult(0, &ov, &result, 0);
+ ok (GetLastError() == ERROR_IO_INCOMPLETE, "error wrong\n");
+ ok( r == FALSE, "should return false\n");
+
+ ResetEvent( ov.hEvent );
+
+ ov.Internal = STATUS_PENDING;
+ ov.InternalHigh = 0;
+ r = GetOverlappedResult(0, &ov, &result, 0);
+ ok (GetLastError() == ERROR_IO_INCOMPLETE, "error wrong\n");
+ ok( r == FALSE, "should return false\n");
+
+ r = CloseHandle( ov.hEvent );
+ ok( r == TRUE, "close handle failed\n");
+}
+
START_TEST(file)
{
test__hread( );
test_GetFileType();
test_async_file_errors();
test_read_write();
+ test_OpenFile_exists();
+ test_overlapped();
}
#include "winbase.h"
#include "wine/test.h"
+static SIZE_T resize_9x(SIZE_T size)
+{
+ DWORD dwSizeAligned = (size + 3) & ~3;
+ return max(dwSizeAligned, 12); /* at least 12 bytes */
+}
+
START_TEST(heap)
{
void *mem;
SIZE_T heap_size;
mem = HeapAlloc(GetProcessHeap(), 0, size);
heap_size = HeapSize(GetProcessHeap(), 0, mem);
- ok(size == heap_size, "HeapSize returned %lu instead of %lu\n", heap_size, size);
+ ok(heap_size == size || heap_size == resize_9x(size),
+ "HeapSize returned %lu instead of %lu or %lu\n", heap_size, size, resize_9x(size));
HeapFree(GetProcessHeap(), 0, mem);
}
size = GlobalSize(gbl);
ok(size >= 10 && size <= 16, "Memory not resized to size 10, instead size=%ld\n", size);
- todo_wine
- {
- gbl = GlobalReAlloc(gbl, 0, GMEM_MOVEABLE);
- ok(gbl != NULL, "GlobalReAlloc should not fail on size 0\n");
- }
+ gbl = GlobalReAlloc(gbl, 0, GMEM_MOVEABLE);
+ ok(gbl != NULL, "GlobalReAlloc should not fail on size 0\n");
size = GlobalSize(gbl);
ok(size == 0, "Memory not resized to size 0, instead size=%ld\n", size);
size = LocalSize(gbl);
ok(size >= 10 && size <= 16, "Memory not resized to size 10, instead size=%ld\n", size);
- todo_wine
- {
- gbl = LocalReAlloc(gbl, 0, LMEM_MOVEABLE);
- ok(gbl != NULL, "LocalReAlloc should not fail on size 0\n");
- }
+ gbl = LocalReAlloc(gbl, 0, LMEM_MOVEABLE);
+ ok(gbl != NULL, "LocalReAlloc should not fail on size 0\n");
size = LocalSize(gbl);
ok(size == 0, "Memory not resized to size 0, instead size=%ld\n", size);
gbl = LocalReAlloc(0, 10, LMEM_MOVEABLE);
ok(gbl == NULL, "local realloc allocated memory\n");
+ /* trying to lock empty memory should give an error */
+ gbl = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT,0);
+ ok(gbl != NULL, "returned NULL\n");
+ SetLastError(0xdeadbeef);
+ mem = GlobalLock(gbl);
+ ok( GetLastError() == ERROR_DISCARDED, "should return an error\n");
+ ok( mem == NULL, "should return NULL\n");
+ GlobalFree(gbl);
}
ok(dst[0] == ch || strchrW(outOfSequenceDigits, ch) ||
/* Wine (correctly) maps all Unicode 4.0+ digits */
- isdigitW(ch) || (ch >= 0x24F5 && ch <= 0x24FD) || ch == 0x24FF,
+ isdigitW(ch) || (ch >= 0x24F5 && ch <= 0x24FD) || ch == 0x24FF ||
+ (ch >= 0x1369 && ch <= 0x1371),
"MAP_FOLDDIGITS: ch %d 0x%04x Expected unchanged got %d\n", ch, ch, dst[0]);
}
static void testLoadLibraryA(void)
{
- HMODULE hModule;
+ HMODULE hModule, hModule1;
FARPROC fp;
SetLastError(0xdeadbeef);
- hModule = LoadLibraryA("ntdll.dll");
- ok( hModule != NULL, "ntdll.dll should be loadable\n");
+ hModule = LoadLibraryA("kernel32.dll");
+ ok( hModule != NULL, "kernel32.dll should be loadable\n");
ok( GetLastError() == 0xdeadbeef, "GetLastError should be 0xdeadbeef but is %08lx\n", GetLastError());
- fp = GetProcAddress(hModule, "NtCreateFile");
- ok( fp != NULL, "Call should be there\n");
+ fp = GetProcAddress(hModule, "CreateFileA");
+ ok( fp != NULL, "CreateFileA should be there\n");
ok( GetLastError() == 0xdeadbeef, "GetLastError should be 0xdeadbeef but is %08lx\n", GetLastError());
+ SetLastError(0xdeadbeef);
+ hModule1 = LoadLibraryA("kernel32 ");
+ /* Only winNT does this */
+ if (GetLastError() != ERROR_DLL_NOT_FOUND)
+ {
+ ok( hModule1 != NULL, "\"kernel32 \" should be loadable\n");
+ ok( GetLastError() == 0xdeadbeef, "GetLastError should be 0xdeadbeef but is %08lx\n", GetLastError());
+ ok( hModule == hModule1, "Loaded wrong module\n");
+ FreeLibrary(hModule1);
+ }
FreeLibrary(hModule);
}
DWORD len,len1,drives;
INT id;
HANDLE hndl;
+ BOOL bRes;
*curDrive = *otherDrive = NOT_A_VALID_DRIVE;
sprintf(tmpstr1,"pat%x.tmp",id & 0xffff);
ok(lstrcmpiA(newdir+lstrlenA(tmppath),tmpstr)==0 ||
lstrcmpiA(newdir+lstrlenA(tmppath),tmpstr1)==0,
- "GetTempPath returned '%s' which doesn't match '%s' or '%s'. id=%x\n",
+ "GetTempFileNameA returned '%s' which doesn't match '%s' or '%s'. id=%x\n",
newdir,tmpstr,tmpstr1,id);
+ ok((id=GetTempFileNameA(tmppath,NULL,0,newdir)),"GetTempFileNameA failed\n");
+ sprintf(tmpstr,"%.4x.tmp",id & 0xffff);
+ sprintf(tmpstr1,"%x.tmp",id & 0xffff);
+ ok(lstrcmpiA(newdir+lstrlenA(tmppath),tmpstr)==0 ||
+ lstrcmpiA(newdir+lstrlenA(tmppath),tmpstr1)==0,
+ "GetTempFileNameA returned '%s' which doesn't match '%s' or '%s'. id=%x\n",
+ newdir,tmpstr,tmpstr1,id);
+
+
/* Find first valid drive letter that is neither newdir[0] nor curDrive */
drives = GetLogicalDrives() & ~(1<<(newdir[0]-'A'));
if( *curDrive != NOT_A_VALID_DRIVE)
ok(CreateDirectoryA(tmpstr,NULL),"CreateDirectoryA failed\n");
sprintf(tmpstr,"%s\\%s",newdir,LONGDIR);
ok(CreateDirectoryA(tmpstr,NULL),"CreateDirectoryA failed\n");
+ bRes = CreateDirectoryA("c:",NULL);
+ ok(!bRes && (GetLastError() == ERROR_ACCESS_DENIED ||
+ GetLastError() == ERROR_ALREADY_EXISTS),
+ "CreateDirectoryA(\"c:\" should have failed (%ld)\n", GetLastError());
+ bRes = CreateDirectoryA("c:\\",NULL);
+ ok(!bRes && (GetLastError() == ERROR_ACCESS_DENIED ||
+ GetLastError() == ERROR_ALREADY_EXISTS),
+ "CreateDirectoryA(\"c:\\\" should have failed (%ld)\n", GetLastError());
sprintf(tmpstr,"%s\\%s\\%s",newdir,SHORTDIR,SHORTFILE);
hndl=CreateFileA(tmpstr,GENERIC_WRITE,0,NULL,
CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
/* lpSecurityAttrib */ NULL);
ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
+ ok(WaitNamedPipeA(PIPENAME, 2000), "WaitNamedPipe failed (%08lx)\n", GetLastError());
+
hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
- ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed\n");
+ ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed (%08lx)\n", GetLastError());
/* don't try to do i/o if one side couldn't be opened, as it hangs */
if (hFile != INVALID_HANDLE_VALUE) {
ok(ReadFile(piperead,readbuf,sizeof(readbuf),&read, NULL), "Read from broken pipe withe with pending data failed\n");
ok(read == sizeof(PIPENAME), "Read from anonymous pipe got %ld bytes instead of %d\n", read, sizeof(PIPENAME));
/* But now we need to get informed that the pipe is closed */
- todo_wine ok(ReadFile(piperead,readbuf,sizeof(readbuf),&read, NULL) == 0, "Broken pipe not detected\n");
+ ok(ReadFile(piperead,readbuf,sizeof(readbuf),&read, NULL) == 0, "Broken pipe not detected\n");
}
START_TEST(pipe)
ok(strCmp(result, expect, 0) == 0, "%s:%s expected '%s', got '%s'\n", sect, key, expect, result); \
} while (0)
-/* using !expect insures that the test will fail if the sect/key isn't present
+/* using !expect ensures that the test will fail if the sect/key isn't present
* in result file
*/
#define okChildInt(sect, key, expect) \
static void test_CommandLine(void)
{
- char buffer[MAX_PATH];
+ char buffer[MAX_PATH], fullpath[MAX_PATH], *lpFilePart, *p;
PROCESS_INFORMATION info;
STARTUPINFOA startup;
+ DWORD len;
memset(&startup, 0, sizeof(startup));
startup.cb = sizeof(startup);
okChildString("Arguments", "CommandLineA", buffer);
release_memory();
assert(DeleteFileA(resfile) != 0);
+
+ /* Test for Bug1330 to show that XP doesn't change '/' to '\\' in argv[0]*/
+ get_file_name(resfile);
+ sprintf(buffer, "./%s tests/process.c %s \"a\\\"b\\\\\" c\\\" d", selfname, resfile);
+ ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
+ /* wait for child to terminate */
+ ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
+ /* child process has changed result file, so let profile functions know about it */
+ WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
+ sprintf(buffer, "./%s", selfname);
+ okChildString("Arguments", "argvA0", buffer);
+ release_memory();
+ assert(DeleteFileA(resfile) != 0);
+
+ get_file_name(resfile);
+ sprintf(buffer, ".\\%s tests/process.c %s \"a\\\"b\\\\\" c\\\" d", selfname, resfile);
+ ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
+ /* wait for child to terminate */
+ ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
+ /* child process has changed result file, so let profile functions know about it */
+ WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
+ sprintf(buffer, ".\\%s", selfname);
+ okChildString("Arguments", "argvA0", buffer);
+ release_memory();
+ assert(DeleteFileA(resfile) != 0);
+
+ get_file_name(resfile);
+ len = GetFullPathNameA(selfname, MAX_PATH, fullpath, &lpFilePart);
+ assert ( lpFilePart != 0);
+ *(lpFilePart -1 ) = 0;
+ p = strrchr(fullpath, '\\');
+ assert (p);
+ sprintf(buffer, "..%s/%s tests/process.c %s \"a\\\"b\\\\\" c\\\" d", p, selfname, resfile);
+ ok(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
+ /* wait for child to terminate */
+ ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
+ /* child process has changed result file, so let profile functions know about it */
+ WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
+ sprintf(buffer, "..%s/%s", p, selfname);
+ okChildString("Arguments", "argvA0", buffer);
+ release_memory();
+ assert(DeleteFileA(resfile) != 0);
+
}
static void test_Directory(void)
if( h == INVALID_HANDLE_VALUE) return;
WriteFile( h, content, sizeof(content), &count, NULL);
CloseHandle( h);
+
/* enumerate the keys */
ret=GetPrivateProfileStringA( "s", NULL, "", buf, sizeof(buf),
TESTFILE2);
for( p = buf + strlen(buf) + 1; *p;p += strlen(p)+1)
p[-1] = ',';
/* and test */
- ok( !strcmp( buf, "name1,name2,name4"), "wrong keys returned: %s\n",
+ ok( ret == 18 && !strcmp( buf, "name1,name2,name4"), "wrong keys returned(%d): %s\n", ret,
buf);
ret=GetPrivateProfileSectionA("s", buf, sizeof(buf), TESTFILE2);
for( p = buf + strlen(buf) + 1; *p;p += strlen(p)+1)
p[-1] = ',';
/* and test */
- ok( !strcmp( buf, "name1=val1,name2=,name3,name4=val4"), "wrong section returned: %s\n",
- buf);
+ ok( ret == 35 && !strcmp( buf, "name1=val1,name2=,name3,name4=val4"), "wrong section returned(%d): %s\n",
+ ret, buf);
/* add a new key to test that the file is quite usable */
WritePrivateProfileStringA( "s", "name5", "val5", TESTFILE2);
TESTFILE2);
for( p = buf + strlen(buf) + 1; *p;p += strlen(p)+1)
p[-1] = ',';
- ok( !strcmp( buf, "name1,name2,name4,name5"), "wrong keys returned: %s\n",
- buf);
+ ok( ret == 24 && !strcmp( buf, "name1,name2,name4,name5"), "wrong keys returned(%d): %s\n",
+ ret, buf);
+
DeleteFileA( TESTFILE2);
}
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL);
r = pSignalObjectAndWait(file, file, 0, FALSE);
ok( r == WAIT_FAILED, "should fail\n");
- todo_wine {
ok( ERROR_INVALID_HANDLE == GetLastError(), "should return invalid handle error\n");
- }
CloseHandle(file);
}
} t1Struct;
/* WinME supports OpenThread but doesn't know about access restrictions so
- we require them to be either completly ignored or always obeyed.
+ we require them to be either completely ignored or always obeyed.
*/
INT obeying_ars = 0; /* -1 == no, 0 == dunno yet, 1 == yes */
#define obey_ar(x) \
? ok(!(x), "access restrictions obeyed\n") \
: ok( (x), "access restrictions not obeyed\n"))
-/* Basic test that simulatneous threads can access shared memory,
+/* Basic test that simultaneous threads can access shared memory,
that the thread local storage routines work correctly, and that
threads actually run concurrently
*/
for(i=0;i<NUM_THREADS;i++) {
while(tstruct->threadmem[i]==0) ;
}
-/* Check that noone cahnged our tls memory */
+
+ /* lstrlenA contains an exception handler so this makes sure exceptions work in threads */
+ ok( lstrlenA( (char *)0xdeadbeef ) == 0, "lstrlenA: unexpected success\n" );
+
+/* Check that noone changed our tls memory */
ok((int)TlsGetValue(tlsIndex)-1==tstruct->threadnum,
"TlsGetValue failed\n");
return NUM_THREADS+tstruct->threadnum;
t1Struct tstruct[NUM_THREADS];
int error;
DWORD i,j;
+ DWORD GLE, ret;
+
+ /* lstrlenA contains an exception handler so this makes sure exceptions work in the main thread */
+ ok( lstrlenA( (char *)0xdeadbeef ) == 0, "lstrlenA: unexpected success\n" );
+
/* Retrieve current Thread ID for later comparisons */
curthreadId=GetCurrentThreadId();
/* Allocate some local storage */
ok(CloseHandle(thread[i])!=0,"CloseHandle failed\n");
}
ok(TlsFree(tlsIndex)!=0,"TlsFree failed\n");
+
+ /* Test how passing NULL as a pointer to threadid works */
+ SetLastError(0xFACEaBAD);
+ thread[0] = CreateThread(NULL,0,threadFunc2,NULL,0,NULL);
+ GLE = GetLastError();
+ if (thread[0]) { /* NT */
+ ok(GLE==0xFACEaBAD, "CreateThread set last error to %ld, expected 4207848365\n", GLE);
+ ret = WaitForSingleObject(thread[0],100);
+ ok(ret==WAIT_OBJECT_0, "threadFunc2 did not exit during 100 ms\n");
+ ret = GetExitCodeThread(thread[0],&exitCode);
+ ok(ret!=0, "GetExitCodeThread returned %ld (expected nonzero)\n", ret);
+ ok(exitCode==99, "threadFunc2 exited with code: %ld (expected 99)\n", exitCode);
+ ok(CloseHandle(thread[0])!=0,"Error closing thread handle\n");
+ }
+ else { /* 9x */
+ ok(GLE==ERROR_INVALID_PARAMETER, "CreateThread set last error to %ld, expected 87\n", GLE);
+ }
}
/* Check that using the CREATE_SUSPENDED flag works */
thread = CreateThread(NULL,0,threadFunc4,
(LPVOID)event, 0,&threadId);
ok(thread!=NULL,"Create Thread failed\n");
-/* Terminate thread has a race condition in Wine. If the thread is terminated
+/* TerminateThread has a race condition in Wine. If the thread is terminated
before it starts, it leaves a process behind. Therefore, we wait for the
thread to signal that it has started. There is no easy way to force the
race to occur, so we don't try to find it.
"SetThreadPriority Failed\n");
ok(GetThreadPriority(curthread)==THREAD_PRIORITY_TIME_CRITICAL,
"GetThreadPriority Failed\n");
- //ok(SetThreadPriority(curthread,THREAD_PRIORITY_IDLE)!=0,
- //"SetThreadPriority Failed\n");
- //ok(GetThreadPriority(curthread)==THREAD_PRIORITY_IDLE,
- //"GetThreadPriority Failed\n");
+ ok(SetThreadPriority(curthread,THREAD_PRIORITY_IDLE)!=0,
+ "SetThreadPriority Failed\n");
+ ok(GetThreadPriority(curthread)==THREAD_PRIORITY_IDLE,
+ "GetThreadPriority Failed\n");
ok(SetThreadPriority(curthread,0)!=0,"SetThreadPriority Failed\n");
/* Check thread priority boost */
}
}
+static VOID test_GetThreadExitCode(void)
+{
+ DWORD exitCode, threadid;
+ DWORD GLE, ret;
+ HANDLE thread;
+
+ ret = GetExitCodeThread((HANDLE)0x2bad2bad,&exitCode);
+ ok(ret==0, "GetExitCodeThread returned non zero value: %ld\n", ret);
+ GLE = GetLastError();
+ ok(GLE==ERROR_INVALID_HANDLE, "GetLastError returned %ld (expected 6)\n", GLE);
+
+ thread = CreateThread(NULL,0,threadFunc2,NULL,0,&threadid);
+ ret = WaitForSingleObject(thread,100);
+ ok(ret==WAIT_OBJECT_0, "threadFunc2 did not exit during 100 ms\n");
+ ret = GetExitCodeThread(thread,&exitCode);
+ ok(ret==exitCode || ret==1,
+ "GetExitCodeThread returned %ld (expected 1 or %ld)\n", ret, exitCode);
+ ok(exitCode==99, "threadFunc2 exited with code %ld (expected 99)\n", exitCode);
+ ok(CloseHandle(thread)!=0,"Error closing thread handle\n");
+}
+
+#ifdef __i386__
+
+static int test_value = 0;
+static HANDLE event;
+
+static void WINAPI set_test_val( int val )
+{
+ test_value += val;
+}
+
+static DWORD WINAPI threadFunc6(LPVOID p)
+{
+ SetEvent( event );
+ Sleep( 1000 );
+ test_value *= (int)p;
+ return 0;
+}
+
+static void test_SetThreadContext(void)
+{
+ CONTEXT ctx;
+ int *stack;
+ HANDLE thread;
+ DWORD threadid;
+ DWORD prevcount;
+
+ SetLastError(0xdeadbeef);
+ event = CreateEvent( NULL, TRUE, FALSE, NULL );
+ thread = CreateThread( NULL, 0, threadFunc6, (void *)2, 0, &threadid );
+ ok( thread != NULL, "CreateThread failed : (%ld)\n", GetLastError() );
+ if (!thread)
+ {
+ trace("Thread creation failed, skipping rest of test\n");
+ return;
+ }
+ WaitForSingleObject( event, INFINITE );
+ SuspendThread( thread );
+ CloseHandle( event );
+
+ ctx.ContextFlags = CONTEXT_FULL;
+ SetLastError(0xdeadbeef);
+ ok( GetThreadContext( thread, &ctx ), "GetThreadContext failed : (%ld)\n", GetLastError() );
+
+ /* simulate a call to set_test_val(10) */
+ stack = (int *)ctx.Esp;
+ stack[-1] = 10;
+ stack[-2] = ctx.Eip;
+ ctx.Esp -= 2 * sizeof(int *);
+ ctx.Eip = (DWORD)set_test_val;
+ SetLastError(0xdeadbeef);
+ ok( SetThreadContext( thread, &ctx ), "SetThreadContext failed : (%ld)\n", GetLastError() );
+
+ SetLastError(0xdeadbeef);
+ prevcount = ResumeThread( thread );
+ ok ( prevcount == 1, "Previous suspend count (%ld) instead of 1, last error : (%ld)\n",
+ prevcount, GetLastError() );
+
+ WaitForSingleObject( thread, INFINITE );
+ ok( test_value == 20, "test_value %d instead of 20\n", test_value );
+}
+
+#endif /* __i386__ */
+
+
START_TEST(thread)
{
HINSTANCE lib;
/* Neither Cygwin nor mingW export OpenThread, so do a dynamic check
so that the compile passes
*/
- lib=LoadLibraryA("kernel32");
- ok(lib!=NULL,"Couldn't load kernel32.dll\n");
+ lib=GetModuleHandleA("kernel32.dll");
+ ok(lib!=NULL,"Couldn't get a handle for kernel32.dll\n");
pGetThreadPriorityBoost=(GetThreadPriorityBoost_t)GetProcAddress(lib,"GetThreadPriorityBoost");
pOpenThread=(OpenThread_t)GetProcAddress(lib,"OpenThread");
pSetThreadIdealProcessor=(SetThreadIdealProcessor_t)GetProcAddress(lib,"SetThreadIdealProcessor");
test_thread_priority();
test_GetThreadTimes();
test_thread_processor();
+ test_GetThreadExitCode();
+#ifdef __i386__
+ test_SetThreadContext();
+#endif
}