[PATCH 1/4] ntoskrnl.exe/tests: Move driver testing helpers to a separate file.

Rémi Bernon rbernon at codeweavers.com
Mon Aug 30 02:37:36 CDT 2021


Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---

The idea for this series is to have the driver-based HID test live in
dlls/hid/tests instead of ntoskrnl.exe, as it probably should.

The driver_hid source and the other driver test utility, however, aren't
moved. I think it would be inconvenient to duplicate the driver test
utility code, but moreover because I intend to make driver_hid much more
flexible and to share it in other modules tests if possible.

The actual driver test cases will be entirely controlled from the test
executables instead of being hardcoded in the driver, and we'll then be
able to use it to create virtual devices and test them from the user
side.

For APIs such as DInput, it will allow us to have test cases without
requiring actual devices, and even better, test cases with controlled
input, or specific device features, such as force-feedback.

 dlls/ntoskrnl.exe/tests/driver_tests.h | 565 ++++++++++++++++++++++
 dlls/ntoskrnl.exe/tests/ntoskrnl.c     | 630 +------------------------
 2 files changed, 583 insertions(+), 612 deletions(-)
 create mode 100644 dlls/ntoskrnl.exe/tests/driver_tests.h

diff --git a/dlls/ntoskrnl.exe/tests/driver_tests.h b/dlls/ntoskrnl.exe/tests/driver_tests.h
new file mode 100644
index 00000000000..dee183154e8
--- /dev/null
+++ b/dlls/ntoskrnl.exe/tests/driver_tests.h
@@ -0,0 +1,565 @@
+/*
+ * ntoskrnl.exe testing framework
+ *
+ * Copyright 2015 Sebastian Lackner
+ * Copyright 2015 Michael Müller
+ * Copyright 2015 Christian Costa
+ * 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
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <time.h>
+
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
+#include "windef.h"
+#include "winbase.h"
+#include "winioctl.h"
+#include "winternl.h"
+#include "winuser.h"
+#include "winnls.h"
+#include "winsvc.h"
+#include "winreg.h"
+#include "wincrypt.h"
+
+#include "mscat.h"
+#include "newdev.h"
+#include "ntsecapi.h"
+#include "objbase.h"
+#include "setupapi.h"
+
+#include "wine/mssign.h"
+#include "wine/test.h"
+
+#include "driver.h"
+
+static HANDLE test_data_mapping;
+static struct test_data *test_data;
+
+static HRESULT (WINAPI *pSignerSign)(SIGNER_SUBJECT_INFO *subject, SIGNER_CERT *cert,
+        SIGNER_SIGNATURE_INFO *signature, SIGNER_PROVIDER_INFO *provider,
+        const WCHAR *timestamp, CRYPT_ATTRIBUTES *attr, void *sip_data);
+
+#define load_resource (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : load_resource_
+static void load_resource_(const WCHAR *name, WCHAR *filename)
+{
+    static WCHAR path[MAX_PATH];
+    DWORD written;
+    HANDLE file;
+    HRSRC res;
+    void *ptr;
+
+    GetTempPathW(ARRAY_SIZE(path), path);
+    GetTempFileNameW(path, name, 0, filename);
+
+    file = CreateFileW(filename, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
+    winetest_ok(file != INVALID_HANDLE_VALUE, "failed to create %s, error %u\n", debugstr_w(filename), GetLastError());
+
+    res = FindResourceW(NULL, name, L"TESTDLL");
+    winetest_ok( res != 0, "couldn't find resource\n" );
+    ptr = LockResource( LoadResource( GetModuleHandleA(NULL), res ));
+    WriteFile( file, ptr, SizeofResource( GetModuleHandleA(NULL), res ), &written, NULL );
+    winetest_ok( written == SizeofResource( GetModuleHandleA(NULL), res ), "couldn't write resource\n" );
+    CloseHandle( file );
+}
+
+struct testsign_context
+{
+    HCRYPTPROV provider;
+    const CERT_CONTEXT *cert, *root_cert, *publisher_cert;
+    HCERTSTORE root_store, publisher_store;
+};
+
+static BOOL testsign_create_cert(struct testsign_context *ctx)
+{
+    BYTE encoded_name[100], encoded_key_id[200], public_key_info_buffer[1000];
+    WCHAR container_name[26];
+    BYTE hash_buffer[16], cert_buffer[1000], provider_nameA[100], serial[16];
+    CERT_PUBLIC_KEY_INFO *public_key_info = (CERT_PUBLIC_KEY_INFO *)public_key_info_buffer;
+    CRYPT_KEY_PROV_INFO provider_info = {0};
+    CRYPT_ALGORITHM_IDENTIFIER algid = {0};
+    CERT_AUTHORITY_KEY_ID_INFO key_info;
+    CERT_INFO cert_info = {0};
+    WCHAR provider_nameW[100];
+    CERT_EXTENSION extension;
+    HCRYPTKEY key;
+    DWORD size;
+    BOOL ret;
+
+    memset(ctx, 0, sizeof(*ctx));
+
+    srand(time(NULL));
+    swprintf(container_name, ARRAY_SIZE(container_name), L"wine_testsign%u", rand());
+
+    ret = CryptAcquireContextW(&ctx->provider, container_name, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET);
+    winetest_ok(ret, "Failed to create container, error %#x\n", GetLastError());
+
+    ret = CryptGenKey(ctx->provider, AT_SIGNATURE, CRYPT_EXPORTABLE, &key);
+    winetest_ok(ret, "Failed to create key, error %#x\n", GetLastError());
+    ret = CryptDestroyKey(key);
+    winetest_ok(ret, "Failed to destroy key, error %#x\n", GetLastError());
+    ret = CryptGetUserKey(ctx->provider, AT_SIGNATURE, &key);
+    winetest_ok(ret, "Failed to get user key, error %#x\n", GetLastError());
+    ret = CryptDestroyKey(key);
+    winetest_ok(ret, "Failed to destroy key, error %#x\n", GetLastError());
+
+    size = sizeof(encoded_name);
+    ret = CertStrToNameA(X509_ASN_ENCODING, "CN=winetest_cert", CERT_X500_NAME_STR, NULL, encoded_name, &size, NULL);
+    winetest_ok(ret, "Failed to convert name, error %#x\n", GetLastError());
+    key_info.CertIssuer.cbData = size;
+    key_info.CertIssuer.pbData = encoded_name;
+
+    size = sizeof(public_key_info_buffer);
+    ret = CryptExportPublicKeyInfo(ctx->provider, AT_SIGNATURE, X509_ASN_ENCODING, public_key_info, &size);
+    winetest_ok(ret, "Failed to export public key, error %#x\n", GetLastError());
+    cert_info.SubjectPublicKeyInfo = *public_key_info;
+
+    size = sizeof(hash_buffer);
+    ret = CryptHashPublicKeyInfo(ctx->provider, CALG_MD5, 0, X509_ASN_ENCODING, public_key_info, hash_buffer, &size);
+    winetest_ok(ret, "Failed to hash public key, error %#x\n", GetLastError());
+
+    key_info.KeyId.cbData = size;
+    key_info.KeyId.pbData = hash_buffer;
+
+    RtlGenRandom(serial, sizeof(serial));
+    key_info.CertSerialNumber.cbData = sizeof(serial);
+    key_info.CertSerialNumber.pbData = serial;
+
+    size = sizeof(encoded_key_id);
+    ret = CryptEncodeObject(X509_ASN_ENCODING, X509_AUTHORITY_KEY_ID, &key_info, encoded_key_id, &size);
+    winetest_ok(ret, "Failed to convert name, error %#x\n", GetLastError());
+
+    extension.pszObjId = (char *)szOID_AUTHORITY_KEY_IDENTIFIER;
+    extension.fCritical = TRUE;
+    extension.Value.cbData = size;
+    extension.Value.pbData = encoded_key_id;
+
+    cert_info.dwVersion = CERT_V3;
+    cert_info.SerialNumber = key_info.CertSerialNumber;
+    cert_info.SignatureAlgorithm.pszObjId = (char *)szOID_RSA_SHA1RSA;
+    cert_info.Issuer = key_info.CertIssuer;
+    GetSystemTimeAsFileTime(&cert_info.NotBefore);
+    GetSystemTimeAsFileTime(&cert_info.NotAfter);
+    cert_info.NotAfter.dwHighDateTime += 1;
+    cert_info.Subject = key_info.CertIssuer;
+    cert_info.cExtension = 1;
+    cert_info.rgExtension = &extension;
+    algid.pszObjId = (char *)szOID_RSA_SHA1RSA;
+    size = sizeof(cert_buffer);
+    ret = CryptSignAndEncodeCertificate(ctx->provider, AT_SIGNATURE, X509_ASN_ENCODING,
+            X509_CERT_TO_BE_SIGNED, &cert_info, &algid, NULL, cert_buffer, &size);
+    winetest_ok(ret, "Failed to create certificate, error %#x\n", GetLastError());
+
+    ctx->cert = CertCreateCertificateContext(X509_ASN_ENCODING, cert_buffer, size);
+    winetest_ok(!!ctx->cert, "Failed to create context, error %#x\n", GetLastError());
+
+    size = sizeof(provider_nameA);
+    ret = CryptGetProvParam(ctx->provider, PP_NAME, provider_nameA, &size, 0);
+    winetest_ok(ret, "Failed to get prov param, error %#x\n", GetLastError());
+    MultiByteToWideChar(CP_ACP, 0, (char *)provider_nameA, -1, provider_nameW, ARRAY_SIZE(provider_nameW));
+
+    provider_info.pwszContainerName = (WCHAR *)container_name;
+    provider_info.pwszProvName = provider_nameW;
+    provider_info.dwProvType = PROV_RSA_FULL;
+    provider_info.dwKeySpec = AT_SIGNATURE;
+    ret = CertSetCertificateContextProperty(ctx->cert, CERT_KEY_PROV_INFO_PROP_ID, 0, &provider_info);
+    winetest_ok(ret, "Failed to set provider info, error %#x\n", GetLastError());
+
+    ctx->root_store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_A, 0, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE, "root");
+    if (!ctx->root_store && GetLastError() == ERROR_ACCESS_DENIED)
+    {
+        skip("Failed to open root store.\n");
+
+        ret = CertFreeCertificateContext(ctx->cert);
+        winetest_ok(ret, "Failed to free certificate, error %u\n", GetLastError());
+        ret = CryptReleaseContext(ctx->provider, 0);
+        winetest_ok(ret, "failed to release context, error %u\n", GetLastError());
+
+        return FALSE;
+    }
+    winetest_ok(!!ctx->root_store, "Failed to open store, error %u\n", GetLastError());
+    ret = CertAddCertificateContextToStore(ctx->root_store, ctx->cert, CERT_STORE_ADD_ALWAYS, &ctx->root_cert);
+    if (!ret && GetLastError() == ERROR_ACCESS_DENIED)
+    {
+        skip("Failed to add self-signed certificate to store.\n");
+
+        ret = CertFreeCertificateContext(ctx->cert);
+        winetest_ok(ret, "Failed to free certificate, error %u\n", GetLastError());
+        ret = CertCloseStore(ctx->root_store, CERT_CLOSE_STORE_CHECK_FLAG);
+        winetest_ok(ret, "Failed to close store, error %u\n", GetLastError());
+        ret = CryptReleaseContext(ctx->provider, 0);
+        winetest_ok(ret, "failed to release context, error %u\n", GetLastError());
+
+        return FALSE;
+    }
+    winetest_ok(ret, "Failed to add certificate, error %u\n", GetLastError());
+
+    ctx->publisher_store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_A, 0, 0,
+            CERT_SYSTEM_STORE_LOCAL_MACHINE, "trustedpublisher");
+    winetest_ok(!!ctx->publisher_store, "Failed to open store, error %u\n", GetLastError());
+    ret = CertAddCertificateContextToStore(ctx->publisher_store, ctx->cert,
+            CERT_STORE_ADD_ALWAYS, &ctx->publisher_cert);
+    winetest_ok(ret, "Failed to add certificate, error %u\n", GetLastError());
+
+    return TRUE;
+}
+
+static void testsign_cleanup(struct testsign_context *ctx)
+{
+    BOOL ret;
+
+    ret = CertFreeCertificateContext(ctx->cert);
+    winetest_ok(ret, "Failed to free certificate, error %u\n", GetLastError());
+
+    ret = CertDeleteCertificateFromStore(ctx->root_cert);
+    winetest_ok(ret, "Failed to remove certificate, error %u\n", GetLastError());
+    ret = CertCloseStore(ctx->root_store, CERT_CLOSE_STORE_CHECK_FLAG);
+    winetest_ok(ret, "Failed to close store, error %u\n", GetLastError());
+
+    ret = CertDeleteCertificateFromStore(ctx->publisher_cert);
+    winetest_ok(ret, "Failed to remove certificate, error %u\n", GetLastError());
+    ret = CertCloseStore(ctx->publisher_store, CERT_CLOSE_STORE_CHECK_FLAG);
+    winetest_ok(ret, "Failed to close store, error %u\n", GetLastError());
+
+    ret = CryptReleaseContext(ctx->provider, 0);
+    winetest_ok(ret, "failed to release context, error %u\n", GetLastError());
+}
+
+#define testsign_sign (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : testsign_sign_
+static void testsign_sign_(struct testsign_context *ctx, const WCHAR *filename)
+{
+    SIGNER_ATTR_AUTHCODE authcode = {sizeof(authcode)};
+    SIGNER_SIGNATURE_INFO signature = {sizeof(signature)};
+    SIGNER_SUBJECT_INFO subject = {sizeof(subject)};
+    SIGNER_CERT_STORE_INFO store = {sizeof(store)};
+    SIGNER_CERT cert_info = {sizeof(cert_info)};
+    SIGNER_FILE_INFO file = {sizeof(file)};
+    DWORD index = 0;
+    HRESULT hr;
+
+    subject.dwSubjectChoice = 1;
+    subject.pdwIndex = &index;
+    subject.pSignerFileInfo = &file;
+    file.pwszFileName = (WCHAR *)filename;
+    cert_info.dwCertChoice = 2;
+    cert_info.pCertStoreInfo = &store;
+    store.pSigningCert = ctx->cert;
+    store.dwCertPolicy = 0;
+    signature.algidHash = CALG_SHA_256;
+    signature.dwAttrChoice = SIGNER_AUTHCODE_ATTR;
+    signature.pAttrAuthcode = &authcode;
+    authcode.pwszName = L"";
+    authcode.pwszInfo = L"";
+    hr = pSignerSign(&subject, &cert_info, &signature, NULL, NULL, NULL, NULL);
+    todo_wine winetest_ok(hr == S_OK || broken(hr == NTE_BAD_ALGID) /* < 7 */, "Failed to sign, hr %#x\n", hr);
+}
+
+#define unload_driver (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : unload_driver_
+static void unload_driver_(SC_HANDLE service)
+{
+    SERVICE_STATUS status;
+
+    ControlService(service, SERVICE_CONTROL_STOP, &status);
+    while (status.dwCurrentState == SERVICE_STOP_PENDING)
+    {
+        BOOL ret;
+        Sleep(100);
+        ret = QueryServiceStatus(service, &status);
+        winetest_ok(ret, "QueryServiceStatus failed: %u\n", GetLastError());
+    }
+    winetest_ok(status.dwCurrentState == SERVICE_STOPPED,
+       "expected SERVICE_STOPPED, got %d\n", status.dwCurrentState);
+
+    DeleteService(service);
+    CloseServiceHandle(service);
+}
+
+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));
+    winetest_add_failures(InterlockedExchange(&test_data->todo_failures, 0));
+}
+
+#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";
+
+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 winetest_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 winetest_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 winetest_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);
+        winetest_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);
+        winetest_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");
+        winetest_ok(ret, "Failed to write attr, error %u\n", GetLastError());
+    }
+}
+
+typedef void (*driver_test_callback)(void *);
+
+#define run_driver_test (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : run_driver_test_
+static void run_driver_test_(struct testsign_context *ctx, const WCHAR *name,
+                             driver_test_callback callback, void *args)
+{
+    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;
+
+    GetCurrentDirectoryA(ARRAY_SIZE(cwd), cwd);
+    GetTempPathA(ARRAY_SIZE(tempdir), tempdir);
+    SetCurrentDirectoryA(tempdir);
+
+    load_resource_(name, driver_filename);
+    ret = MoveFileExW(driver_filename, L"winetest.sys", MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING);
+    winetest_ok(ret, "failed to move file, error %u\n", GetLastError());
+
+    f = fopen("winetest.inf", "w");
+    winetest_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);
+    winetest_ok(catalog != INVALID_HANDLE_VALUE, "Failed to create catalog, 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 winetest_ok(ret, "Failed to write catalog, error %u\n", GetLastError());
+
+    ret = CryptCATClose(catalog);
+    winetest_ok(ret, "Failed to close catalog, error %u\n", GetLastError());
+
+    testsign_sign_(ctx, L"winetest.cat");
+
+    /* Install the driver. */
+
+    set = SetupDiCreateDeviceInfoList(NULL, NULL);
+    winetest_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);
+    winetest_ok(ret, "failed to create device, error %#x\n", GetLastError());
+
+    ret = SetupDiSetDeviceRegistryPropertyA( set, &device, SPDRP_HARDWAREID,
+            (const BYTE *)hardware_id, sizeof(hardware_id) );
+    winetest_ok(ret, "failed to create set hardware ID, error %#x\n", GetLastError());
+
+    ret = SetupDiCallClassInstaller(DIF_REGISTERDEVICE, set, &device);
+    winetest_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);
+    winetest_ok(ret, "failed to install device, error %#x\n", GetLastError());
+    winetest_ok(!need_reboot, "expected no reboot necessary\n");
+
+    callback(args);
+
+    ret = SetupDiCallClassInstaller(DIF_REMOVE, set, &device);
+    winetest_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);
+    winetest_ok(file == INVALID_HANDLE_VALUE, "expected failure\n");
+    winetest_ok(GetLastError() == ERROR_FILE_NOT_FOUND, "got error %u\n", GetLastError());
+
+    ret = SetupDiDestroyDeviceInfoList(set);
+    winetest_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);
+    winetest_ok(!!manager, "failed to open service manager, error %u\n", GetLastError());
+    service = OpenServiceA(manager, "winetest", SERVICE_STOP | DELETE);
+    winetest_ok(!!service, "failed to open service, error %u\n", GetLastError());
+    unload_driver_(service);
+    CloseServiceHandle(manager);
+
+    cat_okfile();
+
+    GetFullPathNameA("winetest.inf", sizeof(path), path, NULL);
+    ret = SetupCopyOEMInfA(path, NULL, 0, 0, dest, sizeof(dest), NULL, &filepart);
+    winetest_ok(ret, "Failed to copy INF, error %#x\n", GetLastError());
+    ret = SetupUninstallOEMInfA(filepart, 0, NULL);
+    winetest_ok(ret, "Failed to uninstall INF, error %u\n", GetLastError());
+
+    ret = DeleteFileA("winetest.cat");
+    winetest_ok(ret, "Failed to delete file, error %u\n", GetLastError());
+    ret = DeleteFileA("winetest.inf");
+    winetest_ok(ret, "Failed to delete file, error %u\n", GetLastError());
+    ret = DeleteFileA("winetest.sys");
+    winetest_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");
+    winetest_ok(ret || GetLastError() == ERROR_FILE_NOT_FOUND, "Failed to delete file, error %u\n", GetLastError());
+
+    SetCurrentDirectoryA(cwd);
+}
+
+#define driver_test_init(a) driver_test_init_(__FILE__, __LINE__, a)
+static BOOL driver_test_init_(char const *file, int line, struct testsign_context *ctx)
+{
+    BOOL is_wow64;
+
+    winetest_set_location(file, line);
+
+    pSignerSign = (void *)GetProcAddress(LoadLibraryA("mssign32"), "SignerSign");
+
+    if (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64)
+    {
+        winetest_skip("Running in WoW64.\n");
+        return FALSE;
+    }
+
+    if (!testsign_create_cert(ctx))
+        return FALSE;
+
+    test_data_mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
+            0, sizeof(*test_data), "Global\\winetest_ntoskrnl_section");
+    winetest_ok(!!test_data_mapping, "got error %u\n", GetLastError());
+    test_data = MapViewOfFile(test_data_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);
+    winetest_ok(okfile != INVALID_HANDLE_VALUE, "failed to create file, error %u\n", GetLastError());
+
+    return TRUE;
+}
+
+#define driver_test_cleanup (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : driver_test_cleanup_
+static void driver_test_cleanup_(struct testsign_context *ctx)
+{
+    testsign_cleanup(ctx);
+    UnmapViewOfFile(test_data);
+    CloseHandle(test_data_mapping);
+    CloseHandle(okfile);
+    DeleteFileA("C:\\windows\\winetest_ntoskrnl_okfile");
+}
diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c
index dc10497caee..a0636099def 100644
--- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c
@@ -44,15 +44,12 @@
 #include "ddk/hidpi.h"
 #include "wine/test.h"
 #include "wine/heap.h"
