https://git.reactos.org/?p=reactos.git;a=commitdiff;h=f7932ba2de71f0340daa1…
commit f7932ba2de71f0340daa18db32e083383b8e680b
Author: Amine Khaldi <amine.khaldi(a)reactos.org>
AuthorDate: Sat Oct 21 14:36:29 2017 +0100
[NTDLL_WINETEST] Sync with Wine Staging 2.16. CORE-13762
---
modules/rostests/winetests/ntdll/CMakeLists.txt | 3 +-
modules/rostests/winetests/ntdll/directory.c | 590 ++++++-
modules/rostests/winetests/ntdll/exception.c | 934 ++++++++++-
modules/rostests/winetests/ntdll/file.c | 750 +++++----
modules/rostests/winetests/ntdll/info.c | 625 +++++++-
modules/rostests/winetests/ntdll/large_int.c | 118 +-
modules/rostests/winetests/ntdll/ntdll_test.h | 4 -
modules/rostests/winetests/ntdll/om.c | 1104 +++++++++++--
modules/rostests/winetests/ntdll/path.c | 9 +-
modules/rostests/winetests/ntdll/pipe.c | 527 ++++++-
modules/rostests/winetests/ntdll/process.c | 207 +++
modules/rostests/winetests/ntdll/reg.c | 76 +-
modules/rostests/winetests/ntdll/rtl.c | 405 ++++-
modules/rostests/winetests/ntdll/rtlbitmap.c | 16 +-
modules/rostests/winetests/ntdll/string.c | 75 +-
modules/rostests/winetests/ntdll/testlist.c | 2 +
modules/rostests/winetests/ntdll/threadpool.c | 1919 +++++++++++++++++++++++
modules/rostests/winetests/ntdll/time.c | 121 ++
18 files changed, 6783 insertions(+), 702 deletions(-)
diff --git a/modules/rostests/winetests/ntdll/CMakeLists.txt
b/modules/rostests/winetests/ntdll/CMakeLists.txt
index 4fe5a26ed3..f1055f85db 100644
--- a/modules/rostests/winetests/ntdll/CMakeLists.txt
+++ b/modules/rostests/winetests/ntdll/CMakeLists.txt
@@ -1,7 +1,7 @@
include_directories(BEFORE ${REACTOS_SOURCE_DIR}/sdk/include/reactos/wine)
remove_definitions(-DWINVER=0x502 -D_WIN32_IE=0x600 -D_WIN32_WINNT=0x502)
-add_definitions(-D__WINESRC__)
+add_definitions(-D__WINESRC__ -DWINETEST_USE_DBGSTR_LONGLONG)
list(APPEND SOURCE
atom.c
@@ -17,6 +17,7 @@ list(APPEND SOURCE
path.c
pipe.c
port.c
+ process.c
reg.c
rtl.c
rtlbitmap.c
diff --git a/modules/rostests/winetests/ntdll/directory.c
b/modules/rostests/winetests/ntdll/directory.c
index 89b786d384..21f22ad043 100644
--- a/modules/rostests/winetests/ntdll/directory.c
+++ b/modules/rostests/winetests/ntdll/directory.c
@@ -34,16 +34,20 @@
#define WIN32_NO_STATUS
#include "wine/test.h"
+#include "winnls.h"
#include "wine/winternl.h"
static NTSTATUS (WINAPI *pNtClose)( PHANDLE );
static NTSTATUS (WINAPI *pNtOpenFile) ( PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES,
PIO_STATUS_BLOCK, ULONG, ULONG );
static NTSTATUS (WINAPI
*pNtQueryDirectoryFile)(HANDLE,HANDLE,PIO_APC_ROUTINE,PVOID,PIO_STATUS_BLOCK,
PVOID,ULONG,FILE_INFORMATION_CLASS,BOOLEAN,PUNICODE_STRING,BOOLEAN);
+static NTSTATUS (WINAPI
*pNtQueryInformationFile)(HANDLE,PIO_STATUS_BLOCK,PVOID,LONG,FILE_INFORMATION_CLASS);
+static NTSTATUS (WINAPI
*pNtSetInformationFile)(HANDLE,PIO_STATUS_BLOCK,PVOID,ULONG,FILE_INFORMATION_CLASS);
static BOOLEAN (WINAPI *pRtlCreateUnicodeStringFromAsciiz)(PUNICODE_STRING,LPCSTR);
static BOOL (WINAPI *pRtlDosPathNameToNtPathName_U)( LPCWSTR, PUNICODE_STRING,
PWSTR*, CURDIR* );
static VOID (WINAPI *pRtlInitUnicodeString)( PUNICODE_STRING, LPCWSTR );
static VOID (WINAPI *pRtlFreeUnicodeString)( PUNICODE_STRING );
+static LONG (WINAPI *pRtlCompareUnicodeString)( const UNICODE_STRING*, const
UNICODE_STRING*,BOOLEAN );
static NTSTATUS (WINAPI *pRtlMultiByteToUnicodeN)( LPWSTR dst, DWORD dstlen, LPDWORD
reslen,
LPCSTR src, DWORD srclen );
static NTSTATUS (WINAPI *pRtlWow64EnableFsRedirection)( BOOLEAN enable );
@@ -53,47 +57,56 @@ static NTSTATUS (WINAPI *pRtlWow64EnableFsRedirectionEx)( ULONG
disable, ULONG *
static struct testfile_s {
BOOL attr_done; /* set if attributes were tested for this file already */
const DWORD attr; /* desired attribute */
- const char *name; /* filename to use */
+ WCHAR name[20]; /* filename to use */
const char *target; /* what to point to (only for reparse pts) */
const char *description; /* for error messages */
int nfound; /* How many were found (expect 1) */
- WCHAR nameW[20]; /* unicode version of name (filled in later) */
} testfiles[] = {
- { 0, FILE_ATTRIBUTE_NORMAL, "n.tmp", NULL, "normal" },
- { 0, FILE_ATTRIBUTE_HIDDEN, "h.tmp", NULL, "hidden" },
- { 0, FILE_ATTRIBUTE_SYSTEM, "s.tmp", NULL, "system" },
- { 0, FILE_ATTRIBUTE_DIRECTORY, "d.tmp", NULL, "directory" },
- { 0, FILE_ATTRIBUTE_DIRECTORY, ".", NULL, ". directory" },
- { 0, FILE_ATTRIBUTE_DIRECTORY, "..", NULL, ".. directory" },
- { 0, 0, NULL }
+ { 0, FILE_ATTRIBUTE_NORMAL,
{'l','o','n','g','f','i','l','e','n','a','m','e','.','t','m','p'},
"normal" },
+ { 0, FILE_ATTRIBUTE_NORMAL,
{'n','.','t','m','p',}, "normal" },
+ { 0, FILE_ATTRIBUTE_HIDDEN,
{'h','.','t','m','p',}, "hidden" },
+ { 0, FILE_ATTRIBUTE_SYSTEM,
{'s','.','t','m','p',}, "system" },
+ { 0, FILE_ATTRIBUTE_DIRECTORY,
{'d','.','t','m','p',}, "directory" },
+ { 0, FILE_ATTRIBUTE_NORMAL,
{0xe9,'a','.','t','m','p'}, "normal" },
+ { 0, FILE_ATTRIBUTE_NORMAL,
{0xc9,'b','.','t','m','p'}, "normal" },
+ { 0, FILE_ATTRIBUTE_NORMAL,
{'e','a','.','t','m','p'},
"normal" },
+ { 0, FILE_ATTRIBUTE_DIRECTORY, {'.'}, ".
directory" },
+ { 0, FILE_ATTRIBUTE_DIRECTORY, {'.','.'}, "..
directory" }
};
-static const int max_test_dir_size = 20; /* size of above plus some for .. etc */
+static const int test_dir_count = sizeof(testfiles) / sizeof(testfiles[0]);
+static const int max_test_dir_size = sizeof(testfiles) / sizeof(testfiles[0]) + 5; /*
size of above plus some for .. etc */
+
+static const WCHAR dummyW[] =
{'d','u','m','m','y',0};
+static const WCHAR dotW[] = {'.',0};
+static const WCHAR dotdotW[] = {'.','.',0};
+static const WCHAR backslashW[] = {'\\',0};
/* Create a test directory full of attribute test files, clear counts */
-static void set_up_attribute_test(const char *testdirA)
+static void set_up_attribute_test(const WCHAR *testdir)
{
int i;
BOOL ret;
- ret = CreateDirectoryA(testdirA, NULL);
- ok(ret, "couldn't create dir '%s', error %d\n", testdirA,
GetLastError());
+ ret = CreateDirectoryW(testdir, NULL);
+ ok(ret, "couldn't create dir %s, error %d\n", wine_dbgstr_w(testdir),
GetLastError());
- for (i=0; testfiles[i].name; i++) {
- char buf[MAX_PATH];
- pRtlMultiByteToUnicodeN(testfiles[i].nameW, sizeof(testfiles[i].nameW), NULL,
testfiles[i].name, strlen(testfiles[i].name)+1);
+ for (i=0; i < test_dir_count; i++) {
+ WCHAR buf[MAX_PATH];
- if (strcmp(testfiles[i].name, ".") == 0 || strcmp(testfiles[i].name,
"..") == 0)
+ if (lstrcmpW(testfiles[i].name, dotW) == 0 || lstrcmpW(testfiles[i].name,
dotdotW) == 0)
continue;
- sprintf(buf, "%s\\%s", testdirA, testfiles[i].name);
+ lstrcpyW( buf, testdir );
+ lstrcatW( buf, backslashW );
+ lstrcatW( buf, testfiles[i].name );
if (testfiles[i].attr & FILE_ATTRIBUTE_DIRECTORY) {
- ret = CreateDirectoryA(buf, NULL);
- ok(ret, "couldn't create dir '%s', error %d\n", buf,
GetLastError());
+ ret = CreateDirectoryW(buf, NULL);
+ ok(ret, "couldn't create dir %s, error %d\n",
wine_dbgstr_w(buf), GetLastError());
} else {
- HANDLE h = CreateFileA(buf,
+ HANDLE h = CreateFileW(buf,
GENERIC_READ|GENERIC_WRITE,
0, NULL, CREATE_ALWAYS,
testfiles[i].attr, 0);
- ok( h != INVALID_HANDLE_VALUE, "failed to create temp file
'%s'\n", buf );
+ ok( h != INVALID_HANDLE_VALUE, "failed to create temp file %s\n",
wine_dbgstr_w(buf) );
CloseHandle(h);
}
}
@@ -103,32 +116,34 @@ static void reset_found_files(void)
{
int i;
- for (i = 0; testfiles[i].name; i++)
+ for (i = 0; i < test_dir_count; i++)
testfiles[i].nfound = 0;
}
/* Remove the given test directory and the attribute test files, if any */
-static void tear_down_attribute_test(const char *testdirA)
+static void tear_down_attribute_test(const WCHAR *testdir)
{
int i;
- for (i=0; testfiles[i].name; i++) {
+ for (i = 0; i < test_dir_count; i++) {
int ret;
- char buf[MAX_PATH];
- if (strcmp(testfiles[i].name, ".") == 0 || strcmp(testfiles[i].name,
"..") == 0)
+ WCHAR buf[MAX_PATH];
+ if (lstrcmpW(testfiles[i].name, dotW) == 0 || lstrcmpW(testfiles[i].name,
dotdotW) == 0)
continue;
- sprintf(buf, "%s\\%s", testdirA, testfiles[i].name);
+ lstrcpyW( buf, testdir );
+ lstrcatW( buf, backslashW );
+ lstrcatW( buf, testfiles[i].name );
if (testfiles[i].attr & FILE_ATTRIBUTE_DIRECTORY) {
- ret = RemoveDirectoryA(buf);
+ ret = RemoveDirectoryW(buf);
ok(ret || (GetLastError() == ERROR_PATH_NOT_FOUND),
- "Failed to rmdir %s, error %d\n", buf, GetLastError());
+ "Failed to rmdir %s, error %d\n", wine_dbgstr_w(buf),
GetLastError());
} else {
- ret = DeleteFileA(buf);
+ ret = DeleteFileW(buf);
ok(ret || (GetLastError() == ERROR_PATH_NOT_FOUND),
- "Failed to rm %s, error %d\n", buf, GetLastError());
+ "Failed to rm %s, error %d\n", wine_dbgstr_w(buf),
GetLastError());
}
}
- RemoveDirectoryA(testdirA);
+ RemoveDirectoryW(testdir);
}
/* Match one found file against testfiles[], increment count if found */
@@ -141,35 +156,37 @@ static void tally_test_file(FILE_BOTH_DIRECTORY_INFORMATION
*dir_info)
WCHAR *nameW = dir_info->FileName;
int namelen = dir_info->FileNameLength / sizeof(WCHAR);
- for (i=0; testfiles[i].name; i++) {
- int len = strlen(testfiles[i].name);
- if (namelen != len || memcmp(nameW, testfiles[i].nameW, len*sizeof(WCHAR)))
+ for (i = 0; i < test_dir_count; i++) {
+ int len = lstrlenW(testfiles[i].name);
+ if (namelen != len || memcmp(nameW, testfiles[i].name, len*sizeof(WCHAR)))
continue;
if (!testfiles[i].attr_done) {
- ok (attrib == (testfiles[i].attr & attribmask), "file %s: expected
%s (%x), got %x (is your linux new enough?)\n", testfiles[i].name,
testfiles[i].description, testfiles[i].attr, attrib);
+ ok (attrib == (testfiles[i].attr & attribmask), "file %s: expected
%s (%x), got %x (is your linux new enough?)\n", wine_dbgstr_w(testfiles[i].name),
testfiles[i].description, testfiles[i].attr, attrib);
testfiles[i].attr_done = TRUE;
}
testfiles[i].nfound++;
break;
}
- ok(testfiles[i].name != NULL, "unexpected file found\n");
+ ok(i < test_dir_count, "unexpected file found %s\n",
wine_dbgstr_wn(dir_info->FileName, namelen));
}
static void test_flags_NtQueryDirectoryFile(OBJECT_ATTRIBUTES *attr, const char
*testdirA,
UNICODE_STRING *mask,
BOOLEAN single_entry, BOOLEAN restart_flag)
{
- HANDLE dirh;
+ UNICODE_STRING dummy_mask;
+ HANDLE dirh, new_dirh;
IO_STATUS_BLOCK io;
UINT data_pos, data_size;
UINT data_len; /* length of dir data */
BYTE data[8192]; /* directory data */
FILE_BOTH_DIRECTORY_INFORMATION *dir_info;
- DWORD status;
+ NTSTATUS status;
int numfiles;
int i;
reset_found_files();
+ pRtlInitUnicodeString( &dummy_mask, dummyW );
data_size = mask ? offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[256] ) :
sizeof(data);
@@ -182,12 +199,18 @@ static void test_flags_NtQueryDirectoryFile(OBJECT_ATTRIBUTES *attr,
const char
return;
}
- pNtQueryDirectoryFile( dirh, NULL, NULL, NULL, &io, data, data_size,
- FileBothDirectoryInformation, single_entry, mask, restart_flag );
+ U(io).Status = 0xdeadbeef;
+ status = pNtQueryDirectoryFile( dirh, NULL, NULL, NULL, &io, data, data_size,
+ FileBothDirectoryInformation, single_entry, mask,
restart_flag );
+ ok (status == STATUS_SUCCESS, "failed to query directory; status %x\n",
status);
ok (U(io).Status == STATUS_SUCCESS, "failed to query directory; status
%x\n", U(io).Status);
data_len = io.Information;
ok (data_len >= sizeof(FILE_BOTH_DIRECTORY_INFORMATION), "not enough data in
directory\n");
+ DuplicateHandle( GetCurrentProcess(), dirh, GetCurrentProcess(), &new_dirh,
+ 0, FALSE, DUPLICATE_SAME_ACCESS );
+ pNtClose(dirh);
+
data_pos = 0;
numfiles = 0;
while ((data_pos < data_len) && (numfiles < max_test_dir_size)) {
@@ -196,11 +219,12 @@ static void test_flags_NtQueryDirectoryFile(OBJECT_ATTRIBUTES *attr,
const char
tally_test_file(dir_info);
if (dir_info->NextEntryOffset == 0) {
- pNtQueryDirectoryFile( dirh, 0, NULL, NULL, &io, data, data_size,
- FileBothDirectoryInformation, single_entry, mask, FALSE
);
- if (U(io).Status == STATUS_NO_MORE_FILES)
- break;
- ok (U(io).Status == STATUS_SUCCESS, "failed to query directory; status
%x\n", U(io).Status);
+ U(io).Status = 0xdeadbeef;
+ status = pNtQueryDirectoryFile( new_dirh, 0, NULL, NULL, &io, data,
data_size,
+ FileBothDirectoryInformation, single_entry,
&dummy_mask, FALSE );
+ ok (U(io).Status == status, "wrong status %x / %x\n", status,
U(io).Status);
+ if (status == STATUS_NO_MORE_FILES) break;
+ ok (status == STATUS_SUCCESS, "failed to query directory; status
%x\n", status);
data_len = io.Information;
if (data_len < sizeof(FILE_BOTH_DIRECTORY_INFORMATION))
break;
@@ -213,33 +237,238 @@ static void test_flags_NtQueryDirectoryFile(OBJECT_ATTRIBUTES
*attr, const char
ok(numfiles < max_test_dir_size, "too many loops\n");
if (mask)
- for (i=0; testfiles[i].name; i++)
- ok(testfiles[i].nfound == (testfiles[i].nameW == mask->Buffer),
+ for (i = 0; i < test_dir_count; i++)
+ ok(testfiles[i].nfound == (testfiles[i].name == mask->Buffer),
"Wrong number %d of %s files found
(single_entry=%d,mask=%s)\n",
testfiles[i].nfound, testfiles[i].description, single_entry,
wine_dbgstr_wn(mask->Buffer, mask->Length/sizeof(WCHAR) ));
else
- for (i=0; testfiles[i].name; i++)
+ for (i = 0; i < test_dir_count; i++)
ok(testfiles[i].nfound == 1, "Wrong number %d of %s files found
(single_entry=%d,restart=%d)\n",
testfiles[i].nfound, testfiles[i].description, single_entry,
restart_flag);
- pNtClose(dirh);
+ pNtClose(new_dirh);
}
-static void test_NtQueryDirectoryFile(void)
+static void test_directory_sort( const WCHAR *testdir )
{
OBJECT_ATTRIBUTES attr;
UNICODE_STRING ntdirname;
+ IO_STATUS_BLOCK io;
+ UINT data_pos, data_len, count;
+ BYTE data[8192];
+ WCHAR prev[MAX_PATH], name[MAX_PATH];
+ UNICODE_STRING prev_str, name_str;
+ FILE_BOTH_DIRECTORY_INFORMATION *info;
+ NTSTATUS status;
+ HANDLE handle;
+ int res;
+
+ if (!pRtlDosPathNameToNtPathName_U( testdir, &ntdirname, NULL, NULL ))
+ {
+ ok(0, "RtlDosPathNametoNtPathName_U failed\n");
+ return;
+ }
+ InitializeObjectAttributes( &attr, &ntdirname, OBJ_CASE_INSENSITIVE, 0, NULL
);
+ status = pNtOpenFile( &handle, SYNCHRONIZE | FILE_LIST_DIRECTORY, &attr,
&io, FILE_SHARE_READ,
+ FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT |
FILE_DIRECTORY_FILE );
+ ok(status == STATUS_SUCCESS, "failed to open dir %s\n",
wine_dbgstr_w(testdir) );
+
+ U(io).Status = 0xdeadbeef;
+ status = pNtQueryDirectoryFile( handle, NULL, NULL, NULL, &io, data,
sizeof(data),
+ FileBothDirectoryInformation, FALSE, NULL, TRUE );
+ ok( status == STATUS_SUCCESS, "failed to query directory; status %x\n",
status );
+ ok( U(io).Status == STATUS_SUCCESS, "failed to query directory; status
%x\n", U(io).Status );
+ data_len = io.Information;
+ ok( data_len >= sizeof(FILE_BOTH_DIRECTORY_INFORMATION), "not enough data in
directory\n" );
+ data_pos = 0;
+ count = 0;
+
+ while (data_pos < data_len)
+ {
+ info = (FILE_BOTH_DIRECTORY_INFORMATION *)(data + data_pos);
+
+ memcpy( name, info->FileName, info->FileNameLength );
+ name[info->FileNameLength / sizeof(WCHAR)] = 0;
+ switch (count)
+ {
+ case 0: /* first entry must be '.' */
+ ok( !lstrcmpW( name, dotW ), "wrong name %s\n", wine_dbgstr_w( name
));
+ break;
+ case 1: /* second entry must be '..' */
+ ok( !lstrcmpW( name, dotdotW ), "wrong name %s\n", wine_dbgstr_w(
name ));
+ break;
+ case 2: /* nothing to compare against */
+ break;
+ default:
+ pRtlInitUnicodeString( &prev_str, prev );
+ pRtlInitUnicodeString( &name_str, name );
+ res = pRtlCompareUnicodeString( &prev_str, &name_str, TRUE );
+ ok( res < 0, "wrong result %d %s %s\n", res, wine_dbgstr_w( prev
), wine_dbgstr_w( name ));
+ break;
+ }
+ count++;
+ lstrcpyW( prev, name );
+
+ if (info->NextEntryOffset == 0)
+ {
+ U(io).Status = 0xdeadbeef;
+ status = pNtQueryDirectoryFile( handle, 0, NULL, NULL, &io, data,
sizeof(data),
+ FileBothDirectoryInformation, FALSE, NULL,
FALSE );
+ ok (U(io).Status == status, "wrong status %x / %x\n", status,
U(io).Status);
+ if (status == STATUS_NO_MORE_FILES) break;
+ ok( status == STATUS_SUCCESS, "failed to query directory; status
%x\n", status );
+ data_len = io.Information;
+ data_pos = 0;
+ }
+ else data_pos += info->NextEntryOffset;
+ }
+
+ pNtClose( handle );
+ pRtlFreeUnicodeString( &ntdirname );
+}
+
+static void test_NtQueryDirectoryFile_classes( HANDLE handle, UNICODE_STRING *mask )
+{
+ IO_STATUS_BLOCK io;
+ UINT data_size;
+ ULONG data[256];
+ NTSTATUS status;
+ int class;
+
+ for (class = 0; class < FileMaximumInformation; class++)
+ {
+ U(io).Status = 0xdeadbeef;
+ U(io).Information = 0xdeadbeef;
+ data_size = 0;
+ memset( data, 0x55, sizeof(data) );
+
+ status = pNtQueryDirectoryFile( handle, 0, NULL, NULL, &io, data, data_size,
+ class, FALSE, mask, TRUE );
+ ok( U(io).Status == 0xdeadbeef, "%u: wrong status %x\n", class,
U(io).Status );
+ ok( U(io).Information == 0xdeadbeef, "%u: wrong info %lx\n", class,
U(io).Information );
+ ok(data[0] == 0x55555555, "%u: wrong offset %x\n", class, data[0] );
+
+ switch (class)
+ {
+ case FileIdGlobalTxDirectoryInformation:
+ case FileIdExtdDirectoryInformation:
+ case FileIdExtdBothDirectoryInformation:
+ if (status == STATUS_INVALID_INFO_CLASS || status == STATUS_NOT_IMPLEMENTED)
continue;
+ /* fall through */
+ case FileDirectoryInformation:
+ case FileFullDirectoryInformation:
+ case FileBothDirectoryInformation:
+ case FileNamesInformation:
+ case FileIdBothDirectoryInformation:
+ case FileIdFullDirectoryInformation:
+ case FileObjectIdInformation:
+ case FileQuotaInformation:
+ case FileReparsePointInformation:
+ ok( status == STATUS_INFO_LENGTH_MISMATCH, "%u: wrong status %x\n",
class, status );
+ break;
+ default:
+ ok( status == STATUS_INVALID_INFO_CLASS || status == STATUS_NOT_IMPLEMENTED,
+ "%u: wrong status %x\n", class, status );
+ continue;
+ }
+
+ for (data_size = 1; data_size < sizeof(data); data_size++)
+ {
+ status = pNtQueryDirectoryFile( handle, 0, NULL, NULL, &io, data,
data_size,
+ class, FALSE, mask, TRUE );
+ if (status == STATUS_BUFFER_OVERFLOW)
+ {
+ ok( U(io).Status == STATUS_BUFFER_OVERFLOW, "%u: wrong status
%x\n", class, U(io).Status );
+ ok( U(io).Information == data_size, "%u: wrong info %lx\n",
class, U(io).Information );
+ ok(data[0] == 0, "%u: wrong offset %x\n", class, data[0] );
+ }
+ else
+ {
+ ok( U(io).Status == 0xdeadbeef, "%u: wrong status %x\n", class,
U(io).Status );
+ ok( U(io).Information == 0xdeadbeef, "%u: wrong info %lx\n",
class, U(io).Information );
+ ok(data[0] == 0x55555555, "%u: wrong offset %x\n", class,
data[0] );
+ }
+ if (status != STATUS_INFO_LENGTH_MISMATCH) break;
+ }
+
+ switch (class)
+ {
+ case FileDirectoryInformation:
+ ok( status == STATUS_BUFFER_OVERFLOW, "%u: wrong status %x\n",
class, status );
+ ok( data_size == ((offsetof( FILE_DIRECTORY_INFORMATION, FileName[1] ) + 7)
& ~7),
+ "%u: wrong size %u\n", class, data_size );
+ break;
+ case FileFullDirectoryInformation:
+ ok( status == STATUS_BUFFER_OVERFLOW, "%u: wrong status %x\n",
class, status );
+ ok( data_size == ((offsetof( FILE_FULL_DIRECTORY_INFORMATION, FileName[1] ) +
7) & ~7),
+ "%u: wrong size %u\n", class, data_size );
+ break;
+ case FileBothDirectoryInformation:
+ ok( status == STATUS_BUFFER_OVERFLOW, "%u: wrong status %x\n",
class, status );
+ ok( data_size == ((offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] ) +
7) & ~7),
+ "%u: wrong size %u\n", class, data_size );
+ break;
+ case FileNamesInformation:
+ ok( status == STATUS_BUFFER_OVERFLOW, "%u: wrong status %x\n",
class, status );
+ ok( data_size == ((offsetof( FILE_NAMES_INFORMATION, FileName[1] ) + 7) &
~7),
+ "%u: wrong size %u\n", class, data_size );
+ break;
+ case FileIdBothDirectoryInformation:
+ ok( status == STATUS_BUFFER_OVERFLOW, "%u: wrong status %x\n",
class, status );
+ ok( data_size == ((offsetof( FILE_ID_BOTH_DIRECTORY_INFORMATION, FileName[1]
) + 7) & ~7),
+ "%u: wrong size %u\n", class, data_size );
+ break;
+ case FileIdFullDirectoryInformation:
+ ok( status == STATUS_BUFFER_OVERFLOW, "%u: wrong status %x\n",
class, status );
+ ok( data_size == ((offsetof( FILE_ID_FULL_DIRECTORY_INFORMATION, FileName[1]
) + 7) & ~7),
+ "%u: wrong size %u\n", class, data_size );
+ break;
+ case FileIdGlobalTxDirectoryInformation:
+ ok( status == STATUS_BUFFER_OVERFLOW, "%u: wrong status %x\n",
class, status );
+ ok( data_size == ((offsetof( FILE_ID_GLOBAL_TX_DIR_INFORMATION, FileName[1] )
+ 7) & ~7),
+ "%u: wrong size %u\n", class, data_size );
+ break;
+ case FileObjectIdInformation:
+ ok( status == STATUS_INVALID_INFO_CLASS, "%u: wrong status %x\n",
class, status );
+ ok( data_size == sizeof(FILE_OBJECTID_INFORMATION), "%u: wrong size
%u\n", class, data_size );
+ break;
+ case FileQuotaInformation:
+ ok( status == STATUS_INVALID_INFO_CLASS, "%u: wrong status %x\n",
class, status );
+ ok( data_size == sizeof(FILE_QUOTA_INFORMATION), "%u: wrong size
%u\n", class, data_size );
+ break;
+ case FileReparsePointInformation:
+ ok( status == STATUS_INVALID_INFO_CLASS, "%u: wrong status %x\n",
class, status );
+ ok( data_size == sizeof(FILE_REPARSE_POINT_INFORMATION), "%u: wrong size
%u\n", class, data_size );
+ break;
+ }
+ }
+}
+
+static void test_NtQueryDirectoryFile(void)
+{
+ OBJECT_ATTRIBUTES attr;
+ UNICODE_STRING ntdirname, mask;
char testdirA[MAX_PATH];
WCHAR testdirW[MAX_PATH];
int i;
+ IO_STATUS_BLOCK io;
+ WCHAR short_name[12];
+ UINT data_size;
+ BYTE data[8192];
+ FILE_BOTH_DIRECTORY_INFORMATION *next, *fbdi =
(FILE_BOTH_DIRECTORY_INFORMATION*)data;
+ FILE_POSITION_INFORMATION pos_info;
+ FILE_NAMES_INFORMATION *names;
+ const WCHAR *filename = fbdi->FileName;
+ NTSTATUS status;
+ HANDLE dirh;
/* Clean up from prior aborted run, if any, then set up test files */
ok(GetTempPathA(MAX_PATH, testdirA), "couldn't get temp dir\n");
strcat(testdirA, "NtQueryDirectoryFile.tmp");
- tear_down_attribute_test(testdirA);
- set_up_attribute_test(testdirA);
-
pRtlMultiByteToUnicodeN(testdirW, sizeof(testdirW), NULL, testdirA,
strlen(testdirA)+1);
+ tear_down_attribute_test(testdirW);
+ set_up_attribute_test(testdirW);
+
if (!pRtlDosPathNameToNtPathName_U(testdirW, &ntdirname, NULL, NULL))
{
ok(0, "RtlDosPathNametoNtPathName_U failed\n");
@@ -252,21 +481,250 @@ static void test_NtQueryDirectoryFile(void)
test_flags_NtQueryDirectoryFile(&attr, testdirA, NULL, TRUE, TRUE);
test_flags_NtQueryDirectoryFile(&attr, testdirA, NULL, TRUE, FALSE);
- for (i = 0; testfiles[i].name; i++)
+ for (i = 0; i < test_dir_count; i++)
{
- UNICODE_STRING mask;
-
- if (testfiles[i].nameW[0] == '.') continue; /* . and .. as masks are
broken on Windows */
- mask.Buffer = testfiles[i].nameW;
- mask.Length = mask.MaximumLength = lstrlenW(testfiles[i].nameW) * sizeof(WCHAR);
+ if (testfiles[i].name[0] == '.') continue; /* . and .. as masks are
broken on Windows */
+ mask.Buffer = testfiles[i].name;
+ mask.Length = mask.MaximumLength = lstrlenW(testfiles[i].name) * sizeof(WCHAR);
test_flags_NtQueryDirectoryFile(&attr, testdirA, &mask, FALSE, TRUE);
test_flags_NtQueryDirectoryFile(&attr, testdirA, &mask, FALSE, FALSE);
test_flags_NtQueryDirectoryFile(&attr, testdirA, &mask, TRUE, TRUE);
test_flags_NtQueryDirectoryFile(&attr, testdirA, &mask, TRUE, FALSE);
}
+ /* short path passed as mask */
+ status = pNtOpenFile(&dirh, SYNCHRONIZE | FILE_LIST_DIRECTORY, &attr,
&io, FILE_SHARE_READ,
+ FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT |
FILE_DIRECTORY_FILE);
+ ok(status == STATUS_SUCCESS, "failed to open dir '%s'\n",
testdirA);
+ if (status != STATUS_SUCCESS) {
+ skip("can't test if we can't open the directory\n");
+ return;
+ }
+ status = pNtQueryInformationFile( dirh, &io, &pos_info, sizeof(pos_info),
FilePositionInformation );
+ ok( status == STATUS_SUCCESS, "NtQueryInformationFile failed %x\n", status
);
+ ok( pos_info.CurrentByteOffset.QuadPart == 0, "wrong pos %s\n",
+ wine_dbgstr_longlong(pos_info.CurrentByteOffset.QuadPart));
+
+ pos_info.CurrentByteOffset.QuadPart = 0xbeef;
+ status = pNtSetInformationFile( dirh, &io, &pos_info, sizeof(pos_info),
FilePositionInformation );
+ ok( status == STATUS_SUCCESS, "NtQueryInformationFile failed %x\n", status
);
+
+ status = pNtQueryInformationFile( dirh, &io, &pos_info, sizeof(pos_info),
FilePositionInformation );
+ ok( status == STATUS_SUCCESS, "NtQueryInformationFile failed %x\n", status
);
+ ok( pos_info.CurrentByteOffset.QuadPart == 0xbeef, "wrong pos %s\n",
+ wine_dbgstr_longlong(pos_info.CurrentByteOffset.QuadPart));
+
+ mask.Buffer = testfiles[0].name;
+ mask.Length = mask.MaximumLength = lstrlenW(testfiles[0].name) * sizeof(WCHAR);
+ data_size = offsetof(FILE_BOTH_DIRECTORY_INFORMATION, FileName[256]);
+ U(io).Status = 0xdeadbeef;
+ status = pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size,
+ FileBothDirectoryInformation, TRUE, &mask,
FALSE);
+ ok(status == STATUS_SUCCESS, "failed to query directory; status %x\n",
status);
+ ok(U(io).Status == STATUS_SUCCESS, "failed to query directory; status
%x\n", U(io).Status);
+ ok(fbdi->ShortName[0], "ShortName is empty\n");
+
+ status = pNtQueryInformationFile( dirh, &io, &pos_info, sizeof(pos_info),
FilePositionInformation );
+ ok( status == STATUS_SUCCESS, "NtQueryInformationFile failed %x\n", status
);
+ ok( pos_info.CurrentByteOffset.QuadPart == 0xbeef, "wrong pos %s\n",
+ wine_dbgstr_longlong(pos_info.CurrentByteOffset.QuadPart) );
+
+ mask.Length = mask.MaximumLength = fbdi->ShortNameLength;
+ memcpy(short_name, fbdi->ShortName, mask.Length);
+ mask.Buffer = short_name;
+ U(io).Status = 0xdeadbeef;
+ U(io).Information = 0xdeadbeef;
+ status = pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size,
+ FileBothDirectoryInformation, TRUE, &mask, TRUE);
+ ok(status == STATUS_SUCCESS, "failed to query directory status %x\n",
status);
+ ok(U(io).Status == STATUS_SUCCESS, "failed to query directory status %x\n",
U(io).Status);
+ ok(U(io).Information == offsetof(FILE_BOTH_DIRECTORY_INFORMATION,
FileName[lstrlenW(testfiles[0].name)]),
+ "wrong info %lx\n", U(io).Information);
+ ok(fbdi->FileNameLength == lstrlenW(testfiles[0].name)*sizeof(WCHAR) &&
+ !memcmp(fbdi->FileName, testfiles[0].name, fbdi->FileNameLength),
+ "incorrect long file name: %s\n",
wine_dbgstr_wn(fbdi->FileName,
+ fbdi->FileNameLength/sizeof(WCHAR)));
+
+ status = pNtQueryInformationFile( dirh, &io, &pos_info, sizeof(pos_info),
FilePositionInformation );
+ ok( status == STATUS_SUCCESS, "NtQueryInformationFile failed %x\n", status
);
+ ok( pos_info.CurrentByteOffset.QuadPart == 0xbeef, "wrong pos %s\n",
+ wine_dbgstr_longlong(pos_info.CurrentByteOffset.QuadPart) );
+
+ /* tests with short buffer */
+ memset( data, 0x55, data_size );
+ U(io).Status = 0xdeadbeef;
+ U(io).Information = 0xdeadbeef;
+ data_size = offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] );
+ status = pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size,
+ FileBothDirectoryInformation, TRUE, &mask, TRUE);
+ ok( status == STATUS_BUFFER_OVERFLOW, "wrong status %x\n", status );
+ ok( U(io).Status == STATUS_BUFFER_OVERFLOW, "wrong status %x\n",
U(io).Status );
+ ok( U(io).Information == data_size || broken( U(io).Information == 0),
+ "wrong info %lx\n", U(io).Information );
+ ok( fbdi->NextEntryOffset == 0, "wrong offset %x\n",
fbdi->NextEntryOffset );
+ ok( fbdi->FileNameLength == lstrlenW(testfiles[0].name) * sizeof(WCHAR),
+ "wrong length %x\n", fbdi->FileNameLength );
+ ok( filename[0] == testfiles[0].name[0], "incorrect long file name: %s\n",
+ wine_dbgstr_wn(fbdi->FileName, fbdi->FileNameLength/sizeof(WCHAR)));
+ ok( filename[1] == 0x5555, "incorrect long file name: %s\n",
+ wine_dbgstr_wn(fbdi->FileName, fbdi->FileNameLength/sizeof(WCHAR)));
+
+ test_NtQueryDirectoryFile_classes( dirh, &mask );
+
+ /* mask may or may not be ignored when restarting the search */
+ pRtlInitUnicodeString( &mask, dummyW );
+ U(io).Status = 0xdeadbeef;
+ data_size = offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[256] );
+ status = pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size,
+ FileBothDirectoryInformation, TRUE, &mask, TRUE);
+ ok( status == STATUS_SUCCESS || status == STATUS_NO_MORE_FILES, "wrong status
%x\n", status );
+ ok( U(io).Status == status, "wrong status %x / %x\n", U(io).Status, status
);
+ if (!status)
+ ok( fbdi->FileNameLength == lstrlenW(testfiles[0].name)*sizeof(WCHAR)
&&
+ !memcmp(fbdi->FileName, testfiles[0].name, fbdi->FileNameLength),
+ "incorrect long file name: %s\n",
+ wine_dbgstr_wn(fbdi->FileName, fbdi->FileNameLength/sizeof(WCHAR)));
+
+ pNtClose(dirh);
+
+ status = pNtOpenFile(&dirh, SYNCHRONIZE | FILE_LIST_DIRECTORY, &attr,
&io, FILE_SHARE_READ,
+ FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT |
FILE_DIRECTORY_FILE);
+ ok(status == STATUS_SUCCESS, "failed to open dir '%s'\n",
testdirA);
+
+ memset( data, 0x55, data_size );
+ data_size = sizeof(data);
+ U(io).Status = 0xdeadbeef;
+ U(io).Information = 0xdeadbeef;
+ status = pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size,
+ FileBothDirectoryInformation, FALSE, NULL, TRUE);
+ ok(status == STATUS_SUCCESS, "wrong status %x\n", status);
+ ok(U(io).Status == STATUS_SUCCESS, "wrong status %x\n", U(io).Status);
+ ok(U(io).Information > 0 && U(io).Information < data_size, "wrong
info %lx\n", U(io).Information);
+ ok( fbdi->NextEntryOffset == ((offsetof( FILE_BOTH_DIRECTORY_INFORMATION,
FileName[1] ) + 7) & ~7),
+ "wrong offset %x\n", fbdi->NextEntryOffset );
+ ok( fbdi->FileNameLength == sizeof(WCHAR), "wrong length %x\n",
fbdi->FileNameLength );
+ ok( fbdi->FileName[0] == '.', "incorrect long file name: %s\n",
+ wine_dbgstr_wn(fbdi->FileName, fbdi->FileNameLength/sizeof(WCHAR)));
+ next = (FILE_BOTH_DIRECTORY_INFORMATION *)(data + fbdi->NextEntryOffset);
+ ok( next->NextEntryOffset == ((offsetof( FILE_BOTH_DIRECTORY_INFORMATION,
FileName[2] ) + 7) & ~7),
+ "wrong offset %x\n", next->NextEntryOffset );
+ ok( next->FileNameLength == 2 * sizeof(WCHAR), "wrong length %x\n",
next->FileNameLength );
+ filename = next->FileName;
+ ok( filename[0] == '.' && filename[1] == '.', "incorrect
long file name: %s\n",
+ wine_dbgstr_wn(next->FileName, next->FileNameLength/sizeof(WCHAR)));
+
+ data_size = fbdi->NextEntryOffset + offsetof( FILE_BOTH_DIRECTORY_INFORMATION,
FileName[1] ),
+ memset( data, 0x55, data_size );
+ U(io).Status = 0xdeadbeef;
+ U(io).Information = 0xdeadbeef;
+ status = pNtQueryDirectoryFile( dirh, 0, NULL, NULL, &io, data, data_size,
+ FileBothDirectoryInformation, FALSE, NULL, TRUE );
+ ok( status == STATUS_SUCCESS, "wrong status %x\n", status );
+ ok( U(io).Status == STATUS_SUCCESS, "wrong status %x\n", U(io).Status );
+ ok( U(io).Information == offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] ),
+ "wrong info %lx\n", U(io).Information );
+ ok( fbdi->NextEntryOffset == 0, "wrong offset %x\n",
fbdi->NextEntryOffset );
+ ok( fbdi->FileNameLength == sizeof(WCHAR), "wrong length %x\n",
fbdi->FileNameLength );
+ ok( fbdi->FileName[0] == '.', "incorrect long file name: %s\n",
+ wine_dbgstr_wn(fbdi->FileName, fbdi->FileNameLength/sizeof(WCHAR)));
+ next = (FILE_BOTH_DIRECTORY_INFORMATION *)&fbdi->FileName[1];
+ ok( next->NextEntryOffset == 0x55555555, "wrong offset %x\n",
next->NextEntryOffset );
+
+ data_size = fbdi->NextEntryOffset + offsetof( FILE_BOTH_DIRECTORY_INFORMATION,
FileName[2] ),
+ memset( data, 0x55, data_size );
+ U(io).Status = 0xdeadbeef;
+ U(io).Information = 0xdeadbeef;
+ status = pNtQueryDirectoryFile( dirh, 0, NULL, NULL, &io, data, data_size,
+ FileBothDirectoryInformation, FALSE, NULL, TRUE );
+ ok( status == STATUS_SUCCESS, "wrong status %x\n", status );
+ ok( U(io).Status == STATUS_SUCCESS, "wrong status %x\n", U(io).Status );
+ ok( U(io).Information == offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] ),
+ "wrong info %lx\n", U(io).Information );
+ ok( fbdi->NextEntryOffset == 0, "wrong offset %x\n",
fbdi->NextEntryOffset );
+
+ data_size = ((offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] ) + 7) & ~7)
+
+ offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[2] );
+ memset( data, 0x55, data_size );
+ U(io).Status = 0xdeadbeef;
+ U(io).Information = 0xdeadbeef;
+ status = pNtQueryDirectoryFile( dirh, 0, NULL, NULL, &io, data, data_size,
+ FileBothDirectoryInformation, FALSE, NULL, TRUE );
+ ok( status == STATUS_SUCCESS, "wrong status %x\n", status );
+ ok( U(io).Status == STATUS_SUCCESS, "wrong status %x\n", U(io).Status );
+ ok( U(io).Information == data_size, "wrong info %lx / %x\n",
U(io).Information, data_size );
+ ok( fbdi->NextEntryOffset == ((offsetof( FILE_BOTH_DIRECTORY_INFORMATION,
FileName[1] ) + 7) & ~7),
+ "wrong offset %x\n", fbdi->NextEntryOffset );
+ ok( fbdi->FileNameLength == sizeof(WCHAR), "wrong length %x\n",
fbdi->FileNameLength );
+ ok( fbdi->FileName[0] == '.', "incorrect long file name: %s\n",
+ wine_dbgstr_wn(fbdi->FileName, fbdi->FileNameLength/sizeof(WCHAR)));
+ next = (FILE_BOTH_DIRECTORY_INFORMATION *)(data + fbdi->NextEntryOffset);
+ ok( next->NextEntryOffset == 0, "wrong offset %x\n",
next->NextEntryOffset );
+ ok( next->FileNameLength == 2 * sizeof(WCHAR), "wrong length %x\n",
next->FileNameLength );
+ filename = next->FileName;
+ ok( filename[0] == '.' && filename[1] == '.', "incorrect
long file name: %s\n",
+ wine_dbgstr_wn(next->FileName, next->FileNameLength/sizeof(WCHAR)));
+
+ data_size = ((offsetof( FILE_NAMES_INFORMATION, FileName[1] ) + 7) & ~7) +
+ offsetof( FILE_NAMES_INFORMATION, FileName[2] );
+ memset( data, 0x55, data_size );
+ U(io).Status = 0xdeadbeef;
+ U(io).Information = 0xdeadbeef;
+ status = pNtQueryDirectoryFile( dirh, 0, NULL, NULL, &io, data, data_size,
+ FileNamesInformation, FALSE, NULL, TRUE );
+ ok( status == STATUS_SUCCESS, "wrong status %x\n", status );
+ ok( U(io).Status == STATUS_SUCCESS, "wrong status %x\n", U(io).Status );
+ ok( U(io).Information == data_size, "wrong info %lx / %x\n",
U(io).Information, data_size );
+ names = (FILE_NAMES_INFORMATION *)data;
+ ok( names->NextEntryOffset == ((offsetof( FILE_NAMES_INFORMATION, FileName[1] ) +
7) & ~7),
+ "wrong offset %x\n", names->NextEntryOffset );
+ ok( names->FileNameLength == sizeof(WCHAR), "wrong length %x\n",
names->FileNameLength );
+ ok( names->FileName[0] == '.', "incorrect long file name:
%s\n",
+ wine_dbgstr_wn(names->FileName, names->FileNameLength/sizeof(WCHAR)));
+ names = (FILE_NAMES_INFORMATION *)(data + names->NextEntryOffset);
+ ok( names->NextEntryOffset == 0, "wrong offset %x\n",
names->NextEntryOffset );
+ ok( names->FileNameLength == 2 * sizeof(WCHAR), "wrong length %x\n",
names->FileNameLength );
+ filename = names->FileName;
+ ok( filename[0] == '.' && filename[1] == '.', "incorrect
long file name: %s\n",
+ wine_dbgstr_wn(names->FileName, names->FileNameLength/sizeof(WCHAR)));
+
+ pNtClose(dirh);
+
+ /* create new handle to change mask */
+ status = pNtOpenFile(&dirh, SYNCHRONIZE | FILE_LIST_DIRECTORY, &attr,
&io, FILE_SHARE_READ,
+ FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT |
FILE_DIRECTORY_FILE);
+ ok(status == STATUS_SUCCESS, "failed to open dir '%s'\n",
testdirA);
+
+ pRtlInitUnicodeString( &mask, dummyW );
+ U(io).Status = 0xdeadbeef;
+ data_size = sizeof(data);
+ status = pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size,
+ FileBothDirectoryInformation, TRUE, &mask, TRUE);
+ ok(status == STATUS_NO_SUCH_FILE, "wrong status %x\n", status);
+ ok(U(io).Status == 0xdeadbeef, "wrong status %x\n", U(io).Status);
+
+ U(io).Status = 0xdeadbeef;
+ status = pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size,
+ FileBothDirectoryInformation, TRUE, NULL, FALSE);
+ ok(status == STATUS_NO_MORE_FILES, "wrong status %x\n", status);
+ ok(U(io).Status == STATUS_NO_MORE_FILES, "wrong status %x\n",
U(io).Status);
+
+ U(io).Status = 0xdeadbeef;
+ status = pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size,
+ FileBothDirectoryInformation, TRUE, NULL, TRUE);
+ ok(status == STATUS_NO_MORE_FILES, "wrong status %x\n", status);
+ ok(U(io).Status == STATUS_NO_MORE_FILES, "wrong status %x\n",
U(io).Status);
+
+ pNtClose(dirh);
+
+ U(io).Status = 0xdeadbeef;
+ status = pNtQueryDirectoryFile( (HANDLE)0xbeef, 0, NULL, NULL, &io, data,
data_size,
+ FileBothDirectoryInformation, TRUE, NULL, TRUE );
+ ok(status == STATUS_INVALID_HANDLE, "wrong status %x\n", status);
+ ok(U(io).Status == 0xdeadbeef, "wrong status %x\n", U(io).Status);
+
done:
- tear_down_attribute_test(testdirA);
+ test_directory_sort( testdirW );
+ tear_down_attribute_test( testdirW );
pRtlFreeUnicodeString(&ntdirname);
}
@@ -403,6 +861,8 @@ static void test_redirection(void)
ok( status == STATUS_ACCESS_VIOLATION, "RtlWow64EnableFsRedirectionEx failed
with status %x\n", status );
status = pRtlWow64EnableFsRedirectionEx( TRUE, (void*)1 );
ok( status == STATUS_ACCESS_VIOLATION, "RtlWow64EnableFsRedirectionEx failed
with status %x\n", status );
+ status = pRtlWow64EnableFsRedirectionEx( TRUE, (void*)0xDEADBEEF );
+ ok( status == STATUS_ACCESS_VIOLATION, "RtlWow64EnableFsRedirectionEx failed
with status %x\n", status );
status = pRtlWow64EnableFsRedirection( FALSE );
ok( !status, "RtlWow64EnableFsRedirectionEx failed status %x\n", status );
@@ -415,6 +875,7 @@ static void test_redirection(void)
START_TEST(directory)
{
+ WCHAR sysdir[MAX_PATH];
HMODULE hntdll = GetModuleHandleA("ntdll.dll");
if (!hntdll)
{
@@ -425,14 +886,19 @@ START_TEST(directory)
pNtClose = (void *)GetProcAddress(hntdll, "NtClose");
pNtOpenFile = (void *)GetProcAddress(hntdll, "NtOpenFile");
pNtQueryDirectoryFile = (void *)GetProcAddress(hntdll,
"NtQueryDirectoryFile");
+ pNtQueryInformationFile = (void *)GetProcAddress(hntdll,
"NtQueryInformationFile");
+ pNtSetInformationFile = (void *)GetProcAddress(hntdll,
"NtSetInformationFile");
pRtlCreateUnicodeStringFromAsciiz = (void *)GetProcAddress(hntdll,
"RtlCreateUnicodeStringFromAsciiz");
pRtlDosPathNameToNtPathName_U = (void *)GetProcAddress(hntdll,
"RtlDosPathNameToNtPathName_U");
pRtlInitUnicodeString = (void *)GetProcAddress(hntdll,
"RtlInitUnicodeString");
pRtlFreeUnicodeString = (void *)GetProcAddress(hntdll,
"RtlFreeUnicodeString");
+ pRtlCompareUnicodeString = (void *)GetProcAddress(hntdll,
"RtlCompareUnicodeString");
pRtlMultiByteToUnicodeN = (void
*)GetProcAddress(hntdll,"RtlMultiByteToUnicodeN");
pRtlWow64EnableFsRedirection = (void
*)GetProcAddress(hntdll,"RtlWow64EnableFsRedirection");
pRtlWow64EnableFsRedirectionEx = (void
*)GetProcAddress(hntdll,"RtlWow64EnableFsRedirectionEx");
+ GetSystemDirectoryW( sysdir, MAX_PATH );
+ test_directory_sort( sysdir );
test_NtQueryDirectoryFile();
test_NtQueryDirectoryFile_case();
test_redirection();
diff --git a/modules/rostests/winetests/ntdll/exception.c
b/modules/rostests/winetests/ntdll/exception.c
index 4bd400bb15..8dc2d90482 100644
--- a/modules/rostests/winetests/ntdll/exception.c
+++ b/modules/rostests/winetests/ntdll/exception.c
@@ -39,11 +39,11 @@
static void *code_mem;
-static struct _TEB * (WINAPI *pNtCurrentTeb)(void);
static NTSTATUS (WINAPI *pNtGetContextThread)(HANDLE,CONTEXT*);
static NTSTATUS (WINAPI *pNtSetContextThread)(HANDLE,CONTEXT*);
static NTSTATUS (WINAPI *pRtlRaiseException)(EXCEPTION_RECORD *rec);
static PVOID (WINAPI *pRtlUnwind)(PVOID, PVOID, PEXCEPTION_RECORD, PVOID);
+static VOID (WINAPI *pRtlCaptureContext)(CONTEXT*);
static PVOID (WINAPI *pRtlAddVectoredExceptionHandler)(ULONG first,
PVECTORED_EXCEPTION_HANDLER func);
static ULONG (WINAPI *pRtlRemoveVectoredExceptionHandler)(PVOID handler);
static PVOID (WINAPI *pRtlAddVectoredContinueHandler)(ULONG first,
PVECTORED_EXCEPTION_HANDLER func);
@@ -56,10 +56,72 @@ static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
static NTSTATUS (WINAPI *pNtClose)(HANDLE);
#if defined(__x86_64__)
+typedef struct
+{
+ ULONG Count;
+ struct
+ {
+ ULONG BeginAddress;
+ ULONG EndAddress;
+ ULONG HandlerAddress;
+ ULONG JumpTarget;
+ } ScopeRecord[1];
+} SCOPE_TABLE;
+
+typedef struct
+{
+ ULONG64 ControlPc;
+ ULONG64 ImageBase;
+ PRUNTIME_FUNCTION FunctionEntry;
+ ULONG64 EstablisherFrame;
+ ULONG64 TargetIp;
+ PCONTEXT ContextRecord;
+ void* /*PEXCEPTION_ROUTINE*/ LanguageHandler;
+ PVOID HandlerData;
+ PUNWIND_HISTORY_TABLE HistoryTable;
+ ULONG ScopeIndex;
+} DISPATCHER_CONTEXT;
+
+typedef struct _SETJMP_FLOAT128
+{
+ unsigned __int64 DECLSPEC_ALIGN(16) Part[2];
+} SETJMP_FLOAT128;
+
+typedef struct _JUMP_BUFFER
+{
+ unsigned __int64 Frame;
+ unsigned __int64 Rbx;
+ unsigned __int64 Rsp;
+ unsigned __int64 Rbp;
+ unsigned __int64 Rsi;
+ unsigned __int64 Rdi;
+ unsigned __int64 R12;
+ unsigned __int64 R13;
+ unsigned __int64 R14;
+ unsigned __int64 R15;
+ unsigned __int64 Rip;
+ unsigned __int64 Spare;
+ SETJMP_FLOAT128 Xmm6;
+ SETJMP_FLOAT128 Xmm7;
+ SETJMP_FLOAT128 Xmm8;
+ SETJMP_FLOAT128 Xmm9;
+ SETJMP_FLOAT128 Xmm10;
+ SETJMP_FLOAT128 Xmm11;
+ SETJMP_FLOAT128 Xmm12;
+ SETJMP_FLOAT128 Xmm13;
+ SETJMP_FLOAT128 Xmm14;
+ SETJMP_FLOAT128 Xmm15;
+} _JUMP_BUFFER;
+
static BOOLEAN (CDECL *pRtlAddFunctionTable)(RUNTIME_FUNCTION*, DWORD, DWORD64);
static BOOLEAN (CDECL *pRtlDeleteFunctionTable)(RUNTIME_FUNCTION*);
static BOOLEAN (CDECL *pRtlInstallFunctionTableCallback)(DWORD64, DWORD64, DWORD,
PGET_RUNTIME_FUNCTION_CALLBACK, PVOID, PCWSTR);
static PRUNTIME_FUNCTION (WINAPI *pRtlLookupFunctionEntry)(ULONG64, ULONG64*,
UNWIND_HISTORY_TABLE*);
+static EXCEPTION_DISPOSITION (WINAPI *p__C_specific_handler)(EXCEPTION_RECORD*, ULONG64,
CONTEXT*, DISPATCHER_CONTEXT*);
+static VOID (WINAPI *pRtlCaptureContext)(CONTEXT*);
+static VOID (CDECL *pRtlRestoreContext)(CONTEXT*, EXCEPTION_RECORD*);
+static VOID (CDECL *pRtlUnwindEx)(VOID*, VOID*, EXCEPTION_RECORD*, VOID*, CONTEXT*,
UNWIND_HISTORY_TABLE*);
+static int (CDECL *p_setjmp)(_JUMP_BUFFER*);
#endif
#ifdef __i386__
@@ -221,6 +283,11 @@ static const struct exception
{ { 0xf1, 0x90, 0xc3 }, /* icebp; nop; ret */
1, 1, FALSE, STATUS_SINGLE_STEP, 0 },
+ { { 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, /* mov $0xb8b8b8b8, %eax */
+ 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, /* mov $0xb9b9b9b9, %ecx */
+ 0xba, 0xba, 0xba, 0xba, 0xba, /* mov $0xbabababa, %edx */
+ 0xcd, 0x2d, 0xc3 }, /* int $0x2d; ret */
+ 17, 0, FALSE, STATUS_BREAKPOINT, 3, { 0xb8b8b8b8, 0xb9b9b9b9, 0xbabababa } },
};
static int got_exception;
@@ -238,16 +305,16 @@ static void run_exception_test(void *handler, const void* context,
DWORD oldaccess, oldaccess2;
exc_frame.frame.Handler = handler;
- exc_frame.frame.Prev = pNtCurrentTeb()->Tib.ExceptionList;
+ exc_frame.frame.Prev = NtCurrentTeb()->Tib.ExceptionList;
exc_frame.context = context;
memcpy(code_mem, code, code_size);
if(access)
VirtualProtect(code_mem, code_size, access, &oldaccess);
- pNtCurrentTeb()->Tib.ExceptionList = &exc_frame.frame;
+ NtCurrentTeb()->Tib.ExceptionList = &exc_frame.frame;
func();
- pNtCurrentTeb()->Tib.ExceptionList = exc_frame.frame.Prev;
+ NtCurrentTeb()->Tib.ExceptionList = exc_frame.frame.Prev;
if(access)
VirtualProtect(code_mem, code_size, oldaccess, &oldaccess2);
@@ -263,7 +330,7 @@ static LONG CALLBACK
rtlraiseexception_vectored_handler(EXCEPTION_POINTERS *Exce
ok(rec->ExceptionAddress == (char *)code_mem + 0xb, "ExceptionAddress at %p
instead of %p\n",
rec->ExceptionAddress, (char *)code_mem + 0xb);
- if (pNtCurrentTeb()->Peb->BeingDebugged)
+ if (NtCurrentTeb()->Peb->BeingDebugged)
ok((void *)context->Eax == pRtlRaiseException ||
broken( is_wow64 && context->Eax == 0xf00f00f1 ), /* broken on
vista */
"debugger managed to modify Eax to %x should be %p\n",
@@ -360,11 +427,11 @@ static void run_rtlraiseexception_test(DWORD exceptioncode)
record.NumberParameters = 0;
frame.Handler = rtlraiseexception_handler;
- frame.Prev = pNtCurrentTeb()->Tib.ExceptionList;
+ frame.Prev = NtCurrentTeb()->Tib.ExceptionList;
memcpy(code_mem, call_one_arg_code, sizeof(call_one_arg_code));
- pNtCurrentTeb()->Tib.ExceptionList = &frame;
+ NtCurrentTeb()->Tib.ExceptionList = &frame;
if (have_vectored_api)
{
vectored_handler = pRtlAddVectoredExceptionHandler(TRUE,
&rtlraiseexception_vectored_handler);
@@ -377,7 +444,7 @@ static void run_rtlraiseexception_test(DWORD exceptioncode)
if (have_vectored_api)
pRtlRemoveVectoredExceptionHandler(vectored_handler);
- pNtCurrentTeb()->Tib.ExceptionList = frame.Prev;
+ NtCurrentTeb()->Tib.ExceptionList = frame.Prev;
}
static void test_rtlraiseexception(void)
@@ -445,37 +512,37 @@ static void test_unwind(void)
/* add first unwind handler */
frame1->Handler = unwind_handler;
- frame1->Prev = pNtCurrentTeb()->Tib.ExceptionList;
- pNtCurrentTeb()->Tib.ExceptionList = frame1;
+ frame1->Prev = NtCurrentTeb()->Tib.ExceptionList;
+ NtCurrentTeb()->Tib.ExceptionList = frame1;
/* add second unwind handler */
frame2->Handler = unwind_handler;
- frame2->Prev = pNtCurrentTeb()->Tib.ExceptionList;
- pNtCurrentTeb()->Tib.ExceptionList = frame2;
+ frame2->Prev = NtCurrentTeb()->Tib.ExceptionList;
+ NtCurrentTeb()->Tib.ExceptionList = frame2;
/* test unwind to current frame */
unwind_expected_eax = 0xDEAD0000;
retval = func(pRtlUnwind, frame2, NULL, 0xDEAD0000);
ok(retval == 0xDEAD0000, "RtlUnwind returned eax %08x instead of %08x\n",
retval, 0xDEAD0000);
- ok(pNtCurrentTeb()->Tib.ExceptionList == frame2, "Exception record points to
%p instead of %p\n",
- pNtCurrentTeb()->Tib.ExceptionList, frame2);
+ ok(NtCurrentTeb()->Tib.ExceptionList == frame2, "Exception record points to
%p instead of %p\n",
+ NtCurrentTeb()->Tib.ExceptionList, frame2);
/* unwind to frame1 */
unwind_expected_eax = 0xDEAD0000;
retval = func(pRtlUnwind, frame1, NULL, 0xDEAD0000);
ok(retval == 0xDEAD0001, "RtlUnwind returned eax %08x instead of %08x\n",
retval, 0xDEAD0001);
- ok(pNtCurrentTeb()->Tib.ExceptionList == frame1, "Exception record points to
%p instead of %p\n",
- pNtCurrentTeb()->Tib.ExceptionList, frame1);
+ ok(NtCurrentTeb()->Tib.ExceptionList == frame1, "Exception record points to
%p instead of %p\n",
+ NtCurrentTeb()->Tib.ExceptionList, frame1);
/* restore original handler */
- pNtCurrentTeb()->Tib.ExceptionList = frame1->Prev;
+ NtCurrentTeb()->Tib.ExceptionList = frame1->Prev;
}
static DWORD handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher )
{
const struct exception *except = *(const struct exception **)(frame + 1);
- unsigned int i, entry = except - exceptions;
+ unsigned int i, parameter_count, entry = except - exceptions;
got_exception++;
trace( "exception %u: %x flags:%x addr:%p\n",
@@ -484,20 +551,23 @@ static DWORD handler( EXCEPTION_RECORD *rec,
EXCEPTION_REGISTRATION_RECORD *fram
ok( rec->ExceptionCode == except->status ||
(except->alt_status != 0 && rec->ExceptionCode ==
except->alt_status),
"%u: Wrong exception code %x/%x\n", entry, rec->ExceptionCode,
except->status );
- ok( rec->ExceptionAddress == (char*)code_mem + except->offset,
- "%u: Wrong exception address %p/%p\n", entry,
- rec->ExceptionAddress, (char*)code_mem + except->offset );
-
- if (except->alt_status == 0 || rec->ExceptionCode != except->alt_status)
- {
- ok( rec->NumberParameters == except->nb_params,
- "%u: Wrong number of parameters %u/%u\n", entry,
rec->NumberParameters, except->nb_params );
- }
+ ok( context->Eip == (DWORD_PTR)code_mem + except->offset,
+ "%u: Unexpected eip %#x/%#lx\n", entry,
+ context->Eip, (DWORD_PTR)code_mem + except->offset );
+ ok( rec->ExceptionAddress == (char*)context->Eip ||
+ (rec->ExceptionCode == STATUS_BREAKPOINT && rec->ExceptionAddress
== (char*)context->Eip + 1),
+ "%u: Unexpected exception address %p/%p\n", entry,
+ rec->ExceptionAddress, (char*)context->Eip );
+
+ if (except->status == STATUS_BREAKPOINT && is_wow64)
+ parameter_count = 1;
+ else if (except->alt_status == 0 || rec->ExceptionCode !=
except->alt_status)
+ parameter_count = except->nb_params;
else
- {
- ok( rec->NumberParameters == except->alt_nb_params,
- "%u: Wrong number of parameters %u/%u\n", entry,
rec->NumberParameters, except->nb_params );
- }
+ parameter_count = except->alt_nb_params;
+
+ ok( rec->NumberParameters == parameter_count,
+ "%u: Unexpected parameter count %u/%u\n", entry,
rec->NumberParameters, parameter_count );
/* Most CPUs (except Intel Core apparently) report a segment limit violation */
/* instead of page faults for accesses beyond 0xffffffff */
@@ -532,7 +602,7 @@ static DWORD handler( EXCEPTION_RECORD *rec,
EXCEPTION_REGISTRATION_RECORD *fram
skip_params:
/* don't handle exception if it's not the address we expected */
- if (rec->ExceptionAddress != (char*)code_mem + except->offset) return
ExceptionContinueSearch;
+ if (context->Eip != (DWORD_PTR)code_mem + except->offset) return
ExceptionContinueSearch;
context->Eip += except->length;
return ExceptionContinueExecution;
@@ -754,12 +824,21 @@ static DWORD int3_handler( EXCEPTION_RECORD *rec,
EXCEPTION_REGISTRATION_RECORD
static const BYTE int3_code[] = { 0xCC, 0xc3 }; /* int 3, ret */
+static DWORD WINAPI hw_reg_exception_thread( void *arg )
+{
+ int expect = (ULONG_PTR)arg;
+ got_exception = 0;
+ run_exception_test( bpx_handler, NULL, dummy_code, sizeof(dummy_code), 0 );
+ ok( got_exception == expect, "expected %u exceptions, got %d\n", expect,
got_exception );
+ return 0;
+}
static void test_exceptions(void)
{
CONTEXT ctx;
NTSTATUS res;
struct dbgreg_test dreg_test;
+ HANDLE h;
if (!pNtGetContextThread || !pNtSetContextThread)
{
@@ -813,6 +892,33 @@ static void test_exceptions(void)
/* test int3 handling */
run_exception_test(int3_handler, NULL, int3_code, sizeof(int3_code), 0);
+
+ /* test that hardware breakpoints are not inherited by created threads */
+ res = pNtSetContextThread( GetCurrentThread(), &ctx );
+ ok( res == STATUS_SUCCESS, "NtSetContextThread failed with %x\n", res );
+
+ h = CreateThread( NULL, 0, hw_reg_exception_thread, 0, 0, NULL );
+ WaitForSingleObject( h, 10000 );
+ CloseHandle( h );
+
+ h = CreateThread( NULL, 0, hw_reg_exception_thread, (void *)4, CREATE_SUSPENDED, NULL
);
+ ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
+ res = pNtGetContextThread( h, &ctx );
+ ok( res == STATUS_SUCCESS, "NtGetContextThread failed with %x\n", res );
+ ok( ctx.Dr0 == 0, "dr0 %x\n", ctx.Dr0 );
+ ok( ctx.Dr7 == 0, "dr7 %x\n", ctx.Dr7 );
+ ctx.Dr0 = (DWORD)code_mem;
+ ctx.Dr7 = 3;
+ res = pNtSetContextThread( h, &ctx );
+ ok( res == STATUS_SUCCESS, "NtSetContextThread failed with %x\n", res );
+ ResumeThread( h );
+ WaitForSingleObject( h, 10000 );
+ CloseHandle( h );
+
+ ctx.Dr0 = 0;
+ ctx.Dr7 = 0;
+ res = pNtSetContextThread( GetCurrentThread(), &ctx );
+ ok( res == STATUS_SUCCESS, "NtSetContextThread failed with %x\n", res );
}
static void test_debugger(void)
@@ -855,7 +961,7 @@ static void test_debugger(void)
if (de.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT)
{
- if(de.u.CreateProcessInfo.lpBaseOfImage !=
pNtCurrentTeb()->Peb->ImageBaseAddress)
+ if(de.u.CreateProcessInfo.lpBaseOfImage !=
NtCurrentTeb()->Peb->ImageBaseAddress)
{
skip("child process loaded at different address, terminating
it\n");
pNtTerminateProcess(pi.hProcess, 0);
@@ -940,6 +1046,24 @@ static void test_debugger(void)
}
}
else if (stage == 7 || stage == 8)
+ {
+ ok(de.u.Exception.ExceptionRecord.ExceptionCode ==
EXCEPTION_BREAKPOINT,
+ "expected EXCEPTION_BREAKPOINT, got %08x\n",
de.u.Exception.ExceptionRecord.ExceptionCode);
+ ok((char *)ctx.Eip == (char *)code_mem_address + 0x1d,
+ "expected Eip = %p, got 0x%x\n", (char
*)code_mem_address + 0x1d, ctx.Eip);
+
+ if (stage == 8) continuestatus = DBG_EXCEPTION_NOT_HANDLED;
+ }
+ else if (stage == 9 || stage == 10)
+ {
+ ok(de.u.Exception.ExceptionRecord.ExceptionCode ==
EXCEPTION_BREAKPOINT,
+ "expected EXCEPTION_BREAKPOINT, got %08x\n",
de.u.Exception.ExceptionRecord.ExceptionCode);
+ ok((char *)ctx.Eip == (char *)code_mem_address + 2,
+ "expected Eip = %p, got 0x%x\n", (char
*)code_mem_address + 2, ctx.Eip);
+
+ if (stage == 10) continuestatus = DBG_EXCEPTION_NOT_HANDLED;
+ }
+ else if (stage == 11 || stage == 12)
{
ok(de.u.Exception.ExceptionRecord.ExceptionCode ==
EXCEPTION_INVALID_HANDLE,
"unexpected exception code %08x, expected %08x\n",
de.u.Exception.ExceptionRecord.ExceptionCode,
@@ -947,7 +1071,7 @@ static void test_debugger(void)
ok(de.u.Exception.ExceptionRecord.NumberParameters == 0,
"unexpected number of parameters %d, expected 0\n",
de.u.Exception.ExceptionRecord.NumberParameters);
- if (stage == 8) continuestatus = DBG_EXCEPTION_NOT_HANDLED;
+ if (stage == 12) continuestatus = DBG_EXCEPTION_NOT_HANDLED;
}
else
ok(FALSE, "unexpected stage %x\n", stage);
@@ -1035,22 +1159,25 @@ static DWORD simd_fault_handler( EXCEPTION_RECORD *rec,
EXCEPTION_REGISTRATION_R
context->Eip += 3; /* skip addps */
return ExceptionContinueExecution;
}
-
- /* stage 2 - divide by zero fault */
- if( rec->ExceptionCode == EXCEPTION_ILLEGAL_INSTRUCTION)
- skip("system doesn't support SIMD exceptions\n");
- else {
- ok( rec->ExceptionCode == STATUS_FLOAT_MULTIPLE_TRAPS,
- "exception code: %#x, should be %#x\n",
- rec->ExceptionCode, STATUS_FLOAT_MULTIPLE_TRAPS);
- ok( rec->NumberParameters == 1 || broken(is_wow64 &&
rec->NumberParameters == 2),
- "# of params: %i, should be 1\n",
- rec->NumberParameters);
- if( rec->NumberParameters == 1 )
- ok( rec->ExceptionInformation[0] == 0, "param #1: %lx, should be
0\n", rec->ExceptionInformation[0]);
+ else if ( *stage == 2 || *stage == 3 ) {
+ /* stage 2 - divide by zero fault */
+ /* stage 3 - invalid operation fault */
+ if( rec->ExceptionCode == EXCEPTION_ILLEGAL_INSTRUCTION)
+ skip("system doesn't support SIMD exceptions\n");
+ else {
+ ok( rec->ExceptionCode == STATUS_FLOAT_MULTIPLE_TRAPS,
+ "exception code: %#x, should be %#x\n",
+ rec->ExceptionCode, STATUS_FLOAT_MULTIPLE_TRAPS);
+ ok( rec->NumberParameters == 1 || broken(is_wow64 &&
rec->NumberParameters == 2),
+ "# of params: %i, should be 1\n",
+ rec->NumberParameters);
+ if( rec->NumberParameters == 1 )
+ ok( rec->ExceptionInformation[0] == 0, "param #1: %lx, should be
0\n", rec->ExceptionInformation[0]);
+ }
+ context->Eip += 3; /* skip divps */
}
-
- context->Eip += 3; /* skip divps */
+ else
+ ok(FALSE, "unexpected stage %x\n", *stage);
return ExceptionContinueExecution;
}
@@ -1058,6 +1185,7 @@ static DWORD simd_fault_handler( EXCEPTION_RECORD *rec,
EXCEPTION_REGISTRATION_R
static const BYTE simd_exception_test[] = {
0x83, 0xec, 0x4, /* sub $0x4, %esp */
0x0f, 0xae, 0x1c, 0x24, /* stmxcsr (%esp) */
+ 0x8b, 0x04, 0x24, /* mov (%esp),%eax * store mxcsr */
0x66, 0x81, 0x24, 0x24, 0xff, 0xfd, /* andw $0xfdff,(%esp) * enable divide by */
0x0f, 0xae, 0x14, 0x24, /* ldmxcsr (%esp) * zero exceptions */
0x6a, 0x01, /* push $0x1 */
@@ -1068,7 +1196,22 @@ static const BYTE simd_exception_test[] = {
0x0f, 0x57, 0xc0, /* xorps %xmm0,%xmm0 * clear divisor */
0x0f, 0x5e, 0xc8, /* divps %xmm0,%xmm1 * generate fault */
0x83, 0xc4, 0x10, /* add $0x10,%esp */
- 0x66, 0x81, 0x0c, 0x24, 0x00, 0x02, /* orw $0x200,(%esp) * disable exceptions */
+ 0x89, 0x04, 0x24, /* mov %eax,(%esp) * restore to old mxcsr
*/
+ 0x0f, 0xae, 0x14, 0x24, /* ldmxcsr (%esp) */
+ 0x83, 0xc4, 0x04, /* add $0x4,%esp */
+ 0xc3, /* ret */
+};
+
+static const BYTE simd_exception_test2[] = {
+ 0x83, 0xec, 0x4, /* sub $0x4, %esp */
+ 0x0f, 0xae, 0x1c, 0x24, /* stmxcsr (%esp) */
+ 0x8b, 0x04, 0x24, /* mov (%esp),%eax * store mxcsr */
+ 0x66, 0x81, 0x24, 0x24, 0x7f, 0xff, /* andw $0xff7f,(%esp) * enable invalid
*/
+ 0x0f, 0xae, 0x14, 0x24, /* ldmxcsr (%esp) * operation exceptions
*/
+ 0x0f, 0x57, 0xc9, /* xorps %xmm1,%xmm1 * clear dividend */
+ 0x0f, 0x57, 0xc0, /* xorps %xmm0,%xmm0 * clear divisor */
+ 0x0f, 0x5e, 0xc8, /* divps %xmm0,%xmm1 * generate fault */
+ 0x89, 0x04, 0x24, /* mov %eax,(%esp) * restore to old mxcsr
*/
0x0f, 0xae, 0x14, 0x24, /* ldmxcsr (%esp) */
0x83, 0xc4, 0x04, /* add $0x4,%esp */
0xc3, /* ret */
@@ -1097,7 +1240,14 @@ static void test_simd_exceptions(void)
got_exception = 0;
run_exception_test(simd_fault_handler, &stage, simd_exception_test,
sizeof(simd_exception_test), 0);
- ok( got_exception == 1, "got exception: %i, should be 1\n",
got_exception);
+ ok(got_exception == 1, "got exception: %i, should be 1\n", got_exception);
+
+ /* generate a SIMD exception, test FPE_FLTINV */
+ stage = 3;
+ got_exception = 0;
+ run_exception_test(simd_fault_handler, &stage, simd_exception_test2,
+ sizeof(simd_exception_test2), 0);
+ ok(got_exception == 1, "got exception: %i, should be 1\n", got_exception);
}
struct fpu_exception_info
@@ -1166,7 +1316,7 @@ static void test_fpu_exceptions(void)
ok(info.exception_code == EXCEPTION_FLT_STACK_CHECK,
"Got exception code %#x, expected EXCEPTION_FLT_STACK_CHECK\n",
info.exception_code);
ok(info.exception_offset == 0x19 ||
- broken( is_wow64 && info.exception_offset == info.eip_offset ),
+ broken( info.exception_offset == info.eip_offset ),
"Got exception offset %#x, expected 0x19\n", info.exception_offset);
ok(info.eip_offset == 0x1b, "Got EIP offset %#x, expected 0x1b\n",
info.eip_offset);
@@ -1175,7 +1325,7 @@ static void test_fpu_exceptions(void)
ok(info.exception_code == EXCEPTION_FLT_DIVIDE_BY_ZERO,
"Got exception code %#x, expected EXCEPTION_FLT_DIVIDE_BY_ZERO\n",
info.exception_code);
ok(info.exception_offset == 0x17 ||
- broken( is_wow64 && info.exception_offset == info.eip_offset ),
+ broken( info.exception_offset == info.eip_offset ),
"Got exception offset %#x, expected 0x17\n", info.exception_offset);
ok(info.eip_offset == 0x19, "Got EIP offset %#x, expected 0x19\n",
info.eip_offset);
}
@@ -1323,8 +1473,138 @@ static void test_dpe_exceptions(void)
ok(stat == STATUS_ACCESS_DENIED, "enabling DEP while permanent: status
%08x\n", stat);
}
+static void test_thread_context(void)
+{
+ CONTEXT context;
+ NTSTATUS status;
+ struct expected
+ {
+ DWORD Eax, Ebx, Ecx, Edx, Esi, Edi, Ebp, Esp, Eip,
+ SegCs, SegDs, SegEs, SegFs, SegGs, SegSs, EFlags, prev_frame;
+ } expect;
+ NTSTATUS (*func_ptr)( struct expected *res, void *func, void *arg1, void *arg2 ) =
(void *)code_mem;
+
+ static const BYTE call_func[] =
+ {
+ 0x55, /* pushl %ebp */
+ 0x89, 0xe5, /* mov %esp,%ebp */
+ 0x50, /* pushl %eax ; add a bit of offset to the stack */
+ 0x50, /* pushl %eax */
+ 0x50, /* pushl %eax */
+ 0x50, /* pushl %eax */
+ 0x8b, 0x45, 0x08, /* mov 0x8(%ebp),%eax */
+ 0x8f, 0x00, /* popl (%eax) */
+ 0x89, 0x58, 0x04, /* mov %ebx,0x4(%eax) */
+ 0x89, 0x48, 0x08, /* mov %ecx,0x8(%eax) */
+ 0x89, 0x50, 0x0c, /* mov %edx,0xc(%eax) */
+ 0x89, 0x70, 0x10, /* mov %esi,0x10(%eax) */
+ 0x89, 0x78, 0x14, /* mov %edi,0x14(%eax) */
+ 0x89, 0x68, 0x18, /* mov %ebp,0x18(%eax) */
+ 0x89, 0x60, 0x1c, /* mov %esp,0x1c(%eax) */
+ 0xff, 0x75, 0x04, /* pushl 0x4(%ebp) */
+ 0x8f, 0x40, 0x20, /* popl 0x20(%eax) */
+ 0x8c, 0x48, 0x24, /* mov %cs,0x24(%eax) */
+ 0x8c, 0x58, 0x28, /* mov %ds,0x28(%eax) */
+ 0x8c, 0x40, 0x2c, /* mov %es,0x2c(%eax) */
+ 0x8c, 0x60, 0x30, /* mov %fs,0x30(%eax) */
+ 0x8c, 0x68, 0x34, /* mov %gs,0x34(%eax) */
+ 0x8c, 0x50, 0x38, /* mov %ss,0x38(%eax) */
+ 0x9c, /* pushf */
+ 0x8f, 0x40, 0x3c, /* popl 0x3c(%eax) */
+ 0xff, 0x75, 0x00, /* pushl 0x0(%ebp) ; previous stack frame */
+ 0x8f, 0x40, 0x40, /* popl 0x40(%eax) */
+ 0x8b, 0x00, /* mov (%eax),%eax */
+ 0xff, 0x75, 0x14, /* pushl 0x14(%ebp) */
+ 0xff, 0x75, 0x10, /* pushl 0x10(%ebp) */
+ 0xff, 0x55, 0x0c, /* call *0xc(%ebp) */
+ 0xc9, /* leave */
+ 0xc3, /* ret */
+ };
+
+ memcpy( func_ptr, call_func, sizeof(call_func) );
+
+#define COMPARE(reg) \
+ ok( context.reg == expect.reg, "wrong " #reg " %08x/%08x\n",
context.reg, expect.reg )
+
+ memset( &context, 0xcc, sizeof(context) );
+ memset( &expect, 0xcc, sizeof(expect) );
+ func_ptr( &expect, pRtlCaptureContext, &context, 0 );
+ trace( "expect: eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x ebp=%08x
esp=%08x "
+ "eip=%08x cs=%04x ds=%04x es=%04x fs=%04x gs=%04x ss=%04x flags=%08x
prev=%08x\n",
+ expect.Eax, expect.Ebx, expect.Ecx, expect.Edx, expect.Esi, expect.Edi,
+ expect.Ebp, expect.Esp, expect.Eip, expect.SegCs, expect.SegDs, expect.SegEs,
+ expect.SegFs, expect.SegGs, expect.SegSs, expect.EFlags, expect.prev_frame );
+ trace( "actual: eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x ebp=%08x
esp=%08x "
+ "eip=%08x cs=%04x ds=%04x es=%04x fs=%04x gs=%04x ss=%04x
flags=%08x\n",
+ context.Eax, context.Ebx, context.Ecx, context.Edx, context.Esi, context.Edi,
+ context.Ebp, context.Esp, context.Eip, context.SegCs, context.SegDs,
context.SegEs,
+ context.SegFs, context.SegGs, context.SegSs, context.EFlags );
+
+ ok( context.ContextFlags == (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS)
||
+ broken( context.ContextFlags == 0xcccccccc ), /* <= vista */
+ "wrong flags %08x\n", context.ContextFlags );
+ COMPARE( Eax );
+ COMPARE( Ebx );
+ COMPARE( Ecx );
+ COMPARE( Edx );
+ COMPARE( Esi );
+ COMPARE( Edi );
+ COMPARE( Eip );
+ COMPARE( SegCs );
+ COMPARE( SegDs );
+ COMPARE( SegEs );
+ COMPARE( SegFs );
+ COMPARE( SegGs );
+ COMPARE( SegSs );
+ COMPARE( EFlags );
+ /* Ebp is from the previous stackframe */
+ ok( context.Ebp == expect.prev_frame, "wrong Ebp %08x/%08x\n", context.Ebp,
expect.prev_frame );
+ /* Esp is the value on entry to the previous stackframe */
+ ok( context.Esp == expect.Ebp + 8, "wrong Esp %08x/%08x\n", context.Esp,
expect.Ebp + 8 );
+
+ memset( &context, 0xcc, sizeof(context) );
+ memset( &expect, 0xcc, sizeof(expect) );
+ context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS;
+ status = func_ptr( &expect, pNtGetContextThread, (void *)GetCurrentThread(),
&context );
+ ok( status == STATUS_SUCCESS, "NtGetContextThread failed %08x\n", status
);
+ trace( "expect: eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x ebp=%08x
esp=%08x "
+ "eip=%08x cs=%04x ds=%04x es=%04x fs=%04x gs=%04x ss=%04x flags=%08x
prev=%08x\n",
+ expect.Eax, expect.Ebx, expect.Ecx, expect.Edx, expect.Esi, expect.Edi,
+ expect.Ebp, expect.Esp, expect.Eip, expect.SegCs, expect.SegDs, expect.SegEs,
+ expect.SegFs, expect.SegGs, expect.SegSs, expect.EFlags, expect.prev_frame );
+ trace( "actual: eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x ebp=%08x
esp=%08x "
+ "eip=%08x cs=%04x ds=%04x es=%04x fs=%04x gs=%04x ss=%04x
flags=%08x\n",
+ context.Eax, context.Ebx, context.Ecx, context.Edx, context.Esi, context.Edi,
+ context.Ebp, context.Esp, context.Eip, context.SegCs, context.SegDs,
context.SegEs,
+ context.SegFs, context.SegGs, context.SegSs, context.EFlags );
+ /* Eax, Ecx, Edx, EFlags are not preserved */
+ COMPARE( Ebx );
+ COMPARE( Esi );
+ COMPARE( Edi );
+ COMPARE( Ebp );
+ /* Esp is the stack upon entry to NtGetContextThread */
+ ok( context.Esp == expect.Esp - 12 || context.Esp == expect.Esp - 16,
+ "wrong Esp %08x/%08x\n", context.Esp, expect.Esp );
+ /* Eip is somewhere close to the NtGetContextThread implementation */
+ ok( (char *)context.Eip >= (char *)pNtGetContextThread - 0x10000 &&
+ (char *)context.Eip <= (char *)pNtGetContextThread + 0x10000,
+ "wrong Eip %08x/%08x\n", context.Eip, (DWORD)pNtGetContextThread );
+ ok( *(WORD *)context.Eip == 0xc483 || *(WORD *)context.Eip == 0x08c2 || *(WORD
*)context.Eip == 0x8dc3,
+ "expected 0xc483 or 0x08c2 or 0x8dc3, got %04x\n", *(WORD *)context.Eip
);
+ /* segment registers clear the high word */
+ ok( context.SegCs == LOWORD(expect.SegCs), "wrong SegCs %08x/%08x\n",
context.SegCs, expect.SegCs );
+ ok( context.SegDs == LOWORD(expect.SegDs), "wrong SegDs %08x/%08x\n",
context.SegDs, expect.SegDs );
+ ok( context.SegEs == LOWORD(expect.SegEs), "wrong SegEs %08x/%08x\n",
context.SegEs, expect.SegEs );
+ ok( context.SegFs == LOWORD(expect.SegFs), "wrong SegFs %08x/%08x\n",
context.SegFs, expect.SegFs );
+ ok( context.SegGs == LOWORD(expect.SegGs), "wrong SegGs %08x/%08x\n",
context.SegGs, expect.SegGs );
+ ok( context.SegSs == LOWORD(expect.SegSs), "wrong SegSs %08x/%08x\n",
context.SegSs, expect.SegGs );
+#undef COMPARE
+}
+
#elif defined(__x86_64__)
+#define is_wow64 0
+
#define UNW_FLAG_NHANDLER 0
#define UNW_FLAG_EHANDLER 1
#define UNW_FLAG_UHANDLER 2
@@ -1598,6 +1878,131 @@ static void test_virtual_unwind(void)
call_virtual_unwind( i, &tests[i] );
}
+static int consolidate_dummy_called;
+static PVOID CALLBACK test_consolidate_dummy(EXCEPTION_RECORD *rec)
+{
+ CONTEXT *ctx = (CONTEXT *)rec->ExceptionInformation[1];
+ consolidate_dummy_called = 1;
+ ok(ctx->Rip == 0xdeadbeef, "test_consolidate_dummy failed for Rip, expected:
0xdeadbeef, got: %lx\n", ctx->Rip);
+ return (PVOID)rec->ExceptionInformation[2];
+}
+
+static void test_restore_context(void)
+{
+ SETJMP_FLOAT128 *fltsave;
+ EXCEPTION_RECORD rec;
+ _JUMP_BUFFER buf;
+ CONTEXT ctx;
+ int i, pass;
+
+ if (!pRtlUnwindEx || !pRtlRestoreContext || !pRtlCaptureContext || !p_setjmp)
+ {
+ skip("RtlUnwindEx/RtlCaptureContext/RtlRestoreContext/_setjmp not
found\n");
+ return;
+ }
+
+ /* RtlRestoreContext(NULL, NULL); crashes on Windows */
+
+ /* test simple case of capture and restore context */
+ pass = 0;
+ InterlockedIncrement(&pass); /* interlocked to prevent compiler from moving after
capture */
+ pRtlCaptureContext(&ctx);
+ if (InterlockedIncrement(&pass) == 2) /* interlocked to prevent compiler from
moving before capture */
+ {
+ pRtlRestoreContext(&ctx, NULL);
+ ok(0, "shouldn't be reached\n");
+ }
+ else
+ ok(pass < 4, "unexpected pass %d\n", pass);
+
+ /* test with jmp using RltRestoreContext */
+ pass = 0;
+ InterlockedIncrement(&pass);
+ RtlCaptureContext(&ctx);
+ InterlockedIncrement(&pass); /* only called once */
+ p_setjmp(&buf);
+ InterlockedIncrement(&pass);
+ if (pass == 3)
+ {
+ rec.ExceptionCode = STATUS_LONGJUMP;
+ rec.NumberParameters = 1;
+ rec.ExceptionInformation[0] = (DWORD64)&buf;
+
+ /* uses buf.Rip instead of ctx.Rip */
+ pRtlRestoreContext(&ctx, &rec);
+ ok(0, "shouldn't be reached\n");
+ }
+ else if (pass == 4)
+ {
+ ok(buf.Rbx == ctx.Rbx, "longjmp failed for Rbx, expected: %lx, got:
%lx\n", buf.Rbx, ctx.Rbx);
+ ok(buf.Rsp == ctx.Rsp, "longjmp failed for Rsp, expected: %lx, got:
%lx\n", buf.Rsp, ctx.Rsp);
+ ok(buf.Rbp == ctx.Rbp, "longjmp failed for Rbp, expected: %lx, got:
%lx\n", buf.Rbp, ctx.Rbp);
+ ok(buf.Rsi == ctx.Rsi, "longjmp failed for Rsi, expected: %lx, got:
%lx\n", buf.Rsi, ctx.Rsi);
+ ok(buf.Rdi == ctx.Rdi, "longjmp failed for Rdi, expected: %lx, got:
%lx\n", buf.Rdi, ctx.Rdi);
+ ok(buf.R12 == ctx.R12, "longjmp failed for R12, expected: %lx, got:
%lx\n", buf.R12, ctx.R12);
+ ok(buf.R13 == ctx.R13, "longjmp failed for R13, expected: %lx, got:
%lx\n", buf.R13, ctx.R13);
+ ok(buf.R14 == ctx.R14, "longjmp failed for R14, expected: %lx, got:
%lx\n", buf.R14, ctx.R14);
+ ok(buf.R15 == ctx.R15, "longjmp failed for R15, expected: %lx, got:
%lx\n", buf.R15, ctx.R15);
+
+ fltsave = &buf.Xmm6;
+ for (i = 0; i < 10; i++)
+ {
+ ok(fltsave[i].Part[0] == ctx.u.FltSave.XmmRegisters[i + 6].Low,
+ "longjmp failed for Xmm%d, expected %lx, got %lx\n", i + 6,
+ fltsave[i].Part[0], ctx.u.FltSave.XmmRegisters[i + 6].Low);
+
+ ok(fltsave[i].Part[1] == ctx.u.FltSave.XmmRegisters[i + 6].High,
+ "longjmp failed for Xmm%d, expected %lx, got %lx\n", i + 6,
+ fltsave[i].Part[1], ctx.u.FltSave.XmmRegisters[i + 6].High);
+ }
+ }
+ else
+ ok(0, "unexpected pass %d\n", pass);
+
+ /* test with jmp through RtlUnwindEx */
+ pass = 0;
+ InterlockedIncrement(&pass);
+ pRtlCaptureContext(&ctx);
+ InterlockedIncrement(&pass); /* only called once */
+ p_setjmp(&buf);
+ InterlockedIncrement(&pass);
+ if (pass == 3)
+ {
+ rec.ExceptionCode = STATUS_LONGJUMP;
+ rec.NumberParameters = 1;
+ rec.ExceptionInformation[0] = (DWORD64)&buf;
+
+ /* uses buf.Rip instead of bogus 0xdeadbeef */
+ pRtlUnwindEx((void*)buf.Rsp, (void*)0xdeadbeef, &rec, NULL, &ctx, NULL);
+ ok(0, "shouldn't be reached\n");
+ }
+ else
+ ok(pass == 4, "unexpected pass %d\n", pass);
+
+
+ /* test with consolidate */
+ pass = 0;
+ InterlockedIncrement(&pass);
+ RtlCaptureContext(&ctx);
+ InterlockedIncrement(&pass);
+ if (pass == 2)
+ {
+ rec.ExceptionCode = STATUS_UNWIND_CONSOLIDATE;
+ rec.NumberParameters = 3;
+ rec.ExceptionInformation[0] = (DWORD64)test_consolidate_dummy;
+ rec.ExceptionInformation[1] = (DWORD64)&ctx;
+ rec.ExceptionInformation[2] = ctx.Rip;
+ ctx.Rip = 0xdeadbeef;
+
+ pRtlRestoreContext(&ctx, &rec);
+ ok(0, "shouldn't be reached\n");
+ }
+ else if (pass == 3)
+ ok(consolidate_dummy_called, "test_consolidate_dummy not called\n");
+ else
+ ok(0, "unexpected pass %d\n", pass);
+}
+
static RUNTIME_FUNCTION* CALLBACK dynamic_unwind_callback( DWORD64 pc, PVOID context )
{
static const int code_offset = 1024;
@@ -1714,9 +2119,155 @@ static void test_dynamic_unwind(void)
}
+static int termination_handler_called;
+static void WINAPI termination_handler(ULONG flags, ULONG64 frame)
+{
+ termination_handler_called++;
+
+ ok(flags == 1 || broken(flags == 0x401), "flags = %x\n", flags);
+ ok(frame == 0x1234, "frame = %p\n", (void*)frame);
+}
+
+static void test___C_specific_handler(void)
+{
+ DISPATCHER_CONTEXT dispatch;
+ EXCEPTION_RECORD rec;
+ CONTEXT context;
+ ULONG64 frame;
+ EXCEPTION_DISPOSITION ret;
+ SCOPE_TABLE scope_table;
+
+ if (!p__C_specific_handler)
+ {
+ win_skip("__C_specific_handler not available\n");
+ return;
+ }
+
+ memset(&rec, 0, sizeof(rec));
+ rec.ExceptionFlags = 2; /* EH_UNWINDING */
+ frame = 0x1234;
+ memset(&dispatch, 0, sizeof(dispatch));
+ dispatch.ImageBase = (ULONG_PTR)GetModuleHandleA(NULL);
+ dispatch.ControlPc = dispatch.ImageBase + 0x200;
+ dispatch.HandlerData = &scope_table;
+ dispatch.ContextRecord = &context;
+ scope_table.Count = 1;
+ scope_table.ScopeRecord[0].BeginAddress = 0x200;
+ scope_table.ScopeRecord[0].EndAddress = 0x400;
+ scope_table.ScopeRecord[0].HandlerAddress =
(ULONG_PTR)termination_handler-dispatch.ImageBase;
+ scope_table.ScopeRecord[0].JumpTarget = 0;
+ memset(&context, 0, sizeof(context));
+
+ termination_handler_called = 0;
+ ret = p__C_specific_handler(&rec, frame, &context, &dispatch);
+ ok(ret == ExceptionContinueSearch, "__C_specific_handler returned %x\n",
ret);
+ ok(termination_handler_called == 1, "termination_handler_called = %d\n",
+ termination_handler_called);
+ ok(dispatch.ScopeIndex == 1, "dispatch.ScopeIndex = %d\n",
dispatch.ScopeIndex);
+
+ ret = p__C_specific_handler(&rec, frame, &context, &dispatch);
+ ok(ret == ExceptionContinueSearch, "__C_specific_handler returned %x\n",
ret);
+ ok(termination_handler_called == 1, "termination_handler_called = %d\n",
+ termination_handler_called);
+ ok(dispatch.ScopeIndex == 1, "dispatch.ScopeIndex = %d\n",
dispatch.ScopeIndex);
+}
+
#endif /* __x86_64__ */
#if defined(__i386__) || defined(__x86_64__)
+
+static DWORD WINAPI register_check_thread(void *arg)
+{
+ NTSTATUS status;
+ CONTEXT ctx;
+
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
+
+ status = pNtGetContextThread(GetCurrentThread(), &ctx);
+ ok(status == STATUS_SUCCESS, "NtGetContextThread failed with %x\n",
status);
+ ok(!ctx.Dr0, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr0);
+ ok(!ctx.Dr1, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr1);
+ ok(!ctx.Dr2, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr2);
+ ok(!ctx.Dr3, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr3);
+ ok(!ctx.Dr6, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr6);
+ ok(!ctx.Dr7, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr7);
+
+ return 0;
+}
+
+static void test_debug_registers(void)
+{
+ static const struct
+ {
+ ULONG_PTR dr0, dr1, dr2, dr3, dr6, dr7;
+ }
+ tests[] =
+ {
+ { 0x42424240, 0, 0x126bb070, 0x0badbad0, 0, 0xffff0115 },
+ { 0x42424242, 0, 0x100f0fe7, 0x0abebabe, 0, 0x115 },
+ };
+ NTSTATUS status;
+ CONTEXT ctx;
+ HANDLE thread;
+ int i;
+
+ for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++)
+ {
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
+ ctx.Dr0 = tests[i].dr0;
+ ctx.Dr1 = tests[i].dr1;
+ ctx.Dr2 = tests[i].dr2;
+ ctx.Dr3 = tests[i].dr3;
+ ctx.Dr6 = tests[i].dr6;
+ ctx.Dr7 = tests[i].dr7;
+
+ status = pNtSetContextThread(GetCurrentThread(), &ctx);
+ ok(status == STATUS_SUCCESS, "NtGetContextThread failed with %08x\n",
status);
+
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
+
+ status = pNtGetContextThread(GetCurrentThread(), &ctx);
+ ok(status == STATUS_SUCCESS, "NtGetContextThread failed with %08x\n",
status);
+ ok(ctx.Dr0 == tests[i].dr0, "test %d: expected %lx, got %lx\n", i,
tests[i].dr0, (DWORD_PTR)ctx.Dr0);
+ ok(ctx.Dr1 == tests[i].dr1, "test %d: expected %lx, got %lx\n", i,
tests[i].dr1, (DWORD_PTR)ctx.Dr1);
+ ok(ctx.Dr2 == tests[i].dr2, "test %d: expected %lx, got %lx\n", i,
tests[i].dr2, (DWORD_PTR)ctx.Dr2);
+ ok(ctx.Dr3 == tests[i].dr3, "test %d: expected %lx, got %lx\n", i,
tests[i].dr3, (DWORD_PTR)ctx.Dr3);
+ ok((ctx.Dr6 & 0xf00f) == tests[i].dr6, "test %d: expected %lx, got
%lx\n", i, tests[i].dr6, (DWORD_PTR)ctx.Dr6);
+ ok((ctx.Dr7 & ~0xdc00) == tests[i].dr7, "test %d: expected %lx, got
%lx\n", i, tests[i].dr7, (DWORD_PTR)ctx.Dr7);
+ }
+
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
+ ctx.Dr0 = 0xffffffff;
+ ctx.Dr1 = 0xffffffff;
+ ctx.Dr2 = 0xffffffff;
+ ctx.Dr3 = 0xffffffff;
+ ctx.Dr6 = 0xffffffff;
+ ctx.Dr7 = 0x00000400;
+ status = pNtSetContextThread(GetCurrentThread(), &ctx);
+ ok(status == STATUS_SUCCESS, "NtSetContextThread failed with %x\n",
status);
+
+ thread = CreateThread(NULL, 0, register_check_thread, NULL, CREATE_SUSPENDED, NULL);
+ ok(thread != INVALID_HANDLE_VALUE, "CreateThread failed with %d\n",
GetLastError());
+
+ ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
+ status = pNtGetContextThread(thread, &ctx);
+ ok(status == STATUS_SUCCESS, "NtGetContextThread failed with %x\n",
status);
+ ok(!ctx.Dr0, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr0);
+ ok(!ctx.Dr1, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr1);
+ ok(!ctx.Dr2, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr2);
+ ok(!ctx.Dr3, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr3);
+ ok(!ctx.Dr6, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr6);
+ ok(!ctx.Dr7, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr7);
+
+ ResumeThread(thread);
+ WaitForSingleObject(thread, 10000);
+ CloseHandle(thread);
+}
+
static DWORD outputdebugstring_exceptions;
static LONG CALLBACK outputdebugstring_vectored_handler(EXCEPTION_POINTERS
*ExceptionInfo)
@@ -1750,6 +2301,7 @@ static void test_outputdebugstring(DWORD numexc)
outputdebugstring_exceptions = 0;
OutputDebugStringA("Hello World");
+
ok(outputdebugstring_exceptions == numexc, "OutputDebugStringA generated %d
exceptions, expected %d\n",
outputdebugstring_exceptions, numexc);
@@ -1805,6 +2357,236 @@ static void test_ripevent(DWORD numexc)
pRtlRemoveVectoredExceptionHandler(vectored_handler);
}
+static DWORD debug_service_exceptions;
+
+static LONG CALLBACK debug_service_handler(EXCEPTION_POINTERS *ExceptionInfo)
+{
+ EXCEPTION_RECORD *rec = ExceptionInfo->ExceptionRecord;
+ trace("vect. handler %08x addr:%p\n", rec->ExceptionCode,
rec->ExceptionAddress);
+
+ ok(rec->ExceptionCode == EXCEPTION_BREAKPOINT, "ExceptionCode is %08x instead
of %08x\n",
+ rec->ExceptionCode, EXCEPTION_BREAKPOINT);
+
+#ifdef __i386__
+ ok(ExceptionInfo->ContextRecord->Eip == (DWORD)code_mem + 0x1c,
+ "expected Eip = %x, got %x\n", (DWORD)code_mem + 0x1c,
ExceptionInfo->ContextRecord->Eip);
+ ok(rec->NumberParameters == (is_wow64 ? 1 : 3),
+ "ExceptionParameters is %d instead of %d\n", rec->NumberParameters,
is_wow64 ? 1 : 3);
+ ok(rec->ExceptionInformation[0] == ExceptionInfo->ContextRecord->Eax,
+ "expected ExceptionInformation[0] = %x, got %lx\n",
+ ExceptionInfo->ContextRecord->Eax, rec->ExceptionInformation[0]);
+ if (!is_wow64)
+ {
+ ok(rec->ExceptionInformation[1] == 0x11111111,
+ "got ExceptionInformation[1] = %lx\n",
rec->ExceptionInformation[1]);
+ ok(rec->ExceptionInformation[2] == 0x22222222,
+ "got ExceptionInformation[2] = %lx\n",
rec->ExceptionInformation[2]);
+ }
+#else
+ ok(ExceptionInfo->ContextRecord->Rip == (DWORD_PTR)code_mem + 0x2f,
+ "expected Rip = %lx, got %lx\n", (DWORD_PTR)code_mem + 0x2f,
ExceptionInfo->ContextRecord->Rip);
+ ok(rec->NumberParameters == 1,
+ "ExceptionParameters is %d instead of 1\n", rec->NumberParameters);
+ ok(rec->ExceptionInformation[0] == ExceptionInfo->ContextRecord->Rax,
+ "expected ExceptionInformation[0] = %lx, got %lx\n",
+ ExceptionInfo->ContextRecord->Rax, rec->ExceptionInformation[0]);
+#endif
+
+ debug_service_exceptions++;
+ return (rec->ExceptionCode == EXCEPTION_BREAKPOINT) ? EXCEPTION_CONTINUE_EXECUTION
: EXCEPTION_CONTINUE_SEARCH;
+}
+
+#ifdef __i386__
+
+static const BYTE call_debug_service_code[] = {
+ 0x53, /* pushl %ebx */
+ 0x57, /* pushl %edi */
+ 0x8b, 0x44, 0x24, 0x0c, /* movl 12(%esp),%eax */
+ 0xb9, 0x11, 0x11, 0x11, 0x11, /* movl $0x11111111,%ecx */
+ 0xba, 0x22, 0x22, 0x22, 0x22, /* movl $0x22222222,%edx */
+ 0xbb, 0x33, 0x33, 0x33, 0x33, /* movl $0x33333333,%ebx */
+ 0xbf, 0x44, 0x44, 0x44, 0x44, /* movl $0x44444444,%edi */
+ 0xcd, 0x2d, /* int $0x2d */
+ 0xeb, /* jmp $+17 */
+ 0x0f, 0x1f, 0x00, /* nop */
+ 0x31, 0xc0, /* xorl %eax,%eax */
+ 0xeb, 0x0c, /* jmp $+14 */
+ 0x90, 0x90, 0x90, 0x90, /* nop */
+ 0x90, 0x90, 0x90, 0x90,
+ 0x90,
+ 0x31, 0xc0, /* xorl %eax,%eax */
+ 0x40, /* incl %eax */
+ 0x5f, /* popl %edi */
+ 0x5b, /* popl %ebx */
+ 0xc3, /* ret */
+};
+
+#else
+
+static const BYTE call_debug_service_code[] = {
+ 0x53, /* push %rbx */
+ 0x57, /* push %rdi */
+ 0x48, 0x89, 0xc8, /* movl %rcx,%rax */
+ 0x48, 0xb9, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, /* movabs
$0x1111111111111111,%rcx */
+ 0x48, 0xba, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, /* movabs
$0x2222222222222222,%rdx */
+ 0x48, 0xbb, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, /* movabs
$0x3333333333333333,%rbx */
+ 0x48, 0xbf, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, /* movabs
$0x4444444444444444,%rdi */
+ 0xcd, 0x2d, /* int $0x2d */
+ 0xeb, /* jmp $+17 */
+ 0x0f, 0x1f, 0x00, /* nop */
+ 0x48, 0x31, 0xc0, /* xor %rax,%rax */
+ 0xeb, 0x0e, /* jmp $+16 */
+ 0x90, 0x90, 0x90, 0x90, /* nop */
+ 0x90, 0x90, 0x90, 0x90,
+ 0x48, 0x31, 0xc0, /* xor %rax,%rax */
+ 0x48, 0xff, 0xc0, /* inc %rax */
+ 0x5f, /* pop %rdi */
+ 0x5b, /* pop %rbx */
+ 0xc3, /* ret */
+};
+
+#endif
+
+static void test_debug_service(DWORD numexc)
+{
+ DWORD (CDECL *func)(DWORD_PTR) = code_mem;
+ DWORD expected_exc, expected_ret;
+ void *vectored_handler;
+ DWORD ret;
+
+ /* code will return 0 if execution resumes immediately after "int $0x2d",
otherwise 1 */
+ memcpy(code_mem, call_debug_service_code, sizeof(call_debug_service_code));
+
+ vectored_handler = pRtlAddVectoredExceptionHandler(TRUE,
&debug_service_handler);
+ ok(vectored_handler != 0, "RtlAddVectoredExceptionHandler failed\n");
+
+ expected_exc = numexc;
+ expected_ret = (numexc != 0);
+
+ /* BREAKPOINT_BREAK */
+ debug_service_exceptions = 0;
+ ret = func(0);
+ ok(debug_service_exceptions == expected_exc,
+ "BREAKPOINT_BREAK generated %u exceptions, expected %u\n",
+ debug_service_exceptions, expected_exc);
+ ok(ret == expected_ret,
+ "BREAKPOINT_BREAK returned %u, expected %u\n", ret, expected_ret);
+
+ /* BREAKPOINT_PROMPT */
+ debug_service_exceptions = 0;
+ ret = func(2);
+ ok(debug_service_exceptions == expected_exc,
+ "BREAKPOINT_PROMPT generated %u exceptions, expected %u\n",
+ debug_service_exceptions, expected_exc);
+ ok(ret == expected_ret,
+ "BREAKPOINT_PROMPT returned %u, expected %u\n", ret, expected_ret);
+
+ /* invalid debug service */
+ debug_service_exceptions = 0;
+ ret = func(6);
+ ok(debug_service_exceptions == expected_exc,
+ "invalid debug service generated %u exceptions, expected %u\n",
+ debug_service_exceptions, expected_exc);
+ ok(ret == expected_ret,
+ "invalid debug service returned %u, expected %u\n", ret, expected_ret);
+
+ expected_exc = (is_wow64 ? numexc : 0);
+ expected_ret = (is_wow64 && numexc);
+
+ /* BREAKPOINT_PRINT */
+ debug_service_exceptions = 0;
+ ret = func(1);
+ ok(debug_service_exceptions == expected_exc,
+ "BREAKPOINT_PRINT generated %u exceptions, expected %u\n",
+ debug_service_exceptions, expected_exc);
+ ok(ret == expected_ret,
+ "BREAKPOINT_PRINT returned %u, expected %u\n", ret, expected_ret);
+
+ /* BREAKPOINT_LOAD_SYMBOLS */
+ debug_service_exceptions = 0;
+ ret = func(3);
+ ok(debug_service_exceptions == expected_exc,
+ "BREAKPOINT_LOAD_SYMBOLS generated %u exceptions, expected %u\n",
+ debug_service_exceptions, expected_exc);
+ ok(ret == expected_ret,
+ "BREAKPOINT_LOAD_SYMBOLS returned %u, expected %u\n", ret,
expected_ret);
+
+ /* BREAKPOINT_UNLOAD_SYMBOLS */
+ debug_service_exceptions = 0;
+ ret = func(4);
+ ok(debug_service_exceptions == expected_exc,
+ "BREAKPOINT_UNLOAD_SYMBOLS generated %u exceptions, expected %u\n",
+ debug_service_exceptions, expected_exc);
+ ok(ret == expected_ret,
+ "BREAKPOINT_UNLOAD_SYMBOLS returned %u, expected %u\n", ret,
expected_ret);
+
+ /* BREAKPOINT_COMMAND_STRING */
+ debug_service_exceptions = 0;
+ ret = func(5);
+ ok(debug_service_exceptions == expected_exc || broken(debug_service_exceptions ==
numexc),
+ "BREAKPOINT_COMMAND_STRING generated %u exceptions, expected %u\n",
+ debug_service_exceptions, expected_exc);
+ ok(ret == expected_ret || broken(ret == (numexc != 0)),
+ "BREAKPOINT_COMMAND_STRING returned %u, expected %u\n", ret,
expected_ret);
+
+ pRtlRemoveVectoredExceptionHandler(vectored_handler);
+}
+
+static DWORD breakpoint_exceptions;
+
+static LONG CALLBACK breakpoint_handler(EXCEPTION_POINTERS *ExceptionInfo)
+{
+ EXCEPTION_RECORD *rec = ExceptionInfo->ExceptionRecord;
+ trace("vect. handler %08x addr:%p\n", rec->ExceptionCode,
rec->ExceptionAddress);
+
+ ok(rec->ExceptionCode == EXCEPTION_BREAKPOINT, "ExceptionCode is %08x instead
of %08x\n",
+ rec->ExceptionCode, EXCEPTION_BREAKPOINT);
+
+#ifdef __i386__
+ ok(ExceptionInfo->ContextRecord->Eip == (DWORD)code_mem + 1,
+ "expected Eip = %x, got %x\n", (DWORD)code_mem + 1,
ExceptionInfo->ContextRecord->Eip);
+ ok(rec->NumberParameters == (is_wow64 ? 1 : 3),
+ "ExceptionParameters is %d instead of %d\n", rec->NumberParameters,
is_wow64 ? 1 : 3);
+ ok(rec->ExceptionInformation[0] == 0,
+ "got ExceptionInformation[0] = %lx\n",
rec->ExceptionInformation[0]);
+ ExceptionInfo->ContextRecord->Eip = (DWORD)code_mem + 2;
+#else
+ ok(ExceptionInfo->ContextRecord->Rip == (DWORD_PTR)code_mem + 1,
+ "expected Rip = %lx, got %lx\n", (DWORD_PTR)code_mem + 1,
ExceptionInfo->ContextRecord->Rip);
+ ok(rec->NumberParameters == 1,
+ "ExceptionParameters is %d instead of 1\n", rec->NumberParameters);
+ ok(rec->ExceptionInformation[0] == 0,
+ "got ExceptionInformation[0] = %lx\n",
rec->ExceptionInformation[0]);
+ ExceptionInfo->ContextRecord->Rip = (DWORD_PTR)code_mem + 2;
+#endif
+
+ breakpoint_exceptions++;
+ return (rec->ExceptionCode == EXCEPTION_BREAKPOINT) ? EXCEPTION_CONTINUE_EXECUTION
: EXCEPTION_CONTINUE_SEARCH;
+}
+
+static const BYTE breakpoint_code[] = {
+ 0xcd, 0x03, /* int $0x3 */
+ 0xc3, /* ret */
+};
+
+static void test_breakpoint(DWORD numexc)
+{
+ DWORD (CDECL *func)(void) = code_mem;
+ void *vectored_handler;
+
+ memcpy(code_mem, breakpoint_code, sizeof(breakpoint_code));
+
+ vectored_handler = pRtlAddVectoredExceptionHandler(TRUE, &breakpoint_handler);
+ ok(vectored_handler != 0, "RtlAddVectoredExceptionHandler failed\n");
+
+ breakpoint_exceptions = 0;
+ func();
+ ok(breakpoint_exceptions == numexc, "int $0x3 generated %u exceptions, expected
%u\n",
+ breakpoint_exceptions, numexc);
+
+ pRtlRemoveVectoredExceptionHandler(vectored_handler);
+}
+
static DWORD invalid_handle_exceptions;
static LONG CALLBACK invalid_handle_vectored_handler(EXCEPTION_POINTERS *ExceptionInfo)
@@ -1893,6 +2675,10 @@ static void test_vectored_continue_handler(void)
START_TEST(exception)
{
HMODULE hntdll = GetModuleHandleA("ntdll.dll");
+#if defined(__x86_64__)
+ HMODULE hmsvcrt = LoadLibraryA("msvcrt.dll");
+#endif
+
#ifdef __REACTOS__
if (!winetest_interactive &&
!strcmp(winetest_platform, "windows"))
@@ -1907,13 +2693,13 @@ START_TEST(exception)
return;
}
- pNtCurrentTeb = (void *)GetProcAddress( hntdll, "NtCurrentTeb" );
pNtGetContextThread = (void *)GetProcAddress( hntdll, "NtGetContextThread"
);
pNtSetContextThread = (void *)GetProcAddress( hntdll, "NtSetContextThread"
);
pNtReadVirtualMemory = (void *)GetProcAddress( hntdll,
"NtReadVirtualMemory" );
pNtClose = (void *)GetProcAddress( hntdll, "NtClose" );
pRtlUnwind = (void *)GetProcAddress( hntdll, "RtlUnwind" );
pRtlRaiseException = (void *)GetProcAddress( hntdll, "RtlRaiseException"
);
+ pRtlCaptureContext = (void *)GetProcAddress( hntdll, "RtlCaptureContext"
);
pNtTerminateProcess = (void *)GetProcAddress( hntdll, "NtTerminateProcess"
);
pRtlAddVectoredExceptionHandler = (void *)GetProcAddress( hntdll,
"RtlAddVectoredExceptionHandler" );
@@ -1930,11 +2716,6 @@ START_TEST(exception)
pIsWow64Process = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"),
"IsWow64Process");
#ifdef __i386__
- if (!pNtCurrentTeb)
- {
- skip( "NtCurrentTeb not found\n" );
- return;
- }
if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 ))
is_wow64 = FALSE;
if (pRtlAddVectoredExceptionHandler && pRtlRemoveVectoredExceptionHandler)
@@ -1955,7 +2736,7 @@ START_TEST(exception)
}
/* child must be run under a debugger */
- if (!pNtCurrentTeb()->Peb->BeingDebugged)
+ if (!NtCurrentTeb()->Peb->BeingDebugged)
{
ok(FALSE, "child process not being debugged?\n");
return;
@@ -1980,8 +2761,16 @@ START_TEST(exception)
test_stage = 6;
test_ripevent(1);
test_stage = 7;
- test_closehandle(0);
+ test_debug_service(0);
test_stage = 8;
+ test_debug_service(1);
+ test_stage = 9;
+ test_breakpoint(0);
+ test_stage = 10;
+ test_breakpoint(1);
+ test_stage = 11;
+ test_closehandle(0);
+ test_stage = 12;
test_closehandle(1);
}
else
@@ -1994,8 +2783,11 @@ START_TEST(exception)
test_unwind();
test_exceptions();
test_rtlraiseexception();
+ test_debug_registers();
test_outputdebugstring(1);
test_ripevent(1);
+ test_debug_service(1);
+ test_breakpoint(1);
test_closehandle(0);
test_vectored_continue_handler();
test_debugger();
@@ -2003,6 +2795,7 @@ START_TEST(exception)
test_fpu_exceptions();
test_dpe_exceptions();
test_prot_fault();
+ test_thread_context();
#elif defined(__x86_64__)
pRtlAddFunctionTable = (void *)GetProcAddress( hntdll,
@@ -2013,12 +2806,27 @@ START_TEST(exception)
"RtlInstallFunctionTableCallback" );
pRtlLookupFunctionEntry = (void *)GetProcAddress( hntdll,
"RtlLookupFunctionEntry" );
-
+ p__C_specific_handler = (void *)GetProcAddress( hntdll,
+
"__C_specific_handler" );
+ pRtlCaptureContext = (void *)GetProcAddress( hntdll,
+
"RtlCaptureContext" );
+ pRtlRestoreContext = (void *)GetProcAddress( hntdll,
+
"RtlRestoreContext" );
+ pRtlUnwindEx = (void *)GetProcAddress( hntdll,
+ "RtlUnwindEx"
);
+ p_setjmp = (void *)GetProcAddress( hmsvcrt,
+ "_setjmp" );
+
+ test_debug_registers();
test_outputdebugstring(1);
test_ripevent(1);
+ test_debug_service(1);
+ test_breakpoint(1);
test_closehandle(0);
test_vectored_continue_handler();
test_virtual_unwind();
+ test___C_specific_handler();
+ test_restore_context();
if (pRtlAddFunctionTable && pRtlDeleteFunctionTable &&
pRtlInstallFunctionTableCallback && pRtlLookupFunctionEntry)
test_dynamic_unwind();
@@ -2027,5 +2835,5 @@ START_TEST(exception)
#endif
- VirtualFree(code_mem, 0, MEM_FREE);
+ VirtualFree(code_mem, 0, MEM_RELEASE);
}
diff --git a/modules/rostests/winetests/ntdll/file.c
b/modules/rostests/winetests/ntdll/file.c
index 0387398e5d..3316399c2f 100644
--- a/modules/rostests/winetests/ntdll/file.c
+++ b/modules/rostests/winetests/ntdll/file.c
@@ -94,6 +94,7 @@ static NTSTATUS (WINAPI *pNtWriteFile)(HANDLE hFile, HANDLE hEvent,
static NTSTATUS (WINAPI *pNtCancelIoFile)(HANDLE hFile, PIO_STATUS_BLOCK io_status);
static NTSTATUS (WINAPI *pNtCancelIoFileEx)(HANDLE hFile, PIO_STATUS_BLOCK iosb,
PIO_STATUS_BLOCK io_status);
static NTSTATUS (WINAPI *pNtClose)( PHANDLE );
+static NTSTATUS (WINAPI *pNtFsControlFile) (HANDLE handle, HANDLE event, PIO_APC_ROUTINE
apc, PVOID apc_context, PIO_STATUS_BLOCK io, ULONG code, PVOID in_buffer, ULONG in_size,
PVOID out_buffer, ULONG out_size);
static NTSTATUS (WINAPI *pNtCreateIoCompletion)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES,
ULONG);
static NTSTATUS (WINAPI *pNtOpenIoCompletion)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES);
@@ -106,6 +107,7 @@ static NTSTATUS (WINAPI
*pNtQueryDirectoryFile)(HANDLE,HANDLE,PIO_APC_ROUTINE,PV
PVOID,ULONG,FILE_INFORMATION_CLASS,BOOLEAN,PUNICODE_STRING,BOOLEAN);
static NTSTATUS (WINAPI
*pNtQueryVolumeInformationFile)(HANDLE,PIO_STATUS_BLOCK,PVOID,ULONG,FS_INFORMATION_CLASS);
static NTSTATUS (WINAPI *pNtQueryFullAttributesFile)(const OBJECT_ATTRIBUTES*,
FILE_NETWORK_OPEN_INFORMATION*);
+static NTSTATUS (WINAPI *pNtFlushBuffersFile)(HANDLE, IO_STATUS_BLOCK*);
static NTSTATUS (WINAPI
*pNtQueryEaFile)(HANDLE,PIO_STATUS_BLOCK,PVOID,ULONG,BOOLEAN,PVOID,ULONG,PULONG,BOOLEAN);
static inline BOOL is_signaled( HANDLE obj )
@@ -113,31 +115,8 @@ static inline BOOL is_signaled( HANDLE obj )
return WaitForSingleObject( obj, 0 ) == WAIT_OBJECT_0;
}
-static const char* debugstr_longlong(ULONGLONG ll)
-{
- static char str[17];
- if (sizeof(ll) > sizeof(unsigned long) && ll >> 32)
- sprintf(str, "%lx%08lx", (unsigned long)(ll >> 32), (unsigned
long)ll);
- else
- sprintf(str, "%lx", (unsigned long)ll);
- return str;
-}
-
-#define PIPENAME "\\\\.\\pipe\\ntdll_tests_file.c"
#define TEST_BUF_LEN 3
-static BOOL create_pipe( HANDLE *read, HANDLE *write, ULONG flags, ULONG size )
-{
- *read = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_INBOUND | flags, PIPE_TYPE_BYTE |
PIPE_WAIT,
- 1, size, size, NMPWAIT_USE_DEFAULT_WAIT, NULL);
- ok(*read != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
-
- *write = CreateFileA(PIPENAME, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
- ok(*write != INVALID_HANDLE_VALUE, "CreateFile failed (%d)\n",
GetLastError());
-
- return TRUE;
-}
-
static HANDLE create_temp_file( ULONG flags )
{
char path[MAX_PATH], buffer[MAX_PATH];
@@ -198,18 +177,22 @@ static void WINAPI apc( void *arg, IO_STATUS_BLOCK *iosb, ULONG
reserved )
static void create_file_test(void)
{
+ static const WCHAR notepadW[] =
{'n','o','t','e','p','a','d','.','e','x','e',0};
static const WCHAR systemrootW[] =
{'\\','S','y','s','t','e','m','R','o','o','t',
'\\','f','a','i','l','i','n','g',0};
+ static const WCHAR systemrootExplorerW[] =
{'\\','S','y','s','t','e','m','R','o','o','t',
+
'\\','e','x','p','l','o','r','e','r','.','e','x','e',0};
static const WCHAR questionmarkInvalidNameW[] =
{'a','f','i','l','e','?',0};
static const WCHAR pipeInvalidNameW[] = {'a','|','b',0};
static const WCHAR pathInvalidNtW[] =
{'\\','\\','?','\\',0};
static const WCHAR pathInvalidNt2W[] =
{'\\','?','?','\\',0};
static const WCHAR pathInvalidDosW[] =
{'\\','D','o','s','D','e','v','i','c','e','s','\\',0};
static const char testdata[] = "Hello World";
+ static const WCHAR sepW[] = {'\\',0};
FILE_NETWORK_OPEN_INFORMATION info;
NTSTATUS status;
HANDLE dir, file;
- WCHAR path[MAX_PATH];
+ WCHAR path[MAX_PATH], temp[MAX_PATH];
OBJECT_ATTRIBUTES attr;
IO_STATUS_BLOCK io;
UNICODE_STRING nameW;
@@ -389,6 +372,25 @@ static void create_file_test(void)
status = pNtQueryFullAttributesFile( &attr, &info );
ok( status == STATUS_OBJECT_NAME_INVALID,
"query %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status );
+
+ GetWindowsDirectoryW( path, MAX_PATH );
+ path[2] = 0;
+ ok( QueryDosDeviceW( path, temp, MAX_PATH ),
+ "QueryDosDeviceW failed with error %u\n", GetLastError() );
+ lstrcatW( temp, sepW );
+ lstrcatW( temp, path+3 );
+ lstrcatW( temp, sepW );
+ lstrcatW( temp, notepadW );
+
+ pRtlInitUnicodeString( &nameW, temp );
+ status = pNtQueryFullAttributesFile( &attr, &info );
+ ok( status == STATUS_SUCCESS,
+ "query %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status );
+
+ pRtlInitUnicodeString( &nameW, systemrootExplorerW );
+ status = pNtQueryFullAttributesFile( &attr, &info );
+ ok( status == STATUS_SUCCESS,
+ "query %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status );
}
static void open_file_test(void)
@@ -660,268 +662,14 @@ static void delete_file_test(void)
static void read_file_test(void)
{
const char text[] = "foobar";
- HANDLE handle, read, write;
+ HANDLE handle;
+ IO_STATUS_BLOCK iosb;
NTSTATUS status;
- IO_STATUS_BLOCK iosb, iosb2;
- DWORD written;
int apc_count = 0;
char buffer[128];
LARGE_INTEGER offset;
HANDLE event = CreateEventA( NULL, TRUE, FALSE, NULL );
- BOOL ret;
-
- buffer[0] = 1;
-
- if (!create_pipe( &read, &write, FILE_FLAG_OVERLAPPED, 4096 )) return;
-
- /* try read with no data */
- U(iosb).Status = 0xdeadbabe;
- iosb.Information = 0xdeadbeef;
- ok( is_signaled( read ), "read handle is not signaled\n" );
- status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL,
NULL );
- ok( status == STATUS_PENDING, "wrong status %x\n", status );
- ok( !is_signaled( read ), "read handle is signaled\n" );
- ok( !is_signaled( event ), "event is signaled\n" );
- ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
- ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information
);
- ok( !apc_count, "apc was called\n" );
- ret = WriteFile( write, buffer, 1, &written, NULL );
- ok(ret && written == 1, "WriteFile error %d\n", GetLastError());
- /* iosb updated here by async i/o */
- Sleep(1); /* FIXME: needed for wine to run the i/o apc */
- ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status );
- ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information );
- ok( !is_signaled( read ), "read handle is signaled\n" );
- ok( is_signaled( event ), "event is not signaled\n" );
- ok( !apc_count, "apc was called\n" );
- apc_count = 0;
- SleepEx( 1, FALSE ); /* non-alertable sleep */
- ok( !apc_count, "apc was called\n" );
- SleepEx( 1, TRUE ); /* alertable sleep */
- ok( apc_count == 1, "apc not called\n" );
-
- /* with no event, the pipe handle itself gets signaled */
- apc_count = 0;
- U(iosb).Status = 0xdeadbabe;
- iosb.Information = 0xdeadbeef;
- ok( !is_signaled( read ), "read handle is signaled\n" );
- status = pNtReadFile( read, 0, apc, &apc_count, &iosb, buffer, 1, NULL, NULL
);
- ok( status == STATUS_PENDING, "wrong status %x\n", status );
- ok( !is_signaled( read ), "read handle is signaled\n" );
- ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
- ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information
);
- ok( !apc_count, "apc was called\n" );
- ret = WriteFile( write, buffer, 1, &written, NULL );
- ok(ret && written == 1, "WriteFile error %d\n", GetLastError());
- /* iosb updated here by async i/o */
- Sleep(1); /* FIXME: needed for wine to run the i/o apc */
- ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status );
- ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information );
- ok( is_signaled( read ), "read handle is not signaled\n" );
- ok( !apc_count, "apc was called\n" );
- apc_count = 0;
- SleepEx( 1, FALSE ); /* non-alertable sleep */
- ok( !apc_count, "apc was called\n" );
- SleepEx( 1, TRUE ); /* alertable sleep */
- ok( apc_count == 1, "apc not called\n" );
- /* now read with data ready */
- apc_count = 0;
- U(iosb).Status = 0xdeadbabe;
- iosb.Information = 0xdeadbeef;
- ResetEvent( event );
- ret = WriteFile( write, buffer, 1, &written, NULL );
- ok(ret && written == 1, "WriteFile error %d\n", GetLastError());
- status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL,
NULL );
- ok( status == STATUS_SUCCESS, "wrong status %x\n", status );
- ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status );
- ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information );
- ok( is_signaled( event ), "event is not signaled\n" );
- ok( !apc_count, "apc was called\n" );
- SleepEx( 1, FALSE ); /* non-alertable sleep */
- ok( !apc_count, "apc was called\n" );
- SleepEx( 1, TRUE ); /* alertable sleep */
- ok( apc_count == 1, "apc not called\n" );
-
- /* try read with no data */
- apc_count = 0;
- U(iosb).Status = 0xdeadbabe;
- iosb.Information = 0xdeadbeef;
- ok( is_signaled( event ), "event is not signaled\n" ); /* check that read
resets the event */
- status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL,
NULL );
- ok( status == STATUS_PENDING, "wrong status %x\n", status );
- ok( !is_signaled( event ), "event is signaled\n" );
- ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
- ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information
);
- ok( !apc_count, "apc was called\n" );
- ret = WriteFile( write, buffer, 1, &written, NULL );
- ok(ret && written == 1, "WriteFile error %d\n", GetLastError());
- /* partial read is good enough */
- Sleep(1); /* FIXME: needed for wine to run the i/o apc */
- ok( is_signaled( event ), "event is not signaled\n" );
- ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status );
- ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information );
- ok( !apc_count, "apc was called\n" );
- SleepEx( 1, TRUE ); /* alertable sleep */
- ok( apc_count == 1, "apc was not called\n" );
-
- /* read from disconnected pipe */
- apc_count = 0;
- U(iosb).Status = 0xdeadbabe;
- iosb.Information = 0xdeadbeef;
- CloseHandle( write );
- status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL,
NULL );
- ok( status == STATUS_PIPE_BROKEN, "wrong status %x\n", status );
- ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
- ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information
);
- ok( !is_signaled( event ), "event is signaled\n" );
- ok( !apc_count, "apc was called\n" );
- SleepEx( 1, TRUE ); /* alertable sleep */
- ok( !apc_count, "apc was called\n" );
- CloseHandle( read );
-
- /* read from closed handle */
- apc_count = 0;
- U(iosb).Status = 0xdeadbabe;
- iosb.Information = 0xdeadbeef;
- SetEvent( event );
- status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL,
NULL );
- ok( status == STATUS_INVALID_HANDLE, "wrong status %x\n", status );
- ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
- ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information
);
- ok( is_signaled( event ), "event is not signaled\n" ); /* not reset on
invalid handle */
- ok( !apc_count, "apc was called\n" );
- SleepEx( 1, TRUE ); /* alertable sleep */
- ok( !apc_count, "apc was called\n" );
-
- /* disconnect while async read is in progress */
- if (!create_pipe( &read, &write, FILE_FLAG_OVERLAPPED, 4096 )) return;
- apc_count = 0;
- U(iosb).Status = 0xdeadbabe;
- iosb.Information = 0xdeadbeef;
- status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL,
NULL );
- ok( status == STATUS_PENDING, "wrong status %x\n", status );
- ok( !is_signaled( event ), "event is signaled\n" );
- ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
- ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information
);
- ok( !apc_count, "apc was called\n" );
- CloseHandle( write );
- Sleep(1); /* FIXME: needed for wine to run the i/o apc */
- ok( U(iosb).Status == STATUS_PIPE_BROKEN, "wrong status %x\n",
U(iosb).Status );
- ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
- ok( is_signaled( event ), "event is not signaled\n" );
- ok( !apc_count, "apc was called\n" );
- SleepEx( 1, TRUE ); /* alertable sleep */
- ok( apc_count == 1, "apc was not called\n" );
- CloseHandle( read );
-
- if (!create_pipe( &read, &write, FILE_FLAG_OVERLAPPED, 4096 )) return;
- ret = DuplicateHandle(GetCurrentProcess(), read, GetCurrentProcess(), &handle, 0,
TRUE, DUPLICATE_SAME_ACCESS);
- ok(ret, "Failed to duplicate handle: %d\n", GetLastError());
-
- apc_count = 0;
- U(iosb).Status = 0xdeadbabe;
- iosb.Information = 0xdeadbeef;
- status = pNtReadFile( handle, event, apc, &apc_count, &iosb, buffer, 2, NULL,
NULL );
- ok( status == STATUS_PENDING, "wrong status %x\n", status );
- ok( !is_signaled( event ), "event is signaled\n" );
- ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
- ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information
);
- ok( !apc_count, "apc was called\n" );
- /* Cancel by other handle */
- status = pNtCancelIoFile( read, &iosb2 );
- ok(status == STATUS_SUCCESS, "failed to cancel by different handle: %x\n",
status);
- Sleep(1); /* FIXME: needed for wine to run the i/o apc */
- ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status
);
- ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
- ok( is_signaled( event ), "event is not signaled\n" );
- ok( !apc_count, "apc was called\n" );
- SleepEx( 1, TRUE ); /* alertable sleep */
- ok( apc_count == 1, "apc was not called\n" );
-
- apc_count = 0;
- U(iosb).Status = 0xdeadbabe;
- iosb.Information = 0xdeadbeef;
- status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL,
NULL );
- ok( status == STATUS_PENDING, "wrong status %x\n", status );
- ok( !is_signaled( event ), "event is signaled\n" );
- ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
- ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information
);
- ok( !apc_count, "apc was called\n" );
- /* Close queued handle */
- CloseHandle( read );
- SleepEx( 1, TRUE ); /* alertable sleep */
- ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
- ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information
);
- status = pNtCancelIoFile( read, &iosb2 );
- ok(status == STATUS_INVALID_HANDLE, "cancelled by closed handle?\n");
- status = pNtCancelIoFile( handle, &iosb2 );
- ok(status == STATUS_SUCCESS, "failed to cancel: %x\n", status);
- Sleep(1); /* FIXME: needed for wine to run the i/o apc */
- ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status
);
- ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
- ok( is_signaled( event ), "event is not signaled\n" );
- ok( !apc_count, "apc was called\n" );
- SleepEx( 1, TRUE ); /* alertable sleep */
- ok( apc_count == 1, "apc was not called\n" );
- CloseHandle( handle );
- CloseHandle( write );
-
- if (pNtCancelIoFileEx)
- {
- /* Basic Cancel Ex */
- if (!create_pipe( &read, &write, FILE_FLAG_OVERLAPPED, 4096 )) return;
-
- apc_count = 0;
- U(iosb).Status = 0xdeadbabe;
- iosb.Information = 0xdeadbeef;
- status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2,
NULL, NULL );
- ok( status == STATUS_PENDING, "wrong status %x\n", status );
- ok( !is_signaled( event ), "event is signaled\n" );
- ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status
);
- ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n",
iosb.Information );
- ok( !apc_count, "apc was called\n" );
- status = pNtCancelIoFileEx( read, &iosb, &iosb2 );
- ok(status == STATUS_SUCCESS, "Failed to cancel I/O\n");
- Sleep(1); /* FIXME: needed for wine to run the i/o apc */
- ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n",
U(iosb).Status );
- ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
- ok( is_signaled( event ), "event is not signaled\n" );
- ok( !apc_count, "apc was called\n" );
- SleepEx( 1, TRUE ); /* alertable sleep */
- ok( apc_count == 1, "apc was not called\n" );
-
- /* Duplicate iosb */
- apc_count = 0;
- U(iosb).Status = 0xdeadbabe;
- iosb.Information = 0xdeadbeef;
- status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2,
NULL, NULL );
- ok( status == STATUS_PENDING, "wrong status %x\n", status );
- ok( !is_signaled( event ), "event is signaled\n" );
- ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status
);
- ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n",
iosb.Information );
- ok( !apc_count, "apc was called\n" );
- status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2,
NULL, NULL );
- ok( status == STATUS_PENDING, "wrong status %x\n", status );
- ok( !is_signaled( event ), "event is signaled\n" );
- ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status
);
- ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n",
iosb.Information );
- ok( !apc_count, "apc was called\n" );
- status = pNtCancelIoFileEx( read, &iosb, &iosb2 );
- ok(status == STATUS_SUCCESS, "Failed to cancel I/O\n");
- Sleep(1); /* FIXME: needed for wine to run the i/o apc */
- ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n",
U(iosb).Status );
- ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
- ok( is_signaled( event ), "event is not signaled\n" );
- ok( !apc_count, "apc was called\n" );
- SleepEx( 1, TRUE ); /* alertable sleep */
- ok( apc_count == 2, "apc was not called\n" );
-
- CloseHandle( read );
- CloseHandle( write );
- }
-
- /* now try a real file */
if (!(handle = create_temp_file( FILE_FLAG_OVERLAPPED ))) return;
apc_count = 0;
U(iosb).Status = 0xdeadbabe;
@@ -1297,7 +1045,7 @@ static void test_iocp_fileio(HANDLE h)
ok( completionKey == CKEY_SECOND, "Invalid completion key: %lx\n",
completionKey );
ok( ioSb.Information == 0, "Invalid ioSb.Information: %ld\n",
ioSb.Information );
/* wine sends wrong status here */
- todo_wine ok( U(ioSb).Status == STATUS_PIPE_BROKEN, "Invalid
ioSb.Status: %x\n", U(ioSb).Status);
+ ok( U(ioSb).Status == STATUS_PIPE_BROKEN, "Invalid ioSb.Status:
%x\n", U(ioSb).Status);
ok( completionValue == (ULONG_PTR)&o, "Invalid completion value:
%lx\n", completionValue );
}
}
@@ -1315,6 +1063,7 @@ static void test_iocp_fileio(HANDLE h)
{
OVERLAPPED o = {0,};
BYTE send_buf[TEST_BUF_LEN], recv_buf[TEST_BUF_LEN];
+ int apc_count = 0;
DWORD read;
long count;
@@ -1343,6 +1092,58 @@ static void test_iocp_fileio(HANDLE h)
}
count = get_pending_msgs(h);
ok( !count, "Unexpected msg count: %ld\n", count );
+
+ /* using APCs on handle with associated completion port is not allowed */
+ res = NtReadFile( hPipeSrv, NULL, apc, &apc_count, &iosb, recv_buf,
sizeof(recv_buf), NULL, NULL );
+ ok(res == STATUS_INVALID_PARAMETER, "NtReadFile returned %x\n", res);
+ }
+
+ CloseHandle( hPipeSrv );
+ CloseHandle( hPipeClt );
+
+ /* test associating a completion port with a handle after an async using APC is
queued */
+ hPipeSrv = CreateNamedPipeA( pipe_name, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 4, 1024, 1024, 1000, NULL );
+ ok( hPipeSrv != INVALID_HANDLE_VALUE, "Cannot create named pipe\n" );
+ if (hPipeSrv == INVALID_HANDLE_VALUE )
+ return;
+ hPipeClt = CreateFileA( pipe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL );
+ ok( hPipeClt != INVALID_HANDLE_VALUE, "Cannot connect to pipe\n" );
+ if (hPipeClt != INVALID_HANDLE_VALUE)
+ {
+ BYTE send_buf[TEST_BUF_LEN], recv_buf[TEST_BUF_LEN];
+ int apc_count = 0;
+ DWORD read;
+ long count;
+
+ memset( send_buf, 0, TEST_BUF_LEN );
+ memset( recv_buf, 0xde, TEST_BUF_LEN );
+ count = get_pending_msgs(h);
+ ok( !count, "Unexpected msg count: %ld\n", count );
+
+ res = NtReadFile( hPipeSrv, NULL, apc, &apc_count, &iosb, recv_buf,
sizeof(recv_buf), NULL, NULL );
+ ok(res == STATUS_PENDING, "NtReadFile returned %x\n", res);
+
+ U(iosb).Status = 0xdeadbeef;
+ res = pNtSetInformationFile( hPipeSrv, &iosb, &fci, sizeof(fci),
FileCompletionInformation );
+ ok( res == STATUS_SUCCESS, "NtSetInformationFile failed: %x\n", res );
+ ok( U(iosb).Status == STATUS_SUCCESS, "iosb.Status invalid: %x\n",
U(iosb).Status );
+ count = get_pending_msgs(h);
+ ok( !count, "Unexpected msg count: %ld\n", count );
+
+ WriteFile( hPipeClt, send_buf, TEST_BUF_LEN, &read, NULL );
+
+ ok(!apc_count, "apc_count = %u\n", apc_count);
+ count = get_pending_msgs(h);
+ ok( !count, "Unexpected msg count: %ld\n", count );
+
+ SleepEx(1, TRUE); /* alertable sleep */
+ ok(apc_count == 1, "apc was not called\n");
+ count = get_pending_msgs(h);
+ ok( !count, "Unexpected msg count: %ld\n", count );
+
+ /* using APCs on handle with associated completion port is not allowed */
+ res = NtReadFile( hPipeSrv, NULL, apc, &apc_count, &iosb, recv_buf,
sizeof(recv_buf), NULL, NULL );
+ ok(res == STATUS_INVALID_PARAMETER, "NtReadFile returned %x\n", res);
}
CloseHandle( hPipeSrv );
@@ -1371,10 +1172,10 @@ static void test_file_full_size_information(void)
/* Test for FileFsSizeInformation */
ok(fsi.TotalAllocationUnits.QuadPart > 0,
"[fsi] TotalAllocationUnits expected positive, got 0x%s\n",
- debugstr_longlong(fsi.TotalAllocationUnits.QuadPart));
+ wine_dbgstr_longlong(fsi.TotalAllocationUnits.QuadPart));
ok(fsi.AvailableAllocationUnits.QuadPart > 0,
"[fsi] AvailableAllocationUnits expected positive, got 0x%s\n",
- debugstr_longlong(fsi.AvailableAllocationUnits.QuadPart));
+ wine_dbgstr_longlong(fsi.AvailableAllocationUnits.QuadPart));
/* Assume file system is NTFS */
ok(fsi.BytesPerSector == 512, "[fsi] BytesPerSector expected 512, got
%d\n",fsi.BytesPerSector);
@@ -1382,21 +1183,21 @@ static void test_file_full_size_information(void)
ok(ffsi.TotalAllocationUnits.QuadPart > 0,
"[ffsi] TotalAllocationUnits expected positive, got negative value
0x%s\n",
- debugstr_longlong(ffsi.TotalAllocationUnits.QuadPart));
+ wine_dbgstr_longlong(ffsi.TotalAllocationUnits.QuadPart));
ok(ffsi.CallerAvailableAllocationUnits.QuadPart > 0,
"[ffsi] CallerAvailableAllocationUnits expected positive, got negative value
0x%s\n",
- debugstr_longlong(ffsi.CallerAvailableAllocationUnits.QuadPart));
+ wine_dbgstr_longlong(ffsi.CallerAvailableAllocationUnits.QuadPart));
ok(ffsi.ActualAvailableAllocationUnits.QuadPart > 0,
"[ffsi] ActualAvailableAllocationUnits expected positive, got negative value
0x%s\n",
- debugstr_longlong(ffsi.ActualAvailableAllocationUnits.QuadPart));
+ wine_dbgstr_longlong(ffsi.ActualAvailableAllocationUnits.QuadPart));
ok(ffsi.TotalAllocationUnits.QuadPart == fsi.TotalAllocationUnits.QuadPart,
"[ffsi] TotalAllocationUnits error fsi:0x%s, ffsi:0x%s\n",
- debugstr_longlong(fsi.TotalAllocationUnits.QuadPart),
- debugstr_longlong(ffsi.TotalAllocationUnits.QuadPart));
+ wine_dbgstr_longlong(fsi.TotalAllocationUnits.QuadPart),
+ wine_dbgstr_longlong(ffsi.TotalAllocationUnits.QuadPart));
ok(ffsi.CallerAvailableAllocationUnits.QuadPart ==
fsi.AvailableAllocationUnits.QuadPart,
"[ffsi] CallerAvailableAllocationUnits error fsi:0x%s, ffsi: 0x%s\n",
- debugstr_longlong(fsi.AvailableAllocationUnits.QuadPart),
- debugstr_longlong(ffsi.CallerAvailableAllocationUnits.QuadPart));
+ wine_dbgstr_longlong(fsi.AvailableAllocationUnits.QuadPart),
+ wine_dbgstr_longlong(ffsi.CallerAvailableAllocationUnits.QuadPart));
/* Assume file system is NTFS */
ok(ffsi.BytesPerSector == 512, "[ffsi] BytesPerSector expected 512, got
%d\n",ffsi.BytesPerSector);
@@ -1592,7 +1393,7 @@ static void test_file_rename_information(void)
res = pNtQueryInformationFile( handle, &io, fni, sizeof(FILE_NAME_INFORMATION) +
MAX_PATH * sizeof(WCHAR), FileNameInformation );
ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res );
fni->FileName[ fni->FileNameLength / sizeof(WCHAR) ] = 0;
- ok( !lstrcmpW(fni->FileName, newpath + 2), "FileName expected %s, got
%s\n",
+ ok( !lstrcmpiW(fni->FileName, newpath + 2), "FileName expected %s, got
%s\n",
wine_dbgstr_w(newpath + 2), wine_dbgstr_w(fni->FileName) );
HeapFree( GetProcessHeap(), 0, fni );
@@ -1762,7 +1563,7 @@ static void test_file_rename_information(void)
res = pNtQueryInformationFile( handle, &io, fni, sizeof(FILE_NAME_INFORMATION) +
MAX_PATH * sizeof(WCHAR), FileNameInformation );
ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res );
fni->FileName[ fni->FileNameLength / sizeof(WCHAR) ] = 0;
- ok( !lstrcmpW(fni->FileName, newpath + 2), "FileName expected %s, got
%s\n",
+ ok( !lstrcmpiW(fni->FileName, newpath + 2), "FileName expected %s, got
%s\n",
wine_dbgstr_w(newpath + 2), wine_dbgstr_w(fni->FileName) );
HeapFree( GetProcessHeap(), 0, fni );
@@ -2168,7 +1969,7 @@ static void test_file_rename_information(void)
res = pNtQueryInformationFile( handle, &io, fni, sizeof(FILE_NAME_INFORMATION) +
MAX_PATH * sizeof(WCHAR), FileNameInformation );
ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res );
fni->FileName[ fni->FileNameLength / sizeof(WCHAR) ] = 0;
- ok( !lstrcmpW(fni->FileName, newpath + 2), "FileName expected %s, got
%s\n",
+ ok( !lstrcmpiW(fni->FileName, newpath + 2), "FileName expected %s, got
%s\n",
wine_dbgstr_w(newpath + 2), wine_dbgstr_w(fni->FileName) );
HeapFree( GetProcessHeap(), 0, fni );
@@ -2181,6 +1982,7 @@ static void test_file_rename_information(void)
static void test_file_link_information(void)
{
+ static const WCHAR pipeW[] =
{'\\','\\','.','\\','p','i','p','e','\\','w','i','n','e','_','t','e','s','t',0};
static const WCHAR foo_txtW[] =
{'\\','f','o','o','.','t','x','t',0};
static const WCHAR fooW[] = {'f','o','o',0};
WCHAR tmp_path[MAX_PATH], oldpath[MAX_PATH + 16], newpath[MAX_PATH + 16], *filename,
*p;
@@ -2224,7 +2026,7 @@ static void test_file_link_information(void)
res = pNtQueryInformationFile( handle, &io, fni, sizeof(FILE_NAME_INFORMATION) +
MAX_PATH * sizeof(WCHAR), FileNameInformation );
ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res );
fni->FileName[ fni->FileNameLength / sizeof(WCHAR) ] = 0;
- ok( !lstrcmpW(fni->FileName, oldpath + 2), "FileName expected %s, got
%s\n",
+ ok( !lstrcmpiW(fni->FileName, oldpath + 2), "FileName expected %s, got
%s\n",
wine_dbgstr_w(oldpath + 2), wine_dbgstr_w(fni->FileName) );
HeapFree( GetProcessHeap(), 0, fni );
@@ -2394,7 +2196,7 @@ static void test_file_link_information(void)
res = pNtQueryInformationFile( handle, &io, fni, sizeof(FILE_NAME_INFORMATION) +
MAX_PATH * sizeof(WCHAR), FileNameInformation );
ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res );
fni->FileName[ fni->FileNameLength / sizeof(WCHAR) ] = 0;
- ok( !lstrcmpW(fni->FileName, oldpath + 2), "FileName expected %s, got
%s\n",
+ ok( !lstrcmpiW(fni->FileName, oldpath + 2), "FileName expected %s, got
%s\n",
wine_dbgstr_w(oldpath + 2), wine_dbgstr_w(fni->FileName) );
HeapFree( GetProcessHeap(), 0, fni );
@@ -2797,12 +2599,36 @@ static void test_file_link_information(void)
res = pNtQueryInformationFile( handle, &io, fni, sizeof(FILE_NAME_INFORMATION) +
MAX_PATH * sizeof(WCHAR), FileNameInformation );
ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res );
fni->FileName[ fni->FileNameLength / sizeof(WCHAR) ] = 0;
- ok( !lstrcmpW(fni->FileName, oldpath + 2), "FileName expected %s, got
%s\n",
+ ok( !lstrcmpiW(fni->FileName, oldpath + 2), "FileName expected %s, got
%s\n",
wine_dbgstr_w(oldpath + 2), wine_dbgstr_w(fni->FileName) );
HeapFree( GetProcessHeap(), 0, fni );
CloseHandle( handle );
CloseHandle( handle2 );
+
+ handle = CreateEventA( NULL, FALSE, FALSE, "wine_test_event" );
+ ok( !!handle, "Failed to create event: %u\n", GetLastError());
+
+ fni = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_NAME_INFORMATION) + MAX_PATH *
sizeof(WCHAR) );
+ res = pNtQueryInformationFile( handle, &io, fni, sizeof(FILE_NAME_INFORMATION) +
MAX_PATH * sizeof(WCHAR), FileNameInformation );
+ ok( res == STATUS_OBJECT_TYPE_MISMATCH, "res expected
STATUS_OBJECT_TYPE_MISMATCH, got %x\n", res );
+ HeapFree( GetProcessHeap(), 0, fni );
+
+ CloseHandle( handle );
+
+ handle = CreateNamedPipeW( pipeW, PIPE_ACCESS_DUPLEX,
PIPE_TYPE_BYTE|PIPE_READMODE_BYTE, 10, 512, 512, 0, NULL);
+ ok( handle != INVALID_HANDLE_VALUE, "Failed to create named pipe: %u\n",
GetLastError());
+
+ fni = HeapAlloc( GetProcessHeap(), 0, sizeof(FILE_NAME_INFORMATION) + MAX_PATH *
sizeof(WCHAR) );
+ res = pNtQueryInformationFile( handle, &io, fni, sizeof(FILE_NAME_INFORMATION) +
MAX_PATH * sizeof(WCHAR), FileNameInformation );
+ ok( res == STATUS_SUCCESS, "res expected STATUS_SUCCESS, got %x\n", res );
+ fni->FileName[ fni->FileNameLength / sizeof(WCHAR) ] = 0;
+ ok( !lstrcmpiW(fni->FileName, pipeW + 8), "FileName expected %s, got
%s\n",
+ wine_dbgstr_w(pipeW + 8), wine_dbgstr_w(fni->FileName) );
+ HeapFree( GetProcessHeap(), 0, fni );
+
+ CloseHandle( handle );
+
HeapFree( GetProcessHeap(), 0, fli );
delete_object( oldpath );
delete_object( newpath );
@@ -3349,6 +3175,213 @@ static void test_file_all_name_information(void)
HeapFree( GetProcessHeap(), 0, file_name );
}
+static void test_file_completion_information(void)
+{
+ static const char buf[] = "testdata";
+ FILE_IO_COMPLETION_NOTIFICATION_INFORMATION info;
+ OVERLAPPED ov, *pov;
+ IO_STATUS_BLOCK io;
+ NTSTATUS status;
+ DWORD num_bytes;
+ HANDLE port, h;
+ ULONG_PTR key;
+ BOOL ret;
+ int i;
+
+ if (!(h = create_temp_file(0))) return;
+
+ status = pNtSetInformationFile(h, &io, &info, sizeof(info) - 1,
FileIoCompletionNotificationInformation);
+ ok(status == STATUS_INFO_LENGTH_MISMATCH || status == STATUS_INVALID_INFO_CLASS /* XP
*/,
+ "expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status);
+ if (status == STATUS_INVALID_INFO_CLASS || status == STATUS_NOT_IMPLEMENTED)
+ {
+ win_skip("FileIoCompletionNotificationInformation class not
supported\n");
+ CloseHandle(h);
+ return;
+ }
+
+ info.Flags = FILE_SKIP_COMPLETION_PORT_ON_SUCCESS;
+ status = pNtSetInformationFile(h, &io, &info, sizeof(info),
FileIoCompletionNotificationInformation);
+ ok(status == STATUS_INVALID_PARAMETER, "expected STATUS_INVALID_PARAMETER, got
%08x\n", status);
+
+ CloseHandle(h);
+ if (!(h = create_temp_file(FILE_FLAG_OVERLAPPED))) return;
+
+ info.Flags = FILE_SKIP_SET_EVENT_ON_HANDLE;
+ status = pNtSetInformationFile(h, &io, &info, sizeof(info),
FileIoCompletionNotificationInformation);
+ ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n",
status);
+
+ info.Flags = FILE_SKIP_SET_USER_EVENT_ON_FAST_IO;
+ status = pNtSetInformationFile(h, &io, &info, sizeof(info),
FileIoCompletionNotificationInformation);
+ ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n",
status);
+
+ CloseHandle(h);
+ if (!(h = create_temp_file(FILE_FLAG_OVERLAPPED))) return;
+
+ info.Flags = ~0U;
+ status = pNtQueryInformationFile(h, &io, &info, sizeof(info),
FileIoCompletionNotificationInformation);
+ ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n",
status);
+ ok(!(info.Flags & FILE_SKIP_COMPLETION_PORT_ON_SUCCESS), "got %08x\n",
info.Flags);
+
+ memset(&ov, 0, sizeof(ov));
+ ov.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
+ port = CreateIoCompletionPort(h, NULL, 0xdeadbeef, 0);
+ ok(port != NULL, "CreateIoCompletionPort failed, error %u\n",
GetLastError());
+
+ for (i = 0; i < 10; i++)
+ {
+ SetLastError(0xdeadbeef);
+ ret = WriteFile(h, buf, sizeof(buf), &num_bytes, &ov);
+ if (ret || GetLastError() != ERROR_IO_PENDING) break;
+ ret = GetOverlappedResult(h, &ov, &num_bytes, TRUE);
+ ok(ret, "GetOverlappedResult failed, error %u\n", GetLastError());
+ ret = GetQueuedCompletionStatus(port, &num_bytes, &key, &pov, 1000);
+ ok(ret, "GetQueuedCompletionStatus failed, error %u\n",
GetLastError());
+ ret = FALSE;
+ }
+ if (ret)
+ {
+ ok(num_bytes == sizeof(buf), "expected sizeof(buf), got %u\n",
num_bytes);
+
+ key = 0;
+ pov = NULL;
+ ret = GetQueuedCompletionStatus(port, &num_bytes, &key, &pov, 1000);
+ ok(ret, "GetQueuedCompletionStatus failed, error %u\n",
GetLastError());
+ ok(key == 0xdeadbeef, "expected 0xdeadbeef, got %lx\n", key);
+ ok(pov == &ov, "expected %p, got %p\n", &ov, pov);
+ }
+ else
+ win_skip("WriteFile never returned TRUE\n");
+
+ info.Flags = FILE_SKIP_COMPLETION_PORT_ON_SUCCESS;
+ status = pNtSetInformationFile(h, &io, &info, sizeof(info),
FileIoCompletionNotificationInformation);
+ ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n",
status);
+
+ info.Flags = 0;
+ status = pNtQueryInformationFile(h, &io, &info, sizeof(info),
FileIoCompletionNotificationInformation);
+ ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n",
status);
+ ok((info.Flags & FILE_SKIP_COMPLETION_PORT_ON_SUCCESS) != 0, "got
%08x\n", info.Flags);
+
+ for (i = 0; i < 10; i++)
+ {
+ SetLastError(0xdeadbeef);
+ ret = WriteFile(h, buf, sizeof(buf), &num_bytes, &ov);
+ if (ret || GetLastError() != ERROR_IO_PENDING) break;
+ ret = GetOverlappedResult(h, &ov, &num_bytes, TRUE);
+ ok(ret, "GetOverlappedResult failed, error %u\n", GetLastError());
+ ret = FALSE;
+ }
+ if (ret)
+ {
+ ok(num_bytes == sizeof(buf), "expected sizeof(buf), got %u\n",
num_bytes);
+
+ pov = (void *)0xdeadbeef;
+ ret = GetQueuedCompletionStatus(port, &num_bytes, &key, &pov, 500);
+ ok(!ret, "GetQueuedCompletionStatus succeeded\n");
+ ok(pov == NULL, "expected NULL, got %p\n", pov);
+ }
+ else
+ win_skip("WriteFile never returned TRUE\n");
+
+ info.Flags = 0;
+ status = pNtSetInformationFile(h, &io, &info, sizeof(info),
FileIoCompletionNotificationInformation);
+ ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n",
status);
+
+ info.Flags = 0;
+ status = pNtQueryInformationFile(h, &io, &info, sizeof(info),
FileIoCompletionNotificationInformation);
+ ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n",
status);
+ ok((info.Flags & FILE_SKIP_COMPLETION_PORT_ON_SUCCESS) != 0, "got
%08x\n", info.Flags);
+
+ for (i = 0; i < 10; i++)
+ {
+ SetLastError(0xdeadbeef);
+ ret = WriteFile(h, buf, sizeof(buf), &num_bytes, &ov);
+ if (ret || GetLastError() != ERROR_IO_PENDING) break;
+ ret = GetOverlappedResult(h, &ov, &num_bytes, TRUE);
+ ok(ret, "GetOverlappedResult failed, error %u\n", GetLastError());
+ ret = GetQueuedCompletionStatus(port, &num_bytes, &key, &pov, 1000);
+ ok(ret, "GetQueuedCompletionStatus failed, error %u\n",
GetLastError());
+ ret = FALSE;
+ }
+ if (ret)
+ {
+ ok(num_bytes == sizeof(buf), "expected sizeof(buf), got %u\n",
num_bytes);
+
+ pov = (void *)0xdeadbeef;
+ ret = GetQueuedCompletionStatus(port, &num_bytes, &key, &pov, 1000);
+ ok(!ret, "GetQueuedCompletionStatus succeeded\n");
+ ok(pov == NULL, "expected NULL, got %p\n", pov);
+ }
+ else
+ win_skip("WriteFile never returned TRUE\n");
+
+ CloseHandle(ov.hEvent);
+ CloseHandle(port);
+ CloseHandle(h);
+}
+
+static void test_file_id_information(void)
+{
+ BY_HANDLE_FILE_INFORMATION info;
+ FILE_ID_INFORMATION fid;
+ IO_STATUS_BLOCK io;
+ NTSTATUS status;
+ DWORD *dwords;
+ HANDLE h;
+ BOOL ret;
+
+ if (!(h = create_temp_file(0))) return;
+
+ memset( &fid, 0x11, sizeof(fid) );
+ status = pNtQueryInformationFile( h, &io, &fid, sizeof(fid),
FileIdInformation );
+ if (status == STATUS_NOT_IMPLEMENTED || status == STATUS_INVALID_INFO_CLASS)
+ {
+ win_skip( "FileIdInformation not supported\n" );
+ CloseHandle( h );
+ return;
+ }
+
+ memset( &info, 0x22, sizeof(info) );
+ ret = GetFileInformationByHandle( h, &info );
+ ok( ret, "GetFileInformationByHandle failed\n" );
+
+ dwords = (DWORD *)&fid.VolumeSerialNumber;
+ ok( dwords[0] == info.dwVolumeSerialNumber, "expected %08x, got %08x\n",
+ info.dwVolumeSerialNumber, dwords[0] );
+ ok( dwords[1] != 0x11111111, "expected != 0x11111111\n" );
+
+ dwords = (DWORD *)&fid.FileId;
+ ok( dwords[0] == info.nFileIndexLow, "expected %08x, got %08x\n",
info.nFileIndexLow, dwords[0] );
+ ok( dwords[1] == info.nFileIndexHigh, "expected %08x, got %08x\n",
info.nFileIndexHigh, dwords[1] );
+ ok( dwords[2] == 0, "expected 0, got %08x\n", dwords[2] );
+ ok( dwords[3] == 0, "expected 0, got %08x\n", dwords[3] );
+
+ CloseHandle( h );
+}
+
+static void test_file_access_information(void)
+{
+ FILE_ACCESS_INFORMATION info;
+ IO_STATUS_BLOCK io;
+ NTSTATUS status;
+ HANDLE h;
+
+ if (!(h = create_temp_file(0))) return;
+
+ status = pNtQueryInformationFile( h, &io, &info, sizeof(info) - 1,
FileAccessInformation );
+ ok( status == STATUS_INFO_LENGTH_MISMATCH, "expected
STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status );
+
+ status = pNtQueryInformationFile( (HANDLE)0xdeadbeef, &io, &info,
sizeof(info), FileAccessInformation );
+ ok( status == STATUS_INVALID_HANDLE, "expected STATUS_INVALID_HANDLE, got
%08x\n", status );
+
+ memset(&info, 0x11, sizeof(info));
+ status = pNtQueryInformationFile( h, &io, &info, sizeof(info),
FileAccessInformation );
+ ok( status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status
);
+ ok( info.AccessFlags == 0x13019f, "got %08x\n", info.AccessFlags );
+
+ CloseHandle( h );
+}
+
static void test_query_volume_information_file(void)
{
NTSTATUS status;
@@ -3616,13 +3649,15 @@ static void test_read_write(void)
{
static const char contents[14] = "1234567890abcd";
char buf[256];
- HANDLE hfile;
+ HANDLE hfile, event;
OVERLAPPED ovl;
IO_STATUS_BLOCK iob;
DWORD ret, bytes, status, off;
LARGE_INTEGER offset;
LONG i;
+ event = CreateEventA( NULL, TRUE, FALSE, NULL );
+
U(iob).Status = -1;
iob.Information = -1;
offset.QuadPart = 0;
@@ -3631,6 +3666,22 @@ static void test_read_write(void)
ok(U(iob).Status == -1, "expected -1, got %#x\n", U(iob).Status);
ok(iob.Information == -1, "expected -1, got %lu\n", iob.Information);
+ U(iob).Status = -1;
+ iob.Information = -1;
+ offset.QuadPart = 0;
+ status = pNtReadFile(INVALID_HANDLE_VALUE, 0, NULL, NULL, &iob, NULL,
sizeof(buf), &offset, NULL);
+ ok(status == STATUS_OBJECT_TYPE_MISMATCH || status == STATUS_INVALID_HANDLE,
"expected STATUS_OBJECT_TYPE_MISMATCH, got %#x\n", status);
+ ok(U(iob).Status == -1, "expected -1, got %#x\n", U(iob).Status);
+ ok(iob.Information == -1, "expected -1, got %lu\n", iob.Information);
+
+ U(iob).Status = -1;
+ iob.Information = -1;
+ offset.QuadPart = 0;
+ status = pNtWriteFile(INVALID_HANDLE_VALUE, 0, NULL, NULL, &iob, buf,
sizeof(buf), &offset, NULL);
+ ok(status == STATUS_OBJECT_TYPE_MISMATCH || status == STATUS_INVALID_HANDLE,
"expected STATUS_OBJECT_TYPE_MISMATCH, got %#x\n", status);
+ ok(U(iob).Status == -1, "expected -1, got %#x\n", U(iob).Status);
+ ok(iob.Information == -1, "expected -1, got %lu\n", iob.Information);
+
U(iob).Status = -1;
iob.Information = -1;
offset.QuadPart = 0;
@@ -3649,6 +3700,15 @@ static void test_read_write(void)
ok(U(iob).Status == -1, "expected -1, got %#x\n", U(iob).Status);
ok(iob.Information == -1, "expected -1, got %lu\n", iob.Information);
+ U(iob).Status = -1;
+ iob.Information = -1;
+ SetEvent(event);
+ status = pNtWriteFile(hfile, event, NULL, NULL, &iob, NULL, sizeof(contents),
NULL, NULL);
+ ok(status == STATUS_INVALID_USER_BUFFER, "expected STATUS_INVALID_USER_BUFFER,
got %#x\n", status);
+ ok(U(iob).Status == -1, "expected -1, got %#x\n", U(iob).Status);
+ ok(iob.Information == -1, "expected -1, got %lu\n", iob.Information);
+ ok(!is_signaled(event), "event is not signaled\n");
+
U(iob).Status = -1;
iob.Information = -1;
status = pNtReadFile(hfile, 0, NULL, NULL, &iob, NULL, sizeof(contents), NULL,
NULL);
@@ -3656,6 +3716,24 @@ static void test_read_write(void)
ok(U(iob).Status == -1, "expected -1, got %#x\n", U(iob).Status);
ok(iob.Information == -1, "expected -1, got %lu\n", iob.Information);
+ U(iob).Status = -1;
+ iob.Information = -1;
+ SetEvent(event);
+ status = pNtReadFile(hfile, event, NULL, NULL, &iob, NULL, sizeof(contents),
NULL, NULL);
+ ok(status == STATUS_ACCESS_VIOLATION, "expected STATUS_ACCESS_VIOLATION, got
%#x\n", status);
+ ok(U(iob).Status == -1, "expected -1, got %#x\n", U(iob).Status);
+ ok(iob.Information == -1, "expected -1, got %lu\n", iob.Information);
+ ok(is_signaled(event), "event is not signaled\n");
+
+ U(iob).Status = -1;
+ iob.Information = -1;
+ SetEvent(event);
+ status = pNtReadFile(hfile, event, NULL, NULL, &iob, (void*)0xdeadbeef,
sizeof(contents), NULL, NULL);
+ ok(status == STATUS_ACCESS_VIOLATION, "expected STATUS_ACCESS_VIOLATION, got
%#x\n", status);
+ ok(U(iob).Status == -1, "expected -1, got %#x\n", U(iob).Status);
+ ok(iob.Information == -1, "expected -1, got %lu\n", iob.Information);
+ ok(is_signaled(event), "event is not signaled\n");
+
U(iob).Status = -1;
iob.Information = -1;
status = pNtWriteFile(hfile, 0, NULL, NULL, &iob, contents, 7, NULL, NULL);
@@ -4321,7 +4399,78 @@ static void test_read_write(void)
off = SetFilePointer(hfile, 0, NULL, FILE_CURRENT);
ok(off == 0, "expected 0, got %u\n", off);
+ CloseHandle(event);
+ CloseHandle(hfile);
+}
+
+static void test_ioctl(void)
+{
+ HANDLE event = CreateEventA(NULL, TRUE, FALSE, NULL);
+ IO_STATUS_BLOCK iosb;
+ HANDLE file;
+ NTSTATUS status;
+
+ file = create_temp_file(FILE_FLAG_OVERLAPPED);
+ ok(file != INVALID_HANDLE_VALUE, "could not create temp file\n");
+
+ SetEvent(event);
+ status = pNtFsControlFile(file, event, NULL, NULL, &iosb, 0xdeadbeef, 0, 0, 0,
0);
+ todo_wine
+ ok(status == STATUS_INVALID_DEVICE_REQUEST, "NtFsControlFile returned
%x\n", status);
+ ok(!is_signaled(event), "event is signaled\n");
+
+ status = pNtFsControlFile(file, (HANDLE)0xdeadbeef, NULL, NULL, &iosb,
0xdeadbeef, 0, 0, 0, 0);
+ ok(status == STATUS_INVALID_HANDLE, "NtFsControlFile returned %x\n",
status);
+
+ CloseHandle(event);
+ CloseHandle(file);
+}
+
+static void test_flush_buffers_file(void)
+{
+ char path[MAX_PATH], buffer[MAX_PATH];
+ HANDLE hfile, hfileread;
+ NTSTATUS status;
+ IO_STATUS_BLOCK io_status_block;
+
+ GetTempPathA(MAX_PATH, path);
+ GetTempFileNameA(path, "foo", 0, buffer);
+ hfile = CreateFileA(buffer, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL,
CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, 0);
+ ok(hfile != INVALID_HANDLE_VALUE, "failed to create temp file.\n" );
+
+ hfileread = CreateFileA(buffer, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
+ OPEN_EXISTING, 0, NULL);
+ ok(hfileread != INVALID_HANDLE_VALUE, "could not open temp file, error
%d.\n", GetLastError());
+
+ status = pNtFlushBuffersFile(hfile, NULL);
+ todo_wine
+ ok(status == STATUS_ACCESS_VIOLATION, "expected STATUS_ACCESS_VIOLATION, got
%#x.\n", status);
+
+ status = pNtFlushBuffersFile(hfile, (IO_STATUS_BLOCK *)0xdeadbeaf);
+ todo_wine
+ ok(status == STATUS_ACCESS_VIOLATION, "expected STATUS_ACCESS_VIOLATION, got
%#x.\n", status);
+
+ status = pNtFlushBuffersFile(hfile, &io_status_block);
+ ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x.\n",
status);
+
+ status = pNtFlushBuffersFile(hfileread, &io_status_block);
+ ok(status == STATUS_ACCESS_DENIED, "expected STATUS_ACCESS_DENIED, got
%#x.\n", status);
+
+ status = pNtFlushBuffersFile(NULL, &io_status_block);
+ ok(status == STATUS_INVALID_HANDLE, "expected STATUS_INVALID_HANDLE, got
%#x.\n", status);
+
+ CloseHandle(hfileread);
CloseHandle(hfile);
+ hfile = CreateFileA(buffer, FILE_APPEND_DATA, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
+ OPEN_EXISTING, 0, NULL);
+ ok(hfile != INVALID_HANDLE_VALUE, "could not open temp file, error %d.\n",
GetLastError());
+
+ status = pNtFlushBuffersFile(hfile, &io_status_block);
+ ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#x.\n",
status);
+
+ CloseHandle(hfile);
+ DeleteFileA(buffer);
}
static void test_query_ea(void)
@@ -4601,6 +4750,7 @@ START_TEST(file)
pNtCancelIoFile = (void *)GetProcAddress(hntdll,
"NtCancelIoFile");
pNtCancelIoFileEx = (void *)GetProcAddress(hntdll,
"NtCancelIoFileEx");
pNtClose = (void *)GetProcAddress(hntdll, "NtClose");
+ pNtFsControlFile = (void *)GetProcAddress(hntdll,
"NtFsControlFile");
pNtCreateIoCompletion = (void *)GetProcAddress(hntdll,
"NtCreateIoCompletion");
pNtOpenIoCompletion = (void *)GetProcAddress(hntdll,
"NtOpenIoCompletion");
pNtQueryIoCompletion = (void *)GetProcAddress(hntdll,
"NtQueryIoCompletion");
@@ -4611,6 +4761,7 @@ START_TEST(file)
pNtQueryDirectoryFile = (void *)GetProcAddress(hntdll,
"NtQueryDirectoryFile");
pNtQueryVolumeInformationFile = (void *)GetProcAddress(hntdll,
"NtQueryVolumeInformationFile");
pNtQueryFullAttributesFile = (void *)GetProcAddress(hntdll,
"NtQueryFullAttributesFile");
+ pNtFlushBuffersFile = (void *)GetProcAddress(hntdll,
"NtFlushBuffersFile");
pNtQueryEaFile = (void *)GetProcAddress(hntdll, "NtQueryEaFile");
test_read_write();
@@ -4632,8 +4783,13 @@ START_TEST(file)
test_file_rename_information();
test_file_link_information();
test_file_disposition_information();
+ test_file_completion_information();
+ test_file_id_information();
+ test_file_access_information();
test_query_volume_information_file();
test_query_attribute_information_file();
+ test_ioctl();
+ test_flush_buffers_file();
test_query_ea();
test_junction_points();
}
diff --git a/modules/rostests/winetests/ntdll/info.c
b/modules/rostests/winetests/ntdll/info.c
index c0e2b1ac5d..d03d26c0b9 100755
--- a/modules/rostests/winetests/ntdll/info.c
+++ b/modules/rostests/winetests/ntdll/info.c
@@ -22,7 +22,9 @@
#include <winnls.h>
#include <stdio.h>
+static NTSTATUS (WINAPI * pRtlDowncaseUnicodeString)(UNICODE_STRING *, const
UNICODE_STRING *, BOOLEAN);
static NTSTATUS (WINAPI * pNtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS, PVOID,
ULONG, PULONG);
+static NTSTATUS (WINAPI * pNtQuerySystemInformationEx)(SYSTEM_INFORMATION_CLASS, void*,
ULONG, void*, ULONG, ULONG*);
static NTSTATUS (WINAPI * pNtPowerInformation)(POWER_INFORMATION_LEVEL, PVOID, ULONG,
PVOID, ULONG);
static NTSTATUS (WINAPI * pNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID,
ULONG, PULONG);
static NTSTATUS (WINAPI * pNtQueryInformationThread)(HANDLE, THREADINFOCLASS, PVOID,
ULONG, PULONG);
@@ -36,6 +38,7 @@ static NTSTATUS (WINAPI * pNtUnmapViewOfSection)(HANDLE,PVOID);
static NTSTATUS (WINAPI * pNtClose)(HANDLE);
static ULONG (WINAPI * pNtGetCurrentProcessorNumber)(void);
static BOOL (WINAPI * pIsWow64Process)(HANDLE, PBOOL);
+static BOOL (WINAPI *
pGetLogicalProcessorInformationEx)(LOGICAL_PROCESSOR_RELATIONSHIP,SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*,DWORD*);
static BOOL is_wow64;
@@ -56,12 +59,15 @@ static BOOL InitFunctionPtrs(void)
{
/* All needed functions are NT based, so using GetModuleHandle is a good check */
HMODULE hntdll = GetModuleHandleA("ntdll");
+ HMODULE hkernel32 = GetModuleHandleA("kernel32");
+
if (!hntdll)
{
win_skip("Not running on NT\n");
return FALSE;
}
+ NTDLL_GET_PROC(RtlDowncaseUnicodeString);
NTDLL_GET_PROC(NtQuerySystemInformation);
NTDLL_GET_PROC(NtPowerInformation);
NTDLL_GET_PROC(NtQueryInformationProcess);
@@ -78,8 +84,16 @@ static BOOL InitFunctionPtrs(void)
/* not present before XP */
pNtGetCurrentProcessorNumber = (void *) GetProcAddress(hntdll,
"NtGetCurrentProcessorNumber");
- pIsWow64Process = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"),
"IsWow64Process");
+ pIsWow64Process = (void *)GetProcAddress(hkernel32, "IsWow64Process");
if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 ))
is_wow64 = FALSE;
+
+ /* starting with Win7 */
+ pNtQuerySystemInformationEx = (void *) GetProcAddress(hntdll,
"NtQuerySystemInformationEx");
+ if (!pNtQuerySystemInformationEx)
+ win_skip("NtQuerySystemInformationEx() is not supported, some tests will be
skipped.\n");
+
+ pGetLogicalProcessorInformationEx = (void *) GetProcAddress(hkernel32,
"GetLogicalProcessorInformationEx");
+
return TRUE;
}
@@ -288,7 +302,7 @@ static void test_query_process(void)
/* test ReturnLength */
ReturnLength = 0;
status = pNtQuerySystemInformation(SystemProcessInformation, NULL, 0,
&ReturnLength);
- ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_LENGTH_MISMATCH got
%08x\n", status);
+ ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH
got %08x\n", status);
ok( ReturnLength > 0 || broken(ReturnLength == 0) /* NT4, Win2K */,
"Expected a ReturnLength to show the needed length\n");
@@ -474,13 +488,15 @@ static void test_query_module(void)
static void test_query_handle(void)
{
NTSTATUS status;
- ULONG ReturnLength;
+ ULONG ExpectedLength, ReturnLength;
ULONG SystemInformationLength = sizeof(SYSTEM_HANDLE_INFORMATION);
SYSTEM_HANDLE_INFORMATION* shi = HeapAlloc(GetProcessHeap(), 0,
SystemInformationLength);
- HANDLE event_handle;
+ HANDLE EventHandle;
+ BOOL found;
+ INT i;
- event_handle = CreateEventA(NULL, FALSE, FALSE, NULL);
- ok( event_handle != NULL, "CreateEventA failed %u\n", GetLastError() );
+ EventHandle = CreateEventA(NULL, FALSE, FALSE, NULL);
+ ok( EventHandle != NULL, "CreateEventA failed %u\n", GetLastError() );
/* Request the needed length : a SystemInformationLength greater than one struct sets
ReturnLength */
ReturnLength = 0xdeadbeef;
@@ -490,34 +506,116 @@ static void test_query_handle(void)
SystemInformationLength = ReturnLength;
shi = HeapReAlloc(GetProcessHeap(), 0, shi , SystemInformationLength);
+ memset(shi, 0x55, SystemInformationLength);
ReturnLength = 0xdeadbeef;
status = pNtQuerySystemInformation(SystemHandleInformation, shi,
SystemInformationLength, &ReturnLength);
- if (status != STATUS_INFO_LENGTH_MISMATCH) /* vista */
+ while (status == STATUS_INFO_LENGTH_MISMATCH) /* Vista / 2008 */
{
- ULONG ExpectedLength = FIELD_OFFSET(SYSTEM_HANDLE_INFORMATION,
Handle[shi->Count]);
- unsigned int i;
- BOOL found = FALSE;
+ SystemInformationLength *= 2;
+ shi = HeapReAlloc(GetProcessHeap(), 0, shi, SystemInformationLength);
+ memset(shi, 0x55, SystemInformationLength);
+ status = pNtQuerySystemInformation(SystemHandleInformation, shi,
SystemInformationLength, &ReturnLength);
+ }
+ ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status
);
+ ExpectedLength = FIELD_OFFSET(SYSTEM_HANDLE_INFORMATION, Handle[shi->Count]);
+ ok( ReturnLength == ExpectedLength || broken(ReturnLength == ExpectedLength -
sizeof(DWORD)), /* Vista / 2008 */
+ "Expected length %u, got %u\n", ExpectedLength, ReturnLength );
+ ok( shi->Count > 1, "Expected more than 1 handle, got %u\n",
shi->Count );
+ ok( shi->Handle[1].HandleValue != 0x5555 || broken( shi->Handle[1].HandleValue
== 0x5555 ), /* Vista / 2008 */
+ "Uninitialized second handle\n" );
+ if (shi->Handle[1].HandleValue == 0x5555)
+ {
+ win_skip("Skipping broken SYSTEM_HANDLE_INFORMATION\n");
+ CloseHandle(EventHandle);
+ goto done;
+ }
+
+ for (i = 0, found = FALSE; i < shi->Count && !found; i++)
+ found = (shi->Handle[i].OwnerPid == GetCurrentProcessId()) &&
+ ((HANDLE)(ULONG_PTR)shi->Handle[i].HandleValue == EventHandle);
+ ok( found, "Expected to find event handle %p (pid %x) in handle list\n",
EventHandle, GetCurrentProcessId() );
- ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n",
status );
- ok( ReturnLength == ExpectedLength, "Expected length %u, got %u\n",
ExpectedLength, ReturnLength );
- ok( shi->Count > 1, "Expected more than 1 handles, got %u\n",
shi->Count );
+ if (!found)
for (i = 0; i < shi->Count; i++)
- {
- if (shi->Handle[i].OwnerPid == GetCurrentProcessId() &&
- (HANDLE)(ULONG_PTR)shi->Handle[i].HandleValue == event_handle)
- {
- found = TRUE;
- break;
- }
- }
- ok( found, "Expected to find event handle in handle list\n" );
+ trace( "%d: handle %x pid %x\n", i, shi->Handle[i].HandleValue,
shi->Handle[i].OwnerPid );
+
+ CloseHandle(EventHandle);
+
+ ReturnLength = 0xdeadbeef;
+ status = pNtQuerySystemInformation(SystemHandleInformation, shi,
SystemInformationLength, &ReturnLength);
+ while (status == STATUS_INFO_LENGTH_MISMATCH) /* Vista / 2008 */
+ {
+ SystemInformationLength *= 2;
+ shi = HeapReAlloc(GetProcessHeap(), 0, shi, SystemInformationLength);
+ status = pNtQuerySystemInformation(SystemHandleInformation, shi,
SystemInformationLength, &ReturnLength);
}
+ ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status
);
+ for (i = 0, found = FALSE; i < shi->Count && !found; i++)
+ found = (shi->Handle[i].OwnerPid == GetCurrentProcessId()) &&
+ ((HANDLE)(ULONG_PTR)shi->Handle[i].HandleValue == EventHandle);
+ ok( !found, "Unexpectedly found event handle in handle list\n" );
status = pNtQuerySystemInformation(SystemHandleInformation, NULL,
SystemInformationLength, &ReturnLength);
ok( status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got
%08x\n", status );
- CloseHandle(event_handle);
+done:
+ HeapFree( GetProcessHeap(), 0, shi);
+}
+
+static void test_query_handle_ex(void)
+{
+ NTSTATUS status;
+ ULONG ExpectedLength, ReturnLength;
+ ULONG SystemInformationLength = sizeof(SYSTEM_HANDLE_INFORMATION_EX);
+ SYSTEM_HANDLE_INFORMATION_EX* shi = HeapAlloc(GetProcessHeap(), 0,
SystemInformationLength);
+ HANDLE EventHandle;
+ BOOL found;
+ INT i;
+
+ EventHandle = CreateEventA(NULL, FALSE, FALSE, NULL);
+ ok( EventHandle != NULL, "CreateEventA failed %u\n", GetLastError() );
+
+ ReturnLength = 0xdeadbeef;
+ status = pNtQuerySystemInformation(SystemExtendedHandleInformation, shi,
SystemInformationLength, &ReturnLength);
+ ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected
STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status);
+ ok( ReturnLength != 0xdeadbeef, "Expected valid ReturnLength\n" );
+
+ SystemInformationLength = ReturnLength;
+ shi = HeapReAlloc(GetProcessHeap(), 0, shi , SystemInformationLength);
+ memset(shi, 0x55, SystemInformationLength);
+
+ ReturnLength = 0xdeadbeef;
+ status = pNtQuerySystemInformation(SystemExtendedHandleInformation, shi,
SystemInformationLength, &ReturnLength);
+ ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status
);
+ ExpectedLength = FIELD_OFFSET(SYSTEM_HANDLE_INFORMATION_EX, Handle[shi->Count]);
+ ok( ReturnLength == ExpectedLength, "Expected length %u, got %u\n",
ExpectedLength, ReturnLength );
+ ok( shi->Count > 1, "Expected more than 1 handle, got %u\n",
(DWORD)shi->Count );
+
+ for (i = 0, found = FALSE; i < shi->Count && !found; i++)
+ found = (shi->Handle[i].UniqueProcessId == GetCurrentProcessId()) &&
+ ((HANDLE)(ULONG_PTR)shi->Handle[i].HandleValue == EventHandle);
+ ok( found, "Expected to find event handle %p (pid %x) in handle list\n",
EventHandle, GetCurrentProcessId() );
+
+ if (!found)
+ {
+ for (i = 0; i < shi->Count; i++)
+ trace( "%d: handle %x pid %x\n", i,
(DWORD)shi->Handle[i].HandleValue, (DWORD)shi->Handle[i].UniqueProcessId );
+ }
+
+ CloseHandle(EventHandle);
+
+ ReturnLength = 0xdeadbeef;
+ status = pNtQuerySystemInformation(SystemExtendedHandleInformation, shi,
SystemInformationLength, &ReturnLength);
+ ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status
);
+ for (i = 0, found = FALSE; i < shi->Count && !found; i++)
+ found = (shi->Handle[i].UniqueProcessId == GetCurrentProcessId()) &&
+ ((HANDLE)(ULONG_PTR)shi->Handle[i].HandleValue == EventHandle);
+ ok( !found, "Unexpectedly found event handle in handle list\n" );
+
+ status = pNtQuerySystemInformation(SystemExtendedHandleInformation, NULL,
SystemInformationLength, &ReturnLength);
+ ok( status == STATUS_ACCESS_VIOLATION, "Expected STATUS_ACCESS_VIOLATION, got
%08x\n", status );
+
HeapFree( GetProcessHeap(), 0, shi);
}
@@ -684,6 +782,110 @@ static void test_query_logicalproc(void)
HeapFree(GetProcessHeap(), 0, slpi);
}
+static void test_query_logicalprocex(void)
+{
+ SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *infoex, *infoex2;
+ DWORD relationship, len2, len;
+ NTSTATUS status;
+ BOOL ret;
+
+ if (!pNtQuerySystemInformationEx)
+ return;
+
+ len = 0;
+ relationship = RelationProcessorCore;
+ status = pNtQuerySystemInformationEx(SystemLogicalProcessorInformationEx,
&relationship, sizeof(relationship), NULL, 0, &len);
+ ok(status == STATUS_INFO_LENGTH_MISMATCH, "got 0x%08x\n", status);
+ ok(len > 0, "got %u\n", len);
+
+ len = 0;
+ relationship = RelationAll;
+ status = pNtQuerySystemInformationEx(SystemLogicalProcessorInformationEx,
&relationship, sizeof(relationship), NULL, 0, &len);
+ ok(status == STATUS_INFO_LENGTH_MISMATCH, "got 0x%08x\n", status);
+ ok(len > 0, "got %u\n", len);
+
+ len2 = 0;
+ ret = pGetLogicalProcessorInformationEx(RelationAll, NULL, &len2);
+ ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d, error
%d\n", ret, GetLastError());
+ ok(len == len2, "got %u, expected %u\n", len2, len);
+
+ if (len && len == len2) {
+ int j, i;
+
+ infoex = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
+ infoex2 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
+
+ status = pNtQuerySystemInformationEx(SystemLogicalProcessorInformationEx,
&relationship, sizeof(relationship), infoex, len, &len);
+ ok(status == STATUS_SUCCESS, "got 0x%08x\n", status);
+
+ ret = pGetLogicalProcessorInformationEx(RelationAll, infoex2, &len2);
+ ok(ret, "got %d, error %d\n", ret, GetLastError());
+ ok(!memcmp(infoex, infoex2, len), "returned info data mismatch\n");
+
+ for(i = 0; status == STATUS_SUCCESS && i < len; ){
+ SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *ex = (void*)(((char *)infoex) + i);
+
+ ok(ex->Relationship >= RelationProcessorCore &&
ex->Relationship <= RelationGroup,
+ "Got invalid relationship value: 0x%x\n",
ex->Relationship);
+ if (!ex->Size)
+ {
+ ok(0, "got infoex[%u].Size=0\n", i);
+ break;
+ }
+
+ trace("infoex[%u].Size: %u\n", i, ex->Size);
+ switch(ex->Relationship){
+ case RelationProcessorCore:
+ case RelationProcessorPackage:
+ trace("infoex[%u].Relationship: 0x%x (Core == 0x0 or Package ==
0x3)\n", i, ex->Relationship);
+ trace("infoex[%u].Processor.Flags: 0x%x\n", i,
ex->Processor.Flags);
+#ifndef __REACTOS__
+ trace("infoex[%u].Processor.EfficiencyClass: 0x%x\n", i,
ex->Processor.EfficiencyClass);
+#endif
+ trace("infoex[%u].Processor.GroupCount: 0x%x\n", i,
ex->Processor.GroupCount);
+ for(j = 0; j < ex->Processor.GroupCount; ++j){
+ trace("infoex[%u].Processor.GroupMask[%u].Mask: 0x%lx\n",
i, j, ex->Processor.GroupMask[j].Mask);
+ trace("infoex[%u].Processor.GroupMask[%u].Group: 0x%x\n",
i, j, ex->Processor.GroupMask[j].Group);
+ }
+ break;
+ case RelationNumaNode:
+ trace("infoex[%u].Relationship: 0x%x (NumaNode)\n", i,
ex->Relationship);
+ trace("infoex[%u].NumaNode.NodeNumber: 0x%x\n", i,
ex->NumaNode.NodeNumber);
+ trace("infoex[%u].NumaNode.GroupMask.Mask: 0x%lx\n", i,
ex->NumaNode.GroupMask.Mask);
+ trace("infoex[%u].NumaNode.GroupMask.Group: 0x%x\n", i,
ex->NumaNode.GroupMask.Group);
+ break;
+ case RelationCache:
+ trace("infoex[%u].Relationship: 0x%x (Cache)\n", i,
ex->Relationship);
+ trace("infoex[%u].Cache.Level: 0x%x\n", i,
ex->Cache.Level);
+ trace("infoex[%u].Cache.Associativity: 0x%x\n", i,
ex->Cache.Associativity);
+ trace("infoex[%u].Cache.LineSize: 0x%x\n", i,
ex->Cache.LineSize);
+ trace("infoex[%u].Cache.CacheSize: 0x%x\n", i,
ex->Cache.CacheSize);
+ trace("infoex[%u].Cache.Type: 0x%x\n", i, ex->Cache.Type);
+ trace("infoex[%u].Cache.GroupMask.Mask: 0x%lx\n", i,
ex->Cache.GroupMask.Mask);
+ trace("infoex[%u].Cache.GroupMask.Group: 0x%x\n", i,
ex->Cache.GroupMask.Group);
+ break;
+ case RelationGroup:
+ trace("infoex[%u].Relationship: 0x%x (Group)\n", i,
ex->Relationship);
+ trace("infoex[%u].Group.MaximumGroupCount: 0x%x\n", i,
ex->Group.MaximumGroupCount);
+ trace("infoex[%u].Group.ActiveGroupCount: 0x%x\n", i,
ex->Group.ActiveGroupCount);
+ for(j = 0; j < ex->Group.ActiveGroupCount; ++j){
+ trace("infoex[%u].Group.GroupInfo[%u].MaximumProcessorCount:
0x%x\n", i, j, ex->Group.GroupInfo[j].MaximumProcessorCount);
+ trace("infoex[%u].Group.GroupInfo[%u].ActiveProcessorCount:
0x%x\n", i, j, ex->Group.GroupInfo[j].ActiveProcessorCount);
+ trace("infoex[%u].Group.GroupInfo[%u].ActiveProcessorMask:
0x%lx\n", i, j, ex->Group.GroupInfo[j].ActiveProcessorMask);
+ }
+ break;
+ default:
+ break;
+ }
+
+ i += ex->Size;
+ }
+
+ HeapFree(GetProcessHeap(), 0, infoex);
+ HeapFree(GetProcessHeap(), 0, infoex2);
+ }
+}
+
static void test_query_processor_power_info(void)
{
NTSTATUS status;
@@ -904,12 +1106,32 @@ static void test_query_process_basic(void)
ok( pbi.UniqueProcessId > 0, "Expected a ProcessID > 0, got 0\n");
}
+static void dump_vm_counters(const char *header, const VM_COUNTERS *pvi)
+{
+ trace("%s:\n", header);
+ trace("PeakVirtualSize : %lu\n", pvi->PeakVirtualSize);
+ trace("VirtualSize : %lu\n", pvi->VirtualSize);
+ trace("PageFaultCount : %u\n", pvi->PageFaultCount);
+ trace("PeakWorkingSetSize : %lu\n", pvi->PeakWorkingSetSize);
+ trace("WorkingSetSize : %lu\n", pvi->WorkingSetSize);
+ trace("QuotaPeakPagedPoolUsage : %lu\n",
pvi->QuotaPeakPagedPoolUsage);
+ trace("QuotaPagedPoolUsage : %lu\n", pvi->QuotaPagedPoolUsage);
+ trace("QuotaPeakNonPagePoolUsage : %lu\n",
pvi->QuotaPeakNonPagedPoolUsage);
+ trace("QuotaNonPagePoolUsage : %lu\n",
pvi->QuotaNonPagedPoolUsage);
+ trace("PagefileUsage : %lu\n", pvi->PagefileUsage);
+ trace("PeakPagefileUsage : %lu\n", pvi->PeakPagefileUsage);
+}
+
static void test_query_process_vm(void)
{
NTSTATUS status;
ULONG ReturnLength;
VM_COUNTERS pvi;
ULONG old_size = FIELD_OFFSET(VM_COUNTERS,PrivatePageCount);
+ HANDLE process;
+ SIZE_T prev_size;
+ const SIZE_T alloc_size = 16 * 1024 * 1024;
+ void *ptr;
status = pNtQueryInformationProcess(NULL, ProcessVmCounters, NULL, sizeof(pvi),
NULL);
ok( status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_HANDLE,
@@ -935,11 +1157,72 @@ static void test_query_process_vm(void)
ok( ReturnLength == old_size || ReturnLength == sizeof(pvi), "Inconsistent
length %d\n", ReturnLength);
/* Check if we have some return values */
- trace("WorkingSetSize : %ld\n", pvi.WorkingSetSize);
- todo_wine
- {
- ok( pvi.WorkingSetSize > 0, "Expected a WorkingSetSize > 0\n");
- }
+ dump_vm_counters("VM counters for GetCurrentProcess", &pvi);
+ ok( pvi.WorkingSetSize > 0, "Expected a WorkingSetSize > 0\n");
+ ok( pvi.PagefileUsage > 0, "Expected a PagefileUsage > 0\n");
+
+ process = OpenProcess(PROCESS_VM_READ, FALSE, GetCurrentProcessId());
+ status = pNtQueryInformationProcess(process, ProcessVmCounters, &pvi,
sizeof(pvi), NULL);
+ ok( status == STATUS_ACCESS_DENIED, "Expected STATUS_ACCESS_DENIED, got
%08x\n", status);
+ CloseHandle(process);
+
+ process = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE,
GetCurrentProcessId());
+ status = pNtQueryInformationProcess(process, ProcessVmCounters, &pvi,
sizeof(pvi), NULL);
+ ok( status == STATUS_SUCCESS || broken(!process) /* XP */, "Expected
STATUS_SUCCESS, got %08x\n", status);
+ CloseHandle(process);
+
+ memset(&pvi, 0, sizeof(pvi));
+ process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId());
+ status = pNtQueryInformationProcess(process, ProcessVmCounters, &pvi,
sizeof(pvi), NULL);
+ ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n",
status);
+
+ /* Check if we have some return values */
+ dump_vm_counters("VM counters for GetCurrentProcessId", &pvi);
+ ok( pvi.WorkingSetSize > 0, "Expected a WorkingSetSize > 0\n");
+ ok( pvi.PagefileUsage > 0, "Expected a PagefileUsage > 0\n");
+
+ CloseHandle(process);
+
+ /* Check if we have real counters */
+ status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessVmCounters, &pvi,
sizeof(pvi), NULL);
+ ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n",
status);
+ prev_size = pvi.VirtualSize;
+ if (winetest_debug > 1)
+ dump_vm_counters("VM counters before VirtualAlloc", &pvi);
+ ptr = VirtualAlloc(NULL, alloc_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
+ ok( ptr != NULL, "VirtualAlloc failed, err %u\n", GetLastError());
+ status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessVmCounters, &pvi,
sizeof(pvi), NULL);
+ ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n",
status);
+ if (winetest_debug > 1)
+ dump_vm_counters("VM counters after VirtualAlloc", &pvi);
+ todo_wine ok( pvi.VirtualSize >= prev_size + alloc_size,
+ "Expected to be greater than %lu, got %lu\n", prev_size + alloc_size,
pvi.VirtualSize);
+ VirtualFree( ptr, 0, MEM_RELEASE);
+
+ status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessVmCounters, &pvi,
sizeof(pvi), NULL);
+ ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n",
status);
+ prev_size = pvi.VirtualSize;
+ if (winetest_debug > 1)
+ dump_vm_counters("VM counters before VirtualAlloc", &pvi);
+ ptr = VirtualAlloc(NULL, alloc_size, MEM_RESERVE, PAGE_READWRITE);
+ ok( ptr != NULL, "VirtualAlloc failed, err %u\n", GetLastError());
+ status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessVmCounters, &pvi,
sizeof(pvi), NULL);
+ ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n",
status);
+ if (winetest_debug > 1)
+ dump_vm_counters("VM counters after VirtualAlloc(MEM_RESERVE)",
&pvi);
+ todo_wine ok( pvi.VirtualSize >= prev_size + alloc_size,
+ "Expected to be greater than %lu, got %lu\n", prev_size + alloc_size,
pvi.VirtualSize);
+ prev_size = pvi.VirtualSize;
+
+ ptr = VirtualAlloc(ptr, alloc_size, MEM_COMMIT, PAGE_READWRITE);
+ ok( ptr != NULL, "VirtualAlloc failed, err %u\n", GetLastError());
+ status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessVmCounters, &pvi,
sizeof(pvi), NULL);
+ ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n",
status);
+ if (winetest_debug > 1)
+ dump_vm_counters("VM counters after VirtualAlloc(MEM_COMMIT)",
&pvi);
+ ok( pvi.VirtualSize == prev_size,
+ "Expected to equal to %lu, got %lu\n", prev_size, pvi.VirtualSize);
+ VirtualFree( ptr, 0, MEM_RELEASE);
}
static void test_query_process_io(void)
@@ -975,7 +1258,7 @@ static void test_query_process_io(void)
ok( sizeof(pii) == ReturnLength, "Inconsistent length %d\n",
ReturnLength);
/* Check if we have some return values */
- trace("OtherOperationCount : 0x%x%08x\n", (DWORD)(pii.OtherOperationCount
>> 32), (DWORD)pii.OtherOperationCount);
+ trace("OtherOperationCount : 0x%s\n",
wine_dbgstr_longlong(pii.OtherOperationCount));
todo_wine
{
ok( pii.OtherOperationCount > 0, "Expected an OtherOperationCount >
0\n");
@@ -1070,7 +1353,7 @@ static void test_query_process_debug_port(int argc, char **argv)
status = pNtQueryInformationProcess(NULL, ProcessDebugPort,
&debug_port, sizeof(debug_port), NULL);
- ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_ACCESS_VIOLATION, got
%#x.\n", status);
+ ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got
%#x.\n", status);
status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessDebugPort,
&debug_port, sizeof(debug_port) - 1, NULL);
@@ -1111,6 +1394,40 @@ static void test_query_process_debug_port(int argc, char **argv)
ok(ret, "CloseHandle failed, last error %#x.\n", GetLastError());
}
+static void test_query_process_priority(void)
+{
+ PROCESS_PRIORITY_CLASS priority[2];
+ ULONG ReturnLength;
+ DWORD orig_priority;
+ NTSTATUS status;
+ BOOL ret;
+
+ status = pNtQueryInformationProcess(NULL, ProcessPriorityClass, NULL,
sizeof(priority[0]), NULL);
+ ok(status == STATUS_ACCESS_VIOLATION || broken(status == STATUS_INVALID_HANDLE) /*
w2k3 */,
+ "Expected STATUS_ACCESS_VIOLATION, got %08x\n", status);
+
+ status = pNtQueryInformationProcess(NULL, ProcessPriorityClass, &priority,
sizeof(priority[0]), NULL);
+ ok(status == STATUS_INVALID_HANDLE, "Expected STATUS_INVALID_HANDLE, got
%08x\n", status);
+
+ status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessPriorityClass,
&priority, 1, &ReturnLength);
+ ok(status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH,
got %08x\n", status);
+
+ status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessPriorityClass,
&priority, sizeof(priority), &ReturnLength);
+ ok(status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH,
got %08x\n", status);
+
+ orig_priority = GetPriorityClass(GetCurrentProcess());
+ ret = SetPriorityClass(GetCurrentProcess(), BELOW_NORMAL_PRIORITY_CLASS);
+ ok(ret, "Failed to set priority class: %u\n", GetLastError());
+
+ status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessPriorityClass,
&priority, sizeof(priority[0]), &ReturnLength);
+ ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n",
status);
+ ok(priority[0].PriorityClass == PROCESS_PRIOCLASS_BELOW_NORMAL,
+ "Expected PROCESS_PRIOCLASS_BELOW_NORMAL, got %u\n",
priority[0].PriorityClass);
+
+ ret = SetPriorityClass(GetCurrentProcess(), orig_priority);
+ ok(ret, "Failed to reset priority class: %u\n", GetLastError());
+}
+
static void test_query_process_handlecount(void)
{
NTSTATUS status;
@@ -1293,27 +1610,27 @@ static void test_query_process_debug_object_handle(int argc, char
**argv)
static void test_query_process_debug_flags(int argc, char **argv)
{
+ static const DWORD test_flags[] = { DEBUG_PROCESS,
+ DEBUG_ONLY_THIS_PROCESS,
+ DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS,
+ CREATE_SUSPENDED };
DWORD debug_flags = 0xdeadbeef;
char cmdline[MAX_PATH];
PROCESS_INFORMATION pi;
STARTUPINFOA si = { 0 };
NTSTATUS status;
+ DEBUG_EVENT ev;
+ DWORD result;
BOOL ret;
+ int i, j;
- sprintf(cmdline, "%s %s %s", argv[0], argv[1], "debuggee");
-
- si.cb = sizeof(si);
- ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, DEBUG_PROCESS |
DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &si, &pi);
- ok(ret, "CreateProcess failed, last error %#x.\n", GetLastError());
- if (!ret) return;
+ /* test invalid arguments */
+ status = pNtQueryInformationProcess(NULL, ProcessDebugFlags, NULL, 0, NULL);
+ ok(status == STATUS_INFO_LENGTH_MISMATCH || broken(status ==
STATUS_INVALID_INFO_CLASS) /* WOW64 */,
+ "Expected STATUS_INFO_LENGTH_MISMATCH, got %#x.\n", status);
- status = pNtQueryInformationProcess(NULL, ProcessDebugFlags,
- NULL, 0, NULL);
- ok(status == STATUS_INFO_LENGTH_MISMATCH || broken(status ==
STATUS_INVALID_INFO_CLASS) /* NT4 */, "Expected STATUS_INFO_LENGTH_MISMATCH, got
%#x.\n", status);
-
- status = pNtQueryInformationProcess(NULL, ProcessDebugFlags,
- NULL, sizeof(debug_flags), NULL);
- ok(status == STATUS_INVALID_HANDLE || status == STATUS_ACCESS_VIOLATION ||
broken(status == STATUS_INVALID_INFO_CLASS) /* W7PROX64 (32-bit) */,
+ status = pNtQueryInformationProcess(NULL, ProcessDebugFlags, NULL,
sizeof(debug_flags), NULL);
+ ok(status == STATUS_INVALID_HANDLE || status == STATUS_ACCESS_VIOLATION ||
broken(status == STATUS_INVALID_INFO_CLASS) /* WOW64 */,
"Expected STATUS_INVALID_HANDLE, got %#x.\n", status);
status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessDebugFlags,
@@ -1322,45 +1639,123 @@ static void test_query_process_debug_flags(int argc, char
**argv)
status = pNtQueryInformationProcess(NULL, ProcessDebugFlags,
&debug_flags, sizeof(debug_flags), NULL);
- ok(status == STATUS_INVALID_HANDLE || broken(status == STATUS_INVALID_INFO_CLASS) /*
NT4 */, "Expected STATUS_ACCESS_VIOLATION, got %#x.\n", status);
+ ok(status == STATUS_INVALID_HANDLE || broken(status == STATUS_INVALID_INFO_CLASS) /*
WOW64 */,
+ "Expected STATUS_INVALID_HANDLE, got %#x.\n", status);
status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessDebugFlags,
&debug_flags, sizeof(debug_flags) - 1, NULL);
- ok(status == STATUS_INFO_LENGTH_MISMATCH || broken(status ==
STATUS_INVALID_INFO_CLASS) /* NT4 */, "Expected STATUS_INFO_LENGTH_MISMATCH, got
%#x.\n", status);
+ ok(status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH,
got %#x.\n", status);
status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessDebugFlags,
&debug_flags, sizeof(debug_flags) + 1, NULL);
- ok(status == STATUS_INFO_LENGTH_MISMATCH || broken(status ==
STATUS_INVALID_INFO_CLASS) /* NT4 */, "Expected STATUS_INFO_LENGTH_MISMATCH, got
%#x.\n", status);
+ ok(status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH,
got %#x.\n", status);
+ /* test ProcessDebugFlags of current process */
status = pNtQueryInformationProcess(GetCurrentProcess(), ProcessDebugFlags,
&debug_flags, sizeof(debug_flags), NULL);
- ok(!status || broken(status == STATUS_INVALID_INFO_CLASS) /* NT4 */,
"NtQueryInformationProcess failed, status %#x.\n", status);
- ok(debug_flags == TRUE|| broken(status == STATUS_INVALID_INFO_CLASS) /* NT4 */,
"Expected flag TRUE, got %x.\n", debug_flags);
-
- status = pNtQueryInformationProcess(pi.hProcess, ProcessDebugFlags,
- &debug_flags, sizeof(debug_flags), NULL);
- ok(!status || broken(status == STATUS_INVALID_INFO_CLASS) /* NT4 */,
"NtQueryInformationProcess failed, status %#x.\n", status);
- ok(debug_flags == FALSE || broken(status == STATUS_INVALID_INFO_CLASS) /* NT4 */,
"Expected flag FALSE, got %x.\n", debug_flags);
+ ok(!status, "NtQueryInformationProcess failed, status %#x.\n", status);
+ ok(debug_flags == TRUE, "Expected flag TRUE, got %x.\n", debug_flags);
- for (;;)
+ for (i = 0; i < sizeof(test_flags)/sizeof(test_flags[0]); i++)
{
- DEBUG_EVENT ev;
+ DWORD expected_flags = !(test_flags[i] & DEBUG_ONLY_THIS_PROCESS);
+ sprintf(cmdline, "%s %s %s", argv[0], argv[1], "debuggee");
- ret = WaitForDebugEvent(&ev, INFINITE);
- ok(ret, "WaitForDebugEvent failed, last error %#x.\n",
GetLastError());
- if (!ret) break;
+ si.cb = sizeof(si);
+ ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, test_flags[i], NULL, NULL,
&si, &pi);
+ ok(ret, "CreateProcess failed, last error %#x.\n", GetLastError());
- if (ev.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) break;
+ if (!(test_flags[i] & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS)))
+ {
+ /* test ProcessDebugFlags before attaching with debugger */
+ status = pNtQueryInformationProcess(pi.hProcess, ProcessDebugFlags,
+ &debug_flags, sizeof(debug_flags), NULL);
+ ok(!status, "NtQueryInformationProcess failed, status %#x.\n",
status);
+ ok(debug_flags == TRUE, "Expected flag TRUE, got %x.\n",
debug_flags);
+
+ ret = DebugActiveProcess(pi.dwProcessId);
+ ok(ret, "DebugActiveProcess failed, last error %#x.\n",
GetLastError());
+ expected_flags = FALSE;
+ }
- ret = ContinueDebugEvent(ev.dwProcessId, ev.dwThreadId, DBG_CONTINUE);
- ok(ret, "ContinueDebugEvent failed, last error %#x.\n",
GetLastError());
- if (!ret) break;
- }
+ /* test ProcessDebugFlags after attaching with debugger */
+ status = pNtQueryInformationProcess(pi.hProcess, ProcessDebugFlags,
+ &debug_flags, sizeof(debug_flags), NULL);
+ ok(!status, "NtQueryInformationProcess failed, status %#x.\n",
status);
+ ok(debug_flags == expected_flags, "Expected flag %x, got %x.\n",
expected_flags, debug_flags);
- ret = CloseHandle(pi.hThread);
- ok(ret, "CloseHandle failed, last error %#x.\n", GetLastError());
- ret = CloseHandle(pi.hProcess);
- ok(ret, "CloseHandle failed, last error %#x.\n", GetLastError());
+ if (!(test_flags[i] & CREATE_SUSPENDED))
+ {
+ /* Continue a couple of times to make sure the process is fully initialized,
+ * otherwise Windows XP deadlocks in the following DebugActiveProcess(). */
+ for (;;)
+ {
+ ret = WaitForDebugEvent(&ev, 1000);
+ ok(ret, "WaitForDebugEvent failed, last error %#x.\n",
GetLastError());
+ if (!ret) break;
+
+ if (ev.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT) break;
+
+ ret = ContinueDebugEvent(ev.dwProcessId, ev.dwThreadId, DBG_CONTINUE);
+ ok(ret, "ContinueDebugEvent failed, last error %#x.\n",
GetLastError());
+ if (!ret) break;
+ }
+
+ result = SuspendThread(pi.hThread);
+ ok(result == 0, "Expected 0, got %u.\n", result);
+ }
+
+ ret = DebugActiveProcessStop(pi.dwProcessId);
+ ok(ret, "DebugActiveProcessStop failed, last error %#x.\n",
GetLastError());
+
+ /* test ProcessDebugFlags after detaching debugger */
+ status = pNtQueryInformationProcess(pi.hProcess, ProcessDebugFlags,
+ &debug_flags, sizeof(debug_flags), NULL);
+ ok(!status, "NtQueryInformationProcess failed, status %#x.\n",
status);
+ ok(debug_flags == expected_flags, "Expected flag %x, got %x.\n",
expected_flags, debug_flags);
+
+ ret = DebugActiveProcess(pi.dwProcessId);
+ ok(ret, "DebugActiveProcess failed, last error %#x.\n",
GetLastError());
+
+ /* test ProcessDebugFlags after re-attaching debugger */
+ status = pNtQueryInformationProcess(pi.hProcess, ProcessDebugFlags,
+ &debug_flags, sizeof(debug_flags), NULL);
+ ok(!status, "NtQueryInformationProcess failed, status %#x.\n",
status);
+ ok(debug_flags == FALSE, "Expected flag FALSE, got %x.\n",
debug_flags);
+
+ result = ResumeThread(pi.hThread);
+ todo_wine ok(result == 2, "Expected 2, got %u.\n", result);
+
+ /* Wait until the process is terminated. On Windows XP the process randomly
+ * gets stuck in a non-continuable exception, so stop after 100 iterations.
+ * On Windows 2003, the debugged process disappears (or stops?) without
+ * any EXIT_PROCESS_DEBUG_EVENT after a couple of events. */
+ for (j = 0; j < 100; j++)
+ {
+ ret = WaitForDebugEvent(&ev, 1000);
+ ok(ret || broken(GetLastError() == ERROR_SEM_TIMEOUT),
+ "WaitForDebugEvent failed, last error %#x.\n",
GetLastError());
+ if (!ret) break;
+
+ if (ev.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) break;
+
+ ret = ContinueDebugEvent(ev.dwProcessId, ev.dwThreadId, DBG_CONTINUE);
+ ok(ret, "ContinueDebugEvent failed, last error %#x.\n",
GetLastError());
+ if (!ret) break;
+ }
+ ok(j < 100 || broken(j >= 100) /* Win XP */, "Expected less than 100
debug events.\n");
+
+ /* test ProcessDebugFlags after process has terminated */
+ status = pNtQueryInformationProcess(pi.hProcess, ProcessDebugFlags,
+ &debug_flags, sizeof(debug_flags), NULL);
+ ok(!status, "NtQueryInformationProcess failed, status %#x.\n",
status);
+ ok(debug_flags == FALSE, "Expected flag FALSE, got %x.\n",
debug_flags);
+
+ ret = CloseHandle(pi.hThread);
+ ok(ret, "CloseHandle failed, last error %#x.\n", GetLastError());
+ ret = CloseHandle(pi.hProcess);
+ ok(ret, "CloseHandle failed, last error %#x.\n", GetLastError());
+ }
}
static void test_readvirtualmemory(void)
@@ -1439,7 +1834,7 @@ static void test_mapprotection(void)
status = pNtSetInformationProcess( GetCurrentProcess(), ProcessExecuteFlags,
&flags, sizeof(flags) );
ok( (status == STATUS_SUCCESS) || (status == STATUS_INVALID_INFO_CLASS),
"Expected STATUS_SUCCESS, got %08x\n", status);
- size.u.LowPart = 0x1000;
+ size.u.LowPart = 0x2000;
size.u.HighPart = 0;
status = pNtCreateSection ( &h,
STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ | SECTION_MAP_WRITE |
SECTION_MAP_EXECUTE,
@@ -1453,7 +1848,7 @@ static void test_mapprotection(void)
offset.u.LowPart = 0;
offset.u.HighPart = 0;
- count = 0x1000;
+ count = 0x2000;
addr = NULL;
status = pNtMapViewOfSection ( h, GetCurrentProcess(), &addr, 0, 0, &offset,
&count, ViewShare, 0, PAGE_READWRITE);
ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n",
status);
@@ -1476,7 +1871,7 @@ static void test_mapprotection(void)
ok( retlen == sizeof(info), "Expected STATUS_SUCCESS, got %08x\n",
status);
ok((info.Protect & ~PAGE_NOCACHE) == PAGE_READWRITE, "addr.Protect is not
PAGE_READWRITE, but 0x%x\n", info.Protect);
- status = pNtUnmapViewOfSection (GetCurrentProcess(), addr);
+ status = pNtUnmapViewOfSection( GetCurrentProcess(), (char *)addr + 0x1050 );
ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n",
status);
pNtClose (h);
@@ -1488,12 +1883,17 @@ static void test_queryvirtualmemory(void)
{
NTSTATUS status;
SIZE_T readcount;
+ static const WCHAR windowsW[] =
{'w','i','n','d','o','w','s'};
static const char teststring[] = "test string";
static char datatestbuf[42] = "abc";
static char rwtestbuf[42];
MEMORY_BASIC_INFORMATION mbi;
char stackbuf[42];
HMODULE module;
+ char buffer_name[sizeof(MEMORY_SECTION_NAME) + MAX_PATH * sizeof(WCHAR)];
+ MEMORY_SECTION_NAME *msn = (MEMORY_SECTION_NAME *)buffer_name;
+ BOOL found;
+ int i;
module = GetModuleHandleA( "ntdll.dll" );
trace("Check flags of the PE header of NTDLL.DLL at %p\n", module);
@@ -1567,6 +1967,43 @@ static void test_queryvirtualmemory(void)
"mbi.Protect is 0x%x\n", mbi.Protect);
}
else skip( "bss is outside of module\n" ); /* this can happen on Mac OS
*/
+
+ trace("Check section name of NTDLL.DLL with invalid size\n");
+ module = GetModuleHandleA( "ntdll.dll" );
+ memset(msn, 0, sizeof(*msn));
+ readcount = 0;
+ status = pNtQueryVirtualMemory(NtCurrentProcess(), module, MemorySectionName, msn,
sizeof(*msn), &readcount);
+ ok( status == STATUS_BUFFER_OVERFLOW, "Expected STATUS_BUFFER_OVERFLOW, got
%08x\n", status);
+ ok( readcount > 0, "Expected readcount to be > 0\n");
+
+ trace("Check section name of NTDLL.DLL with invalid size\n");
+ module = GetModuleHandleA( "ntdll.dll" );
+ memset(msn, 0, sizeof(*msn));
+ readcount = 0;
+ status = pNtQueryVirtualMemory(NtCurrentProcess(), module, MemorySectionName, msn,
sizeof(*msn) - 1, &readcount);
+ ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected
STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status);
+ ok( readcount > 0, "Expected readcount to be > 0\n");
+
+ trace("Check section name of NTDLL.DLL\n");
+ module = GetModuleHandleA( "ntdll.dll" );
+ memset(msn, 0x55, sizeof(*msn));
+ memset(buffer_name, 0x77, sizeof(buffer_name));
+ readcount = 0;
+ status = pNtQueryVirtualMemory(NtCurrentProcess(), module, MemorySectionName, msn,
sizeof(buffer_name), &readcount);
+ ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n",
status);
+ ok( readcount > 0, "Expected readcount to be > 0\n");
+ trace ("Section Name: %s\n",
wine_dbgstr_w(msn->SectionFileName.Buffer));
+ pRtlDowncaseUnicodeString( &msn->SectionFileName,
&msn->SectionFileName, FALSE );
+ for (found = FALSE, i = (msn->SectionFileName.Length - sizeof(windowsW)) /
sizeof(WCHAR); i >= 0; i--)
+ found |= !memcmp( &msn->SectionFileName.Buffer[i], windowsW,
sizeof(windowsW) );
+ ok( found, "Section name does not contain \"Windows\"\n");
+
+ trace("Check section name of non mapped memory\n");
+ memset(msn, 0, sizeof(*msn));
+ readcount = 0;
+ status = pNtQueryVirtualMemory(NtCurrentProcess(), &buffer_name,
MemorySectionName, msn, sizeof(buffer_name), &readcount);
+ ok( status == STATUS_INVALID_ADDRESS, "Expected STATUS_INVALID_ADDRESS, got
%08x\n", status);
+ ok( readcount == 0 || broken(readcount != 0) /* wow64 */, "Expected readcount to
be 0\n");
}
static void test_affinity(void)
@@ -1780,6 +2217,39 @@ static void test_thread_start_address(void)
CloseHandle(thread);
}
+static void test_query_data_alignment(void)
+{
+ ULONG ReturnLength;
+ NTSTATUS status;
+ DWORD value;
+
+ value = 0xdeadbeef;
+ status = pNtQuerySystemInformation(SystemRecommendedSharedDataAlignment, &value,
sizeof(value), &ReturnLength);
+ ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n",
status);
+ ok(sizeof(value) == ReturnLength, "Inconsistent length %u\n",
ReturnLength);
+ ok(value == 64, "Expected 64, got %u\n", value);
+}
+
+static void test_working_set_limit(void)
+{
+ DWORD_PTR lower = 0, upper = ~(DWORD_PTR)0;
+ MEMORY_BASIC_INFORMATION mbi;
+ SIZE_T readcount;
+ NTSTATUS status;
+
+ while (lower != upper)
+ {
+ DWORD_PTR check = (lower >> 1) + (upper >> 1) + (lower & upper
& 1);
+ status = pNtQueryVirtualMemory(NtCurrentProcess(), (void *)check,
MemoryBasicInformation,
+ &mbi, sizeof(MEMORY_BASIC_INFORMATION),
&readcount);
+ if (status == STATUS_INVALID_PARAMETER) upper = check;
+ else lower = check + 1;
+ }
+
+ trace("working set limit is %p\n", (void *)upper);
+ ok(upper != ~(DWORD_PTR)0, "expected != ~(DWORD_PTR)0\n");
+}
+
START_TEST(info)
{
char **argv;
@@ -1825,6 +2295,10 @@ START_TEST(info)
trace("Starting test_query_handle()\n");
test_query_handle();
+ /* 0x40 SystemHandleInformation */
+ trace("Starting test_query_handle_ex()\n");
+ test_query_handle_ex();
+
/* 0x15 SystemCacheInformation */
trace("Starting test_query_cache()\n");
test_query_cache();
@@ -1844,6 +2318,7 @@ START_TEST(info)
/* 0x49 SystemLogicalProcessorInformation */
trace("Starting test_query_logicalproc()\n");
test_query_logicalproc();
+ test_query_logicalprocex();
/* NtPowerInformation */
@@ -1873,6 +2348,10 @@ START_TEST(info)
trace("Starting test_process_debug_port()\n");
test_query_process_debug_port(argc, argv);
+ /* 0x12 ProcessPriorityClass */
+ trace("Starting test_query_process_priority()\n");
+ test_query_process_priority();
+
/* 0x14 ProcessHandleCount */
trace("Starting test_query_process_handlecount()\n");
test_query_process_handlecount();
@@ -1911,4 +2390,10 @@ START_TEST(info)
trace("Starting test_thread_start_address()\n");
test_thread_start_address();
+
+ trace("Starting test_query_data_alignment()\n");
+ test_query_data_alignment();
+
+ trace("Starting test_working_set_limit()\n");
+ test_working_set_limit();
}
diff --git a/modules/rostests/winetests/ntdll/large_int.c
b/modules/rostests/winetests/ntdll/large_int.c
index f13ae882d0..4562e6768e 100755
--- a/modules/rostests/winetests/ntdll/large_int.c
+++ b/modules/rostests/winetests/ntdll/large_int.c
@@ -33,6 +33,8 @@ static VOID (WINAPI *pRtlFreeAnsiString)(PSTRING);
static NTSTATUS (WINAPI *pRtlInt64ToUnicodeString)(ULONGLONG, ULONG, UNICODE_STRING *);
static NTSTATUS (WINAPI *pRtlLargeIntegerToChar)(ULONGLONG *, ULONG, ULONG, PCHAR);
static NTSTATUS (WINAPI *pRtlUnicodeStringToAnsiString)(STRING *, const UNICODE_STRING *,
BOOLEAN);
+static void (WINAPI *p_alldvrm)(LONGLONG, LONGLONG);
+static void (WINAPI *p_aulldvrm)(ULONGLONG, ULONGLONG);
static void InitFunctionPtrs(void)
@@ -45,6 +47,8 @@ static void InitFunctionPtrs(void)
pRtlInt64ToUnicodeString = (void *)GetProcAddress(hntdll,
"RtlInt64ToUnicodeString");
pRtlLargeIntegerToChar = (void *)GetProcAddress(hntdll,
"RtlLargeIntegerToChar");
pRtlUnicodeStringToAnsiString = (void *)GetProcAddress(hntdll,
"RtlUnicodeStringToAnsiString");
+ p_alldvrm = (void *)GetProcAddress(hntdll, "_alldvrm");
+ p_aulldvrm = (void *)GetProcAddress(hntdll, "_aulldvrm");
} /* if */
}
@@ -113,10 +117,9 @@ static void test_RtlExtendedMagicDivide(void)
for (i = 0; i < NB_MAGIC_DIVIDE; i++) {
result = pRtlExtendedMagicDivide(magic_divide[i].a, magic_divide[i].b,
magic_divide[i].shift);
ok(result == magic_divide[i].result,
- "call failed: RtlExtendedMagicDivide(0x%x%08x, 0x%x%08x, %d) has result
0x%x%08x, expected 0x%x%08x\n",
- (DWORD)(magic_divide[i].a >> 32), (DWORD)magic_divide[i].a,
(DWORD)(magic_divide[i].b >> 32),
- (DWORD)magic_divide[i].b, magic_divide[i].shift, (DWORD)(result >> 32),
(DWORD)result,
- (DWORD)(magic_divide[i].result >> 32), (DWORD)magic_divide[i].result);
+ "call failed: RtlExtendedMagicDivide(0x%s, 0x%s, %d) has result 0x%s,
expected 0x%s\n",
+ wine_dbgstr_longlong(magic_divide[i].a), wine_dbgstr_longlong(magic_divide[i].b),
magic_divide[i].shift,
+ wine_dbgstr_longlong(result), wine_dbgstr_longlong(magic_divide[i].result));
}
}
@@ -332,14 +335,12 @@ static void one_RtlInt64ToUnicodeString_test(int test_num, const
largeint2str_t
} /* if */
} else {
ok(result == largeint2str->result,
- "(test %d): RtlInt64ToUnicodeString(0x%x%08x, %d, [out]) has result %x,
expected: %x\n",
- test_num, (DWORD)(largeint2str->value >> 32),
(DWORD)largeint2str->value,
- largeint2str->base, result, largeint2str->result);
+ "(test %d): RtlInt64ToUnicodeString(0x%s, %d, [out]) has result %x,
expected: %x\n",
+ test_num, wine_dbgstr_longlong(largeint2str->value), largeint2str->base,
result, largeint2str->result);
if (result == STATUS_SUCCESS) {
ok(unicode_string.Buffer[unicode_string.Length/sizeof(WCHAR)] == '\0',
- "(test %d): RtlInt64ToUnicodeString(0x%x%08x, %d, [out]) string
\"%s\" is not NULL terminated\n",
- test_num, (DWORD)(largeint2str->value >> 32),
(DWORD)largeint2str->value,
- largeint2str->base, ansi_str.Buffer);
+ "(test %d): RtlInt64ToUnicodeString(0x%s, %d, [out]) string
\"%s\" is not NULL terminated\n",
+ test_num, wine_dbgstr_longlong(largeint2str->value), largeint2str->base,
ansi_str.Buffer);
} /* if */
} /* if */
ok(memcmp(unicode_string.Buffer, expected_unicode_string.Buffer,
LARGE_STRI_BUFFER_LENGTH * sizeof(WCHAR)) == 0,
@@ -347,12 +348,12 @@ static void one_RtlInt64ToUnicodeString_test(int test_num, const
largeint2str_t
test_num, (DWORD)(largeint2str->value >>32),
(DWORD)largeint2str->value, largeint2str->base,
ansi_str.Buffer, expected_ansi_str.Buffer);
ok(unicode_string.Length == expected_unicode_string.Length,
- "(test %d): RtlInt64ToUnicodeString(0x%x%08x, %d, [out]) string has Length
%d, expected: %d\n",
- test_num, (DWORD)(largeint2str->value >> 32),
(DWORD)largeint2str->value, largeint2str->base,
+ "(test %d): RtlInt64ToUnicodeString(0x%s, %d, [out]) string has Length %d,
expected: %d\n",
+ test_num, wine_dbgstr_longlong(largeint2str->value), largeint2str->base,
unicode_string.Length, expected_unicode_string.Length);
ok(unicode_string.MaximumLength == expected_unicode_string.MaximumLength,
- "(test %d): RtlInt64ToUnicodeString(0x%x%08x, %d, [out]) string has
MaximumLength %d, expected: %d\n",
- test_num, (DWORD)(largeint2str->value >> 32),
(DWORD)largeint2str->value, largeint2str->base,
+ "(test %d): RtlInt64ToUnicodeString(0x%s, %d, [out]) string has MaximumLength
%d, expected: %d\n",
+ test_num, wine_dbgstr_longlong(largeint2str->value), largeint2str->base,
unicode_string.MaximumLength, expected_unicode_string.MaximumLength);
pRtlFreeAnsiString(&expected_ansi_str);
pRtlFreeAnsiString(&ansi_str);
@@ -392,12 +393,12 @@ static void one_RtlLargeIntegerToChar_test(int test_num, const
largeint2str_t *l
result = pRtlLargeIntegerToChar(&value, largeint2str->base,
largeint2str->MaximumLength, dest_str);
} /* if */
ok(result == largeint2str->result,
- "(test %d): RtlLargeIntegerToChar(0x%x%08x, %d, %d, [out]) has result %x,
expected: %x\n",
- test_num, (DWORD)(largeint2str->value >> 32),
(DWORD)largeint2str->value, largeint2str->base,
+ "(test %d): RtlLargeIntegerToChar(0x%s, %d, %d, [out]) has result %x,
expected: %x\n",
+ test_num, wine_dbgstr_longlong(largeint2str->value), largeint2str->base,
largeint2str->MaximumLength, result, largeint2str->result);
ok(memcmp(dest_str, largeint2str->Buffer, LARGE_STRI_BUFFER_LENGTH) == 0,
- "(test %d): RtlLargeIntegerToChar(0x%x%08x, %d, %d, [out]) assigns string
\"%s\", expected: \"%s\"\n",
- test_num, (DWORD)(largeint2str->value >> 32),
(DWORD)largeint2str->value, largeint2str->base,
+ "(test %d): RtlLargeIntegerToChar(0x%s, %d, %d, [out]) assigns string
\"%s\", expected: \"%s\"\n",
+ test_num, wine_dbgstr_longlong(largeint2str->value), largeint2str->base,
largeint2str->MaximumLength, dest_str, largeint2str->Buffer);
}
@@ -415,30 +416,89 @@ static void test_RtlLargeIntegerToChar(void)
value = largeint2str[0].value;
result = pRtlLargeIntegerToChar(&value, 20, largeint2str[0].MaximumLength,
NULL);
ok(result == STATUS_INVALID_PARAMETER,
- "(test a): RtlLargeIntegerToChar(0x%x%08x, %d, %d, NULL) has result %x,
expected: %x\n",
- (DWORD)(largeint2str[0].value >> 32), (DWORD)largeint2str[0].value, 20,
+ "(test a): RtlLargeIntegerToChar(0x%s, %d, %d, NULL) has result %x, expected:
%x\n",
+ wine_dbgstr_longlong(largeint2str[0].value), 20,
largeint2str[0].MaximumLength, result, STATUS_INVALID_PARAMETER);
result = pRtlLargeIntegerToChar(&value, 20, 0, NULL);
ok(result == STATUS_INVALID_PARAMETER,
- "(test b): RtlLargeIntegerToChar(0x%x%08x, %d, %d, NULL) has result %x,
expected: %x\n",
- (DWORD)(largeint2str[0].value >> 32), (DWORD)largeint2str[0].value, 20,
+ "(test b): RtlLargeIntegerToChar(0x%s, %d, %d, NULL) has result %x, expected:
%x\n",
+ wine_dbgstr_longlong(largeint2str[0].value), 20,
largeint2str[0].MaximumLength, result, STATUS_INVALID_PARAMETER);
result = pRtlLargeIntegerToChar(&value, largeint2str[0].base, 0, NULL);
ok(result == STATUS_BUFFER_OVERFLOW,
- "(test c): RtlLargeIntegerToChar(0x%x%08x, %d, %d, NULL) has result %x,
expected: %x\n",
- (DWORD)(largeint2str[0].value >> 32), (DWORD)largeint2str[0].value,
- largeint2str[0].base, 0, result, STATUS_BUFFER_OVERFLOW);
+ "(test c): RtlLargeIntegerToChar(0x%s, %d, %d, NULL) has result %x, expected:
%x\n",
+ wine_dbgstr_longlong(largeint2str[0].value), largeint2str[0].base, 0, result,
STATUS_BUFFER_OVERFLOW);
result = pRtlLargeIntegerToChar(&value, largeint2str[0].base,
largeint2str[0].MaximumLength, NULL);
ok(result == STATUS_ACCESS_VIOLATION,
- "(test d): RtlLargeIntegerToChar(0x%x%08x, %d, %d, NULL) has result %x,
expected: %x\n",
- (DWORD)(largeint2str[0].value >> 32), (DWORD)largeint2str[0].value,
+ "(test d): RtlLargeIntegerToChar(0x%s, %d, %d, NULL) has result %x, expected:
%x\n",
+ wine_dbgstr_longlong(largeint2str[0].value),
largeint2str[0].base, largeint2str[0].MaximumLength, result,
STATUS_ACCESS_VIOLATION);
}
+#ifdef __i386__
+
+#include "pshpack1.h"
+struct lldvrm_thunk
+{
+ BYTE push_ebx; /* pushl %ebx */
+ DWORD push_esp1; /* pushl 24(%esp) */
+ DWORD push_esp2; /* pushl 24(%esp) */
+ DWORD push_esp3; /* pushl 24(%esp) */
+ DWORD push_esp4; /* pushl 24(%esp) */
+ DWORD call; /* call 24(%esp) */
+ WORD mov_ecx_eax; /* movl %ecx,%eax */
+ WORD mov_ebx_edx; /* movl %ebx,%edx */
+ BYTE pop_ebx; /* popl %ebx */
+ BYTE ret; /* ret */
+};
+#include "poppack.h"
+
+static void test__alldvrm(void)
+{
+ struct lldvrm_thunk *thunk = VirtualAlloc(NULL, sizeof(*thunk), MEM_COMMIT,
PAGE_EXECUTE_READWRITE);
+ ULONGLONG (CDECL *call_lldvrm_func)(void *func, ULONGLONG, ULONGLONG) = (void
*)thunk;
+ ULONGLONG ret;
+
+ memset(thunk, 0x90, sizeof(*thunk));
+ thunk->push_ebx = 0x53; /* pushl %ebx */
+ thunk->push_esp1 = 0x182474ff; /* pushl 24(%esp) */
+ thunk->push_esp2 = 0x182474ff; /* pushl 24(%esp) */
+ thunk->push_esp3 = 0x182474ff; /* pushl 24(%esp) */
+ thunk->push_esp4 = 0x182474ff; /* pushl 24(%esp) */
+ thunk->call = 0x182454ff; /* call 24(%esp) */
+ thunk->pop_ebx = 0x5b; /* popl %ebx */
+ thunk->ret = 0xc3; /* ret */
+
+ ret = call_lldvrm_func(p_alldvrm, 0x0123456701234567ULL, 3);
+ ok(ret == 0x61172255b66c77ULL, "got %x%08x\n", (DWORD)(ret >> 32),
(DWORD)ret);
+ ret = call_lldvrm_func(p_alldvrm, 0x0123456701234567ULL, -3);
+ ok(ret == 0xff9ee8ddaa499389ULL, "got %x%08x\n", (DWORD)(ret >> 32),
(DWORD)ret);
+
+ ret = call_lldvrm_func(p_aulldvrm, 0x0123456701234567ULL, 3);
+ ok(ret == 0x61172255b66c77ULL, "got %x%08x\n", (DWORD)(ret >> 32),
(DWORD)ret);
+ ret = call_lldvrm_func(p_aulldvrm, 0x0123456701234567ULL, -3);
+ ok(ret == 0, "got %x%08x\n", (DWORD)(ret >> 32), (DWORD)ret);
+
+ thunk->mov_ecx_eax = 0xc889;
+ thunk->mov_ebx_edx = 0xda89;
+
+ ret = call_lldvrm_func(p_alldvrm, 0x0123456701234567ULL, 3);
+ ok(ret == 2, "got %x%08x\n", (DWORD)(ret >> 32), (DWORD)ret);
+ ret = call_lldvrm_func(p_alldvrm, 0x0123456701234567ULL, -3);
+ ok(ret == 2, "got %x%08x\n", (DWORD)(ret >> 32), (DWORD)ret);
+
+ ret = call_lldvrm_func(p_aulldvrm, 0x0123456701234567ULL, 3);
+ ok(ret == 2, "got %x%08x\n", (DWORD)(ret >> 32), (DWORD)ret);
+ ret = call_lldvrm_func(p_aulldvrm, 0x0123456701234567ULL, -3);
+ ok(ret == 0x123456701234567ULL, "got %x%08x\n", (DWORD)(ret >> 32),
(DWORD)ret);
+}
+#endif /* __i386__ */
+
+
START_TEST(large_int)
{
InitFunctionPtrs();
@@ -449,4 +509,8 @@ START_TEST(large_int)
test_RtlInt64ToUnicodeString();
if (pRtlLargeIntegerToChar)
test_RtlLargeIntegerToChar();
+
+#ifdef __i386__
+ test__alldvrm();
+#endif /* __i386__ */
}
diff --git a/modules/rostests/winetests/ntdll/ntdll_test.h
b/modules/rostests/winetests/ntdll/ntdll_test.h
index 8d88308315..84ed6a4a71 100755
--- a/modules/rostests/winetests/ntdll/ntdll_test.h
+++ b/modules/rostests/winetests/ntdll/ntdll_test.h
@@ -20,10 +20,6 @@
#include <stdarg.h>
-#ifndef _WIN32_WINNT
-#define _WIN32_WINNT 0x500 /* For NTSTATUS */
-#endif
-
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h"
diff --git a/modules/rostests/winetests/ntdll/om.c
b/modules/rostests/winetests/ntdll/om.c
index 65e9260a1e..651db0a1ee 100644
--- a/modules/rostests/winetests/ntdll/om.c
+++ b/modules/rostests/winetests/ntdll/om.c
@@ -33,12 +33,25 @@ static NTSTATUS (WINAPI *pNtCreateEvent) ( PHANDLE, ACCESS_MASK, const
POBJECT_A
static NTSTATUS (WINAPI *pNtOpenEvent) ( PHANDLE, ACCESS_MASK, const
POBJECT_ATTRIBUTES);
static NTSTATUS (WINAPI *pNtPulseEvent) ( HANDLE, PULONG );
static NTSTATUS (WINAPI *pNtQueryEvent) ( HANDLE, EVENT_INFORMATION_CLASS, PVOID, ULONG,
PULONG );
+static NTSTATUS (WINAPI *pNtCreateJobObject)( PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES
);
+static NTSTATUS (WINAPI *pNtOpenJobObject)( PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES );
+static NTSTATUS (WINAPI *pNtCreateKey)( PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, ULONG,
+ const UNICODE_STRING *, ULONG, PULONG );
+static NTSTATUS (WINAPI *pNtOpenKey)( PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES );
+static NTSTATUS (WINAPI *pNtDeleteKey)( HANDLE );
+static NTSTATUS (WINAPI *pNtCreateMailslotFile)( PHANDLE, ACCESS_MASK,
POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK,
+ ULONG, ULONG, ULONG, PLARGE_INTEGER );
static NTSTATUS (WINAPI *pNtCreateMutant)( PHANDLE, ACCESS_MASK, const
POBJECT_ATTRIBUTES, BOOLEAN );
static NTSTATUS (WINAPI *pNtOpenMutant) ( PHANDLE, ACCESS_MASK, const POBJECT_ATTRIBUTES
);
+static NTSTATUS (WINAPI *pNtQueryMutant) ( HANDLE, MUTANT_INFORMATION_CLASS, PVOID,
ULONG, PULONG );
+static NTSTATUS (WINAPI *pNtReleaseMutant)( HANDLE, PLONG );
static NTSTATUS (WINAPI *pNtCreateSemaphore)( PHANDLE, ACCESS_MASK,const
POBJECT_ATTRIBUTES,LONG,LONG );
+static NTSTATUS (WINAPI *pNtOpenSemaphore)( PHANDLE, ACCESS_MASK, const
POBJECT_ATTRIBUTES );
static NTSTATUS (WINAPI *pNtCreateTimer) ( PHANDLE, ACCESS_MASK, const
POBJECT_ATTRIBUTES, TIMER_TYPE );
+static NTSTATUS (WINAPI *pNtOpenTimer)( PHANDLE, ACCESS_MASK, const POBJECT_ATTRIBUTES
);
static NTSTATUS (WINAPI *pNtCreateSection)( PHANDLE, ACCESS_MASK, const
POBJECT_ATTRIBUTES, const PLARGE_INTEGER,
ULONG, ULONG, HANDLE );
+static NTSTATUS (WINAPI *pNtOpenSection)( PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES );
static NTSTATUS (WINAPI *pNtOpenFile) ( PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES,
PIO_STATUS_BLOCK, ULONG, ULONG );
static NTSTATUS (WINAPI *pNtClose) ( HANDLE );
static NTSTATUS (WINAPI *pNtCreateNamedPipeFile)( PHANDLE, ULONG, POBJECT_ATTRIBUTES,
PIO_STATUS_BLOCK,
@@ -55,11 +68,28 @@ static NTSTATUS (WINAPI *pNtOpenKeyedEvent)( HANDLE *, ACCESS_MASK,
const OBJECT
static NTSTATUS (WINAPI *pNtWaitForKeyedEvent)( HANDLE, const void *, BOOLEAN, const
LARGE_INTEGER * );
static NTSTATUS (WINAPI *pNtReleaseKeyedEvent)( HANDLE, const void *, BOOLEAN, const
LARGE_INTEGER * );
static NTSTATUS (WINAPI *pNtCreateIoCompletion)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES,
ULONG);
+static NTSTATUS (WINAPI *pNtOpenIoCompletion)( PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES
);
+static NTSTATUS (WINAPI *pNtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS, PVOID,
ULONG, PULONG);
#define KEYEDEVENT_WAIT 0x0001
#define KEYEDEVENT_WAKE 0x0002
#define KEYEDEVENT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | 0x0003)
+#define ROUND_UP(value, alignment) (((value) + ((alignment) - 1)) &
~((alignment)-1))
+
+static LPCSTR wine_dbgstr_us( const UNICODE_STRING *us )
+{
+ if (!us) return "(null)";
+ return wine_dbgstr_wn(us->Buffer, us->Length / sizeof(WCHAR));
+}
+
+static inline int strncmpW( const WCHAR *str1, const WCHAR *str2, int n )
+{
+ if (n <= 0) return 0;
+ while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++;
}
+ return *str1 - *str2;
+}
+
static void test_case_sensitive (void)
{
static const WCHAR buffer1[] =
{'\\','B','a','s','e','N','a','m','e','d','O','b','j','e','c','t','s','\\','t','e','s','t',0};
@@ -165,33 +195,34 @@ static void test_namespace_pipe(void)
status == STATUS_OBJECT_NAME_INVALID, /* vista */
"NtOpenFile should have failed with STATUS_OBJECT_NAME_NOT_FOUND
got(%08x)\n", status);
+ str.Length -= 4 * sizeof(WCHAR);
+ status = pNtOpenFile(&h, GENERIC_READ, &attr, &iosb,
FILE_SHARE_READ|FILE_SHARE_WRITE, 0);
+ ok(status == STATUS_SUCCESS, "NtOpenFile should have succeeded got %08x\n",
status);
+ pNtClose( h );
+
+ str.Length -= sizeof(WCHAR);
+ status = pNtOpenFile(&h, GENERIC_READ, &attr, &iosb,
FILE_SHARE_READ|FILE_SHARE_WRITE, 0);
+ ok(status == STATUS_SUCCESS, "NtOpenFile should have succeeded got %08x\n",
status);
+ pNtClose( h );
+
pNtClose(pipe);
}
#define DIRECTORY_QUERY (0x0001)
#define SYMBOLIC_LINK_QUERY 0x0001
-#define DIR_TEST_CREATE_FAILURE(h,e) \
- status = pNtCreateDirectoryObject(h, DIRECTORY_QUERY, &attr);\
- ok(status == e,"NtCreateDirectoryObject should have failed with %s
got(%08x)\n", #e, status);
-#define DIR_TEST_OPEN_FAILURE(h,e) \
- status = pNtOpenDirectoryObject(h, DIRECTORY_QUERY, &attr);\
- ok(status == e,"NtOpenDirectoryObject should have failed with %s
got(%08x)\n", #e, status);
-#define DIR_TEST_CREATE_OPEN_FAILURE(h,n,e) \
- pRtlCreateUnicodeStringFromAsciiz(&str, n);\
- DIR_TEST_CREATE_FAILURE(h,e) DIR_TEST_OPEN_FAILURE(h,e)\
- pRtlFreeUnicodeString(&str);
-
-#define DIR_TEST_CREATE_SUCCESS(h) \
- status = pNtCreateDirectoryObject(h, DIRECTORY_QUERY, &attr); \
- ok(status == STATUS_SUCCESS, "Failed to create Directory(%08x)\n",
status);
-#define DIR_TEST_OPEN_SUCCESS(h) \
- status = pNtOpenDirectoryObject(h, DIRECTORY_QUERY, &attr); \
- ok(status == STATUS_SUCCESS, "Failed to open Directory(%08x)\n", status);
-#define DIR_TEST_CREATE_OPEN_SUCCESS(h,n) \
- pRtlCreateUnicodeStringFromAsciiz(&str, n);\
- DIR_TEST_CREATE_SUCCESS(&h) pNtClose(h); DIR_TEST_OPEN_SUCCESS(&h)
pNtClose(h); \
- pRtlFreeUnicodeString(&str);
+#define DIR_TEST_CREATE_OPEN(n,e) \
+ do { \
+ HANDLE h; \
+ pRtlCreateUnicodeStringFromAsciiz(&str, n); \
+ status = pNtCreateDirectoryObject( &h, DIRECTORY_QUERY, &attr ); \
+ ok( status == e, "NtCreateDirectoryObject(%s) got %08x\n", n, status );
\
+ if (!status) pNtClose( h ); \
+ status = pNtOpenDirectoryObject( &h, DIRECTORY_QUERY, &attr ); \
+ ok( status == e, "NtOpenDirectoryObject(%s) got %08x\n", n, status );
\
+ if (!status) pNtClose( h ); \
+ pRtlFreeUnicodeString(&str); \
+ } while(0)
static BOOL is_correct_dir( HANDLE dir, const char *name )
{
@@ -216,13 +247,14 @@ static HANDLE get_base_dir(void)
UNICODE_STRING str;
OBJECT_ATTRIBUTES attr;
HANDLE dir, h;
- unsigned int i;
+ char name[40];
h = CreateMutexA(NULL, FALSE, objname);
ok(h != 0, "CreateMutexA failed got ret=%p (%d)\n", h, GetLastError());
InitializeObjectAttributes(&attr, &str, OBJ_OPENIF, 0, NULL);
- pRtlCreateUnicodeStringFromAsciiz(&str, "\\BaseNamedObjects\\Local");
+ sprintf( name, "\\BaseNamedObjects\\Session\\%u",
NtCurrentTeb()->Peb->SessionId );
+ pRtlCreateUnicodeStringFromAsciiz(&str, name );
status = pNtOpenDirectoryObject(&dir, DIRECTORY_QUERY, &attr);
pRtlFreeUnicodeString(&str);
if (!status && is_correct_dir( dir, objname )) goto done;
@@ -234,16 +266,6 @@ static HANDLE get_base_dir(void)
if (!status && is_correct_dir( dir, objname )) goto done;
if (!status) pNtClose( dir );
- for (i = 0; i < 20; i++)
- {
- char name[40];
- sprintf( name, "\\BaseNamedObjects\\Session\\%u", i );
- pRtlCreateUnicodeStringFromAsciiz(&str, name );
- status = pNtOpenDirectoryObject(&dir, DIRECTORY_QUERY, &attr);
- pRtlFreeUnicodeString(&str);
- if (!status && is_correct_dir( dir, objname )) goto done;
- if (!status) pNtClose( dir );
- }
dir = 0;
done:
@@ -262,10 +284,12 @@ static void test_name_collisions(void)
InitializeObjectAttributes(&attr, &str, 0, 0, NULL);
pRtlCreateUnicodeStringFromAsciiz(&str, "\\");
- DIR_TEST_CREATE_FAILURE(&h, STATUS_OBJECT_NAME_COLLISION)
+ status = pNtCreateDirectoryObject( &h, DIRECTORY_QUERY, &attr );
+ ok( status == STATUS_OBJECT_NAME_COLLISION, "NtCreateDirectoryObject got
%08x\n", status );
InitializeObjectAttributes(&attr, &str, OBJ_OPENIF, 0, NULL);
- DIR_TEST_CREATE_FAILURE(&h, STATUS_OBJECT_NAME_EXISTS)
+ status = pNtCreateDirectoryObject( &h, DIRECTORY_QUERY, &attr );
+ ok( status == STATUS_OBJECT_NAME_EXISTS, "NtCreateDirectoryObject got
%08x\n", status );
pNtClose(h);
status = pNtCreateMutant(&h, GENERIC_ALL, &attr, FALSE);
ok(status == STATUS_OBJECT_TYPE_MISMATCH,
@@ -356,12 +380,529 @@ static void test_name_collisions(void)
pNtClose(dir);
}
+static void test_all_kernel_objects( UINT line, OBJECT_ATTRIBUTES *attr,
+ NTSTATUS create_expect, NTSTATUS open_expect )
+{
+ UNICODE_STRING target;
+ LARGE_INTEGER size;
+ NTSTATUS status, status2;
+ HANDLE ret, ret2;
+
+ pRtlCreateUnicodeStringFromAsciiz( &target, "\\DosDevices" );
+ size.QuadPart = 4096;
+
+ status = pNtCreateMutant( &ret, GENERIC_ALL, attr, FALSE );
+ ok( status == create_expect, "%u: NtCreateMutant failed %x\n", line, status
);
+ status2 = pNtOpenMutant( &ret2, GENERIC_ALL, attr );
+ ok( status2 == open_expect, "%u: NtOpenMutant failed %x\n", line, status2
);
+ if (!status) pNtClose( ret );
+ if (!status2) pNtClose( ret2 );
+ status = pNtCreateSemaphore( &ret, GENERIC_ALL, attr, 1, 2 );
+ ok( status == create_expect, "%u: NtCreateSemaphore failed %x\n", line,
status );
+ status2 = pNtOpenSemaphore( &ret2, GENERIC_ALL, attr );
+ ok( status2 == open_expect, "%u: NtOpenSemaphore failed %x\n", line,
status2 );
+ if (!status) pNtClose( ret );
+ if (!status2) pNtClose( ret2 );
+ status = pNtCreateEvent( &ret, GENERIC_ALL, attr, 1, 0 );
+ ok( status == create_expect, "%u: NtCreateEvent failed %x\n", line, status
);
+ status2 = pNtOpenEvent( &ret2, GENERIC_ALL, attr );
+ ok( status2 == open_expect, "%u: NtOpenEvent failed %x\n", line, status2
);
+ if (!status) pNtClose( ret );
+ if (!status2) pNtClose( ret2 );
+ status = pNtCreateKeyedEvent( &ret, GENERIC_ALL, attr, 0 );
+ ok( status == create_expect, "%u: NtCreateKeyedEvent failed %x\n", line,
status );
+ status2 = pNtOpenKeyedEvent( &ret2, GENERIC_ALL, attr );
+ ok( status2 == open_expect, "%u: NtOpenKeyedEvent failed %x\n", line,
status2 );
+ if (!status) pNtClose( ret );
+ if (!status2) pNtClose( ret2 );
+ status = pNtCreateTimer( &ret, GENERIC_ALL, attr, NotificationTimer );
+ ok( status == create_expect, "%u: NtCreateTimer failed %x\n", line, status
);
+ status2 = pNtOpenTimer( &ret2, GENERIC_ALL, attr );
+ ok( status2 == open_expect, "%u: NtOpenTimer failed %x\n", line, status2
);
+ if (!status) pNtClose( ret );
+ if (!status2) pNtClose( ret2 );
+ status = pNtCreateIoCompletion( &ret, GENERIC_ALL, attr, 0 );
+ ok( status == create_expect, "%u: NtCreateCompletion failed %x\n", line,
status );
+ status2 = pNtOpenIoCompletion( &ret2, GENERIC_ALL, attr );
+ ok( status2 == open_expect, "%u: NtOpenCompletion failed %x\n", line,
status2 );
+ if (!status) pNtClose( ret );
+ if (!status2) pNtClose( ret2 );
+ status = pNtCreateJobObject( &ret, GENERIC_ALL, attr );
+ ok( status == create_expect, "%u: NtCreateJobObject failed %x\n", line,
status );
+ status2 = pNtOpenJobObject( &ret2, GENERIC_ALL, attr );
+ ok( status2 == open_expect, "%u: NtOpenJobObject failed %x\n", line,
status2 );
+ if (!status) pNtClose( ret );
+ if (!status2) pNtClose( ret2 );
+ status = pNtCreateDirectoryObject( &ret, GENERIC_ALL, attr );
+ ok( status == create_expect, "%u: NtCreateDirectoryObject failed %x\n",
line, status );
+ status2 = pNtOpenDirectoryObject( &ret2, GENERIC_ALL, attr );
+ ok( status2 == open_expect, "%u: NtOpenDirectoryObject failed %x\n", line,
status2 );
+ if (!status) pNtClose( ret );
+ if (!status2) pNtClose( ret2 );
+ status = pNtCreateSymbolicLinkObject( &ret, GENERIC_ALL, attr, &target );
+ ok( status == create_expect, "%u: NtCreateSymbolicLinkObject failed %x\n",
line, status );
+ status2 = pNtOpenSymbolicLinkObject( &ret2, GENERIC_ALL, attr );
+ ok( status2 == open_expect, "%u: NtOpenSymbolicLinkObject failed %x\n",
line, status2 );
+ if (!status) pNtClose( ret );
+ if (!status2) pNtClose( ret2 );
+ status = pNtCreateSection( &ret, SECTION_MAP_WRITE, attr, &size,
PAGE_READWRITE, SEC_COMMIT, 0 );
+ ok( status == create_expect, "%u: NtCreateSection failed %x\n", line,
status );
+ status2 = pNtOpenSection( &ret2, SECTION_MAP_WRITE, attr );
+ ok( status2 == open_expect, "%u: NtOpenSection failed %x\n", line, status2
);
+ if (!status) pNtClose( ret );
+ if (!status2) pNtClose( ret2 );
+ pRtlFreeUnicodeString( &target );
+}
+
+static void test_name_limits(void)
+{
+ static const WCHAR localW[] =
{'\\','B','a','s','e','N','a','m','e','d','O','b','j','e','c','t','s','\\','L','o','c','a','l',0};
+ static const WCHAR pipeW[] =
{'\\','D','e','v','i','c','e','\\','N','a','m','e','d','P','i','p','e','\\'};
+ static const WCHAR mailslotW[] =
{'\\','D','e','v','i','c','e','\\','M','a','i','l','S','l','o','t','\\'};
+ static const WCHAR registryW[] =
{'\\','R','E','G','I','S','T','R','Y','\\','M','a','c','h','i','n','e','\\','S','O','F','T','W','A','R','E','\\','M','i','c','r','o','s','o','f','t','\\'};
+ OBJECT_ATTRIBUTES attr, attr2, attr3;
+ IO_STATUS_BLOCK iosb;
+ LARGE_INTEGER size, timeout;
+ UNICODE_STRING str, str2, target;
+ NTSTATUS status;
+ HANDLE ret, ret2;
+ DWORD i;
+
+ InitializeObjectAttributes( &attr, &str, 0, 0, NULL );
+ InitializeObjectAttributes( &attr2, &str, 0, (HANDLE)0xdeadbeef, NULL );
+ InitializeObjectAttributes( &attr3, &str, 0, 0, NULL );
+ str.Buffer = HeapAlloc( GetProcessHeap(), 0, 65536 + sizeof(registryW));
+ str.MaximumLength = 65534;
+ for (i = 0; i < 65536 / sizeof(WCHAR); i++) str.Buffer[i] = 'a';
+ size.QuadPart = 4096;
+ pRtlCreateUnicodeStringFromAsciiz( &target, "\\DosDevices" );
+
+ if (!(attr.RootDirectory = get_base_dir()))
+ {
+ win_skip( "couldn't find the BaseNamedObjects dir\n" );
+ return;
+ }
+
+ str.Length = 0;
+ status = pNtCreateMutant( &ret, GENERIC_ALL, &attr2, FALSE );
+ ok( status == STATUS_SUCCESS, "%u: NtCreateMutant failed %x\n", str.Length,
status );
+ attr3.RootDirectory = ret;
+ status = pNtOpenMutant( &ret2, GENERIC_ALL, &attr );
+ ok( status == STATUS_OBJECT_TYPE_MISMATCH, "%u: NtOpenMutant failed %x\n",
str.Length, status );
+ status = pNtOpenMutant( &ret2, GENERIC_ALL, &attr3 );
+ ok( status == STATUS_OBJECT_TYPE_MISMATCH || status == STATUS_INVALID_HANDLE,
+ "%u: NtOpenMutant failed %x\n", str.Length, status );
+ pNtClose( ret );
+ status = pNtCreateSemaphore( &ret, GENERIC_ALL, &attr2, 1, 2 );
+ ok( status == STATUS_SUCCESS, "%u: NtCreateSemaphore failed %x\n",
str.Length, status );
+ attr3.RootDirectory = ret;
+ status = pNtOpenSemaphore( &ret2, GENERIC_ALL, &attr );
+ ok( status == STATUS_OBJECT_TYPE_MISMATCH, "%u: NtOpenSemaphore failed
%x\n", str.Length, status );
+ status = pNtOpenSemaphore( &ret2, GENERIC_ALL, &attr3 );
+ ok( status == STATUS_OBJECT_TYPE_MISMATCH || status == STATUS_INVALID_HANDLE,
+ "%u: NtOpenSemaphore failed %x\n", str.Length, status );
+ pNtClose( ret );
+ status = pNtCreateEvent( &ret, GENERIC_ALL, &attr2, 1, 0 );
+ ok( status == STATUS_SUCCESS, "%u: NtCreateEvent failed %x\n", str.Length,
status );
+ attr3.RootDirectory = ret;
+ status = pNtOpenEvent( &ret2, GENERIC_ALL, &attr );
+ ok( status == STATUS_OBJECT_TYPE_MISMATCH, "%u: NtOpenEvent failed %x\n",
str.Length, status );
+ status = pNtOpenEvent( &ret2, GENERIC_ALL, &attr3 );
+ ok( status == STATUS_OBJECT_TYPE_MISMATCH || status == STATUS_INVALID_HANDLE,
+ "%u: NtOpenEvent failed %x\n", str.Length, status );
+ pNtClose( ret );
+ status = pNtCreateKeyedEvent( &ret, GENERIC_ALL, &attr2, 0 );
+ ok( status == STATUS_SUCCESS, "%u: NtCreateKeyedEvent failed %x\n",
str.Length, status );
+ attr3.RootDirectory = ret;
+ status = pNtOpenKeyedEvent( &ret2, GENERIC_ALL, &attr );
+ ok( status == STATUS_OBJECT_TYPE_MISMATCH, "%u: NtOpenKeyedEvent failed
%x\n", str.Length, status );
+ status = pNtOpenKeyedEvent( &ret2, GENERIC_ALL, &attr3 );
+ ok( status == STATUS_OBJECT_TYPE_MISMATCH || status == STATUS_INVALID_HANDLE,
+ "%u: NtOpenKeyedEvent failed %x\n", str.Length, status );
+ pNtClose( ret );
+ status = pNtCreateTimer( &ret, GENERIC_ALL, &attr2, NotificationTimer );
+ ok( status == STATUS_SUCCESS, "%u: NtCreateTimer failed %x\n", str.Length,
status );
+ attr3.RootDirectory = ret;
+ status = pNtOpenTimer( &ret2, GENERIC_ALL, &attr );
+ ok( status == STATUS_OBJECT_TYPE_MISMATCH, "%u: NtOpenTimer failed %x\n",
str.Length, status );
+ status = pNtOpenTimer( &ret2, GENERIC_ALL, &attr3 );
+ ok( status == STATUS_OBJECT_TYPE_MISMATCH || status == STATUS_INVALID_HANDLE,
+ "%u: NtOpenTimer failed %x\n", str.Length, status );
+ pNtClose( ret );
+ status = pNtCreateIoCompletion( &ret, GENERIC_ALL, &attr2, 0 );
+ ok( status == STATUS_SUCCESS, "%u: NtCreateCompletion failed %x\n",
str.Length, status );
+ attr3.RootDirectory = ret;
+ status = pNtOpenIoCompletion( &ret2, GENERIC_ALL, &attr );
+ ok( status == STATUS_OBJECT_TYPE_MISMATCH, "%u: NtOpenCompletion failed
%x\n", str.Length, status );
+ status = pNtOpenIoCompletion( &ret2, GENERIC_ALL, &attr3 );
+ ok( status == STATUS_OBJECT_TYPE_MISMATCH || status == STATUS_INVALID_HANDLE,
+ "%u: NtOpenCompletion failed %x\n", str.Length, status );
+ pNtClose( ret );
+ status = pNtCreateJobObject( &ret, GENERIC_ALL, &attr2 );
+ ok( status == STATUS_SUCCESS, "%u: NtCreateJobObject failed %x\n",
str.Length, status );
+ attr3.RootDirectory = ret;
+ status = pNtOpenJobObject( &ret2, GENERIC_ALL, &attr );
+ ok( status == STATUS_OBJECT_TYPE_MISMATCH, "%u: NtOpenJobObject failed
%x\n", str.Length, status );
+ status = pNtOpenJobObject( &ret2, GENERIC_ALL, &attr3 );
+ ok( status == STATUS_OBJECT_TYPE_MISMATCH || status == STATUS_INVALID_HANDLE,
+ "%u: NtOpenJobObject failed %x\n", str.Length, status );
+ pNtClose( ret );
+ status = pNtCreateDirectoryObject( &ret, GENERIC_ALL, &attr2 );
+ ok( status == STATUS_SUCCESS, "%u: NtCreateDirectoryObject failed %x\n",
str.Length, status );
+ attr3.RootDirectory = ret;
+ status = pNtOpenDirectoryObject( &ret2, GENERIC_ALL, &attr );
+ ok( status == STATUS_SUCCESS || broken(status == STATUS_ACCESS_DENIED), /* winxp */
+ "%u: NtOpenDirectoryObject failed %x\n", str.Length, status );
+ if (!status) pNtClose( ret2 );
+ status = pNtOpenDirectoryObject( &ret2, GENERIC_ALL, &attr3 );
+ ok( status == STATUS_SUCCESS, "%u: NtOpenDirectoryObject failed %x\n",
str.Length, status );
+ pNtClose( ret2 );
+ pNtClose( ret );
+ status = pNtCreateSymbolicLinkObject( &ret, GENERIC_ALL, &attr2, &target
);
+ ok( status == STATUS_SUCCESS, "%u: NtCreateSymbolicLinkObject failed %x\n",
str.Length, status );
+ attr3.RootDirectory = ret;
+ status = pNtOpenSymbolicLinkObject( &ret2, GENERIC_ALL, &attr );
+ ok( status == STATUS_OBJECT_TYPE_MISMATCH, "%u: NtOpenSymbolicLinkObject failed
%x\n", str.Length, status );
+ status = pNtOpenSymbolicLinkObject( &ret2, GENERIC_ALL, &attr3 );
+ ok( status == STATUS_SUCCESS, "%u: NtOpenSymbolicLinkObject failed %x\n",
str.Length, status );
+ pNtClose( ret2 );
+ pNtClose( ret );
+ status = pNtCreateSection( &ret, SECTION_MAP_WRITE, &attr2, &size,
PAGE_READWRITE, SEC_COMMIT, 0 );
+ ok( status == STATUS_SUCCESS, "%u: NtCreateSection failed %x\n",
str.Length, status );
+ attr3.RootDirectory = ret;
+ status = pNtOpenSection( &ret2, SECTION_MAP_WRITE, &attr );
+ ok( status == STATUS_OBJECT_TYPE_MISMATCH, "%u: NtOpenSection failed %x\n",
str.Length, status );
+ status = pNtOpenSection( &ret2, SECTION_MAP_WRITE, &attr3 );
+ ok( status == STATUS_OBJECT_TYPE_MISMATCH || status == STATUS_INVALID_HANDLE,
+ "%u: NtOpenSection failed %x\n", str.Length, status );
+ pNtClose( ret );
+
+ str.Length = 67;
+ test_all_kernel_objects( __LINE__, &attr2, STATUS_OBJECT_NAME_INVALID,
STATUS_OBJECT_NAME_INVALID );
+
+ str.Length = 65532;
+ test_all_kernel_objects( __LINE__, &attr, STATUS_SUCCESS, STATUS_SUCCESS );
+
+ str.Length = 65534;
+ test_all_kernel_objects( __LINE__, &attr, STATUS_OBJECT_NAME_INVALID,
STATUS_OBJECT_NAME_INVALID );
+
+ str.Length = 128;
+ for (attr.Length = 0; attr.Length <= 2 * sizeof(attr); attr.Length++)
+ {
+ if (attr.Length == sizeof(attr))
+ test_all_kernel_objects( __LINE__, &attr, STATUS_SUCCESS, STATUS_SUCCESS
);
+ else
+ test_all_kernel_objects( __LINE__, &attr, STATUS_INVALID_PARAMETER,
STATUS_INVALID_PARAMETER );
+ }
+ attr.Length = sizeof(attr);
+
+ /* null attributes or ObjectName, with or without RootDirectory */
+ attr3.RootDirectory = 0;
+ attr2.ObjectName = attr3.ObjectName = NULL;
+ test_all_kernel_objects( __LINE__, &attr2, STATUS_OBJECT_NAME_INVALID,
STATUS_OBJECT_NAME_INVALID );
+ test_all_kernel_objects( __LINE__, &attr3, STATUS_SUCCESS,
STATUS_OBJECT_PATH_SYNTAX_BAD );
+
+ attr3.ObjectName = &str2;
+ pRtlInitUnicodeString( &str2, localW );
+ status = pNtOpenSymbolicLinkObject( &ret, SYMBOLIC_LINK_QUERY, &attr3 );
+ ok( status == STATUS_SUCCESS, "can't open BaseNamedObjects\\Local
%x\n", status );
+ attr3.ObjectName = &str;
+ attr3.RootDirectory = ret;
+ test_all_kernel_objects( __LINE__, &attr3, STATUS_OBJECT_TYPE_MISMATCH,
STATUS_OBJECT_TYPE_MISMATCH );
+ pNtClose( attr3.RootDirectory );
+
+ status = pNtCreateMutant( &ret, GENERIC_ALL, NULL, FALSE );
+ ok( status == STATUS_SUCCESS, "NULL: NtCreateMutant failed %x\n", status
);
+ pNtClose( ret );
+ status = pNtOpenMutant( &ret, GENERIC_ALL, NULL );
+ ok( status == STATUS_INVALID_PARAMETER, "NULL: NtOpenMutant failed %x\n",
status );
+ status = pNtCreateSemaphore( &ret, GENERIC_ALL, NULL, 1, 2 );
+ ok( status == STATUS_SUCCESS, "NULL: NtCreateSemaphore failed %x\n", status
);
+ pNtClose( ret );
+ status = pNtOpenSemaphore( &ret, GENERIC_ALL, NULL );
+ ok( status == STATUS_INVALID_PARAMETER, "NULL: NtOpenSemaphore failed
%x\n", status );
+ status = pNtCreateEvent( &ret, GENERIC_ALL, NULL, 1, 0 );
+ ok( status == STATUS_SUCCESS, "NULL: NtCreateEvent failed %x\n", status );
+ pNtClose( ret );
+ status = pNtOpenEvent( &ret, GENERIC_ALL, NULL );
+ ok( status == STATUS_INVALID_PARAMETER, "NULL: NtOpenEvent failed %x\n",
status );
+ status = pNtCreateKeyedEvent( &ret, GENERIC_ALL, NULL, 0 );
+ ok( status == STATUS_SUCCESS, "NULL: NtCreateKeyedEvent failed %x\n",
status );
+ pNtClose( ret );
+ status = pNtOpenKeyedEvent( &ret, GENERIC_ALL, NULL );
+ ok( status == STATUS_INVALID_PARAMETER, "NULL: NtOpenKeyedEvent failed
%x\n", status );
+ status = pNtCreateTimer( &ret, GENERIC_ALL, NULL, NotificationTimer );
+ ok( status == STATUS_SUCCESS, "NULL: NtCreateTimer failed %x\n", status );
+ pNtClose( ret );
+ status = pNtOpenTimer( &ret, GENERIC_ALL, NULL );
+ ok( status == STATUS_INVALID_PARAMETER, "NULL: NtOpenTimer failed %x\n",
status );
+ status = pNtCreateIoCompletion( &ret, GENERIC_ALL, NULL, 0 );
+ ok( status == STATUS_SUCCESS, "NULL: NtCreateCompletion failed %x\n",
status );
+ pNtClose( ret );
+ status = pNtOpenIoCompletion( &ret, GENERIC_ALL, NULL );
+ ok( status == STATUS_INVALID_PARAMETER, "NULL: NtOpenCompletion failed
%x\n", status );
+ status = pNtCreateJobObject( &ret, GENERIC_ALL, NULL );
+ ok( status == STATUS_SUCCESS, "NULL: NtCreateJobObject failed %x\n", status
);
+ pNtClose( ret );
+ status = pNtOpenJobObject( &ret, GENERIC_ALL, NULL );
+ ok( status == STATUS_INVALID_PARAMETER, "NULL: NtOpenJobObject failed
%x\n", status );
+ status = pNtCreateDirectoryObject( &ret, GENERIC_ALL, NULL );
+ ok( status == STATUS_SUCCESS, "NULL: NtCreateDirectoryObject failed %x\n",
status );
+ pNtClose( ret );
+ status = pNtOpenDirectoryObject( &ret, GENERIC_ALL, NULL );
+ ok( status == STATUS_INVALID_PARAMETER, "NULL: NtOpenDirectoryObject failed
%x\n", status );
+ status = pNtCreateSymbolicLinkObject( &ret, GENERIC_ALL, NULL, &target );
+ ok( status == STATUS_ACCESS_VIOLATION || broken( status == STATUS_SUCCESS), /* winxp
*/
+ "NULL: NtCreateSymbolicLinkObject failed %x\n", status );
+ if (!status) pNtClose( ret );
+ status = pNtOpenSymbolicLinkObject( &ret, GENERIC_ALL, NULL );
+ ok( status == STATUS_INVALID_PARAMETER, "NULL: NtOpenSymbolicLinkObject failed
%x\n", status );
+ status = pNtCreateSection( &ret, SECTION_MAP_WRITE, NULL, &size,
PAGE_READWRITE, SEC_COMMIT, 0 );
+ ok( status == STATUS_SUCCESS, "NULL: NtCreateSection failed %x\n", status
);
+ pNtClose( ret );
+ status = pNtOpenSection( &ret, SECTION_MAP_WRITE, NULL );
+ ok( status == STATUS_INVALID_PARAMETER, "NULL: NtOpenSection failed %x\n",
status );
+ attr2.ObjectName = attr3.ObjectName = &str;
+
+ /* named pipes */
+ memcpy( str.Buffer, pipeW, sizeof(pipeW) );
+ for (i = 0; i < 65536 / sizeof(WCHAR); i++) str.Buffer[i +
sizeof(pipeW)/sizeof(WCHAR)] = 'a';
+ str.Length = 0;
+ attr.RootDirectory = 0;
+ attr.Attributes = OBJ_CASE_INSENSITIVE;
+ timeout.QuadPart = -10000;
+ status = pNtCreateNamedPipeFile( &ret, GENERIC_ALL, &attr, &iosb,
FILE_SHARE_READ|FILE_SHARE_WRITE,
+ FILE_CREATE, FILE_PIPE_FULL_DUPLEX, 0, 0, 0, 1, 256,
256, &timeout );
+ ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "%u: NtCreateNamedPipeFile failed
%x\n", str.Length, status );
+ status = pNtCreateNamedPipeFile( &ret, GENERIC_ALL, &attr2, &iosb,
FILE_SHARE_READ|FILE_SHARE_WRITE,
+ FILE_CREATE, FILE_PIPE_FULL_DUPLEX, 0, 0, 0, 1, 256,
256, &timeout );
+ ok( status == STATUS_INVALID_HANDLE, "%u: NtCreateNamedPipeFile failed
%x\n", str.Length, status );
+ str.Length = 67;
+ status = pNtCreateNamedPipeFile( &ret, GENERIC_ALL, &attr2, &iosb,
FILE_SHARE_READ|FILE_SHARE_WRITE,
+ FILE_CREATE, FILE_PIPE_FULL_DUPLEX, 0, 0, 0, 1, 256,
256, &timeout );
+ ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtCreateNamedPipeFile failed
%x\n", str.Length, status );
+ str.Length = 128;
+ for (attr.Length = 0; attr.Length <= 2 * sizeof(attr); attr.Length++)
+ {
+ status = pNtCreateNamedPipeFile( &ret, GENERIC_ALL, &attr, &iosb,
FILE_SHARE_READ|FILE_SHARE_WRITE,
+ FILE_CREATE, FILE_PIPE_FULL_DUPLEX, 0, 0, 0, 1,
256, 256, &timeout );
+ if (attr.Length == sizeof(attr))
+ {
+ ok( status == STATUS_SUCCESS, "%u: NtCreateNamedPipeFile failed
%x\n", str.Length, status );
+ pNtClose( ret );
+ }
+ else ok( status == STATUS_INVALID_PARAMETER,
+ "%u: NtCreateNamedPipeFile failed %x\n", str.Length, status
);
+ }
+ attr.Length = sizeof(attr);
+ str.Length = 65532;
+ status = pNtCreateNamedPipeFile( &ret, GENERIC_ALL, &attr, &iosb,
FILE_SHARE_READ|FILE_SHARE_WRITE,
+ FILE_CREATE, FILE_PIPE_FULL_DUPLEX, 0, 0, 0, 1, 256,
256, &timeout );
+ ok( status == STATUS_SUCCESS, "%u: NtCreateNamedPipeFile failed %x\n",
str.Length, status );
+ pNtClose( ret );
+ str.Length = 65534;
+ status = pNtCreateNamedPipeFile( &ret, GENERIC_ALL, &attr, &iosb,
FILE_SHARE_READ|FILE_SHARE_WRITE,
+ FILE_CREATE, FILE_PIPE_FULL_DUPLEX, 0, 0, 0, 1, 256,
256, &timeout );
+ ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtCreateNamedPipeFile failed
%x\n", str.Length, status );
+ attr3.RootDirectory = 0;
+ attr2.ObjectName = attr3.ObjectName = NULL;
+ status = pNtCreateNamedPipeFile( &ret, GENERIC_ALL, &attr2, &iosb,
FILE_SHARE_READ|FILE_SHARE_WRITE,
+ FILE_CREATE, FILE_PIPE_FULL_DUPLEX, 0, 0, 0, 1, 256,
256, &timeout );
+ ok( status == STATUS_OBJECT_NAME_INVALID, "NULL: NtCreateNamedPipeFile failed
%x\n", status );
+ status = pNtCreateNamedPipeFile( &ret, GENERIC_ALL, &attr3, &iosb,
FILE_SHARE_READ|FILE_SHARE_WRITE,
+ FILE_CREATE, FILE_PIPE_FULL_DUPLEX, 0, 0, 0, 1, 256,
256, &timeout );
+ ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NULL: NtCreateNamedPipeFile failed
%x\n", status );
+ status = pNtCreateNamedPipeFile( &ret, GENERIC_ALL, NULL, &iosb,
FILE_SHARE_READ|FILE_SHARE_WRITE,
+ FILE_CREATE, FILE_PIPE_FULL_DUPLEX, 0, 0, 0, 1, 256,
256, &timeout );
+ ok( status == STATUS_INVALID_PARAMETER, "NULL: NtCreateNamedPipeFile failed
%x\n", status );
+ attr2.ObjectName = attr3.ObjectName = &str;
+
+ /* mailslots */
+ memcpy( str.Buffer, mailslotW, sizeof(mailslotW) );
+ for (i = 0; i < 65536 / sizeof(WCHAR); i++) str.Buffer[i +
sizeof(mailslotW)/sizeof(WCHAR)] = 'a';
+ str.Length = 0;
+ status = pNtCreateMailslotFile( &ret, GENERIC_ALL, &attr, &iosb, 0, 0, 0,
NULL );
+ ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "%u: NtCreateMailslotFile failed
%x\n", str.Length, status );
+ status = pNtCreateMailslotFile( &ret, GENERIC_ALL, &attr2, &iosb, 0, 0,
0, NULL );
+ ok( status == STATUS_INVALID_HANDLE, "%u: NtCreateMailslotFile failed
%x\n", str.Length, status );
+ str.Length = 67;
+ status = pNtCreateMailslotFile( &ret, GENERIC_ALL, &attr2, &iosb, 0, 0,
0, NULL );
+ ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtCreateMailslotFile failed
%x\n", str.Length, status );
+ str.Length = 128;
+ for (attr.Length = 0; attr.Length <= 2 * sizeof(attr); attr.Length++)
+ {
+ status = pNtCreateMailslotFile( &ret, GENERIC_ALL, &attr, &iosb, 0,
0, 0, NULL );
+ if (attr.Length == sizeof(attr))
+ {
+ ok( status == STATUS_SUCCESS, "%u: NtCreateMailslotFile failed
%x\n", str.Length, status );
+ pNtClose( ret );
+ }
+ else ok( status == STATUS_INVALID_PARAMETER,
+ "%u: NtCreateMailslotFile failed %x\n", str.Length, status );
+ }
+ attr.Length = sizeof(attr);
+ str.Length = 65532;
+ status = pNtCreateMailslotFile( &ret, GENERIC_ALL, &attr, &iosb, 0, 0, 0,
NULL );
+ ok( status == STATUS_SUCCESS, "%u: NtCreateMailslotFile failed %x\n",
str.Length, status );
+ pNtClose( ret );
+ str.Length = 65534;
+ status = pNtCreateMailslotFile( &ret, GENERIC_ALL, &attr, &iosb, 0, 0, 0,
NULL );
+ ok( status == STATUS_OBJECT_NAME_INVALID, "%u: NtCreateMailslotFile failed
%x\n", str.Length, status );
+ attr3.RootDirectory = 0;
+ attr2.ObjectName = attr3.ObjectName = NULL;
+ status = pNtCreateMailslotFile( &ret, GENERIC_ALL, &attr2, &iosb, 0, 0,
0, NULL );
+ ok( status == STATUS_OBJECT_NAME_INVALID, "NULL: NtCreateMailslotFile failed
%x\n", status );
+ status = pNtCreateMailslotFile( &ret, GENERIC_ALL, &attr3, &iosb, 0, 0,
0, NULL );
+ ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NULL: NtCreateMailslotFile failed
%x\n", status );
+ status = pNtCreateMailslotFile( &ret, GENERIC_ALL, NULL, &iosb, 0, 0, 0, NULL
);
+ ok( status == STATUS_INVALID_PARAMETER, "NULL: NtCreateMailslotFile failed
%x\n", status );
+ attr2.ObjectName = attr3.ObjectName = &str;
+
+ /* registry keys */
+ memcpy( str.Buffer, registryW, sizeof(registryW) );
+ for (i = 0; i < 65536 / sizeof(WCHAR); i++) str.Buffer[i +
sizeof(registryW)/sizeof(WCHAR)] = 'a';
+ str.Length = 0;
+ status = pNtCreateKey( &ret, GENERIC_ALL, &attr, 0, NULL, 0, NULL );
+ todo_wine
+ ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "%u: NtCreateKey failed %x\n",
str.Length, status );
+ status = pNtCreateKey( &ret, GENERIC_ALL, &attr2, 0, NULL, 0, NULL );
+ ok( status == STATUS_INVALID_HANDLE, "%u: NtCreateKey failed %x\n",
str.Length, status );
+ status = pNtOpenKey( &ret, GENERIC_ALL, &attr2 );
+ ok( status == STATUS_INVALID_HANDLE, "%u: NtOpenKey failed %x\n",
str.Length, status );
+ str.Length = sizeof(registryW) + 250 * sizeof(WCHAR) + 1;
+ status = pNtCreateKey( &ret, GENERIC_ALL, &attr, 0, NULL, 0, NULL );
+ ok( status == STATUS_OBJECT_NAME_INVALID ||
+ status == STATUS_INVALID_PARAMETER ||
+ broken( status == STATUS_SUCCESS ), /* wow64 */
+ "%u: NtCreateKey failed %x\n", str.Length, status );
+ if (!status)
+ {
+ pNtDeleteKey( ret );
+ pNtClose( ret );
+ }
+ str.Length = sizeof(registryW) + 256 * sizeof(WCHAR);
+ status = pNtCreateKey( &ret, GENERIC_ALL, &attr, 0, NULL, 0, NULL );
+ ok( status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED,
+ "%u: NtCreateKey failed %x\n", str.Length, status );
+ if (!status)
+ {
+ status = pNtOpenKey( &ret2, KEY_READ, &attr );
+ ok( status == STATUS_SUCCESS, "%u: NtOpenKey failed %x\n", str.Length,
status );
+ pNtClose( ret2 );
+ attr3.RootDirectory = ret;
+ str.Length = 0;
+ status = pNtOpenKey( &ret2, KEY_READ, &attr3 );
+ ok( status == STATUS_SUCCESS, "%u: NtOpenKey failed %x\n", str.Length,
status );
+ pNtClose( ret2 );
+ pNtDeleteKey( ret );
+ pNtClose( ret );
+
+ str.Length = sizeof(registryW) + 256 * sizeof(WCHAR);
+ for (attr.Length = 0; attr.Length <= 2 * sizeof(attr); attr.Length++)
+ {
+ if (attr.Length == sizeof(attr))
+ {
+ status = pNtCreateKey( &ret, GENERIC_ALL, &attr, 0, NULL, 0, NULL
);
+ ok( status == STATUS_SUCCESS, "%u: NtCreateKey failed %x\n",
str.Length, status );
+ status = pNtOpenKey( &ret2, KEY_READ, &attr );
+ ok( status == STATUS_SUCCESS, "%u: NtOpenKey failed %x\n",
str.Length, status );
+ pNtClose( ret2 );
+ pNtDeleteKey( ret );
+ pNtClose( ret );
+ }
+ else
+ {
+ status = pNtCreateKey( &ret, GENERIC_ALL, &attr, 0, NULL, 0, NULL
);
+ ok( status == STATUS_INVALID_PARAMETER, "%u: NtCreateKey failed
%x\n", str.Length, status );
+ status = pNtOpenKey( &ret2, KEY_READ, &attr );
+ ok( status == STATUS_INVALID_PARAMETER, "%u: NtOpenKey failed
%x\n", str.Length, status );
+ }
+ }
+ attr.Length = sizeof(attr);
+ }
+ str.Length = sizeof(registryW) + 256 * sizeof(WCHAR) + 1;
+ status = pNtCreateKey( &ret, GENERIC_ALL, &attr, 0, NULL, 0, NULL );
+ ok( status == STATUS_OBJECT_NAME_INVALID ||
+ status == STATUS_INVALID_PARAMETER ||
+ broken( status == STATUS_SUCCESS ), /* win7 */
+ "%u: NtCreateKey failed %x\n", str.Length, status );
+ if (!status)
+ {
+ pNtDeleteKey( ret );
+ pNtClose( ret );
+ }
+ status = pNtOpenKey( &ret, GENERIC_ALL, &attr );
+ ok( status == STATUS_OBJECT_NAME_INVALID ||
+ status == STATUS_INVALID_PARAMETER ||
+ broken( status == STATUS_OBJECT_NAME_NOT_FOUND ), /* wow64 */
+ "%u: NtOpenKey failed %x\n", str.Length, status );
+ str.Length++;
+ status = pNtCreateKey( &ret, GENERIC_ALL, &attr, 0, NULL, 0, NULL );
+ ok( status == STATUS_INVALID_PARAMETER, "%u: NtCreateKey failed %x\n",
str.Length, status );
+ status = pNtOpenKey( &ret, GENERIC_ALL, &attr );
+ todo_wine
+ ok( status == STATUS_INVALID_PARAMETER, "%u: NtOpenKey failed %x\n",
str.Length, status );
+ str.Length = 2000;
+ status = pNtCreateKey( &ret, GENERIC_ALL, &attr, 0, NULL, 0, NULL );
+ ok( status == STATUS_INVALID_PARAMETER, "%u: NtCreateKey failed %x\n",
str.Length, status );
+ status = pNtOpenKey( &ret, GENERIC_ALL, &attr );
+ todo_wine
+ ok( status == STATUS_INVALID_PARAMETER, "%u: NtOpenKey failed %x\n",
str.Length, status );
+ /* some Windows versions change the error past 2050 chars, others past 4066 chars,
some don't */
+ str.Length = 5000;
+ status = pNtCreateKey( &ret, GENERIC_ALL, &attr, 0, NULL, 0, NULL );
+ ok( status == STATUS_BUFFER_OVERFLOW ||
+ status == STATUS_BUFFER_TOO_SMALL ||
+ status == STATUS_INVALID_PARAMETER,
+ "%u: NtCreateKey failed %x\n", str.Length, status );
+ status = pNtOpenKey( &ret, GENERIC_ALL, &attr );
+ todo_wine
+ ok( status == STATUS_BUFFER_OVERFLOW ||
+ status == STATUS_BUFFER_TOO_SMALL ||
+ status == STATUS_INVALID_PARAMETER,
+ "%u: NtOpenKey failed %x\n", str.Length, status );
+ str.Length = 65534;
+ status = pNtCreateKey( &ret, GENERIC_ALL, &attr, 0, NULL, 0, NULL );
+ ok( status == STATUS_OBJECT_NAME_INVALID ||
+ status == STATUS_BUFFER_OVERFLOW ||
+ status == STATUS_BUFFER_TOO_SMALL,
+ "%u: NtCreateKey failed %x\n", str.Length, status );
+ status = pNtOpenKey( &ret, GENERIC_ALL, &attr );
+ todo_wine
+ ok( status == STATUS_OBJECT_NAME_INVALID ||
+ status == STATUS_BUFFER_OVERFLOW ||
+ status == STATUS_BUFFER_TOO_SMALL,
+ "%u: NtOpenKey failed %x\n", str.Length, status );
+ attr3.RootDirectory = 0;
+ attr2.ObjectName = attr3.ObjectName = NULL;
+ status = pNtCreateKey( &ret, GENERIC_ALL, &attr2, 0, NULL, 0, NULL );
+ todo_wine
+ ok( status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_HANDLE,
+ "NULL: NtCreateKey failed %x\n", status );
+ status = pNtCreateKey( &ret, GENERIC_ALL, &attr3, 0, NULL, 0, NULL );
+ todo_wine
+ ok( status == STATUS_ACCESS_VIOLATION, "NULL: NtCreateKey failed %x\n",
status );
+ status = pNtCreateKey( &ret, GENERIC_ALL, NULL, 0, NULL, 0, NULL );
+ ok( status == STATUS_ACCESS_VIOLATION, "NULL: NtCreateKey failed %x\n",
status );
+ status = pNtOpenKey( &ret, GENERIC_ALL, &attr2 );
+ ok( status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_HANDLE,
+ "NULL: NtOpenKey failed %x\n", status );
+ status = pNtOpenKey( &ret, GENERIC_ALL, &attr3 );
+ ok( status == STATUS_ACCESS_VIOLATION, "NULL: NtOpenKey failed %x\n",
status );
+ status = pNtOpenKey( &ret, GENERIC_ALL, NULL );
+ ok( status == STATUS_ACCESS_VIOLATION, "NULL: NtOpenKey failed %x\n",
status );
+ attr2.ObjectName = attr3.ObjectName = &str;
+
+ pRtlFreeUnicodeString( &str );
+ pRtlFreeUnicodeString( &target );
+}
+
static void test_directory(void)
{
NTSTATUS status;
UNICODE_STRING str;
OBJECT_ATTRIBUTES attr;
- HANDLE dir, dir1, h;
+ HANDLE dir, dir1, h, h2;
BOOL is_nt4;
/* No name and/or no attributes */
@@ -380,28 +921,34 @@ static void test_directory(void)
"NtOpenDirectoryObject should have failed with STATUS_INVALID_PARAMETER
got(%08x)\n", status);
InitializeObjectAttributes(&attr, NULL, 0, 0, NULL);
- DIR_TEST_CREATE_SUCCESS(&dir)
- DIR_TEST_OPEN_FAILURE(&h, STATUS_OBJECT_PATH_SYNTAX_BAD)
+ status = pNtCreateDirectoryObject( &dir, DIRECTORY_QUERY, &attr );
+ ok( status == STATUS_SUCCESS, "Failed to create directory %08x\n", status
);
+ status = pNtOpenDirectoryObject( &h, DIRECTORY_QUERY, &attr );
+ ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtOpenDirectoryObject got
%08x\n", status );
/* Bad name */
InitializeObjectAttributes(&attr, &str, 0, 0, NULL);
pRtlCreateUnicodeStringFromAsciiz(&str, "");
- DIR_TEST_CREATE_SUCCESS(&h)
+ status = pNtCreateDirectoryObject( &h, DIRECTORY_QUERY, &attr );
+ ok( status == STATUS_SUCCESS, "Failed to create directory %08x\n", status
);
pNtClose(h);
- DIR_TEST_OPEN_FAILURE(&h, STATUS_OBJECT_PATH_SYNTAX_BAD)
+ status = pNtOpenDirectoryObject( &h, DIRECTORY_QUERY, &attr );
+ ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtOpenDirectoryObject got
%08x\n", status );
pRtlFreeUnicodeString(&str);
pNtClose(dir);
- DIR_TEST_CREATE_OPEN_FAILURE(&h, "BaseNamedObjects",
STATUS_OBJECT_PATH_SYNTAX_BAD)
- DIR_TEST_CREATE_OPEN_FAILURE(&h, "\\BaseNamedObjects\\",
STATUS_OBJECT_NAME_INVALID)
- DIR_TEST_CREATE_OPEN_FAILURE(&h, "\\\\BaseNamedObjects",
STATUS_OBJECT_NAME_INVALID)
- DIR_TEST_CREATE_OPEN_FAILURE(&h, "\\BaseNamedObjects\\\\om.c-test",
STATUS_OBJECT_NAME_INVALID)
- DIR_TEST_CREATE_OPEN_FAILURE(&h, "\\BaseNamedObjects\\om.c-test\\",
STATUS_OBJECT_PATH_NOT_FOUND)
+ DIR_TEST_CREATE_OPEN( "BaseNamedObjects", STATUS_OBJECT_PATH_SYNTAX_BAD );
+ DIR_TEST_CREATE_OPEN( "\\BaseNamedObjects\\", STATUS_OBJECT_NAME_INVALID
);
+ DIR_TEST_CREATE_OPEN( "\\\\BaseNamedObjects", STATUS_OBJECT_NAME_INVALID
);
+ DIR_TEST_CREATE_OPEN( "\\BaseNamedObjects\\\\om.c-test",
STATUS_OBJECT_NAME_INVALID );
+ DIR_TEST_CREATE_OPEN( "\\BaseNamedObjects\\om.c-test\\",
STATUS_OBJECT_PATH_NOT_FOUND );
pRtlCreateUnicodeStringFromAsciiz(&str,
"\\BaseNamedObjects\\om.c-test");
- DIR_TEST_CREATE_SUCCESS(&h)
- DIR_TEST_OPEN_SUCCESS(&dir1)
+ status = pNtCreateDirectoryObject( &h, DIRECTORY_QUERY, &attr );
+ ok( status == STATUS_SUCCESS, "Failed to create directory %08x\n", status
);
+ status = pNtOpenDirectoryObject( &dir1, DIRECTORY_QUERY, &attr );
+ ok( status == STATUS_SUCCESS, "Failed to open directory %08x\n", status );
pRtlFreeUnicodeString(&str);
pNtClose(h);
pNtClose(dir1);
@@ -423,9 +970,43 @@ static void test_directory(void)
pRtlFreeUnicodeString(&str);
InitializeObjectAttributes(&attr, &str, 0, dir, NULL);
pRtlCreateUnicodeStringFromAsciiz(&str, "one more level");
- DIR_TEST_CREATE_FAILURE(&h, STATUS_OBJECT_TYPE_MISMATCH)
+ status = pNtCreateDirectoryObject( &h, DIRECTORY_QUERY, &attr );
+ ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtCreateDirectoryObject got
%08x\n", status );
pRtlFreeUnicodeString(&str);
+ pRtlCreateUnicodeStringFromAsciiz( &str,
"\\BaseNamedObjects\\Local\\om.c-test" );
+ InitializeObjectAttributes( &attr, &str, 0, 0, NULL );
+ status = pNtCreateDirectoryObject( &dir1, DIRECTORY_QUERY, &attr );
+ ok( status == STATUS_SUCCESS, "Failed to create directory %08x\n",
status );
+ pRtlFreeUnicodeString( &str );
+ pRtlCreateUnicodeStringFromAsciiz( &str, "om.c-test" );
+ InitializeObjectAttributes( &attr, &str, 0, dir, NULL );
+ status = pNtOpenDirectoryObject( &h, DIRECTORY_QUERY, &attr );
+ ok( status == STATUS_OBJECT_TYPE_MISMATCH, "Failed to open directory
%08x\n", status );
+ if (!status) pNtClose(h);
+ pRtlFreeUnicodeString( &str );
+
+ pRtlCreateUnicodeStringFromAsciiz( &str, "om.c-event" );
+ InitializeObjectAttributes( &attr, &str, 0, dir1, NULL );
+ status = pNtCreateEvent( &h, GENERIC_ALL, &attr, 1, 0 );
+ ok( status == STATUS_SUCCESS, "NtCreateEvent failed %x\n", status );
+ status = pNtOpenEvent( &h2, GENERIC_ALL, &attr );
+ ok( status == STATUS_SUCCESS, "NtOpenEvent failed %x\n", status );
+ pNtClose( h2 );
+ pRtlFreeUnicodeString( &str );
+ pRtlCreateUnicodeStringFromAsciiz( &str, "om.c-test\\om.c-event"
);
+ InitializeObjectAttributes( &attr, &str, 0, dir, NULL );
+ status = pNtOpenEvent( &h2, GENERIC_ALL, &attr );
+ ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtOpenEvent failed %x\n",
status );
+ pRtlFreeUnicodeString( &str );
+ pRtlCreateUnicodeStringFromAsciiz( &str,
"\\BasedNamedObjects\\Local\\om.c-test\\om.c-event" );
+ InitializeObjectAttributes( &attr, &str, 0, 0, NULL );
+ status = pNtOpenEvent( &h2, GENERIC_ALL, &attr );
+ ok( status == STATUS_OBJECT_PATH_NOT_FOUND, "NtOpenEvent failed %x\n",
status );
+ pRtlFreeUnicodeString( &str );
+ pNtClose( h );
+ pNtClose( dir1 );
+
str.Buffer = buffer;
str.MaximumLength = sizeof(buffer);
len = 0xdeadbeef;
@@ -463,22 +1044,26 @@ error:
pRtlCreateUnicodeStringFromAsciiz(&str, "\\BaseNamedObjects");
InitializeObjectAttributes(&attr, &str, 0, 0, NULL);
- DIR_TEST_OPEN_SUCCESS(&dir)
+ status = pNtOpenDirectoryObject( &dir, DIRECTORY_QUERY, &attr );
+ ok( status == STATUS_SUCCESS, "Failed to open directory %08x\n", status );
pRtlFreeUnicodeString(&str);
InitializeObjectAttributes(&attr, NULL, 0, dir, NULL);
- DIR_TEST_OPEN_FAILURE(&h, STATUS_OBJECT_NAME_INVALID)
+ status = pNtOpenDirectoryObject( &h, DIRECTORY_QUERY, &attr );
+ ok( status == STATUS_OBJECT_NAME_INVALID, "NtOpenDirectoryObject got
%08x\n", status );
InitializeObjectAttributes(&attr, &str, 0, dir, NULL);
- DIR_TEST_CREATE_OPEN_SUCCESS(h, "")
- DIR_TEST_CREATE_OPEN_FAILURE(&h, "\\", STATUS_OBJECT_PATH_SYNTAX_BAD)
- DIR_TEST_CREATE_OPEN_FAILURE(&h, "\\om.c-test",
STATUS_OBJECT_PATH_SYNTAX_BAD)
- DIR_TEST_CREATE_OPEN_FAILURE(&h, "\\om.c-test\\",
STATUS_OBJECT_PATH_SYNTAX_BAD)
- DIR_TEST_CREATE_OPEN_FAILURE(&h, "om.c-test\\",
STATUS_OBJECT_PATH_NOT_FOUND)
+ DIR_TEST_CREATE_OPEN( "", STATUS_SUCCESS );
+ DIR_TEST_CREATE_OPEN( "\\", STATUS_OBJECT_PATH_SYNTAX_BAD );
+ DIR_TEST_CREATE_OPEN( "\\om.c-test", STATUS_OBJECT_PATH_SYNTAX_BAD );
+ DIR_TEST_CREATE_OPEN( "\\om.c-test\\", STATUS_OBJECT_PATH_SYNTAX_BAD );
+ DIR_TEST_CREATE_OPEN( "om.c-test\\", STATUS_OBJECT_PATH_NOT_FOUND );
pRtlCreateUnicodeStringFromAsciiz(&str, "om.c-test");
- DIR_TEST_CREATE_SUCCESS(&dir1)
- DIR_TEST_OPEN_SUCCESS(&h)
+ status = pNtCreateDirectoryObject( &dir1, DIRECTORY_QUERY, &attr );
+ ok( status == STATUS_SUCCESS, "Failed to create directory %08x\n", status
);
+ status = pNtOpenDirectoryObject( &h, DIRECTORY_QUERY, &attr );
+ ok( status == STATUS_SUCCESS, "Failed to open directory %08x\n", status );
pRtlFreeUnicodeString(&str);
pNtClose(h);
@@ -488,23 +1073,28 @@ error:
/* Nested directories */
pRtlCreateUnicodeStringFromAsciiz(&str, "\\");
InitializeObjectAttributes(&attr, &str, 0, 0, NULL);
- DIR_TEST_OPEN_SUCCESS(&dir)
+ status = pNtOpenDirectoryObject( &dir, DIRECTORY_QUERY, &attr );
+ ok( status == STATUS_SUCCESS, "Failed to open directory %08x\n", status );
InitializeObjectAttributes(&attr, &str, 0, dir, NULL);
- DIR_TEST_OPEN_FAILURE(&h, STATUS_OBJECT_PATH_SYNTAX_BAD)
+ status = pNtOpenDirectoryObject( &h, DIRECTORY_QUERY, &attr );
+ ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtOpenDirectoryObject got
%08x\n", status );
pRtlFreeUnicodeString(&str);
pNtClose(dir);
InitializeObjectAttributes(&attr, &str, 0, 0, NULL);
pRtlCreateUnicodeStringFromAsciiz(&str,
"\\BaseNamedObjects\\om.c-test");
- DIR_TEST_CREATE_SUCCESS(&dir)
+ status = pNtCreateDirectoryObject( &dir, DIRECTORY_QUERY, &attr );
+ ok( status == STATUS_SUCCESS, "Failed to create directory %08x\n", status
);
pRtlFreeUnicodeString(&str);
pRtlCreateUnicodeStringFromAsciiz(&str, "\\BaseNamedObjects\\om.c-test\\one
more level");
- DIR_TEST_CREATE_SUCCESS(&h)
+ status = pNtCreateDirectoryObject( &h, DIRECTORY_QUERY, &attr );
+ ok( status == STATUS_SUCCESS, "Failed to create directory %08x\n", status
);
pRtlFreeUnicodeString(&str);
pNtClose(h);
InitializeObjectAttributes(&attr, &str, 0, dir, NULL);
pRtlCreateUnicodeStringFromAsciiz(&str, "one more level");
- DIR_TEST_CREATE_SUCCESS(&h)
+ status = pNtCreateDirectoryObject( &h, DIRECTORY_QUERY, &attr );
+ ok( status == STATUS_SUCCESS, "Failed to create directory %08x\n", status
);
pRtlFreeUnicodeString(&str);
pNtClose(h);
@@ -514,15 +1104,18 @@ error:
{
InitializeObjectAttributes(&attr, &str, 0, 0, NULL);
pRtlCreateUnicodeStringFromAsciiz(&str,
"\\BaseNamedObjects\\Global\\om.c-test");
- DIR_TEST_CREATE_SUCCESS(&dir)
+ status = pNtCreateDirectoryObject( &dir, DIRECTORY_QUERY, &attr );
+ ok( status == STATUS_SUCCESS, "Failed to create directory %08x\n",
status );
pRtlFreeUnicodeString(&str);
pRtlCreateUnicodeStringFromAsciiz(&str,
"\\BaseNamedObjects\\Local\\om.c-test\\one more level");
- DIR_TEST_CREATE_SUCCESS(&h)
+ status = pNtCreateDirectoryObject( &h, DIRECTORY_QUERY, &attr );
+ ok( status == STATUS_SUCCESS, "Failed to create directory %08x\n",
status );
pRtlFreeUnicodeString(&str);
pNtClose(h);
InitializeObjectAttributes(&attr, &str, 0, dir, NULL);
pRtlCreateUnicodeStringFromAsciiz(&str, "one more level");
- DIR_TEST_CREATE_SUCCESS(&dir)
... 4309 lines suppressed ...