/* =====================================================================
 *  mktestdev —— 创建/删除一个"假 PnP 设备"用于安全演练
 *  作者：星陨 (Meteor) for MeteorVarg   2026-09-26
 *
 *  作用：在系统里生成一个 root 枚举的设备，友好名叫 "Smart-Camara Test Device"
 *        它没有真实驱动，纯占位，用来测试"扫描→删除→恢复"流程
 *
 *  用法：
 *      mktestdev.exe create     创建（可重复执行，会生成多个实例）
 *      mktestdev.exe remove     删除所有本工具创建的实例
 *      mktestdev.exe list       列出本工具创建的实例
 *
 *  编译：
 *      x86_64-w64-mingw32-gcc -O2 -Wall -o mktestdev.exe mktestdev.c \
 *          -lsetupapi -lcfgmgr32 -static
 * ===================================================================== */
#define _WIN32_WINNT 0x0601
#include <windows.h>
#include <setupapi.h>
#include <cfgmgr32.h>
#include <devguid.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

/* 相机类 GUID {ca3e7ab9-b4c3-4ae6-8251-579ef933890f} */
static const GUID CAMERA_CLASS =
    { 0xca3e7ab9, 0xb4c3, 0x4ae6, { 0x82, 0x51, 0x57, 0x9e, 0xf9, 0x33, 0x89, 0x0f } };

#define DEV_NAME  L"SmartCamaraTest"
#define DEV_FRIENDLY L"Smart-Camara Test Device"
#define HWID      L"ROOT\\SmartCamaraTest"

static BOOL is_elevated(void) {
    BOOL f = FALSE; HANDLE t; TOKEN_ELEVATION e; DWORD s;
    if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &t)) {
        if (GetTokenInformation(t, TokenElevation, &e, sizeof(e), &s)) f = e.TokenIsElevated;
        CloseHandle(t);
    }
    return f;
}

/* 创建一个假的 root 设备 */
static int dev_create(void) {
    HDEVINFO h = SetupDiCreateDeviceInfoList(&CAMERA_CLASS, NULL);
    SP_DEVINFO_DATA d;
    HKEY key;
    if (h == INVALID_HANDLE_VALUE) { printf("  [错误] CreateDeviceInfoList 失败 %lu\n", GetLastError()); return 1; }

    d.cbSize = sizeof(d);
    if (!SetupDiCreateDeviceInfoW(h, DEV_NAME, &CAMERA_CLASS, DEV_FRIENDLY,
                                  NULL, DICD_GENERATE_ID, &d)) {
        printf("  [错误] CreateDeviceInfo 失败 %lu\n", GetLastError());
        SetupDiDestroyDeviceInfoList(h);
        return 1;
    }
    if (!SetupDiSetDeviceRegistryPropertyW(h, &d, SPDRP_HARDWAREID,
                                           (const BYTE *)HWID, (DWORD)(sizeof(HWID)))) {
        printf("  [错误] 设置 HardwareID 失败 %lu\n", GetLastError());
        SetupDiDestroyDeviceInfoList(h);
        return 1;
    }
    if (!SetupDiCallClassInstaller(DIF_REGISTERDEVICE, h, &d)) {
        printf("  [错误] 注册设备失败 %lu（需要管理员权限）\n", GetLastError());
        SetupDiDestroyDeviceInfoList(h);
        return 1;
    }
    /* 把友好名写进设备注册表键，这样它在设备管理器/枚举里就是这个名字 */
    key = SetupDiOpenDevRegKey(h, &d, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_ALL_ACCESS);
    if (key) {
        RegSetValueExW(key, L"FriendlyName", 0, REG_SZ,
                       (const BYTE *)DEV_FRIENDLY, (DWORD)sizeof(DEV_FRIENDLY));
        RegSetValueExW(key, L"DeviceDesc", 0, REG_SZ,
                       (const BYTE *)DEV_FRIENDLY, (DWORD)sizeof(DEV_FRIENDLY));
        RegCloseKey(key);
    }
    wchar_t id[512] = L"";
    CM_Get_Device_IDW(d.DevInst, id, 512, 0);
    wprintf(L"  ✔ 已创建：%ls\n", id);
    SetupDiDestroyDeviceInfoList(h);
    return 0;
}

