Pergunta

Para o meu projeto atual C ++ Eu preciso para detectar uma cadeia exclusiva para cada monitor que está conectado e ativo em um grande número de computadores.

A investigação apontou para 2 opções

  1. Use WMI e consulta a Win32_DesktopMonitor para todos os monitores ativos. Use o PNPDeviceID para a identificação única de monitores.

  2. Use o EnumDisplayDevices API, e cavar para baixo para obter o ID do dispositivo.

Estou interessado em usar o ID do dispositivo para identificação modelo único porque os monitores usando o plugue padrão e motorista jogo irá relatar uma corda genérico como o nome do monitor "plug padrão e um monitor play"

Fui experimentando problemas com o método WMI, parece ser apenas retornando 1 monitor na minha máquina Vista, olhando para o doco despeja ele não funciona como esperado em dispositivos não WDDM.

Os EnumDisplayDevices parece ser um pouco problemático para começar quando ele é executado a partir de um serviço de fundo (especialmente no Vista), Se é em sessão 0 retornará nenhuma informação.

  • Tem mais alguém teve que fazer algo semelhante (encontrar cadeia de modelo único para todos os monitores ativos conectados?)

  • Que abordagem funcionou melhor?

Foi útil?

Solução

Este é o meu código atual work-in-progress para detectar o ID do dispositivo monitor, de forma confiável.

CString DeviceID;
DISPLAY_DEVICE dd; 
dd.cb = sizeof(dd); 
DWORD dev = 0; 
// device index 
int id = 1; 
// monitor number, as used by Display Properties > Settings

while (EnumDisplayDevices(0, dev, &dd, 0))
{
    DISPLAY_DEVICE ddMon;
    ZeroMemory(&ddMon, sizeof(ddMon));
    ddMon.cb = sizeof(ddMon);
    DWORD devMon = 0;

    while (EnumDisplayDevices(dd.DeviceName, devMon, &ddMon, 0))
    {
        if (ddMon.StateFlags & DISPLAY_DEVICE_ACTIVE && 
                     !(ddMon.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER))
        {
            DeviceID.Format (L"%s", ddMon.DeviceID);
            DeviceID = DeviceID.Mid (8, DeviceID.Find (L"\\", 9) - 8);
        }
        devMon++;

        ZeroMemory(&ddMon, sizeof(ddMon));
        ddMon.cb = sizeof(ddMon);
    }

    ZeroMemory(&dd, sizeof(dd));
    dd.cb = sizeof(dd);
    dev++; 
}

Outras dicas

Eu só descobri que você pode consultar Win32_PnPEntity para o serviço = "Monitor", e ele irá retornar todos os monitores.

Os resultados na minha máquina:

select * from Win32_PnPEntity where service="monitor"

Availability | Caption               | ClassGuid                              | CompatibleID | ConfigManagerErrorCode | ConfigManagerUserConfig | CreationClassName | Description           | DeviceID                           | ErrorCleared | ErrorDescription | HardwareID  | InstallDate | LastErrorCode | Manufacturer | Name                  | PNPDeviceID                        | PowerManagementCapabilities | PowerManagementSupported | Service | Status | StatusInfo | SystemCreationClassName | SystemName
             | Dell 2007FP (Digital) | {4d36e96e-e325-11ce-bfc1-08002be10318} | array[0..0]  | 0                      | False                   | Win32_PnPEntity   | Dell 2007FP (Digital) | DISPLAY\DELA021\5&4F61016&0&UID257 |              |                  | array[0..0] |             |               | Dell Inc.    | Dell 2007FP (Digital) | DISPLAY\DELA021\5&4F61016&0&UID257 |                             |                          | monitor | OK     |            | Win32_ComputerSystem    | 8HVS05J
             | Dell ST2320L_Digital  | {4d36e96e-e325-11ce-bfc1-08002be10318} | array[0..0]  | 0                      | False                   | Win32_PnPEntity   | Dell ST2320L_Digital  | DISPLAY\DELF023\5&4F61016&0&UID256 |              |                  | array[0..0] |             |               | Dell Inc.    | Dell ST2320L_Digital  | DISPLAY\DELF023\5&4F61016&0&UID256 |                             |                          | monitor | OK     |            | Win32_ComputerSystem    | 8HVS05J

Estamos brincando com EnumDisplayDevices a fim de detectar se o fabricante atual placa de vídeo é NVIDIA. Não é o mesmo, mas talvez ele iria ajudar. Nossa peça ficou assim:

int disp_num = 0;
    BOOL res = TRUE;
    do {
        DISPLAY_DEVICE disp_dev_info; 
        ZeroMemory( &disp_dev_info, sizeof(DISPLAY_DEVICE) );
        disp_dev_info.cb = sizeof(DISPLAY_DEVICE);
        res = EnumDisplayDevices( 0, disp_num++, &disp_dev_info, 0x00000001 );
        if(res &&
           disp_dev_info.DeviceString[0]!=0 && disp_dev_info.DeviceString[0]=='N' &&
           disp_dev_info.DeviceString[1]!=0 && disp_dev_info.DeviceString[1]=='V' && 
           disp_dev_info.DeviceString[2]!=0 && disp_dev_info.DeviceString[2]=='I' && 
           disp_dev_info.DeviceString[3]!=0 && disp_dev_info.DeviceString[3]=='D' && 
           disp_dev_info.DeviceString[4]!=0 && disp_dev_info.DeviceString[4]=='I' && 
           disp_dev_info.DeviceString[5]!=0 && disp_dev_info.DeviceString[5]=='A'){
            isNVidia = true;
        }
        int x = 0;
    }while( res != FALSE );

Pretty idiota, mas de trabalho.

Eu nunca tentei fazê-lo a partir de um serviço, mas EnumDisplayDevices geralmente funciona bem quando executado como um usuário. Eu acredito que os serviços são executados em uma sessão separada (e sem cabeça), o que poderia explicar o problema que você está vendo lá.

Você poderia executar um programa de ajuda de seu serviço, representando uma conta de usuário que tenha acesso aos ecrãs?

O método Win32_DesktopMonitor retorna apenas 1 monitor na minha máquina Vista também. O PnP ID parece ser definido corretamente, no entanto.

Eu tive um jogo rápido com a API EnumDisplayDevices, e enquanto parece descobrir os detalhes do adaptador de forma confiável (presumivelmente porque a maioria das pessoas não vai deixá-lo como "VGA Standard" por muito tempo), ele só retorna "Plug and Play monitor" para os monitores conectados.

Este ecos pesquisa que eu fiz para isso há vários anos (tinha que colocar algum código em conjunto para ajuda na Sova essas memórias off).

Esta é a partir de uma conta de usuário normal. Se você tem uma maneira confiável para obter EnumDisplayDevices para devolver o PnP ID, mesmo em sessões de usuário normais, eu estaria interessado - estamos investigando se qualquer uma dessas informações está disponível para um driver de dispositivo

Uma coisa que você poderia fazer, se executar o código de sessão # 0 não é suficiente confiável, é para ver se você pode gerar um processo helper (usando CreateProcessAsUser ou usando COM com apelidos de ativação), que vai correr na contexto do usuário.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top