2012-03-01 109 views
4

我试图以编程方式在我的监视器上获取信息。循环的内容现在并不重要,它们只包含在满足循环条件时将打印的调试语句。现在,外部循环代码执行三次,而内部循环代码从未被访问,这意味着(内部)循环的while条件从不为真,这意味着调用失败。EnumDisplayDevices函数不适合我

我在这里的问题是,在Windows API称,关于此功能:

为了获得一个显示器上lpDevice,第一个电话EnumDisplayDevices>设置为NULL信息。然后调用EnumDisplayDevices并将lpDevice设置为DISPLAY_DEVICE.DeviceName>,从第一次调用EnumDisplayDevices并将iDevNum设置为零。然后> DISPLAY_DEVICE.DeviceString是监视器名称。

...但即使做完了它所说的,第二个EnumDisplayDevices调用总是失败?任何见识?

此外,我正在做这个作为服务级别的应用程序在Windows XP和Windows 7上获得相同的结果。当我尝试打印出dd.DeviceName时,它给了我一个地址(例如:0x12cfa4),但是这必须是函数在第二次调用时所期待的,因为MSDN只是传递显示设备指针并将.DeviceName附加到它...

C++(使用Qt),使用Windows API/MSDN调用。

DISPLAY_DEVICE dd; 

    dd.cb = sizeof(DISPLAY_DEVICE); 

    DWORD deviceNum = 0; 
    while(EnumDisplayDevices(NULL, deviceNum, &dd, 0)){ 
     qWarning() << "We've entered the outer loop."; 

     while(EnumDisplayDevices(dd.DeviceName, 0, &dd, 0)){ 
      qWarning() << "We've entered the inner loop."; 
     } 

     deviceNum++; 
    } 

回答

9

问题是在使用'dd'的成员作为输入字符串时将'dd'传入内部调用。我知道这是没有道理的,但我怀疑由于dd是一个输出参数,API正在写入它,但是在输入参数的内容在它上面写着之后再查看它。这可能会发生,如果他们在执行完成之前执行了将输出参数memset为0的操作。

只要确保它不是在发送一个非空的dd的东西,我做了第二个dd与它完全相同的位,事情仍然正常工作。这绝对是别名记忆。

#include <windows.h> 
#include <stdio.h> 

#pragma comment(lib, "user32.lib") 

void DumpDevice(const DISPLAY_DEVICE& dd, size_t nSpaceCount) 
{ 
    printf("%*sDevice Name: %s\n", nSpaceCount, "", dd.DeviceName); 
    printf("%*sDevice String: %s\n", nSpaceCount, "", dd.DeviceString); 
    printf("%*sState Flags: %x\n", nSpaceCount, "", dd.StateFlags); 
    printf("%*sDeviceID: %s\n", nSpaceCount, "", dd.DeviceID); 
    printf("%*sDeviceKey: ...%s\n\n", nSpaceCount, "", dd.DeviceKey+42); 
} 

int main() 
{ 
    DISPLAY_DEVICE dd; 

    dd.cb = sizeof(DISPLAY_DEVICE); 

    DWORD deviceNum = 0; 
    while(EnumDisplayDevices(NULL, deviceNum, &dd, 0)){ 
     DumpDevice(dd, 0); 
     DISPLAY_DEVICE newdd = {0}; 
     newdd.cb = sizeof(DISPLAY_DEVICE); 
     DWORD monitorNum = 0; 
     while (EnumDisplayDevices(dd.DeviceName, monitorNum, &newdd, 0)) 
     { 
      DumpDevice(newdd, 4); 
      monitorNum++; 
     } 
     puts(""); 
     deviceNum++; 
    } 

    return 0; 
} 

我在这个盒子,现在只有1个显示器,所以我无法验证内部循环,但我怀疑,因为“newdd”永远不会被叠到调用它的罚款。你也可以说你在服务环境中 - 我不确定这个Winstation是否会限制你对显示器的看法 - 这也可能是一个问题;但我怀疑你仍然应该至少能够看到物理设备。在我的机器,我得到:

Device Name: \\.\DISPLAY1 
Device String: NVIDIA GeForce GTX 580 
State Flags: 8000005 
DeviceID: PCI\VEN_10DE&DEV_1080&SUBSYS_15803842&REV_A1 
DeviceKey: ...\Control\Video\{B0CDD262-FCFB-4FD4-A03C-54621896C9CD}\0000 

    Device Name: \\.\DISPLAY1\Monitor0 
    Device String: Generic PnP Monitor 
    State Flags: 3 
    DeviceID: MONITOR\DEL4016\{4d36e96e-e325-11ce-bfc1-08002be10318}\0002 
    DeviceKey: ...\Control\Class\{4d36e96e-e325-11ce-bfc1-08002be10318}\0002 

Device Name: \\.\DISPLAY2 
Device String: NVIDIA GeForce GTX 580 
State Flags: 0 
DeviceID: PCI\VEN_10DE&DEV_1080&SUBSYS_15803842&REV_A1 
DeviceKey: ...\Control\Video\{B0CDD262-FCFB-4FD4-A03C-54621896C9CD}\0001 

Device Name: \\.\DISPLAYV1 
Device String: RDPDD Chained DD 
State Flags: 8 
DeviceID: 
DeviceKey: ...\Control\Video\{DEB039CC-B704-4F53-B43E-9DD4432FA2E9}\0000 

Device Name: \\.\DISPLAYV2 
Device String: RDP Encoder Mirror Driver 
State Flags: 200008 
DeviceID: 
DeviceKey: ...\Control\Video\{42cf9257-1d96-4c9d-87f3-0d8e74595f78}\0000 

Device Name: \\.\DISPLAYV3 
Device String: RDP Reflector Display Driver 
State Flags: 200008 
DeviceID: 
DeviceKey: ...\Control\Video\{b043b95c-5670-4f10-b934-8ed0c8eb59a8}\0000 
+0

我刚刚写完很多相同的东西。别名是问题。 – arx 2012-03-01 22:06:43

+0

不知道这是自发布代码以来发生了什么变化,但我发现在MSVC2015中,我必须使用%S而不是%s,因为DeviceName,DeviceString等是WCHAR数组,我猜想包含/ 0数据在每秒字符中。 – scone 2016-02-09 00:24:17