C++ 如何从注册表读取REG_二进制值关联值?

C++ 如何从注册表读取REG_二进制值关联值?,c++,c,windows,registry,C++,C,Windows,Registry,注册表中有一个(或多个)键,具体取决于您有多少个监视器HKEY\U LOCAL\U MACHINE\SYSTEM\CurrentControlSet\Enum\DISPLAY\DEL404C\{Some Unique ID}\Device Parameters\EDID,这是一个REG\u二进制键。就我而言,这是: 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 9

注册表中有一个(或多个)键,具体取决于您有多少个监视器
HKEY\U LOCAL\U MACHINE\SYSTEM\CurrentControlSet\Enum\DISPLAY\DEL404C\{Some Unique ID}\Device Parameters\EDID
,这是一个
REG\u二进制键。就我而言,这是:

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_二进制值包含有关所连接监视器的信息(如序列号和类型)。我只需要这两个值。我的问题是如何用C或C++ +< /P>读取这些值? 我有一个VB脚本可以实现这一点:
'如果位置以
&H00 ff
strSerFind=Chr(&H00)&Chr(&H00)&Chr(&H00)&Chr(&HfF)

'或以
&H00 fc

strMdlFind=Chr(&H00) & Chr(&H00) & Chr(&H00) & Chr(&Hfc)
此链接还包含有关EDID的信息:


有人能帮我吗,我怎么能用C来做这个?我只能找到VB脚本示例,但不幸的是我不理解它们,而且这对我来说非常重要

前面的问题解释了如何使用C/C++/C#获取EDID。它不是通过注册表,但只要它有效

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

   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 ) );
你提到想要“序列号”和“类型”。没有“类型”,但有一个制造商ID和一个产品ID。在大多数情况下,它们不会作为有意义的字符串存储在您获取的信息中……它们只是数值。它们都在前16个字节中

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


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

这应该是文本字符串“00h FFh FFh FFh FFh 00h”,它用于检查我们是否正在查看有效的EDID块。您的数据从我们期望的内容开始:

00 FF FF FF FF FF FF 00
字节8和9-制造商ID

这些ID由Microsoft分配,是三个字母的代码。哦,当然,他们可能为此“浪费”了整整三个ASCII字节。但这太明智了。因此,他们在一个非常“非魔法”的标题数字上浪费了八个字节,并发明了一种“巧妙”的方法将这三个字母编码为两个字节所包含的十六位。他们是怎么做到的

        +--------+--------+
        | Byte 8 | Byte 9 |
--------+--------+--------+
Bit #    76543210 76543210
-----------------=---------
Meaning  0αααααββ βββγγγγγ
所以字节8的最高阶位总是零,剩下的15位被分成三组,每组5位(我称之为α、β和γ)。每一个都被解释为一个字母,其中“00001=a”;“00010=B”。。。“11010=Z”

你有:

10 AC
用16位二进制表示的十六进制
10AC
0001000010101100
。让我们把那张桌子拿回来:

        +--------+--------+
        | Byte 8 | Byte 9 |
--------+--------+--------+
Bit #    76543210 76543210
-----------------=---------
Meaning  0αααααββ βββγγγγγ
-----------------=---------
Yours    00010000 10101100
因此
α=00100
(十进制4),
β=00101
(十进制5),
γ=01100
(十进制12)。使用这些十进制数字作为英文字母表的索引,我们得到了D-E-L。通过这种神秘的魔法,我们确定您的显示器很可能是戴尔制造的。:)

字节10和11-产品ID代码

这是一个由制造商分配的双字节编号,存储为“LSB first”。也就是说,第一个字节是最低有效位值。你有:

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

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

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

53 43 34 42
您可以将其解释为
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
}
(注意:我倾向于避免在@freerider's
sizeof(Buffer)等数组上使用
sizeof
以上。虽然从技术上讲,它在这种情况下可以工作,但它不会返回数组中的元素数……相反,在这种情况下,元素恰好是字节,因此它可以工作……但很快就会遇到问题,例如,当您通过指针将数组传递给另一个函数时,它突然开始将其大小报告为0的大小f指针…)

除此之外,如何从字节缓冲区中提取结构数据是一个非常普遍的问题,对于C风格编程来说是非常基础的,如果您不知道从哪里开始,那么您可能应该使用更简单的程序。从制造商名称中获取三个五位段涉及位移位、位屏蔽或位字段等内容。遍历数组涉及地址以及如何索引数组之类的内容

我现在能马上找到的最接近的平行问题是:

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

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

有了以上信息,你至少应该能够做出一个决定