Windows注册表操作

注册表是Windows操作系统中一个重要的数据库,其中保存着操作系统和各种软件的重要信息。注册表是如此的重要,所以也是病毒和反病毒软件的兵家必争之地。

注册表是Windows系统管理和维护的配置较为复杂的信息数据库,它以树状形式存储信息。可以通过“开始”->“运行”,在运行窗口中输入“regedit”,来打开Windows提供的“注册表编辑器”窗口。如下图所示:


注册表由若干部分组成,分别是根键、子键、键值项。

根键:类似于磁盘驱动器的名称,在树状结构中类似于树的根节点。如上图中1标识框出的部分,根键的父节点是“计算机”。

子键:类似于文件夹,一个根键下可以包含多个子键,子键下也可以包含多个子键。如上图标识2、3所框出的部分。

键值项:不包括子键的子键就是键值项。如上图标识4所框出的部分。

无论是根键、子键还是键值项,都是注册表中的结构,具体的数据就存储在各个结构的相应位置。注册表的数据由3部分组成:名称、类型和值。如上图右边框出的部分。

好了,基本的注册表知识介绍完了,下面介绍操作注册表的常用API。

打开注册表

LONG RegOpenKeyEx(
  HKEY hKey,//指定一个父键句柄
  LPCTSTR lpSubKey,//指向一个字符串,用来表示要打开的子键名称
  DWORD ulOptions,//系统保留,必须指定为0
  REGSAM samDesired,//打开注册表的存取权限,为了方便对注册表的操作,通常使用KEY_ALL_ACCESS
  PHKEY phkResult//指向一个双字变量,用来接收打开的子键句柄
);

如果函数执行成功,则返回ERROR_SUCCESS,并且在phResult中保存打开后返回的子键句柄。所谓打开注册表,实质就是打开注册表的某个子键,然后进行操作。

关闭注册表

LONG RegCloseKey(
  HKEY hKey//要关闭的注册表句柄
);

创建一个子键

LONG RegCreateKeyEx(
  HKEY hKey,//指定父键句柄
  LPCTSTR lpSubKey,//指向一个字符串,用来表示要创建的子键名称
  DWORD Reserved,//系统保留,必须指定为0
  LPTSTR lpClass,//子键类型名,一般设置为NULL
  DWORD dwOptions,//创建子键时的选项,通常使用REG_OPTION_NON_VOLATILE宏,表示子键被创建到注册表中而不是内存中
  REGSAM samDesired,//打开注册表的存取权限,为了方便对注册表的操作,通常使用KEY_ALL_ACCESS
  LPSECURITY_ATTRIBUTES lpSecurityAttributes,//指向一个SECURITY_ATTRIBUTES结构体,用来指定注册表句柄的安全属性,一般设置为NULL
  PHKEY phkResult,//指向一个双字变量,用来保存打开的子键句柄
  LPDWORD lpdwDisposition//一般设置为NULL
);

如果函数执行成功,则返回ERROR_SUCCESS,并在phkResult中保存返回创建子键的句柄。当需要创建的子键已经存在的时候,该函数起到与RegOpenKeyEx函数同样的效果。

删除子键

LONG RegDeleteKey(
  HKEY hKey,//父键句柄
  LPCTSTR lpSubKey//要删除的子键名称字符串
);

需要注意的是,该函数只能删除键值项,即删除最下层的子键。

读取键名称的数据或查询键名称的属性

LONG RegQueryValueEx(
  HKEY hKey,//用来指定要读取的键值项所处的子键句柄
  LPCTSTR lpValueName,//用来指定要读取的键值项的名称
  LPDWORD lpReserved,//保留参数,必须为NULL
  LPDWORD lpType,//接收返回的键值类型,如果不需要返回键值项类型,可以给NULL值
  LPBYTE lpData,//指向一个缓冲区,用来接收返回的键值数据
  LPDWORD lpcbData//调用函数时,该参数指定缓冲区的长度;函数返回时,该参数保存缓冲区实际接收到的长度。
);