-#include "wine/mssign.h"
-
-#include "driver.h"
 
 static const GUID GUID_NULL;
 
-static HANDLE device;
+#include "driver_tests.h"
 
-static struct test_data *test_data;
+static HANDLE device;
 
 static BOOL (WINAPI *pRtlDosPathNameToNtPathName_U)(const WCHAR *, UNICODE_STRING *, WCHAR **, CURDIR *);
 static BOOL (WINAPI *pRtlFreeUnicodeString)(UNICODE_STRING *);
@@ -63,237 +60,6 @@ static HRESULT (WINAPI *pSignerSign)(SIGNER_SUBJECT_INFO *subject, SIGNER_CERT *
         SIGNER_SIGNATURE_INFO *signature, SIGNER_PROVIDER_INFO *provider,
         const WCHAR *timestamp, CRYPT_ATTRIBUTES *attr, void *sip_data);
 
-static void load_resource(const WCHAR *name, WCHAR *filename)
-{
-    static WCHAR path[MAX_PATH];
-    DWORD written;
-    HANDLE file;
-    HRSRC res;
-    void *ptr;
-
-    GetTempPathW(ARRAY_SIZE(path), path);
-    GetTempFileNameW(path, name, 0, filename);
-
-    file = CreateFileW(filename, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
-    ok(file != INVALID_HANDLE_VALUE, "failed to create %s, error %u\n", debugstr_w(filename), GetLastError());
-
-    res = FindResourceW(NULL, name, L"TESTDLL");
-    ok( res != 0, "couldn't find resource\n" );
-    ptr = LockResource( LoadResource( GetModuleHandleA(NULL), res ));
-    WriteFile( file, ptr, SizeofResource( GetModuleHandleA(NULL), res ), &written, NULL );
-    ok( written == SizeofResource( GetModuleHandleA(NULL), res ), "couldn't write resource\n" );
-    CloseHandle( file );
-}
-
-struct testsign_context
-{
-    HCRYPTPROV provider;
-    const CERT_CONTEXT *cert, *root_cert, *publisher_cert;
-    HCERTSTORE root_store, publisher_store;
-};
-
-static BOOL testsign_create_cert(struct testsign_context *ctx)
-{
-    BYTE encoded_name[100], encoded_key_id[200], public_key_info_buffer[1000];
-    WCHAR container_name[26];
-    BYTE hash_buffer[16], cert_buffer[1000], provider_nameA[100], serial[16];
-    CERT_PUBLIC_KEY_INFO *public_key_info = (CERT_PUBLIC_KEY_INFO *)public_key_info_buffer;
-    CRYPT_KEY_PROV_INFO provider_info = {0};
-    CRYPT_ALGORITHM_IDENTIFIER algid = {0};
-    CERT_AUTHORITY_KEY_ID_INFO key_info;
-    CERT_INFO cert_info = {0};
-    WCHAR provider_nameW[100];
-    CERT_EXTENSION extension;
-    HCRYPTKEY key;
-    DWORD size;
-    BOOL ret;
-
-    memset(ctx, 0, sizeof(*ctx));
-
-    srand(time(NULL));
-    swprintf(container_name, ARRAY_SIZE(container_name), L"wine_testsign%u", rand());
-
-    ret = CryptAcquireContextW(&ctx->provider, container_name, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET);
-    ok(ret, "Failed to create container, error %#x\n", GetLastError());
-
-    ret = CryptGenKey(ctx->provider, AT_SIGNATURE, CRYPT_EXPORTABLE, &key);
-    ok(ret, "Failed to create key, error %#x\n", GetLastError());
-    ret = CryptDestroyKey(key);
-    ok(ret, "Failed to destroy key, error %#x\n", GetLastError());
-    ret = CryptGetUserKey(ctx->provider, AT_SIGNATURE, &key);
-    ok(ret, "Failed to get user key, error %#x\n", GetLastError());
-    ret = CryptDestroyKey(key);
-    ok(ret, "Failed to destroy key, error %#x\n", GetLastError());
-
-    size = sizeof(encoded_name);
-    ret = CertStrToNameA(X509_ASN_ENCODING, "CN=winetest_cert", CERT_X500_NAME_STR, NULL, encoded_name, &size, NULL);
-    ok(ret, "Failed to convert name, error %#x\n", GetLastError());
-    key_info.CertIssuer.cbData = size;
-    key_info.CertIssuer.pbData = encoded_name;
-
-    size = sizeof(public_key_info_buffer);
-    ret = CryptExportPublicKeyInfo(ctx->provider, AT_SIGNATURE, X509_ASN_ENCODING, public_key_info, &size);
-    ok(ret, "Failed to export public key, error %#x\n", GetLastError());
-    cert_info.SubjectPublicKeyInfo = *public_key_info;
-
-    size = sizeof(hash_buffer);
-    ret = CryptHashPublicKeyInfo(ctx->provider, CALG_MD5, 0, X509_ASN_ENCODING, public_key_info, hash_buffer, &size);
-    ok(ret, "Failed to hash public key, error %#x\n", GetLastError());
-
-    key_info.KeyId.cbData = size;
-    key_info.KeyId.pbData = hash_buffer;
-
-    RtlGenRandom(serial, sizeof(serial));
-    key_info.CertSerialNumber.cbData = sizeof(serial);
-    key_info.CertSerialNumber.pbData = serial;
-
-    size = sizeof(encoded_key_id);
-    ret = CryptEncodeObject(X509_ASN_ENCODING, X509_AUTHORITY_KEY_ID, &key_info, encoded_key_id, &size);
-    ok(ret, "Failed to convert name, error %#x\n", GetLastError());
-
-    extension.pszObjId = (char *)szOID_AUTHORITY_KEY_IDENTIFIER;
-    extension.fCritical = TRUE;
-    extension.Value.cbData = size;
-    extension.Value.pbData = encoded_key_id;
-
-    cert_info.dwVersion = CERT_V3;
-    cert_info.SerialNumber = key_info.CertSerialNumber;
-    cert_info.SignatureAlgorithm.pszObjId = (char *)szOID_RSA_SHA1RSA;
-    cert_info.Issuer = key_info.CertIssuer;
-    GetSystemTimeAsFileTime(&cert_info.NotBefore);
-    GetSystemTimeAsFileTime(&cert_info.NotAfter);
-    cert_info.NotAfter.dwHighDateTime += 1;
-    cert_info.Subject = key_info.CertIssuer;
-    cert_info.cExtension = 1;
-    cert_info.rgExtension = &extension;
-    algid.pszObjId = (char *)szOID_RSA_SHA1RSA;
-    size = sizeof(cert_buffer);
-    ret = CryptSignAndEncodeCertificate(ctx->provider, AT_SIGNATURE, X509_ASN_ENCODING,
-            X509_CERT_TO_BE_SIGNED, &cert_info, &algid, NULL, cert_buffer, &size);
-    ok(ret, "Failed to create certificate, error %#x\n", GetLastError());
-
-    ctx->cert = CertCreateCertificateContext(X509_ASN_ENCODING, cert_buffer, size);
-    ok(!!ctx->cert, "Failed to create context, error %#x\n", GetLastError());
-
-    size = sizeof(provider_nameA);
-    ret = CryptGetProvParam(ctx->provider, PP_NAME, provider_nameA, &size, 0);
-    ok(ret, "Failed to get prov param, error %#x\n", GetLastError());
-    MultiByteToWideChar(CP_ACP, 0, (char *)provider_nameA, -1, provider_nameW, ARRAY_SIZE(provider_nameW));
-
-    provider_info.pwszContainerName = (WCHAR *)container_name;
-    provider_info.pwszProvName = provider_nameW;
-    provider_info.dwProvType = PROV_RSA_FULL;
-    provider_info.dwKeySpec = AT_SIGNATURE;
-    ret = CertSetCertificateContextProperty(ctx->cert, CERT_KEY_PROV_INFO_PROP_ID, 0, &provider_info);
-    ok(ret, "Failed to set provider info, error %#x\n", GetLastError());
-
-    ctx->root_store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_A, 0, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE, "root");
-    if (!ctx->root_store && GetLastError() == ERROR_ACCESS_DENIED)
-    {
-        skip("Failed to open root store.\n");
-
-        ret = CertFreeCertificateContext(ctx->cert);
-        ok(ret, "Failed to free certificate, error %u\n", GetLastError());
-        ret = CryptReleaseContext(ctx->provider, 0);
-        ok(ret, "failed to release context, error %u\n", GetLastError());
-
-        return FALSE;
-    }
-    ok(!!ctx->root_store, "Failed to open store, error %u\n", GetLastError());
-    ret = CertAddCertificateContextToStore(ctx->root_store, ctx->cert, CERT_STORE_ADD_ALWAYS, &ctx->root_cert);
-    if (!ret && GetLastError() == ERROR_ACCESS_DENIED)
-    {
-        skip("Failed to add self-signed certificate to store.\n");
-
-        ret = CertFreeCertificateContext(ctx->cert);
-        ok(ret, "Failed to free certificate, error %u\n", GetLastError());
-        ret = CertCloseStore(ctx->root_store, CERT_CLOSE_STORE_CHECK_FLAG);
-        ok(ret, "Failed to close store, error %u\n", GetLastError());
-        ret = CryptReleaseContext(ctx->provider, 0);
-        ok(ret, "failed to release context, error %u\n", GetLastError());
-
-        return FALSE;
-    }
-    ok(ret, "Failed to add certificate, error %u\n", GetLastError());
-
-    ctx->publisher_store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_A, 0, 0,
-            CERT_SYSTEM_STORE_LOCAL_MACHINE, "trustedpublisher");
-    ok(!!ctx->publisher_store, "Failed to open store, error %u\n", GetLastError());
-    ret = CertAddCertificateContextToStore(ctx->publisher_store, ctx->cert,
-            CERT_STORE_ADD_ALWAYS, &ctx->publisher_cert);
-    ok(ret, "Failed to add certificate, error %u\n", GetLastError());
-
-    return TRUE;
-}
-
-static void testsign_cleanup(struct testsign_context *ctx)
-{
-    BOOL ret;
-
-    ret = CertFreeCertificateContext(ctx->cert);
-    ok(ret, "Failed to free certificate, error %u\n", GetLastError());
-
-    ret = CertDeleteCertificateFromStore(ctx->root_cert);
-    ok(ret, "Failed to remove certificate, error %u\n", GetLastError());
-    ret = CertCloseStore(ctx->root_store, CERT_CLOSE_STORE_CHECK_FLAG);
-    ok(ret, "Failed to close store, error %u\n", GetLastError());
-
-    ret = CertDeleteCertificateFromStore(ctx->publisher_cert);
-    ok(ret, "Failed to remove certificate, error %u\n", GetLastError());
-    ret = CertCloseStore(ctx->publisher_store, CERT_CLOSE_STORE_CHECK_FLAG);
-    ok(ret, "Failed to close store, error %u\n", GetLastError());
-
-    ret = CryptReleaseContext(ctx->provider, 0);
-    ok(ret, "failed to release context, error %u\n", GetLastError());
-}
-
-static void testsign_sign(struct testsign_context *ctx, const WCHAR *filename)
-{
-    SIGNER_ATTR_AUTHCODE authcode = {sizeof(authcode)};
-    SIGNER_SIGNATURE_INFO signature = {sizeof(signature)};
-    SIGNER_SUBJECT_INFO subject = {sizeof(subject)};
-    SIGNER_CERT_STORE_INFO store = {sizeof(store)};
-    SIGNER_CERT cert_info = {sizeof(cert_info)};
-    SIGNER_FILE_INFO file = {sizeof(file)};
-    DWORD index = 0;
-    HRESULT hr;
-
-    subject.dwSubjectChoice = 1;
-    subject.pdwIndex = &index;
-    subject.pSignerFileInfo = &file;
-    file.pwszFileName = (WCHAR *)filename;
-    cert_info.dwCertChoice = 2;
-    cert_info.pCertStoreInfo = &store;
-    store.pSigningCert = ctx->cert;
-    store.dwCertPolicy = 0;
-    signature.algidHash = CALG_SHA_256;
-    signature.dwAttrChoice = SIGNER_AUTHCODE_ATTR;
-    signature.pAttrAuthcode = &authcode;
-    authcode.pwszName = L"";
-    authcode.pwszInfo = L"";
-    hr = pSignerSign(&subject, &cert_info, &signature, NULL, NULL, NULL, NULL);
-    todo_wine ok(hr == S_OK || broken(hr == NTE_BAD_ALGID) /* < 7 */, "Failed to sign, hr %#x\n", hr);
-}
-
-static void unload_driver(SC_HANDLE service)
-{
-    SERVICE_STATUS status;
-
-    ControlService(service, SERVICE_CONTROL_STOP, &status);
-    while (status.dwCurrentState == SERVICE_STOP_PENDING)
-    {
-        BOOL ret;
-        Sleep(100);
-        ret = QueryServiceStatus(service, &status);
-        ok(ret, "QueryServiceStatus failed: %u\n", GetLastError());
-    }
-    ok(status.dwCurrentState == SERVICE_STOPPED,
-       "expected SERVICE_STOPPED, got %d\n", status.dwCurrentState);
-
-    DeleteService(service);
-    CloseServiceHandle(service);
-}
-
 static SC_HANDLE load_driver(struct testsign_context *ctx, WCHAR *filename,
         const WCHAR *resname, const WCHAR *driver_name)
 {
@@ -369,26 +135,6 @@ static BOOL start_driver(HANDLE service, BOOL vista_plus)
 
 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));
