📄 treeview.c
字号:
/*
* Regedit treeview
*
* Copyright (C) 2002 Robert Dickenson <robd@reactos.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <regedit.h>
/* Global variables and constants */
/* Image_Open, Image_Closed, and Image_Root - integer variables for indexes of the images. */
/* CX_ICON and CY_ICON - width and height of an icon. */
/* NUM_ICON - number of icons to add to the image list. */
int Image_Open;
int Image_Closed;
int Image_Root;
static LPTSTR pathBuffer;
#define CX_ICON 16
#define CY_ICON 16
#define NUM_ICONS 3
static BOOL get_item_path(HWND hwndTV, HTREEITEM hItem, HKEY* phKey, LPTSTR* pKeyPath, int* pPathLen, int* pMaxLen)
{
TVITEM item;
size_t maxLen, len;
LPTSTR newStr;
item.mask = TVIF_PARAM;
item.hItem = hItem;
if (!TreeView_GetItem(hwndTV, &item)) return FALSE;
if (item.lParam) {
/* found root key with valid key value */
*phKey = (HKEY)item.lParam;
return TRUE;
}
if(!get_item_path(hwndTV, TreeView_GetParent(hwndTV, hItem), phKey, pKeyPath, pPathLen, pMaxLen)) return FALSE;
if (*pPathLen) {
(*pKeyPath)[*pPathLen] = _T('\\');
++(*pPathLen);
}
do {
item.mask = TVIF_TEXT;
item.hItem = hItem;
item.pszText = *pKeyPath + *pPathLen;
maxLen = *pMaxLen - *pPathLen;
item.cchTextMax = (int) maxLen;
if (!TreeView_GetItem(hwndTV, &item)) return FALSE;
len = _tcslen(item.pszText);
if (len < maxLen - 1) {
*pPathLen += (int) len;
break;
}
newStr = HeapReAlloc(GetProcessHeap(), 0, *pKeyPath, *pMaxLen * 2);
if (!newStr) return FALSE;
*pKeyPath = newStr;
*pMaxLen *= 2;
} while(TRUE);
return TRUE;
}
LPCTSTR GetItemPath(HWND hwndTV, HTREEITEM hItem, HKEY* phRootKey)
{
int pathLen = 0, maxLen;
*phRootKey = NULL;
if (!pathBuffer) pathBuffer = HeapAlloc(GetProcessHeap(), 0, 1024);
if (!pathBuffer) return NULL;
*pathBuffer = 0;
maxLen = (int) HeapSize(GetProcessHeap(), 0, pathBuffer);
if (maxLen == -1) return NULL;
if (!hItem) hItem = TreeView_GetSelection(hwndTV);
if (!hItem) return NULL;
if (!get_item_path(hwndTV, hItem, phRootKey, &pathBuffer, &pathLen, &maxLen)) {
return NULL;
}
return pathBuffer;
}
BOOL DeleteNode(HWND hwndTV, HTREEITEM hItem)
{
if (!hItem) hItem = TreeView_GetSelection(hwndTV);
if (!hItem) return FALSE;
return TreeView_DeleteItem(hwndTV, hItem);
}
/* Add an entry to the tree. Only give hKey for root nodes (HKEY_ constants) */
static HTREEITEM AddEntryToTree(HWND hwndTV, HTREEITEM hParent, LPTSTR label, HKEY hKey, DWORD dwChildren)
{
TVITEM tvi;
TVINSERTSTRUCT tvins;
if (hKey) {
if (RegQueryInfoKey(hKey, 0, 0, 0, &dwChildren, 0, 0, 0, 0, 0, 0, 0) != ERROR_SUCCESS) {
dwChildren = 0;
}
}
tvi.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_CHILDREN | TVIF_PARAM;
tvi.pszText = label;
tvi.cchTextMax = lstrlen(tvi.pszText);
tvi.iImage = Image_Closed;
tvi.iSelectedImage = Image_Open;
tvi.cChildren = dwChildren;
tvi.lParam = (LPARAM)hKey;
tvins.item = tvi;
tvins.hInsertAfter = (HTREEITEM)(hKey ? TVI_LAST : TVI_FIRST);
tvins.hParent = hParent;
return TreeView_InsertItem(hwndTV, &tvins);
}
BOOL RefreshTreeItem(HWND hwndTV, HTREEITEM hItem)
{
HKEY hRoot, hKey, hSubKey;
HTREEITEM childItem;
LPCTSTR KeyPath;
DWORD dwCount, dwIndex, dwMaxSubKeyLen;
LPTSTR Name = NULL;
TVITEM tvItem;
LPTSTR pszNodes = NULL;
BOOL bSuccess = FALSE;
LPTSTR s;
BOOL bAddedAny;
KeyPath = GetItemPath(hwndTV, hItem, &hRoot);
if (*KeyPath) {
if (RegOpenKeyEx(hRoot, KeyPath, 0, KEY_READ, &hKey) != ERROR_SUCCESS) {
goto done;
}
} else {
hKey = hRoot;
}
if (RegQueryInfoKey(hKey, 0, 0, 0, &dwCount, &dwMaxSubKeyLen, 0, 0, 0, 0, 0, 0) != ERROR_SUCCESS) {
goto done;
}
/* Set the number of children again */
tvItem.mask = TVIF_CHILDREN;
tvItem.hItem = hItem;
tvItem.cChildren = dwCount;
if (!TreeView_SetItem(hwndTV, &tvItem)) {
goto done;
}
/* We don't have to bother with the rest if it's not expanded. */
if (TreeView_GetItemState(hwndTV, hItem, TVIS_EXPANDED) == 0) {
RegCloseKey(hKey);
bSuccess = TRUE;
goto done;
}
dwMaxSubKeyLen++; /* account for the \0 terminator */
if (!(Name = HeapAlloc(GetProcessHeap(), 0, dwMaxSubKeyLen * sizeof(TCHAR)))) {
goto done;
}
tvItem.cchTextMax = dwMaxSubKeyLen;
/*if (!(tvItem.pszText = HeapAlloc(GetProcessHeap(), 0, dwMaxSubKeyLen * sizeof(TCHAR)))) {
goto done;
}*/
/* Get all of the tree node siblings in one contiguous block of memory */
{
DWORD dwPhysicalSize = 0;
DWORD dwActualSize = 0;
DWORD dwNewPhysicalSize;
LPTSTR pszNewNodes;
DWORD dwStep = 10000;
for (childItem = TreeView_GetChild(hwndTV, hItem); childItem;
childItem = TreeView_GetNextSibling(hwndTV, childItem)) {
if (dwActualSize + dwMaxSubKeyLen + 1 > dwPhysicalSize)
{
dwNewPhysicalSize = dwActualSize + dwMaxSubKeyLen + 1 + dwStep;
if (pszNodes)
pszNewNodes = (LPTSTR) HeapReAlloc(GetProcessHeap(), 0, pszNodes, dwNewPhysicalSize * sizeof(TCHAR));
else
pszNewNodes = (LPTSTR) HeapAlloc(GetProcessHeap(), 0, dwNewPhysicalSize * sizeof(TCHAR));
if (!pszNewNodes)
goto done;
dwPhysicalSize = dwNewPhysicalSize;
pszNodes = pszNewNodes;
}
tvItem.mask = TVIF_TEXT;
tvItem.hItem = childItem;
tvItem.pszText = &pszNodes[dwActualSize];
tvItem.cchTextMax = dwPhysicalSize - dwActualSize;
if (!TreeView_GetItem(hwndTV, &tvItem))
goto done;
dwActualSize += (DWORD) _tcslen(&pszNodes[dwActualSize]) + 1;
}
if (pszNodes)
pszNodes[dwActualSize] = '\0';
}
/* Now go through all the children in the registry, and check if any have to be added. */
bAddedAny = FALSE;
for (dwIndex = 0; dwIndex < dwCount; dwIndex++) {
DWORD cName = dwMaxSubKeyLen, dwSubCount;
BOOL found;
found = FALSE;
if (RegEnumKeyEx(hKey, dwIndex, Name, &cName, 0, 0, 0, NULL) != ERROR_SUCCESS) {
continue;
}
/* Check if the node is already in there. */
if (pszNodes) {
for (s = pszNodes; *s; s += _tcslen(s) + 1) {
if (!_tcscmp(s, Name)) {
found = TRUE;
break;
}
}
}
if (found == FALSE) {
/* Find the number of children of the node. */
dwSubCount = 0;
if (RegOpenKeyEx(hKey, Name, 0, KEY_QUERY_VALUE, &hSubKey) == ERROR_SUCCESS) {
if (RegQueryInfoKey(hSubKey, 0, 0, 0, &dwSubCount, 0, 0, 0, 0, 0, 0, 0) != ERROR_SUCCESS) {
dwSubCount = 0;
}
RegCloseKey(hSubKey);
}
AddEntryToTree(hwndTV, hItem, Name, NULL, dwSubCount);
bAddedAny = TRUE;
}
}
RegCloseKey(hKey);
if (bAddedAny)
SendMessage(hwndTV, TVM_SORTCHILDREN, 0, (LPARAM) hItem);
/* Now go through all the children in the tree, and check if any have to be removed. */
childItem = TreeView_GetChild(hwndTV, hItem);
while (childItem) {
HTREEITEM nextItem = TreeView_GetNextSibling(hwndTV, childItem);
if (RefreshTreeItem(hwndTV, childItem) == FALSE) {
(void)TreeView_DeleteItem(hwndTV, childItem);
}
childItem = nextItem;
}
bSuccess = TRUE;
done:
if (pszNodes)
HeapFree(GetProcessHeap(), 0, pszNodes);
if (Name)
HeapFree(GetProcessHeap(), 0, Name);
return bSuccess;
}
BOOL RefreshTreeView(HWND hwndTV)
{
HTREEITEM hItem;
HTREEITEM hSelectedItem;
HCURSOR hcursorOld;
hSelectedItem = TreeView_GetSelection(hwndTV);
hcursorOld = SetCursor(LoadCursor(NULL, IDC_WAIT));
SendMessage(hwndTV, WM_SETREDRAW, FALSE, 0);
hItem = TreeView_GetChild(hwndTV, TreeView_GetRoot(hwndTV));
while (hItem) {
RefreshTreeItem(hwndTV, hItem);
hItem = TreeView_GetNextSibling(hwndTV, hItem);
}
SendMessage(hwndTV, WM_SETREDRAW, TRUE, 0);
SetCursor(hcursorOld);
/* We reselect the currently selected node, this will prompt a refresh of the listview. */
(void)TreeView_SelectItem(hwndTV, hSelectedItem);
return TRUE;
}
HTREEITEM InsertNode(HWND hwndTV, HTREEITEM hItem, LPTSTR name)
{
TCHAR buf[MAX_NEW_KEY_LEN];
HTREEITEM hNewItem = 0;
TVITEMEX item;
/* Default to the current selection */
if (!hItem)
{
hItem = TreeView_GetSelection(hwndTV);
if (!hItem)
return FALSE;
}
memset(&item, 0, sizeof(item));
item.hItem = hItem;
item.mask = TVIF_CHILDREN | TVIF_HANDLE | TVIF_STATE;
if (!TreeView_GetItem(hwndTV, &item))
return FALSE;
if ((item.state & TVIS_EXPANDEDONCE) && (item.cChildren > 0))
{
hNewItem = AddEntryToTree(hwndTV, hItem, name, 0, 0);
SendMessage(hwndTV, TVM_SORTCHILDREN, 0, (LPARAM) hItem);
}
else
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -