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
path.c
pipe.c
port.c
+ process.c
reg.c
rtl.c
rtlbitmap.c
#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 );
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);
}
}
{
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 */
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);
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)) {
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;
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");
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);
}
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 );
START_TEST(directory)
{
+ WCHAR sysdir[MAX_PATH];
HMODULE hntdll = GetModuleHandleA("ntdll.dll");
if (!hntdll)
{
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();
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);
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__
{ { 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;
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);
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",
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);
if (have_vectored_api)
pRtlRemoveVectoredExceptionHandler(vectored_handler);
- pNtCurrentTeb()->Tib.ExceptionList = frame.Prev;
+ NtCurrentTeb()->Tib.ExceptionList = frame.Prev;
}
static void test_rtlraiseexception(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",
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 */
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;
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)
{
/* 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)
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);
}
}
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,
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);
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;
}
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 */
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 */
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
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);
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);
}
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
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;
}
+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)
outputdebugstring_exceptions = 0;
OutputDebugStringA("Hello World");
+
ok(outputdebugstring_exceptions == numexc, "OutputDebugStringA generated %d exceptions, expected %d\n",
outputdebugstring_exceptions, 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)
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"))
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" );
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)
}
/* child must be run under a debugger */
- if (!pNtCurrentTeb()->Peb->BeingDebugged)
+ if (!NtCurrentTeb()->Peb->BeingDebugged)
{
ok(FALSE, "child process not being debugged?\n");
return;
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
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();
test_fpu_exceptions();
test_dpe_exceptions();
test_prot_fault();
+ test_thread_context();
#elif defined(__x86_64__)
pRtlAddFunctionTable = (void *)GetProcAddress( hntdll,
"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();
#endif
- VirtualFree(code_mem, 0, MEM_FREE);
+ VirtualFree(code_mem, 0, MEM_RELEASE);
}
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);
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 )
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];
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;
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)
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;
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 );
}
}
{
OVERLAPPED o = {0,};
BYTE send_buf[TEST_BUF_LEN], recv_buf[TEST_BUF_LEN];
+ int apc_count = 0;
DWORD read;
long count;
}
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 );
/* 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);
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);
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 );
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 );
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 );
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;
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 );
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 );
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 );
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;
{
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;
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;
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);
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);
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)
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");
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();
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();
}
#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);
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;
{
/* 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);
/* 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;
}
/* 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");
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;
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);
}
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;
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,
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)
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");
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);
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;
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,
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)
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,
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);
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);
{
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);
"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)
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;
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();
/* 0x49 SystemLogicalProcessorInformation */
trace("Starting test_query_logicalproc()\n");
test_query_logicalproc();
+ test_query_logicalprocex();
/* NtPowerInformation */
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();
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();
}
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)
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 */
}
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));
}
}
} /* 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,
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);
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);
}
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();
test_RtlInt64ToUnicodeString();
if (pRtlLargeIntegerToChar)
test_RtlLargeIntegerToChar();
+
+#ifdef __i386__
+ test__alldvrm();
+#endif /* __i386__ */
}
#include <stdarg.h>
-#ifndef _WIN32_WINNT
-#define _WIN32_WINNT 0x500 /* For NTSTATUS */
-#endif
-
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h"
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,
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};
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 )
{
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;
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:
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,
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 */
"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);
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;
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);
/* 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);
{
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)
+ status = pNtCreateDirectoryObject( &dir, DIRECTORY_QUERY, &attr );
+ ok( status == STATUS_SUCCESS, "Failed to create directory %08x\n", status );
pRtlFreeUnicodeString(&str);
pNtClose(h);
pNtClose(dir);
InitializeObjectAttributes(&attr, &str, 0, 0, NULL);
pRtlCreateUnicodeStringFromAsciiz(&str, "\\BaseNamedObjects");
- 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, &str, 0, dir, NULL);
pNtClose(dir);
}
-#define SYMLNK_TEST_CREATE_OPEN_FAILURE2(h,n,t,e,e2) \
- pRtlCreateUnicodeStringFromAsciiz(&str, n);\
- pRtlCreateUnicodeStringFromAsciiz(&target, t);\
- status = pNtCreateSymbolicLinkObject(h, SYMBOLIC_LINK_QUERY, &attr, &target);\
- ok(status == e || status == e2, \
- "NtCreateSymbolicLinkObject should have failed with %s or %s got(%08x)\n", #e, #e2, status);\
- status = pNtOpenSymbolicLinkObject(h, SYMBOLIC_LINK_QUERY, &attr);\
- ok(status == e || status == e2, \
- "NtOpenSymbolicLinkObject should have failed with %s or %s got(%08x)\n", #e, #e2, status);\
- pRtlFreeUnicodeString(&target);\
- pRtlFreeUnicodeString(&str);
-
-#define SYMLNK_TEST_CREATE_OPEN_FAILURE(h,n,t,e) SYMLNK_TEST_CREATE_OPEN_FAILURE2(h,n,t,e,e)
-
static void test_symboliclink(void)
{
NTSTATUS status;
/* No name and/or no attributes */
InitializeObjectAttributes(&attr, NULL, 0, 0, NULL);
- SYMLNK_TEST_CREATE_OPEN_FAILURE2(NULL, "", "", STATUS_ACCESS_VIOLATION, STATUS_INVALID_PARAMETER)
+ pRtlCreateUnicodeStringFromAsciiz(&target, "\\DosDevices");
+ status = pNtCreateSymbolicLinkObject( NULL, SYMBOLIC_LINK_QUERY, &attr, &target );
+ ok( status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_PARAMETER,
+ "NtCreateSymbolicLinkObject got %08x\n", status );
+ status = pNtOpenSymbolicLinkObject( NULL, SYMBOLIC_LINK_QUERY, &attr );
+ ok( status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_PARAMETER,
+ "NtOpenSymbolicLinkObject got %08x\n", status );
status = pNtCreateSymbolicLinkObject(&h, SYMBOLIC_LINK_QUERY, NULL, NULL);
ok(status == STATUS_ACCESS_VIOLATION,
"NtOpenSymbolicLinkObject should have failed with STATUS_INVALID_PARAMETER got(%08x)\n", status);
/* No attributes */
- pRtlCreateUnicodeStringFromAsciiz(&target, "\\DosDevices");
status = pNtCreateSymbolicLinkObject(&h, SYMBOLIC_LINK_QUERY, NULL, &target);
ok(status == STATUS_SUCCESS || status == STATUS_ACCESS_VIOLATION, /* nt4 */
"NtCreateSymbolicLinkObject failed(%08x)\n", status);
pRtlFreeUnicodeString(&str);
pRtlFreeUnicodeString(&target);
- SYMLNK_TEST_CREATE_OPEN_FAILURE(&h, "BaseNamedObjects", "->Somewhere", STATUS_OBJECT_PATH_SYNTAX_BAD)
- SYMLNK_TEST_CREATE_OPEN_FAILURE(&h, "\\BaseNamedObjects\\", "->Somewhere", STATUS_OBJECT_NAME_INVALID)
- SYMLNK_TEST_CREATE_OPEN_FAILURE(&h, "\\\\BaseNamedObjects", "->Somewhere", STATUS_OBJECT_NAME_INVALID)
- SYMLNK_TEST_CREATE_OPEN_FAILURE(&h, "\\BaseNamedObjects\\\\om.c-test", "->Somewhere", STATUS_OBJECT_NAME_INVALID)
- SYMLNK_TEST_CREATE_OPEN_FAILURE2(&h, "\\BaseNamedObjects\\om.c-test\\", "->Somewhere",
- STATUS_OBJECT_NAME_INVALID, STATUS_OBJECT_PATH_NOT_FOUND)
-
+ pRtlCreateUnicodeStringFromAsciiz( &target, "->Somewhere");
+
+ pRtlCreateUnicodeStringFromAsciiz( &str, "BaseNamedObjects" );
+ status = pNtCreateSymbolicLinkObject( &h, SYMBOLIC_LINK_QUERY, &attr, &target );
+ ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtCreateSymbolicLinkObject got %08x\n", status );
+ status = pNtOpenSymbolicLinkObject( &h, SYMBOLIC_LINK_QUERY, &attr );
+ ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtOpenSymbolicLinkObject got %08x\n", status );
+ pRtlFreeUnicodeString( &str );
+
+ pRtlCreateUnicodeStringFromAsciiz( &str, "\\BaseNamedObjects\\" );
+ status = pNtCreateSymbolicLinkObject( &h, SYMBOLIC_LINK_QUERY, &attr, &target );
+ ok( status == STATUS_OBJECT_NAME_INVALID, "NtCreateSymbolicLinkObject got %08x\n", status );
+ status = pNtOpenSymbolicLinkObject( &h, SYMBOLIC_LINK_QUERY, &attr );
+ ok( status == STATUS_OBJECT_NAME_INVALID, "NtOpenSymbolicLinkObject got %08x\n", status );
+ pRtlFreeUnicodeString( &str );
+
+ pRtlCreateUnicodeStringFromAsciiz( &str, "\\\\BaseNamedObjects" );
+ status = pNtCreateSymbolicLinkObject( &h, SYMBOLIC_LINK_QUERY, &attr, &target );
+ ok( status == STATUS_OBJECT_NAME_INVALID, "NtCreateSymbolicLinkObject got %08x\n", status );
+ status = pNtOpenSymbolicLinkObject( &h, SYMBOLIC_LINK_QUERY, &attr );
+ ok( status == STATUS_OBJECT_NAME_INVALID, "NtOpenSymbolicLinkObject got %08x\n", status );
+ pRtlFreeUnicodeString( &str );
+
+ pRtlCreateUnicodeStringFromAsciiz( &str, "\\BaseNamedObjects\\\\om.c-test" );
+ status = pNtCreateSymbolicLinkObject( &h, SYMBOLIC_LINK_QUERY, &attr, &target );
+ ok( status == STATUS_OBJECT_NAME_INVALID, "NtCreateSymbolicLinkObject got %08x\n", status );
+ status = pNtOpenSymbolicLinkObject( &h, SYMBOLIC_LINK_QUERY, &attr );
+ ok( status == STATUS_OBJECT_NAME_INVALID, "NtOpenSymbolicLinkObject got %08x\n", status );
+ pRtlFreeUnicodeString( &str );
+
+ pRtlCreateUnicodeStringFromAsciiz( &str, "\\BaseNamedObjects\\om.c-test\\" );
+ status = pNtCreateSymbolicLinkObject( &h, SYMBOLIC_LINK_QUERY, &attr, &target );
+ ok( status == STATUS_OBJECT_NAME_INVALID || status == STATUS_OBJECT_PATH_NOT_FOUND,
+ "NtCreateSymbolicLinkObject got %08x\n", status );
+ status = pNtOpenSymbolicLinkObject( &h, SYMBOLIC_LINK_QUERY, &attr );
+ ok( status == STATUS_OBJECT_NAME_INVALID || status == STATUS_OBJECT_PATH_NOT_FOUND,
+ "NtOpenSymbolicLinkObject got %08x\n", status );
+ pRtlFreeUnicodeString( &str );
+ pRtlFreeUnicodeString(&target);
/* Compound test */
if (!(dir = get_base_dir()))
char buffer[1024];
NTSTATUS status;
ULONG len, expected_len;
- UNICODE_STRING *str;
+ OBJECT_ATTRIBUTES attr;
+ UNICODE_STRING path, session, *str;
char dir[MAX_PATH], tmp_path[MAX_PATH], file1[MAX_PATH + 16];
LARGE_INTEGER size;
+ sprintf( tmp_path, "\\Sessions\\%u", NtCurrentTeb()->Peb->SessionId );
+ pRtlCreateUnicodeStringFromAsciiz( &session, tmp_path );
+ InitializeObjectAttributes( &attr, &path, 0, 0, 0 );
+
handle = CreateEventA( NULL, FALSE, FALSE, "test_event" );
len = 0;
str = (UNICODE_STRING *)buffer;
ok( sizeof(UNICODE_STRING) + str->Length + sizeof(WCHAR) == len, "unexpected len %u\n", len );
ok( str->Length >= sizeof(name), "unexpected len %u\n", str->Length );
- /* there can be a \\Sessions prefix in the name */
- ok( !memcmp( str->Buffer + (str->Length - sizeof(name)) / sizeof(WCHAR), name, sizeof(name) ),
+ ok( len > sizeof(UNICODE_STRING) + sizeof("\\test_event") * sizeof(WCHAR),
+ "name too short %s\n", wine_dbgstr_w(str->Buffer) );
+ /* check for \\Sessions prefix in the name */
+ ok( (str->Length > session.Length &&
+ !memcmp( str->Buffer, session.Buffer, session.Length ) &&
+ !memcmp( str->Buffer + session.Length / sizeof(WCHAR), name, sizeof(name) )) ||
+ broken( !memcmp( str->Buffer, name, sizeof(name) )), /* winxp */
"wrong name %s\n", wine_dbgstr_w(str->Buffer) );
+ trace( "got %s len %u\n", wine_dbgstr_w(str->Buffer), len );
len -= sizeof(WCHAR);
status = pNtQueryObject( handle, ObjectNameInformation, buffer, len, &len );
ok( str->Buffer && !memcmp( str->Buffer, type_section, sizeof(type_section) ),
"wrong/bad type name %s (%p)\n", wine_dbgstr_w(str->Buffer), str->Buffer );
pNtClose( handle );
+
+ handle = CreateMailslotA( "\\\\.\\mailslot\\test_mailslot", 100, 1000, NULL );
+ ok( handle != INVALID_HANDLE_VALUE, "CreateMailslot failed err %u\n", GetLastError() );
+ len = 0;
+ status = pNtQueryObject( handle, ObjectNameInformation, buffer, sizeof(buffer), &len );
+ ok( status == STATUS_SUCCESS , "NtQueryObject returned %x\n", status );
+ str = (UNICODE_STRING *)buffer;
+ ok( len > sizeof(UNICODE_STRING), "unexpected len %u\n", len );
+ str = (UNICODE_STRING *)buffer;
+ expected_len = sizeof(UNICODE_STRING) + str->Length + sizeof(WCHAR);
+ ok( len == expected_len || broken(len == expected_len - sizeof(WCHAR)), /* NT4 */
+ "unexpected len %u\n", len );
+ ok( len > sizeof(UNICODE_STRING) + sizeof("\\test_mailslot") * sizeof(WCHAR),
+ "name too short %s\n", wine_dbgstr_w(str->Buffer) );
+ trace( "got %s len %u\n", wine_dbgstr_w(str->Buffer), len );
+ pNtClose( handle );
+
+ handle = CreateNamedPipeA( "\\\\.\\pipe\\test_pipe", PIPE_ACCESS_DUPLEX, PIPE_READMODE_BYTE,
+ 1, 1000, 1000, 1000, NULL );
+ ok( handle != INVALID_HANDLE_VALUE, "CreateNamedPipe failed err %u\n", GetLastError() );
+ len = 0;
+ status = pNtQueryObject( handle, ObjectNameInformation, buffer, sizeof(buffer), &len );
+ ok( status == STATUS_SUCCESS , "NtQueryObject returned %x\n", status );
+ str = (UNICODE_STRING *)buffer;
+ ok( len > sizeof(UNICODE_STRING), "unexpected len %u\n", len );
+ str = (UNICODE_STRING *)buffer;
+ expected_len = sizeof(UNICODE_STRING) + str->Length + sizeof(WCHAR);
+ ok( len == expected_len || broken(len == expected_len - sizeof(WCHAR)), /* NT4 */
+ "unexpected len %u\n", len );
+ ok( len > sizeof(UNICODE_STRING) + sizeof("\\test_pipe") * sizeof(WCHAR),
+ "name too short %s\n", wine_dbgstr_w(str->Buffer) );
+ trace( "got %s len %u\n", wine_dbgstr_w(str->Buffer), len );
+ pNtClose( handle );
+
+ pRtlCreateUnicodeStringFromAsciiz( &path, "\\REGISTRY\\Machine\\Software\\Classes" );
+ status = pNtCreateKey( &handle, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
+ ok( status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED,
+ "NtCreateKey failed status %x\n", status );
+ pRtlFreeUnicodeString( &path );
+ if (status == STATUS_SUCCESS)
+ {
+ len = 0;
+ status = pNtQueryObject( handle, ObjectNameInformation, buffer, sizeof(buffer), &len );
+ ok( status == STATUS_SUCCESS , "NtQueryObject returned %x\n", status );
+ str = (UNICODE_STRING *)buffer;
+ todo_wine
+ ok( len > sizeof(UNICODE_STRING), "unexpected len %u\n", len );
+ str = (UNICODE_STRING *)buffer;
+ expected_len = sizeof(UNICODE_STRING) + str->Length + sizeof(WCHAR);
+ todo_wine
+ ok( len == expected_len || broken(len == expected_len - sizeof(WCHAR)), /* NT4 */
+ "unexpected len %u\n", len );
+ todo_wine
+ ok( len > sizeof(UNICODE_STRING) + sizeof("\\Classes") * sizeof(WCHAR),
+ "name too short %s\n", wine_dbgstr_w(str->Buffer) );
+ trace( "got %s len %u\n", wine_dbgstr_w(str->Buffer), len );
+ pNtClose( handle );
+ }
+ pRtlFreeUnicodeString( &session );
+}
+
+static BOOL winver_equal_or_newer(WORD major, WORD minor)
+{
+ OSVERSIONINFOEXW info = {sizeof(info)};
+ ULONGLONG mask = 0;
+
+ info.dwMajorVersion = major;
+ info.dwMinorVersion = minor;
+
+ VER_SET_CONDITION(mask, VER_MAJORVERSION, VER_GREATER_EQUAL);
+ VER_SET_CONDITION(mask, VER_MINORVERSION, VER_GREATER_EQUAL);
+
+ return VerifyVersionInfoW(&info, VER_MAJORVERSION | VER_MINORVERSION, mask);
+}
+
+static void test_query_object_types(void)
+{
+ static const WCHAR typeW[] = {'T','y','p','e'};
+ static const WCHAR eventW[] = {'E','v','e','n','t'};
+ SYSTEM_HANDLE_INFORMATION_EX *shi;
+ OBJECT_TYPES_INFORMATION *buffer;
+ OBJECT_TYPE_INFORMATION *type;
+ NTSTATUS status;
+ HANDLE handle;
+ BOOL found;
+ ULONG len, i, event_type_index = 0;
+
+ buffer = HeapAlloc( GetProcessHeap(), 0, sizeof(OBJECT_TYPES_INFORMATION) );
+ ok( buffer != NULL, "Failed to allocate memory\n" );
+
+ status = pNtQueryObject( NULL, ObjectTypesInformation, buffer, sizeof(OBJECT_TYPES_INFORMATION), &len );
+ ok( status == STATUS_INFO_LENGTH_MISMATCH, "NtQueryObject failed %x\n", status );
+ ok( len, "len is zero\n");
+
+ buffer = HeapReAlloc( GetProcessHeap(), 0, buffer, len );
+ ok( buffer != NULL, "Failed to allocate memory\n" );
+
+ memset( buffer, 0, len );
+ status = pNtQueryObject( NULL, ObjectTypesInformation, buffer, len, &len );
+ ok( status == STATUS_SUCCESS, "NtQueryObject failed %x\n", status );
+ ok( buffer->NumberOfTypes, "NumberOfTypes is zero\n" );
+
+ type = (OBJECT_TYPE_INFORMATION *)(buffer + 1);
+ for (i = 0; i < buffer->NumberOfTypes; i++)
+ {
+ USHORT length = type->TypeName.MaximumLength;
+ trace( "Type %u: %s\n", i, wine_dbgstr_us(&type->TypeName) );
+
+ if (i == 0)
+ {
+ ok( type->TypeName.Length == sizeof(typeW) && !strncmpW(typeW, type->TypeName.Buffer, 4),
+ "Expected 'Type' as first type, got %s\n", wine_dbgstr_us(&type->TypeName) );
+ }
+ if (type->TypeName.Length == sizeof(eventW) && !strncmpW(eventW, type->TypeName.Buffer, 5))
+ {
+ if (winver_equal_or_newer( 6, 2 ))
+ event_type_index = type->TypeIndex;
+ else
+ event_type_index = winver_equal_or_newer( 6, 1 ) ? i + 2 : i + 1;
+ }
+
+ type = (OBJECT_TYPE_INFORMATION *)ROUND_UP( (DWORD_PTR)(type + 1) + length, sizeof(DWORD_PTR) );
+ }
+
+ HeapFree( GetProcessHeap(), 0, buffer );
+
+ ok( event_type_index, "Could not find object type for events\n" );
+
+ handle = CreateEventA( NULL, FALSE, FALSE, NULL );
+ ok( handle != NULL, "Failed to create event\n" );
+
+ shi = HeapAlloc( GetProcessHeap(), 0, sizeof(*shi) );
+ ok( shi != NULL, "Failed to allocate memory\n" );
+
+ status = pNtQuerySystemInformation( SystemExtendedHandleInformation, shi, sizeof(*shi), &len );
+ ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status );
+
+ shi = HeapReAlloc( GetProcessHeap(), 0, shi, len );
+ ok( shi != NULL, "Failed to allocate memory\n" );
+
+ status = pNtQuerySystemInformation( SystemExtendedHandleInformation, shi, len, &len );
+ ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status );
+
+ found = FALSE;
+ for (i = 0; i < shi->Count; i++)
+ {
+ if (shi->Handle[i].UniqueProcessId != GetCurrentProcessId())
+ continue;
+ if ((HANDLE)(ULONG_PTR)shi->Handle[i].HandleValue != handle)
+ continue;
+
+ ok( shi->Handle[i].ObjectTypeIndex == event_type_index, "Event type does not match: %u vs %u\n",
+ shi->Handle[i].ObjectTypeIndex, event_type_index );
+
+ found = TRUE;
+ break;
+ }
+ ok( found, "Expected to find event handle %p (pid %x) in handle list\n", handle, GetCurrentProcessId() );
+
+ HeapFree( GetProcessHeap(), 0, shi );
+ CloseHandle( handle );
}
static void test_type_mismatch(void)
CloseHandle(ov.hEvent);
}
+static DWORD WINAPI mutant_thread( void *arg )
+{
+ MUTANT_BASIC_INFORMATION info;
+ NTSTATUS status;
+ HANDLE mutant;
+ DWORD ret;
+
+ mutant = arg;
+ ret = WaitForSingleObject( mutant, 1000 );
+ ok( ret == WAIT_OBJECT_0, "WaitForSingleObject failed %08x\n", ret );
+
+ memset(&info, 0xcc, sizeof(info));
+ status = pNtQueryMutant(mutant, MutantBasicInformation, &info, sizeof(info), NULL);
+ ok( status == STATUS_SUCCESS, "NtQueryMutant failed %08x\n", status );
+ ok( info.CurrentCount == 0, "expected 0, got %d\n", info.CurrentCount );
+ ok( info.OwnedByCaller == TRUE, "expected TRUE, got %d\n", info.OwnedByCaller );
+ ok( info.AbandonedState == FALSE, "expected FALSE, got %d\n", info.AbandonedState );
+ /* abandon mutant */
+
+ return 0;
+}
+
+static void test_mutant(void)
+{
+ static const WCHAR name[] = {'\\','B','a','s','e','N','a','m','e','d','O','b','j','e','c','t','s',
+ '\\','t','e','s','t','_','m','u','t','a','n','t',0};
+ MUTANT_BASIC_INFORMATION info;
+ OBJECT_ATTRIBUTES attr;
+ UNICODE_STRING str;
+ NTSTATUS status;
+ HANDLE mutant;
+ HANDLE thread;
+ DWORD ret;
+ ULONG len;
+ LONG prev;
+
+ pRtlInitUnicodeString(&str, name);
+ InitializeObjectAttributes(&attr, &str, 0, 0, NULL);
+ status = pNtCreateMutant(&mutant, GENERIC_ALL, &attr, TRUE);
+ ok( status == STATUS_SUCCESS, "Failed to create Mutant(%08x)\n", status );
+
+ /* bogus */
+ status = pNtQueryMutant(mutant, MutantBasicInformation, &info, 0, NULL);
+ ok( status == STATUS_INFO_LENGTH_MISMATCH,
+ "Failed to NtQueryMutant, expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status );
+ status = pNtQueryMutant(mutant, 0x42, &info, sizeof(info), NULL);
+ ok( status == STATUS_INVALID_INFO_CLASS || broken(status == STATUS_NOT_IMPLEMENTED), /* 32-bit on Vista/2k8 */
+ "Failed to NtQueryMutant, expected STATUS_INVALID_INFO_CLASS, got %08x\n", status );
+ status = pNtQueryMutant((HANDLE)0xdeadbeef, MutantBasicInformation, &info, sizeof(info), NULL);
+ ok( status == STATUS_INVALID_HANDLE,
+ "Failed to NtQueryMutant, expected STATUS_INVALID_HANDLE, got %08x\n", status );
+
+ /* new */
+ len = -1;
+ memset(&info, 0xcc, sizeof(info));
+ status = pNtQueryMutant(mutant, MutantBasicInformation, &info, sizeof(info), &len);
+ ok( status == STATUS_SUCCESS, "NtQueryMutant failed %08x\n", status );
+ ok( info.CurrentCount == 0, "expected 0, got %d\n", info.CurrentCount );
+ ok( info.OwnedByCaller == TRUE, "expected TRUE, got %d\n", info.OwnedByCaller );
+ ok( info.AbandonedState == FALSE, "expected FALSE, got %d\n", info.AbandonedState );
+ ok( len == sizeof(info), "got %u\n", len );
+
+ ret = WaitForSingleObject( mutant, 1000 );
+ ok( ret == WAIT_OBJECT_0, "WaitForSingleObject failed %08x\n", ret );
+
+ memset(&info, 0xcc, sizeof(info));
+ status = pNtQueryMutant(mutant, MutantBasicInformation, &info, sizeof(info), NULL);
+ ok( status == STATUS_SUCCESS, "NtQueryMutant failed %08x\n", status );
+ ok( info.CurrentCount == -1, "expected -1, got %d\n", info.CurrentCount );
+ ok( info.OwnedByCaller == TRUE, "expected TRUE, got %d\n", info.OwnedByCaller );
+ ok( info.AbandonedState == FALSE, "expected FALSE, got %d\n", info.AbandonedState );
+
+ prev = 0xdeadbeef;
+ status = pNtReleaseMutant(mutant, &prev);
+ ok( status == STATUS_SUCCESS, "NtQueryRelease failed %08x\n", status );
+ ok( prev == -1, "NtQueryRelease failed, expected -1, got %d\n", prev );
+
+ prev = 0xdeadbeef;
+ status = pNtReleaseMutant(mutant, &prev);
+ ok( status == STATUS_SUCCESS, "NtQueryRelease failed %08x\n", status );
+ ok( prev == 0, "NtQueryRelease failed, expected 0, got %d\n", prev );
+
+ memset(&info, 0xcc, sizeof(info));
+ status = pNtQueryMutant(mutant, MutantBasicInformation, &info, sizeof(info), NULL);
+ ok( status == STATUS_SUCCESS, "NtQueryMutant failed %08x\n", status );
+ ok( info.CurrentCount == 1, "expected 1, got %d\n", info.CurrentCount );
+ ok( info.OwnedByCaller == FALSE, "expected FALSE, got %d\n", info.OwnedByCaller );
+ ok( info.AbandonedState == FALSE, "expected FALSE, got %d\n", info.AbandonedState );
+
+ /* abandoned */
+ thread = CreateThread( NULL, 0, mutant_thread, mutant, 0, NULL );
+ ret = WaitForSingleObject( thread, 1000 );
+ ok( ret == WAIT_OBJECT_0, "WaitForSingleObject failed %08x\n", ret );
+ CloseHandle( thread );
+
+ memset(&info, 0xcc, sizeof(info));
+ status = pNtQueryMutant(mutant, MutantBasicInformation, &info, sizeof(info), NULL);
+ ok( status == STATUS_SUCCESS, "NtQueryMutant failed %08x\n", status );
+ ok( info.CurrentCount == 1, "expected 0, got %d\n", info.CurrentCount );
+ ok( info.OwnedByCaller == FALSE, "expected FALSE, got %d\n", info.OwnedByCaller );
+ ok( info.AbandonedState == TRUE, "expected TRUE, got %d\n", info.AbandonedState );
+
+ ret = WaitForSingleObject( mutant, 1000 );
+ ok( ret == WAIT_ABANDONED_0, "WaitForSingleObject failed %08x\n", ret );
+
+ memset(&info, 0xcc, sizeof(info));
+ status = pNtQueryMutant(mutant, MutantBasicInformation, &info, sizeof(info), NULL);
+ ok( status == STATUS_SUCCESS, "NtQueryMutant failed %08x\n", status );
+ ok( info.CurrentCount == 0, "expected 0, got %d\n", info.CurrentCount );
+ ok( info.OwnedByCaller == TRUE, "expected TRUE, got %d\n", info.OwnedByCaller );
+ ok( info.AbandonedState == FALSE, "expected FALSE, got %d\n", info.AbandonedState );
+
+ NtClose( mutant );
+}
+
START_TEST(om)
{
HMODULE hntdll = GetModuleHandleA("ntdll.dll");
pRtlCreateUnicodeStringFromAsciiz = (void *)GetProcAddress(hntdll, "RtlCreateUnicodeStringFromAsciiz");
pRtlFreeUnicodeString = (void *)GetProcAddress(hntdll, "RtlFreeUnicodeString");
pNtCreateEvent = (void *)GetProcAddress(hntdll, "NtCreateEvent");
+ pNtCreateJobObject = (void *)GetProcAddress(hntdll, "NtCreateJobObject");
+ pNtOpenJobObject = (void *)GetProcAddress(hntdll, "NtOpenJobObject");
+ pNtCreateKey = (void *)GetProcAddress(hntdll, "NtCreateKey");
+ pNtOpenKey = (void *)GetProcAddress(hntdll, "NtOpenKey");
+ pNtDeleteKey = (void *)GetProcAddress(hntdll, "NtDeleteKey");
+ pNtCreateMailslotFile = (void *)GetProcAddress(hntdll, "NtCreateMailslotFile");
pNtCreateMutant = (void *)GetProcAddress(hntdll, "NtCreateMutant");
pNtOpenEvent = (void *)GetProcAddress(hntdll, "NtOpenEvent");
pNtQueryEvent = (void *)GetProcAddress(hntdll, "NtQueryEvent");
pNtPulseEvent = (void *)GetProcAddress(hntdll, "NtPulseEvent");
pNtOpenMutant = (void *)GetProcAddress(hntdll, "NtOpenMutant");
+ pNtQueryMutant = (void *)GetProcAddress(hntdll, "NtQueryMutant");
+ pNtReleaseMutant = (void *)GetProcAddress(hntdll, "NtReleaseMutant");
pNtOpenFile = (void *)GetProcAddress(hntdll, "NtOpenFile");
pNtClose = (void *)GetProcAddress(hntdll, "NtClose");
pRtlInitUnicodeString = (void *)GetProcAddress(hntdll, "RtlInitUnicodeString");
pNtCreateSymbolicLinkObject = (void *)GetProcAddress(hntdll, "NtCreateSymbolicLinkObject");
pNtQuerySymbolicLinkObject = (void *)GetProcAddress(hntdll, "NtQuerySymbolicLinkObject");
pNtCreateSemaphore = (void *)GetProcAddress(hntdll, "NtCreateSemaphore");
+ pNtOpenSemaphore = (void *)GetProcAddress(hntdll, "NtOpenSemaphore");
pNtCreateTimer = (void *)GetProcAddress(hntdll, "NtCreateTimer");
+ pNtOpenTimer = (void *)GetProcAddress(hntdll, "NtOpenTimer");
pNtCreateSection = (void *)GetProcAddress(hntdll, "NtCreateSection");
+ pNtOpenSection = (void *)GetProcAddress(hntdll, "NtOpenSection");
pNtQueryObject = (void *)GetProcAddress(hntdll, "NtQueryObject");
pNtReleaseSemaphore = (void *)GetProcAddress(hntdll, "NtReleaseSemaphore");
pNtCreateKeyedEvent = (void *)GetProcAddress(hntdll, "NtCreateKeyedEvent");
pNtWaitForKeyedEvent = (void *)GetProcAddress(hntdll, "NtWaitForKeyedEvent");
pNtReleaseKeyedEvent = (void *)GetProcAddress(hntdll, "NtReleaseKeyedEvent");
pNtCreateIoCompletion = (void *)GetProcAddress(hntdll, "NtCreateIoCompletion");
+ pNtOpenIoCompletion = (void *)GetProcAddress(hntdll, "NtOpenIoCompletion");
+ pNtQuerySystemInformation = (void *)GetProcAddress(hntdll, "NtQuerySystemInformation");
test_case_sensitive();
test_namespace_pipe();
test_name_collisions();
+ test_name_limits();
test_directory();
test_symboliclink();
test_query_object();
+ test_query_object_types();
test_type_mismatch();
test_event();
+ test_mutant();
test_keyed_events();
test_null_device();
}
{ "c:/test/ .... .. ", "c:\\test\\", NULL},
{ "c:/test/..", "c:\\", NULL},
{ "c:/test/.. ", "c:\\test\\", NULL},
- { "c:/TEST", "c:\\test", "test"},
+ { "c:/TEST", "c:\\TEST", "TEST"},
{ "c:/test/file", "c:\\test\\file", "file"},
{ "c:/test./file", "c:\\test\\file", "file"},
{ "c:/test.. /file", "c:\\test.. \\file","file"},
{ "c:///test\\..\\file\\..\\//", "c:\\", NULL},
{ "c:/test../file", "c:\\test.\\file", "file",
"c:\\test..\\file", "file"}, /* vista */
+ { "c:\\test", "c:\\test", "test"},
{ NULL, NULL, NULL}
};
"Wrong result %d/%d for \"%s\"\n", ret, len, test->path );
ok(pRtlUnicodeToMultiByteN(rbufferA,MAX_PATH,&reslen,rbufferW,(lstrlenW(rbufferW) + 1) * sizeof(WCHAR)) == STATUS_SUCCESS,
"RtlUnicodeToMultiByteN failed\n");
- ok(!lstrcmpiA(rbufferA,test->rname) || (test->alt_rname && !lstrcmpiA(rbufferA,test->alt_rname)),
+ ok(!lstrcmpA(rbufferA,test->rname) || (test->alt_rname && !lstrcmpA(rbufferA,test->alt_rname)),
"Got \"%s\" expected \"%s\"\n",rbufferA,test->rname);
if (file_part)
{
ok(pRtlUnicodeToMultiByteN(rfileA,MAX_PATH,&reslen,file_part,(lstrlenW(file_part) + 1) * sizeof(WCHAR)) == STATUS_SUCCESS,
"RtlUnicodeToMultiByteN failed\n");
- ok((test->rfile && !lstrcmpiA(rfileA,test->rfile)) ||
- (test->alt_rfile && !lstrcmpiA(rfileA,test->alt_rfile)),
+ ok((test->rfile && !lstrcmpA(rfileA,test->rfile)) ||
+ (test->alt_rfile && !lstrcmpA(rfileA,test->alt_rfile)),
"Got \"%s\" expected \"%s\"\n",rfileA,test->rfile);
}
else
static NTSTATUS (WINAPI *pNtQueryInformationFile) (IN HANDLE FileHandle, OUT PIO_STATUS_BLOCK IoStatusBlock, OUT PVOID FileInformation, IN ULONG Length, IN FILE_INFORMATION_CLASS FileInformationClass);
static NTSTATUS (WINAPI *pNtSetInformationFile) (HANDLE handle, PIO_STATUS_BLOCK io, PVOID ptr, ULONG len, FILE_INFORMATION_CLASS class);
static NTSTATUS (WINAPI *pNtCancelIoFile) (HANDLE hFile, PIO_STATUS_BLOCK io_status);
+static NTSTATUS (WINAPI *pNtCancelIoFileEx) (HANDLE hFile, IO_STATUS_BLOCK *iosb, IO_STATUS_BLOCK *io_status);
static void (WINAPI *pRtlInitUnicodeString) (PUNICODE_STRING target, PCWSTR source);
static HANDLE (WINAPI *pOpenThread)(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId);
loadfunc(NtQueryInformationFile)
loadfunc(NtSetInformationFile)
loadfunc(NtCancelIoFile)
+ loadfunc(NtCancelIoFileEx)
loadfunc(RtlInitUnicodeString)
/* not fatal */
return TRUE;
}
+static inline BOOL is_signaled( HANDLE obj )
+{
+ return WaitForSingleObject( obj, 0 ) == WAIT_OBJECT_0;
+}
+
static const WCHAR testpipe[] = { '\\', '\\', '.', '\\', 'p', 'i', 'p', 'e', '\\',
't', 'e', 's', 't', 'p', 'i', 'p', 'e', 0 };
static const WCHAR testpipe_nt[] = { '\\', '?', '?', '\\', 'p', 'i', 'p', 'e', '\\',
return res;
}
+static BOOL ioapc_called;
+static void CALLBACK ioapc(void *arg, PIO_STATUS_BLOCK io, ULONG reserved)
+{
+ ioapc_called = TRUE;
+}
+
+static NTSTATUS listen_pipe(HANDLE hPipe, HANDLE hEvent, PIO_STATUS_BLOCK iosb, BOOL use_apc)
+{
+ int dummy;
+
+ ioapc_called = FALSE;
+
+ return pNtFsControlFile(hPipe, hEvent, use_apc ? &ioapc: NULL, use_apc ? &dummy: NULL, iosb, FSCTL_PIPE_LISTEN, 0, 0, 0, 0);
+}
+
static void test_create_invalid(void)
{
IO_STATUS_BLOCK iosb;
int j, k;
FILE_PIPE_LOCAL_INFORMATION info;
IO_STATUS_BLOCK iosb;
+ HANDLE hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
static const DWORD access[] = { 0, GENERIC_READ, GENERIC_WRITE, GENERIC_READ | GENERIC_WRITE};
static const DWORD sharing[] = { FILE_SHARE_READ, FILE_SHARE_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE };
HANDLE hclient;
BOOL should_succeed = TRUE;
- res = create_pipe(&hserver, sharing[j], FILE_SYNCHRONOUS_IO_NONALERT);
+ res = create_pipe(&hserver, sharing[j], 0);
if (res) {
ok(0, "NtCreateNamedPipeFile returned %x, sharing: %x\n", res, sharing[j]);
continue;
}
+ res = listen_pipe(hserver, hEvent, &iosb, FALSE);
+ ok(res == STATUS_PENDING, "NtFsControlFile returned %x\n", res);
+
res = pNtQueryInformationFile(hserver, &iosb, &info, sizeof(info), (FILE_INFORMATION_CLASS)24);
ok(!res, "NtQueryInformationFile for server returned %x, sharing: %x\n", res, sharing[j]);
ok(info.NamedPipeConfiguration == pipe_config[j], "wrong duplex status for pipe: %d, expected %d\n",
CloseHandle(hserver);
}
}
-}
-
-static BOOL ioapc_called;
-static void CALLBACK ioapc(void *arg, PIO_STATUS_BLOCK io, ULONG reserved)
-{
- ioapc_called = TRUE;
-}
-
-static NTSTATUS listen_pipe(HANDLE hPipe, HANDLE hEvent, PIO_STATUS_BLOCK iosb, BOOL use_apc)
-{
- int dummy;
-
- ioapc_called = FALSE;
-
- return pNtFsControlFile(hPipe, hEvent, use_apc ? &ioapc: NULL, use_apc ? &dummy: NULL, iosb, FSCTL_PIPE_LISTEN, 0, 0, 0, 0);
+ CloseHandle(hEvent);
}
static void test_overlapped(void)
if (hClient != INVALID_HANDLE_VALUE)
{
+ SetEvent(hEvent);
memset(&iosb, 0x55, sizeof(iosb));
res = listen_pipe(hPipe, hEvent, &iosb, TRUE);
ok(res == STATUS_PIPE_CONNECTED, "NtFsControlFile returned %x\n", res);
ok(U(iosb).Status == 0x55555555, "iosb.Status got changed to %x\n", U(iosb).Status);
+ ok(!is_signaled(hEvent), "hEvent not signaled\n");
CloseHandle(hClient);
}
CloseHandle(hEvent);
}
+static void test_completion(void)
+{
+ static const char buf[] = "testdata";
+ FILE_IO_COMPLETION_NOTIFICATION_INFORMATION info;
+ HANDLE port, pipe, client;
+ IO_STATUS_BLOCK iosb;
+ OVERLAPPED ov, *pov;
+ IO_STATUS_BLOCK io;
+ NTSTATUS status;
+ DWORD num_bytes;
+ ULONG_PTR key;
+ DWORD dwret;
+ BOOL ret;
+
+ memset(&ov, 0, sizeof(ov));
+ ov.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
+ ok(ov.hEvent != INVALID_HANDLE_VALUE, "CreateEvent failed, error %u\n", GetLastError());
+
+ status = create_pipe(&pipe, FILE_SHARE_READ | FILE_SHARE_WRITE, 0 /* OVERLAPPED */);
+ ok(!status, "NtCreateNamedPipeFile returned %x\n", status);
+ status = listen_pipe(pipe, ov.hEvent, &iosb, FALSE);
+ ok(status == STATUS_PENDING, "NtFsControlFile returned %x\n", status);
+
+ client = CreateFileW(testpipe, GENERIC_READ | GENERIC_WRITE, 0, 0,
+ OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
+ ok(client != INVALID_HANDLE_VALUE, "CreateFile failed, error %u\n", GetLastError());
+ dwret = WaitForSingleObject(ov.hEvent, 0);
+ ok(dwret == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", dwret);
+
+ port = CreateIoCompletionPort(client, NULL, 0xdeadbeef, 0);
+ ok(port != NULL, "CreateIoCompletionPort failed, error %u\n", GetLastError());
+
+ ret = WriteFile(client, buf, sizeof(buf), &num_bytes, &ov);
+ ok(ret, "WriteFile failed, error %u\n", GetLastError());
+ 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);
+
+ info.Flags = FILE_SKIP_COMPLETION_PORT_ON_SUCCESS;
+ status = pNtSetInformationFile(client, &io, &info, sizeof(info), FileIoCompletionNotificationInformation);
+ ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status);
+
+ info.Flags = 0;
+ status = pNtQueryInformationFile(client, &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);
+
+ ret = WriteFile(client, buf, sizeof(buf), &num_bytes, &ov);
+ ok(ret, "WriteFile failed, error %u\n", GetLastError());
+ 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);
+
+ CloseHandle(ov.hEvent);
+ CloseHandle(client);
+ CloseHandle(pipe);
+ CloseHandle(port);
+}
+
static BOOL userapc_called;
static void CALLBACK userapc(ULONG_PTR dwParam)
{
ok(ioapc_called, "IOAPC didn't run\n");
+ CloseHandle(hPipe);
+
+ res = create_pipe(&hPipe, FILE_SHARE_READ | FILE_SHARE_WRITE, 0 /* OVERLAPPED */);
+ ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
+
+ memset(&iosb, 0x55, sizeof(iosb));
+ res = listen_pipe(hPipe, hEvent, &iosb, FALSE);
+ ok(res == STATUS_PENDING, "NtFsControlFile returned %x\n", res);
+
+ res = pNtCancelIoFileEx(hPipe, &iosb, &cancel_sb);
+ ok(!res, "NtCancelIoFileEx returned %x\n", res);
+
+ ok(U(iosb).Status == STATUS_CANCELLED, "Wrong iostatus %x\n", U(iosb).Status);
+ ok(WaitForSingleObject(hEvent, 0) == 0, "hEvent not signaled\n");
+
CloseHandle(hEvent);
CloseHandle(hPipe);
}
CloseHandle(hServer);
}
+static void WINAPI apc( void *arg, IO_STATUS_BLOCK *iosb, ULONG reserved )
+{
+ int *count = arg;
+ (*count)++;
+ ok( !reserved, "reserved is not 0: %x\n", reserved );
+}
+
+static void test_peek(HANDLE pipe, BOOL is_msgmode)
+{
+ FILE_PIPE_PEEK_BUFFER buf;
+ IO_STATUS_BLOCK iosb;
+ HANDLE event = CreateEventA( NULL, TRUE, FALSE, NULL );
+ NTSTATUS status;
+
+ memset(&iosb, 0x55, sizeof(iosb));
+ status = NtFsControlFile(pipe, NULL, NULL, NULL, &iosb, FSCTL_PIPE_PEEK, NULL, 0, &buf, sizeof(buf));
+ ok(!status || status == STATUS_PENDING, "NtFsControlFile failed: %x\n", status);
+ ok(!iosb.Status, "iosb.Status = %x\n", iosb.Status);
+ ok(buf.ReadDataAvailable == 1, "ReadDataAvailable = %u\n", buf.ReadDataAvailable);
+
+ ResetEvent(event);
+ memset(&iosb, 0x55, sizeof(iosb));
+ status = NtFsControlFile(pipe, event, NULL, NULL, &iosb, FSCTL_PIPE_PEEK, NULL, 0, &buf, sizeof(buf));
+ ok(!status || status == STATUS_PENDING, "NtFsControlFile failed: %x\n", status);
+ ok(buf.ReadDataAvailable == 1, "ReadDataAvailable = %u\n", buf.ReadDataAvailable);
+ ok(!iosb.Status, "iosb.Status = %x\n", iosb.Status);
+ todo_wine_if(!is_msgmode)
+ ok(is_signaled(event), "event is not signaled\n");
+
+ CloseHandle(event);
+}
+
+#define PIPENAME "\\\\.\\pipe\\ntdll_tests_pipe.c"
+
+static BOOL create_pipe_pair( HANDLE *read, HANDLE *write, ULONG flags, ULONG type, ULONG size )
+{
+ const BOOL server_reader = flags & PIPE_ACCESS_INBOUND;
+ HANDLE client, server;
+
+ server = CreateNamedPipeA(PIPENAME, flags, PIPE_WAIT | type,
+ 1, size, size, NMPWAIT_USE_DEFAULT_WAIT, NULL);
+ ok(server != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
+
+ client = CreateFileA(PIPENAME, server_reader ? GENERIC_WRITE : GENERIC_READ | FILE_WRITE_ATTRIBUTES, 0,
+ NULL, OPEN_EXISTING, flags & FILE_FLAG_OVERLAPPED, 0);
+ ok(client != INVALID_HANDLE_VALUE, "CreateFile failed (%d)\n", GetLastError());
+
+ if(server_reader)
+ {
+ *read = server;
+ *write = client;
+ }
+ else
+ {
+ if(type & PIPE_READMODE_MESSAGE)
+ {
+ DWORD read_mode = PIPE_READMODE_MESSAGE;
+ ok(SetNamedPipeHandleState(client, &read_mode, NULL, NULL), "Change mode\n");
+ }
+
+ *read = client;
+ *write = server;
+ }
+ return TRUE;
+}
+
+static void read_pipe_test(ULONG pipe_flags, ULONG pipe_type)
+{
+ IO_STATUS_BLOCK iosb, iosb2;
+ HANDLE handle, read, write;
+ HANDLE event = CreateEventA( NULL, TRUE, FALSE, NULL );
+ int apc_count = 0;
+ char buffer[128];
+ DWORD written;
+ BOOL ret;
+ NTSTATUS status;
+
+ if (!create_pipe_pair( &read, &write, FILE_FLAG_OVERLAPPED | pipe_flags, pipe_type, 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 = NtReadFile( 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 = NtReadFile( 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());
+
+ test_peek(read, pipe_type & PIPE_TYPE_MESSAGE);
+
+ status = NtReadFile( 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" );
+
+ /* now partial read with data ready */
+ apc_count = 0;
+ U(iosb).Status = 0xdeadbabe;
+ iosb.Information = 0xdeadbeef;
+ ResetEvent( event );
+ ret = WriteFile( write, buffer, 2, &written, NULL );
+ ok(ret && written == 2, "WriteFile error %d\n", GetLastError());
+ status = NtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL );
+ if (pipe_type & PIPE_READMODE_MESSAGE)
+ {
+ ok( status == STATUS_BUFFER_OVERFLOW, "wrong status %x\n", status );
+ ok( U(iosb).Status == STATUS_BUFFER_OVERFLOW, "wrong status %x\n", U(iosb).Status );
+ }
+ else
+ {
+ 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" );
+ apc_count = 0;
+ status = NtReadFile( 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 = NtReadFile( 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 = NtReadFile( 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 disconnected pipe, with invalid event handle */
+ apc_count = 0;
+ U(iosb).Status = 0xdeadbabe;
+ iosb.Information = 0xdeadbeef;
+ status = NtReadFile( read, (HANDLE)0xdeadbeef, 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( !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 = NtReadFile( 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_pair( &read, &write, FILE_FLAG_OVERLAPPED | pipe_flags, pipe_type, 4096 )) return;
+ apc_count = 0;
+ U(iosb).Status = 0xdeadbabe;
+ iosb.Information = 0xdeadbeef;
+ status = NtReadFile( 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 */
+ todo_wine_if(!(pipe_type & PIPE_TYPE_MESSAGE) && (pipe_flags & PIPE_ACCESS_OUTBOUND))
+ 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_pair( &read, &write, FILE_FLAG_OVERLAPPED | pipe_flags, pipe_type, 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 = NtReadFile( 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 = NtReadFile( 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_pair( &read, &write, FILE_FLAG_OVERLAPPED | pipe_flags, pipe_type, 4096 )) return;
+
+ apc_count = 0;
+ U(iosb).Status = 0xdeadbabe;
+ iosb.Information = 0xdeadbeef;
+ status = NtReadFile( 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 = NtReadFile( 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 = NtReadFile( 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 );
+ }
+
+ CloseHandle(event);
+}
+
START_TEST(pipe)
{
if (!init_func_ptrs())
trace("starting overlapped tests\n");
test_overlapped();
+ trace("starting completion tests\n");
+ test_completion();
+
trace("starting FILE_PIPE_INFORMATION tests\n");
test_filepipeinfo();
trace("starting cancelio tests\n");
test_cancelio();
+
+ trace("starting byte read in byte mode client -> server\n");
+ read_pipe_test(PIPE_ACCESS_INBOUND, PIPE_TYPE_BYTE);
+ trace("starting byte read in message mode client -> server\n");
+ read_pipe_test(PIPE_ACCESS_INBOUND, PIPE_TYPE_MESSAGE);
+ trace("starting message read in message mode client -> server\n");
+ read_pipe_test(PIPE_ACCESS_INBOUND, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE);
+ trace("starting byte read in byte mode server -> client\n");
+ read_pipe_test(PIPE_ACCESS_OUTBOUND, PIPE_TYPE_BYTE);
+ trace("starting byte read in message mode server -> client\n");
+ read_pipe_test(PIPE_ACCESS_OUTBOUND, PIPE_TYPE_MESSAGE);
+ trace("starting message read in message mode server -> client\n");
+ read_pipe_test(PIPE_ACCESS_OUTBOUND, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE);
}
--- /dev/null
+/*
+ * Unit test suite for process functions
+ *
+ * Copyright 2017 Michael Müller
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdio.h>
+
+#include "ntdll_test.h"
+
+#include "windef.h"
+#include "winbase.h"
+
+static NTSTATUS (WINAPI *pNtResumeProcess)(HANDLE);
+static NTSTATUS (WINAPI *pNtSuspendProcess)(HANDLE);
+static NTSTATUS (WINAPI *pNtSuspendThread)(HANDLE,PULONG);
+static NTSTATUS (WINAPI *pNtResumeThread)(HANDLE);
+
+static void test_NtSuspendProcess(char *process_name)
+{
+ PROCESS_INFORMATION info;
+ DEBUG_EVENT ev;
+ STARTUPINFOA startup;
+ NTSTATUS status;
+ HANDLE event;
+ char buffer[MAX_PATH];
+ ULONG count;
+ DWORD ret;
+
+ status = pNtResumeProcess(GetCurrentProcess());
+ ok(status == STATUS_SUCCESS, "NtResumeProcess failed: %x\n", status);
+
+ event = CreateEventA(NULL, TRUE, FALSE, "wine_suspend_event");
+ ok(!!event, "Failed to create event: %u\n", GetLastError());
+
+ memset(&startup, 0, sizeof(startup));
+ startup.cb = sizeof(startup);
+
+ sprintf(buffer, "%s tests/process.c dummy_process wine_suspend_event", process_name);
+ ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info);
+ ok(ret, "CreateProcess failed with error %u\n", GetLastError());
+
+ ret = WaitForSingleObject(event, 500);
+ ok(ret == WAIT_OBJECT_0, "Event was not signaled: %d\n", ret);
+
+ status = pNtSuspendProcess(info.hProcess);
+ ok(status == STATUS_SUCCESS, "NtResumeProcess failed: %x\n", status);
+
+ ResetEvent(event);
+
+ ret = WaitForSingleObject(event, 200);
+ ok(ret == WAIT_TIMEOUT, "Expected timeout, got: %d\n", ret);
+
+ status = NtResumeThread(info.hThread, &count);
+ ok(status == STATUS_SUCCESS, "NtResumeProcess failed: %x\n", status);
+ ok(count == 1, "Expected count 1, got %d\n", count);
+
+ ret = WaitForSingleObject(event, 200);
+ ok(ret == WAIT_OBJECT_0, "Event was not signaled: %d\n", ret);
+
+ status = pNtResumeProcess(info.hProcess);
+ ok(status == STATUS_SUCCESS, "NtResumeProcess failed: %x\n", status);
+
+ status = pNtSuspendThread(info.hThread, &count);
+ ok(status == STATUS_SUCCESS, "NtSuspendThread failed: %x\n", status);
+ ok(count == 0, "Expected count 0, got %d\n", count);
+
+ ResetEvent(event);
+
+ ret = WaitForSingleObject(event, 200);
+ ok(ret == WAIT_TIMEOUT, "Expected timeout, got: %d\n", ret);
+
+ status = pNtResumeProcess(info.hProcess);
+ ok(status == STATUS_SUCCESS, "NtResumeProcess failed: %x\n", status);
+
+ ret = WaitForSingleObject(event, 200);
+ ok(ret == WAIT_OBJECT_0, "Event was not signaled: %d\n", ret);
+
+ status = pNtSuspendThread(info.hThread, &count);
+ ok(status == STATUS_SUCCESS, "NtSuspendThread failed: %x\n", status);
+ ok(count == 0, "Expected count 0, got %d\n", count);
+
+ status = pNtSuspendThread(info.hThread, &count);
+ ok(status == STATUS_SUCCESS, "NtSuspendThread failed: %x\n", status);
+ ok(count == 1, "Expected count 1, got %d\n", count);
+
+ ResetEvent(event);
+
+ ret = WaitForSingleObject(event, 200);
+ ok(ret == WAIT_TIMEOUT, "Expected timeout, got: %d\n", ret);
+
+ status = pNtResumeProcess(info.hProcess);
+ ok(status == STATUS_SUCCESS, "NtResumeProcess failed: %x\n", status);
+
+ ret = WaitForSingleObject(event, 200);
+ ok(ret == WAIT_TIMEOUT, "Expected timeout, got: %d\n", ret);
+
+ status = pNtResumeProcess(info.hProcess);
+ ok(status == STATUS_SUCCESS, "NtResumeProcess failed: %x\n", status);
+
+ ret = WaitForSingleObject(event, 200);
+ ok(ret == WAIT_OBJECT_0, "Event was not signaled: %d\n", ret);
+
+ ret = DebugActiveProcess(info.dwProcessId);
+ ok(ret, "Failed to debug process: %d\n", GetLastError());
+
+ ResetEvent(event);
+
+ ret = WaitForSingleObject(event, 200);
+ ok(ret == WAIT_TIMEOUT, "Expected timeout, got: %d\n", ret);
+
+ for (;;)
+ {
+ ret = WaitForDebugEvent(&ev, INFINITE);
+ ok(ret, "WaitForDebugEvent failed, last error %#x.\n", GetLastError());
+ if (!ret) break;
+
+ if (ev.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT) break;
+
+ ret = ContinueDebugEvent(ev.dwProcessId, ev.dwThreadId, DBG_CONTINUE);
+ ok(ret, "ContinueDebugEvent failed, last error %#x.\n", GetLastError());
+ if (!ret) break;
+ }
+
+ ResetEvent(event);
+
+ ret = WaitForSingleObject(event, 200);
+ ok(ret == WAIT_TIMEOUT, "Expected timeout, got: %d\n", ret);
+
+ status = pNtResumeProcess(info.hProcess);
+ ok(status == STATUS_SUCCESS, "NtResumeProcess failed: %x\n", status);
+
+ ret = WaitForSingleObject(event, 200);
+ ok(ret == WAIT_TIMEOUT, "Expected timeout, got: %d\n", ret);
+
+ status = NtResumeThread(info.hThread, &count);
+ ok(status == STATUS_SUCCESS, "NtResumeProcess failed: %x\n", status);
+ ok(count == 0, "Expected count 0, got %d\n", count);
+
+ ret = WaitForSingleObject(event, 200);
+ ok(ret == WAIT_TIMEOUT, "Expected timeout, got: %d\n", ret);
+
+ ret = ContinueDebugEvent(ev.dwProcessId, ev.dwThreadId, DBG_CONTINUE);
+ ok(ret, "ContinueDebugEvent failed, last error %#x.\n", GetLastError());
+
+ ret = WaitForSingleObject(event, 200);
+ ok(ret == WAIT_OBJECT_0, "Event was not signaled: %d\n", ret);
+
+ TerminateProcess(info.hProcess, 0);
+
+ CloseHandle(info.hProcess);
+ CloseHandle(info.hThread);
+}
+
+static void dummy_process(char *event_name)
+{
+ HANDLE event = OpenEventA(EVENT_ALL_ACCESS, FALSE, event_name);
+
+ while (TRUE)
+ {
+ SetEvent(event);
+ OutputDebugStringA("test");
+ Sleep(5);
+ }
+}
+
+START_TEST(process)
+{
+ HMODULE mod;
+ char **argv;
+ int argc;
+
+ argc = winetest_get_mainargs(&argv);
+ if (argc >= 4 && strcmp(argv[2], "dummy_process") == 0)
+ {
+ dummy_process(argv[3]);
+ return;
+ }
+
+ mod = GetModuleHandleA("ntdll.dll");
+ if (!mod)
+ {
+ win_skip("Not running on NT, skipping tests\n");
+ return;
+ }
+
+ pNtResumeProcess = (void*)GetProcAddress(mod, "NtResumeProcess");
+ pNtSuspendProcess = (void*)GetProcAddress(mod, "NtSuspendProcess");
+ pNtResumeThread = (void*)GetProcAddress(mod, "NtResumeThread");
+ pNtSuspendThread = (void*)GetProcAddress(mod, "NtSuspendThread");
+
+ test_NtSuspendProcess(argv[0]);
+}
/* Zero accessmask */
attr.Length = sizeof(attr);
+ key = (HANDLE)0xdeadbeef;
status = pNtOpenKey(&key, 0, &attr);
todo_wine
ok(status == STATUS_ACCESS_DENIED, "Expected STATUS_ACCESS_DENIED, got: 0x%08x\n", status);
+todo_wine
+ ok(!key, "key = %p\n", key);
if (status == STATUS_SUCCESS) NtClose(key);
/* Calling without parent key requres full registry path. */
pRtlCreateUnicodeStringFromAsciiz( &str, "Machine" );
InitializeObjectAttributes(&attr, &str, 0, 0, 0);
+ key = (HANDLE)0xdeadbeef;
status = pNtOpenKey(&key, KEY_READ, &attr);
todo_wine ok(status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtOpenKey Failed: 0x%08x\n", status);
+todo_wine
+ ok(!key, "key = %p\n", key);
pRtlFreeUnicodeString( &str );
/* Open is case sensitive unless OBJ_CASE_INSENSITIVE is specified. */
/* try opening the target through the link */
attr.ObjectName = &link_str;
+ key = (HANDLE)0xdeadbeef;
status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey wrong status 0x%08x\n", status );
+ ok( !key, "key = %p\n", key );
attr.ObjectName = &target_str;
status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
"wrong len %u\n", len );
pNtClose( key );
+ if (pNtOpenKeyEx)
+ {
+ /* REG_OPTION_OPEN_LINK flag doesn't matter */
+ status = pNtOpenKeyEx( &key, KEY_ALL_ACCESS, &attr, REG_OPTION_OPEN_LINK );
+ ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
+
+ len = sizeof(buffer);
+ status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
+ ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
+ ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
+ "wrong len %u\n", len );
+ pNtClose( key );
+
+ status = pNtOpenKeyEx( &key, KEY_ALL_ACCESS, &attr, 0 );
+ ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
+
+ len = sizeof(buffer);
+ status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
+ ok( status == STATUS_SUCCESS, "NtQueryValueKey failed: 0x%08x\n", status );
+ ok( len == FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,Data) + target_len - sizeof(WCHAR),
+ "wrong len %u\n", len );
+ pNtClose( key );
+
+ attr.Attributes = 0;
+ status = pNtOpenKeyEx( &key, KEY_ALL_ACCESS, &attr, REG_OPTION_OPEN_LINK );
+ ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
+
+ len = sizeof(buffer);
+ status = pNtQueryValueKey( key, &symlink_str, KeyValuePartialInformation, info, len, &len );
+ ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtQueryValueKey failed: 0x%08x\n", status );
+ pNtClose( key );
+ }
+
+ attr.Attributes = OBJ_OPENLINK;
status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
len = sizeof(buffer);
"wrong len %u\n", len );
pNtClose( key );
+ /* delete target and create by NtCreateKey on link */
+ attr.ObjectName = &target_str;
+ status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
+ ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08x\n", status );
+ status = pNtDeleteKey( key );
+ ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
+ pNtClose( key );
+
+ attr.ObjectName = &link_str;
+ attr.Attributes = 0;
+ status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
+ ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey wrong status 0x%08x\n", status );
+
+ status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
+ todo_wine ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
+ pNtClose( key );
+ if (status) /* can be removed once todo_wine above is fixed */
+ {
+ attr.ObjectName = &target_str;
+ attr.Attributes = OBJ_OPENLINK;
+ status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
+ ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status );
+ pNtClose( key );
+ }
+
+ attr.ObjectName = &target_str;
+ attr.Attributes = OBJ_OPENLINK;
+ status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
+ ok( status == STATUS_SUCCESS, "NtOpenKey wrong status 0x%08x\n", status );
+
if (0) /* crashes the Windows kernel on some Vista systems */
{
/* reopen the link from itself */
ok( status == STATUS_SUCCESS || status == STATUS_OBJECT_NAME_NOT_FOUND,
"NtOpenKey wrong status 0x%08x\n", status );
- status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, 0 );
+ key = (HKEY)0xdeadbeef;
+ status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, REG_OPTION_CREATE_LINK, NULL );
ok( status == STATUS_OBJECT_NAME_COLLISION, "NtCreateKey failed: 0x%08x\n", status );
+ ok( !key, "key = %p\n", key );
status = pNtDeleteKey( link );
ok( status == STATUS_SUCCESS, "NtDeleteKey failed: 0x%08x\n", status );
static BOOLEAN (WINAPI * pRtlFreeHandle)(RTL_HANDLE_TABLE *, RTL_HANDLE *);
static NTSTATUS (WINAPI *pRtlAllocateAndInitializeSid)(PSID_IDENTIFIER_AUTHORITY,BYTE,DWORD,DWORD,DWORD,DWORD,DWORD,DWORD,DWORD,DWORD,PSID*);
static NTSTATUS (WINAPI *pRtlFreeSid)(PSID);
-static struct _TEB * (WINAPI *pNtCurrentTeb)(void);
static DWORD (WINAPI *pRtlGetThreadErrorMode)(void);
static NTSTATUS (WINAPI *pRtlSetThreadErrorMode)(DWORD, LPDWORD);
static IMAGE_BASE_RELOCATION *(WINAPI *pLdrProcessRelocationBlock)(void*,UINT,USHORT*,INT_PTR);
static BOOL (WINAPI *pRtlIsCriticalSectionLocked)(CRITICAL_SECTION *);
static BOOL (WINAPI *pRtlIsCriticalSectionLockedByThread)(CRITICAL_SECTION *);
static NTSTATUS (WINAPI *pRtlInitializeCriticalSectionEx)(CRITICAL_SECTION *, ULONG, ULONG);
+static NTSTATUS (WINAPI *pLdrEnumerateLoadedModules)(void *, void *, void *);
static NTSTATUS (WINAPI *pRtlQueryPackageIdentity)(HANDLE, WCHAR*, SIZE_T*, WCHAR*, SIZE_T*, BOOLEAN*);
+static NTSTATUS (WINAPI *pLdrRegisterDllNotification)(ULONG, PLDR_DLL_NOTIFICATION_FUNCTION, void *, void **);
+static NTSTATUS (WINAPI *pLdrUnregisterDllNotification)(void *);
static HMODULE hkernel32 = 0;
static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
#define LEN 16
static const char* src_src = "This is a test!"; /* 16 bytes long, incl NUL */
+static WCHAR ws2_32dllW[] = {'w','s','2','_','3','2','.','d','l','l',0};
+static WCHAR wintrustdllW[] = {'w','i','n','t','r','u','s','t','.','d','l','l',0};
+static WCHAR crypt32dllW[] = {'c','r','y','p','t','3','2','.','d','l','l',0};
static ULONG src_aligned_block[4];
static ULONG dest_aligned_block[32];
static const char *src = (const char*)src_aligned_block;
pRtlFreeHandle = (void *)GetProcAddress(hntdll, "RtlFreeHandle");
pRtlAllocateAndInitializeSid = (void *)GetProcAddress(hntdll, "RtlAllocateAndInitializeSid");
pRtlFreeSid = (void *)GetProcAddress(hntdll, "RtlFreeSid");
- pNtCurrentTeb = (void *)GetProcAddress(hntdll, "NtCurrentTeb");
pRtlGetThreadErrorMode = (void *)GetProcAddress(hntdll, "RtlGetThreadErrorMode");
pRtlSetThreadErrorMode = (void *)GetProcAddress(hntdll, "RtlSetThreadErrorMode");
pLdrProcessRelocationBlock = (void *)GetProcAddress(hntdll, "LdrProcessRelocationBlock");
pRtlIsCriticalSectionLocked = (void *)GetProcAddress(hntdll, "RtlIsCriticalSectionLocked");
pRtlIsCriticalSectionLockedByThread = (void *)GetProcAddress(hntdll, "RtlIsCriticalSectionLockedByThread");
pRtlInitializeCriticalSectionEx = (void *)GetProcAddress(hntdll, "RtlInitializeCriticalSectionEx");
+ pLdrEnumerateLoadedModules = (void *)GetProcAddress(hntdll, "LdrEnumerateLoadedModules");
pRtlQueryPackageIdentity = (void *)GetProcAddress(hntdll, "RtlQueryPackageIdentity");
+ pLdrRegisterDllNotification = (void *)GetProcAddress(hntdll, "LdrRegisterDllNotification");
+ pLdrUnregisterDllNotification = (void *)GetProcAddress(hntdll, "LdrUnregisterDllNotification");
}
hkernel32 = LoadLibraryA("kernel32.dll");
ok(hkernel32 != 0, "LoadLibrary failed\n");
result = pRtlUlonglongByteSwap( ((ULONGLONG)0x76543210 << 32) | 0x87654321 );
ok( (((ULONGLONG)0x21436587 << 32) | 0x10325476) == result,
- "RtlUlonglongByteSwap(0x7654321087654321) returns 0x%x%08x, expected 0x2143658710325476\n",
- (DWORD)(result >> 32), (DWORD)result);
+ "RtlUlonglongByteSwap(0x7654321087654321) returns 0x%s, expected 0x2143658710325476\n",
+ wine_dbgstr_longlong(result));
}
seed_bak = seed;
result = pRtlUniform(&seed);
ok(result == expected,
- "test: 0x%x%08x RtlUniform(&seed (seed == %x)) returns %x, expected %x\n",
- (DWORD)(num >> 32), (DWORD)num, seed_bak, result, expected);
+ "test: 0x%s RtlUniform(&seed (seed == %x)) returns %x, expected %x\n",
+ wine_dbgstr_longlong(num), seed_bak, result, expected);
ok(seed == expected,
- "test: 0x%x%08x RtlUniform(&seed (seed == %x)) sets seed to %x, expected %x\n",
- (DWORD)(num >> 32), (DWORD)num, seed_bak, result, expected);
+ "test: 0x%s RtlUniform(&seed (seed == %x)) sets seed to %x, expected %x\n",
+ wine_dbgstr_longlong(num), seed_bak, result, expected);
} /* for */
/*
* Further investigation shows: In the different regions the highest bit
seed_bak = seed;
result = pRtlUniform(&seed);
ok(result == expected,
- "test: 0x%x%08x RtlUniform(&seed (seed == %x)) returns %x, expected %x\n",
- (DWORD)(num >> 32), (DWORD)num, seed_bak, result, expected);
+ "test: 0x%s RtlUniform(&seed (seed == %x)) returns %x, expected %x\n",
+ wine_dbgstr_longlong(num), seed_bak, result, expected);
ok(seed == expected,
- "test: 0x%x%08x RtlUniform(&seed (seed == %x)) sets seed to %x, expected %x\n",
- (DWORD)(num >> 32), (DWORD)num, seed_bak, result, expected);
+ "test: 0x%s RtlUniform(&seed (seed == %x)) sets seed to %x, expected %x\n",
+ wine_dbgstr_longlong(num), seed_bak, result, expected);
} /* for */
/*
* More tests show that RtlUniform does not return 0x7ffffffd for seed values
mode, oldmode);
ok(pRtlGetThreadErrorMode() == 0x70,
"RtlGetThreadErrorMode returned 0x%x, expected 0x%x\n", mode, 0x70);
- if (!is_wow64 && pNtCurrentTeb)
- ok(pNtCurrentTeb()->HardErrorDisabled == 0x70,
+ if (!is_wow64)
+ {
+ ok(NtCurrentTeb()->HardErrorDisabled == 0x70,
"The TEB contains 0x%x, expected 0x%x\n",
- pNtCurrentTeb()->HardErrorDisabled, 0x70);
+ NtCurrentTeb()->HardErrorDisabled, 0x70);
+ }
status = pRtlSetThreadErrorMode(0, &mode);
ok(status == STATUS_SUCCESS ||
mode, 0x70);
ok(pRtlGetThreadErrorMode() == 0,
"RtlGetThreadErrorMode returned 0x%x, expected 0x%x\n", mode, 0);
- if (!is_wow64 && pNtCurrentTeb)
- ok(pNtCurrentTeb()->HardErrorDisabled == 0,
+ if (!is_wow64)
+ {
+ ok(NtCurrentTeb()->HardErrorDisabled == 0,
"The TEB contains 0x%x, expected 0x%x\n",
- pNtCurrentTeb()->HardErrorDisabled, 0);
+ NtCurrentTeb()->HardErrorDisabled, 0);
+ }
for (mode = 1; mode; mode <<= 1)
{
RtlDeleteCriticalSection((PRTL_CRITICAL_SECTION)&cs);
}
+static void test_RtlLeaveCriticalSection(void)
+{
+ RTL_CRITICAL_SECTION cs;
+ NTSTATUS status;
+
+ if (!pRtlInitializeCriticalSectionEx)
+ return; /* Skip winxp */
+
+ status = RtlInitializeCriticalSection(&cs);
+ ok(!status, "RtlInitializeCriticalSection failed: %x\n", status);
+
+ status = RtlEnterCriticalSection(&cs);
+ ok(!status, "RtlEnterCriticalSection failed: %x\n", status);
+ todo_wine
+ ok(cs.LockCount == -2, "expected LockCount == -2, got %d\n", cs.LockCount);
+ ok(cs.RecursionCount == 1, "expected RecursionCount == 1, got %d\n", cs.RecursionCount);
+ ok(cs.OwningThread == ULongToHandle(GetCurrentThreadId()), "unexpected OwningThread\n");
+
+ status = RtlLeaveCriticalSection(&cs);
+ ok(!status, "RtlLeaveCriticalSection failed: %x\n", status);
+ ok(cs.LockCount == -1, "expected LockCount == -1, got %d\n", cs.LockCount);
+ ok(cs.RecursionCount == 0, "expected RecursionCount == 0, got %d\n", cs.RecursionCount);
+ ok(!cs.OwningThread, "unexpected OwningThread %p\n", cs.OwningThread);
+
+ /*
+ * Trying to leave a section that wasn't acquired modifies RecursionCount to an invalid value,
+ * but doesn't modify LockCount so that an attempt to enter the section later will work.
+ */
+ status = RtlLeaveCriticalSection(&cs);
+ ok(!status, "RtlLeaveCriticalSection failed: %x\n", status);
+ ok(cs.LockCount == -1, "expected LockCount == -1, got %d\n", cs.LockCount);
+ ok(cs.RecursionCount == -1, "expected RecursionCount == -1, got %d\n", cs.RecursionCount);
+ ok(!cs.OwningThread, "unexpected OwningThread %p\n", cs.OwningThread);
+
+ /* and again */
+ status = RtlLeaveCriticalSection(&cs);
+ ok(!status, "RtlLeaveCriticalSection failed: %x\n", status);
+ ok(cs.LockCount == -1, "expected LockCount == -1, got %d\n", cs.LockCount);
+ ok(cs.RecursionCount == -2, "expected RecursionCount == -2, got %d\n", cs.RecursionCount);
+ ok(!cs.OwningThread, "unexpected OwningThread %p\n", cs.OwningThread);
+
+ /* entering section fixes RecursionCount */
+ status = RtlEnterCriticalSection(&cs);
+ ok(!status, "RtlEnterCriticalSection failed: %x\n", status);
+ todo_wine
+ ok(cs.LockCount == -2, "expected LockCount == -2, got %d\n", cs.LockCount);
+ ok(cs.RecursionCount == 1, "expected RecursionCount == 1, got %d\n", cs.RecursionCount);
+ ok(cs.OwningThread == ULongToHandle(GetCurrentThreadId()), "unexpected OwningThread\n");
+
+ status = RtlLeaveCriticalSection(&cs);
+ ok(!status, "RtlLeaveCriticalSection failed: %x\n", status);
+ ok(cs.LockCount == -1, "expected LockCount == -1, got %d\n", cs.LockCount);
+ ok(cs.RecursionCount == 0, "expected RecursionCount == 0, got %d\n", cs.RecursionCount);
+ ok(!cs.OwningThread, "unexpected OwningThread %p\n", cs.OwningThread);
+
+ status = RtlDeleteCriticalSection(&cs);
+ ok(!status, "RtlDeleteCriticalSection failed: %x\n", status);
+}
+
+struct ldr_enum_context
+{
+ BOOL abort;
+ BOOL found;
+ int count;
+};
+
+static void WINAPI ldr_enum_callback(LDR_MODULE *module, void *context, BOOLEAN *stop)
+{
+ static const WCHAR ntdllW[] = {'n','t','d','l','l','.','d','l','l',0};
+ struct ldr_enum_context *ctx = context;
+
+ if (!lstrcmpiW(module->BaseDllName.Buffer, ntdllW))
+ ctx->found = TRUE;
+
+ ctx->count++;
+ *stop = ctx->abort;
+}
+
+static void test_LdrEnumerateLoadedModules(void)
+{
+ struct ldr_enum_context ctx;
+ NTSTATUS status;
+
+ if (!pLdrEnumerateLoadedModules)
+ {
+ win_skip("LdrEnumerateLoadedModules not available\n");
+ return;
+ }
+
+ ctx.abort = FALSE;
+ ctx.found = FALSE;
+ ctx.count = 0;
+ status = pLdrEnumerateLoadedModules(NULL, ldr_enum_callback, &ctx);
+ ok(status == STATUS_SUCCESS, "LdrEnumerateLoadedModules failed with %08x\n", status);
+ ok(ctx.count > 1, "Expected more than one module, got %d\n", ctx.count);
+ ok(ctx.found, "Could not find ntdll in list of modules\n");
+
+ ctx.abort = TRUE;
+ ctx.count = 0;
+ status = pLdrEnumerateLoadedModules(NULL, ldr_enum_callback, &ctx);
+ ok(status == STATUS_SUCCESS, "LdrEnumerateLoadedModules failed with %08x\n", status);
+ ok(ctx.count == 1, "Expected exactly one module, got %d\n", ctx.count);
+
+ status = pLdrEnumerateLoadedModules((void *)0x1, ldr_enum_callback, (void *)0xdeadbeef);
+ ok(status == STATUS_INVALID_PARAMETER, "expected STATUS_INVALID_PARAMETER, got 0x%08x\n", status);
+
+ status = pLdrEnumerateLoadedModules((void *)0xdeadbeef, ldr_enum_callback, (void *)0xdeadbeef);
+ ok(status == STATUS_INVALID_PARAMETER, "expected STATUS_INVALID_PARAMETER, got 0x%08x\n", status);
+
+ status = pLdrEnumerateLoadedModules(NULL, NULL, (void *)0xdeadbeef);
+ ok(status == STATUS_INVALID_PARAMETER, "expected STATUS_INVALID_PARAMETER, got 0x%08x\n", status);
+}
+
static void test_RtlQueryPackageIdentity(void)
{
const WCHAR programW[] = {'M','i','c','r','o','s','o','f','t','.','W','i','n','d','o','w','s','.',
CoUninitialize();
}
+static DWORD (CALLBACK *orig_entry)(HMODULE,DWORD,LPVOID);
+static DWORD *dll_main_data;
+
+static inline void *get_rva( HMODULE module, DWORD va )
+{
+ return (void *)((char *)module + va);
+}
+
+static void CALLBACK ldr_notify_callback1(ULONG reason, LDR_DLL_NOTIFICATION_DATA *data, void *context)
+{
+ const IMAGE_IMPORT_DESCRIPTOR *imports;
+ const IMAGE_THUNK_DATA *import_list;
+ IMAGE_THUNK_DATA *thunk_list;
+ DWORD *calls = context;
+ LIST_ENTRY *mark;
+ LDR_MODULE *mod;
+ ULONG size;
+ int i, j;
+
+ *calls <<= 4;
+ *calls |= reason;
+
+ ok(data->Loaded.Flags == 0, "Expected flags 0, got %x\n", data->Loaded.Flags);
+ ok(!lstrcmpiW(data->Loaded.BaseDllName->Buffer, ws2_32dllW), "Expected ws2_32.dll, got %s\n",
+ wine_dbgstr_w(data->Loaded.BaseDllName->Buffer));
+ ok(!!data->Loaded.DllBase, "Expected non zero base address\n");
+ ok(data->Loaded.SizeOfImage, "Expected non zero image size\n");
+
+ /* expect module to be last module listed in LdrData load order list */
+ mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
+ mod = CONTAINING_RECORD(mark->Blink, LDR_MODULE, InMemoryOrderModuleList);
+ ok(mod->BaseAddress == data->Loaded.DllBase, "Expected base address %p, got %p\n",
+ data->Loaded.DllBase, mod->BaseAddress);
+ ok(!lstrcmpiW(mod->BaseDllName.Buffer, ws2_32dllW), "Expected ws2_32.dll, got %s\n",
+ wine_dbgstr_w(mod->BaseDllName.Buffer));
+
+ /* show that imports have already been resolved */
+ imports = RtlImageDirectoryEntryToData(data->Loaded.DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &size);
+ ok(!!imports, "Expected dll to have imports\n");
+
+ for (i = 0; imports[i].Name; i++)
+ {
+ thunk_list = get_rva(data->Loaded.DllBase, (DWORD)imports[i].FirstThunk);
+ if (imports[i].OriginalFirstThunk)
+ import_list = get_rva(data->Loaded.DllBase, (DWORD)imports[i].OriginalFirstThunk);
+ else
+ import_list = thunk_list;
+
+ for (j = 0; import_list[j].u1.Ordinal; j++)
+ {
+ ok(thunk_list[j].u1.AddressOfData > data->Loaded.SizeOfImage,
+ "Import has not been resolved: %p\n", (void*)thunk_list[j].u1.Function);
+ }
+ }
+}
+
+static void CALLBACK ldr_notify_callback2(ULONG reason, LDR_DLL_NOTIFICATION_DATA *data, void *context)
+{
+ DWORD *calls = context;
+ *calls <<= 4;
+ *calls |= reason + 2;
+}
+
+static BOOL WINAPI fake_dll_main(HINSTANCE instance, DWORD reason, void* reserved)
+{
+ if (reason == DLL_PROCESS_ATTACH)
+ {
+ *dll_main_data <<= 4;
+ *dll_main_data |= 3;
+ }
+ else if (reason == DLL_PROCESS_DETACH)
+ {
+ *dll_main_data <<= 4;
+ *dll_main_data |= 4;
+ }
+ return orig_entry(instance, reason, reserved);
+}
+
+static void CALLBACK ldr_notify_callback_dll_main(ULONG reason, LDR_DLL_NOTIFICATION_DATA *data, void *context)
+{
+ DWORD *calls = context;
+ LIST_ENTRY *mark;
+ LDR_MODULE *mod;
+
+ *calls <<= 4;
+ *calls |= reason;
+
+ if (reason != LDR_DLL_NOTIFICATION_REASON_LOADED)
+ return;
+
+ mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
+ mod = CONTAINING_RECORD(mark->Blink, LDR_MODULE, InMemoryOrderModuleList);
+ ok(mod->BaseAddress == data->Loaded.DllBase, "Expected base address %p, got %p\n",
+ data->Loaded.DllBase, mod->BaseAddress);
+ if (mod->BaseAddress != data->Loaded.DllBase)
+ return;
+
+ orig_entry = mod->EntryPoint;
+ mod->EntryPoint = fake_dll_main;
+ dll_main_data = calls;
+}
+
+static BOOL WINAPI fake_dll_main_fail(HINSTANCE instance, DWORD reason, void* reserved)
+{
+ if (reason == DLL_PROCESS_ATTACH)
+ {
+ *dll_main_data <<= 4;
+ *dll_main_data |= 3;
+ }
+ else if (reason == DLL_PROCESS_DETACH)
+ {
+ *dll_main_data <<= 4;
+ *dll_main_data |= 4;
+ }
+ return FALSE;
+}
+
+static void CALLBACK ldr_notify_callback_fail(ULONG reason, LDR_DLL_NOTIFICATION_DATA *data, void *context)
+{
+ DWORD *calls = context;
+ LIST_ENTRY *mark;
+ LDR_MODULE *mod;
+
+ *calls <<= 4;
+ *calls |= reason;
+
+ if (reason != LDR_DLL_NOTIFICATION_REASON_LOADED)
+ return;
+
+ mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
+ mod = CONTAINING_RECORD(mark->Blink, LDR_MODULE, InMemoryOrderModuleList);
+ ok(mod->BaseAddress == data->Loaded.DllBase, "Expected base address %p, got %p\n",
+ data->Loaded.DllBase, mod->BaseAddress);
+ if (mod->BaseAddress != data->Loaded.DllBase)
+ return;
+
+ orig_entry = mod->EntryPoint;
+ mod->EntryPoint = fake_dll_main_fail;
+ dll_main_data = calls;
+}
+
+static void CALLBACK ldr_notify_callback_imports(ULONG reason, LDR_DLL_NOTIFICATION_DATA *data, void *context)
+{
+ DWORD *calls = context;
+
+ if (reason != LDR_DLL_NOTIFICATION_REASON_LOADED)
+ return;
+
+ if (!lstrcmpiW(data->Loaded.BaseDllName->Buffer, crypt32dllW))
+ {
+ *calls <<= 4;
+ *calls |= 1;
+ }
+
+ if (!lstrcmpiW(data->Loaded.BaseDllName->Buffer, wintrustdllW))
+ {
+ *calls <<= 4;
+ *calls |= 2;
+ }
+}
+
+static void test_LdrRegisterDllNotification(void)
+{
+ void *cookie, *cookie2;
+ NTSTATUS status;
+ HMODULE mod;
+ DWORD calls;
+
+ if (!pLdrRegisterDllNotification || !pLdrUnregisterDllNotification)
+ {
+ win_skip("Ldr(Un)RegisterDllNotification not available\n");
+ return;
+ }
+
+ /* generic test */
+ status = pLdrRegisterDllNotification(0, ldr_notify_callback1, &calls, &cookie);
+ ok(!status, "Expected STATUS_SUCCESS, got %08x\n", status);
+
+ calls = 0;
+ mod = LoadLibraryW(ws2_32dllW);
+ ok(!!mod, "Failed to load library: %d\n", GetLastError());
+ ok(calls == LDR_DLL_NOTIFICATION_REASON_LOADED, "Expected LDR_DLL_NOTIFICATION_REASON_LOADED, got %x\n", calls);
+
+ calls = 0;
+ FreeLibrary(mod);
+ ok(calls == LDR_DLL_NOTIFICATION_REASON_UNLOADED, "Expected LDR_DLL_NOTIFICATION_REASON_UNLOADED, got %x\n", calls);
+
+ /* test order of callbacks */
+ status = pLdrRegisterDllNotification(0, ldr_notify_callback2, &calls, &cookie2);
+ ok(!status, "Expected STATUS_SUCCESS, got %08x\n", status);
+
+ calls = 0;
+ mod = LoadLibraryW(ws2_32dllW);
+ ok(!!mod, "Failed to load library: %d\n", GetLastError());
+ ok(calls == 0x13, "Expected order 0x13, got %x\n", calls);
+
+ calls = 0;
+ FreeLibrary(mod);
+ ok(calls == 0x24, "Expected order 0x24, got %x\n", calls);
+
+ pLdrUnregisterDllNotification(cookie2);
+ pLdrUnregisterDllNotification(cookie);
+
+ /* test dll main order */
+ status = pLdrRegisterDllNotification(0, ldr_notify_callback_dll_main, &calls, &cookie);
+ ok(!status, "Expected STATUS_SUCCESS, got %08x\n", status);
+
+ calls = 0;
+ mod = LoadLibraryW(ws2_32dllW);
+ ok(!!mod, "Failed to load library: %d\n", GetLastError());
+ ok(calls == 0x13, "Expected order 0x13, got %x\n", calls);
+
+ calls = 0;
+ FreeLibrary(mod);
+ ok(calls == 0x42, "Expected order 0x42, got %x\n", calls);
+
+ pLdrUnregisterDllNotification(cookie);
+
+ /* test dll main order */
+ status = pLdrRegisterDllNotification(0, ldr_notify_callback_fail, &calls, &cookie);
+ ok(!status, "Expected STATUS_SUCCESS, got %08x\n", status);
+
+ calls = 0;
+ mod = LoadLibraryW(ws2_32dllW);
+ ok(!mod, "Expected library to fail loading\n");
+ ok(calls == 0x1342, "Expected order 0x1342, got %x\n", calls);
+
+ pLdrUnregisterDllNotification(cookie);
+
+ /* test dll with dependencies */
+ status = pLdrRegisterDllNotification(0, ldr_notify_callback_imports, &calls, &cookie);
+ ok(!status, "Expected STATUS_SUCCESS, got %08x\n", status);
+
+ calls = 0;
+ mod = LoadLibraryW(wintrustdllW);
+ ok(!!mod, "Failed to load library: %d\n", GetLastError());
+ ok(calls == 0x12, "Expected order 0x12, got %x\n", calls);
+
+ FreeLibrary(mod);
+ pLdrUnregisterDllNotification(cookie);
+}
+
START_TEST(rtl)
{
InitFunctionPtrs();
test_RtlDecompressBuffer();
test_RtlIsCriticalSectionLocked();
test_RtlInitializeCriticalSectionEx();
+ test_RtlLeaveCriticalSection();
+ test_LdrEnumerateLoadedModules();
test_RtlQueryPackageIdentity();
+ test_LdrRegisterDllNotification();
}
ulLong <<= i;
cPos = pRtlFindMostSignificantBit(ulLong);
- ok (cPos == i, "didn't find MSB 0x%x%08x %d %d\n",
- (DWORD)(ulLong >> 32), (DWORD)ulLong, i, cPos);
+ ok (cPos == i, "didn't find MSB 0x%s %d %d\n",
+ wine_dbgstr_longlong(ulLong ), i, cPos);
/* Set all bits lower than bit i */
ulLong = ((ulLong - 1) << 1) | 1;
cPos = pRtlFindMostSignificantBit(ulLong);
- ok (cPos == i, "didn't find MSB 0x%x%08x %d %d\n",
- (DWORD)(ulLong >> 32), (DWORD)ulLong, i, cPos);
+ ok (cPos == i, "didn't find MSB 0x%s %d %d\n",
+ wine_dbgstr_longlong(ulLong ), i, cPos);
}
cPos = pRtlFindMostSignificantBit(0);
ok (cPos == -1, "found bit when not set\n");
ulLong = (ULONGLONG)1 << i;
cPos = pRtlFindLeastSignificantBit(ulLong);
- ok (cPos == i, "didn't find LSB 0x%x%08x %d %d\n",
- (DWORD)(ulLong >> 32), (DWORD)ulLong, i, cPos);
+ ok (cPos == i, "didn't find LSB 0x%s %d %d\n",
+ wine_dbgstr_longlong(ulLong ), i, cPos);
ulLong = ~((ULONGLONG)0) << i;
cPos = pRtlFindLeastSignificantBit(ulLong);
- ok (cPos == i, "didn't find LSB 0x%x%08x %d %d\n",
- (DWORD)(ulLong >> 32), (DWORD)ulLong, i, cPos);
+ ok (cPos == i, "didn't find LSB 0x%s %d %d\n",
+ wine_dbgstr_longlong(ulLong ), i, cPos);
}
cPos = pRtlFindLeastSignificantBit(0);
ok (cPos == -1, "found bit when not set\n");
dest_str[LARGE_STRI_BUFFER_LENGTH] = '\0';
result = p_i64toa(ulonglong2str->value, dest_str, ulonglong2str->base);
ok(result == dest_str,
- "(test %d): _i64toa(%08x%08x, [out], %d) has result %p, expected: %p\n",
- test_num, (DWORD)(ulonglong2str->value >> 32), (DWORD)ulonglong2str->value,
- ulonglong2str->base, result, dest_str);
+ "(test %d): _i64toa(%s, [out], %d) has result %p, expected: %p\n",
+ test_num, wine_dbgstr_longlong(ulonglong2str->value), ulonglong2str->base, result, dest_str);
if (ulonglong2str->mask & 0x04) {
if (memcmp(dest_str, ulonglong2str->Buffer, LARGE_STRI_BUFFER_LENGTH) != 0) {
if (memcmp(dest_str, ulonglong2str[1].Buffer, LARGE_STRI_BUFFER_LENGTH) != 0) {
ok(memcmp(dest_str, ulonglong2str->Buffer, LARGE_STRI_BUFFER_LENGTH) == 0,
- "(test %d): _i64toa(%08x%08x, [out], %d) assigns string \"%s\", expected: \"%s\"\n",
- test_num, (DWORD)(ulonglong2str->value >> 32), (DWORD)ulonglong2str->value,
+ "(test %d): _i64toa(%s, [out], %d) assigns string \"%s\", expected: \"%s\"\n",
+ test_num, wine_dbgstr_longlong(ulonglong2str->value),
ulonglong2str->base, dest_str, ulonglong2str->Buffer);
} /* if */
} /* if */
} else {
ok(memcmp(dest_str, ulonglong2str->Buffer, LARGE_STRI_BUFFER_LENGTH) == 0,
- "(test %d): _i64toa(%08x%08x, [out], %d) assigns string \"%s\", expected: \"%s\"\n",
- test_num, (DWORD)(ulonglong2str->value >> 32), (DWORD)ulonglong2str->value,
+ "(test %d): _i64toa(%s, [out], %d) assigns string \"%s\", expected: \"%s\"\n",
+ test_num, wine_dbgstr_longlong(ulonglong2str->value),
ulonglong2str->base, dest_str, ulonglong2str->Buffer);
} /* if */
}
dest_str[LARGE_STRI_BUFFER_LENGTH] = '\0';
result = p_ui64toa(ulonglong2str->value, dest_str, ulonglong2str->base);
ok(result == dest_str,
- "(test %d): _ui64toa(%08x%08x, [out], %d) has result %p, expected: %p\n",
- test_num, (DWORD)(ulonglong2str->value >> 32), (DWORD)ulonglong2str->value,
- ulonglong2str->base, result, dest_str);
+ "(test %d): _ui64toa(%s, [out], %d) has result %p, expected: %p\n",
+ test_num, wine_dbgstr_longlong(ulonglong2str->value), ulonglong2str->base, result, dest_str);
ok(memcmp(dest_str, ulonglong2str->Buffer, LARGE_STRI_BUFFER_LENGTH) == 0,
- "(test %d): _ui64toa(%08x%08x, [out], %d) assigns string \"%s\", expected: \"%s\"\n",
- test_num, (DWORD)(ulonglong2str->value >> 32), (DWORD)ulonglong2str->value,
+ "(test %d): _ui64toa(%s, [out], %d) assigns string \"%s\", expected: \"%s\"\n",
+ test_num, wine_dbgstr_longlong(ulonglong2str->value),
ulonglong2str->base, dest_str, ulonglong2str->Buffer);
}
result = p_i64tow(ulonglong2str->value, dest_wstr, ulonglong2str->base);
pRtlUnicodeStringToAnsiString(&ansi_str, &unicode_string, 1);
ok(result == dest_wstr,
- "(test %d): _i64tow(0x%x%08x, [out], %d) has result %p, expected: %p\n",
- test_num, (DWORD)(ulonglong2str->value >> 32), (DWORD)ulonglong2str->value,
- ulonglong2str->base, result, dest_wstr);
+ "(test %d): _i64tow(0x%s, [out], %d) has result %p, expected: %p\n",
+ test_num, wine_dbgstr_longlong(ulonglong2str->value), ulonglong2str->base, result, dest_wstr);
if (ulonglong2str->mask & 0x04) {
if (memcmp(dest_wstr, expected_wstr, LARGE_STRI_BUFFER_LENGTH * sizeof(WCHAR)) != 0) {
for (pos = 0; pos < LARGE_STRI_BUFFER_LENGTH; pos++) {
expected_wstr[LARGE_STRI_BUFFER_LENGTH] = '\0';
if (memcmp(dest_wstr, expected_wstr, LARGE_STRI_BUFFER_LENGTH * sizeof(WCHAR)) != 0) {
ok(memcmp(dest_wstr, expected_wstr, LARGE_STRI_BUFFER_LENGTH * sizeof(WCHAR)) == 0,
- "(test %d): _i64tow(0x%x%08x, [out], %d) assigns string \"%s\", expected: \"%s\"\n",
- test_num, (DWORD)(ulonglong2str->value >> 32), (DWORD)ulonglong2str->value,
+ "(test %d): _i64tow(0x%s, [out], %d) assigns string \"%s\", expected: \"%s\"\n",
+ test_num, wine_dbgstr_longlong(ulonglong2str->value),
ulonglong2str->base, ansi_str.Buffer, ulonglong2str->Buffer);
} /* if */
} /* if */
} else {
ok(memcmp(dest_wstr, expected_wstr, LARGE_STRI_BUFFER_LENGTH * sizeof(WCHAR)) == 0,
- "(test %d): _i64tow(0x%x%08x, [out], %d) assigns string \"%s\", expected: \"%s\"\n",
- test_num, (DWORD)(ulonglong2str->value >> 32), (DWORD)ulonglong2str->value,
+ "(test %d): _i64tow(0x%s, [out], %d) assigns string \"%s\", expected: \"%s\"\n",
+ test_num, wine_dbgstr_longlong(ulonglong2str->value),
ulonglong2str->base, ansi_str.Buffer, ulonglong2str->Buffer);
} /* if */
pRtlFreeAnsiString(&ansi_str);
result = p_ui64tow(ulonglong2str->value, dest_wstr, ulonglong2str->base);
pRtlUnicodeStringToAnsiString(&ansi_str, &unicode_string, 1);
ok(result == dest_wstr,
- "(test %d): _ui64tow(0x%x%08x, [out], %d) has result %p, expected: %p\n",
- test_num, (DWORD)(ulonglong2str->value >> 32), (DWORD)ulonglong2str->value,
+ "(test %d): _ui64tow(0x%s, [out], %d) has result %p, expected: %p\n",
+ test_num, wine_dbgstr_longlong(ulonglong2str->value),
ulonglong2str->base, result, dest_wstr);
ok(memcmp(dest_wstr, expected_wstr, LARGE_STRI_BUFFER_LENGTH * sizeof(WCHAR)) == 0,
- "(test %d): _ui64tow(0x%x%08x, [out], %d) assigns string \"%s\", expected: \"%s\"\n",
- test_num, (DWORD)(ulonglong2str->value >> 32), (DWORD)ulonglong2str->value,
+ "(test %d): _ui64tow(0x%s, [out], %d) assigns string \"%s\", expected: \"%s\"\n",
+ test_num, wine_dbgstr_longlong(ulonglong2str->value),
ulonglong2str->base, ansi_str.Buffer, ulonglong2str->Buffer);
pRtlFreeAnsiString(&ansi_str);
}
/* Crashes on XP and W2K3 */
result = p_i64tow(ulonglong2str[0].value, NULL, 10);
ok(result == NULL,
- "(test d): _i64tow(0x%x%08x, NULL, 10) has result %p, expected: NULL\n",
- (DWORD)(ulonglong2str[0].value >> 32), (DWORD)ulonglong2str[0].value, result);
+ "(test d): _i64tow(0x%s, NULL, 10) has result %p, expected: NULL\n",
+ wine_dbgstr_longlong(ulonglong2str[0].value), result);
}
if (p_ui64tow) {
/* Crashes on XP and W2K3 */
result = p_ui64tow(ulonglong2str[0].value, NULL, 10);
ok(result == NULL,
- "(test e): _ui64tow(0x%x%08x, NULL, 10) has result %p, expected: NULL\n",
- (DWORD)(ulonglong2str[0].value >> 32), (DWORD)ulonglong2str[0].value, result);
+ "(test e): _ui64tow(0x%s, NULL, 10) has result %p, expected: NULL\n",
+ wine_dbgstr_longlong(ulonglong2str[0].value), result);
}
} /* if */
}
ok(result == str2longlong[test_num].value ||
(result == ((str2longlong[test_num].overflow == -1) ?
ULL(0x80000000,0x00000000) : ULL(0x7fffffff,0xffffffff))),
- "(test %d): call failed: _atoi64(\"%s\") has result 0x%x%08x, expected: 0x%x%08x\n",
- test_num, str2longlong[test_num].str, (DWORD)(result >> 32), (DWORD)result,
- (DWORD)(str2longlong[test_num].value >> 32), (DWORD)str2longlong[test_num].value);
+ "(test %d): call failed: _atoi64(\"%s\") has result 0x%s, expected: 0x%s\n",
+ test_num, str2longlong[test_num].str, wine_dbgstr_longlong(result),
+ wine_dbgstr_longlong(str2longlong[test_num].value));
else
ok(result == str2longlong[test_num].value,
- "(test %d): call failed: _atoi64(\"%s\") has result 0x%x%08x, expected: 0x%x%08x\n",
- test_num, str2longlong[test_num].str, (DWORD)(result >> 32), (DWORD)result,
- (DWORD)(str2longlong[test_num].value >> 32), (DWORD)str2longlong[test_num].value);
+ "(test %d): call failed: _atoi64(\"%s\") has result 0x%s, expected: 0x%s\n",
+ test_num, str2longlong[test_num].str, wine_dbgstr_longlong(result),
+ wine_dbgstr_longlong(str2longlong[test_num].value));
}
}
ok(result == str2longlong[test_num].value ||
(result == ((str2longlong[test_num].overflow == -1) ?
ULL(0x80000000,0x00000000) : ULL(0x7fffffff,0xffffffff))),
- "(test %d): call failed: _atoi64(\"%s\") has result 0x%x%08x, expected: 0x%x%08x\n",
- test_num, str2longlong[test_num].str, (DWORD)(result >> 32), (DWORD)result,
- (DWORD)(str2longlong[test_num].value >> 32), (DWORD)str2longlong[test_num].value);
+ "(test %d): call failed: _atoi64(\"%s\") has result 0x%s, expected: 0x%s\n",
+ test_num, str2longlong[test_num].str, wine_dbgstr_longlong(result),
+ wine_dbgstr_longlong(str2longlong[test_num].value));
else
ok(result == str2longlong[test_num].value,
- "(test %d): call failed: _atoi64(\"%s\") has result 0x%x%08x, expected: 0x%x%08x\n",
- test_num, str2longlong[test_num].str, (DWORD)(result >> 32), (DWORD)result,
- (DWORD)(str2longlong[test_num].value >> 32), (DWORD)str2longlong[test_num].value);
+ "(test %d): call failed: _atoi64(\"%s\") has result 0x%s, expected: 0x%s\n",
+ test_num, str2longlong[test_num].str, wine_dbgstr_longlong(result),
+ wine_dbgstr_longlong(str2longlong[test_num].value));
pRtlFreeUnicodeString(&uni);
}
}
extern void func_path(void);
extern void func_pipe(void);
extern void func_port(void);
+extern void func_process(void);
extern void func_reg(void);
extern void func_rtl(void);
extern void func_rtlbitmap(void);
{ "path", func_path },
{ "pipe", func_pipe },
{ "port", func_port },
+ { "process", func_process },
{ "reg", func_reg },
{ "rtl", func_rtl },
{ "rtlbitmap", func_rtlbitmap },
--- /dev/null
+/*
+ * Unit test suite for thread pool functions
+ *
+ * Copyright 2015-2016 Sebastian Lackner
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "ntdll_test.h"
+
+static HMODULE hntdll = 0;
+static NTSTATUS (WINAPI *pTpAllocCleanupGroup)(TP_CLEANUP_GROUP **);
+static NTSTATUS (WINAPI *pTpAllocPool)(TP_POOL **,PVOID);
+static NTSTATUS (WINAPI *pTpAllocTimer)(TP_TIMER **,PTP_TIMER_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *);
+static NTSTATUS (WINAPI *pTpAllocWait)(TP_WAIT **,PTP_WAIT_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *);
+static NTSTATUS (WINAPI *pTpAllocWork)(TP_WORK **,PTP_WORK_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *);
+static NTSTATUS (WINAPI *pTpCallbackMayRunLong)(TP_CALLBACK_INSTANCE *);
+static VOID (WINAPI *pTpCallbackReleaseSemaphoreOnCompletion)(TP_CALLBACK_INSTANCE *,HANDLE,DWORD);
+static VOID (WINAPI *pTpDisassociateCallback)(TP_CALLBACK_INSTANCE *);
+static BOOL (WINAPI *pTpIsTimerSet)(TP_TIMER *);
+static VOID (WINAPI *pTpReleaseWait)(TP_WAIT *);
+static VOID (WINAPI *pTpPostWork)(TP_WORK *);
+static VOID (WINAPI *pTpReleaseCleanupGroup)(TP_CLEANUP_GROUP *);
+static VOID (WINAPI *pTpReleaseCleanupGroupMembers)(TP_CLEANUP_GROUP *,BOOL,PVOID);
+static VOID (WINAPI *pTpReleasePool)(TP_POOL *);
+static VOID (WINAPI *pTpReleaseTimer)(TP_TIMER *);
+static VOID (WINAPI *pTpReleaseWork)(TP_WORK *);
+static VOID (WINAPI *pTpSetPoolMaxThreads)(TP_POOL *,DWORD);
+static VOID (WINAPI *pTpSetTimer)(TP_TIMER *,LARGE_INTEGER *,LONG,LONG);
+static VOID (WINAPI *pTpSetWait)(TP_WAIT *,HANDLE,LARGE_INTEGER *);
+static NTSTATUS (WINAPI *pTpSimpleTryPost)(PTP_SIMPLE_CALLBACK,PVOID,TP_CALLBACK_ENVIRON *);
+static VOID (WINAPI *pTpWaitForTimer)(TP_TIMER *,BOOL);
+static VOID (WINAPI *pTpWaitForWait)(TP_WAIT *,BOOL);
+static VOID (WINAPI *pTpWaitForWork)(TP_WORK *,BOOL);
+
+#define NTDLL_GET_PROC(func) \
+ do \
+ { \
+ p ## func = (void *)GetProcAddress(hntdll, #func); \
+ if (!p ## func) trace("Failed to get address for %s\n", #func); \
+ } \
+ while (0)
+
+static BOOL init_threadpool(void)
+{
+ hntdll = GetModuleHandleA("ntdll");
+ if (!hntdll)
+ {
+ win_skip("Could not load ntdll\n");
+ return FALSE;
+ }
+
+ NTDLL_GET_PROC(TpAllocCleanupGroup);
+ NTDLL_GET_PROC(TpAllocPool);
+ NTDLL_GET_PROC(TpAllocTimer);
+ NTDLL_GET_PROC(TpAllocWait);
+ NTDLL_GET_PROC(TpAllocWork);
+ NTDLL_GET_PROC(TpCallbackMayRunLong);
+ NTDLL_GET_PROC(TpCallbackReleaseSemaphoreOnCompletion);
+ NTDLL_GET_PROC(TpDisassociateCallback);
+ NTDLL_GET_PROC(TpIsTimerSet);
+ NTDLL_GET_PROC(TpPostWork);
+ NTDLL_GET_PROC(TpReleaseCleanupGroup);
+ NTDLL_GET_PROC(TpReleaseCleanupGroupMembers);
+ NTDLL_GET_PROC(TpReleasePool);
+ NTDLL_GET_PROC(TpReleaseTimer);
+ NTDLL_GET_PROC(TpReleaseWait);
+ NTDLL_GET_PROC(TpReleaseWork);
+ NTDLL_GET_PROC(TpSetPoolMaxThreads);
+ NTDLL_GET_PROC(TpSetTimer);
+ NTDLL_GET_PROC(TpSetWait);
+ NTDLL_GET_PROC(TpSimpleTryPost);
+ NTDLL_GET_PROC(TpWaitForTimer);
+ NTDLL_GET_PROC(TpWaitForWait);
+ NTDLL_GET_PROC(TpWaitForWork);
+
+ if (!pTpAllocPool)
+ {
+ win_skip("Threadpool functions not supported, skipping tests\n");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+#undef NTDLL_GET_PROC
+
+
+static DWORD CALLBACK rtl_work_cb(void *userdata)
+{
+ HANDLE semaphore = userdata;
+ trace("Running rtl_work callback\n");
+ ReleaseSemaphore(semaphore, 1, NULL);
+ return 0;
+}
+
+static void test_RtlQueueWorkItem(void)
+{
+ HANDLE semaphore;
+ NTSTATUS status;
+ DWORD result;
+
+ semaphore = CreateSemaphoreA(NULL, 0, 1, NULL);
+ ok(semaphore != NULL, "CreateSemaphoreA failed %u\n", GetLastError());
+
+ status = RtlQueueWorkItem(rtl_work_cb, semaphore, WT_EXECUTEDEFAULT);
+ ok(!status, "RtlQueueWorkItem failed with status %x\n", status);
+ result = WaitForSingleObject(semaphore, 1000);
+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
+
+ status = RtlQueueWorkItem(rtl_work_cb, semaphore, WT_EXECUTEINIOTHREAD);
+ ok(!status, "RtlQueueWorkItem failed with status %x\n", status);
+ result = WaitForSingleObject(semaphore, 1000);
+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
+
+ status = RtlQueueWorkItem(rtl_work_cb, semaphore, WT_EXECUTEINPERSISTENTTHREAD);
+ ok(!status, "RtlQueueWorkItem failed with status %x\n", status);
+ result = WaitForSingleObject(semaphore, 1000);
+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
+
+ status = RtlQueueWorkItem(rtl_work_cb, semaphore, WT_EXECUTELONGFUNCTION);
+ ok(!status, "RtlQueueWorkItem failed with status %x\n", status);
+ result = WaitForSingleObject(semaphore, 1000);
+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
+
+ status = RtlQueueWorkItem(rtl_work_cb, semaphore, WT_TRANSFER_IMPERSONATION);
+ ok(!status, "RtlQueueWorkItem failed with status %x\n", status);
+ result = WaitForSingleObject(semaphore, 1000);
+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
+
+ CloseHandle(semaphore);
+}
+
+struct rtl_wait_info
+{
+ HANDLE semaphore1;
+ HANDLE semaphore2;
+ DWORD wait_result;
+ DWORD threadid;
+ LONG userdata;
+};
+
+static void CALLBACK rtl_wait_cb(void *userdata, BOOLEAN timeout)
+{
+ struct rtl_wait_info *info = userdata;
+ DWORD result;
+
+ trace("Running rtl_wait callback\n");
+
+ if (!timeout)
+ InterlockedIncrement(&info->userdata);
+ else
+ InterlockedExchangeAdd(&info->userdata, 0x10000);
+ info->threadid = GetCurrentThreadId();
+ ReleaseSemaphore(info->semaphore1, 1, NULL);
+
+ if (info->semaphore2)
+ {
+ result = WaitForSingleObject(info->semaphore2, 200);
+ ok(result == info->wait_result, "expected %u, got %u\n", info->wait_result, result);
+ ReleaseSemaphore(info->semaphore1, 1, NULL);
+ }
+}
+
+static HANDLE rtl_wait_apc_semaphore;
+
+static void CALLBACK rtl_wait_apc_cb(ULONG_PTR userdata)
+{
+ trace("Running rtl_wait_apc callback\n");
+ if (rtl_wait_apc_semaphore)
+ ReleaseSemaphore(rtl_wait_apc_semaphore, 1, NULL);
+}
+
+static void test_RtlRegisterWait(void)
+{
+ HANDLE wait1, event, thread;
+ struct rtl_wait_info info;
+ HANDLE semaphores[2];
+ NTSTATUS status;
+ DWORD result;
+
+ semaphores[0] = CreateSemaphoreW(NULL, 0, 2, NULL);
+ ok(semaphores[0] != NULL, "failed to create semaphore\n");
+ semaphores[1] = CreateSemaphoreW(NULL, 0, 1, NULL);
+ ok(semaphores[1] != NULL, "failed to create semaphore\n");
+ info.semaphore1 = semaphores[0];
+ info.semaphore2 = NULL;
+
+ event = CreateEventW(NULL, FALSE, FALSE, NULL);
+ ok(event != NULL, "failed to create event\n");
+
+ /* basic test for RtlRegisterWait and RtlDeregisterWait */
+ wait1 = NULL;
+ info.userdata = 0;
+ status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT);
+ ok(!status, "RtlRegisterWait failed with status %x\n", status);
+ ok(wait1 != NULL, "expected wait1 != NULL\n");
+ status = RtlDeregisterWait(wait1);
+ ok(!status, "RtlDeregisterWait failed with status %x\n", status);
+ ok(info.userdata == 0, "expected info.userdata = 0, got %u\n", info.userdata);
+
+ /* infinite timeout, signal the semaphore two times */
+ info.userdata = 0;
+ status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEDEFAULT);
+ ok(!status, "RtlRegisterWait failed with status %x\n", status);
+ ReleaseSemaphore(semaphores[1], 1, NULL);
+ result = WaitForSingleObject(semaphores[0], 100);
+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
+ ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata);
+ ReleaseSemaphore(semaphores[1], 1, NULL);
+ result = WaitForSingleObject(semaphores[0], 100);
+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
+ ok(info.userdata == 2, "expected info.userdata = 2, got %u\n", info.userdata);
+ result = WaitForSingleObject(semaphores[1], 0);
+ ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
+ Sleep(50);
+ status = RtlDeregisterWait(wait1);
+ ok(!status, "RtlDeregisterWait failed with status %x\n", status);
+
+ /* repeat test with WT_EXECUTEONLYONCE */
+ info.userdata = 0;
+ status = RtlRegisterWait(&wait1, semaphores[1], rtl_wait_cb, &info, INFINITE, WT_EXECUTEONLYONCE);
+ ok(!status, "RtlRegisterWait failed with status %x\n", status);
+ ReleaseSemaphore(semaphores[1], 1, NULL);
+ result = WaitForSingleObject(semaphores[0], 100);
+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
+ ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata);
+ ReleaseSemaphore(semaphores[1], 1, NULL);
+ result = WaitForSingleObject(semaphores[0], 100);
+ ok(result == WAIT_TIMEOUT, "WaitForSingleObject returned %u\n", result);
+ ok(info.userdata == 1, "expected info.userdata = 1, got %u\n", info.userdata);
+ result = WaitForSingleObject(semaphores[1], 0);
+ ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", result);
+ Sleep(50);