Как я могу прочитать значения REG_BINARY, связанные значения из реестра? - PullRequest
2 голосов
/ 06 сентября 2011

В реестре есть один (или более) ключ, в зависимости от того, сколько у вас мониторов HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\DISPLAY\DEL404C\{Some Unique ID}\Device Parameters\EDID, то есть REG_BINARY key. В моем случае это:

00 FF FF FF FF FF FF 00 10 AC 4C 40 53 43 34 42 34 14 01 03 0A 2F 1E 78 EE EE 95 A3 54
4C 99 26 0F 50 54 A5 4B 00 71 4F 81 80 B3 00 01 01 01 01 01 01 01 01 01 01 21 39 90 30 
62 1A 27 40 68 B0 36 00 DA 28 11 00 00 1C 00 00 00 FF 00 34 57 31 4D 44 30 43 53 42 34 
43 53 0A 00 00 00 FC 00 44 45 4C 4C 20 50 32 32 31 30 0A 20 20 00 00 00 FD 00 38 4B 1E 
53 10 00 0A 20 20 20 20 20 20 00 FA

Это значение reg_binary содержит информацию (например, серийный номер и тип) о подключенном мониторе. Мне нужны только эти два значения. У меня вопрос, как я могу прочитать эти значения, используя C или C ++?

У меня есть скрипт VB, который может сделать это:
«Вы можете сказать, если местоположение содержит серийный номер, если оно начинается с &H00 00 00 ff strSerFind=Chr(&H00) & Chr(&H00) & Chr(&H00) & Chr(&HfF)

'или описание модели, если оно начинается с &H00 00 00 fc

strMdlFind=Chr(&H00) & Chr(&H00) & Chr(&H00) & Chr(&Hfc)

Эта ссылка также содержит информацию об EDID: http://en.wikipedia.org/wiki/Extended_display_identification_data

Может ли кто-нибудь помочь мне, как я могу сделать это в C? Я могу найти только примеры сценариев VB, но, к сожалению, я их не понимаю, а также это было бы очень важно для меня.

Ответы [ 3 ]

5 голосов
/ 06 сентября 2011

Вы упоминаете, что хотите "серийный номер" и "тип".Здесь нет «типа», но есть идентификатор производителя и идентификатор продукта.По большей части они не хранятся в виде значимых строк в информации, которую вы возвращаете ... они просто числовые значения.И все они в первых 16 байтах.

Я буду декодировать начало в соответствии со спецификацией, которую вы цитируете.


Байты 0,1,2,3, 4,5,6,7 - Информация заголовка

Это должна быть буквальная строка «00h FFh FFh FFh FFh FFh FFh 00h», которая служит проверкой работоспособности, которую мы смотрим надействительный блок EDID.Ваши данные начинаются с того, что мы ожидаем:

00 FF FF FF FF FF FF 00

Байты 8 и 9 - Идентификатор производителя.

Эти идентификаторы назначаются Microsoft и имеют трибуквенные коды.О, конечно, они могли бы "потратить" три целых байта в ASCII для этого.Но это было бы слишком разумно.Таким образом, они отбросили восемь байтов чрезвычайно «немагического» числа для заголовка и изобрели «оригинальный» способ кодировать эти три буквы в шестнадцать битов, содержащихся в двух байтах.Как они справились?

        +--------+--------+
        | Byte 8 | Byte 9 |
--------+--------+--------+
Bit #    76543210 76543210
-----------------=---------
Meaning  0αααααββ βββγγγγγ

Таким образом, бит старшего разряда байта 8 всегда равен нулю, а оставшиеся 15 бит разделены на три группы по 5 бит (которые я назвал α, β и γ).Каждый интерпретируется как буква, где «00001 = A»;"00010 = В";... "11010 = Z".

Вы получили:

10 AC

И шестнадцатеричное 10AC, выраженное в 16 двоичных разрядах, равно 0001000010101100.Итак, давайте снова вернем эту таблицу:

        +--------+--------+
        | Byte 8 | Byte 9 |
--------+--------+--------+
Bit #    76543210 76543210
-----------------=---------
Meaning  0αααααββ βββγγγγγ
-----------------=---------
Yours    00010000 10101100

Итак α = 00100 (десятичный 4), β = 00101 (десятичный 5), γ = 01100 (десятичный 12).Используя эти десятичные числа в качестве указателей на английский алфавит, мы получаем DEL.По этому тайному колдовству мы определили, что ваш монитор, скорее всего, сделан Dell.:)

Байты 10 и 11 - Идентификатор продукта Код

Это двухбайтовый номер, назначенный производителем и сохраненный как «LSB first».Это означает, что первый байт является наименее значимым значением места.У вас есть:

4C 40

Который нам нужно интерпретировать как шестнадцатеричное число 404C.

Байт 12,13,14,15 - Серийный номер.

Это 32-разрядное значение, назначенное производителем, которое не имеет требований к формату.Он «обычно сохраняется как младший бит», но не обязательно.