/* 找到本工具创建的所有实例 */
static int enum_mine(wchar_t ids[][512], int max) {
    HDEVINFO h = SetupDiGetClassDevsW(&CAMERA_CLASS, NULL, NULL, DIGCF_ALLCLASSES);
    SP_DEVINFO_DATA d;
    int n = 0;
    if (h == INVALID_HANDLE_VALUE) return 0;
    d.cbSize = sizeof(d);
    for (DWORD i = 0; n < max && SetupDiEnumDeviceInfo(h, i, &d); i++) {
        wchar_t id[512] = L"";
        CM_Get_Device_IDW(d.DevInst, id, 512, 0);
        if (wcsstr(id, DEV_NAME)) {
            wcscpy(ids[n], id);
            n++;
        }
    }
    SetupDiDestroyDeviceInfoList(h);
    return n;
}

static int dev_remove(void) {
    wchar_t ids[64][512];
    int n = enum_mine(ids, 64);
    if (!n) { printf("  （没有找到本工具创建的设备）\n"); return 0; }
    printf("  找到 %d 个，开始删除...\n", n);
    for (int k = 0; k < n; k++) {
        HDEVINFO h = SetupDiGetClassDevsW(&CAMERA_CLASS, NULL, NULL, DIGCF_ALLCLASSES);
        SP_DEVINFO_DATA d; int done = 0;
        if (h != INVALID_HANDLE_VALUE) {
            d.cbSize = sizeof(d);
            for (DWORD i = 0; SetupDiEnumDeviceInfo(h, i, &d); i++) {
                wchar_t id[512] = L"";
                CM_Get_Device_IDW(d.DevInst, id, 512, 0);
                if (_wcsicmp(id, ids[k]) == 0) {
                    SP_REMOVEDEVICE_PARAMS rp;
                    memset(&rp, 0, sizeof(rp));
                    rp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
                    rp.ClassInstallHeader.InstallFunction = DIF_REMOVE;
                    rp.Scope = DI_REMOVEDEVICE_GLOBAL;
                    if (SetupDiSetClassInstallParamsW(h, &d, &rp.ClassInstallHeader, sizeof(rp)))
                        if (SetupDiCallClassInstaller(DIF_REMOVE, h, &d)) done = 1;
                    break;
                }
            }
            SetupDiDestroyDeviceInfoList(h);
        }
        wprintf(L"  %ls  %ls\n", done ? L"✔ 已删除" : L"✘ 删除失败", ids[k]);
    }
    return 0;
}

static int dev_list(void) {
    wchar_t ids[64][512];
    int n = enum_mine(ids, 64);
    printf("  本工具创建的假设备：%d 个\n", n);
    for (int k = 0; k < n; k++) wprintf(L"    %ls\n", ids[k]);
    return 0;
}

int wmain(int argc, wchar_t **argv) {
    SetConsoleOutputCP(CP_UTF8);
    setvbuf(stdout, NULL, _IONBF, 0);
    printf("\n  ==== mktestdev · 假设备演练工具 ====\n");
    if (!is_elevated()) {
        printf("  [警告] 当前不是管理员，创建/删除可能失败\n");
    }
    if (argc < 2) {
        printf("  用法：mktestdev.exe create | remove | list\n\n");
        return 1;
    }
    if (!_wcsicmp(argv[1], L"create")) return dev_create();
    if (!_wcsicmp(argv[1], L"remove")) return dev_remove();
    if (!_wcsicmp(argv[1], L"list"))   return dev_list();
    printf("  未知参数：%ls\n", argv[1]);
    return 1;
}
