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

kam*_*mpi 2 c c++ windows 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
Run Code Online (Sandbox Code Playgroud)

此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)
Run Code Online (Sandbox Code Playgroud)

此链接还包含有关EDID的信息:http://en.wikipedia.org/wiki/Extended_display_identification_data

有人可以帮助我,我怎么能用C做到这一点?我只能找到VB脚本示例,但遗憾的是我不理解它们,对我来说这也很重要.

Hos*_*ork 5

你提到想要"序列号"和"类型".没有"类型",但有制造商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
Run Code Online (Sandbox Code Playgroud)

字节8和9 - 制造商ID.

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

        +--------+--------+
        | Byte 8 | Byte 9 |
--------+--------+--------+
Bit #    76543210 76543210
-----------------=---------
Meaning  0??????? ????????
Run Code Online (Sandbox Code Playgroud)

因此,字节8的最高位始终为零,剩余的15位被分成3组,每组5位(我称之为α,β和γ).每个都被解释为一个字母,其中"00001 = A"; "00010 = B"; ......"11010 = Z".

你有:

10 AC
Run Code Online (Sandbox Code Playgroud)

十六进制10AC表示为16位二进制位0001000010101100.那么让我们再把这张桌子带回来:

        +--------+--------+
        | Byte 8 | Byte 9 |
--------+--------+--------+
Bit #    76543210 76543210
-----------------=---------
Meaning  0??????? ????????
-----------------=---------
Yours    00010000 10101100
Run Code Online (Sandbox Code Playgroud)

所以? = 00100(十进制4),? = 00101(十进制5),? = 01100(十进制12).使用这些十进制数作为英文字母的索引,我们得到DEL.通过这种神秘的巫术,我们确定您的显示器很可能是由戴尔制造的.:)

字节10和11 - 产品ID代码

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

4C 40
Run Code Online (Sandbox Code Playgroud)

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

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

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

53 43 34 42
Run Code Online (Sandbox Code Playgroud)

您可以将其解释为0x53433442,或者0x42344353等等......只要您将一个值与另一个值进行比较是一致的.


所以现在你看到它只有三个字母和一些数字.将字节放入缓冲区后,有很多方法可以提取信息.@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
}
Run Code Online (Sandbox Code Playgroud)

(注意:我更喜欢避免使用上面的sizeof@ freerider这样的on数组sizeof( Buffer ).虽然它在技术上可以在这种情况下工作,但它不会返回数组中的元素数...而是数组在内存中占用的字节数在这种情况下,元素碰巧实际上是字节,所以它会起作用......但是你很快遇到问题,比如当你通过指针将数组传递给另一个函数时,突然它开始报告它的大小作为指针的大小...)

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

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

从字节缓冲区中提取IP

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

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

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

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