繁体   English   中英

如何从注册表中读取REG_BINARY值相关值?

[英]How can i read a REG_BINARY values associated value from registry?

在注册表中有一个(或多个)密钥,具体取决于您有多少台显示器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开头&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脚本示例,但不幸的是我不理解它们,对我来说这也很重要。

你提到想要“序列号”和“类型”。 没有“类型”,但有制造商ID和产品ID。 在大多数情况下,这些不会作为有意义的字符串存储在您获取的信息中......它们只是数值。 它们都在前16个字节中。

我会根据您引用的规范解码开头。


字节0,1,2,3,4,5,6,7 - 标题信息

这应该是文字字符串“00h FFh FFh FFh FFh FFh FFh FFh 00h”,它用作我们正在查看有效EDID块的健全性检查。 您的数据完全符合我们的预期:

00 FF FF FF FF FF FF 00

字节8和9 - 制造商ID。

这些ID由Microsoft分配,并且是三字母代码。 哦,当然,他们可以用ASCII“浪费”三个完整的字节。 但那太本事了。 因此,他们在标题的极其“非魔法”数字上烧掉了八个字节,并发明了一种“巧妙”的方式将这三个字母编码为由两个字节保存的16位。 他们怎么把它拉下来?

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

因此,字节8的最高位始终为零,剩余的15位被分成3组,每组5位(我称之为α,β和γ)。 每个都被解释为一个字母,其中“00001 = A”; “00010 = B”; ......“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。 通过这种神秘的巫术,我们确定您的显示器很可能是由戴尔制造的。 :)

字节10和11 - 产品ID代码

这是一个由制造商分配的双字节数字,存储为“LSB优先”。 这就是说第一个字节是最不重要的位置值。 你有:

4C 40

我们需要将其解释为十六进制数404C

字节12,13,14,15 - 序列号。

这是制造商分配的32位值,不需要格式。 它“通常存储为LSB优先”,但不一定是。

53 43 34 42

您可以将其解释为0x534334420x42344353 ,或者其他任何...只要您在将一个值与另一个值进行比较时保持一致。


所以现在你看到它只有三个字母和一些数字。 将字节放入缓冲区后,有很多方法可以提取信息。 @freerider提供了一些关于这方面的信息,我只想再多说一些。

EDID标准说你作为描述得到的是128字节。 这是注册表项的情况,您可以假设如果没有正好128个字节则它已损坏。 所以使用@freerider提供的代码,没有必要传递大于那个...如果那是你感兴趣的EDID的唯一部分,你可以从技术上下降到16:

#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
}

除此之外,你关于如何从字节缓冲区中提取结构数据的问题是一个非常普遍的问题,并且是C风格编程的基础,如果你不知道从哪里开始那么你应该通过更简单的程序。 从制造商名称中获取三个五位段涉及位移,位屏蔽或位字段等操作。 通过数组处理地址以及如何索引数组和类似的东西。

我现在可以随意找到的最接近的平行问题是:

从字节缓冲区中提取IP

有很多方法可以做到这一点,但有趣的是你可以在内存中定义一个结构的布局,然后告诉程序“嘿,我找到的这个内存块就像我定义的结构一样。所以让我吧从中提取信息就像我在程序中定义对象一样“......

但是,您必须对数据结构对齐等问题保持敏感。 那是因为编译器自然地将对象放入内存的方式不一定与您认为的那样匹配:

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

根据上述信息,您至少应该能够阅读一些教程并了解哪些有用。 如果你无法找出问题的一部分,那么将这个小部分作为自己的问题打破,并显示你尝试了什么以及为什么它不起作用......

上一个问题解释了如何使用C / C ++ / C#获取EDID。 它不是通过注册表,但只要它工作...

在Windows XP / 7中获取EDID的Win32代码

如果您仍想阅读注册表,请使用RegQueryValueEx和朋友。

   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 ) );

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM