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

Rémi Bernon rbernon at codeweavers.com
Mon Aug 30 03:23:26 CDT 2021


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

Supersedes: 212831-212833

v2: * Use the caller source location for skip messages.

    * Drop the symlink remove patch, seems like it was actually used.

 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..751b2f9b208
--- /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)
+    {
+        winetest_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)
+    {
+        winetest_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