写入键值项的函数

LONG RegSetValueEx(
  HKEY hKey,//用来指定要写入的键值项所处的子键句柄
  LPCTSTR lpValueName,//指定定义键值项名称的字符串
  DWORD Reserved,//保留参数,必须为0
  DWORD dwType,//指出要写入的键值数据的类型
  const BYTE* lpData,//指向要写入键值数据的缓冲区
  DWORD cbData//要写入键值数据的缓冲区长度
);

删除键值项函数

LONG RegDeleteValue(
  HKEY hKey,//用来指定要删除的句柄
  LPCTSTR lpValueName//要删除键值项的名称
);

枚举子键的函数

LONG RegEnumKeyEx(
  HKEY hKey,//指定被枚举的键句柄
  DWORD dwIndex,//指定需要返回信息的子键索引编号
  LPTSTR lpName,//用户接收返回子键名称的缓冲区
  LPDWORD lpcName,//调用函数前,该参数保留lpName指向缓冲区的长度;函数调用后,该参数保存缓冲区实际接收到的数据的长度
  LPDWORD lpReserved,//保留参数,必须为NULL   
  LPTSTR lpClass,//一般为NULL
  LPDWORD lpcClass,//一般为NULL
  PFILETIME lpftLastWriteTime//指向一个FILETIME结构体,用于接收最后一次被写入的时间。
);

枚举键值的函数

LONG RegEnumValue(
  HKEY hKey,//指定被枚举的键句柄
  DWORD dwIndex,//指定需要返回信息的键值索引号
  LPTSTR lpValueName,//用户接收返回键值名称的缓冲区
  LPDWORD lpcValueName,// 调用函数前,该参数保留lpName指向缓冲区的长度;函数调用后,该参数保存缓冲区实际接收到的数据的长度
  LPDWORD lpReserved, //保留参数,必须为NULL
  LPDWORD lpType,//指向一个用于返回键值数据类型的双字变量
  LPBYTE lpData,//用户接收返回值数据的缓冲区
  LPDWORD lpcbData//在调用函数前,保存lpData指向缓冲区的长度;函数调用后,该参数保存缓冲区实际接收到的数据长度
);

至此,注册表操作的常用API就介绍完了,接下来当然要开始实践一番了。

我们知道系统中有些程序是开机启动的,下面我们就注册表中一个开机启动处来进行下面的程序开发。其中一处开机启动的注册表位置是:"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run\"。

首先布局我们的主界面如下:

点击“添加启动”按钮出现的附属界面如下:

Windows注册表操作_第1张图片

在附属界面的对应类中关联两个成员变量,分别用于保存两个文本框中输入的值。点击“确定”按钮把值更新到对应的成员变量中,可以用UpdateData函数来实现。

在主界面cpp中定义一个宏,来标识我们要操作的注册表位置:

#define REG_RUN"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run\\"

初始化CListCtrl控件:
//设置扩展样式
	m_RunList.SetExtendedStyle(
		m_RunList.GetExtendedStyle()
		| LVS_EX_GRIDLINES
		| LVS_EX_FULLROWSELECT);

	//在ListCtrl中插入新列
	m_RunList.InsertColumn(0, TEXT("NO."));
	m_RunList.InsertColumn(1, TEXT("键值名称"));
	m_RunList.InsertColumn(2, TEXT("键    值"));

	//LVSCW_AUTOSIZE_USEHEADER:
	/*列的宽度自动匹配为标题文本
	如果这个值用着最后一列,列宽被设置为ListCtrl剩余的宽度*/
	m_RunList.SetColumnWidth(0, LVSCW_AUTOSIZE_USEHEADER);
	m_RunList.SetColumnWidth(1, LVSCW_AUTOSIZE_USEHEADER);
	m_RunList.SetColumnWidth(2, LVSCW_AUTOSIZE_USEHEADER);