53 43 34 42

Вы можете интерпретировать это как 0x53433442, или 0x42344353, или как угодно ... до тех пор, пока выпоследовательны в сравнении одного значения с другим.


Итак, теперь вы видите, что это всего три буквы и несколько цифр.Как только вы помещаете байты в буфер, есть много способов извлечь информацию.@freerider предоставил некоторую информацию об этом, я просто добавлю немного больше.

Стандарт EDID говорит, что в качестве описания вы получите 128 байтов.Это относится к разделу реестра, и вы, вероятно, можете предположить, что, если нет точно 128 байтов, он поврежден.Таким образом, используя код, предоставленный @freerider, не нужно было бы передавать что-то большее, чем это ... технически вы могли бы опуститься до 16, если это единственная часть EDID, которая вас интересует:

#define EDID_BUFFER_SIZE 128
// in idiomatic C++ it's better to say:
//     const size_t edidBufferSize = 128;

BYTE edidBuffer[EDID_BUFFER_SIZE];
DWORD nLength = GetLocalMachineProfileBuffer( Buffer, EDID_BUFFER_SIZE );
if (nLength != EDID_BUFFER_SIZE) {
    // handle error case, not a valid EDID block
} else {
    // valid EDID block, do extraction:
    // * manufacturer ID
    // * product ID
    // * serial number
}

(Примечание: я предпочитаю избегать использования sizeof для массивов, таких как @ freerider's sizeof( Buffer ) выше. Хотя это технически будет работать в этом случае, оно не возвращает количество элементов вмассив ... скорее количество байтов, которое массив занимает в памяти . В этом случае элементы оказываются фактически байтами, так что это будет работать ... но вы быстро сталкиваетесь с проблемами, как когда выпередать массив в другую функцию по указателю, и вдруг он начинает сообщать свой размер как размер указателя ...)

Кроме того, ваш вопрос о том, как извлечь структурные данные из буфера байтов, является очень общим и настолько фундаментальным для программирования в стиле C, что если вы не знаете, с чего начать, то вам, вероятно, следуетработать через более простые программы.Получение трех пятибитных сегментов из названия производителя включает такие вещи, как смещение битов, маскирование битов или битовые поля.Прохождение массива имеет дело с адресами и с тем, как индексировать массивы и тому подобное.

Ближайший параллельный вопрос, который я мог бы найти сейчас, заключается в следующем:

извлечение IP из буферабайт

Множество способов сделать это, но интересным является то, что вы можете определить расположение структуры в памяти и затем сказать программе: «Эй, этот блок памяти, который я нашел, заложенкак структура, которую я определил. Итак, позвольте мне извлечь информацию из нее так же просто, как если бы я определил объект в моей программе "...

Но тогда вы должны быть чувствительны к таким вопросам, как структура данныхвыравнивание.Это связано с тем, что способ, которым ваш компилятор естественным образом помещает объекты в память, не обязательно соответствует тому, что вы думаете:

http://en.wikipedia.org/wiki/Data_structure_alignment

С приведенной выше информацией вы по крайней мере сможетепопробуйте прочитать некоторые учебники и посмотреть, что работает.Если вы не можете понять одну часть проблемы, выделите эту небольшую часть как отдельный вопрос и покажите, что вы пытались и почему она не сработала ...

2 голосов
/ 06 сентября 2011

Этот предыдущий вопрос объясняет, как получить EDID с C / C ++ / C #. Это не через реестр, но пока работает ...

Код Win32 для получения EDID в Windows XP / 7

Если вы все еще хотите прочитать реестр, используйте RegQueryValueEx и друзей.

1 голос
/ 06 сентября 2011
   DWORD GetLocalMachineProfileBuffer(BYTE* pBuffer, DWORD nMaxLength )
    {
        CString szSubKey = "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\DISPLAY\DEL404C{Some Unique ID}\Device Parameters\EDID";

        DWORD   rc; 
        DWORD   dwType; 
        HKEY    hOpenedKey;

        if( ERROR_SUCCESS == RegOpenKeyEx (
                HKEY_LOCAL_MACHINE, // handle of open key 
                szSubKey,               // address of name of subkey to open 
                0,                  // reserved 
                KEY_READ,       // security access mask 
                &hOpenedKey            // address of handle of open key 
                ) )
        {
            rc = RegQueryValueEx( 
                hOpenedKey, 
                (const char*)szValueName, 
                0, 
                &dwType, 
                (LPBYTE)pBuffer, 
                &nMaxLength ); 
            if( rc != ERROR_SUCCESS ) 
            { 
                return (DWORD)-1;
            } 
            else 
            { 
                ASSERT( dwType == REG_BINARY ); 
            } 

            RegCloseKey( hOpenedKey );
            return nMaxLength; 
        }
        else
        {
            return (DWORD)-1;
        }   
    }

Назовите это так:

BYTE Buffer[20000];
DWORD nLength = GetLocalMachineProfileBuffer( Buffer, sizeof( Buffer ) );
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...