It is quite rare to have more than one or two of these, and lists are slightly easier to work with.
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ntoskrnl.exe/pnp.c | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-)
diff --git a/dlls/ntoskrnl.exe/pnp.c b/dlls/ntoskrnl.exe/pnp.c index 6652be73c47..913a63e8f0d 100644 --- a/dlls/ntoskrnl.exe/pnp.c +++ b/dlls/ntoskrnl.exe/pnp.c @@ -42,6 +42,7 @@ #include "wine/exception.h" #include "wine/heap.h" #include "wine/rbtree.h" +#include "wine/list.h"
#include "ntoskrnl_private.h" #include "plugplay.h" @@ -923,20 +924,25 @@ static DRIVER_OBJECT *pnp_manager; struct root_pnp_device { WCHAR id[MAX_DEVICE_ID_LEN]; - struct wine_rb_entry entry; + struct list entry; DEVICE_OBJECT *device; };
-static int root_pnp_devices_rb_compare( const void *key, const struct wine_rb_entry *entry ) +static struct list root_pnp_devices = LIST_INIT(root_pnp_devices); + +static struct root_pnp_device *find_root_pnp_device( const WCHAR *id ) { - const struct root_pnp_device *device = WINE_RB_ENTRY_VALUE( entry, const struct root_pnp_device, entry ); - const WCHAR *k = key; + struct root_pnp_device *device;
- return wcsicmp( k, device->id ); + LIST_FOR_EACH_ENTRY( device, &root_pnp_devices, struct root_pnp_device, entry ) + { + if (!wcsicmp( id, device->id )) + return device; + } + + return NULL; }
-static struct wine_rb_tree root_pnp_devices = { root_pnp_devices_rb_compare }; - static NTSTATUS WINAPI pnp_manager_device_pnp( DEVICE_OBJECT *device, IRP *irp ) { IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp ); @@ -1043,15 +1049,12 @@ void pnp_manager_start(void) ERR("RpcBindingFromStringBinding() failed, error %#x\n", err); }
-static void destroy_root_pnp_device( struct wine_rb_entry *entry, void *context ) -{ - struct root_pnp_device *device = WINE_RB_ENTRY_VALUE(entry, struct root_pnp_device, entry); - remove_device( device->device ); -} - void pnp_manager_stop(void) { - wine_rb_destroy( &root_pnp_devices, destroy_root_pnp_device, NULL ); + struct root_pnp_device *device, *next; + + LIST_FOR_EACH_ENTRY_SAFE( device, next, &root_pnp_devices, struct root_pnp_device, entry ) + remove_device( device->device ); IoDeleteDriver( pnp_manager ); RpcBindingFree( &plugplay_binding_handle ); } @@ -1088,7 +1091,7 @@ void pnp_manager_enumerate_root_devices( const WCHAR *driver_name )
SetupDiGetDeviceInstanceIdW( set, &sp_device, id, ARRAY_SIZE(id), NULL );
- if (wine_rb_get( &root_pnp_devices, id )) + if (find_root_pnp_device( id )) continue;
TRACE("Adding new root-enumerated device %s.\n", debugstr_w(id)); @@ -1103,12 +1106,7 @@ void pnp_manager_enumerate_root_devices( const WCHAR *driver_name ) pnp_device = device->DeviceExtension; wcscpy( pnp_device->id, id ); pnp_device->device = device; - if (wine_rb_put( &root_pnp_devices, id, &pnp_device->entry )) - { - ERR("Failed to insert device %s into tree.\n", debugstr_w(id)); - IoDeleteDevice( device ); - continue; - } + list_add_tail( &root_pnp_devices, &pnp_device->entry );
start_device( device, set, &sp_device ); }
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ntoskrnl.exe/ntoskrnl.c | 52 +++++++++++++++------------- dlls/ntoskrnl.exe/ntoskrnl_private.h | 26 ++++++++++++++ dlls/ntoskrnl.exe/pnp.c | 37 ++++++++------------ dlls/ntoskrnl.exe/sync.c | 19 +++------- 4 files changed, 71 insertions(+), 63 deletions(-)
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c index 685f7d4345b..1ddd3f4d4f0 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/ntoskrnl.c @@ -21,34 +21,20 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
-#include <stdarg.h> #include <assert.h>
#define NONAMELESSUNION #define NONAMELESSSTRUCT
-#include "ntstatus.h" -#define WIN32_NO_STATUS -#include "windef.h" -#include "winsvc.h" -#include "winternl.h" +#include "ntoskrnl_private.h" #include "excpt.h" -#include "winioctl.h" -#include "winbase.h" #include "winreg.h" #include "ntsecapi.h" #include "ddk/csq.h" -#include "ddk/ntddk.h" -#include "ddk/ntifs.h" -#include "ddk/wdm.h" #include "wine/server.h" -#include "wine/debug.h" #include "wine/heap.h" -#include "wine/rbtree.h" #include "wine/svcctl.h"
-#include "ntoskrnl_private.h" - WINE_DEFAULT_DEBUG_CHANNEL(ntoskrnl); WINE_DECLARE_DEBUG_CHANNEL(relay);
@@ -90,14 +76,6 @@ static void *ldr_notify_cookie; static PLOAD_IMAGE_NOTIFY_ROUTINE load_image_notify_routines[8]; static unsigned int load_image_notify_routine_count;
-struct wine_driver -{ - DRIVER_OBJECT driver_obj; - DRIVER_EXTENSION driver_extension; - SERVICE_STATUS_HANDLE service_handle; - struct wine_rb_entry entry; -}; - static int wine_drivers_rb_compare( const void *key, const struct wine_rb_entry *entry ) { const struct wine_driver *driver = WINE_RB_ENTRY_VALUE( entry, const struct wine_driver, entry ); @@ -110,6 +88,24 @@ static struct wine_rb_tree wine_drivers = { wine_drivers_rb_compare };
DECLARE_CRITICAL_SECTION(drivers_cs);
+struct wine_driver *get_driver( const WCHAR *name ) +{ + static const WCHAR driverW[] = L"\Driver\"; + struct wine_rb_entry *entry; + UNICODE_STRING drv_name; + + drv_name.Length = (wcslen( driverW ) + wcslen( name )) * sizeof(WCHAR); + if (!(drv_name.Buffer = malloc( drv_name.Length + sizeof(WCHAR) ))) + return NULL; + wcscpy( drv_name.Buffer, driverW ); + wcscat( drv_name.Buffer, name ); + entry = wine_rb_get( &wine_drivers, &drv_name ); + free( drv_name.Buffer ); + + if (entry) return WINE_RB_ENTRY_VALUE( entry, struct wine_driver, entry ); + return NULL; +} + static HANDLE get_device_manager(void) { static HANDLE device_manager; @@ -902,6 +898,7 @@ NTSTATUS CDECL wine_ntoskrnl_main_loop( HANDLE stop_event ) HANDLE manager = get_device_manager(); struct dispatch_context context; NTSTATUS status = STATUS_SUCCESS; + struct wine_driver *driver; HANDLE handles[2];
context.handle = NULL; @@ -983,9 +980,13 @@ NTSTATUS CDECL wine_ntoskrnl_main_loop( HANDLE stop_event )
done: /* Native PnP drivers expect that all of their devices will be removed when - * their unload routine is called, so we must stop the PnP manager first. */ - pnp_manager_stop(); + * their unload routine is called. Moreover, we cannot unload a module + * until we have removed devices for all lower drivers, so we have to stop + * all devices first, and then unload all drivers. */ + WINE_RB_FOR_EACH_ENTRY( driver, &wine_drivers, struct wine_driver, entry ) + pnp_manager_stop_driver( driver ); wine_rb_destroy( &wine_drivers, unload_driver, NULL ); + pnp_manager_stop(); return status; }
@@ -1486,6 +1487,7 @@ NTSTATUS WINAPI IoCreateDriver( UNICODE_STRING *name, PDRIVER_INITIALIZE init ) build_driver_keypath( driver->driver_obj.DriverName.Buffer, &driver->driver_extension.ServiceKeyName ); for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) driver->driver_obj.MajorFunction[i] = unhandled_irp; + list_init( &driver->root_pnp_devices );
EnterCriticalSection( &drivers_cs ); if (wine_rb_put( &wine_drivers, &driver->driver_obj.DriverName, &driver->entry )) diff --git a/dlls/ntoskrnl.exe/ntoskrnl_private.h b/dlls/ntoskrnl.exe/ntoskrnl_private.h index a1e1b892e8c..c0b588f3135 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl_private.h +++ b/dlls/ntoskrnl.exe/ntoskrnl_private.h @@ -21,7 +21,21 @@ #ifndef __WINE_NTOSKRNL_PRIVATE_H #define __WINE_NTOSKRNL_PRIVATE_H
+#include <stdarg.h> +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winioctl.h" +#include "winbase.h" +#include "winsvc.h" +#include "winternl.h" +#include "ddk/ntifs.h" +#include "ddk/wdm.h" + #include "wine/asm.h" +#include "wine/debug.h" +#include "wine/list.h" +#include "wine/rbtree.h"
static inline LPCSTR debugstr_us( const UNICODE_STRING *us ) { @@ -76,12 +90,24 @@ extern POBJECT_TYPE SeTokenObjectType; 0, 0, { (DWORD_PTR)(__FILE__ ": " # cs) }}; \ static CRITICAL_SECTION cs = { &cs##_debug, -1, 0, 0, 0, 0 };
+struct wine_driver +{ + DRIVER_OBJECT driver_obj; + DRIVER_EXTENSION driver_extension; + SERVICE_STATUS_HANDLE service_handle; + struct wine_rb_entry entry; + struct list root_pnp_devices; +}; + void ObReferenceObject( void *obj ) DECLSPEC_HIDDEN;
void pnp_manager_enumerate_root_devices( const WCHAR *driver_name ) DECLSPEC_HIDDEN; void pnp_manager_start(void) DECLSPEC_HIDDEN; +void pnp_manager_stop_driver( struct wine_driver *driver ) DECLSPEC_HIDDEN; void pnp_manager_stop(void) DECLSPEC_HIDDEN;
+struct wine_driver *get_driver( const WCHAR *name ) DECLSPEC_HIDDEN; + static const WCHAR servicesW[] = {'\','R','e','g','i','s','t','r','y', '\','M','a','c','h','i','n','e', '\','S','y','s','t','e','m', diff --git a/dlls/ntoskrnl.exe/pnp.c b/dlls/ntoskrnl.exe/pnp.c index 913a63e8f0d..dce6bb90c68 100644 --- a/dlls/ntoskrnl.exe/pnp.c +++ b/dlls/ntoskrnl.exe/pnp.c @@ -20,31 +20,17 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
-#include <stdarg.h> - #define NONAMELESSUNION
-#include "ntstatus.h" -#define WIN32_NO_STATUS -#include "windef.h" -#include "winbase.h" -#include "winioctl.h" +#include "ntoskrnl_private.h" #include "winreg.h" #include "winuser.h" -#include "winsvc.h" -#include "winternl.h" #include "setupapi.h" #include "cfgmgr32.h" #include "dbt.h" -#include "ddk/wdm.h" -#include "ddk/ntifs.h" -#include "wine/debug.h" #include "wine/exception.h" #include "wine/heap.h" -#include "wine/rbtree.h" -#include "wine/list.h"
-#include "ntoskrnl_private.h" #include "plugplay.h"
#include "initguid.h" @@ -928,13 +914,11 @@ struct root_pnp_device DEVICE_OBJECT *device; };
-static struct list root_pnp_devices = LIST_INIT(root_pnp_devices); - -static struct root_pnp_device *find_root_pnp_device( const WCHAR *id ) +static struct root_pnp_device *find_root_pnp_device( struct wine_driver *driver, const WCHAR *id ) { struct root_pnp_device *device;
- LIST_FOR_EACH_ENTRY( device, &root_pnp_devices, struct root_pnp_device, entry ) + LIST_FOR_EACH_ENTRY( device, &driver->root_pnp_devices, struct root_pnp_device, entry ) { if (!wcsicmp( id, device->id )) return device; @@ -1049,12 +1033,16 @@ void pnp_manager_start(void) ERR("RpcBindingFromStringBinding() failed, error %#x\n", err); }
-void pnp_manager_stop(void) +void pnp_manager_stop_driver( struct wine_driver *driver ) { struct root_pnp_device *device, *next;
- LIST_FOR_EACH_ENTRY_SAFE( device, next, &root_pnp_devices, struct root_pnp_device, entry ) + LIST_FOR_EACH_ENTRY_SAFE( device, next, &driver->root_pnp_devices, struct root_pnp_device, entry ) remove_device( device->device ); +} + +void pnp_manager_stop(void) +{ IoDeleteDriver( pnp_manager ); RpcBindingFree( &plugplay_binding_handle ); } @@ -1066,6 +1054,7 @@ void pnp_manager_enumerate_root_devices( const WCHAR *driver_name ) WCHAR buffer[MAX_SERVICE_NAME + ARRAY_SIZE(driverW)], id[MAX_DEVICE_ID_LEN]; SP_DEVINFO_DATA sp_device = {sizeof(sp_device)}; struct root_pnp_device *pnp_device; + struct wine_driver *driver; DEVICE_OBJECT *device; NTSTATUS status; unsigned int i; @@ -1073,6 +1062,8 @@ void pnp_manager_enumerate_root_devices( const WCHAR *driver_name )
TRACE("Searching for new root-enumerated devices for driver %s.\n", debugstr_w(driver_name));
+ driver = get_driver( driver_name ); + set = SetupDiGetClassDevsW( NULL, rootW, NULL, DIGCF_ALLCLASSES ); if (set == INVALID_HANDLE_VALUE) { @@ -1091,7 +1082,7 @@ void pnp_manager_enumerate_root_devices( const WCHAR *driver_name )
SetupDiGetDeviceInstanceIdW( set, &sp_device, id, ARRAY_SIZE(id), NULL );
- if (find_root_pnp_device( id )) + if (find_root_pnp_device( driver, id )) continue;
TRACE("Adding new root-enumerated device %s.\n", debugstr_w(id)); @@ -1106,7 +1097,7 @@ void pnp_manager_enumerate_root_devices( const WCHAR *driver_name ) pnp_device = device->DeviceExtension; wcscpy( pnp_device->id, id ); pnp_device->device = device; - list_add_tail( &root_pnp_devices, &pnp_device->entry ); + list_add_tail( &driver->root_pnp_devices, &pnp_device->entry );
start_device( device, set, &sp_device ); } diff --git a/dlls/ntoskrnl.exe/sync.c b/dlls/ntoskrnl.exe/sync.c index 2aa60a0f2a0..445c8d890ab 100644 --- a/dlls/ntoskrnl.exe/sync.c +++ b/dlls/ntoskrnl.exe/sync.c @@ -19,23 +19,12 @@ */
#include <limits.h> -#include <stdarg.h> - -#include "ntstatus.h" -#define WIN32_NO_STATUS -#include "windef.h" -#include "winbase.h" -#include "winternl.h" -#include "ddk/ntddk.h" -#include "ddk/wdm.h" -#include "ddk/ntifs.h" - -#include "wine/asm.h" -#include "wine/debug.h" -#include "wine/heap.h" -#include "wine/server.h"
#include "ntoskrnl_private.h" +#include "ddk/ntddk.h" + +#include "wine/heap.h" +#include "wine/server.h"
WINE_DEFAULT_DEBUG_CHANNEL(ntoskrnl);
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ntoskrnl.exe/ntoskrnl.c | 2 +- dlls/ntoskrnl.exe/ntoskrnl.exe.spec | 1 + dlls/ntoskrnl.exe/ntoskrnl_private.h | 3 ++- dlls/ntoskrnl.exe/pnp.c | 23 +++++++++++++++++++---- programs/winedevice/device.c | 6 ++++++ 5 files changed, 29 insertions(+), 6 deletions(-)
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c index 1ddd3f4d4f0..bb9f4bf5259 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/ntoskrnl.c @@ -3824,7 +3824,7 @@ NTSTATUS WINAPI ZwLoadDriver( const UNICODE_STRING *service_name ) driver = WINE_RB_ENTRY_VALUE( entry, struct wine_driver, entry ); driver->service_handle = service_handle;
- pnp_manager_enumerate_root_devices( service_name->Buffer + wcslen( servicesW ) ); + wine_enumerate_root_devices( service_name->Buffer + wcslen( servicesW ) );
set_service_status( service_handle, SERVICE_RUNNING, SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN ); diff --git a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec index 0f5ab76a195..6dea87f347b 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec +++ b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec @@ -1686,3 +1686,4 @@ # or 'wine_' (for user-visible functions) to avoid namespace conflicts.
@ cdecl wine_ntoskrnl_main_loop(long) +@ cdecl wine_enumerate_root_devices(wstr) diff --git a/dlls/ntoskrnl.exe/ntoskrnl_private.h b/dlls/ntoskrnl.exe/ntoskrnl_private.h index c0b588f3135..c736a9805a0 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl_private.h +++ b/dlls/ntoskrnl.exe/ntoskrnl_private.h @@ -101,11 +101,12 @@ struct wine_driver
void ObReferenceObject( void *obj ) DECLSPEC_HIDDEN;
-void pnp_manager_enumerate_root_devices( const WCHAR *driver_name ) DECLSPEC_HIDDEN; void pnp_manager_start(void) DECLSPEC_HIDDEN; void pnp_manager_stop_driver( struct wine_driver *driver ) DECLSPEC_HIDDEN; void pnp_manager_stop(void) DECLSPEC_HIDDEN;
+void CDECL wine_enumerate_root_devices( const WCHAR *driver_name ); + struct wine_driver *get_driver( const WCHAR *name ) DECLSPEC_HIDDEN;
static const WCHAR servicesW[] = {'\','R','e','g','i','s','t','r','y', diff --git a/dlls/ntoskrnl.exe/pnp.c b/dlls/ntoskrnl.exe/pnp.c index dce6bb90c68..7994a8b85b9 100644 --- a/dlls/ntoskrnl.exe/pnp.c +++ b/dlls/ntoskrnl.exe/pnp.c @@ -1047,13 +1047,14 @@ void pnp_manager_stop(void) RpcBindingFree( &plugplay_binding_handle ); }
-void pnp_manager_enumerate_root_devices( const WCHAR *driver_name ) +void CDECL wine_enumerate_root_devices( const WCHAR *driver_name ) { static const WCHAR driverW[] = {'\','D','r','i','v','e','r','\',0}; static const WCHAR rootW[] = {'R','O','O','T',0}; WCHAR buffer[MAX_SERVICE_NAME + ARRAY_SIZE(driverW)], id[MAX_DEVICE_ID_LEN]; SP_DEVINFO_DATA sp_device = {sizeof(sp_device)}; - struct root_pnp_device *pnp_device; + struct list new_list = LIST_INIT(new_list); + struct root_pnp_device *pnp_device, *next; struct wine_driver *driver; DEVICE_OBJECT *device; NTSTATUS status; @@ -1082,8 +1083,13 @@ void pnp_manager_enumerate_root_devices( const WCHAR *driver_name )
SetupDiGetDeviceInstanceIdW( set, &sp_device, id, ARRAY_SIZE(id), NULL );
- if (find_root_pnp_device( driver, id )) + if ((pnp_device = find_root_pnp_device( driver, id ))) + { + TRACE("Found device %s already enumerated.\n", debugstr_w(id)); + list_remove( &pnp_device->entry ); + list_add_tail( &new_list, &pnp_device->entry ); continue; + }
TRACE("Adding new root-enumerated device %s.\n", debugstr_w(id));
@@ -1097,10 +1103,19 @@ void pnp_manager_enumerate_root_devices( const WCHAR *driver_name ) pnp_device = device->DeviceExtension; wcscpy( pnp_device->id, id ); pnp_device->device = device; - list_add_tail( &driver->root_pnp_devices, &pnp_device->entry ); + list_add_tail( &new_list, &pnp_device->entry );
start_device( device, set, &sp_device ); }
+ LIST_FOR_EACH_ENTRY_SAFE( pnp_device, next, &driver->root_pnp_devices, struct root_pnp_device, entry ) + { + TRACE("Removing device %s.\n", debugstr_w(pnp_device->id)); + + remove_device( pnp_device->device ); + } + + list_move_head( &driver->root_pnp_devices, &new_list ); + SetupDiDestroyDeviceInfoList(set); } diff --git a/programs/winedevice/device.c b/programs/winedevice/device.c index 3acc5e8a799..509cab96308 100644 --- a/programs/winedevice/device.c +++ b/programs/winedevice/device.c @@ -35,6 +35,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(winedevice); static const WCHAR servicesW[] = L"\Registry\Machine\System\CurrentControlSet\Services\";
extern NTSTATUS CDECL wine_ntoskrnl_main_loop( HANDLE stop_event ); +extern void CDECL wine_enumerate_root_devices( const WCHAR *driver_name );
static WCHAR winedeviceW[] = L"winedevice"; static SERVICE_STATUS_HANDLE service_handle; @@ -55,6 +56,8 @@ static void set_service_status( SERVICE_STATUS_HANDLE handle, DWORD state, DWORD SetServiceStatus( handle, &status ); }
+#define SERVICE_CONTROL_REENUMERATE_ROOT_DEVICES 128 + static DWORD device_handler( DWORD ctrl, const WCHAR *driver_name ) { UNICODE_STRING service_name; @@ -78,6 +81,9 @@ static DWORD device_handler( DWORD ctrl, const WCHAR *driver_name ) result = RtlNtStatusToDosError(ZwUnloadDriver( &service_name )); break;
+ case SERVICE_CONTROL_REENUMERATE_ROOT_DEVICES: + wine_enumerate_root_devices( driver_name ); + default: FIXME( "got driver ctrl %x for %s\n", ctrl, wine_dbgstr_w(driver_name) ); break;
If the service is already running, starting it has no effect.
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/setupapi/devinst.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/dlls/setupapi/devinst.c b/dlls/setupapi/devinst.c index de0413e74f5..0a396cc8464 100644 --- a/dlls/setupapi/devinst.c +++ b/dlls/setupapi/devinst.c @@ -104,6 +104,8 @@ static const WCHAR AddInterface[] = {'A','d','d','I','n','t','e','r','f','a','c' static const WCHAR backslashW[] = {'\',0}; static const WCHAR emptyW[] = {0};
+#define SERVICE_CONTROL_REENUMERATE_ROOT_DEVICES 128 + struct driver { WCHAR inf_path[MAX_PATH]; @@ -5123,13 +5125,20 @@ BOOL WINAPI SetupDiInstallDevice(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data) if (!wcsnicmp(device->instanceId, rootW, lstrlenW(rootW)) && svc_name[0] && (manager = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT))) { - if ((service = OpenServiceW(manager, svc_name, SERVICE_START))) + if ((service = OpenServiceW(manager, svc_name, SERVICE_START | SERVICE_USER_DEFINED_CONTROL))) { + SERVICE_STATUS status; + if (!StartServiceW(service, 0, NULL) && GetLastError() != ERROR_SERVICE_ALREADY_RUNNING) { ERR("Failed to start service %s for device %s, error %u.\n", debugstr_w(svc_name), debugstr_w(device->instanceId), GetLastError()); } + if (!ControlService(service, SERVICE_CONTROL_REENUMERATE_ROOT_DEVICES, &status)) + { + ERR("Failed to control service %s for device %s, error %u.\n", + debugstr_w(svc_name), debugstr_w(device->instanceId), GetLastError()); + } CloseServiceHandle(service); } else
Allow them to be unloaded.
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/setupapi/devinst.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+)
diff --git a/dlls/setupapi/devinst.c b/dlls/setupapi/devinst.c index 0a396cc8464..8f826c30250 100644 --- a/dlls/setupapi/devinst.c +++ b/dlls/setupapi/devinst.c @@ -19,6 +19,7 @@ */
#include <stdarg.h> +#include <stdlib.h>
#include "windef.h" #include "winbase.h" @@ -1692,15 +1693,38 @@ BOOL WINAPI SetupDiRegisterDeviceInfo(HDEVINFO devinfo, SP_DEVINFO_DATA *device_ */ BOOL WINAPI SetupDiRemoveDevice(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data) { + SC_HANDLE manager = NULL, service = NULL; struct device *device; + WCHAR *service_name; + DWORD size;
TRACE("devinfo %p, device_data %p.\n", devinfo, device_data);
if (!(device = get_device(devinfo, device_data))) return FALSE;
+ if (!(manager = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT))) + return FALSE; + + if (!RegGetValueW(device->key, NULL, L"Service", RRF_RT_REG_SZ, NULL, NULL, &size)) + { + service_name = malloc(size); + if (!RegGetValueW(device->key, NULL, L"Service", RRF_RT_REG_SZ, NULL, service_name, &size)) + service = OpenServiceW(manager, service_name, SERVICE_USER_DEFINED_CONTROL); + free(service_name); + } + remove_device(device);
+ if (service) + { + SERVICE_STATUS status; + if (!ControlService(service, SERVICE_CONTROL_REENUMERATE_ROOT_DEVICES, &status)) + ERR("Failed to control service %s, error %u.\n", debugstr_w(service_name), GetLastError()); + CloseServiceHandle(service); + } + CloseServiceHandle(manager); + return TRUE; }
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ntoskrnl.exe/tests/ntoskrnl.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c index c3ebe5b8ee1..e65dac38cec 100644 --- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c @@ -43,6 +43,7 @@ static HANDLE device; static BOOL (WINAPI *pRtlDosPathNameToNtPathName_U)(const WCHAR *, UNICODE_STRING *, WCHAR **, CURDIR *); static BOOL (WINAPI *pRtlFreeUnicodeString)(UNICODE_STRING *); static BOOL (WINAPI *pCancelIoEx)(HANDLE, OVERLAPPED *); +static BOOL (WINAPI *pIsWow64Process)(HANDLE, BOOL *); static BOOL (WINAPI *pSetFileCompletionNotificationModes)(HANDLE, UCHAR); static HRESULT (WINAPI *pSignerSign)(SIGNER_SUBJECT_INFO *subject, SIGNER_CERT *cert, SIGNER_SIGNATURE_INFO *signature, SIGNER_PROVIDER_INFO *provider, @@ -939,16 +940,23 @@ START_TEST(ntoskrnl) WCHAR filename[MAX_PATH], filename2[MAX_PATH]; struct testsign_context ctx; SC_HANDLE service, service2; + BOOL ret, is_wow64; DWORD written; - BOOL ret;
pRtlDosPathNameToNtPathName_U = (void *)GetProcAddress(GetModuleHandleA("ntdll"), "RtlDosPathNameToNtPathName_U"); pRtlFreeUnicodeString = (void *)GetProcAddress(GetModuleHandleA("ntdll"), "RtlFreeUnicodeString"); pCancelIoEx = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "CancelIoEx"); + pIsWow64Process = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process"); pSetFileCompletionNotificationModes = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "SetFileCompletionNotificationModes"); pSignerSign = (void *)GetProcAddress(LoadLibraryA("mssign32"), "SignerSign");
+ if (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64) + { + skip("Running in WoW64.\n"); + return; + } + if (!testsign_create_cert(&ctx)) return;
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=88126
Your paranoid android.
=== w7u_el (32 bit report) ===
ntoskrnl.exe: ntoskrnl: Timeout
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ntoskrnl.exe/tests/Makefile.in | 6 +- dlls/ntoskrnl.exe/tests/driver_pnp.c | 143 +++++++++++++++ dlls/ntoskrnl.exe/tests/driver_pnp.spec | 1 + dlls/ntoskrnl.exe/tests/ntoskrnl.c | 226 ++++++++++++++++++++++++ 4 files changed, 375 insertions(+), 1 deletion(-) create mode 100644 dlls/ntoskrnl.exe/tests/driver_pnp.c create mode 100644 dlls/ntoskrnl.exe/tests/driver_pnp.spec
diff --git a/dlls/ntoskrnl.exe/tests/Makefile.in b/dlls/ntoskrnl.exe/tests/Makefile.in index 4b2052d43f4..c799dfcaf77 100644 --- a/dlls/ntoskrnl.exe/tests/Makefile.in +++ b/dlls/ntoskrnl.exe/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = ntoskrnl.exe -IMPORTS = advapi32 crypt32 wintrust ws2_32 +IMPORTS = advapi32 crypt32 newdev setupapi wintrust ws2_32
driver_IMPORTS = winecrt0 ntoskrnl driver_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native @@ -9,6 +9,8 @@ driver3_IMPORTS = winecrt0 ntoskrnl driver3_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native driver4_IMPORTS = winecrt0 ntoskrnl netio driver4_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native +driver_pnp_IMPORTS = winecrt0 ntoskrnl +driver_pnp_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native
SOURCES = \ driver.c \ @@ -19,4 +21,6 @@ SOURCES = \ driver3.spec \ driver4.c \ driver4.spec \ + driver_pnp.c \ + driver_pnp.spec \ ntoskrnl.c diff --git a/dlls/ntoskrnl.exe/tests/driver_pnp.c b/dlls/ntoskrnl.exe/tests/driver_pnp.c new file mode 100644 index 00000000000..53403d2fa7b --- /dev/null +++ b/dlls/ntoskrnl.exe/tests/driver_pnp.c @@ -0,0 +1,143 @@ +/* + * ntoskrnl.exe testing framework + * + * Copyright 2020 Zebediah Figura + * + * 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 <stdarg.h> + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" +#include "winternl.h" +#include "winioctl.h" +#include "ddk/wdm.h" + +#include "driver.h" + +static const GUID control_class = {0xdeadbeef, 0x29ef, 0x4538, {0xa5, 0xfd, 0xb6, 0x95, 0x73, 0xa3, 0x62, 0xc0}}; +static UNICODE_STRING control_symlink; + +static DEVICE_OBJECT *bus_fdo, *bus_pdo; + +static NTSTATUS fdo_pnp(IRP *irp) +{ + IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp); + NTSTATUS ret; + + switch (stack->MinorFunction) + { + case IRP_MN_START_DEVICE: + irp->IoStatus.Status = IoSetDeviceInterfaceState(&control_symlink, TRUE); + break; + + case IRP_MN_SURPRISE_REMOVAL: + irp->IoStatus.Status = STATUS_SUCCESS; + break; + + case IRP_MN_REMOVE_DEVICE: + IoSetDeviceInterfaceState(&control_symlink, FALSE); + irp->IoStatus.Status = STATUS_SUCCESS; + IoSkipCurrentIrpStackLocation(irp); + ret = IoCallDriver(bus_pdo, irp); + IoDetachDevice(bus_pdo); + IoDeleteDevice(bus_fdo); + RtlFreeUnicodeString(&control_symlink); + return ret; + } + + IoSkipCurrentIrpStackLocation(irp); + return IoCallDriver(bus_pdo, irp); +} + +static NTSTATUS pdo_pnp(DEVICE_OBJECT *device_obj, IRP *irp) +{ + IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp); + NTSTATUS ret = irp->IoStatus.Status; + + switch (stack->MinorFunction) + { + case IRP_MN_START_DEVICE: + ret = STATUS_SUCCESS; + break; + + case IRP_MN_QUERY_CAPABILITIES: + case IRP_MN_SURPRISE_REMOVAL: + ret = STATUS_SUCCESS; + break; + } + + irp->IoStatus.Status = ret; + IoCompleteRequest(irp, IO_NO_INCREMENT); + return ret; +} + +static NTSTATUS WINAPI driver_pnp(DEVICE_OBJECT *device, IRP *irp) +{ + if (device == bus_fdo) + return fdo_pnp(irp); + return pdo_pnp(device, irp); +} + +static NTSTATUS WINAPI driver_add_device(DRIVER_OBJECT *driver, DEVICE_OBJECT *pdo) +{ + NTSTATUS ret; + + if ((ret = IoCreateDevice(driver, 0, NULL, FILE_DEVICE_BUS_EXTENDER, 0, FALSE, &bus_fdo))) + return ret; + + if ((ret = IoRegisterDeviceInterface(pdo, &control_class, NULL, &control_symlink))) + { + IoDeleteDevice(bus_fdo); + return ret; + } + + IoAttachDeviceToDeviceStack(bus_fdo, pdo); + bus_pdo = pdo; + bus_fdo->Flags &= ~DO_DEVICE_INITIALIZING; + return STATUS_SUCCESS; +} + +static NTSTATUS WINAPI driver_create(DEVICE_OBJECT *device, IRP *irp) +{ + irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest(irp, IO_NO_INCREMENT); + return STATUS_SUCCESS; +} + +static NTSTATUS WINAPI driver_close(DEVICE_OBJECT *device, IRP *irp) +{ + irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest(irp, IO_NO_INCREMENT); + return STATUS_SUCCESS; +} + +static void WINAPI driver_unload(DRIVER_OBJECT *driver) +{ +} + +NTSTATUS WINAPI DriverEntry(DRIVER_OBJECT *driver, UNICODE_STRING *registry) +{ + driver->DriverExtension->AddDevice = driver_add_device; + driver->DriverUnload = driver_unload; + driver->MajorFunction[IRP_MJ_PNP] = driver_pnp; + driver->MajorFunction[IRP_MJ_CREATE] = driver_create; + driver->MajorFunction[IRP_MJ_CLOSE] = driver_close; + + return STATUS_SUCCESS; +} diff --git a/dlls/ntoskrnl.exe/tests/driver_pnp.spec b/dlls/ntoskrnl.exe/tests/driver_pnp.spec new file mode 100644 index 00000000000..ad33444716a --- /dev/null +++ b/dlls/ntoskrnl.exe/tests/driver_pnp.spec @@ -0,0 +1 @@ +# nothing here yet diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c index e65dac38cec..c9f680f01e8 100644 --- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c @@ -32,12 +32,16 @@ #include "ntsecapi.h" #include "mscat.h" #include "mssip.h" +#include "setupapi.h" +#include "newdev.h" #include "wine/test.h" #include "wine/heap.h" #include "wine/mssign.h"
#include "driver.h"
+static const GUID GUID_NULL; + static HANDLE device;
static BOOL (WINAPI *pRtlDosPathNameToNtPathName_U)(const WCHAR *, UNICODE_STRING *, WCHAR **, CURDIR *); @@ -935,6 +939,226 @@ static void test_driver4(struct testsign_context *ctx) ok(ret, "DeleteFile failed: %u\n", GetLastError()); }
+static void add_file_to_catalog(HANDLE catalog, const WCHAR *file) +{ + SIP_SUBJECTINFO subject_info = {sizeof(SIP_SUBJECTINFO)}; + SIP_INDIRECT_DATA *indirect_data; + const WCHAR *filepart = file; + CRYPTCATMEMBER *member; + WCHAR hash_buffer[100]; + GUID subject_guid; + unsigned int i; + DWORD size; + BOOL ret; + + ret = CryptSIPRetrieveSubjectGuidForCatalogFile(file, NULL, &subject_guid); + todo_wine ok(ret, "Failed to get subject guid, error %u\n", GetLastError()); + + size = 0; + subject_info.pgSubjectType = &subject_guid; + subject_info.pwsFileName = file; + subject_info.DigestAlgorithm.pszObjId = (char *)szOID_OIWSEC_sha1; + subject_info.dwFlags = SPC_INC_PE_RESOURCES_FLAG | SPC_INC_PE_IMPORT_ADDR_TABLE_FLAG | SPC_EXC_PE_PAGE_HASHES_FLAG | 0x10000; + ret = CryptSIPCreateIndirectData(&subject_info, &size, NULL); + todo_wine ok(ret, "Failed to get indirect data size, error %u\n", GetLastError()); + + indirect_data = malloc(size); + ret = CryptSIPCreateIndirectData(&subject_info, &size, indirect_data); + todo_wine ok(ret, "Failed to get indirect data, error %u\n", GetLastError()); + if (ret) + { + memset(hash_buffer, 0, sizeof(hash_buffer)); + for (i = 0; i < indirect_data->Digest.cbData; ++i) + swprintf(&hash_buffer[i * 2], 2, L"%02X", indirect_data->Digest.pbData[i]); + + member = CryptCATPutMemberInfo(catalog, (WCHAR *)file, + hash_buffer, &subject_guid, 0, size, (BYTE *)indirect_data); + ok(!!member, "Failed to write member, error %u\n", GetLastError()); + + if (wcsrchr(file, '\')) + filepart = wcsrchr(file, '\') + 1; + + ret = !!CryptCATPutAttrInfo(catalog, member, (WCHAR *)L"File", + CRYPTCAT_ATTR_NAMEASCII | CRYPTCAT_ATTR_DATAASCII | CRYPTCAT_ATTR_AUTHENTICATED, + (wcslen(filepart) + 1) * 2, (BYTE *)filepart); + ok(ret, "Failed to write attr, error %u\n", GetLastError()); + + ret = !!CryptCATPutAttrInfo(catalog, member, (WCHAR *)L"OSAttr", + CRYPTCAT_ATTR_NAMEASCII | CRYPTCAT_ATTR_DATAASCII | CRYPTCAT_ATTR_AUTHENTICATED, + sizeof(L"2:6.0"), (BYTE *)L"2:6.0"); + ok(ret, "Failed to write attr, error %u\n", GetLastError()); + } +} + +static void test_pnp_driver(struct testsign_context *ctx) +{ + static const char hardware_id[] = "test_hardware_id\0"; + char path[MAX_PATH], dest[MAX_PATH], *filepart; + SP_DEVINFO_DATA device = {sizeof(device)}; + char cwd[MAX_PATH], tempdir[MAX_PATH]; + WCHAR driver_filename[MAX_PATH]; + SC_HANDLE manager, service; + BOOL ret, need_reboot; + HANDLE catalog, file; + HDEVINFO set; + FILE *f; + +#ifdef __i386__ +#define EXT "x86" +#elif defined(__x86_64__) +#define EXT "amd64" +#elif defined(__arm__) +#define EXT "arm" +#elif defined(__aarch64__) +#define EXT "arm64" +#else +#define EXT +#endif + + static const char inf_text[] = + "[Version]\n" + "Signature=$Chicago$\n" + "ClassGuid={4d36e97d-e325-11ce-bfc1-08002be10318}\n" + "CatalogFile=winetest.cat\n" + "DriverVer=09/21/2006,6.0.5736.1\n" + + "[Manufacturer]\n" + "Wine=mfg_section,NT" EXT "\n" + + "[mfg_section.NT" EXT "]\n" + "Wine test root driver=device_section,test_hardware_id\n" + + "[device_section.NT" EXT "]\n" + "CopyFiles=file_section\n" + + "[device_section.NT" EXT ".Services]\n" + "AddService=winetest,0x2,svc_section\n" + + "[file_section]\n" + "winetest.sys\n" + + "[SourceDisksFiles]\n" + "winetest.sys=1\n" + + "[SourceDisksNames]\n" + "1=,winetest.sys\n" + + "[DestinationDirs]\n" + "DefaultDestDir=12\n" + + "[svc_section]\n" + "ServiceBinary=%12%\winetest.sys\n" + "ServiceType=1\n" + "StartType=3\n" + "ErrorControl=1\n" + "LoadOrderGroup=Extended Base\n" + "DisplayName="winetest bus driver"\n" + "; they don't sleep anymore, on the beach\n"; + + GetCurrentDirectoryA(ARRAY_SIZE(cwd), cwd); + GetTempPathA(ARRAY_SIZE(tempdir), tempdir); + SetCurrentDirectoryA(tempdir); + + load_resource(L"driver_pnp.dll", driver_filename); + ret = MoveFileExW(driver_filename, L"winetest.sys", MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING); + ok(ret, "failed to move file, error %u\n", GetLastError()); + + f = fopen("winetest.inf", "w"); + ok(!!f, "failed to open winetest.inf: %s\n", strerror(errno)); + fputs(inf_text, f); + fclose(f); + + /* Create the catalog file. */ + + catalog = CryptCATOpen((WCHAR *)L"winetest.cat", CRYPTCAT_OPEN_CREATENEW, 0, CRYPTCAT_VERSION_1, 0); + ok(catalog != INVALID_HANDLE_VALUE, "Failed to create catalog, error %#x\n", GetLastError()); + + ret = !!CryptCATPutCatAttrInfo(catalog, (WCHAR *)L"HWID1", + CRYPTCAT_ATTR_NAMEASCII | CRYPTCAT_ATTR_DATAASCII | CRYPTCAT_ATTR_AUTHENTICATED, + sizeof(L"test_hardware_id"), (BYTE *)L"test_hardware_id"); + todo_wine ok(ret, "failed to add attribute, error %#x\n", GetLastError()); + + ret = !!CryptCATPutCatAttrInfo(catalog, (WCHAR *)L"OS", + CRYPTCAT_ATTR_NAMEASCII | CRYPTCAT_ATTR_DATAASCII | CRYPTCAT_ATTR_AUTHENTICATED, + sizeof(L"VistaX64"), (BYTE *)L"VistaX64"); + todo_wine ok(ret, "failed to add attribute, error %#x\n", GetLastError()); + + add_file_to_catalog(catalog, L"winetest.sys"); + add_file_to_catalog(catalog, L"winetest.inf"); + + ret = CryptCATPersistStore(catalog); + todo_wine ok(ret, "Failed to write catalog, error %u\n", GetLastError()); + + ret = CryptCATClose(catalog); + ok(ret, "Failed to close catalog, error %u\n", GetLastError()); + + testsign_sign(ctx, L"winetest.cat"); + + /* Install the driver. */ + + set = SetupDiCreateDeviceInfoList(NULL, NULL); + ok(set != INVALID_HANDLE_VALUE, "failed to create device list, error %#x\n", GetLastError()); + + ret = SetupDiCreateDeviceInfoA(set, "root\winetest\0", &GUID_NULL, NULL, NULL, 0, &device); + ok(ret, "failed to create device, error %#x\n", GetLastError()); + + ret = SetupDiSetDeviceRegistryPropertyA( set, &device, SPDRP_HARDWAREID, + (const BYTE *)hardware_id, sizeof(hardware_id) ); + ok(ret, "failed to create set hardware ID, error %#x\n", GetLastError()); + + ret = SetupDiCallClassInstaller(DIF_REGISTERDEVICE, set, &device); + ok(ret, "failed to register device, error %#x\n", GetLastError()); + + GetFullPathNameA("winetest.inf", sizeof(path), path, NULL); + ret = UpdateDriverForPlugAndPlayDevicesA(NULL, hardware_id, path, INSTALLFLAG_FORCE, &need_reboot); + ok(ret, "failed to install device, error %#x\n", GetLastError()); + ok(!need_reboot, "expected no reboot necessary\n"); + + /* Tests. */ + + file = CreateFileA("\\?\root#winetest#0#{deadbeef-29ef-4538-a5fd-b69573a362c0}", 0, 0, NULL, OPEN_EXISTING, 0, NULL); + ok(file != INVALID_HANDLE_VALUE, "got error %u\n", GetLastError()); + CloseHandle(file); + + /* Clean up. */ + + ret = SetupDiCallClassInstaller(DIF_REMOVE, set, &device); + ok(ret, "failed to remove device, error %#x\n", GetLastError()); + + file = CreateFileA("\\?\root#winetest#0#{deadbeef-29ef-4538-a5fd-b69573a362c0}", 0, 0, NULL, OPEN_EXISTING, 0, NULL); + ok(file == INVALID_HANDLE_VALUE, "expected failure\n"); + ok(GetLastError() == ERROR_FILE_NOT_FOUND, "got error %u\n", GetLastError()); + + ret = SetupDiDestroyDeviceInfoList(set); + ok(ret, "failed to destroy set, error %#x\n", GetLastError()); + + /* Windows stops the service but does not delete it. */ + manager = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT); + ok(!!manager, "failed to open service manager, error %u\n", GetLastError()); + service = OpenServiceA(manager, "winetest", SERVICE_STOP | DELETE); + ok(!!service, "failed to open service, error %u\n", GetLastError()); + unload_driver(service); + CloseServiceHandle(manager); + + GetFullPathNameA("winetest.inf", sizeof(path), path, NULL); + ret = SetupCopyOEMInfA(path, NULL, 0, 0, dest, sizeof(dest), NULL, &filepart); + ok(ret, "Failed to copy INF, error %#x\n", GetLastError()); + ret = SetupUninstallOEMInfA(filepart, 0, NULL); + ok(ret, "Failed to uninstall INF, error %u\n", GetLastError()); + + ret = DeleteFileA("winetest.cat"); + ok(ret, "Failed to delete file, error %u\n", GetLastError()); + ret = DeleteFileA("winetest.inf"); + ok(ret, "Failed to delete file, error %u\n", GetLastError()); + ret = DeleteFileA("winetest.sys"); + ok(ret, "Failed to delete file, error %u\n", GetLastError()); + /* Windows 10 apparently deletes the image in SetupUninstallOEMInf(). */ + ret = DeleteFileA("C:/windows/system32/drivers/winetest.sys"); + ok(ret || GetLastError() == ERROR_FILE_NOT_FOUND, "Failed to delete file, error %u\n", GetLastError()); + + SetCurrentDirectoryA(cwd); +} + START_TEST(ntoskrnl) { WCHAR filename[MAX_PATH], filename2[MAX_PATH]; @@ -1008,5 +1232,7 @@ START_TEST(ntoskrnl) subtest("driver4"); test_driver4(&ctx);
+ test_pnp_driver(&ctx); + testsign_cleanup(&ctx); }