用VC6编写注册表管理程序(二)
顾剑辉(Solarsoft)
1. 用树来显示注册表信息。
注意:注册表信息内容比较多,不可能全部显示,则可一开始,先显示最接近于树根,再根据操作来逐步显示子树的方案来实现,
1) 初始化树
void CRegLeftView::OnInitialUpdate()
{
CTreeView::OnInitialUpdate();
/*定义TreeCtrl的图标*/
m_pImageList = new CImageList();
CWinApp* pApp = AfxGetApp();
ASSERT(m_pImageList != NULL);
m_pImageList->Create(16, 16, ILC_COLOR8 | ILC_MASK, 9, 9);
m_pImageList->Add(pApp->LoadIcon(ICO_MYCOMPUTER));
m_pImageList->Add(pApp->LoadIcon(ICO_OPENFLD));
m_pImageList->Add(pApp->LoadIcon(ICO_CLSDFLD));
GetTreeCtrl().SetImageList(m_pImageList , TVSIL_NORMAL);
HTREEITEM hParent = GetTreeCtrl().InsertItem(MYCOMPUTER, ILI_MYCOMP, ILI_MYCOMP);
//显示树根,MYCOMPUTER宏定义为“我的电脑”
InitTreeView(hParent);
//初始化主键
GetTreeCtrl().Expand(hParent, TVE_EXPAND);
}
void CRegLeftView::InitTreeView(HTREEITEM hParent)
{
HTREEITEM hItem;
for(int i=0;i<6;i++)
{
hItem = GetTreeCtrl().InsertItem(HKey_Root[i], ILI_CLSDFLD, ILI_OPENFLD, hParent);
AddDummyNode(hItem);//加入空子树
}
}
2) 发送树型视图消息TVN_ITEMEXPANDING和TVN_SELCHANGING的编写,前者为列表项被扩展(或收缩),后者为当前的选择项发生变化。
函数体如下:
void CRegLeftView::OnItemexpanding(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
HKEY hKey;
HTREEITEM hItem = pNMTreeView->itemNew.hItem;
if(!IsSubTree(hItem))
{
CString strDataName = GetDataFromItem (hItem);
//返回除去“我的电脑”的项目名,实为键路径
hKey=GetHkey(strDataName);
//返回当前项目名的主键
CString strSubKey;
int i=strDataName.Find("\\");
if(i==-1)
{
strSubKey="";
}else
strSubKey=strDataName.Mid(i+1);
CWaitCursor wait;
if (pNMTreeView->action == TVE_EXPAND)
{
if(strDataName != MYCOMPUTER)
{
DeleteChildren (hItem);
//删除当前项目的所有子树
if (!EnumerateKey(hKey,strSubKey,hItem))
//枚举当前项目的所有子树
*pResult = TRUE;
}
}
}
*pResult = 0;
}
void CRegLeftView::OnSelchanging(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
if(i!=0)
{
HKEY hKey;
HTREEITEM hItem = pNMTreeView->itemNew.hItem;
CString strDataName = GetDataFromItem (hItem);
hKey=GetHkey(strDataName);
CString strSubKey;
int i=strDataName.Find("\\");
if(i==-1)
{
strSubKey="";
}else
strSubKey=strDataName.Mid(i+1);
CWaitCursor wait;
CRegExplorerDoc* pDoc = GetDocument();
pDoc->m_RegExplorerView->DeleteAllItems();
//与文档类通信的代码,并可以操作RegExplorerView
if(strDataName == MYCOMPUTER)
return;
pDoc->m_RegExplorerView->DoListView(hKey,strSubKey);
}
i++;
*pResult = 0;
}
其他函数的实现:
CString CRegLeftView::GetDataFromItem(HTREEITEM hItem)
{
CString str;
while (hItem != NULL)
{
CString string = GetTreeCtrl().GetItemText (hItem);
if ((string.Right (1) != "\\") && !str.IsEmpty ())
string += "\\";
str = string + str;
hItem = GetTreeCtrl().GetParentItem (hItem);
}
//8为我的电脑的长度,为的是去除我的电脑4个字
if(str.Left(8) == MYCOMPUTER && str.GetLength() > 8)
str = str.Mid(9);
return str;
}
HKEY CRegLeftView::GetHkey(LPCTSTR strKey)
{
HKEY hKeyRootName;
CString cstrKeyRootName=strKey;
int i=cstrKeyRootName.Find("\\");
if(i!=-1)
cstrKeyRootName=cstrKeyRootName.Left(i);
if(cstrKeyRootName == _T("HKEY_CLASSES_ROOT"))
hKeyRootName = HKEY_CLASSES_ROOT;
else if(cstrKeyRootName == _T("HKEY_CURRENT_USER"))
hKeyRootName = HKEY_CURRENT_USER;
else if(cstrKeyRootName == _T("HKEY_LOCAL_MACHINE"))
hKeyRootName = HKEY_LOCAL_MACHINE;
else if(cstrKeyRootName == _T("HKEY_USERS"))
hKeyRootName = HKEY_USERS;
else if(cstrKeyRootName == _T("HKEY_PERFORMANCE_DATA"))
hKeyRootName = HKEY_PERFORMANCE_DATA;
else if(cstrKeyRootName == _T("HKEY_CURRENT_CONFIG"))
hKeyRootName = HKEY_CURRENT_CONFIG;
else if(cstrKeyRootName == _T("HKEY_DYN_DATA"))
hKeyRootName = HKEY_DYN_DATA;
return hKeyRootName;
}
/*一层树算法:对注册表树的当前一层进行枚举*/
UINT CRegLeftView::EnumerateKey(HKEY hKey, LPCTSTR strKey, HTREEITEM hItem)
{
HTREEITEM hSubItem;
TCHAR strCurString[100];
long lResult;
DWORD dwCurIndex=0;
HKEY hCurKey;
CString strCurKey;
CString strSubKey=strKey;
CString str=strKey;
if(strKey=="")
{
AddDummyNode(hItem);
return 0;
}
CWaitCursor wait;
//CRegExplorerDoc* pDoc = GetDocument();
//pDoc->m_ExplorerView->DeleteAllItems();
//第二部分工作,加入对ListView的支持
lResult = RegOpenKeyEx(hKey, strKey, 0, KEY_ENUMERATE_SUB_KEYS, &hCurKey);
if( lResult != ERROR_SUCCESS )
return 0;
do
{
lResult = RegEnumKey(hCurKey, dwCurIndex, strCurString , sizeof(strCurString));
if((lResult == ERROR_NO_MORE_ITEMS) || (lResult == ERROR_INVALID_HANDLE))
{
break;
}
else
{
strCurKey.Format("%s",strCurString);
hSubItem=GetTreeCtrl().InsertItem (strCurKey, 2, 1, hItem,TVI_SORT);
if(!strCurKey.IsEmpty()&&!str.IsEmpty())
{
strSubKey = str + "\\" + strCurString;
}
else
{
strSubKey = strCurString;
}
if(HasSubKey(hKey , strSubKey))
{
AddDummyNode(hSubItem);
}
dwCurIndex++;
}
}while(TRUE);
RegCloseKey(hCurKey);
return dwCurIndex;
}
void CRegLeftView::AddDummyNode(HTREEITEM hItem)
{
GetTreeCtrl().InsertItem ("", 2, 1, hItem);
}
UINT CRegLeftView::DeleteChildren(HTREEITEM hItem)
{
UINT nCount = 0;
HTREEITEM hChild = GetTreeCtrl().GetChildItem (hItem);
while (hChild != NULL) {
HTREEITEM hNextItem = GetTreeCtrl().GetNextSiblingItem (hChild);
GetTreeCtrl().DeleteItem (hChild);
hChild = hNextItem;
nCount++;
}
return nCount;
}
右边列表CregExplorerView类的实现:
在类里定义private型的变量 HKEY m_hKey;//通信函数传来主键
CString m_strSubKey;//子键名
1. 和文档类进行通信的代码同上。
2. 显示当前树的数据
在CRegLeftView::OnSelchanging中有一通信函数pDoc->m_RegExplorerView->
DoListView(hKey,strSubKey);
void CRegExplorerView::DoListView(HKEY hKey, LPCTSTR strSubKey)
{
LV_ITEM lvitem;
int iActualItem;
CString strTemp1="(默认)",strTemp2="(未设置类型)",strTemp3="(未设置键值)";
m_hKey=hKey;
m_strSubKey=strSubKey;
lvitem.mask = LVIF_TEXT | LVIF_IMAGE;
lvitem.iItem = 0;
lvitem.iSubItem = 0;
lvitem.pszText = strTemp1.GetBuffer(strTemp1.GetLength());
lvitem.iImage =ICI_STR;
iActualItem = GetListCtrl().InsertItem(&lvitem);
GetListCtrl().SetItemText(iActualItem,1,strTemp2.GetBuffer(0));
GetListCtrl().SetItemText(iActualItem,2,strTemp3.GetBuffer(0));
EnumerateValues(hKey,strSubKey);//枚举该子键的所有数据项并显示在ListView上
}
void CRegExplorerView::EnumerateValues(HKEY hKey, LPCTSTR cstrKey)
{
static HKEY hLastKey = hKey;
LONG lResult;
DWORD dwIndex = 0;
HKEY hCurKey = hKey;
DWORD dwKeyType;
DWORD dwKeyDataLength, dwKeyNameLen;
LPBYTE pbbinKeyData = NULL;
TCHAR *tcKeyName = NULL;
TCHAR tcDataType[1024] = _T("");
lResult = RegOpenKeyEx(hCurKey, cstrKey, 0, KEY_QUERY_VALUE , &hKey);
if(lResult != ERROR_SUCCESS)
return;
DWORD lNoOfValues = 0;
DWORD lLongestKeyNameLen = 1;
DWORD lLongestDataLen = 1;
lResult = RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL, &lNoOfValues, &lLongestKeyNameLen, &lLongestDataLen,
NULL, NULL);
if(lResult != ERROR_SUCCESS)
return;
hLastKey = hKey;
lLongestKeyNameLen++;
lLongestDataLen++;
tcKeyName = new TCHAR[lLongestKeyNameLen];
pbbinKeyData = new BYTE[lLongestDataLen];
CString cstrFinalData, cstrTemp;
while(TRUE)
{
memset(pbbinKeyData, 0, lLongestDataLen);
memset(tcKeyName, 0, lLongestKeyNameLen);
dwKeyType = dwKeyDataLength = dwKeyNameLen = 0;
dwKeyNameLen = lLongestKeyNameLen;
dwKeyDataLength = lLongestDataLen;
lResult = RegEnumValue(hKey, dwIndex, tcKeyName, &dwKeyNameLen, NULL, &dwKeyType, pbbinKeyData, &dwKeyDataLength);
if(lResult == ERROR_NO_MORE_ITEMS)
break;
AddRegistryItem(tcKeyName, dwKeyType, pbbinKeyData, dwKeyDataLength, dwIndex);//显示数据于ListView
dwIndex++;
}
RegCloseKey(hKey);
delete tcKeyName;
delete pbbinKeyData;
}
int CRegExplorerView::AddRegistryItem(CString Name, DWORD Type, void *Data, DWORD DataSize, int Row)
{
if (Name.IsEmpty())
{
DeleteAllItems();
Name="(默认)";
}
LVITEM Item={0};
Item.mask=LVIF_TEXT | LVIF_IMAGE;
Item.cchTextMax=Name.GetLength();
Item.iItem=Row;
Item.pszText=Name.GetBuffer(0);
int iPosition;
CString FormatData;
switch (Type)
{
case REG_DWORD_BIG_ENDIAN:
case REG_DWORD:
{
Item.iImage=1;
iPosition=GetListCtrl().InsertItem(&Item);
GetListCtrl().SetItemText(iPosition,1,"REG_DWORD");
DWORD* dwData=(DWORD*) Data;
if (Data!=NULL)
{
FormatData.Format("0x%x (%d)",*dwData,*dwData);
GetListCtrl().SetItemText(iPosition,2,FormatData.GetBuffer(0));
}
break;
}
case REG_BINARY:
{
Item.iImage=1;
iPosition=GetListCtrl().InsertItem(&Item);
GetListCtrl().SetItemText(iPosition,1,"REG_BINARY");
if (Data!=NULL)
{
FormatData=FormatBinary((BYTE*) Data,DataSize);
GetListCtrl().SetItemText(iPosition,2,FormatData.GetBuffer(0));
}
break;
}
case REG_EXPAND_SZ:
case REG_SZ:
case REG_LINK:
case REG_MULTI_SZ:
{
Item.iImage=0;
iPosition=GetListCtrl().InsertItem(&Item);
GetListCtrl().SetItemText(iPosition,1,"REG_SZ");
if (Data!=NULL)
{
FormatData.Format("\"%s\"",(char*) Data);
GetListCtrl().SetItemText(iPosition,2,FormatData.GetBuffer(0));
}
break;
}
default:
{
Item.mask=LVIF_TEXT;
iPosition=GetListCtrl().InsertItem(&Item);
GetListCtrl().SetItemText(iPosition,1,"REG_NONE");
break;
}
}
return iPosition;
}
到此数据的显示已经基本完成,余下为数据操作的代码