windows 如何从注册表中读取 REG_BINARY 值关联的值?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7317281/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 18:00:29  来源:igfitidea点击:

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

c++cwindowsregistry

提问by kampi

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\EDIDwhich is a REG_BINARY key. In my case this is :

在注册表中有一个(或多个)键,具体取决于您拥有的显示器数量HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\DISPLAY\DEL404C\{Some Unique ID}\Device Parameters\EDIDREG_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

This reg_binary value contains information (such as Serial Number and Type) about the connected monitor. I only need these two values. My question is how can i read these values using C or C++?

此 reg_binary 值包含有关所连接显示器的信息(例如序列号和类型)。我只需要这两个值。我的问题是如何使用 C 或 C++ 读取这些值?

I have a VB script which can do this:
'you can tell If the location contains a serial number If it starts with &H00 00 00 ffstrSerFind=Chr(&H00) & Chr(&H00) & Chr(&H00) & Chr(&HfF)

我有一个可以执行此操作的 VB 脚本:
'您可以判断该位置是否包含序列号 如果它以&H00 00 00 ffstrSerFind=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? I can find only VB script examples, but unfortunately i don't understand them, and also it would be very important for me.

有人可以帮助我,我怎么能用 C 语言做到这一点?我只能找到 VB 脚本示例,但不幸的是我不理解它们,而且这对我来说非常重要。

采纳答案by Lucian

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

回答by HostileFork says dont trust SE

You mention wanting the "serial number" and "type". There is no "type" but there is a manufacturer ID and a product 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.

您提到想要“序列号”和“类型”。没有“类型”,但有制造商 ID 和产品 ID。在大多数情况下,这些不会作为有意义的字符串存储在您返回的信息中……它们只是数字值。它们都在前 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. Your data starts off with exactly what we expect:

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

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. Oh sure, they could have "wasted" three whole bytes in ASCII for this. 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. How'd they pull it off?

这些 ID 由 Microsoft 分配,是三个字母的代码。哦,当然,他们本可以为此“浪费”三个完整的 ASCII 字节。但这太明智了。因此,他们在标题的一个极其“非魔法”的数字上浪费了 8 个字节,并发明了一种“巧妙”的方法,将这三个字母编码为由两个字节组成的 16 位。他们是怎么弄下来的?

        +--------+--------+
        | 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 γ). Each is interpreted as a letter, where "00001=A"; "00010=B"; ... "11010=Z".

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

You've got:

你有:

10 AC

And hexadecimal 10ACexpressed as 16 binary bits is 0001000010101100. So let's bring that table back again:

十六进制10AC表示为 16 个二进制位是0001000010101100. 所以让我们再次把这张桌子拿回来:

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

So α = 00100(decimal 4), β = 00101(decimal 5), γ = 01100(decimal 12). Using those decimal numbers as indexes into the English alphabet we get D-E-L. By this arcane sorcery we have determined that your monitor is most likely made by Dell. :)

所以α = 00100(十进制4),β = 00101(十进制5),γ = 01100(十进制12)。使用这些十进制数作为英文字母表的索引,我们得到了 DEL。通过这个神秘的魔法,我们确定您的显示器很可能是戴尔制造的。:)

Bytes 10 and 11 - Product ID Code

字节 10 和 11 - 产品 ID 代码

This is a two-byte number, assigned by the manufacturer, stored as "LSB first". This is to say that the first byte is the least significant place value. You have:

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

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. It is "usually stored as LSB first", but doesn't have to be.

这是制造商分配的 32 位值,对格式没有要求。它“通常首先存储为 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.

您可以将其解释为0x53433442、 或0x42344353或其他任何内容……只要您在将一个值与另一个值进行比较时保持一致。



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. 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. 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:

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
}

(Note: I prefer to avoid using the sizeofon 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...)

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

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. 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.

除此之外,您关于如何从字节缓冲区中提取结构数据的问题是一个非常普遍的问题,并且是 C 风格编程的基础,如果您不知道从哪里开始,那么您可能应该解决更简单的程序。从制造商名称中提取三个五位段涉及诸如位移、位掩码或位字段之类的事情。遍历数组处理地址以及如何索引数组等等。

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...

有了上面的信息,您至少应该能够尝试阅读一些教程并了解哪些有用。如果您无法弄清楚问题的一部分,则将这一小部分分解为自己的问题,并展示您尝试过的内容以及为什么它不起作用......

回答by kichik

This previous question explains how to get EDID with C/C++/C#. It's not through the registry, but as long it works...

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

Win32 code to get EDID in Windows XP/7

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

If you want to still read the registry, use RegQueryValueExand friends.

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