枚举对应位置的启动项:

//清空ListCtrl中的所有项
	m_RunList.DeleteAllItems();

	DWORD dwType = 0;
	DWORD dwBufferSize = MAXBYTE;
	DWORD dwKeySize = MAXBYTE;
	char szValueName[MAXBYTE] = { 0 };
	char szValueKey[MAXBYTE] = { 0 };

	HKEY hKey = NULL;
	//打开注册表
	LONG lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
		TEXT(REG_RUN), 0, KEY_ALL_ACCESS, &hKey);

	if (lRet != ERROR_SUCCESS)
		return;

	int i = 0;
	CString strTmp;

	while (TRUE)
	{
		//枚举键项
		lRet = RegEnumValue(hKey, i, (LPWSTR)szValueName,
			&dwBufferSize, NULL, &dwType,
			(unsigned char *)szValueKey, &dwKeySize);

		//没有则退出循环
		if (lRet == ERROR_NO_MORE_ITEMS)
			break;

		//把得到的键项显示到列表控件中
		strTmp.Format(_T("%d"), i + 1);
		m_RunList.InsertItem(i, strTmp);
		m_RunList.SetItemText(i, 1, (LPCTSTR)szValueName);
		m_RunList.SetItemText(i, 2, (LPCTSTR)szValueKey);

		ZeroMemory(szValueKey, MAXBYTE);
		ZeroMemory(szValueName, MAXBYTE);

		dwBufferSize = MAXBYTE;
		dwKeySize = MAXBYTE;

		++i;
	}

	RegCloseKey(hKey);

添加启动项代码:

CRegAdd RegAdd;//CRegAdd是我定义的附属Dialog类
	RegAdd.DoModal();

	//AfxMessageBox(RegAdd.m_szKeyName);
	//AfxMessageBox(RegAdd.m_szKeyValue);
	//判断输入是否完整
	if (strlen((const char *)RegAdd.m_szKeyName.GetBuffer(0)) > 0 &&
		strlen((const char *)RegAdd.m_szKeyValue.GetBuffer(0)) > 0)
	{
		HKEY hKey = NULL;
		LONG lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
			TEXT(REG_RUN), 0, KEY_ALL_ACCESS, &hKey);

		if (lRet != ERROR_SUCCESS)
		{
			AfxMessageBox(_T("添加注册表项发生错误!"));
			return;
		}
		RegSetValueEx(hKey, RegAdd.m_szKeyName, 0,
			REG_SZ, (const BYTE *)(LPCTSTR)RegAdd.m_szKeyValue,
			RegAdd.m_szKeyValue.GetLength() * 2); 
		RegCloseKey(hKey);

		ShowRunList();
	}
	else
	{
		AfxMessageBox(_T("请输入完整内容!"));
	}

删除启动项代码:

POSITION pos = m_RunList.GetFirstSelectedItemPosition();
	int nSelected = -1;
	while (pos)
	{
		nSelected = m_RunList.GetNextSelectedItem(pos);//获得选中的最后一项
	}
	if (-1 == nSelected)
	{
		AfxMessageBox(_T("请选择要删除的启动项"));
		return;
	}
	char szKeyName[MAXBYTE] = { 0 };
	m_RunList.GetItemText(nSelected, 1, (LPTSTR)szKeyName, MAXBYTE);
	HKEY hKey = NULL;
	LONG lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
		TEXT(REG_RUN), 0, KEY_ALL_ACCESS, &hKey);
	RegDeleteValue(hKey, (LPCWSTR)szKeyName);
	RegCloseKey(hKey);
	ShowRunList();//定义的枚举启动项函数

主要的函数操作就是上面这些了,运行项目就可以尝试给自己的系统添加和删除启动项了(*^-^*)



你可能感兴趣的:(Windows注册表操作)