|
|
/*******************************************************************************
* * (C) COPYRIGHT MICROSOFT CORP., 1993-1994 * * TITLE: REGKEY.C * * VERSION: 4.01 * * AUTHOR: Tracy Sharpe * * DATE: 05 Mar 1994 * * KeyTreeWnd TreeView routines for the Registry Editor. * *******************************************************************************/
#include "pch.h"
#include "regedit.h"
#include "regkey.h"
#include "regvalue.h"
#include "regresid.h"
#define MAX_KEYNAME_TEMPLATE_ID 100
#define SELCHANGE_TIMER_ID 1
#define REFRESH_DPA_GROW 16
VOID PASCAL RegEdit_OnKeyTreeDelete( HWND hWnd, HTREEITEM hTreeItem );
VOID PASCAL RegEdit_OnKeyTreeRename( HWND hWnd, HTREEITEM hTreeItem );
int WINAPI DPACompareKeyNames( LPVOID lpString1, LPVOID lpString2, LPARAM lParam );
HTREEITEM PASCAL KeyTree_InsertItem( HWND hKeyTreeWnd, HTREEITEM hParent, HTREEITEM hInsertAfter, LPCTSTR lpText, UINT fHasKids, LPARAM lParam );
BOOL PASCAL DoesKeyHaveKids( HKEY hKey, LPTSTR lpKeyName );
VOID PASCAL KeyTree_EditLabel( HWND hKeyTreeWnd, HTREEITEM hTreeItem );
BOOL PASCAL KeyTree_CanDeleteOrRenameItem( HWND hWnd, HTREEITEM hTreeItem );
/*******************************************************************************
* * RegEdit_OnNewKey * * DESCRIPTION: * * PARAMETERS: * hWnd, handle of RegEdit window. * *******************************************************************************/
VOID PASCAL RegEdit_OnNewKey( HWND hWnd, HTREEITEM hTreeItem ) { TCHAR KeyName[MAXKEYNAME*2]; UINT cchKeyName = 0; HKEY hRootKey; HKEY hKey; UINT ErrorStringID; BOOL fNewKeyIsOnlyChild; UINT NewKeyNameID; HKEY hNewKey; HTREEITEM hNewTreeItem; TV_ITEM TVItem; hRootKey = KeyTree_BuildKeyPath(g_RegEditData.hKeyTreeWnd, hTreeItem, KeyName, BKP_TOSUBKEY); cchKeyName = lstrlen(KeyName);
if(RegOpenKeyEx(hRootKey,KeyName,0,KEY_CREATE_SUB_KEY,&hKey) != ERROR_SUCCESS) { //
// Get the text of the selected tree item so that we can display
// a more meaningful error message.
//
TVItem.mask = TVIF_TEXT; TVItem.hItem = hTreeItem; TVItem.pszText = (LPTSTR) KeyName; TVItem.cchTextMax = sizeof(KeyName)/sizeof(TCHAR); TreeView_GetItem(g_RegEditData.hKeyTreeWnd, &TVItem); ErrorStringID = IDS_NEWKEYPARENTOPENFAILED; goto error_ShowDialog; } TVItem.mask = TVIF_STATE | TVIF_CHILDREN; TVItem.hItem = hTreeItem; TreeView_GetItem(g_RegEditData.hKeyTreeWnd, &TVItem); fNewKeyIsOnlyChild = FALSE; if (TVItem.cChildren == FALSE) { //
// The selected key doesn't have any subkeys, so we can't do an expand
// on it just yet. We'll just set a flag and later tag it with a
// plus/minus icon and expand it.
//
fNewKeyIsOnlyChild = TRUE; } else if (!(TVItem.state & TVIS_EXPANDED)) { //
// The selected key isn't expanded. Do it now so that we can do an
// in-place edit and don't reenumerate the "New Key #xxx" after we do
// the RegCreateKey.
//
TreeView_Expand(g_RegEditData.hKeyTreeWnd, hTreeItem, TVE_EXPAND); } if (RegEdit_GetTemporaryKeyName(hWnd, KeyName, hKey)) { if((cchKeyName + lstrlen(KeyName) + 1) < MAXKEYNAME) { if (RegCreateKey(hKey, KeyName, &hNewKey) != ERROR_SUCCESS) { ErrorStringID = IDS_NEWKEYCANNOTCREATE; goto error_CloseKey; } RegCloseKey(hNewKey); if (fNewKeyIsOnlyChild) { TVItem.mask = TVIF_CHILDREN; TVItem.cChildren = TRUE; TreeView_SetItem(g_RegEditData.hKeyTreeWnd, &TVItem); TreeView_Expand(g_RegEditData.hKeyTreeWnd, hTreeItem, TVE_EXPAND); // WARNING: It is possible for our new item _not_ to be the only child
// if our view is out of date!
hNewTreeItem = TreeView_GetChild(g_RegEditData.hKeyTreeWnd, hTreeItem); } else { hNewTreeItem = KeyTree_InsertItem(g_RegEditData.hKeyTreeWnd, hTreeItem, TVI_LAST, KeyName, FALSE, 0); } TreeView_SelectItem(g_RegEditData.hKeyTreeWnd, hNewTreeItem); KeyTree_EditLabel(g_RegEditData.hKeyTreeWnd, hNewTreeItem); } else { ErrorStringID = IDS_RENAMEKEYTOOLONG; goto error_CloseKey; } } else { ErrorStringID = IDS_NEWKEYNOUNIQUE; goto error_CloseKey; }
RegCloseKey(hKey); return; error_CloseKey: RegCloseKey(hKey); // FEATURE: For any errors that may crop up, we may need to turn off the
// child flag.
error_ShowDialog: InternalMessageBox(g_hInstance, hWnd, MAKEINTRESOURCE(ErrorStringID), MAKEINTRESOURCE(IDS_NEWKEYERRORTITLE), MB_ICONERROR | MB_OK, (LPTSTR) KeyName); }
//------------------------------------------------------------------------------
// RegEdit_GetTemporaryKeyName
//
// DESCRIPTION: Loop through the registry trying to find a valid temporary name
// until the user renames the key.
//
// PARAMETERS: HWND hWnd - handle to window
// PTSTR pszKeyName
//
// RETURN: True, if unique name is found
//------------------------------------------------------------------------------
BOOL RegEdit_GetTemporaryKeyName(HWND hWnd, PTSTR pszKeyName, HKEY hKey) { HKEY hNewKey; UINT uNewKeyNameID = 1;
while (uNewKeyNameID < MAX_KEYNAME_TEMPLATE_ID) { wsprintf(pszKeyName, g_RegEditData.pNewKeyTemplate, uNewKeyNameID);
if(RegOpenKeyEx(hKey, pszKeyName, 0, 0, &hNewKey) == ERROR_FILE_NOT_FOUND) { break; } RegCloseKey(hNewKey);
uNewKeyNameID++; }
if (uNewKeyNameID == MAX_KEYNAME_TEMPLATE_ID) { InternalMessageBox(g_hInstance, hWnd, MAKEINTRESOURCE(IDS_NEWKEYNOUNIQUE), MAKEINTRESOURCE(IDS_NEWKEYERRORTITLE), MB_ICONERROR | MB_OK, pszKeyName); }
return (uNewKeyNameID != MAX_KEYNAME_TEMPLATE_ID); }
/*******************************************************************************
* * RegEdit_OnKeyTreeItemExpanding * * DESCRIPTION: * * PARAMETERS: * hWnd, handle of RegEdit window. * lpNMTreeView, TreeView notification data. * *******************************************************************************/
LRESULT PASCAL RegEdit_OnKeyTreeItemExpanding( HWND hWnd, LPNM_TREEVIEW lpNMTreeView ) {
HWND hKeyTreeWnd; HTREEITEM hExpandingTreeItem; TCHAR KeyName[MAXKEYNAME]; TV_ITEM TVItem;
hKeyTreeWnd = g_RegEditData.hKeyTreeWnd; hExpandingTreeItem = lpNMTreeView-> itemNew.hItem;
//
// Check if we're to expand the given tree item for the first time. If so,
// delve into the registry to get all of the key's subkeys.
//
if (lpNMTreeView-> action & TVE_EXPAND && !(lpNMTreeView-> itemNew.state & TVIS_EXPANDEDONCE)) {
if (TreeView_GetChild(hKeyTreeWnd, hExpandingTreeItem) != NULL) return FALSE;
RegEdit_SetWaitCursor(TRUE);
if (!KeyTree_ExpandBranch(hKeyTreeWnd, hExpandingTreeItem)) {
//
// Get the text of the selected tree item so that we can display
// a more meaningful error message.
//
TVItem.mask = TVIF_TEXT; TVItem.hItem = hExpandingTreeItem; TVItem.pszText = (LPTSTR) KeyName; TVItem.cchTextMax = sizeof(KeyName)/sizeof(TCHAR);
TreeView_GetItem(hKeyTreeWnd, &TVItem);
InternalMessageBox(g_hInstance, hWnd, MAKEINTRESOURCE(IDS_OPENKEYCANNOTOPEN), MAKEINTRESOURCE(IDS_OPENKEYERRORTITLE), MB_ICONERROR | MB_OK, (LPTSTR) KeyName);
}
RegEdit_SetWaitCursor(FALSE);
}
return FALSE;
}
/*******************************************************************************
* * RegEdit_OnKeyTreeSelChanged * * DESCRIPTION: * Depending on how the user has selected the new item in the KeyTreeWnd, * we call to the real worker routine, RegEdit_KeyTreeSelChanged, or delay * the call for several milliseconds. * * PARAMETERS: * hWnd, handle of RegEdit window. * lpNMTreeView, TreeView notification data. * *******************************************************************************/
VOID PASCAL RegEdit_OnKeyTreeSelChanged( HWND hWnd, LPNM_TREEVIEW lpNMTreeView ) {
UINT TimerDelay;
//
// We delay the actual update of the selection and thus of the
// ValueListWnd for several milliseconds. This avoids unnecessary flashing
// as the user scrolls through the tree. (This behavior is directly taken
// from the Explorer.)
//
switch (g_RegEditData.SelChangeTimerState) {
case SCTS_TIMERSET: KillTimer(hWnd, SELCHANGE_TIMER_ID); // FALL THROUGH
case SCTS_TIMERCLEAR: #ifdef WINNT
//
// This behavior is extremely annoying so I am changing it.
//
TimerDelay = 1; #else
TimerDelay = (lpNMTreeView != NULL && lpNMTreeView-> action == TVC_BYMOUSE) ? (1) : (GetDoubleClickTime() * 3 / 2); #endif
SetTimer(hWnd, SELCHANGE_TIMER_ID, TimerDelay, NULL); g_RegEditData.SelChangeTimerState = SCTS_TIMERSET; break;
//
// We want to punt the first selection change notification that comes
// through.
//
case SCTS_INITIALIZING: RegEdit_KeyTreeSelChanged(hWnd); break;
}
}
/*******************************************************************************
* * RegEdit_OnSelChangedTimer * * DESCRIPTION: * Called several milliseconds after a keyboard operation has selected a new * item in the KeyTreeWnd. Act as if a new selection has just been made in * the KeyTreeWnd. * * PARAMETERS: * hWnd, handle of RegEdit window. * *******************************************************************************/
VOID PASCAL RegEdit_OnSelChangedTimer( HWND hWnd ) {
KillTimer(hWnd, SELCHANGE_TIMER_ID); g_RegEditData.SelChangeTimerState = SCTS_TIMERCLEAR;
RegEdit_KeyTreeSelChanged(hWnd);
}
/*******************************************************************************
* * RegEdit_KeyTreeSelChanged * * DESCRIPTION: * Called after a new item has been selected in the KeyTreeWnd. Opens a * registry key to the new branch and notifies the ValueListWnd to update * itself. * * PARAMETERS: * hWnd, handle of RegEdit window. * *******************************************************************************/
VOID PASCAL RegEdit_KeyTreeSelChanged( HWND hWnd ) {
HWND hKeyTreeWnd; HTREEITEM hSelectedTreeItem; RECT ItemRect; RECT ClientRect; RECT FromRect; RECT ToRect; HKEY hRootKey; TCHAR KeyName[MAXKEYNAME]; TV_ITEM TVItem;
hKeyTreeWnd = g_RegEditData.hKeyTreeWnd; hSelectedTreeItem = TreeView_GetSelection(hKeyTreeWnd);
if (g_RegEditData.SelChangeTimerState != SCTS_INITIALIZING) {
//
// Draw an animation that shows the "expansion" of the newly selected
// tree item to the ListView.
//
TreeView_GetItemRect(hKeyTreeWnd, hSelectedTreeItem, &ItemRect, TRUE); GetClientRect(hKeyTreeWnd, &ClientRect); IntersectRect(&FromRect, &ClientRect, &ItemRect); MapWindowPoints(hKeyTreeWnd, hWnd, (LPPOINT) &FromRect, 2);
GetWindowRect(g_RegEditData.hValueListWnd, &ToRect); MapWindowPoints(NULL, hWnd, (LPPOINT) &ToRect, 2);
DrawAnimatedRects(hWnd, IDANI_OPEN, &FromRect, &ToRect);
}
//
// Close the previously selected item's key handle, if appropriate.
//
if (g_RegEditData.hCurrentSelectionKey != NULL) {
RegCloseKey(g_RegEditData.hCurrentSelectionKey); g_RegEditData.hCurrentSelectionKey = NULL;
}
RegEdit_UpdateStatusBar();
//
// Simple case-- we're changing to one of the top-level labels, such as
// "My Computer" or a network computer name. Right now, nothing is
// displayed in the ListView, so just empty it and return.
//
if (TreeView_GetParent(hKeyTreeWnd, hSelectedTreeItem) != NULL) {
//
// Build a registry path to the selected tree item and open a registry
// key.
//
hRootKey = KeyTree_BuildKeyPath(hKeyTreeWnd, hSelectedTreeItem, KeyName, BKP_TOSUBKEY);
if(RegOpenKeyEx(hRootKey,KeyName, 0, MAXIMUM_ALLOWED, &g_RegEditData.hCurrentSelectionKey) != ERROR_SUCCESS) {
//
// Get the text of the selected tree item so that we can display
// a more meaningful error message.
//
TVItem.mask = TVIF_TEXT; TVItem.hItem = hSelectedTreeItem; TVItem.pszText = (LPTSTR) KeyName; TVItem.cchTextMax = sizeof(KeyName)/sizeof(TCHAR);
TreeView_GetItem(hKeyTreeWnd, &TVItem);
InternalMessageBox(g_hInstance, hWnd, MAKEINTRESOURCE(IDS_OPENKEYCANNOTOPEN), MAKEINTRESOURCE(IDS_OPENKEYERRORTITLE), MB_ICONERROR | MB_OK, (LPTSTR) KeyName);
}
}
RegEdit_OnValueListRefresh(hWnd);
}
/*******************************************************************************
* * RegEdit_OnKeyTreeBeginLabelEdit * * DESCRIPTION: * * PARAMETERS: * hWnd, handle of RegEdit window. * lpTVDispInfo, * *******************************************************************************/
BOOL PASCAL RegEdit_OnKeyTreeBeginLabelEdit( HWND hWnd, TV_DISPINFO FAR* lpTVDispInfo ) {
//
// B#7933: We don't want the user to hurt themselves by making it too easy
// to rename keys and values. Only allow renames via the menus.
//
//
// We don't get any information on the source of this editing action, so
// we must maintain a flag that tells us whether or not this is "good".
//
if (!g_RegEditData.fAllowLabelEdits) return TRUE;
//
// All other labels are fair game. We need to disable our keyboard
// accelerators so that the edit control can "see" them.
//
g_fDisableAccelerators = TRUE;
return FALSE;
}
/*******************************************************************************
* * RegEdit_OnKeyTreeEndLabelEdit * * DESCRIPTION: * * PARAMETERS: * hWnd, handle of RegEdit window. * lpTVDispInfo, * *******************************************************************************/
BOOL PASCAL RegEdit_OnKeyTreeEndLabelEdit( HWND hWnd, TV_DISPINFO FAR* lpTVDispInfo ) {
HWND hKeyTreeWnd; HKEY hRootKey; TCHAR SourceKeyName[MAXKEYNAME*2]; TCHAR DestinationKeyName[MAXKEYNAME]; HKEY hSourceKey; HKEY hDestinationKey; LPTSTR lpEndOfParentKey; UINT ErrorStringID; TV_ITEM TVItem;
//
// We can reenable our keyboard accelerators now that the edit control no
// longer needs to "see" them.
//
g_fDisableAccelerators = FALSE;
hKeyTreeWnd = g_RegEditData.hKeyTreeWnd;
//
// Check to see if the user cancelled the edit. If so, we don't care so
// just return.
//
if (lpTVDispInfo-> item.pszText == NULL) return FALSE;
//
// Attempt to open the key to be renamed. This may or may not be the same
// key that is already open.
//
hRootKey = KeyTree_BuildKeyPath(hKeyTreeWnd, lpTVDispInfo-> item.hItem, SourceKeyName, BKP_TOSUBKEY); if (lstrlen(SourceKeyName) >= MAXKEYNAME) { ErrorStringID = IDS_RENAMEKEYTOOLONG; goto error_ShowDialog;
}
if(RegOpenKeyEx(hRootKey,SourceKeyName,0,KEY_ENUMERATE_SUB_KEYS|KEY_QUERY_VALUE,&hSourceKey) != ERROR_SUCCESS) {
ErrorStringID = IDS_RENAMEKEYOTHERERROR; goto error_ShowDialog;
}
//
// Take the full path name of the key (relative to a predefined root key)
// and replace the old key name with the new. Make sure that this key
// doesn't exceed our internal buffers.
//
lstrcpy(DestinationKeyName, SourceKeyName);
if ((lpEndOfParentKey = StrRChr(DestinationKeyName, NULL, TEXT('\\'))) != NULL) lpEndOfParentKey++;
else lpEndOfParentKey = DestinationKeyName;
*lpEndOfParentKey = 0;
if (lstrlen(DestinationKeyName) + lstrlen(lpTVDispInfo-> item.pszText) >= MAXKEYNAME) { ErrorStringID = IDS_RENAMEKEYTOOLONG; goto error_CloseSourceKey; }
lstrcpy(lpEndOfParentKey, lpTVDispInfo-> item.pszText);
//
// Make sure there are no backslashes in the name.
//
if (StrChr(lpEndOfParentKey, TEXT('\\')) != NULL) {
ErrorStringID = IDS_RENAMEKEYBADCHARS; goto error_CloseSourceKey;
}
//
// Make sure there the name isn't empty
//
if (DestinationKeyName[0] == 0) { ErrorStringID = IDS_RENAMEKEYEMPTY; goto error_CloseSourceKey; }
//
// Make sure that the destination doesn't already exist.
//
if(RegOpenKeyEx(hRootKey,DestinationKeyName,0,KEY_QUERY_VALUE,&hDestinationKey) == ERROR_SUCCESS) {
RegCloseKey(hDestinationKey);
ErrorStringID = IDS_RENAMEKEYEXISTS; goto error_CloseSourceKey;
}
//
// Create the destination key and do the copy.
//
if (RegCreateKey(hRootKey, DestinationKeyName, &hDestinationKey) != ERROR_SUCCESS) {
ErrorStringID = IDS_RENAMEKEYOTHERERROR; goto error_CloseSourceKey;
}
// FEATURE: Check this return (when it gets one!)
if (!CopyRegistry(hSourceKey, hDestinationKey)) { RegCloseKey(hDestinationKey); RegCloseKey(hSourceKey);
ErrorStringID = IDS_RENAMEKEYOTHERERROR; goto error_ShowDialog; }
RegCloseKey(hSourceKey);
//
// Check to see if we're renaming the currently selected key. If so, toss
// our cached key handle and change to our source key.
//
if (TreeView_GetSelection(hKeyTreeWnd) == lpTVDispInfo-> item.hItem) {
RegCloseKey(g_RegEditData.hCurrentSelectionKey);
g_RegEditData.hCurrentSelectionKey = hDestinationKey;
//
// We can't just call RegEdit_UpdateStatusBar here... the tree item
// won't be updated until we return TRUE from this message. So we must
// post a message to tell ourselves to do the update later on.
//
PostMessage(hWnd, REM_UPDATESTATUSBAR, 0, 0);
}
else RegCloseKey(hDestinationKey);
if (RegDeleteKeyRecursive(hRootKey, SourceKeyName) != ERROR_SUCCESS) {
ErrorStringID = IDS_RENAMEKEYOTHERERROR; goto error_ShowDialog;
}
return TRUE;
error_CloseSourceKey: RegCloseKey(hSourceKey);
error_ShowDialog: TVItem.hItem = lpTVDispInfo-> item.hItem; TVItem.mask = TVIF_TEXT; TVItem.pszText = SourceKeyName; TVItem.cchTextMax = sizeof(SourceKeyName)/sizeof(TCHAR);
TreeView_GetItem(hKeyTreeWnd, &TVItem);
InternalMessageBox(g_hInstance, hWnd, MAKEINTRESOURCE(ErrorStringID), MAKEINTRESOURCE(IDS_RENAMEKEYERRORTITLE), MB_ICONERROR | MB_OK, (LPTSTR) SourceKeyName);
return FALSE;
}
/*******************************************************************************
* * RegEdit_OnKeyTreeCommand * * DESCRIPTION: * Handles the selection of a menu item by the user intended for the * KeyTree child window. * * PARAMETERS: * hWnd, handle of RegEdit window. * MenuCommand, identifier of menu command. * hTreeItem, * *******************************************************************************/
VOID PASCAL RegEdit_OnKeyTreeCommand( HWND hWnd, int MenuCommand, HTREEITEM hTreeItem ) {
HWND hKeyTreeWnd;
hKeyTreeWnd = g_RegEditData.hKeyTreeWnd;
//
// Assume that the we mean the current selection if we're to dispatch a
// command that requires a tree item. This is necessary because the tree
// control will let you activate the context menu of one tree item while
// another one is really the selected tree item.
//
if (hTreeItem == NULL) hTreeItem = TreeView_GetSelection(hKeyTreeWnd);
switch (MenuCommand) {
case ID_CONTEXTMENU: RegEdit_OnKeyTreeContextMenu(hWnd, TRUE); break;
case ID_TOGGLE: TreeView_Expand(hKeyTreeWnd, hTreeItem, TVE_TOGGLE); break;
case ID_DELETE: RegEdit_OnKeyTreeDelete(hWnd, hTreeItem); break;
case ID_RENAME: RegEdit_OnKeyTreeRename(hWnd, hTreeItem); break;
case ID_DISCONNECT: RegEdit_OnKeyTreeDisconnect(hWnd, hTreeItem); break;
case ID_COPYKEYNAME: RegEdit_OnCopyKeyName(hWnd, hTreeItem); break;
case ID_NEWKEY: RegEdit_OnNewKey(hWnd, hTreeItem); break;
case ID_NEWSTRINGVALUE: case ID_NEWBINARYVALUE: if (hTreeItem != TreeView_GetSelection(hKeyTreeWnd)) {
//
// Force the selection to occur now, so that we're dealing
// with the right open key.
//
TreeView_SelectItem(hKeyTreeWnd, hTreeItem); RegEdit_OnSelChangedTimer(hWnd);
} // FALL THROUGH
default: //
// Check to see if this menu command should be handled by the main
// window's command handler.
//
if (MenuCommand >= ID_FIRSTMAINMENUITEM && MenuCommand <= ID_LASTMAINMENUITEM) RegEdit_OnCommand(hWnd, MenuCommand, NULL, 0); break;
}
}
/*******************************************************************************
* * RegEdit_OnKeyTreeContextMenu * * DESCRIPTION: * * PARAMETERS: * *******************************************************************************/
VOID PASCAL RegEdit_OnKeyTreeContextMenu( HWND hWnd, BOOL fByAccelerator ) {
HWND hKeyTreeWnd; DWORD MessagePos; POINT MessagePoint; TV_HITTESTINFO TVHitTestInfo; UINT MenuID; HMENU hContextMenu; HMENU hContextPopupMenu; TV_ITEM TVItem; int MenuCommand;
hKeyTreeWnd = g_RegEditData.hKeyTreeWnd;
//
// If fByAcclerator is TRUE, then the user hit Shift-F10 to bring up the
// context menu. Following the Cabinet's convention, this menu is
// placed at (0,0) of the KeyTree client area.
//
if (fByAccelerator) {
MessagePoint.x = 0; MessagePoint.y = 0;
ClientToScreen(hKeyTreeWnd, &MessagePoint);
TVItem.hItem = TreeView_GetSelection(hKeyTreeWnd);
}
else {
MessagePos = GetMessagePos();
MessagePoint.x = GET_X_LPARAM(MessagePos); MessagePoint.y = GET_Y_LPARAM(MessagePos);
TVHitTestInfo.pt = MessagePoint; ScreenToClient(hKeyTreeWnd, &TVHitTestInfo.pt); TVItem.hItem = TreeView_HitTest(hKeyTreeWnd, &TVHitTestInfo);
}
//
// Determine which context menu to use and load it up.
//
if (TVItem.hItem == NULL) { return; // No context menu for now
} else { // Select the item to be dragged
TreeView_Select(g_RegEditData.hKeyTreeWnd, TVItem.hItem, TVGN_CARET);
if (TreeView_GetParent(hKeyTreeWnd, TVItem.hItem) == NULL) MenuID = IDM_COMPUTER_CONTEXT;
else MenuID = IDM_KEY_CONTEXT;
}
if ((hContextMenu = LoadMenu(g_hInstance, MAKEINTRESOURCE(MenuID))) == NULL) return;
hContextPopupMenu = GetSubMenu(hContextMenu, 0);
TVItem.mask = TVIF_STATE | TVIF_CHILDREN; TreeView_GetItem(hKeyTreeWnd, &TVItem);
if (TVItem.state & TVIS_EXPANDED) ModifyMenu(hContextPopupMenu, ID_TOGGLE, MF_BYCOMMAND | MF_STRING, ID_TOGGLE, g_RegEditData.pCollapse);
if (MenuID == IDM_COMPUTER_CONTEXT) {
if (g_RegEditData.fHaveNetwork) {
if (TreeView_GetPrevSibling(hKeyTreeWnd, TVItem.hItem) == NULL) EnableMenuItem(hContextPopupMenu, ID_DISCONNECT, MF_GRAYED | MF_BYCOMMAND);
}
else {
DeleteMenu(hContextPopupMenu, ID_DISCONNECT, MF_BYCOMMAND); DeleteMenu(hContextPopupMenu, ID_NETSEPARATOR, MF_BYCOMMAND);
}
}
else {
RegEdit_SetKeyTreeEditMenuItems(hContextPopupMenu, TVItem.hItem);
if (TVItem.cChildren == 0) EnableMenuItem(hContextPopupMenu, ID_TOGGLE, MF_GRAYED | MF_BYCOMMAND);
}
SetMenuDefaultItem(hContextPopupMenu, ID_TOGGLE, MF_BYCOMMAND);
MenuCommand = TrackPopupMenuEx(hContextPopupMenu, TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTALIGN | TPM_TOPALIGN, MessagePoint.x, MessagePoint.y, hWnd, NULL);
DestroyMenu(hContextMenu);
RegEdit_OnKeyTreeCommand(hWnd, MenuCommand, TVItem.hItem);
}
/*******************************************************************************
* * RegEdit_SetKeyTreeEditMenuItems * * DESCRIPTION: * Shared routine between the main menu and the context menu to setup the * edit menu items. * * PARAMETERS: * hPopupMenu, handle of popup menu to modify. * hTreeItem, handle of selected tree item. * *******************************************************************************/
VOID PASCAL RegEdit_SetKeyTreeEditMenuItems( HMENU hPopupMenu, HTREEITEM hSelectedTreeItem ) {
UINT EnableFlags;
EnableFlags = KeyTree_CanDeleteOrRenameItem(g_RegEditData.hKeyTreeWnd, hSelectedTreeItem) ? (MF_ENABLED | MF_BYCOMMAND) : (MF_GRAYED | MF_BYCOMMAND);
EnableMenuItem(hPopupMenu, ID_DELETE, EnableFlags); EnableMenuItem(hPopupMenu, ID_RENAME, EnableFlags);
}
/*******************************************************************************
* * RegEdit_OnKeyTreeDelete * * DESCRIPTION: * * PARAMETERS: * *******************************************************************************/
VOID PASCAL RegEdit_OnKeyTreeDelete( HWND hWnd, HTREEITEM hTreeItem ) {
HWND hKeyTreeWnd; HKEY hRootKey; TCHAR KeyName[MAXKEYNAME]; HTREEITEM hParentTreeItem; TV_ITEM TVItem;
hKeyTreeWnd = g_RegEditData.hKeyTreeWnd;
if (!KeyTree_CanDeleteOrRenameItem(hKeyTreeWnd, hTreeItem)) return;
if (InternalMessageBox(g_hInstance, hWnd, MAKEINTRESOURCE(IDS_CONFIRMDELKEYTEXT), MAKEINTRESOURCE(IDS_CONFIRMDELKEYTITLE), MB_ICONWARNING | MB_YESNO) != IDYES) return;
if (hTreeItem == TreeView_GetSelection(hKeyTreeWnd)) {
if (g_RegEditData.hCurrentSelectionKey != NULL) {
RegCloseKey(g_RegEditData.hCurrentSelectionKey); g_RegEditData.hCurrentSelectionKey = NULL;
}
}
hRootKey = KeyTree_BuildKeyPath(hKeyTreeWnd, hTreeItem, KeyName, BKP_TOSUBKEY);
if (RegDeleteKeyRecursive(hRootKey, KeyName) == ERROR_SUCCESS) {
SetWindowRedraw(hKeyTreeWnd, FALSE);
hParentTreeItem = TreeView_GetParent(hKeyTreeWnd, hTreeItem);
TreeView_DeleteItem(hKeyTreeWnd, hTreeItem);
//
// See if the key that we just deleted was the last child of its
// parent. If so, remove the expand/collapse button.
//
if (TreeView_GetChild(hKeyTreeWnd, hParentTreeItem) == NULL) {
TVItem.mask = TVIF_CHILDREN | TVIF_STATE; TVItem.hItem = hParentTreeItem; TVItem.cChildren = 0; TVItem.state = 0; TVItem.stateMask = TVIS_EXPANDED | TVIS_EXPANDEDONCE; TreeView_SetItem(hKeyTreeWnd, &TVItem);
}
//
// Make sure we can see the selected tree item now since it may be
// currently off-screen.
//
TreeView_EnsureVisible(hKeyTreeWnd, TreeView_GetSelection(hKeyTreeWnd));
SetWindowRedraw(hKeyTreeWnd, TRUE);
UpdateWindow(hKeyTreeWnd);
}
else {
TVItem.hItem = hTreeItem; TVItem.mask = TVIF_TEXT; TVItem.pszText = KeyName; TVItem.cchTextMax = sizeof(KeyName)/sizeof(TCHAR);
TreeView_GetItem(hKeyTreeWnd, &TVItem);
InternalMessageBox(g_hInstance, hWnd, MAKEINTRESOURCE(IDS_DELETEKEYDELETEFAILED), MAKEINTRESOURCE(IDS_DELETEKEYERRORTITLE), MB_ICONERROR | MB_OK, KeyName);
//
// Need to refresh the tree at this point, as some subkeys may have
// been deleted successfully even if we didn't have sufficient
// permissions to delete all of them.
//
RegEdit_OnKeyTreeRefresh(hWnd); }
}
/*******************************************************************************
* * RegEdit_OnKeyTreeRename * * DESCRIPTION: * * PARAMETERS: * *******************************************************************************/
VOID PASCAL RegEdit_OnKeyTreeRename( HWND hWnd, HTREEITEM hTreeItem ) {
if (KeyTree_CanDeleteOrRenameItem(g_RegEditData.hKeyTreeWnd, hTreeItem)) KeyTree_EditLabel(g_RegEditData.hKeyTreeWnd, hTreeItem);
}
/*******************************************************************************
* * RegEdit_OnKeyTreeRefresh * * DESCRIPTION: * * PARAMETERS: * *******************************************************************************/
VOID PASCAL RegEdit_OnKeyTreeRefresh( HWND hWnd ) {
HDPA hDPA; HWND hKeyTreeWnd; HTREEITEM hPrevSelectedTreeItem; TV_ITEM EnumTVItem; TV_ITEM CurrentTVItem; HKEY hRootKey; TCHAR KeyName[MAXKEYNAME]; int MaximumSubKeyLength; int Index; HKEY hEnumKey; int CompareResult; LPTSTR lpDPAKeyName; HTREEITEM hTempTreeItem;
if ((hDPA = DPA_CreateEx(REFRESH_DPA_GROW, GetProcessHeap())) == NULL) return;
hKeyTreeWnd = g_RegEditData.hKeyTreeWnd;
RegEdit_SetWaitCursor(TRUE); SetWindowRedraw(hKeyTreeWnd, FALSE);
hPrevSelectedTreeItem = TreeView_GetSelection(hKeyTreeWnd);
EnumTVItem.mask = TVIF_TEXT; EnumTVItem.pszText = KeyName; EnumTVItem.cchTextMax = sizeof(KeyName)/sizeof(TCHAR);
CurrentTVItem.mask = TVIF_STATE | TVIF_CHILDREN; CurrentTVItem.stateMask = 0; CurrentTVItem.hItem = TreeView_GetRoot(hKeyTreeWnd);
while (TRUE) {
TreeView_GetItem(hKeyTreeWnd, &CurrentTVItem); hRootKey = KeyTree_BuildKeyPath(hKeyTreeWnd, CurrentTVItem.hItem, KeyName, BKP_TOSUBKEY);
if (CurrentTVItem.state & TVIS_EXPANDED) {
//
// If this isn't a top-level label (and it won't be if hRootKey is
// not NULL), then compare the actual contents of the registry
// against what we're showing.
//
if(hRootKey && RegOpenKeyEx(hRootKey,KeyName,0,KEY_ENUMERATE_SUB_KEYS,&hEnumKey) == ERROR_SUCCESS) {
//
// As a result of adding new keys and renaming existing ones,
// the children of this item may be out of order. For the
// following algorithm to work correctly, we must now sort
// these keys.
//
TreeView_SortChildren(hKeyTreeWnd, CurrentTVItem.hItem, FALSE);
//
// Build a sorted dynamic array of strings that represent the
// keys actually in the registry at this time.
//
MaximumSubKeyLength = MAXKEYNAME - (lstrlen(KeyName) + 1); Index = 0;
while (RegEnumKey(hEnumKey, Index, KeyName, MaximumSubKeyLength) == ERROR_SUCCESS) {
lpDPAKeyName = NULL; Str_SetPtr(&lpDPAKeyName, KeyName); DPA_InsertPtr(hDPA, Index++, lpDPAKeyName);
}
RegCloseKey(hEnumKey); DPA_Sort(hDPA, DPACompareKeyNames, 0);
//
// Does this key have subkeys anymore? If not, then we need
// to reset it's child flag and remove all of it's children.
//
if (Index == 0) {
DPA_DeleteAllPtrs(hDPA);
TreeView_Expand(hKeyTreeWnd, CurrentTVItem.hItem, TVE_COLLAPSE | TVE_COLLAPSERESET);
CurrentTVItem.cChildren = 0; goto SetCurrentTreeItem;
}
//
// Merge the keys that we found during our above enumeration
// with the keys that our key tree lists. Add and remove
// elements from the tree as appropriate.
//
lpDPAKeyName = DPA_FastGetPtr(hDPA, --Index);
EnumTVItem.hItem = TreeView_GetChild(hKeyTreeWnd, CurrentTVItem.hItem); if (EnumTVItem.hItem) TreeView_GetItem(hKeyTreeWnd, &EnumTVItem);
while (Index >= 0 && EnumTVItem.hItem != NULL) {
CompareResult = lstrcmpi(KeyName, lpDPAKeyName);
if (CompareResult == 0) {
EnumTVItem.hItem = TreeView_GetNextSibling(hKeyTreeWnd, EnumTVItem.hItem); if (EnumTVItem.hItem) TreeView_GetItem(hKeyTreeWnd, &EnumTVItem);
goto GetNextDPAPointer;
}
else if (CompareResult > 0) {
KeyTree_InsertItem(hKeyTreeWnd, CurrentTVItem.hItem, TVI_SORT, lpDPAKeyName, DoesKeyHaveKids(hEnumKey, lpDPAKeyName), 0);
GetNextDPAPointer: Str_SetPtr(&lpDPAKeyName, NULL);
if (--Index >= 0) lpDPAKeyName = DPA_FastGetPtr(hDPA, Index);
}
else {
hTempTreeItem = TreeView_GetNextSibling(hKeyTreeWnd, EnumTVItem.hItem); TreeView_DeleteItem(hKeyTreeWnd, EnumTVItem.hItem); EnumTVItem.hItem = hTempTreeItem; if (EnumTVItem.hItem) TreeView_GetItem(hKeyTreeWnd, &EnumTVItem);
}
}
//
// Once we drop to here, we may have extra items in the key
// tree or in the dynamic array. Process them accordingly.
//
if (Index >= 0) {
while (TRUE) {
KeyTree_InsertItem(hKeyTreeWnd, CurrentTVItem.hItem, TVI_SORT, lpDPAKeyName, DoesKeyHaveKids(hEnumKey, lpDPAKeyName), 0);
Str_SetPtr(&lpDPAKeyName, NULL);
if (--Index < 0) break;
lpDPAKeyName = DPA_FastGetPtr(hDPA, Index);
}
}
else {
while (EnumTVItem.hItem != NULL) {
hTempTreeItem = TreeView_GetNextSibling(hKeyTreeWnd, EnumTVItem.hItem); TreeView_DeleteItem(hKeyTreeWnd, EnumTVItem.hItem); EnumTVItem.hItem = hTempTreeItem;
}
}
DPA_DeleteAllPtrs(hDPA);
}
CurrentTVItem.hItem = TreeView_GetChild(hKeyTreeWnd, CurrentTVItem.hItem);
}
else {
//
// If this isn't a top-level label (and it won't be if hRootKey is
// not NULL), then re-check if this key has any children.
//
if (hRootKey != NULL) {
TreeView_Expand(hKeyTreeWnd, CurrentTVItem.hItem, TVE_COLLAPSE | TVE_COLLAPSERESET);
CurrentTVItem.cChildren = DoesKeyHaveKids(hRootKey, KeyName);
SetCurrentTreeItem: TreeView_SetItem(hKeyTreeWnd, &CurrentTVItem);
}
//
// Because we're at the "bottom" of the TreeView, we now need to
// walk to the siblings of this tree item. And if no siblings
// exist, we walk back to the parent and check again for siblings.
//
while (TRUE) {
if ((hTempTreeItem = TreeView_GetNextSibling(hKeyTreeWnd, CurrentTVItem.hItem)) != NULL) {
CurrentTVItem.hItem = hTempTreeItem; break;
}
if ((CurrentTVItem.hItem = TreeView_GetParent(hKeyTreeWnd, CurrentTVItem.hItem)) == NULL) {
//
// We've now walked over all of the tree items, so do any
// cleanup here and exit.
//
DPA_Destroy(hDPA);
SetWindowRedraw(hKeyTreeWnd, TRUE);
//
// The selection may have changed as a result of having
// the focus on an nonexistent key.
//
if (TreeView_GetSelection(hKeyTreeWnd) != hPrevSelectedTreeItem) { RegEdit_OnKeyTreeSelChanged(hWnd, NULL); } else { if (RegEdit_OnValueListRefresh(hWnd) != ERROR_SUCCESS) { //
// Its possible that the registry key was deleted and replaced with
// an identically-named key. We should just trigger a selection
// change in this case.
//
RegEdit_OnKeyTreeSelChanged(hWnd, NULL); } }
RegEdit_SetWaitCursor(FALSE);
return;
}
}
}
}
}
/*******************************************************************************
* * DPACompareKeyNames * * DESCRIPTION: * Callback comparision routine for refresh's DPA_Sort call. Simply returns * the result of lstrcmpi. * * PARAMETERS: * lpString1, * lpString2, * lParam, ignored optional data. * *******************************************************************************/
int WINAPI DPACompareKeyNames( LPVOID lpString1, LPVOID lpString2, LPARAM lParam ) {
return lstrcmpi((LPTSTR) lpString2, (LPTSTR) lpString1);
}
/*******************************************************************************
* * RegEdit_OnKeyTreeDisconnect * * DESCRIPTION: * * PARAMETERS: * *******************************************************************************/
VOID PASCAL RegEdit_OnKeyTreeDisconnect( HWND hWnd, HTREEITEM hTreeItem ) {
HWND hKeyTreeWnd; TV_ITEM TVItem;
hKeyTreeWnd = g_RegEditData.hKeyTreeWnd;
//
// Disconnect all of the root registry handles that we've opened.
//
TVItem.mask = TVIF_PARAM; TVItem.hItem = TreeView_GetChild(hKeyTreeWnd, hTreeItem);
while (TVItem.hItem != NULL) {
TreeView_GetItem(hKeyTreeWnd, &TVItem);
RegCloseKey((HKEY) TVItem.lParam);
TVItem.hItem = TreeView_GetNextSibling(hKeyTreeWnd, TVItem.hItem);
}
TreeView_DeleteItem(hKeyTreeWnd, hTreeItem);
}
/*******************************************************************************
* * RegEdit_UpdateStatusBar * * DESCRIPTION: * Show the full registry path in the status bar, for lack of anything * better to do with it. * * PARAMETERS: * (none). * *******************************************************************************/
VOID PASCAL RegEdit_UpdateStatusBar( VOID ) {
HWND hKeyTreeWnd; TCHAR KeyName[MAXKEYNAME*2];
hKeyTreeWnd = g_RegEditData.hKeyTreeWnd; KeyTree_BuildKeyPath(hKeyTreeWnd, TreeView_GetSelection(hKeyTreeWnd), KeyName, BKP_TOCOMPUTER); SetWindowText(g_RegEditData.hStatusBarWnd, KeyName);
}
/*******************************************************************************
* * RegEdit_OnCopyKeyName * * DESCRIPTION: * * PARAMETERS: * *******************************************************************************/
VOID PASCAL RegEdit_OnCopyKeyName( HWND hWnd, HTREEITEM hTreeItem ) {
TCHAR KeyName[MAXKEYNAME*2]; UINT KeyNameLength; HANDLE hClipboardData; LPTSTR lpClipboardData;
KeyTree_BuildKeyPath(g_RegEditData.hKeyTreeWnd, hTreeItem, KeyName, BKP_TOSYMBOLICROOT); KeyNameLength = (lstrlen(KeyName) + 1) * sizeof(TCHAR);
if (OpenClipboard(hWnd)) {
if ((hClipboardData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, KeyNameLength)) != NULL) {
lpClipboardData = (LPTSTR) GlobalLock(hClipboardData); CopyMemory(lpClipboardData, KeyName, KeyNameLength); GlobalUnlock(hClipboardData);
EmptyClipboard(); SetClipboardData(CF_UNICODETEXT, hClipboardData);
}
CloseClipboard();
}
}
/*******************************************************************************
* * KeyTree_BuildKeyPath * * DESCRIPTION: * * PARAMETERS: * hTreeViewWnd, handle of KeyTree window. * hTreeItem, handle of tree item to begin building from. * lpKeyPath, buffer to store path in. * fIncludeSymbolicRootName, TRUE if root key's name should be included * (e.g., HKEY_LOCAL_MACHINE), else FALSE. * *******************************************************************************/
HKEY PASCAL KeyTree_BuildKeyPath( HWND hTreeViewWnd, HTREEITEM hTreeItem, LPTSTR lpKeyPath, UINT ToFlags ) {
TV_ITEM TVItem; TCHAR SubKeyName[MAXKEYNAME*2];
*lpKeyPath = '\0';
TVItem.mask = TVIF_TEXT | TVIF_PARAM; TVItem.hItem = hTreeItem; TVItem.pszText = (LPTSTR) SubKeyName; TVItem.cchTextMax = sizeof(SubKeyName)/sizeof(TCHAR);
while (TRUE) {
TreeView_GetItem(hTreeViewWnd, &TVItem);
if (TVItem.lParam != 0 && !(ToFlags & BKP_TOSYMBOLICROOT)) break;
if (*lpKeyPath != '\0') {
lstrcat(SubKeyName, TEXT("\\")); lstrcat(SubKeyName, lpKeyPath);
}
lstrcpy(lpKeyPath, SubKeyName);
if (TVItem.lParam != 0 && (ToFlags & BKP_TOCOMPUTER) != BKP_TOCOMPUTER) break;
TVItem.hItem = TreeView_GetParent(hTreeViewWnd, TVItem.hItem);
if (TVItem.hItem == NULL) {
if ((ToFlags & BKP_TOCOMPUTER) != BKP_TOCOMPUTER) *lpKeyPath = '\0';
break;
}
}
return ((HKEY) TVItem.lParam);
}
/*******************************************************************************
* * KeyTree_InsertItem * * DESCRIPTION: * * PARAMETERS: * *******************************************************************************/
HTREEITEM PASCAL KeyTree_InsertItem( HWND hKeyTreeWnd, HTREEITEM hParent, HTREEITEM hInsertAfter, LPCTSTR lpText, UINT fHasKids, LPARAM lParam ) {
TV_INSERTSTRUCT TVInsertStruct;
TVInsertStruct.hParent = hParent; TVInsertStruct.hInsertAfter = hInsertAfter; TVInsertStruct.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM | TVIF_CHILDREN; // TVInsertStruct.item.hItem = NULL;
// TVInsertStruct.item.state = 0;
// TVInsertStruct.item.stateMask = 0;
TVInsertStruct.item.pszText = (LPTSTR) lpText; // TVInsertStruct.item.cchTextMax = lstrlen(lpText);
TVInsertStruct.item.iImage = IMAGEINDEX(IDI_FOLDER); TVInsertStruct.item.iSelectedImage = IMAGEINDEX(IDI_FOLDEROPEN); TVInsertStruct.item.cChildren = fHasKids; TVInsertStruct.item.lParam = lParam;
return TreeView_InsertItem(hKeyTreeWnd, &TVInsertStruct);
}
/*******************************************************************************
* * KeyTree_ExpandBranch * * DESCRIPTION: * * PARAMETERS: * hTreeViewWnd, handle of KeyTree window. * hTreeItem, handle of tree item to edit. * *******************************************************************************/
BOOL PASCAL KeyTree_ExpandBranch( HWND hKeyTreeWnd, HTREEITEM hExpandingTreeItem ) {
TCHAR KeyName[MAXKEYNAME]; HKEY hRootKey; HKEY hEnumKey; int Index; int MaximumSubKeyLength;
//
// Nothing special needs to be done with a top-level label such as "My
// Computer" or a network computer name. It's children are already filled
// in and are always valid.
//
if (TreeView_GetParent(hKeyTreeWnd, hExpandingTreeItem) == NULL) return TRUE;
hRootKey = KeyTree_BuildKeyPath(hKeyTreeWnd, hExpandingTreeItem, KeyName, FALSE);
if(RegOpenKeyEx(hRootKey,KeyName,0,KEY_ENUMERATE_SUB_KEYS,&hEnumKey) != ERROR_SUCCESS) return FALSE;
MaximumSubKeyLength = MAXKEYNAME - (lstrlen(KeyName) + 1); Index = 0;
while (RegEnumKey(hEnumKey, Index++, KeyName, MaximumSubKeyLength) == ERROR_SUCCESS) {
KeyTree_InsertItem(hKeyTreeWnd, hExpandingTreeItem, TVI_FIRST, KeyName, DoesKeyHaveKids(hEnumKey, KeyName), 0);
}
RegCloseKey(hEnumKey);
//
// Sort the subkeys _after_ inserting all the items. The above insert
// used to specify TVI_SORT, but on NT, expanding a key with several
// subkeys (e.g., HKEY_CLASSES_ROOT) would take several seconds!
//
TreeView_SortChildren(hKeyTreeWnd, hExpandingTreeItem, FALSE);
return TRUE;
}
/*******************************************************************************
* * DoesKeyHaveKids * * DESCRIPTION: * Checks if the given key path has any subkeys or not. * * PARAMETERS: * *******************************************************************************/
BOOL PASCAL DoesKeyHaveKids( HKEY hKey, LPTSTR lpKeyName ) {
BOOL fHasKids; HKEY hCheckChildrenKey; DWORD cSubKeys;
fHasKids = FALSE;
if(RegOpenKeyEx(hKey,lpKeyName,0,KEY_QUERY_VALUE|KEY_ENUMERATE_SUB_KEYS, &hCheckChildrenKey) == ERROR_SUCCESS) {
if (RegQueryInfoKey(hCheckChildrenKey, NULL, NULL, NULL, &cSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS && cSubKeys > 0) fHasKids = TRUE;
RegCloseKey(hCheckChildrenKey);
}
return fHasKids;
}
/*******************************************************************************
* * KeyTree_EditLabel * * DESCRIPTION: * * PARAMETERS: * hTreeViewWnd, handle of KeyTree window. * hTreeItem, handle of tree item to edit. * *******************************************************************************/
VOID PASCAL KeyTree_EditLabel( HWND hKeyTreeWnd, HTREEITEM hTreeItem ) {
g_RegEditData.fAllowLabelEdits = TRUE;
TreeView_EditLabel(hKeyTreeWnd, hTreeItem);
g_RegEditData.fAllowLabelEdits = FALSE;
}
/*******************************************************************************
* * KeyTree_CanDeleteOrRenameItem * * DESCRIPTION: * * PARAMETERS: * hTreeViewWnd, handle of KeyTree window. * hTreeItem, handle of tree item to check. * *******************************************************************************/
BOOL PASCAL KeyTree_CanDeleteOrRenameItem( HWND hWnd, HTREEITEM hTreeItem ) {
TV_ITEM TVItem;
//
// Check if the selected tree item is null. This will occur when viewing
// the Edit popup from the main menu with no selection made.
//
if (hTreeItem != NULL) {
//
// Check if this tree item has any reference data indicating that it
// is a predefined root. Predefined roots cannot be renamed or
// deleted.
//
TVItem.hItem = hTreeItem; TVItem.mask = TVIF_PARAM; TreeView_GetItem(hWnd, &TVItem);
if ((HKEY) TVItem.lParam == NULL) {
//
// Check that this isn't a top-level item such as "My Computer" or
// a remote registry connection.
//
if (TreeView_GetParent(hWnd, hTreeItem) != NULL) return TRUE;
}
}
return FALSE;
}
//------------------------------------------------------------------------------
// KeyTree_GetRootKey
//
// DESCRIPTION: Returns the root key of the item (HKEY_ ...)
//
// PARAMETERS: hTreeItem - treeview item
//------------------------------------------------------------------------------
HKEY KeyTree_GetRootKey(HTREEITEM hTreeItem) { TV_ITEM TVItem; TVItem.mask = TVIF_PARAM; TVItem.hItem = hTreeItem;
TreeView_GetItem(g_RegEditData.hKeyTreeWnd, &TVItem);
while (!TVItem.lParam) { TVItem.hItem = TreeView_GetParent(g_RegEditData.hKeyTreeWnd, TVItem.hItem); TreeView_GetItem(g_RegEditData.hKeyTreeWnd, &TVItem); }
return ((HKEY) TVItem.lParam); }
//------------------------------------------------------------------------------
// KeyTree_GetKeyName
//
// DESCRIPTION: Returns the TEXT of an item
//
// PARAMETERS: hTreeItem - treeview item
// pszText - pointer to an TCHAR array
// cchMax - number of characters in the array
//------------------------------------------------------------------------------
PTSTR KeyTree_GetKeyName(HTREEITEM hTreeItem, PTSTR pszName, int cchNameMax) { TV_ITEM TVItem;
pszName[0] = TEXT('\0');
TVItem.mask = TVIF_TEXT; TVItem.hItem = hTreeItem; TVItem.pszText = pszName; TVItem.cchTextMax = cchNameMax;
TreeView_GetItem(g_RegEditData.hKeyTreeWnd, &TVItem);
return TVItem.pszText; }
|