c++ - 是什么可以导致SetupDiGetClassDevs不返回任何设备接口(interface)? (Windows,C++)

标签 c++ windows unity3d usb hid

我已经在这个问题上工作了一个多月了。

我想做什么:
获取无故障连接到系统的HID设备的列表。

发生了什么:
SetupDiGetClassDevs间歇性地不返回任何设备(针对HID设备进行过滤时),而仅返回所讨论的特定进程。同时运行相同调用的其他进程运行完美。无论我如何努力,我都无法在干净的项目中重现此问题。

背景:
我是在Unity 3D(游戏引擎)下运行的输入系统的作者。我的一个客户在他的(大型)项目中遇到了操纵杆热插拔的问题。在他的游戏的标题屏幕上,一切正常进行。加载第一个游戏级别后,Windows会间歇性地(看似随机地)报告零个HID设备。只要仍然连接当前 Controller ,输入就可以正常工作,但是在这些“故障”期间,如果将 Controller 卸下并重新插入,Windows将返回0设备接口(interface)。

我无权访问该客户的项目(超过80 GB),但已将自己的测试代码注入(inject)可执行文件中,以尝试查找问题的根源。我有超过一千个客户,只有这个项目似乎有这个问题。

这是我在C++ DLL中用来查询系统中HID设备数量的一些测试代码。

int EnumerateDevices() {

int deviceCount = 0;

LPGUID guid = (LPGUID)malloc(sizeof(GUID));
HidD_GetHidGuid(guid);

HDEVINFO deviceInfoSet = SetupDiGetClassDevs(guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);

if (deviceInfoSet != INVALID_HANDLE_VALUE) {

    SP_DEVINFO_DATA* deviceInfoData = new SP_DEVINFO_DATA();
    deviceInfoData->cbSize = sizeof(SP_DEVINFO_DATA);
    deviceInfoData->DevInst = 0;

    DWORD deviceIndex = 0;
    int totalDeviceCount = 0;
    int totalInterfaceCount = 0;

    while (SetupDiEnumDeviceInfo(deviceInfoSet, deviceIndex, deviceInfoData)) {
        deviceIndex += 1;

        SP_DEVICE_INTERFACE_DATA* deviceInterfaceData = new SP_DEVICE_INTERFACE_DATA();
        deviceInterfaceData->cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
        int deviceInterfaceIndex = 0;

        while (SetupDiEnumDeviceInterfaces(deviceInfoSet, deviceInfoData, guid, deviceInterfaceIndex, deviceInterfaceData)) {
            deviceInterfaceIndex++;
            deviceCount++;
            totalInterfaceCount++;
        }

        totalDeviceCount++;
    }
    stringstream ssss;

    if(deviceIndex == 0) {
        ssss << "No devices. Last error = " << GetLastError() << "/n";
    }


    ssss << "Total Device Count = " << totalDeviceCount << " Total Interface Count = " << totalInterfaceCount;
    Log(ssss.str());

    SetupDiDestroyDeviceInfoList(deviceInfoSet);
    delete(deviceInfoData);
} else {
    stringstream sss;
    sss << "Invalid handle value!";
    Log(sss.str());
}

free(guid);

return deviceCount;

}

结果始终是正确的,永远不会返回INVALID_HANDLE_VALUE。但是,在某些时段内,Windows报告设备数量为0。SetupDiEnumDeviceInfo返回false,错误代码为259(ERROR_NO_MORE_ITEMS)。

Unity是基于C#的,因此我尝试了在托管代码的每一帧中调用此函数,以及在C++ DLL中旋转一个新线程并记录结果。无论如何,每次无故障时,在第一级的长时间加载中,报告的设备将变为0。并且在整个游戏过程中,间歇地,结果将在6(系统中总设备数)与0之间交替显示。有时,结果为0一次只能粘几分钟,有时只发生一帧。

使这个问题更加有趣的是XInput和Direct Input也将在与此代码完全相同的时间失败。 XInput和DI是独立的,但是我怀疑它们在内部进行相同的Windows函数调用。显然,这个问题不在我的代码中,但是我不知道什么可能导致这种情况。我怀疑其他一些插件正在干扰或可能缺少内存问题。

其他资讯:
如果我将对SetupDiGetClassDevs的调用更改为:
HDEVINFO deviceInfoSet = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_PRESENT | DIGCF_ALLCLASSES);

我始终获得有效的结果返回-168。这永远不会改变。这些都不是设备接口(interface),因此我不能使用此信息。如果我重新添加设备接口(interface)过滤器,则会间歇性地得到0。同样,只有在加载了较大级别并且游戏的内存占用量超过2GB之后,才会发生这种情况。我已经阅读了Direct Input的一些问题,并且堆内存不足导致它返回OK的结果,但没有设备,但据我所知,此问题与内存之间没有关系(除非它永远不会当内存约为500MB时,会在标题屏幕上发生此问题,只有在该级别加载超过1.6GB左右后,您才开始看到它-但同样,我无权访问该项目,以确定其中是否有某些插件/组件导致了此问题)

只是重申一下:
如果我同时运行一个并行进程(另一个使用不同项目的Unity实例)并查看日志,则在该进程返回0的同时,我始终会收到6个设备的正确值。此行为与Windows一致HID函数,直接输入和XInput。当一个失败时,所有失败。然而,同时运行的其他进程从来不会遇到在每个帧看到所有设备的问题。

Unity是基于古老版本的Mono的,因此我认为那里可能存在问题,但是我尝试通过旋转本机线程来进行测试来规避Mono的问题,这表明它实际上并没有任何区别。

经过这么长时间的工作,我一直在网上搜寻信息,但是找不到与该问题遥遥相像的东西。

编辑:忘记提及了,这个项目也使用Steam。

最佳答案

解决方法是,如果您的程序在64位操作系统上运行,则通过在0x80000000以上分配我们的可丢弃堆来强制MS代码在0x80000000以下分配内存。

关于c++ - 是什么可以导致SetupDiGetClassDevs不返回任何设备接口(interface)? (Windows,C++),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32365151/

相关文章:

c# - DateTime.ParseExact 抛出字符串格式错误 Unity3D

c++ - 适用于 Linux(和 Windows)的异步 C++ 通信库

c++ - 以编程方式检索 QSS 样式表属性的值

windows - 如何从操作系统命令行启动 PowerShell 脚本?

windows - 如何让 emacs 正确打印 pdf?

ios - UIApplicationDidBecomeActiveNotification 和 UIApplicationWillResignActiveNotification 并不总是在 Unity iOS App 中触发

c# - 如何在 Unity 中更改对象的枢轴点

c++ - 我可以通过这种方式为链接列表实现push_back方法吗?

c++ - 如何从 C++ 对 bat 文件执行命令

Windows API 编程中的组合框