Wine-devel
Threads by month
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
July 2021
- 86 participants
- 642 discussions
From: Eric Pouech <eric.pouech(a)gmail.com>
In Winedbg, when parsing integral values from command line (mainly pid and event),
allow hexadecimal values (prefixed by 0x)
Signed-off-by: Eric Pouech <eric.pouech(a)gmail.com>
---
programs/winedbg/tgt_active.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/programs/winedbg/tgt_active.c b/programs/winedbg/tgt_active.c
index c9072d5b81c..508e1c58040 100644
--- a/programs/winedbg/tgt_active.c
+++ b/programs/winedbg/tgt_active.c
@@ -667,7 +667,7 @@ static BOOL str2int(const char* str, DWORD_PTR* val)
{
char* ptr;
- *val = strtol(str, &ptr, 10);
+ *val = strtol(str, &ptr, 0);
return str < ptr && !*ptr;
}
1
0
01 Jul '21
So that we can have full featured wine test with thread local data and
context.
Signed-off-by: Rémi Bernon <rbernon(a)codeweavers.com>
---
Supersedes: 208930
v2: Same thing as before, but don't comment-out the okfile cleanup.
dlls/ntoskrnl.exe/tests/Makefile.in | 16 +-
dlls/ntoskrnl.exe/tests/driver.c | 36 ++--
dlls/ntoskrnl.exe/tests/driver.h | 8 -
dlls/ntoskrnl.exe/tests/driver_hid.c | 2 +-
dlls/ntoskrnl.exe/tests/driver_netio.c | 6 +-
dlls/ntoskrnl.exe/tests/driver_pnp.c | 2 +-
dlls/ntoskrnl.exe/tests/ntoskrnl.c | 49 +----
dlls/ntoskrnl.exe/tests/utils.h | 257 ------------------------
include/wine/test.h | 260 +++++++++++++++++++++++--
9 files changed, 287 insertions(+), 349 deletions(-)
delete mode 100644 dlls/ntoskrnl.exe/tests/utils.h
diff --git a/dlls/ntoskrnl.exe/tests/Makefile.in b/dlls/ntoskrnl.exe/tests/Makefile.in
index 863fad30f63..037f0fda637 100644
--- a/dlls/ntoskrnl.exe/tests/Makefile.in
+++ b/dlls/ntoskrnl.exe/tests/Makefile.in
@@ -1,17 +1,23 @@
TESTDLL = ntoskrnl.exe
IMPORTS = advapi32 crypt32 newdev setupapi user32 wintrust ws2_32 hid
-driver_IMPORTS = winecrt0 ntoskrnl
+driver_IMPORTS = winecrt0 ntoskrnl hal
+driver_EXTRADEFS = -DSTANDALONE -DWINETEST_KERNEL
driver_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native
-driver2_IMPORTS = winecrt0 ntoskrnl
+driver2_IMPORTS = winecrt0 ntoskrnl hal
+driver2_EXTRADEFS = -DSTANDALONE -DWINETEST_KERNEL
driver2_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native
-driver3_IMPORTS = winecrt0 ntoskrnl
+driver3_IMPORTS = winecrt0 ntoskrnl hal
+driver3_EXTRADEFS = -DSTANDALONE -DWINETEST_KERNEL
driver3_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native
-driver_hid_IMPORTS = winecrt0 ntoskrnl hidclass
+driver_hid_IMPORTS = winecrt0 ntoskrnl hal hidclass
+driver_hid_EXTRADEFS = -DSTANDALONE -DWINETEST_KERNEL
driver_hid_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native
-driver_netio_IMPORTS = winecrt0 ntoskrnl netio
+driver_netio_IMPORTS = winecrt0 ntoskrnl hal netio
+driver_netio_EXTRADEFS = -DSTANDALONE -DWINETEST_KERNEL
driver_netio_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native
driver_pnp_IMPORTS = winecrt0 ntoskrnl hal
+driver_pnp_EXTRADEFS = -DSTANDALONE -DWINETEST_KERNEL
driver_pnp_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native
SOURCES = \
diff --git a/dlls/ntoskrnl.exe/tests/driver.c b/dlls/ntoskrnl.exe/tests/driver.c
index 94139b4b654..8c5ac6d89d4 100644
--- a/dlls/ntoskrnl.exe/tests/driver.c
+++ b/dlls/ntoskrnl.exe/tests/driver.c
@@ -33,9 +33,9 @@
#include "ddk/ntifs.h"
#include "ddk/wdm.h"
-#include "driver.h"
+#include "wine/test.h"
-#include "utils.h"
+#include "driver.h"
/* memcmp() isn't exported from ntoskrnl on i386 */
static int kmemcmp( const void *ptr1, const void *ptr2, size_t n )
@@ -999,41 +999,41 @@ static void test_call_driver(DEVICE_OBJECT *device)
irp = IoBuildAsynchronousFsdRequest(IRP_MJ_FLUSH_BUFFERS, device, NULL, 0, NULL, &iosb);
ok(irp->UserIosb == &iosb, "unexpected UserIosb\n");
ok(!irp->Cancel, "Cancel = %x\n", irp->Cancel);
- ok(!irp->CancelRoutine, "CancelRoutine = %x\n", irp->CancelRoutine);
+ ok(!irp->CancelRoutine, "CancelRoutine = %p\n", irp->CancelRoutine);
ok(!irp->UserEvent, "UserEvent = %p\n", irp->UserEvent);
ok(irp->CurrentLocation == 2, "CurrentLocation = %u\n", irp->CurrentLocation);
ok(irp->Tail.Overlay.Thread == (PETHREAD)KeGetCurrentThread(),
"IRP thread is not the current thread\n");
ok(!irp->IoStatus.Status, "got status %#x\n", irp->IoStatus.Status);
- ok(!irp->IoStatus.Information, "got information %#x\n", irp->IoStatus.Information);
+ ok(!irp->IoStatus.Information, "got information %#I64x\n", (UINT64)irp->IoStatus.Information);
ok(iosb.Status == 0xdeadbeef, "got status %#x\n", iosb.Status);
- ok(iosb.Information == 0xdeadbeef, "got information %#x\n", iosb.Information);
+ ok(iosb.Information == 0xdeadbeef, "got information %#I64x\n", (UINT64)iosb.Information);
irpsp = IoGetNextIrpStackLocation(irp);
ok(irpsp->MajorFunction == IRP_MJ_FLUSH_BUFFERS, "MajorFunction = %u\n", irpsp->MajorFunction);
- ok(!irpsp->DeviceObject, "DeviceObject = %u\n", irpsp->DeviceObject);
- ok(!irpsp->FileObject, "FileObject = %u\n", irpsp->FileObject);
+ ok(!irpsp->DeviceObject, "DeviceObject = %p\n", irpsp->DeviceObject);
+ ok(!irpsp->FileObject, "FileObject = %p\n", irpsp->FileObject);
ok(!irpsp->CompletionRoutine, "CompletionRoutine = %p\n", irpsp->CompletionRoutine);
status = IoCallDriver(device, irp);
ok(status == STATUS_PENDING, "IoCallDriver returned %#x\n", status);
ok(!irp->IoStatus.Status, "got status %#x\n", irp->IoStatus.Status);
- ok(!irp->IoStatus.Information, "got information %#x\n", irp->IoStatus.Information);
+ ok(!irp->IoStatus.Information, "got information %#I64x\n", (UINT64)irp->IoStatus.Information);
ok(iosb.Status == 0xdeadbeef, "got status %#x\n", iosb.Status);
- ok(iosb.Information == 0xdeadbeef, "got information %#x\n", iosb.Information);
+ ok(iosb.Information == 0xdeadbeef, "got information %#I64x\n", (UINT64)iosb.Information);
irp->IoStatus.Status = STATUS_SUCCESS;
irp->IoStatus.Information = 123;
IoCompleteRequest(irp, IO_NO_INCREMENT);
ok(iosb.Status == STATUS_SUCCESS, "got status %#x\n", iosb.Status);
- ok(iosb.Information == 123, "got information %#x\n", iosb.Information);
+ ok(iosb.Information == 123, "got information %#I64x\n", (UINT64)iosb.Information);
KeInitializeEvent(&event, NotificationEvent, FALSE);
irp = IoBuildSynchronousFsdRequest(IRP_MJ_FLUSH_BUFFERS, device, NULL, 0, NULL, &event, &iosb);
ok(irp->UserIosb == &iosb, "unexpected UserIosb\n");
ok(!irp->Cancel, "Cancel = %x\n", irp->Cancel);
- ok(!irp->CancelRoutine, "CancelRoutine = %x\n", irp->CancelRoutine);
+ ok(!irp->CancelRoutine, "CancelRoutine = %p\n", irp->CancelRoutine);
ok(irp->UserEvent == &event, "UserEvent = %p\n", irp->UserEvent);
ok(irp->CurrentLocation == 2, "CurrentLocation = %u\n", irp->CurrentLocation);
ok(irp->Tail.Overlay.Thread == (PETHREAD)KeGetCurrentThread(),
@@ -1041,8 +1041,8 @@ static void test_call_driver(DEVICE_OBJECT *device)
irpsp = IoGetNextIrpStackLocation(irp);
ok(irpsp->MajorFunction == IRP_MJ_FLUSH_BUFFERS, "MajorFunction = %u\n", irpsp->MajorFunction);
- ok(!irpsp->DeviceObject, "DeviceObject = %u\n", irpsp->DeviceObject);
- ok(!irpsp->FileObject, "FileObject = %u\n", irpsp->FileObject);
+ ok(!irpsp->DeviceObject, "DeviceObject = %p\n", irpsp->DeviceObject);
+ ok(!irpsp->FileObject, "FileObject = %p\n", irpsp->FileObject);
ok(!irpsp->CompletionRoutine, "CompletionRoutine = %p\n", irpsp->CompletionRoutine);
status = wait_single(&event, 0);
@@ -1118,7 +1118,7 @@ static void test_cancel_irp(DEVICE_OBJECT *device)
ok(irp->CurrentLocation == 1, "CurrentLocation = %u\n", irp->CurrentLocation);
irpsp = IoGetCurrentIrpStackLocation(irp);
- ok(irpsp->DeviceObject == device, "DeviceObject = %u\n", irpsp->DeviceObject);
+ ok(irpsp->DeviceObject == device, "DeviceObject = %p\n", irpsp->DeviceObject);
IoSetCancelRoutine(irp, cancel_irp);
cancel_cnt = 0;
@@ -1432,16 +1432,16 @@ static void check_resource_(int line, ERESOURCE *resource, ULONG exclusive_waite
ULONG count;
count = ExGetExclusiveWaiterCount(resource);
- ok_(__FILE__, line, count == exclusive_waiters,
+ ok_(__FILE__, line)(count == exclusive_waiters,
"expected %u exclusive waiters, got %u\n", exclusive_waiters, count);
count = ExGetSharedWaiterCount(resource);
- ok_(__FILE__, line, count == shared_waiters,
+ ok_(__FILE__, line)(count == shared_waiters,
"expected %u shared waiters, got %u\n", shared_waiters, count);
ret = ExIsResourceAcquiredExclusiveLite(resource);
- ok_(__FILE__, line, ret == exclusive,
+ ok_(__FILE__, line)(ret == exclusive,
"expected exclusive %u, got %u\n", exclusive, ret);
count = ExIsResourceAcquiredSharedLite(resource);
- ok_(__FILE__, line, count == shared_count,
+ ok_(__FILE__, line)(count == shared_count,
"expected shared %u, got %u\n", shared_count, count);
}
#define check_resource(a,b,c,d,e) check_resource_(__LINE__,a,b,c,d,e)
diff --git a/dlls/ntoskrnl.exe/tests/driver.h b/dlls/ntoskrnl.exe/tests/driver.h
index 455695ad36b..01d0991a25c 100644
--- a/dlls/ntoskrnl.exe/tests/driver.h
+++ b/dlls/ntoskrnl.exe/tests/driver.h
@@ -49,14 +49,6 @@
static const char teststr[] = "Wine is not an emulator";
-struct test_data
-{
- int running_under_wine;
- int winetest_report_success;
- int winetest_debug;
- int successes, failures, skipped, todo_successes, todo_failures;
-};
-
struct main_test_input
{
DWORD process_id;
diff --git a/dlls/ntoskrnl.exe/tests/driver_hid.c b/dlls/ntoskrnl.exe/tests/driver_hid.c
index 793b25f3189..ed3e5c17d6f 100644
--- a/dlls/ntoskrnl.exe/tests/driver_hid.c
+++ b/dlls/ntoskrnl.exe/tests/driver_hid.c
@@ -32,10 +32,10 @@
#include "ddk/hidpi.h"
#include "ddk/hidport.h"
+#include "wine/test.h"
#include "wine/list.h"
#include "driver.h"
-#include "utils.h"
static UNICODE_STRING control_symlink;
diff --git a/dlls/ntoskrnl.exe/tests/driver_netio.c b/dlls/ntoskrnl.exe/tests/driver_netio.c
index ea9cfd1a4c5..68dbfd1c5e8 100644
--- a/dlls/ntoskrnl.exe/tests/driver_netio.c
+++ b/dlls/ntoskrnl.exe/tests/driver_netio.c
@@ -32,9 +32,9 @@
#include "ddk/wdm.h"
#include "ddk/wsk.h"
-#include "driver.h"
+#include "wine/test.h"
-#include "utils.h"
+#include "driver.h"
static DRIVER_OBJECT *driver_obj;
static DEVICE_OBJECT *device_obj;
@@ -141,7 +141,7 @@ static void test_wsk_get_address_info(void)
{
struct sockaddr_in *addr = (struct sockaddr_in *)addr_info->ai_addr;
- ok(addr_info->ai_addrlen == sizeof(*addr), "Got unexpected ai_addrlen %u.\n", addr_info->ai_addrlen);
+ ok(addr_info->ai_addrlen == sizeof(*addr), "Got unexpected ai_addrlen %I64u.\n", (UINT64)addr_info->ai_addrlen);
ok(addr->sin_family == AF_INET, "Got unexpected sin_family %u.\n", addr->sin_family);
ok(ntohs(addr->sin_port) == 12345, "Got unexpected sin_port %u.\n", ntohs(addr->sin_port));
ok(ntohl(addr->sin_addr.s_addr) == 0x7f000001, "Got unexpected sin_addr %#x.\n",
diff --git a/dlls/ntoskrnl.exe/tests/driver_pnp.c b/dlls/ntoskrnl.exe/tests/driver_pnp.c
index 98ca2ff7961..cf672f6f397 100644
--- a/dlls/ntoskrnl.exe/tests/driver_pnp.c
+++ b/dlls/ntoskrnl.exe/tests/driver_pnp.c
@@ -29,10 +29,10 @@
#include "winioctl.h"
#include "ddk/wdm.h"
+#include "wine/test.h"
#include "wine/list.h"
#include "driver.h"
-#include "utils.h"
static const GUID bus_class = {0xdeadbeef, 0x29ef, 0x4538, {0xa5, 0xfd, 0xb6, 0x95, 0x73, 0xa3, 0x62, 0xc1}};
static const GUID child_class = {0xdeadbeef, 0x29ef, 0x4538, {0xa5, 0xfd, 0xb6, 0x95, 0x73, 0xa3, 0x62, 0xc2}};
diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c
index 0ef621011d3..c3456e56274 100644
--- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c
@@ -52,8 +52,6 @@ static const GUID GUID_NULL;
static HANDLE device;
-static struct test_data *test_data;
-
static BOOL (WINAPI *pRtlDosPathNameToNtPathName_U)(const WCHAR *, UNICODE_STRING *, WCHAR **, CURDIR *);
static BOOL (WINAPI *pRtlFreeUnicodeString)(UNICODE_STRING *);
static BOOL (WINAPI *pCancelIoEx)(HANDLE, OVERLAPPED *);
@@ -367,27 +365,6 @@ static BOOL start_driver(HANDLE service, BOOL vista_plus)
return TRUE;
}
-static HANDLE okfile;
-
-static void cat_okfile(void)
-{
- char buffer[512];
- DWORD size;
-
- SetFilePointer(okfile, 0, NULL, FILE_BEGIN);
-
- do
- {
- ReadFile(okfile, buffer, sizeof(buffer), &size, NULL);
- printf("%.*s", size, buffer);
- } while (size == sizeof(buffer));
-
- SetFilePointer(okfile, 0, NULL, FILE_BEGIN);
- SetEndOfFile(okfile);
-
- winetest_add_failures(InterlockedExchange(&test_data->failures, 0));
-}
-
static ULONG64 modified_value;
static void main_test(void)
@@ -931,7 +908,7 @@ static void test_driver_netio(struct testsign_context *ctx)
ret = DeleteFileW(filename);
ok(ret, "DeleteFile failed: %u\n", GetLastError());
- cat_okfile();
+ winetest_kernel_check();
}
#ifdef __i386__
@@ -1499,7 +1476,7 @@ static void test_pnp_driver(struct testsign_context *ctx)
unload_driver(service);
CloseServiceHandle(manager);
- cat_okfile();
+ winetest_kernel_check();
GetFullPathNameA("winetest.inf", sizeof(path), path, NULL);
ret = SetupCopyOEMInfA(path, NULL, 0, 0, dest, sizeof(dest), NULL, &filepart);
@@ -2638,7 +2615,7 @@ static void test_hid_driver(struct testsign_context *ctx, DWORD report_id)
unload_driver(service);
CloseServiceHandle(manager);
- cat_okfile();
+ winetest_kernel_check();
GetFullPathNameA("winetest.inf", sizeof(path), path, NULL);
ret = SetupCopyOEMInfA(path, NULL, 0, 0, dest, sizeof(dest), NULL, &filepart);
@@ -2665,7 +2642,6 @@ START_TEST(ntoskrnl)
struct testsign_context ctx;
SC_HANDLE service, service2;
BOOL ret, is_wow64;
- HANDLE mapping;
DWORD written;
pRtlDosPathNameToNtPathName_U = (void *)GetProcAddress(GetModuleHandleA("ntdll"), "RtlDosPathNameToNtPathName_U");
@@ -2685,17 +2661,7 @@ START_TEST(ntoskrnl)
if (!testsign_create_cert(&ctx))
return;
- mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
- 0, sizeof(*test_data), "Global\\winetest_ntoskrnl_section");
- ok(!!mapping, "got error %u\n", GetLastError());
- test_data = MapViewOfFile(mapping, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 1024);
- test_data->running_under_wine = !strcmp(winetest_platform, "wine");
- test_data->winetest_report_success = winetest_report_success;
- test_data->winetest_debug = winetest_debug;
-
- okfile = CreateFileA("C:\\windows\\winetest_ntoskrnl_okfile", GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL);
- ok(okfile != INVALID_HANDLE_VALUE, "failed to create file, error %u\n", GetLastError());
+ winetest_kernel_init();
subtest("driver");
if (!(service = load_driver(&ctx, filename, L"driver.dll", L"WineTestDriver")))
@@ -2737,7 +2703,7 @@ START_TEST(ntoskrnl)
ret = DeleteFileW(filename2);
ok(ret, "DeleteFile failed: %u\n", GetLastError());
- cat_okfile();
+ winetest_kernel_check();
test_driver3(&ctx);
subtest("driver_netio");
@@ -2752,8 +2718,5 @@ START_TEST(ntoskrnl)
out:
testsign_cleanup(&ctx);
- UnmapViewOfFile(test_data);
- CloseHandle(mapping);
- CloseHandle(okfile);
- DeleteFileA("C:\\windows\\winetest_ntoskrnl_okfile");
+ winetest_kernel_cleanup();
}
diff --git a/dlls/ntoskrnl.exe/tests/utils.h b/dlls/ntoskrnl.exe/tests/utils.h
deleted file mode 100644
index 6a0e00428a5..00000000000
--- a/dlls/ntoskrnl.exe/tests/utils.h
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * ntoskrnl.exe testing framework
- *
- * Copyright 2015 Sebastian Lackner
- * Copyright 2015 Michael Müller
- * Copyright 2015 Christian Costa
- * Copyright 2020 Paul Gofman for CodeWeavers
- * Copyright 2020-2021 Zebediah Figura for CodeWeavers
- *
- * 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
- */
-
-static HANDLE okfile;
-static LONG successes;
-static LONG failures;
-static LONG skipped;
-static LONG todo_successes;
-static LONG todo_failures;
-static int todo_level, todo_do_loop;
-static int running_under_wine;
-static int winetest_debug;
-static int winetest_report_success;
-
-static inline void kvprintf(const char *format, __ms_va_list ap)
-{
- static char buffer[512];
- IO_STATUS_BLOCK io;
- int len = vsnprintf(buffer, sizeof(buffer), format, ap);
- ZwWriteFile(okfile, NULL, NULL, NULL, &io, buffer, len, NULL, NULL);
-}
-
-static inline void WINAPIV kprintf(const char *format, ...)
-{
- __ms_va_list valist;
-
- __ms_va_start(valist, format);
- kvprintf(format, valist);
- __ms_va_end(valist);
-}
-
-static inline NTSTATUS winetest_init(void)
-{
- const struct test_data *data;
- SIZE_T size = sizeof(*data);
- OBJECT_ATTRIBUTES attr;
- UNICODE_STRING string;
- IO_STATUS_BLOCK io;
- void *addr = NULL;
- HANDLE section;
- NTSTATUS ret;
-
- RtlInitUnicodeString(&string, L"\\BaseNamedObjects\\winetest_ntoskrnl_section");
- /* OBJ_KERNEL_HANDLE is necessary for the file to be accessible from system threads */
- InitializeObjectAttributes(&attr, &string, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, NULL);
- if ((ret = ZwOpenSection(§ion, SECTION_MAP_READ, &attr)))
- return ret;
-
- if ((ret = ZwMapViewOfSection(section, NtCurrentProcess(), &addr,
- 0, 0, NULL, &size, ViewUnmap, 0, PAGE_READONLY)))
- {
- ZwClose(section);
- return ret;
- }
- data = addr;
- running_under_wine = data->running_under_wine;
- winetest_debug = data->winetest_debug;
- winetest_report_success = data->winetest_report_success;
-
- ZwUnmapViewOfSection(NtCurrentProcess(), addr);
- ZwClose(section);
-
- RtlInitUnicodeString(&string, L"\\??\\C:\\windows\\winetest_ntoskrnl_okfile");
- return ZwOpenFile(&okfile, FILE_APPEND_DATA | SYNCHRONIZE, &attr, &io,
- FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT);
-}
-
-static inline void winetest_cleanup(void)
-{
- struct test_data *data;
- SIZE_T size = sizeof(*data);
- OBJECT_ATTRIBUTES attr;
- UNICODE_STRING string;
- void *addr = NULL;
- HANDLE section;
-
- if (winetest_debug)
- {
- kprintf("%04x:ntoskrnl: %d tests executed (%d marked as todo, %d %s), %d skipped.\n",
- PsGetCurrentProcessId(), successes + failures + todo_successes + todo_failures,
- todo_successes, failures + todo_failures,
- (failures + todo_failures != 1) ? "failures" : "failure", skipped );
- }
-
- RtlInitUnicodeString(&string, L"\\BaseNamedObjects\\winetest_ntoskrnl_section");
- /* OBJ_KERNEL_HANDLE is necessary for the file to be accessible from system threads */
- InitializeObjectAttributes(&attr, &string, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, NULL);
-
- if (!ZwOpenSection(§ion, SECTION_MAP_READ | SECTION_MAP_WRITE, &attr))
- {
- if (!ZwMapViewOfSection(section, NtCurrentProcess(), &addr,
- 0, 0, NULL, &size, ViewUnmap, 0, PAGE_READWRITE))
- {
- data = addr;
-
- InterlockedExchangeAdd(&data->successes, successes);
- InterlockedExchangeAdd(&data->failures, failures);
- InterlockedExchangeAdd(&data->skipped, skipped);
- InterlockedExchangeAdd(&data->todo_successes, todo_successes);
- InterlockedExchangeAdd(&data->todo_failures, todo_failures);
-
- ZwUnmapViewOfSection(NtCurrentProcess(), addr);
- }
- ZwClose(section);
- }
-
- ZwClose(okfile);
-}
-
-static inline void WINAPIV vok_(const char *file, int line, int condition, const char *msg, __ms_va_list args)
-{
- const char *current_file;
-
- if (!(current_file = drv_strrchr(file, '/')) &&
- !(current_file = drv_strrchr(file, '\\')))
- current_file = file;
- else
- current_file++;
-
- if (todo_level)
- {
- if (condition)
- {
- kprintf("%s:%d: Test succeeded inside todo block: ", current_file, line);
- kvprintf(msg, args);
- InterlockedIncrement(&todo_failures);
- }
- else
- {
- if (winetest_debug > 0)
- {
- kprintf("%s:%d: Test marked todo: ", current_file, line);
- kvprintf(msg, args);
- }
- InterlockedIncrement(&todo_successes);
- }
- }
- else
- {
- if (!condition)
- {
- kprintf("%s:%d: Test failed: ", current_file, line);
- kvprintf(msg, args);
- InterlockedIncrement(&failures);
- }
- else
- {
- if (winetest_report_success)
- kprintf("%s:%d: Test succeeded\n", current_file, line);
- InterlockedIncrement(&successes);
- }
- }
-}
-
-static inline void WINAPIV ok_(const char *file, int line, int condition, const char *msg, ...)
-{
- __ms_va_list args;
- __ms_va_start(args, msg);
- vok_(file, line, condition, msg, args);
- __ms_va_end(args);
-}
-
-static inline void vskip_(const char *file, int line, const char *msg, __ms_va_list args)
-{
- const char *current_file;
-
- if (!(current_file = drv_strrchr(file, '/')) &&
- !(current_file = drv_strrchr(file, '\\')))
- current_file = file;
- else
- current_file++;
-
- kprintf("%s:%d: Tests skipped: ", current_file, line);
- kvprintf(msg, args);
- skipped++;
-}
-
-static inline void WINAPIV win_skip_(const char *file, int line, const char *msg, ...)
-{
- __ms_va_list args;
- __ms_va_start(args, msg);
- if (running_under_wine)
- vok_(file, line, 0, msg, args);
- else
- vskip_(file, line, msg, args);
- __ms_va_end(args);
-}
-
-static inline void WINAPIV trace_(const char *file, int line, const char *msg, ...)
-{
- const char *current_file;
- __ms_va_list args;
-
- if (!(current_file = drv_strrchr(file, '/')) &&
- !(current_file = drv_strrchr(file, '\\')))
- current_file = file;
- else
- current_file++;
-
- __ms_va_start(args, msg);
- kprintf("%s:%d: ", current_file, line);
- kvprintf(msg, args);
- __ms_va_end(args);
-}
-
-static inline void winetest_start_todo( int is_todo )
-{
- todo_level = (todo_level << 1) | (is_todo != 0);
- todo_do_loop=1;
-}
-
-static inline int winetest_loop_todo(void)
-{
- int do_loop=todo_do_loop;
- todo_do_loop=0;
- return do_loop;
-}
-
-static inline void winetest_end_todo(void)
-{
- todo_level >>= 1;
-}
-
-static inline int broken(int condition)
-{
- return !running_under_wine && condition;
-}
-
-#define ok(condition, ...) ok_(__FILE__, __LINE__, condition, __VA_ARGS__)
-#define todo_if(is_todo) for (winetest_start_todo(is_todo); \
- winetest_loop_todo(); \
- winetest_end_todo())
-#define todo_wine todo_if(running_under_wine)
-#define todo_wine_if(is_todo) todo_if((is_todo) && running_under_wine)
-#define win_skip(...) win_skip_(__FILE__, __LINE__, __VA_ARGS__)
-#define trace(...) trace_(__FILE__, __LINE__, __VA_ARGS__)
diff --git a/include/wine/test.h b/include/wine/test.h
index 8073071d262..ede648fb717 100644
--- a/include/wine/test.h
+++ b/include/wine/test.h
@@ -25,6 +25,9 @@
#include <stdlib.h>
#include <windef.h>
#include <winbase.h>
+#ifdef WINETEST_KERNEL
+#include <ddk/wdm.h>
+#endif /* WINETEST_KERNEL */
#include <wine/debug.h>
#ifdef __WINE_CONFIG_H
@@ -59,6 +62,9 @@ extern int winetest_mute_threshold;
/* current platform */
extern const char *winetest_platform;
+/* output file for kernel tests */
+extern HANDLE okfile;
+
extern void winetest_set_location( const char* file, int line );
extern void winetest_subtest( const char* name );
extern void winetest_ignore_exceptions( BOOL ignore );
@@ -68,6 +74,9 @@ extern void winetest_end_todo(void);
extern int winetest_get_mainargs( char*** pargv );
extern LONG winetest_get_failures(void);
extern void winetest_add_failures( LONG new_failures );
+extern void winetest_kernel_init( void );
+extern void winetest_kernel_check( void );
+extern void winetest_kernel_cleanup( void );
extern void winetest_wait_child_process( HANDLE process );
#ifdef STANDALONE
@@ -214,7 +223,8 @@ DWORD winetest_start_time, winetest_last_time;
int winetest_interactive = 0;
/* current platform */
-const char *winetest_platform = "windows";
+static char winetest_platform_buf[256] = "windows";
+const char *winetest_platform = winetest_platform_buf;
/* report successful tests (BOOL) */
int winetest_report_success = 0;
@@ -226,7 +236,9 @@ int winetest_mute_threshold = 42;
static int winetest_argc;
static char** winetest_argv;
+#ifndef WINETEST_KERNEL
static const struct test *current_test; /* test currently being run */
+#endif /* WINETEST_KERNEL */
static LONG successes; /* number of successful tests */
static LONG failures; /* number of failures */
@@ -240,9 +252,15 @@ static LONG muted_todo_successes; /* same as todo_successes but silent */
/* counts how many times a given line printed a message */
static LONG line_counters[16384];
+/* output file for driver tests */
+HANDLE okfile;
+
/* The following data must be kept track of on a per-thread basis */
struct tls_data
{
+#ifdef WINETEST_KERNEL
+ HANDLE thread;
+#endif /* WINETEST_KERNEL */
const char* current_file; /* file of current check */
int current_line; /* line of current check */
unsigned int todo_level; /* current todo nesting level */
@@ -252,6 +270,38 @@ struct tls_data
char context[8][128]; /* data to print before messages */
unsigned int context_count; /* number of context prefixes */
};
+
+#ifdef WINETEST_KERNEL
+
+static KSPIN_LOCK tls_data_lock;
+static struct tls_data tls_data_pool[128];
+static DWORD tls_data_count;
+
+static struct tls_data *get_tls_data(void)
+{
+ static struct tls_data tls_overflow;
+ struct tls_data *data;
+ HANDLE thread = PsGetCurrentThreadId();
+ KIRQL irql;
+
+ KeAcquireSpinLock(&tls_data_lock, &irql);
+ for (data = tls_data_pool; data != tls_data_pool + tls_data_count; ++data)
+ if (data->thread == thread) break;
+ if (data == tls_data_pool + ARRAY_SIZE(tls_data_pool))
+ data = &tls_overflow;
+ else if (data == tls_data_pool + tls_data_count)
+ {
+ data->thread = thread;
+ data->str_pos = data->strings;
+ tls_data_count++;
+ }
+ KeReleaseSpinLock(&tls_data_lock, irql);
+
+ return data;
+}
+
+#else /* WINETEST_KERNEL */
+
static DWORD tls_index;
static struct tls_data *get_tls_data(void)
@@ -277,6 +327,7 @@ static void exit_process( int code )
ExitProcess( code );
}
+#endif /* WINETEST_KERNEL */
void winetest_set_location( const char* file, int line )
{
@@ -291,6 +342,36 @@ void winetest_set_location( const char* file, int line )
data->current_line=line;
}
+#ifdef WINETEST_KERNEL
+
+static inline void __winetest_vprintf(const char *format, __ms_va_list ap)
+{
+ static char buffer[512];
+ IO_STATUS_BLOCK io;
+ int len = vsnprintf(buffer, sizeof(buffer), format, ap);
+ ZwWriteFile(okfile, NULL, NULL, NULL, &io, buffer, len, NULL, NULL);
+}
+
+static inline void WINAPIV __winetest_printf(const char *format, ...)
+{
+ __ms_va_list valist;
+
+ __ms_va_start(valist, format);
+ __winetest_vprintf(format, valist);
+ __ms_va_end(valist);
+}
+
+const char *winetest_elapsed(void)
+{
+ if (!winetest_time) return "";
+ return "0.000";
+}
+
+#else /* WINETEST_KERNEL */
+
+#define __winetest_printf printf
+#define __winetest_vprintf vprintf
+
const char *winetest_elapsed(void)
{
DWORD now;
@@ -300,15 +381,17 @@ const char *winetest_elapsed(void)
return wine_dbg_sprintf( "%.3f", (now - winetest_start_time) / 1000.0);
}
+#endif /* WINETEST_KERNEL */
+
static void __winetest_cdecl winetest_printf( const char *msg, ... ) __WINE_PRINTF_ATTR(1,2);
static void __winetest_cdecl winetest_printf( const char *msg, ... )
{
struct tls_data *data = get_tls_data();
__winetest_va_list valist;
- printf( "%s:%d:%s ", data->current_file, data->current_line, winetest_elapsed() );
+ __winetest_printf( "%s:%d:%s ", data->current_file, data->current_line, winetest_elapsed() );
__winetest_va_start( valist, msg );
- vprintf( msg, valist );
+ __winetest_vprintf( msg, valist );
__winetest_va_end( valist );
}
static void __winetest_cdecl winetest_print_context( const char *msgtype )
@@ -318,7 +401,7 @@ static void __winetest_cdecl winetest_print_context( const char *msgtype )
winetest_printf( "%s", msgtype );
for (i = 0; i < data->context_count; ++i)
- printf( "%s: ", data->context[i] );
+ __winetest_printf( "%s: ", data->context[i] );
}
void winetest_subtest( const char* name )
@@ -372,7 +455,7 @@ int winetest_vok( int condition, const char *msg, __winetest_va_list args )
if (condition)
{
winetest_print_context( "Test succeeded inside todo block: " );
- vprintf(msg, args);
+ __winetest_vprintf(msg, args);
InterlockedIncrement(&todo_failures);
return 0;
}
@@ -384,7 +467,7 @@ int winetest_vok( int condition, const char *msg, __winetest_va_list args )
if (winetest_debug > 0)
{
winetest_print_context( "Test marked todo: " );
- vprintf(msg, args);
+ __winetest_vprintf(msg, args);
}
InterlockedIncrement(&todo_successes);
}
@@ -398,17 +481,18 @@ int winetest_vok( int condition, const char *msg, __winetest_va_list args )
if (!condition)
{
winetest_print_context( "Test failed: " );
- vprintf(msg, args);
+ __winetest_vprintf(msg, args);
InterlockedIncrement(&failures);
return 0;
}
else
{
- if (winetest_report_success ||
- (winetest_time && GetTickCount() >= winetest_last_time + 1000))
- {
+ if (winetest_report_success)
winetest_printf("Test succeeded\n");
- }
+#ifndef WINETEST_KERNEL
+ else if (winetest_time && GetTickCount() >= winetest_last_time + 1000)
+ winetest_printf("Test succeeded\n");
+#endif /* WINETEST_KERNEL */
InterlockedIncrement(&successes);
return 1;
}
@@ -434,7 +518,7 @@ void __winetest_cdecl winetest_trace( const char *msg, ... )
{
winetest_print_context( "" );
__winetest_va_start(valist, msg);
- vprintf( msg, valist );
+ __winetest_vprintf( msg, valist );
__winetest_va_end(valist);
}
else
@@ -446,7 +530,7 @@ void winetest_vskip( const char *msg, __winetest_va_list args )
if (winetest_add_line() < winetest_mute_threshold)
{
winetest_print_context( "Tests skipped: " );
- vprintf(msg, args);
+ __winetest_vprintf(msg, args);
InterlockedIncrement(&skipped);
}
else
@@ -533,6 +617,155 @@ void winetest_add_failures( LONG new_failures )
InterlockedIncrement( &failures );
}
+struct winetest_kernel_data
+{
+ char winetest_platform[256];
+ int running_under_wine;
+ int winetest_report_success;
+ int winetest_debug;
+ int failures;
+ int todo_failures;
+};
+
+#ifdef WINETEST_KERNEL
+
+static int running_under_wine;
+
+static inline NTSTATUS winetest_init(void)
+{
+ const struct winetest_kernel_data *data;
+ SIZE_T size = sizeof(*data);
+ OBJECT_ATTRIBUTES attr;
+ UNICODE_STRING string;
+ IO_STATUS_BLOCK io;
+ void *addr = NULL;
+ HANDLE section;
+ NTSTATUS ret;
+
+ KeInitializeSpinLock(&tls_data_lock);
+
+ RtlInitUnicodeString(&string, L"\\BaseNamedObjects\\winetest_kernel_section");
+ /* OBJ_KERNEL_HANDLE is necessary for the file to be accessible from system threads */
+ InitializeObjectAttributes(&attr, &string, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, NULL);
+ if ((ret = ZwOpenSection(§ion, SECTION_MAP_READ, &attr)))
+ return ret;
+
+ if ((ret = ZwMapViewOfSection(section, NtCurrentProcess(), &addr,
+ 0, 0, NULL, &size, ViewUnmap, 0, PAGE_READONLY)))
+ {
+ ZwClose(okfile);
+ ZwClose(section);
+ return ret;
+ }
+ data = addr;
+ running_under_wine = data->running_under_wine;
+ winetest_debug = data->winetest_debug;
+ winetest_report_success = data->winetest_report_success;
+ strcpy(winetest_platform_buf, data->winetest_platform);
+
+ ZwUnmapViewOfSection(NtCurrentProcess(), addr);
+ ZwClose(section);
+
+ RtlInitUnicodeString(&string, L"\\??\\C:\\windows\\winetest_kernel_okfile");
+ return ZwOpenFile(&okfile, FILE_APPEND_DATA | SYNCHRONIZE, &attr, &io,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT);
+}
+
+static inline void winetest_cleanup(void)
+{
+ struct winetest_kernel_data *data;
+ SIZE_T size = sizeof(*data);
+ OBJECT_ATTRIBUTES attr;
+ UNICODE_STRING string;
+ void *addr = NULL;
+ HANDLE section;
+
+ if (winetest_debug)
+ {
+ if (muted_todo_successes || muted_skipped || muted_traces)
+ __winetest_printf( "%04x:ntoskrnl:%s Silenced %d todos, %d skips and %d traces.\n",
+ (DWORD)(ULONG_PTR)PsGetCurrentProcessId(), winetest_elapsed(),
+ muted_todo_successes, muted_skipped, muted_traces);
+ __winetest_printf( "%04x:ntoskrnl:%s %d tests executed (%d marked as todo, %d %s), %d skipped.\n",
+ (DWORD)(ULONG_PTR)PsGetCurrentProcessId(), winetest_elapsed(),
+ successes + failures + todo_successes + todo_failures,
+ todo_successes, failures + todo_failures,
+ (failures + todo_failures != 1) ? "failures" : "failure",
+ skipped );
+ }
+
+ RtlInitUnicodeString(&string, L"\\BaseNamedObjects\\winetest_kernel_section");
+ /* OBJ_KERNEL_HANDLE is necessary for the file to be accessible from system threads */
+ InitializeObjectAttributes(&attr, &string, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, NULL);
+
+ if (!ZwOpenSection(§ion, SECTION_MAP_READ | SECTION_MAP_WRITE, &attr))
+ {
+ if (!ZwMapViewOfSection(section, NtCurrentProcess(), &addr,
+ 0, 0, NULL, &size, ViewUnmap, 0, PAGE_READWRITE))
+ {
+ data = addr;
+
+ InterlockedExchangeAdd(&data->failures, failures);
+ InterlockedExchangeAdd(&data->todo_failures, todo_failures);
+
+ ZwUnmapViewOfSection(NtCurrentProcess(), addr);
+ }
+ ZwClose(section);
+ }
+
+ ZwClose(okfile);
+}
+
+#else /* WINETEST_KERNEL */
+
+static HANDLE winetest_mapping;
+static struct winetest_kernel_data *kernel_data;
+
+void winetest_kernel_init(void)
+{
+ winetest_mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0,
+ sizeof(*kernel_data), "Global\\winetest_kernel_section");
+ ok(!!winetest_mapping, "got error %u\n", GetLastError());
+ kernel_data = MapViewOfFile(winetest_mapping, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 1024);
+ ok(strlen(winetest_platform) < 256, "winetest_platform expectedly large!\n");
+ strcpy(kernel_data->winetest_platform, winetest_platform);
+ kernel_data->running_under_wine = !strcmp(winetest_platform, "wine");
+ kernel_data->winetest_report_success = winetest_report_success;
+ kernel_data->winetest_debug = winetest_debug;
+
+ okfile = CreateFileA("C:\\windows\\winetest_kernel_okfile", GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL);
+ ok(okfile != INVALID_HANDLE_VALUE, "failed to create file, error %u\n", GetLastError());
+}
+
+void winetest_kernel_check(void)
+{
+ char buffer[512];
+ DWORD size;
+
+ SetFilePointer(okfile, 0, NULL, FILE_BEGIN);
+
+ do
+ {
+ ReadFile(okfile, buffer, sizeof(buffer), &size, NULL);
+ printf("%.*s", size, buffer);
+ } while (size == sizeof(buffer));
+
+ SetFilePointer(okfile, 0, NULL, FILE_BEGIN);
+ SetEndOfFile(okfile);
+
+ InterlockedExchangeAdd(&failures, InterlockedExchange(&kernel_data->failures, 0));
+ InterlockedExchangeAdd(&todo_failures, InterlockedExchange(&kernel_data->todo_failures, 0));
+}
+
+void winetest_kernel_cleanup(void)
+{
+ UnmapViewOfFile(kernel_data);
+ CloseHandle(winetest_mapping);
+ CloseHandle(okfile);
+ DeleteFileA("C:\\windows\\winetest_kernel_okfile");
+}
+
void winetest_wait_child_process( HANDLE process )
{
DWORD ret;
@@ -702,6 +935,7 @@ int main( int argc, char **argv )
return run_test(argv[1]);
}
+#endif /* WINETEST_KERNEL */
#endif /* STANDALONE */
#endif /* __WINE_WINE_TEST_H */
--
2.32.0
1
0
01 Jul '21
So that we can have full featured wine test with thread local data and
context.
Signed-off-by: Rémi Bernon <rbernon(a)codeweavers.com>
---
I don't know what was going on with [1] and following patches but Marvin
reported a succeeded todo_wine on a test that isn't even marked todo.
I suspect there's some sort of thread conflict happening and this should
fix such issues, see [2] without vs [3] with this patch.
We also miss winetest_push_context / winetest_pop_context and all the
possible improvements done to winetest, so I think it's good to have
this factored together.
I've left winetest_elapsed aside, as it requires KeQueryTickCount, which
isn't exported on Windows. I don't think it's very important to have it
anyway, as we don't even pass winetest_time yet to the driver.
Sorry in advance for the amount of time this will take if Marvin decides
to run everything...
[1] https://testbot.winehq.org/JobDetails.pl?Key=93428
[2] https://testbot.winehq.org/JobDetails.pl?Key=93447
[3] https://testbot.winehq.org/JobDetails.pl?Key=93452
dlls/ntoskrnl.exe/tests/Makefile.in | 16 +-
dlls/ntoskrnl.exe/tests/driver.c | 36 ++--
dlls/ntoskrnl.exe/tests/driver.h | 8 -
dlls/ntoskrnl.exe/tests/driver_hid.c | 2 +-
dlls/ntoskrnl.exe/tests/driver_netio.c | 6 +-
dlls/ntoskrnl.exe/tests/driver_pnp.c | 2 +-
dlls/ntoskrnl.exe/tests/ntoskrnl.c | 49 +----
dlls/ntoskrnl.exe/tests/utils.h | 257 ------------------------
include/wine/test.h | 260 +++++++++++++++++++++++--
9 files changed, 287 insertions(+), 349 deletions(-)
delete mode 100644 dlls/ntoskrnl.exe/tests/utils.h
diff --git a/dlls/ntoskrnl.exe/tests/Makefile.in b/dlls/ntoskrnl.exe/tests/Makefile.in
index 863fad30f63..037f0fda637 100644
--- a/dlls/ntoskrnl.exe/tests/Makefile.in
+++ b/dlls/ntoskrnl.exe/tests/Makefile.in
@@ -1,17 +1,23 @@
TESTDLL = ntoskrnl.exe
IMPORTS = advapi32 crypt32 newdev setupapi user32 wintrust ws2_32 hid
-driver_IMPORTS = winecrt0 ntoskrnl
+driver_IMPORTS = winecrt0 ntoskrnl hal
+driver_EXTRADEFS = -DSTANDALONE -DWINETEST_KERNEL
driver_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native
-driver2_IMPORTS = winecrt0 ntoskrnl
+driver2_IMPORTS = winecrt0 ntoskrnl hal
+driver2_EXTRADEFS = -DSTANDALONE -DWINETEST_KERNEL
driver2_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native
-driver3_IMPORTS = winecrt0 ntoskrnl
+driver3_IMPORTS = winecrt0 ntoskrnl hal
+driver3_EXTRADEFS = -DSTANDALONE -DWINETEST_KERNEL
driver3_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native
-driver_hid_IMPORTS = winecrt0 ntoskrnl hidclass
+driver_hid_IMPORTS = winecrt0 ntoskrnl hal hidclass
+driver_hid_EXTRADEFS = -DSTANDALONE -DWINETEST_KERNEL
driver_hid_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native
-driver_netio_IMPORTS = winecrt0 ntoskrnl netio
+driver_netio_IMPORTS = winecrt0 ntoskrnl hal netio
+driver_netio_EXTRADEFS = -DSTANDALONE -DWINETEST_KERNEL
driver_netio_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native
driver_pnp_IMPORTS = winecrt0 ntoskrnl hal
+driver_pnp_EXTRADEFS = -DSTANDALONE -DWINETEST_KERNEL
driver_pnp_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native
SOURCES = \
diff --git a/dlls/ntoskrnl.exe/tests/driver.c b/dlls/ntoskrnl.exe/tests/driver.c
index 94139b4b654..8c5ac6d89d4 100644
--- a/dlls/ntoskrnl.exe/tests/driver.c
+++ b/dlls/ntoskrnl.exe/tests/driver.c
@@ -33,9 +33,9 @@
#include "ddk/ntifs.h"
#include "ddk/wdm.h"
-#include "driver.h"
+#include "wine/test.h"
-#include "utils.h"
+#include "driver.h"
/* memcmp() isn't exported from ntoskrnl on i386 */
static int kmemcmp( const void *ptr1, const void *ptr2, size_t n )
@@ -999,41 +999,41 @@ static void test_call_driver(DEVICE_OBJECT *device)
irp = IoBuildAsynchronousFsdRequest(IRP_MJ_FLUSH_BUFFERS, device, NULL, 0, NULL, &iosb);
ok(irp->UserIosb == &iosb, "unexpected UserIosb\n");
ok(!irp->Cancel, "Cancel = %x\n", irp->Cancel);
- ok(!irp->CancelRoutine, "CancelRoutine = %x\n", irp->CancelRoutine);
+ ok(!irp->CancelRoutine, "CancelRoutine = %p\n", irp->CancelRoutine);
ok(!irp->UserEvent, "UserEvent = %p\n", irp->UserEvent);
ok(irp->CurrentLocation == 2, "CurrentLocation = %u\n", irp->CurrentLocation);
ok(irp->Tail.Overlay.Thread == (PETHREAD)KeGetCurrentThread(),
"IRP thread is not the current thread\n");
ok(!irp->IoStatus.Status, "got status %#x\n", irp->IoStatus.Status);
- ok(!irp->IoStatus.Information, "got information %#x\n", irp->IoStatus.Information);
+ ok(!irp->IoStatus.Information, "got information %#I64x\n", (UINT64)irp->IoStatus.Information);
ok(iosb.Status == 0xdeadbeef, "got status %#x\n", iosb.Status);
- ok(iosb.Information == 0xdeadbeef, "got information %#x\n", iosb.Information);
+ ok(iosb.Information == 0xdeadbeef, "got information %#I64x\n", (UINT64)iosb.Information);
irpsp = IoGetNextIrpStackLocation(irp);
ok(irpsp->MajorFunction == IRP_MJ_FLUSH_BUFFERS, "MajorFunction = %u\n", irpsp->MajorFunction);
- ok(!irpsp->DeviceObject, "DeviceObject = %u\n", irpsp->DeviceObject);
- ok(!irpsp->FileObject, "FileObject = %u\n", irpsp->FileObject);
+ ok(!irpsp->DeviceObject, "DeviceObject = %p\n", irpsp->DeviceObject);
+ ok(!irpsp->FileObject, "FileObject = %p\n", irpsp->FileObject);
ok(!irpsp->CompletionRoutine, "CompletionRoutine = %p\n", irpsp->CompletionRoutine);
status = IoCallDriver(device, irp);
ok(status == STATUS_PENDING, "IoCallDriver returned %#x\n", status);
ok(!irp->IoStatus.Status, "got status %#x\n", irp->IoStatus.Status);
- ok(!irp->IoStatus.Information, "got information %#x\n", irp->IoStatus.Information);
+ ok(!irp->IoStatus.Information, "got information %#I64x\n", (UINT64)irp->IoStatus.Information);
ok(iosb.Status == 0xdeadbeef, "got status %#x\n", iosb.Status);
- ok(iosb.Information == 0xdeadbeef, "got information %#x\n", iosb.Information);
+ ok(iosb.Information == 0xdeadbeef, "got information %#I64x\n", (UINT64)iosb.Information);
irp->IoStatus.Status = STATUS_SUCCESS;
irp->IoStatus.Information = 123;
IoCompleteRequest(irp, IO_NO_INCREMENT);
ok(iosb.Status == STATUS_SUCCESS, "got status %#x\n", iosb.Status);
- ok(iosb.Information == 123, "got information %#x\n", iosb.Information);
+ ok(iosb.Information == 123, "got information %#I64x\n", (UINT64)iosb.Information);
KeInitializeEvent(&event, NotificationEvent, FALSE);
irp = IoBuildSynchronousFsdRequest(IRP_MJ_FLUSH_BUFFERS, device, NULL, 0, NULL, &event, &iosb);
ok(irp->UserIosb == &iosb, "unexpected UserIosb\n");
ok(!irp->Cancel, "Cancel = %x\n", irp->Cancel);
- ok(!irp->CancelRoutine, "CancelRoutine = %x\n", irp->CancelRoutine);
+ ok(!irp->CancelRoutine, "CancelRoutine = %p\n", irp->CancelRoutine);
ok(irp->UserEvent == &event, "UserEvent = %p\n", irp->UserEvent);
ok(irp->CurrentLocation == 2, "CurrentLocation = %u\n", irp->CurrentLocation);
ok(irp->Tail.Overlay.Thread == (PETHREAD)KeGetCurrentThread(),
@@ -1041,8 +1041,8 @@ static void test_call_driver(DEVICE_OBJECT *device)
irpsp = IoGetNextIrpStackLocation(irp);
ok(irpsp->MajorFunction == IRP_MJ_FLUSH_BUFFERS, "MajorFunction = %u\n", irpsp->MajorFunction);
- ok(!irpsp->DeviceObject, "DeviceObject = %u\n", irpsp->DeviceObject);
- ok(!irpsp->FileObject, "FileObject = %u\n", irpsp->FileObject);
+ ok(!irpsp->DeviceObject, "DeviceObject = %p\n", irpsp->DeviceObject);
+ ok(!irpsp->FileObject, "FileObject = %p\n", irpsp->FileObject);
ok(!irpsp->CompletionRoutine, "CompletionRoutine = %p\n", irpsp->CompletionRoutine);
status = wait_single(&event, 0);
@@ -1118,7 +1118,7 @@ static void test_cancel_irp(DEVICE_OBJECT *device)
ok(irp->CurrentLocation == 1, "CurrentLocation = %u\n", irp->CurrentLocation);
irpsp = IoGetCurrentIrpStackLocation(irp);
- ok(irpsp->DeviceObject == device, "DeviceObject = %u\n", irpsp->DeviceObject);
+ ok(irpsp->DeviceObject == device, "DeviceObject = %p\n", irpsp->DeviceObject);
IoSetCancelRoutine(irp, cancel_irp);
cancel_cnt = 0;
@@ -1432,16 +1432,16 @@ static void check_resource_(int line, ERESOURCE *resource, ULONG exclusive_waite
ULONG count;
count = ExGetExclusiveWaiterCount(resource);
- ok_(__FILE__, line, count == exclusive_waiters,
+ ok_(__FILE__, line)(count == exclusive_waiters,
"expected %u exclusive waiters, got %u\n", exclusive_waiters, count);
count = ExGetSharedWaiterCount(resource);
- ok_(__FILE__, line, count == shared_waiters,
+ ok_(__FILE__, line)(count == shared_waiters,
"expected %u shared waiters, got %u\n", shared_waiters, count);
ret = ExIsResourceAcquiredExclusiveLite(resource);
- ok_(__FILE__, line, ret == exclusive,
+ ok_(__FILE__, line)(ret == exclusive,
"expected exclusive %u, got %u\n", exclusive, ret);
count = ExIsResourceAcquiredSharedLite(resource);
- ok_(__FILE__, line, count == shared_count,
+ ok_(__FILE__, line)(count == shared_count,
"expected shared %u, got %u\n", shared_count, count);
}
#define check_resource(a,b,c,d,e) check_resource_(__LINE__,a,b,c,d,e)
diff --git a/dlls/ntoskrnl.exe/tests/driver.h b/dlls/ntoskrnl.exe/tests/driver.h
index 455695ad36b..01d0991a25c 100644
--- a/dlls/ntoskrnl.exe/tests/driver.h
+++ b/dlls/ntoskrnl.exe/tests/driver.h
@@ -49,14 +49,6 @@
static const char teststr[] = "Wine is not an emulator";
-struct test_data
-{
- int running_under_wine;
- int winetest_report_success;
- int winetest_debug;
- int successes, failures, skipped, todo_successes, todo_failures;
-};
-
struct main_test_input
{
DWORD process_id;
diff --git a/dlls/ntoskrnl.exe/tests/driver_hid.c b/dlls/ntoskrnl.exe/tests/driver_hid.c
index 793b25f3189..ed3e5c17d6f 100644
--- a/dlls/ntoskrnl.exe/tests/driver_hid.c
+++ b/dlls/ntoskrnl.exe/tests/driver_hid.c
@@ -32,10 +32,10 @@
#include "ddk/hidpi.h"
#include "ddk/hidport.h"
+#include "wine/test.h"
#include "wine/list.h"
#include "driver.h"
-#include "utils.h"
static UNICODE_STRING control_symlink;
diff --git a/dlls/ntoskrnl.exe/tests/driver_netio.c b/dlls/ntoskrnl.exe/tests/driver_netio.c
index ea9cfd1a4c5..68dbfd1c5e8 100644
--- a/dlls/ntoskrnl.exe/tests/driver_netio.c
+++ b/dlls/ntoskrnl.exe/tests/driver_netio.c
@@ -32,9 +32,9 @@
#include "ddk/wdm.h"
#include "ddk/wsk.h"
-#include "driver.h"
+#include "wine/test.h"
-#include "utils.h"
+#include "driver.h"
static DRIVER_OBJECT *driver_obj;
static DEVICE_OBJECT *device_obj;
@@ -141,7 +141,7 @@ static void test_wsk_get_address_info(void)
{
struct sockaddr_in *addr = (struct sockaddr_in *)addr_info->ai_addr;
- ok(addr_info->ai_addrlen == sizeof(*addr), "Got unexpected ai_addrlen %u.\n", addr_info->ai_addrlen);
+ ok(addr_info->ai_addrlen == sizeof(*addr), "Got unexpected ai_addrlen %I64u.\n", (UINT64)addr_info->ai_addrlen);
ok(addr->sin_family == AF_INET, "Got unexpected sin_family %u.\n", addr->sin_family);
ok(ntohs(addr->sin_port) == 12345, "Got unexpected sin_port %u.\n", ntohs(addr->sin_port));
ok(ntohl(addr->sin_addr.s_addr) == 0x7f000001, "Got unexpected sin_addr %#x.\n",
diff --git a/dlls/ntoskrnl.exe/tests/driver_pnp.c b/dlls/ntoskrnl.exe/tests/driver_pnp.c
index 98ca2ff7961..cf672f6f397 100644
--- a/dlls/ntoskrnl.exe/tests/driver_pnp.c
+++ b/dlls/ntoskrnl.exe/tests/driver_pnp.c
@@ -29,10 +29,10 @@
#include "winioctl.h"
#include "ddk/wdm.h"
+#include "wine/test.h"
#include "wine/list.h"
#include "driver.h"
-#include "utils.h"
static const GUID bus_class = {0xdeadbeef, 0x29ef, 0x4538, {0xa5, 0xfd, 0xb6, 0x95, 0x73, 0xa3, 0x62, 0xc1}};
static const GUID child_class = {0xdeadbeef, 0x29ef, 0x4538, {0xa5, 0xfd, 0xb6, 0x95, 0x73, 0xa3, 0x62, 0xc2}};
diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c
index 0ef621011d3..c3456e56274 100644
--- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c
@@ -52,8 +52,6 @@ static const GUID GUID_NULL;
static HANDLE device;
-static struct test_data *test_data;
-
static BOOL (WINAPI *pRtlDosPathNameToNtPathName_U)(const WCHAR *, UNICODE_STRING *, WCHAR **, CURDIR *);
static BOOL (WINAPI *pRtlFreeUnicodeString)(UNICODE_STRING *);
static BOOL (WINAPI *pCancelIoEx)(HANDLE, OVERLAPPED *);
@@ -367,27 +365,6 @@ static BOOL start_driver(HANDLE service, BOOL vista_plus)
return TRUE;
}
-static HANDLE okfile;
-
-static void cat_okfile(void)
-{
- char buffer[512];
- DWORD size;
-
- SetFilePointer(okfile, 0, NULL, FILE_BEGIN);
-
- do
- {
- ReadFile(okfile, buffer, sizeof(buffer), &size, NULL);
- printf("%.*s", size, buffer);
- } while (size == sizeof(buffer));
-
- SetFilePointer(okfile, 0, NULL, FILE_BEGIN);
- SetEndOfFile(okfile);
-
- winetest_add_failures(InterlockedExchange(&test_data->failures, 0));
-}
-
static ULONG64 modified_value;
static void main_test(void)
@@ -931,7 +908,7 @@ static void test_driver_netio(struct testsign_context *ctx)
ret = DeleteFileW(filename);
ok(ret, "DeleteFile failed: %u\n", GetLastError());
- cat_okfile();
+ winetest_kernel_check();
}
#ifdef __i386__
@@ -1499,7 +1476,7 @@ static void test_pnp_driver(struct testsign_context *ctx)
unload_driver(service);
CloseServiceHandle(manager);
- cat_okfile();
+ winetest_kernel_check();
GetFullPathNameA("winetest.inf", sizeof(path), path, NULL);
ret = SetupCopyOEMInfA(path, NULL, 0, 0, dest, sizeof(dest), NULL, &filepart);
@@ -2638,7 +2615,7 @@ static void test_hid_driver(struct testsign_context *ctx, DWORD report_id)
unload_driver(service);
CloseServiceHandle(manager);
- cat_okfile();
+ winetest_kernel_check();
GetFullPathNameA("winetest.inf", sizeof(path), path, NULL);
ret = SetupCopyOEMInfA(path, NULL, 0, 0, dest, sizeof(dest), NULL, &filepart);
@@ -2665,7 +2642,6 @@ START_TEST(ntoskrnl)
struct testsign_context ctx;
SC_HANDLE service, service2;
BOOL ret, is_wow64;
- HANDLE mapping;
DWORD written;
pRtlDosPathNameToNtPathName_U = (void *)GetProcAddress(GetModuleHandleA("ntdll"), "RtlDosPathNameToNtPathName_U");
@@ -2685,17 +2661,7 @@ START_TEST(ntoskrnl)
if (!testsign_create_cert(&ctx))
return;
- mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
- 0, sizeof(*test_data), "Global\\winetest_ntoskrnl_section");
- ok(!!mapping, "got error %u\n", GetLastError());
- test_data = MapViewOfFile(mapping, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 1024);
- test_data->running_under_wine = !strcmp(winetest_platform, "wine");
- test_data->winetest_report_success = winetest_report_success;
- test_data->winetest_debug = winetest_debug;
-
- okfile = CreateFileA("C:\\windows\\winetest_ntoskrnl_okfile", GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL);
- ok(okfile != INVALID_HANDLE_VALUE, "failed to create file, error %u\n", GetLastError());
+ winetest_kernel_init();
subtest("driver");
if (!(service = load_driver(&ctx, filename, L"driver.dll", L"WineTestDriver")))
@@ -2737,7 +2703,7 @@ START_TEST(ntoskrnl)
ret = DeleteFileW(filename2);
ok(ret, "DeleteFile failed: %u\n", GetLastError());
- cat_okfile();
+ winetest_kernel_check();
test_driver3(&ctx);
subtest("driver_netio");
@@ -2752,8 +2718,5 @@ START_TEST(ntoskrnl)
out:
testsign_cleanup(&ctx);
- UnmapViewOfFile(test_data);
- CloseHandle(mapping);
- CloseHandle(okfile);
- DeleteFileA("C:\\windows\\winetest_ntoskrnl_okfile");
+ winetest_kernel_cleanup();
}
diff --git a/dlls/ntoskrnl.exe/tests/utils.h b/dlls/ntoskrnl.exe/tests/utils.h
deleted file mode 100644
index 6a0e00428a5..00000000000
--- a/dlls/ntoskrnl.exe/tests/utils.h
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * ntoskrnl.exe testing framework
- *
- * Copyright 2015 Sebastian Lackner
- * Copyright 2015 Michael Müller
- * Copyright 2015 Christian Costa
- * Copyright 2020 Paul Gofman for CodeWeavers
- * Copyright 2020-2021 Zebediah Figura for CodeWeavers
- *
- * 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
- */
-
-static HANDLE okfile;
-static LONG successes;
-static LONG failures;
-static LONG skipped;
-static LONG todo_successes;
-static LONG todo_failures;
-static int todo_level, todo_do_loop;
-static int running_under_wine;
-static int winetest_debug;
-static int winetest_report_success;
-
-static inline void kvprintf(const char *format, __ms_va_list ap)
-{
- static char buffer[512];
- IO_STATUS_BLOCK io;
- int len = vsnprintf(buffer, sizeof(buffer), format, ap);
- ZwWriteFile(okfile, NULL, NULL, NULL, &io, buffer, len, NULL, NULL);
-}
-
-static inline void WINAPIV kprintf(const char *format, ...)
-{
- __ms_va_list valist;
-
- __ms_va_start(valist, format);
- kvprintf(format, valist);
- __ms_va_end(valist);
-}
-
-static inline NTSTATUS winetest_init(void)
-{
- const struct test_data *data;
- SIZE_T size = sizeof(*data);
- OBJECT_ATTRIBUTES attr;
- UNICODE_STRING string;
- IO_STATUS_BLOCK io;
- void *addr = NULL;
- HANDLE section;
- NTSTATUS ret;
-
- RtlInitUnicodeString(&string, L"\\BaseNamedObjects\\winetest_ntoskrnl_section");
- /* OBJ_KERNEL_HANDLE is necessary for the file to be accessible from system threads */
- InitializeObjectAttributes(&attr, &string, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, NULL);
- if ((ret = ZwOpenSection(§ion, SECTION_MAP_READ, &attr)))
- return ret;
-
- if ((ret = ZwMapViewOfSection(section, NtCurrentProcess(), &addr,
- 0, 0, NULL, &size, ViewUnmap, 0, PAGE_READONLY)))
- {
- ZwClose(section);
- return ret;
- }
- data = addr;
- running_under_wine = data->running_under_wine;
- winetest_debug = data->winetest_debug;
- winetest_report_success = data->winetest_report_success;
-
- ZwUnmapViewOfSection(NtCurrentProcess(), addr);
- ZwClose(section);
-
- RtlInitUnicodeString(&string, L"\\??\\C:\\windows\\winetest_ntoskrnl_okfile");
- return ZwOpenFile(&okfile, FILE_APPEND_DATA | SYNCHRONIZE, &attr, &io,
- FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT);
-}
-
-static inline void winetest_cleanup(void)
-{
- struct test_data *data;
- SIZE_T size = sizeof(*data);
- OBJECT_ATTRIBUTES attr;
- UNICODE_STRING string;
- void *addr = NULL;
- HANDLE section;
-
- if (winetest_debug)
- {
- kprintf("%04x:ntoskrnl: %d tests executed (%d marked as todo, %d %s), %d skipped.\n",
- PsGetCurrentProcessId(), successes + failures + todo_successes + todo_failures,
- todo_successes, failures + todo_failures,
- (failures + todo_failures != 1) ? "failures" : "failure", skipped );
- }
-
- RtlInitUnicodeString(&string, L"\\BaseNamedObjects\\winetest_ntoskrnl_section");
- /* OBJ_KERNEL_HANDLE is necessary for the file to be accessible from system threads */
- InitializeObjectAttributes(&attr, &string, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, NULL);
-
- if (!ZwOpenSection(§ion, SECTION_MAP_READ | SECTION_MAP_WRITE, &attr))
- {
- if (!ZwMapViewOfSection(section, NtCurrentProcess(), &addr,
- 0, 0, NULL, &size, ViewUnmap, 0, PAGE_READWRITE))
- {
- data = addr;
-
- InterlockedExchangeAdd(&data->successes, successes);
- InterlockedExchangeAdd(&data->failures, failures);
- InterlockedExchangeAdd(&data->skipped, skipped);
- InterlockedExchangeAdd(&data->todo_successes, todo_successes);
- InterlockedExchangeAdd(&data->todo_failures, todo_failures);
-
- ZwUnmapViewOfSection(NtCurrentProcess(), addr);
- }
- ZwClose(section);
- }
-
- ZwClose(okfile);
-}
-
-static inline void WINAPIV vok_(const char *file, int line, int condition, const char *msg, __ms_va_list args)
-{
- const char *current_file;
-
- if (!(current_file = drv_strrchr(file, '/')) &&
- !(current_file = drv_strrchr(file, '\\')))
- current_file = file;
- else
- current_file++;
-
- if (todo_level)
- {
- if (condition)
- {
- kprintf("%s:%d: Test succeeded inside todo block: ", current_file, line);
- kvprintf(msg, args);
- InterlockedIncrement(&todo_failures);
- }
- else
- {
- if (winetest_debug > 0)
- {
- kprintf("%s:%d: Test marked todo: ", current_file, line);
- kvprintf(msg, args);
- }
- InterlockedIncrement(&todo_successes);
- }
- }
- else
- {
- if (!condition)
- {
- kprintf("%s:%d: Test failed: ", current_file, line);
- kvprintf(msg, args);
- InterlockedIncrement(&failures);
- }
- else
- {
- if (winetest_report_success)
- kprintf("%s:%d: Test succeeded\n", current_file, line);
- InterlockedIncrement(&successes);
- }
- }
-}
-
-static inline void WINAPIV ok_(const char *file, int line, int condition, const char *msg, ...)
-{
- __ms_va_list args;
- __ms_va_start(args, msg);
- vok_(file, line, condition, msg, args);
- __ms_va_end(args);
-}
-
-static inline void vskip_(const char *file, int line, const char *msg, __ms_va_list args)
-{
- const char *current_file;
-
- if (!(current_file = drv_strrchr(file, '/')) &&
- !(current_file = drv_strrchr(file, '\\')))
- current_file = file;
- else
- current_file++;
-
- kprintf("%s:%d: Tests skipped: ", current_file, line);
- kvprintf(msg, args);
- skipped++;
-}
-
-static inline void WINAPIV win_skip_(const char *file, int line, const char *msg, ...)
-{
- __ms_va_list args;
- __ms_va_start(args, msg);
- if (running_under_wine)
- vok_(file, line, 0, msg, args);
- else
- vskip_(file, line, msg, args);
- __ms_va_end(args);
-}
-
-static inline void WINAPIV trace_(const char *file, int line, const char *msg, ...)
-{
- const char *current_file;
- __ms_va_list args;
-
- if (!(current_file = drv_strrchr(file, '/')) &&
- !(current_file = drv_strrchr(file, '\\')))
- current_file = file;
- else
- current_file++;
-
- __ms_va_start(args, msg);
- kprintf("%s:%d: ", current_file, line);
- kvprintf(msg, args);
- __ms_va_end(args);
-}
-
-static inline void winetest_start_todo( int is_todo )
-{
- todo_level = (todo_level << 1) | (is_todo != 0);
- todo_do_loop=1;
-}
-
-static inline int winetest_loop_todo(void)
-{
- int do_loop=todo_do_loop;
- todo_do_loop=0;
- return do_loop;
-}
-
-static inline void winetest_end_todo(void)
-{
- todo_level >>= 1;
-}
-
-static inline int broken(int condition)
-{
- return !running_under_wine && condition;
-}
-
-#define ok(condition, ...) ok_(__FILE__, __LINE__, condition, __VA_ARGS__)
-#define todo_if(is_todo) for (winetest_start_todo(is_todo); \
- winetest_loop_todo(); \
- winetest_end_todo())
-#define todo_wine todo_if(running_under_wine)
-#define todo_wine_if(is_todo) todo_if((is_todo) && running_under_wine)
-#define win_skip(...) win_skip_(__FILE__, __LINE__, __VA_ARGS__)
-#define trace(...) trace_(__FILE__, __LINE__, __VA_ARGS__)
diff --git a/include/wine/test.h b/include/wine/test.h
index 8073071d262..5513022b9c2 100644
--- a/include/wine/test.h
+++ b/include/wine/test.h
@@ -25,6 +25,9 @@
#include <stdlib.h>
#include <windef.h>
#include <winbase.h>
+#ifdef WINETEST_KERNEL
+#include <ddk/wdm.h>
+#endif /* WINETEST_KERNEL */
#include <wine/debug.h>
#ifdef __WINE_CONFIG_H
@@ -59,6 +62,9 @@ extern int winetest_mute_threshold;
/* current platform */
extern const char *winetest_platform;
+/* output file for kernel tests */
+extern HANDLE okfile;
+
extern void winetest_set_location( const char* file, int line );
extern void winetest_subtest( const char* name );
extern void winetest_ignore_exceptions( BOOL ignore );
@@ -68,6 +74,9 @@ extern void winetest_end_todo(void);
extern int winetest_get_mainargs( char*** pargv );
extern LONG winetest_get_failures(void);
extern void winetest_add_failures( LONG new_failures );
+extern void winetest_kernel_init( void );
+extern void winetest_kernel_check( void );
+extern void winetest_kernel_cleanup( void );
extern void winetest_wait_child_process( HANDLE process );
#ifdef STANDALONE
@@ -214,7 +223,8 @@ DWORD winetest_start_time, winetest_last_time;
int winetest_interactive = 0;
/* current platform */
-const char *winetest_platform = "windows";
+static char winetest_platform_buf[256] = "windows";
+const char *winetest_platform = winetest_platform_buf;
/* report successful tests (BOOL) */
int winetest_report_success = 0;
@@ -226,7 +236,9 @@ int winetest_mute_threshold = 42;
static int winetest_argc;
static char** winetest_argv;
+#ifndef WINETEST_KERNEL
static const struct test *current_test; /* test currently being run */
+#endif /* WINETEST_KERNEL */
static LONG successes; /* number of successful tests */
static LONG failures; /* number of failures */
@@ -240,9 +252,15 @@ static LONG muted_todo_successes; /* same as todo_successes but silent */
/* counts how many times a given line printed a message */
static LONG line_counters[16384];
+/* output file for driver tests */
+HANDLE okfile;
+
/* The following data must be kept track of on a per-thread basis */
struct tls_data
{
+#ifdef WINETEST_KERNEL
+ HANDLE thread;
+#endif /* WINETEST_KERNEL */
const char* current_file; /* file of current check */
int current_line; /* line of current check */
unsigned int todo_level; /* current todo nesting level */
@@ -252,6 +270,38 @@ struct tls_data
char context[8][128]; /* data to print before messages */
unsigned int context_count; /* number of context prefixes */
};
+
+#ifdef WINETEST_KERNEL
+
+static KSPIN_LOCK tls_data_lock;
+static struct tls_data tls_data_pool[128];
+static DWORD tls_data_count;
+
+static struct tls_data *get_tls_data(void)
+{
+ static struct tls_data tls_overflow;
+ struct tls_data *data;
+ HANDLE thread = PsGetCurrentThreadId();
+ KIRQL irql;
+
+ KeAcquireSpinLock(&tls_data_lock, &irql);
+ for (data = tls_data_pool; data != tls_data_pool + tls_data_count; ++data)
+ if (data->thread == thread) break;
+ if (data == tls_data_pool + ARRAY_SIZE(tls_data_pool))
+ data = &tls_overflow;
+ else if (data == tls_data_pool + tls_data_count)
+ {
+ data->thread = thread;
+ data->str_pos = data->strings;
+ tls_data_count++;
+ }
+ KeReleaseSpinLock(&tls_data_lock, irql);
+
+ return data;
+}
+
+#else /* WINETEST_KERNEL */
+
static DWORD tls_index;
static struct tls_data *get_tls_data(void)
@@ -277,6 +327,7 @@ static void exit_process( int code )
ExitProcess( code );
}
+#endif /* WINETEST_KERNEL */
void winetest_set_location( const char* file, int line )
{
@@ -291,6 +342,36 @@ void winetest_set_location( const char* file, int line )
data->current_line=line;
}
+#ifdef WINETEST_KERNEL
+
+static inline void __winetest_vprintf(const char *format, __ms_va_list ap)
+{
+ static char buffer[512];
+ IO_STATUS_BLOCK io;
+ int len = vsnprintf(buffer, sizeof(buffer), format, ap);
+ ZwWriteFile(okfile, NULL, NULL, NULL, &io, buffer, len, NULL, NULL);
+}
+
+static inline void WINAPIV __winetest_printf(const char *format, ...)
+{
+ __ms_va_list valist;
+
+ __ms_va_start(valist, format);
+ __winetest_vprintf(format, valist);
+ __ms_va_end(valist);
+}
+
+const char *winetest_elapsed(void)
+{
+ if (!winetest_time) return "";
+ return "0.000";
+}
+
+#else /* WINETEST_KERNEL */
+
+#define __winetest_printf printf
+#define __winetest_vprintf vprintf
+
const char *winetest_elapsed(void)
{
DWORD now;
@@ -300,15 +381,17 @@ const char *winetest_elapsed(void)
return wine_dbg_sprintf( "%.3f", (now - winetest_start_time) / 1000.0);
}
+#endif /* WINETEST_KERNEL */
+
static void __winetest_cdecl winetest_printf( const char *msg, ... ) __WINE_PRINTF_ATTR(1,2);
static void __winetest_cdecl winetest_printf( const char *msg, ... )
{
struct tls_data *data = get_tls_data();
__winetest_va_list valist;
- printf( "%s:%d:%s ", data->current_file, data->current_line, winetest_elapsed() );
+ __winetest_printf( "%s:%d:%s ", data->current_file, data->current_line, winetest_elapsed() );
__winetest_va_start( valist, msg );
- vprintf( msg, valist );
+ __winetest_vprintf( msg, valist );
__winetest_va_end( valist );
}
static void __winetest_cdecl winetest_print_context( const char *msgtype )
@@ -318,7 +401,7 @@ static void __winetest_cdecl winetest_print_context( const char *msgtype )
winetest_printf( "%s", msgtype );
for (i = 0; i < data->context_count; ++i)
- printf( "%s: ", data->context[i] );
+ __winetest_printf( "%s: ", data->context[i] );
}
void winetest_subtest( const char* name )
@@ -372,7 +455,7 @@ int winetest_vok( int condition, const char *msg, __winetest_va_list args )
if (condition)
{
winetest_print_context( "Test succeeded inside todo block: " );
- vprintf(msg, args);
+ __winetest_vprintf(msg, args);
InterlockedIncrement(&todo_failures);
return 0;
}
@@ -384,7 +467,7 @@ int winetest_vok( int condition, const char *msg, __winetest_va_list args )
if (winetest_debug > 0)
{
winetest_print_context( "Test marked todo: " );
- vprintf(msg, args);
+ __winetest_vprintf(msg, args);
}
InterlockedIncrement(&todo_successes);
}
@@ -398,17 +481,18 @@ int winetest_vok( int condition, const char *msg, __winetest_va_list args )
if (!condition)
{
winetest_print_context( "Test failed: " );
- vprintf(msg, args);
+ __winetest_vprintf(msg, args);
InterlockedIncrement(&failures);
return 0;
}
else
{
- if (winetest_report_success ||
- (winetest_time && GetTickCount() >= winetest_last_time + 1000))
- {
+ if (winetest_report_success)
winetest_printf("Test succeeded\n");
- }
+#ifndef WINETEST_KERNEL
+ else if (winetest_time && GetTickCount() >= winetest_last_time + 1000)
+ winetest_printf("Test succeeded\n");
+#endif /* WINETEST_KERNEL */
InterlockedIncrement(&successes);
return 1;
}
@@ -434,7 +518,7 @@ void __winetest_cdecl winetest_trace( const char *msg, ... )
{
winetest_print_context( "" );
__winetest_va_start(valist, msg);
- vprintf( msg, valist );
+ __winetest_vprintf( msg, valist );
__winetest_va_end(valist);
}
else
@@ -446,7 +530,7 @@ void winetest_vskip( const char *msg, __winetest_va_list args )
if (winetest_add_line() < winetest_mute_threshold)
{
winetest_print_context( "Tests skipped: " );
- vprintf(msg, args);
+ __winetest_vprintf(msg, args);
InterlockedIncrement(&skipped);
}
else
@@ -533,6 +617,155 @@ void winetest_add_failures( LONG new_failures )
InterlockedIncrement( &failures );
}
+struct winetest_kernel_data
+{
+ char winetest_platform[256];
+ int running_under_wine;
+ int winetest_report_success;
+ int winetest_debug;
+ int failures;
+ int todo_failures;
+};
+
+#ifdef WINETEST_KERNEL
+
+static int running_under_wine;
+
+static inline NTSTATUS winetest_init(void)
+{
+ const struct winetest_kernel_data *data;
+ SIZE_T size = sizeof(*data);
+ OBJECT_ATTRIBUTES attr;
+ UNICODE_STRING string;
+ IO_STATUS_BLOCK io;
+ void *addr = NULL;
+ HANDLE section;
+ NTSTATUS ret;
+
+ KeInitializeSpinLock(&tls_data_lock);
+
+ RtlInitUnicodeString(&string, L"\\BaseNamedObjects\\winetest_kernel_section");
+ /* OBJ_KERNEL_HANDLE is necessary for the file to be accessible from system threads */
+ InitializeObjectAttributes(&attr, &string, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, NULL);
+ if ((ret = ZwOpenSection(§ion, SECTION_MAP_READ, &attr)))
+ return ret;
+
+ if ((ret = ZwMapViewOfSection(section, NtCurrentProcess(), &addr,
+ 0, 0, NULL, &size, ViewUnmap, 0, PAGE_READONLY)))
+ {
+ ZwClose(okfile);
+ ZwClose(section);
+ return ret;
+ }
+ data = addr;
+ running_under_wine = data->running_under_wine;
+ winetest_debug = data->winetest_debug;
+ winetest_report_success = data->winetest_report_success;
+ strcpy(winetest_platform_buf, data->winetest_platform);
+
+ ZwUnmapViewOfSection(NtCurrentProcess(), addr);
+ ZwClose(section);
+
+ RtlInitUnicodeString(&string, L"\\??\\C:\\windows\\winetest_kernel_okfile");
+ return ZwOpenFile(&okfile, FILE_APPEND_DATA | SYNCHRONIZE, &attr, &io,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT);
+}
+
+static inline void winetest_cleanup(void)
+{
+ struct winetest_kernel_data *data;
+ SIZE_T size = sizeof(*data);
+ OBJECT_ATTRIBUTES attr;
+ UNICODE_STRING string;
+ void *addr = NULL;
+ HANDLE section;
+
+ if (winetest_debug)
+ {
+ if (muted_todo_successes || muted_skipped || muted_traces)
+ __winetest_printf( "%04x:ntoskrnl:%s Silenced %d todos, %d skips and %d traces.\n",
+ (DWORD)(ULONG_PTR)PsGetCurrentProcessId(), winetest_elapsed(),
+ muted_todo_successes, muted_skipped, muted_traces);
+ __winetest_printf( "%04x:ntoskrnl:%s %d tests executed (%d marked as todo, %d %s), %d skipped.\n",
+ (DWORD)(ULONG_PTR)PsGetCurrentProcessId(), winetest_elapsed(),
+ successes + failures + todo_successes + todo_failures,
+ todo_successes, failures + todo_failures,
+ (failures + todo_failures != 1) ? "failures" : "failure",
+ skipped );
+ }
+
+ RtlInitUnicodeString(&string, L"\\BaseNamedObjects\\winetest_kernel_section");
+ /* OBJ_KERNEL_HANDLE is necessary for the file to be accessible from system threads */
+ InitializeObjectAttributes(&attr, &string, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, NULL);
+
+ if (!ZwOpenSection(§ion, SECTION_MAP_READ | SECTION_MAP_WRITE, &attr))
+ {
+ if (!ZwMapViewOfSection(section, NtCurrentProcess(), &addr,
+ 0, 0, NULL, &size, ViewUnmap, 0, PAGE_READWRITE))
+ {
+ data = addr;
+
+ InterlockedExchangeAdd(&data->failures, failures);
+ InterlockedExchangeAdd(&data->todo_failures, todo_failures);
+
+ ZwUnmapViewOfSection(NtCurrentProcess(), addr);
+ }
+ ZwClose(section);
+ }
+
+ ZwClose(okfile);
+}
+
+#else /* WINETEST_KERNEL */
+
+static HANDLE winetest_mapping;
+static struct winetest_kernel_data *kernel_data;
+
+void winetest_kernel_init(void)
+{
+ winetest_mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0,
+ sizeof(*kernel_data), "Global\\winetest_kernel_section");
+ ok(!!winetest_mapping, "got error %u\n", GetLastError());
+ kernel_data = MapViewOfFile(winetest_mapping, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 1024);
+ ok(strlen(winetest_platform) < 256, "winetest_platform expectedly large!\n");
+ strcpy(kernel_data->winetest_platform, winetest_platform);
+ kernel_data->running_under_wine = !strcmp(winetest_platform, "wine");
+ kernel_data->winetest_report_success = winetest_report_success;
+ kernel_data->winetest_debug = winetest_debug;
+
+ okfile = CreateFileA("C:\\windows\\winetest_kernel_okfile", GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL);
+ ok(okfile != INVALID_HANDLE_VALUE, "failed to create file, error %u\n", GetLastError());
+}
+
+void winetest_kernel_check(void)
+{
+ char buffer[512];
+ DWORD size;
+
+ SetFilePointer(okfile, 0, NULL, FILE_BEGIN);
+
+ do
+ {
+ ReadFile(okfile, buffer, sizeof(buffer), &size, NULL);
+ printf("%.*s", size, buffer);
+ } while (size == sizeof(buffer));
+
+ SetFilePointer(okfile, 0, NULL, FILE_BEGIN);
+ /* SetEndOfFile(okfile); */
+
+ InterlockedExchangeAdd(&failures, InterlockedExchange(&kernel_data->failures, 0));
+ InterlockedExchangeAdd(&todo_failures, InterlockedExchange(&kernel_data->todo_failures, 0));
+}
+
+void winetest_kernel_cleanup(void)
+{
+ UnmapViewOfFile(kernel_data);
+ CloseHandle(winetest_mapping);
+ CloseHandle(okfile);
+ /* DeleteFileA("C:\\windows\\winetest_kernel_okfile"); */
+}
+
void winetest_wait_child_process( HANDLE process )
{
DWORD ret;
@@ -702,6 +935,7 @@ int main( int argc, char **argv )
return run_test(argv[1]);
}
+#endif /* WINETEST_KERNEL */
#endif /* STANDALONE */
#endif /* __WINE_WINE_TEST_H */
--
2.32.0
1
1
This adds a new joystick backend, implemented on top of HID and without
any host dependencies. This will be progressively implementated, and
it's not going to be usable until at least a few more patches.
Because of that, and because it may also introduce regressions compared
to the existing backends, it is disabled by default and is optionally
enabled using the following global registry key:
[HKCU\\Software\\Wine\\DirectInput\\Joysticks]
"HID"="enabled"
Or using the corresponding AppDefaults registry key:
[HKCU\\Software\\Wine\\AppDefaults\\<app.exe>\\DirectInput\\Joysticks]
"HID"="enabled"
This setting will be removed later, when it becomes usable enough, to
use the individual device disable mechanism available in joy.cpl.
Signed-off-by: Rémi Bernon <rbernon(a)codeweavers.com>
---
v3: Use setupapi directly, as user32 api usage was confusing. This also
now matches device on either their index, HID handle or vid_pid,
depending on what's been provided.
The instance GUID now includes the HID handle, which will be more
stable than the device index in setupapi device list.
Matching the vid_pid assumes that setupapi device path is upper
case, which I think is the case. We could make sure otherwise but
I don't think we have to and it's not very convenient without wcsupr.
dlls/dinput/Makefile.in | 3 +-
dlls/dinput/dinput_main.c | 3 +-
dlls/dinput/dinput_private.h | 1 +
dlls/dinput/joystick.c | 17 +-
dlls/dinput/joystick_hid.c | 491 ++++++++++++++++++++++++++++++
dlls/dinput/joystick_linux.c | 2 +-
dlls/dinput/joystick_linuxinput.c | 2 +-
dlls/dinput/joystick_private.h | 2 +-
dlls/dinput8/Makefile.in | 3 +-
9 files changed, 513 insertions(+), 11 deletions(-)
create mode 100644 dlls/dinput/joystick_hid.c
diff --git a/dlls/dinput/Makefile.in b/dlls/dinput/Makefile.in
index a22c8a72180..29d3e8ece65 100644
--- a/dlls/dinput/Makefile.in
+++ b/dlls/dinput/Makefile.in
@@ -1,6 +1,6 @@
MODULE = dinput.dll
IMPORTLIB = dinput
-IMPORTS = dinput dxguid uuid comctl32 ole32 user32 advapi32
+IMPORTS = dinput dxguid uuid comctl32 ole32 user32 advapi32 hid setupapi
EXTRADEFS = -DDIRECTINPUT_VERSION=0x0700
EXTRALIBS = $(IOKIT_LIBS) $(FORCEFEEDBACK_LIBS)
@@ -12,6 +12,7 @@ C_SRCS = \
dinput_main.c \
effect_linuxinput.c \
joystick.c \
+ joystick_hid.c \
joystick_linux.c \
joystick_linuxinput.c \
joystick_osx.c \
diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c
index c7b932aca44..88ee1855675 100644
--- a/dlls/dinput/dinput_main.c
+++ b/dlls/dinput/dinput_main.c
@@ -80,7 +80,8 @@ static const struct dinput_device *dinput_devices[] =
&keyboard_device,
&joystick_linuxinput_device,
&joystick_linux_device,
- &joystick_osx_device
+ &joystick_osx_device,
+ &joystick_hid_device,
};
HINSTANCE DINPUT_instance;
diff --git a/dlls/dinput/dinput_private.h b/dlls/dinput/dinput_private.h
index 7e0f56c68df..c11b64585d9 100644
--- a/dlls/dinput/dinput_private.h
+++ b/dlls/dinput/dinput_private.h
@@ -67,6 +67,7 @@ struct DevicePlayer {
extern const struct dinput_device mouse_device DECLSPEC_HIDDEN;
extern const struct dinput_device keyboard_device DECLSPEC_HIDDEN;
+extern const struct dinput_device joystick_hid_device DECLSPEC_HIDDEN;
extern const struct dinput_device joystick_linux_device DECLSPEC_HIDDEN;
extern const struct dinput_device joystick_linuxinput_device DECLSPEC_HIDDEN;
extern const struct dinput_device joystick_osx_device DECLSPEC_HIDDEN;
diff --git a/dlls/dinput/joystick.c b/dlls/dinput/joystick.c
index 8ea7850621c..60153d0d0f3 100644
--- a/dlls/dinput/joystick.c
+++ b/dlls/dinput/joystick.c
@@ -271,13 +271,13 @@ void dump_DIEFFECT(LPCDIEFFECT eff, REFGUID guid, DWORD dwFlags)
}
}
-BOOL device_disabled_registry(const char* name)
+BOOL device_disabled_registry(const char* name, BOOL disable)
{
static const char disabled_str[] = "disabled";
+ static const char enabled_str[] = "enabled";
static const char joystick_key[] = "Joysticks";
char buffer[MAX_PATH];
HKEY hkey, appkey, temp;
- BOOL do_disable = FALSE;
get_app_key(&hkey, &appkey);
@@ -297,16 +297,23 @@ BOOL device_disabled_registry(const char* name)
/* Look for the "controllername"="disabled" key */
if (!get_config_key(hkey, appkey, name, buffer, sizeof(buffer)))
- if (!strcmp(disabled_str, buffer))
+ {
+ if (!disable && !strcmp(disabled_str, buffer))
{
TRACE("Disabling joystick '%s' based on registry key.\n", name);
- do_disable = TRUE;
+ disable = TRUE;
+ }
+ else if (disable && !strcmp(enabled_str, buffer))
+ {
+ TRACE("Enabling joystick '%s' based on registry key.\n", name);
+ disable = FALSE;
}
+ }
if (appkey) RegCloseKey(appkey);
if (hkey) RegCloseKey(hkey);
- return do_disable;
+ return disable;
}
BOOL is_xinput_device(const DIDEVCAPS *devcaps, WORD vid, WORD pid)
diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c
new file mode 100644
index 00000000000..f29c806a51d
--- /dev/null
+++ b/dlls/dinput/joystick_hid.c
@@ -0,0 +1,491 @@
+/* DirectInput HID Joystick device
+ *
+ * Copyright 2021 Rémi Bernon for CodeWeavers
+ *
+ * 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 <assert.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winternl.h"
+#include "winuser.h"
+#include "winerror.h"
+#include "winreg.h"
+
+#include "ddk/hidsdi.h"
+#include "setupapi.h"
+#include "devguid.h"
+#include "dinput.h"
+#include "setupapi.h"
+
+#include "wine/debug.h"
+
+#include "dinput_private.h"
+#include "device_private.h"
+#include "joystick_private.h"
+
+#include "initguid.h"
+#include "devpkey.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(dinput);
+
+DEFINE_GUID( hid_joystick_guid, 0x9e573edb, 0x7734, 0x11d2, 0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7 );
+DEFINE_DEVPROPKEY( DEVPROPKEY_HID_HANDLE, 0xbc62e415, 0xf4fe, 0x405c, 0x8e, 0xda, 0x63, 0x6f, 0xb5, 0x9f, 0x08, 0x98, 2 );
+
+struct hid_joystick
+{
+ IDirectInputDeviceImpl base;
+
+ HANDLE device;
+ PHIDP_PREPARSED_DATA preparsed;
+};
+
+static inline struct hid_joystick *impl_from_IDirectInputDevice8W( IDirectInputDevice8W *iface )
+{
+ return CONTAINING_RECORD( CONTAINING_RECORD( iface, IDirectInputDeviceImpl, IDirectInputDevice8W_iface ),
+ struct hid_joystick, base );
+}
+
+static ULONG WINAPI hid_joystick_Release( IDirectInputDevice8W *iface )
+{
+ struct hid_joystick *impl = impl_from_IDirectInputDevice8W( iface );
+ struct hid_joystick tmp = *impl;
+ ULONG res;
+
+ if (!(res = IDirectInputDevice2WImpl_Release( iface )))
+ {
+ HidD_FreePreparsedData( tmp.preparsed );
+ CloseHandle( tmp.device );
+ }
+
+ return res;
+}
+
+static HRESULT WINAPI hid_joystick_GetCapabilities( IDirectInputDevice8W *iface, DIDEVCAPS *caps )
+{
+ FIXME( "iface %p, caps %p stub!\n", iface, caps );
+
+ if (!caps) return E_POINTER;
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI hid_joystick_EnumObjects( IDirectInputDevice8W *iface, LPDIENUMDEVICEOBJECTSCALLBACKW callback,
+ void *ref, DWORD flags )
+{
+ FIXME( "iface %p, callback %p, ref %p, flags %#x stub!\n", iface, callback, ref, flags );
+
+ if (!callback) return DIERR_INVALIDPARAM;
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI hid_joystick_GetProperty( IDirectInputDevice8W *iface, REFGUID guid, DIPROPHEADER *header )
+{
+ FIXME( "iface %p, guid %s, header %p stub!\n", iface, debugstr_guid( guid ), header );
+
+ if (!header) return DIERR_INVALIDPARAM;
+ if (!IS_DIPROP( guid )) return DI_OK;
+
+ switch (LOWORD( guid ))
+ {
+ default: return IDirectInputDevice2WImpl_GetProperty( iface, guid, header );
+ }
+}
+
+static HRESULT WINAPI hid_joystick_SetProperty( IDirectInputDevice8W *iface, REFGUID guid, const DIPROPHEADER *header )
+{
+ FIXME( "iface %p, guid %s, header %p stub!\n", iface, debugstr_guid( guid ), header );
+
+ if (!header) return DIERR_INVALIDPARAM;
+ if (!IS_DIPROP( guid )) return DI_OK;
+
+ switch (LOWORD( guid ))
+ {
+ default: return IDirectInputDevice2WImpl_SetProperty( iface, guid, header );
+ }
+}
+
+static HRESULT WINAPI hid_joystick_Acquire( IDirectInputDevice8W *iface )
+{
+ HRESULT hr;
+
+ TRACE( "iface %p.\n", iface );
+
+ if ((hr = IDirectInputDevice2WImpl_Acquire( iface )) != DI_OK) return hr;
+
+ return DI_OK;
+}
+
+static HRESULT WINAPI hid_joystick_Unacquire( IDirectInputDevice8W *iface )
+{
+ HRESULT hr;
+
+ TRACE( "iface %p.\n", iface );
+
+ if ((hr = IDirectInputDevice2WImpl_Unacquire( iface )) != DI_OK) return hr;
+
+ return DI_OK;
+}
+
+static HRESULT WINAPI hid_joystick_GetDeviceState( IDirectInputDevice8W *iface, DWORD len, void *ptr )
+{
+ FIXME( "iface %p, len %u, ptr %p stub!\n", iface, len, ptr );
+
+ if (!ptr) return DIERR_INVALIDPARAM;
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI hid_joystick_GetObjectInfo( IDirectInputDevice8W *iface, DIDEVICEOBJECTINSTANCEW *instance,
+ DWORD obj, DWORD how )
+{
+ FIXME( "iface %p, instance %p, obj %#x, how %#x stub!\n", iface, instance, obj, how );
+
+ if (!instance) return E_POINTER;
+ if (instance->dwSize != sizeof(DIDEVICEOBJECTINSTANCE_DX3W) &&
+ instance->dwSize != sizeof(DIDEVICEOBJECTINSTANCEW))
+ return DIERR_INVALIDPARAM;
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI hid_joystick_GetDeviceInfo( IDirectInputDevice8W *iface, DIDEVICEINSTANCEW *instance )
+{
+ FIXME( "iface %p, instance %p stub!\n", iface, instance );
+
+ if (!instance) return E_POINTER;
+ if (instance->dwSize != sizeof(DIDEVICEINSTANCE_DX3W) &&
+ instance->dwSize != sizeof(DIDEVICEINSTANCEW))
+ return DIERR_INVALIDPARAM;
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI hid_joystick_CreateEffect( IDirectInputDevice8W *iface, REFGUID rguid,
+ const DIEFFECT *effect, IDirectInputEffect **out,
+ IUnknown *outer )
+{
+ FIXME( "iface %p, rguid %s, effect %p, out %p, outer %p stub!\n", iface, debugstr_guid( rguid ),
+ effect, out, outer );
+
+ if (!out) return E_POINTER;
+ if (!rguid || !effect) return DI_NOEFFECT;
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI hid_joystick_EnumEffects( IDirectInputDevice8W *iface, LPDIENUMEFFECTSCALLBACKW callback,
+ void *ref, DWORD type )
+{
+ FIXME( "iface %p, callback %p, ref %p, type %#x stub!\n", iface, callback, ref, type );
+
+ if (!callback) return DIERR_INVALIDPARAM;
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI hid_joystick_GetEffectInfo( IDirectInputDevice8W *iface, DIEFFECTINFOW *info, REFGUID guid )
+{
+ FIXME( "iface %p, info %p, guid %s stub!\n", iface, info, debugstr_guid( guid ) );
+
+ if (!info) return E_POINTER;
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI hid_joystick_GetForceFeedbackState( IDirectInputDevice8W *iface, DWORD *out )
+{
+ FIXME( "iface %p, out %p stub!\n", iface, out );
+
+ if (!out) return E_POINTER;
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI hid_joystick_SendForceFeedbackCommand( IDirectInputDevice8W *iface, DWORD flags )
+{
+ FIXME( "iface %p, flags %x stub!\n", iface, flags );
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI hid_joystick_EnumCreatedEffectObjects( IDirectInputDevice8W *iface,
+ LPDIENUMCREATEDEFFECTOBJECTSCALLBACK callback,
+ void *ref, DWORD flags )
+{
+ FIXME( "iface %p, callback %p, ref %p, flags %#x stub!\n", iface, callback, ref, flags );
+
+ if (!callback) return DIERR_INVALIDPARAM;
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI hid_joystick_BuildActionMap( IDirectInputDevice8W *iface, DIACTIONFORMATW *format,
+ const WCHAR *username, DWORD flags )
+{
+ FIXME( "iface %p, format %p, username %s, flags %#x stub!\n", iface, format, debugstr_w(username), flags );
+
+ if (!format) return DIERR_INVALIDPARAM;
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI hid_joystick_SetActionMap( IDirectInputDevice8W *iface, DIACTIONFORMATW *format,
+ const WCHAR *username, DWORD flags )
+{
+ struct hid_joystick *impl = impl_from_IDirectInputDevice8W( iface );
+
+ TRACE( "iface %p, format %p, username %s, flags %#x.\n", iface, format, debugstr_w(username), flags );
+
+ if (!format) return DIERR_INVALIDPARAM;
+
+ return _set_action_map( iface, format, username, flags, impl->base.data_format.wine_df );
+}
+
+static const IDirectInputDevice8WVtbl hid_joystick_vtbl =
+{
+ /*** IUnknown methods ***/
+ IDirectInputDevice2WImpl_QueryInterface,
+ IDirectInputDevice2WImpl_AddRef,
+ hid_joystick_Release,
+ /*** IDirectInputDevice methods ***/
+ hid_joystick_GetCapabilities,
+ hid_joystick_EnumObjects,
+ hid_joystick_GetProperty,
+ hid_joystick_SetProperty,
+ hid_joystick_Acquire,
+ hid_joystick_Unacquire,
+ hid_joystick_GetDeviceState,
+ IDirectInputDevice2WImpl_GetDeviceData,
+ IDirectInputDevice2WImpl_SetDataFormat,
+ IDirectInputDevice2WImpl_SetEventNotification,
+ IDirectInputDevice2WImpl_SetCooperativeLevel,
+ hid_joystick_GetObjectInfo,
+ hid_joystick_GetDeviceInfo,
+ IDirectInputDevice2WImpl_RunControlPanel,
+ IDirectInputDevice2WImpl_Initialize,
+ /*** IDirectInputDevice2 methods ***/
+ hid_joystick_CreateEffect,
+ hid_joystick_EnumEffects,
+ hid_joystick_GetEffectInfo,
+ hid_joystick_GetForceFeedbackState,
+ hid_joystick_SendForceFeedbackCommand,
+ hid_joystick_EnumCreatedEffectObjects,
+ IDirectInputDevice2WImpl_Escape,
+ IDirectInputDevice2WImpl_Poll,
+ IDirectInputDevice2WImpl_SendDeviceData,
+ /*** IDirectInputDevice7 methods ***/
+ IDirectInputDevice7WImpl_EnumEffectsInFile,
+ IDirectInputDevice7WImpl_WriteEffectToFile,
+ /*** IDirectInputDevice8 methods ***/
+ hid_joystick_BuildActionMap,
+ hid_joystick_SetActionMap,
+ IDirectInputDevice8WImpl_GetImageInfo,
+};
+
+static BOOL hid_joystick_device_try_open( const WCHAR *path, HANDLE *device, PHIDP_PREPARSED_DATA *preparsed,
+ HIDD_ATTRIBUTES *attrs, HIDP_CAPS *caps, DIDEVICEINSTANCEW *instance )
+{
+ PHIDP_PREPARSED_DATA preparsed_data = NULL;
+ HANDLE device_file;
+
+ device_file = CreateFileW( path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, 0, 0 );
+ if (device_file == INVALID_HANDLE_VALUE) return FALSE;
+
+ if (!HidD_GetPreparsedData( device_file, &preparsed_data )) goto failed;
+ if (!HidD_GetAttributes( device_file, attrs )) goto failed;
+ if (HidP_GetCaps( preparsed_data, caps ) != HIDP_STATUS_SUCCESS) goto failed;
+
+ if (caps->UsagePage == HID_USAGE_PAGE_GAME) FIXME( "Unimplemented HID game usage page!\n" );
+ if (caps->UsagePage == HID_USAGE_PAGE_SIMULATION) FIXME( "Unimplemented HID simulation usage page!\n" );
+ if (caps->UsagePage != HID_USAGE_PAGE_GENERIC) goto failed;
+ if (caps->Usage != HID_USAGE_GENERIC_GAMEPAD && caps->Usage != HID_USAGE_GENERIC_JOYSTICK) goto failed;
+
+ if (!HidD_GetProductString( device_file, instance->tszInstanceName, MAX_PATH )) goto failed;
+ if (!HidD_GetProductString( device_file, instance->tszProductName, MAX_PATH )) goto failed;
+
+ *device = device_file;
+ *preparsed = preparsed_data;
+ return TRUE;
+
+failed:
+ CloseHandle( device_file );
+ HidD_FreePreparsedData( preparsed_data );
+ return FALSE;
+}
+
+static HRESULT hid_joystick_device_open( DWORD index, UINT32 handle, UINT32 vid_pid, WCHAR *device_path,
+ HANDLE *device, DWORD version, PHIDP_PREPARSED_DATA *preparsed,
+ HIDD_ATTRIBUTES *attrs, HIDP_CAPS *caps, DIDEVICEINSTANCEW *instance )
+{
+ static const WCHAR vid_pid_fmt_w[] = {'V','I','D','_','%','0','4','X','&','P','I','D','_','%','0','4','X',0};
+ char buffer[sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) + MAX_PATH * sizeof(WCHAR)];
+ SP_DEVICE_INTERFACE_DETAIL_DATA_W *detail = (void *)buffer;
+ SP_DEVICE_INTERFACE_DATA iface = {sizeof(iface)};
+ SP_DEVINFO_DATA devinfo = {sizeof(devinfo)};
+ WCHAR vid_pid_w[18] = {0};
+ UINT32 i = 0, hid_handle;
+ HDEVINFO set;
+ DWORD type;
+ GUID hid;
+
+ TRACE( "index %u, handle %u, vid_pid %d\n", index, handle, vid_pid );
+
+ HidD_GetHidGuid( &hid );
+ snprintfW( vid_pid_w, ARRAY_SIZE(vid_pid_w), vid_pid_fmt_w, vid_pid & 0xffff, vid_pid >> 16 );
+
+ set = SetupDiGetClassDevsW( &hid, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT );
+ if (set == INVALID_HANDLE_VALUE) return DIERR_DEVICENOTREG;
+
+ *device = NULL;
+ *preparsed = NULL;
+ while (SetupDiEnumDeviceInterfaces( set, NULL, &hid, i++, &iface ))
+ {
+ detail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
+ if (!SetupDiGetDeviceInterfaceDetailW( set, &iface, detail, sizeof(buffer), NULL, &devinfo ))
+ continue;
+ if (!SetupDiGetDevicePropertyW( set, &devinfo, &DEVPROPKEY_HID_HANDLE, &type,
+ (BYTE *)&hid_handle, sizeof(hid_handle), NULL, 0 ) ||
+ type != DEVPROP_TYPE_UINT32)
+ continue;
+ if (!hid_joystick_device_try_open( detail->DevicePath, device, preparsed, attrs, caps, instance ))
+ continue;
+
+ if (!handle && !vid_pid && !index--) break;
+ if (handle && handle == hid_handle) break;
+ if (vid_pid && strstrW( detail->DevicePath, vid_pid_w )) break;
+
+ CloseHandle( *device );
+ HidD_FreePreparsedData( *preparsed );
+ *device = NULL;
+ *preparsed = NULL;
+ }
+
+ SetupDiDestroyDeviceInfoList( set );
+ if (!*device || !*preparsed) return DIERR_DEVICENOTREG;
+
+ lstrcpynW( device_path, detail->DevicePath, MAX_PATH );
+ instance->guidInstance = hid_joystick_guid;
+ instance->guidInstance.Data3 = hid_handle;
+ instance->guidProduct = DInput_PIDVID_Product_GUID;
+ instance->guidProduct.Data1 = MAKELONG( attrs->VendorID, attrs->ProductID );
+ instance->dwDevType = get_device_type( version, caps->Usage != HID_USAGE_GENERIC_GAMEPAD ) | DIDEVTYPE_HID;
+ instance->guidFFDriver = GUID_NULL;
+ instance->wUsagePage = caps->UsagePage;
+ instance->wUsage = caps->Usage;
+ return DI_OK;
+}
+
+static HRESULT hid_joystick_enum_device( DWORD type, DWORD flags, DIDEVICEINSTANCEW *instance,
+ DWORD version, int index )
+{
+ HIDD_ATTRIBUTES attrs = {sizeof(attrs)};
+ PHIDP_PREPARSED_DATA preparsed;
+ WCHAR device_path[MAX_PATH];
+ HIDP_CAPS caps;
+ HANDLE device;
+ HRESULT hr;
+
+ TRACE( "type %x, flags %#x, instance %p, version %04x, index %d\n", type, flags, instance, version, index );
+
+ hr = hid_joystick_device_open( index, 0, 0, device_path, &device, version,
+ &preparsed, &attrs, &caps, instance );
+ if (hr != DI_OK) return hr;
+
+ HidD_FreePreparsedData( preparsed );
+ CloseHandle( device );
+
+ if (instance->dwSize != sizeof(DIDEVICEINSTANCEW))
+ return S_FALSE;
+ if (version < 0x0800 && type != DIDEVTYPE_JOYSTICK)
+ return S_FALSE;
+ if (version >= 0x0800 && type != DI8DEVCLASS_ALL && type != DI8DEVCLASS_GAMECTRL)
+ return S_FALSE;
+
+ if (device_disabled_registry( "HID", TRUE ))
+ return DIERR_DEVICENOTREG;
+
+ TRACE( "Found device %s, usage %04x:%04x, product %s, instance %s, name %s\n", debugstr_w(device_path),
+ instance->wUsagePage, instance->wUsage, debugstr_guid( &instance->guidProduct ),
+ debugstr_guid( &instance->guidInstance ), debugstr_w(instance->tszInstanceName) );
+
+ return DI_OK;
+}
+
+static HRESULT hid_joystick_create_device( IDirectInputImpl *dinput, REFGUID guid, IDirectInputDevice8W **out )
+{
+ DIDEVICEINSTANCEW instance = {sizeof(instance)};
+ GUID inst_guid = *guid, prod_guid = *guid;
+ DWORD size = sizeof(struct hid_joystick);
+ HIDD_ATTRIBUTES attrs = {sizeof(attrs)};
+ struct hid_joystick *impl = NULL;
+ PHIDP_PREPARSED_DATA preparsed;
+ UINT32 handle = 0, vid_pid = 0;
+ DIDATAFORMAT *format = NULL;
+ WCHAR device_path[MAX_PATH];
+ HIDP_CAPS caps;
+ HANDLE device;
+ HRESULT hr;
+
+ TRACE( "dinput %p, guid %s, out %p\n", dinput, debugstr_guid( guid ), out );
+
+ *out = NULL;
+
+ inst_guid.Data3 = hid_joystick_guid.Data3;
+ prod_guid.Data1 = DInput_PIDVID_Product_GUID.Data1;
+ if (IsEqualGUID( &hid_joystick_guid, &inst_guid )) handle = guid->Data3;
+ else if (IsEqualGUID( &DInput_PIDVID_Product_GUID, &prod_guid )) vid_pid = guid->Data1;
+ else return DIERR_DEVICENOTREG;
+
+ hr = hid_joystick_device_open( 0, handle, vid_pid, device_path, &device, dinput->dwVersion,
+ &preparsed, &attrs, &caps, &instance );
+ if (hr != DI_OK) return hr;
+
+ hr = direct_input_device_alloc( size, &hid_joystick_vtbl, guid, dinput, (void **)&impl );
+ if (FAILED(hr)) goto failed;
+
+ impl->base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": hid_joystick.base.crit");
+ impl->base.dwCoopLevel = DISCL_NONEXCLUSIVE | DISCL_BACKGROUND;
+
+ impl->device = device;
+ impl->preparsed = preparsed;
+
+ if (!(format = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*format) ))) goto failed;
+ impl->base.data_format.wine_df = format;
+
+ TRACE( "Created %p\n", impl );
+
+ *out = &impl->base.IDirectInputDevice8W_iface;
+ return DI_OK;
+
+failed:
+ HeapFree( GetProcessHeap(), 0, format );
+ HeapFree( GetProcessHeap(), 0, impl );
+ HidD_FreePreparsedData( preparsed );
+ CloseHandle( device );
+ return hr;
+}
+
+const struct dinput_device joystick_hid_device =
+{
+ "Wine HID joystick driver",
+ hid_joystick_enum_device,
+ hid_joystick_create_device,
+};
diff --git a/dlls/dinput/joystick_linux.c b/dlls/dinput/joystick_linux.c
index 3215978c995..312ef3d9c42 100644
--- a/dlls/dinput/joystick_linux.c
+++ b/dlls/dinput/joystick_linux.c
@@ -175,7 +175,7 @@ static INT find_joystick_devices(void)
/* Append driver name */
strcat(joydev.name, JOYDEVDRIVER);
- if (device_disabled_registry(joydev.name)) {
+ if (device_disabled_registry(joydev.name, FALSE)) {
close(fd);
continue;
}
diff --git a/dlls/dinput/joystick_linuxinput.c b/dlls/dinput/joystick_linuxinput.c
index 2b970271ec3..558c8cc19e5 100644
--- a/dlls/dinput/joystick_linuxinput.c
+++ b/dlls/dinput/joystick_linuxinput.c
@@ -264,7 +264,7 @@ static void find_joydevs(void)
else
joydev.name = joydev.device;
- if (device_disabled_registry(joydev.name)) {
+ if (device_disabled_registry(joydev.name, FALSE)) {
close(fd);
HeapFree(GetProcessHeap(), 0, joydev.name);
if (joydev.name != joydev.device)
diff --git a/dlls/dinput/joystick_private.h b/dlls/dinput/joystick_private.h
index 874bf3e69a7..9cc30605234 100644
--- a/dlls/dinput/joystick_private.h
+++ b/dlls/dinput/joystick_private.h
@@ -57,7 +57,7 @@ HRESULT setup_dinput_options(JoystickGenericImpl *This, const int *default_axis_
DWORD joystick_map_pov(const POINTL *p) DECLSPEC_HIDDEN;
-BOOL device_disabled_registry(const char* name) DECLSPEC_HIDDEN;
+BOOL device_disabled_registry(const char* name, BOOL disable) DECLSPEC_HIDDEN;
ULONG WINAPI JoystickWGenericImpl_Release(LPDIRECTINPUTDEVICE8W iface);
diff --git a/dlls/dinput8/Makefile.in b/dlls/dinput8/Makefile.in
index 35b3bfb75f5..5032c7689bc 100644
--- a/dlls/dinput8/Makefile.in
+++ b/dlls/dinput8/Makefile.in
@@ -1,6 +1,6 @@
MODULE = dinput8.dll
IMPORTLIB = dinput8
-IMPORTS = dinput8 dxguid uuid comctl32 ole32 user32 advapi32
+IMPORTS = dinput8 dxguid uuid comctl32 ole32 user32 advapi32 hid setupapi
EXTRADEFS = -DDIRECTINPUT_VERSION=0x0800
EXTRALIBS = $(IOKIT_LIBS) $(FORCEFEEDBACK_LIBS)
PARENTSRC = ../dinput
@@ -13,6 +13,7 @@ C_SRCS = \
dinput_main.c \
effect_linuxinput.c \
joystick.c \
+ joystick_hid.c \
joystick_linux.c \
joystick_linuxinput.c \
joystick_osx.c \
--
2.32.0
3
8
[PATCH 1/3] reg/tests: Verify key opening and key deletion in delete_tree()
by Hugh McMaster 01 Jul '21
by Hugh McMaster 01 Jul '21
01 Jul '21
Signed-off-by: Hugh McMaster <hugh.mcmaster(a)outlook.com>
---
programs/reg/tests/add.c | 7 +++++--
programs/reg/tests/reg_test.h | 3 ++-
2 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/programs/reg/tests/add.c b/programs/reg/tests/add.c
index 36fa634796d..469f354de39 100644
--- a/programs/reg/tests/add.c
+++ b/programs/reg/tests/add.c
@@ -154,7 +154,7 @@ void delete_key_(const char *file, unsigned line, HKEY root, const char *path, R
}
}
-LONG delete_tree(HKEY root, const char *path, REGSAM sam)
+LONG delete_tree_(const char *file, unsigned line, HKEY root, const char *path, REGSAM sam)
{
HKEY hkey;
LONG ret;
@@ -163,6 +163,7 @@ LONG delete_tree(HKEY root, const char *path, REGSAM sam)
static const char empty[1];
ret = RegOpenKeyExA(root, path, 0, KEY_READ|sam, &hkey);
+ lok(!ret || ret == ERROR_FILE_NOT_FOUND, "RegOpenKeyExA failed, got error %d\n", ret);
if (ret) return ret;
ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &max_subkey_len,
@@ -184,7 +185,7 @@ LONG delete_tree(HKEY root, const char *path, REGSAM sam)
ret = RegEnumKeyExA(hkey, 0, subkey_name, &subkey_len, NULL, NULL, NULL, NULL);
if (ret == ERROR_NO_MORE_ITEMS) break;
if (ret) goto cleanup;
- ret = delete_tree(hkey, subkey_name, sam);
+ ret = delete_tree_(file, line, hkey, subkey_name, sam);
if (ret) goto cleanup;
}
@@ -193,6 +194,8 @@ LONG delete_tree(HKEY root, const char *path, REGSAM sam)
else
ret = RegDeleteKeyExA(hkey, empty, sam, 0);
+ lok(!ret, "Failed to delete registry key, got error %d\n", ret);
+
cleanup:
HeapFree(GetProcessHeap(), 0, subkey_name);
RegCloseKey(hkey);
diff --git a/programs/reg/tests/reg_test.h b/programs/reg/tests/reg_test.h
index a5d7169beb4..3f64e552a19 100644
--- a/programs/reg/tests/reg_test.h
+++ b/programs/reg/tests/reg_test.h
@@ -64,7 +64,8 @@ void add_key_(const char *file, unsigned line, const HKEY root, const char *path
#define delete_key(r,p,s) delete_key_(__FILE__,__LINE__,r,p,s)
void delete_key_(const char *file, unsigned line, HKEY root, const char *path, REGSAM sam);
-LONG delete_tree(HKEY root, const char *path, REGSAM sam);
+#define delete_tree(r,p,s) delete_tree_(__FILE__,__LINE__,r,p,s)
+LONG delete_tree_(const char *file, unsigned line, HKEY root, const char *path, REGSAM sam);
#define add_value(k,n,t,d,s) add_value_(__FILE__,__LINE__,k,n,t,d,s)
void add_value_(const char *file, unsigned line, HKEY hkey, const char *name,
--
2.32.0
1
2
01 Jul '21
Signed-off-by: Rémi Bernon <rbernon(a)codeweavers.com>
---
v2: Fix W7 broken error (ERROR_CRC instead of ERROR_INVALID_PARAMETER).
dlls/ntoskrnl.exe/tests/ntoskrnl.c | 52 +++++++++++++++++++++++-------
1 file changed, 40 insertions(+), 12 deletions(-)
diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c
index 71dbfe1a5e9..5a7ca2b1f7b 100644
--- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c
@@ -1841,6 +1841,8 @@ static void test_hidp(HANDLE file, int report_id)
{ .DataIndex = 1, },
{ .DataIndex = 5, .RawValue = 1, },
{ .DataIndex = 7, .RawValue = 1, },
+ { .DataIndex = 19, .RawValue = 1, },
+ { .DataIndex = 21, .RawValue = 1, },
{ .DataIndex = 30, },
{ .DataIndex = 31, },
{ .DataIndex = 32, .RawValue = 0xfeedcafe, },
@@ -2199,6 +2201,20 @@ static void test_hidp(HANDLE file, int report_id)
report, caps.InputReportByteLength);
ok(status == HIDP_STATUS_SUCCESS, "HidP_SetUsages returned %#x\n", status);
+ usages[0] = 0x9;
+ usages[1] = 0xb;
+ usages[2] = 0xa;
+ value = 3;
+ ok(report[6] == 0, "got report[6] %x expected 0\n", report[6]);
+ ok(report[7] == 0, "got report[7] %x expected 0\n", report[7]);
+ memcpy(buffer, report, caps.InputReportByteLength);
+ status = HidP_SetUsages(HidP_Input, HID_USAGE_PAGE_KEYBOARD, 0, usages, &value, preparsed_data,
+ report, caps.InputReportByteLength);
+ todo_wine ok(status == HIDP_STATUS_BUFFER_TOO_SMALL, "HidP_SetUsages returned %#x\n", status);
+ buffer[6] = 2;
+ buffer[7] = 4;
+ todo_wine ok(!memcmp(buffer, report, caps.InputReportByteLength), "unexpected report data\n");
+
status = HidP_SetUsageValue(HidP_Input, HID_USAGE_PAGE_LED, 0, 6, 1,
preparsed_data, report, caps.InputReportByteLength);
ok(status == HIDP_STATUS_USAGE_NOT_FOUND, "HidP_SetUsageValue returned %#x\n", status);
@@ -2237,23 +2253,35 @@ static void test_hidp(HANDLE file, int report_id)
status = HidP_GetUsagesEx(HidP_Input, 0, usage_and_pages, &value, preparsed_data, report,
caps.InputReportByteLength);
ok(status == HIDP_STATUS_SUCCESS, "HidP_GetUsagesEx returned %#x\n", status);
- ok(value == 4, "got usage count %d, expected %d\n", value, 4);
+ todo_wine ok(value == 6, "got usage count %d, expected %d\n", value, 4);
ok(usage_and_pages[0].UsagePage == HID_USAGE_PAGE_BUTTON, "got usage_and_pages[0] UsagePage %x, expected %x\n",
usage_and_pages[0].UsagePage, HID_USAGE_PAGE_BUTTON);
ok(usage_and_pages[1].UsagePage == HID_USAGE_PAGE_BUTTON, "got usage_and_pages[1] UsagePage %x, expected %x\n",
usage_and_pages[1].UsagePage, HID_USAGE_PAGE_BUTTON);
- ok(usage_and_pages[2].UsagePage == HID_USAGE_PAGE_LED, "got usage_and_pages[2] UsagePage %x, expected %x\n",
- usage_and_pages[2].UsagePage, HID_USAGE_PAGE_LED);
- ok(usage_and_pages[3].UsagePage == HID_USAGE_PAGE_LED, "got usage_and_pages[3] UsagePage %x, expected %x\n",
- usage_and_pages[3].UsagePage, HID_USAGE_PAGE_LED);
+ ok(usage_and_pages[2].UsagePage == HID_USAGE_PAGE_KEYBOARD, "got usage_and_pages[2] UsagePage %x, expected %x\n",
+ usage_and_pages[2].UsagePage, HID_USAGE_PAGE_KEYBOARD);
+ ok(usage_and_pages[3].UsagePage == HID_USAGE_PAGE_KEYBOARD, "got usage_and_pages[3] UsagePage %x, expected %x\n",
+ usage_and_pages[3].UsagePage, HID_USAGE_PAGE_KEYBOARD);
+ todo_wine
+ ok(usage_and_pages[4].UsagePage == HID_USAGE_PAGE_LED, "got usage_and_pages[4] UsagePage %x, expected %x\n",
+ usage_and_pages[4].UsagePage, HID_USAGE_PAGE_LED);
+ ok(usage_and_pages[5].UsagePage == HID_USAGE_PAGE_LED, "got usage_and_pages[5] UsagePage %x, expected %x\n",
+ usage_and_pages[5].UsagePage, HID_USAGE_PAGE_LED);
ok(usage_and_pages[0].Usage == 4, "got usage_and_pages[0] Usage %x, expected %x\n",
usage_and_pages[0].Usage, 4);
ok(usage_and_pages[1].Usage == 6, "got usage_and_pages[1] Usage %x, expected %x\n",
usage_and_pages[1].Usage, 6);
- ok(usage_and_pages[2].Usage == 6, "got usage_and_pages[2] Usage %x, expected %x\n",
- usage_and_pages[2].Usage, 6);
- ok(usage_and_pages[3].Usage == 4, "got usage_and_pages[3] Usage %x, expected %x\n",
- usage_and_pages[3].Usage, 4);
+ ok(usage_and_pages[2].Usage == 9, "got usage_and_pages[2] Usage %x, expected %x\n",
+ usage_and_pages[2].Usage, 9);
+ todo_wine
+ ok(usage_and_pages[3].Usage == 11, "got usage_and_pages[3] Usage %x, expected %x\n",
+ usage_and_pages[3].Usage, 11);
+ todo_wine
+ ok(usage_and_pages[4].Usage == 6, "got usage_and_pages[4] Usage %x, expected %x\n",
+ usage_and_pages[4].Usage, 6);
+ todo_wine
+ ok(usage_and_pages[5].Usage == 4, "got usage_and_pages[5] Usage %x, expected %x\n",
+ usage_and_pages[5].Usage, 4);
value = HidP_MaxDataListLength(HidP_Feature + 1, preparsed_data);
ok(value == 0, "HidP_MaxDataListLength(HidP_Feature + 1) returned %d, expected %d\n", value, 0);
@@ -2267,15 +2295,15 @@ static void test_hidp(HANDLE file, int report_id)
value = 1;
status = HidP_GetData(HidP_Input, data, &value, preparsed_data, report, caps.InputReportByteLength);
ok(status == HIDP_STATUS_BUFFER_TOO_SMALL, "HidP_GetData returned %#x\n", status);
- ok(value == 9, "got data count %d, expected %d\n", value, 9);
+ todo_wine ok(value == 11, "got data count %d, expected %d\n", value, 11);
memset(data, 0, sizeof(data));
status = HidP_GetData(HidP_Input, data, &value, preparsed_data, report, caps.InputReportByteLength);
ok(status == HIDP_STATUS_SUCCESS, "HidP_GetData returned %#x\n", status);
for (i = 0; i < ARRAY_SIZE(expect_data); ++i)
{
winetest_push_context("data[%d]", i);
- check_member(data[i], expect_data[i], "%d", DataIndex);
- check_member(data[i], expect_data[i], "%d", RawValue);
+ todo_wine_if(i >= 4) check_member(data[i], expect_data[i], "%d", DataIndex);
+ todo_wine_if(i >= 4) check_member(data[i], expect_data[i], "%d", RawValue);
winetest_pop_context();
}
--
2.32.0
2
8
Signed-off-by: Jacek Caban <jacek(a)codeweavers.com>
---
dlls/gdi32/gdiobj.c | 16 ++++++++++
dlls/gdi32/tests/gdiobj.c | 62 ++++++++++++++++++++++++++++++++++++++-
2 files changed, 77 insertions(+), 1 deletion(-)
2
1
[PATCH 4/5] gdi32: Use handle layout compatible with GdiSharedHandleTable to store handles.
by Jacek Caban 01 Jul '21
by Jacek Caban 01 Jul '21
01 Jul '21
Signed-off-by: Jacek Caban <jacek(a)codeweavers.com>
---
dlls/gdi32/gdi_private.h | 2 +-
dlls/gdi32/gdiobj.c | 110 ++++++++++++++++++---------------------
2 files changed, 53 insertions(+), 59 deletions(-)
2
1
Signed-off-by: Jacek Caban <jacek(a)codeweavers.com>
---
This file is not present in WinSDK, but it's provided by mingw. We could
move it to include/wine, if that's preffered.
include/ntgdi.h | 172 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 172 insertions(+)
create mode 100644 include/ntgdi.h
2
1
[PATCH 2/5] gdi32: Move more fields from gdi_handle_entry to gdi_obj_header.
by Jacek Caban 01 Jul '21
by Jacek Caban 01 Jul '21
01 Jul '21
Signed-off-by: Jacek Caban <jacek(a)codeweavers.com>
---
dlls/gdi32/gdi_private.h | 10 +++++++
dlls/gdi32/gdiobj.c | 61 ++++++++++++++++++----------------------
2 files changed, 37 insertions(+), 34 deletions(-)
2
1