简体   繁体   English

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

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

In the registry there is one ( or more ) key depending how many monitors you have HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Enum\\DISPLAY\\DEL404C\\{Some Unique ID}\\Device Parameters\\EDID which is a REG_BINARY key . 在注册表中有一个(或多个)密钥,具体取决于您有多少台显示器HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Enum\\DISPLAY\\DEL404C\\{Some Unique ID}\\Device Parameters\\EDID这是一个REG_BINARY key In my case this is : 在我的情况下,这是:

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

This reg_binary value contains information (such as Serial Number and Type) about the connected monitor. 此reg_binary值包含有关已连接监视器的信息(如序列号和类型)。 I only need these two values. 我只需要这两个值。 My question is how can i read these values using C or C++? 我的问题是如何使用C或C ++读取这些值?

I have a VB script which can do this: 我有一个VB脚本,可以这样做:
'you can tell If the location contains a serial number If it starts with &H00 00 00 ff strSerFind=Chr(&H00) & Chr(&H00) & Chr(&H00) & Chr(&HfF) '你可以判断该位置是否包含一个序列号如果它以&H00 00 00 ff开头&H00 00 00 ff strSerFind=Chr(&H00) & Chr(&H00) & Chr(&H00) & Chr(&HfF)

'or a model description If it starts with &H00 00 00 fc '或型号说明如果以&H00 00 00 fc开头

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

This link also contains information about EDID: http://en.wikipedia.org/wiki/Extended_display_identification_data 此链接还包含有关EDID的信息: http//en.wikipedia.org/wiki/Extended_display_identification_data

Could someone help me, how can i do this in C? 有人可以帮助我,我怎么能用C做到这一点? I can find only VB script examples, but unfortunately i don't understand them, and also it would be very important for me. 我只能找到VB脚本示例,但不幸的是我不理解它们,对我来说这也很重要。

You mention wanting the "serial number" and "type". 你提到想要“序列号”和“类型”。 There is no "type" but there is a manufacturer ID and a product ID. 没有“类型”,但有制造商ID和产品ID。 For the most part these aren't stored as meaningful strings in the information you get back...they are just numeric values. 在大多数情况下,这些不会作为有意义的字符串存储在您获取的信息中......它们只是数值。 And they're all in the first 16 bytes. 它们都在前16个字节中。

I'll decode the beginning according to the spec you cite. 我会根据您引用的规范解码开头。


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

This should be the literal string "00h FFh FFh FFh FFh FFh FFh 00h", which serves as a sanity check that we're looking at a valid EDID block. 这应该是文字字符串“00h FFh FFh FFh FFh FFh FFh FFh 00h”,它用作我们正在查看有效EDID块的健全性检查。 Your data starts off with exactly what we expect: 您的数据完全符合我们的预期:

00 FF FF FF FF FF FF 00

Bytes 8 and 9 - Manufacturer ID. 字节8和9 - 制造商ID。

These IDs are assigned by Microsoft, and are three-letter codes. 这些ID由Microsoft分配,并且是三字母代码。 Oh sure, they could have "wasted" three whole bytes in ASCII for this. 哦,当然,他们可以用ASCII“浪费”三个完整的字节。 But that would have been too sensible. 但那太本事了。 So they frittered away eight bytes on an extremely "non-magic" number for the header, and invented an "ingenious" way to encode those three letters into the sixteen bits held by two bytes. 因此,他们在标题的极其“非魔法”数字上烧掉了八个字节,并发明了一种“巧妙”的方式将这三个字母编码为由两个字节保存的16位。 How'd they pull it off? 他们怎么把它拉下来?

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

So the highest-order bit of Byte 8 is always zero, and the remaining 15 bits are divided into three groups of 5 bits (which I've called α, β, and γ). 因此,字节8的最高位始终为零,剩余的15位被分成3组,每组5位(我称之为α,β和γ)。 Each is interpreted as a letter, where "00001=A"; 每个都被解释为一个字母,其中“00001 = A”; "00010=B"; “00010 = B”; ... "11010=Z". ......“11010 = Z”。

You've got: 你有:

10 AC

And hexadecimal 10AC expressed as 16 binary bits is 0001000010101100 . 十六进制10AC表示为16位二进制位是0001000010101100 So let's bring that table back again: 所以让我们再次把那张桌子带回来:

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

So α = 00100 (decimal 4), β = 00101 (decimal 5), γ = 01100 (decimal 12). 所以α = 00100 (十进制4), β = 00101 (十进制5), γ = 01100 (十进制12)。 Using those decimal numbers as indexes into the English alphabet we get DEL. 使用这些十进制数作为英文字母的索引,我们得到DEL。 By this arcane sorcery we have determined that your monitor is most likely made by Dell. 通过这种神秘的巫术,我们确定您的显示器很可能是由戴尔制造的。 :) :)

Bytes 10 and 11 - Product ID Code 字节10和11 - 产品ID代码

This is a two-byte number, assigned by the manufacturer, stored as "LSB first". 这是一个由制造商分配的双字节数字,存储为“LSB优先”。 This is to say that the first byte is the least significant place value. 这就是说第一个字节是最不重要的位置值。 You have: 你有:

