相关注册表数据
想要通过查询注册表,收集一些系统信息。
1.系统版本信息: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion
ProductName:Windows 10 Enterprise 2015 LTSB
RegisteredOwner:Snowty
SystemRoot:C:\WINDOWS
2.是否为虚拟机: HKEY_LOCAL_MACHINE/HARDWARE/DESCRIPTION/System/BIOS/
SystemProductName:VMware Virtual Platform
3.电脑位数: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment\
PROCESSOR_ARCHITECTURE:
x86 →32位操作系统
AMD64 →64位操作系统
IA64 →64位操作系统(for Itanium-based)
4.office版本: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office\
office2003:11.0
office2007:12.0
office2010:14.0
office2013:15.0
office2016:16.0
office2017:17.0
5.国家/时区: HKEY_CURRENT_USER\Control Panel\International\
sCountry:中华人民共和国
LocalName:zh-CN
sLanguage:CHS
MFC查询注册表信息
代码主要参考《精通MFC程序设计》,人民邮电,姚领田,第24章,注册表编程。
整体来说代码很简单,通俗易懂。但是其间出现了宽字节\0
截断的问题,真心是折腾了好久🙄
使用RegGetValue
进行查询,详细用法可以查看MSDN
LONG WINAPI RegGetValue(
_In_ HKEY hkey,
_In_opt_ LPCTSTR lpSubKey,
_In_opt_ LPCTSTR lpValue,
_In_opt_ DWORD dwFlags,
_Out_opt_ LPDWORD pdwType,
_Out_opt_ PVOID pvData,
_Inout_opt_ LPDWORD pcbData
);
以查询ProductName为例,全部工程代码见Git。
void CRegDataDlg::OnClickedQuery()
{
// TODO: Add your control notification handler code here
//--------------------------------查询系统版本信息--------------------------
//查询ProductName
DWORD cdData=80; //预设置的数据长度
LPDWORD lp=&cdData;
LPBYTE ProductName_Get = new BYTE[80]; //保存查询的数据
long ret = RegGetValue(HKEY_LOCAL_MACHINE, _T("Software\\Microsoft\\Windows NT\\CurrentVersion"),_T("ProductName"), RRF_RT_REG_SZ, NULL, ProductName_Get, lp);//注册表查询,将结果保存在ProductName_Get中
//将unicode转换为ASCII
char ProductName_Get_Buf[100];
DWORD dBufSize = 80;
WideCharToMultiByte(CP_UTF8, 0, (LPCWCH)ProductName_Get, -1, ProductName_Get_Buf, dBufSize, NULL, FALSE);//转换后的结果保存在ProductName_Get_Buf中
m_ProductName = CString(ProductName_Get_Buf);//显示在界面上
UpdateData(false); //将值赋给控件
delete[] ProductName_Get;
}
如果使用RegQueryValueEx
进行查询,则需要先使用RegOpenKeyEx
打开注册表:
void CRegDataDlg::OnClickedQuery()
{
HKEY hKEY; //handler
LPCTSTR banner_Set = _T("Software\\Microsoft\\Windows NT\\CurrentVersion"); //子健目录
long retopen = (::RegOpenKeyEx(HKEY_LOCAL_MACHINE,banner_Set,0,KEY_READ,&hKEY)); //打开系统版本注册表
if(retopen!=ERROR_SUCCESS)
{
MessageBox(_T("ERROR:Can not open the hKEY!"));
return;
}
//查询RegisteredOwner
LPBYTE RegisteredOwner_Get = new BYTE[80];
DWORD type_2 = REG_SZ;
DWORD cdData_2 = 80;
long ret2 = ::RegQueryValueEx(hKEY,_T("RegisteredOwner"),NULL,&type_2,RegisteredOwner_Get,&cdData_2);
if(ret2!=ERROR_SUCCESS)
{
MessageBox(_T("Can not query the Reg"));
return;
}
char dBuf2[100];
DWORD dBufSize2 = 80;
WideCharToMultiByte(CP_UTF8, 0, (LPCWCH)RegisteredOwner_Get, -1, dBuf2, dBufSize2, NULL, FALSE);
m_RegisteredOwner = CString(dBuf2);
delete[] RegisteredOwner_Get;
::RegCloseKey(hKEY);
}
宽字节转换
`WideCharToMultiByte`:此函数是将宽字节转换为ascii,刚好在《加密与解密》这本书的第一章看到过,与此对应的是`MultiByteToWideChar`
`ASCII`:7位,1 byte。
`Unicode`:16位,2 byte,所以称为宽字节,将7位的ASCII扩充为16位(0来填充)。
书上的源码没有使用这个函数进行转换,所以导致我的输出只有字符串的第一个字符,例如本来应该输出Windows 10 Enterprise 2015 LTSB
,但只输出了W
。
后来经彬彬大神的点拨,让我对ProductName_Get
的字符串进行逐个输出,然后看到了\0
的bug。
for(int i = 0; i < 20; ++i)
putchar(ProductName_Get[i]);
可以看到,ProductName_Get[0]=’W’,ProductName_Get[1]=’\0’,直接把字符串截断了