-    winetest_add_failures(InterlockedExchange(&test_data->todo_failures, 0));
-}
-
 static ULONG64 modified_value;
 
 static void main_test(void)
@@ -1239,109 +985,6 @@ static void test_driver_netio(struct testsign_context *ctx)
     cat_okfile();
 }
 
-#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";
-
-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 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}};
 
@@ -1434,7 +1077,7 @@ static void pump_messages(void)
     }
 }
 
-static void test_pnp_devices(void)
+static void test_pnp_devices(void *args)
 {
     static const char expect_hardware_id[] = "winetest_hardware\0winetest_hardware_1\0";
     static const char expect_compat_id[] = "winetest_compat\0winetest_compat_1\0";
@@ -1698,133 +1341,6 @@ static void test_pnp_devices(void)
     UnregisterClassA("ntoskrnl_test_wc", GetModuleHandleA(NULL));
 }
 
-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;
-    unsigned int i;
-    HDEVINFO set;
-    FILE *f;
-
-    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. */
-
-    test_pnp_devices();
-
-    /* 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());
-
-    set = SetupDiGetClassDevsA(NULL, "wine", NULL, DIGCF_ALLCLASSES);
-    ok(set != INVALID_HANDLE_VALUE, "failed to get device list, error %#x\n", GetLastError());
-
-    for (i = 0; SetupDiEnumDeviceInfo(set, i, &device); ++i)
-    {
-        ret = SetupDiCallClassInstaller(DIF_REMOVE, set, &device);
-        ok(ret, "failed to remove device, 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);
-
-    cat_okfile();
-
-    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);
-}
-
 #define check_member_(file, line, val, exp, fmt, member)               \
         ok_(file, line)((val).member == (exp).member,                  \
                         "got " #member " " fmt ", expected " fmt "\n", \
@@ -3131,8 +2647,16 @@ static void test_hidp(HANDLE file, HANDLE async_file, int report_id, BOOL polled
     HidD_FreePreparsedData(preparsed_data);
 }
 
-static void test_hid_device(DWORD report_id, DWORD polled)
+struct test_hid_params
+{
+    BOOL report_id;
+    BOOL polled;
+};
+
+static void test_hid_device(void *args)
 {
+    struct test_hid_params *params = args;
+    BOOL report_id = params->report_id, polled = params->polled;
     char buffer[200];
     SP_DEVICE_INTERFACE_DETAIL_DATA_A *iface_detail = (void *)buffer;
     SP_DEVICE_INTERFACE_DATA iface = {sizeof(iface)};
@@ -3297,18 +2821,11 @@ static void test_hid_device(DWORD report_id, DWORD polled)
 
 static void test_hid_driver(struct testsign_context *ctx, DWORD report_id, DWORD polled)
 {
-    static const char hardware_id[] = "test_hardware_id\0";
-    char path[MAX_PATH], dest[MAX_PATH], *filepart;
+    struct test_hid_params params = {.report_id = report_id, .polled = polled};
     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;
     LSTATUS status;
-    HDEVINFO set;
     HKEY hkey;
-    FILE *f;
 
     GetCurrentDirectoryA(ARRAY_SIZE(cwd), cwd);
     GetTempPathA(ARRAY_SIZE(tempdir), tempdir);
@@ -3323,94 +2840,7 @@ static void test_hid_driver(struct testsign_context *ctx, DWORD report_id, DWORD
     status = RegSetValueExW(hkey, L"PolledMode", 0, REG_DWORD, (void *)&polled, sizeof(polled));
     ok(!status, "RegSetValueExW returned %#x\n", status);
 
-    load_resource(L"driver_hid.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());
-
-    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. */
-
-    test_hid_device(report_id, polled);
-
-    /* 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);
-
-    cat_okfile();
-
-    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);
+    run_driver_test(ctx, L"driver_hid.dll", test_hid_device, &params);
 }
 
 START_TEST(ntoskrnl)
@@ -3418,9 +2848,8 @@ START_TEST(ntoskrnl)
     WCHAR filename[MAX_PATH], filename2[MAX_PATH];
     struct testsign_context ctx;
     SC_HANDLE service, service2;
-    BOOL ret, is_wow64;
-    HANDLE mapping;
     DWORD written;
+    BOOL ret;
 
     pRtlDosPathNameToNtPathName_U = (void *)GetProcAddress(GetModuleHandleA("ntdll"), "RtlDosPathNameToNtPathName_U");
     pRtlFreeUnicodeString = (void *)GetProcAddress(GetModuleHandleA("ntdll"), "RtlFreeUnicodeString");
@@ -3428,29 +2857,10 @@ START_TEST(ntoskrnl)
     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))
+    if (!driver_test_init(&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());
-
     subtest("driver");
     if (!(service = load_driver(&ctx, filename, L"driver.dll", L"WineTestDriver")))
         goto out;
@@ -3497,7 +2907,7 @@ START_TEST(ntoskrnl)
     test_driver_netio(&ctx);
 
     subtest("driver_pnp");
-    test_pnp_driver(&ctx);
+    run_driver_test(&ctx, L"driver_pnp.dll", test_pnp_devices, NULL);
 
     subtest("driver_hid");
     test_hid_driver(&ctx, 0, FALSE);
@@ -3506,9 +2916,5 @@ START_TEST(ntoskrnl)
     test_hid_driver(&ctx, 1, TRUE);
 
 out:
-    testsign_cleanup(&ctx);
-    UnmapViewOfFile(test_data);
-    CloseHandle(mapping);
-    CloseHandle(okfile);
-    DeleteFileA("C:\\windows\\winetest_ntoskrnl_okfile");
+    driver_test_cleanup(&ctx);
 }
-- 
2.33.0




More information about the wine-devel mailing list