4C 40

Which we need to interpret as the hexadecimal number 404C . 我们需要将其解释为十六进制数404C

Bytes 12,13,14,15 - Serial Number. 字节12,13,14,15 - 序列号。

This is a 32-bit value assigned by the manufacturer which has no requirement for the format. 这是制造商分配的32位值,不需要格式。 It is "usually stored as LSB first", but doesn't have to be. 它“通常存储为LSB优先”,但不一定是。

53 43 34 42

You can interpret that as 0x53433442 , or 0x42344353 , or whatever...so long as you're consistent in comparing one value against another. 您可以将其解释为0x534334420x42344353 ,或者其他任何...只要您在将一个值与另一个值进行比较时保持一致。


So now you see it's just three letters and some numbers. 所以现在你看到它只有三个字母和一些数字。 Once you get the bytes into a buffer there are a lot of ways to extract the information. 将字节放入缓冲区后,有很多方法可以提取信息。 @freerider provided some information on that, I'll just throw in a bit more. @freerider提供了一些关于这方面的信息,我只想再多说一些。

The EDID standard says that what you get back as a description is 128 bytes. EDID标准说你作为描述得到的是128字节。 That is the case with the registry key here, and you can probably assume that if there are not exactly 128 bytes it is corrupt. 这是注册表项的情况,您可以假设如果没有正好128个字节则它已损坏。 So using the code provided by @freerider, there'd be no need to pass in anything larger than that...you could technically go down to just 16 if that's the only part of the EDID you're interested in: 所以使用@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
}

(Note: I prefer to avoid using the sizeof on arrays like @freerider's sizeof( Buffer ) above. While it will technically work in this case, it doesn't return the number of elements in the array...rather the number of bytes the array occupies in memory . In this case the elements happen to actually be bytes, so it will work...but you quickly run into problems, like when you pass an array to another function by pointer and suddenly it starts reporting its size as the size of a pointer...) (注意:我更喜欢避免在像@ freerider的sizeof( Buffer )这样的数组上使用sizeof 。虽然它在技术上适用于这种情况,但它不会返回数组中的元素数...而是字节数数组在内存中占用 。在这种情况下,元素实际上是字节,因此它可以工作......但是你很快遇到问题,比如当你通过指针将数组传递给另一个函数时,突然它开始报告其大小为指针的大小......)

Beyond that, your question of how to extract structural data out of a buffer of bytes is a very general one, and is so foundational to C-style programming that if you don't know where to start on it then you should probably work through simpler programs. 除此之外,你关于如何从字节缓冲区中提取结构数据的问题是一个非常普遍的问题,并且是C风格编程的基础,如果你不知道从哪里开始那么你应该通过更简单的程序。 Getting the three five bit segments out of the manufacturer name involves things like bit shifting, bit masking, or bit fields. 从制造商名称中获取三个五位段涉及位移,位屏蔽或位字段等操作。 Going through the array deals with addresses and how to index arrays and things like that. 通过数组处理地址以及如何索引数组和类似的东西。

The closest parallel question I could find offhand right now is this: 我现在可以随意找到的最接近的平行问题是:

extract IP from a buffer of bytes 从字节缓冲区中提取IP

Lots of ways to do it, but an interesting one is that you can define the layout of a structure in memory and then tell the program "hey, this block of memory I found is laid out just like the structure I defined. So let me extract information from it as simply as if I'd defined the object in my program"... 有很多方法可以做到这一点,但有趣的是你可以在内存中定义一个结构的布局,然后告诉程序“嘿,我找到的这个内存块就像我定义的结构一样。所以让我吧从中提取信息就像我在程序中定义对象一样“......

But then you have to be sensitive to issues like data structure alignment. 但是,您必须对数据结构对齐等问题保持敏感。 That's because the way your compiler will naturally put objects into memory doesn't necessarily match what you think it would do: 那是因为编译器自然地将对象放入内存的方式不一定与您认为的那样匹配:

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

With the information above you should at least be able to make a shot at reading some tutorials and seeing what works. 根据上述信息,您至少应该能够阅读一些教程并了解哪些有用。 If you can't figure out one part of the problem then break that little part out as its own question, and show what you tried and why it didn't work... 如果你无法找出问题的一部分,那么将这个小部分作为自己的问题打破,并显示你尝试了什么以及为什么它不起作用......

This previous question explains how to get EDID with C/C++/C#. 上一个问题解释了如何使用C / C ++ / C#获取EDID。 It's not through the registry, but as long it works... 它不是通过注册表,但只要它工作...

Win32 code to get EDID in Windows XP/7 在Windows XP / 7中获取EDID的Win32代码

If you want to still read the registry, use RegQueryValueEx and friends. 如果您仍想阅读注册表,请使用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;
        }   
    }

call it like this: 这样叫:

BYTE Buffer[20000];
DWORD nLength = GetLocalMachineProfileBuffer( Buffer, sizeof( Buffer ) );

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

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