Regedit:  Added a "Goto key" right-click option.

This feature allows the user to right click on certain keys that "link" to other keys, Regedit can provide additional "Go to ...." menu items.  For example, if you click on a ProgID under HKCR, a "Go to 'HKCR\CLSID\{....}' menu item will appear.
Modified: trunk/reactos/subsys/system/regedit/En.rc
Modified: trunk/reactos/subsys/system/regedit/childwnd.c
Modified: trunk/reactos/subsys/system/regedit/main.h
Modified: trunk/reactos/subsys/system/regedit/resource.h
Modified: trunk/reactos/subsys/system/regedit/treeview.c

Modified: trunk/reactos/subsys/system/regedit/En.rc
--- trunk/reactos/subsys/system/regedit/En.rc	2005-10-03 12:12:19 UTC (rev 18242)
+++ trunk/reactos/subsys/system/regedit/En.rc	2005-10-03 12:39:50 UTC (rev 18243)
@@ -340,6 +340,7 @@
 BEGIN
   IDS_EXPAND                     "&Expand"
   IDS_COLLAPSE                   "&Collapse"
+  IDS_GOTO_SUGGESTED_KEY         "&Go to '%s'"
 END
 
 /*****************************************************************/

Modified: trunk/reactos/subsys/system/regedit/childwnd.c
--- trunk/reactos/subsys/system/regedit/childwnd.c	2005-10-03 12:12:19 UTC (rev 18242)
+++ trunk/reactos/subsys/system/regedit/childwnd.c	2005-10-03 12:39:50 UTC (rev 18243)
@@ -30,6 +30,7 @@
 ChildWnd* g_pChildWnd;
 HBITMAP SizingPattern = 0;
 HBRUSH  SizingBrush = 0;
+static TCHAR Suggestions[256];
 
 /*******************************************************************************
  * Local module support methods
@@ -106,11 +107,12 @@
     ChildWnd* pChildWnd = g_pChildWnd;
     HTREEITEM hSelection;
     HKEY hRootKey;
-    LPCTSTR keyPath;
+    LPCTSTR keyPath, s;
     TCHAR szConfirmTitle[256];
     TCHAR szConfirmText[256];
+    WORD wID = LOWORD(wParam);
 
-    switch (LOWORD(wParam)) {
+    switch (wID) {
         /* Parse the menu selections: */
     case ID_REGISTRY_EXIT:
         DestroyWindow(hWnd);
@@ -154,6 +156,18 @@
         SetFocus(pChildWnd->nFocusPanel? pChildWnd->hListWnd: pChildWnd->hTreeWnd);
         break;
     default:
+        if ((wID >= ID_TREE_SUGGESTION_MIN) && (wID <= ID_TREE_SUGGESTION_MAX))
+		{
+            s = Suggestions;
+            while(wID > ID_TREE_SUGGESTION_MIN)
+            {
+                if (*s)
+                    s += _tcslen(s) + 1;
+				wID--;
+            }
+            SelectNode(pChildWnd->hTreeWnd, s);
+            break;
+        }
         return FALSE;
     }
     return TRUE;
@@ -161,6 +175,115 @@
 
 /*******************************************************************************
  *
+ *  Key suggestion
+ */
+
+static LONG RegQueryStringValue(HKEY hKey, LPCTSTR lpSubKey, LPCTSTR lpValueName,
+	LPTSTR lpDest, DWORD dwDestLength)
+{
+	LONG lResult;
+	HKEY hSubKey = NULL;
+	DWORD cbData, dwType;
+
+	if (lpSubKey)
+	{
+		lResult = RegOpenKey(hKey, lpSubKey, &hSubKey);
+		if (lResult != ERROR_SUCCESS)
+			goto done;
+		hKey = hSubKey;
+	}
+
+	cbData = (dwDestLength - 1) * sizeof(*lpDest);
+	lResult = RegQueryValueEx(hKey, lpValueName, NULL, &dwType,
+		(LPBYTE) lpDest, &cbData);
+	if (lResult != ERROR_SUCCESS)
+		goto done;
+	if (dwType != REG_SZ)
+	{
+		lResult = -1;
+		goto done;
+	}
+
+	lpDest[cbData / sizeof(*lpDest)] = '\0';
+
+done:
+	if (lResult != ERROR_SUCCESS)
+		lpDest[0] = '\0';
+	if (hSubKey)
+		RegCloseKey(hSubKey);
+	return lResult;
+}
+
+static void SuggestKeys(HKEY hRootKey, LPCTSTR pszKeyPath, LPTSTR pszSuggestions,
+	size_t iSuggestionsLength)
+{
+	TCHAR szBuffer[256];
+	TCHAR szLastFound[256];
+	size_t i;
+	HKEY hOtherKey, hSubKey;
+	BOOL bFound;
+
+	memset(pszSuggestions, 0, iSuggestionsLength * sizeof(*pszSuggestions));
+	iSuggestionsLength--;
+
+	/* Are we a root key in HKEY_CLASSES_ROOT? */
+	if ((hRootKey == HKEY_CLASSES_ROOT) && pszKeyPath[0] && !_tcschr(pszKeyPath, '\\'))
+	{
+		do
+		{
+			bFound = FALSE;
+
+			/* Check default key */
+			if (RegQueryStringValue(hRootKey, pszKeyPath, NULL,
+				szBuffer, sizeof(szBuffer) / sizeof(szBuffer[0])) == ERROR_SUCCESS)
+			{
+				if (szBuffer[0] != '\0')
+				{
+					if (RegOpenKey(hRootKey, szBuffer, &hOtherKey) == ERROR_SUCCESS)
+					{
+						lstrcpyn(pszSuggestions, TEXT("HKCR\\"), iSuggestionsLength);
+						i = _tcslen(pszSuggestions);
+						pszSuggestions += i;
+	    				iSuggestionsLength -= i;
+
+						lstrcpyn(pszSuggestions, szBuffer, iSuggestionsLength);
+						i = _tcslen(pszSuggestions) + 1;
+						pszSuggestions += i;
+						iSuggestionsLength -= i;
+						RegCloseKey(hOtherKey);
+
+						bFound = TRUE;
+						_tcscpy(szLastFound, szBuffer);
+						pszKeyPath = szLastFound;
+					}
+				}
+			}
+		}
+		while(bFound);
+
+		/* Check CLSID key */
+		if (RegOpenKey(hRootKey, pszKeyPath, &hSubKey) == ERROR_SUCCESS)
+		{
+			if (RegQueryStringValue(hSubKey, TEXT("CLSID"), NULL,
+				szBuffer, sizeof(szBuffer) / sizeof(szBuffer[0])) == ERROR_SUCCESS)
+			{
+				lstrcpyn(pszSuggestions, TEXT("HKCR\\CLSID\\"), iSuggestionsLength);
+				i = _tcslen(pszSuggestions);
+				pszSuggestions += i;
+				iSuggestionsLength -= i;
+
+				lstrcpyn(pszSuggestions, szBuffer, iSuggestionsLength);
+				i = _tcslen(pszSuggestions) + 1;
+				pszSuggestions += i;
+				iSuggestionsLength -= i;
+			}
+			RegCloseKey(hSubKey);
+		}
+	}
+}
+
+/*******************************************************************************
+ *
  *  FUNCTION: ChildWndProc(HWND, unsigned, WORD, LONG)
  *
  *  PURPOSE:  Processes messages for the child windows.
@@ -407,8 +530,13 @@
         HMENU hContextMenu;
         TVITEM item;
         MENUITEMINFO mii;
+        TCHAR resource[256];
         TCHAR buffer[256];
         LPTSTR s;
+        LPCTSTR keyPath;
+        HKEY hRootKey;
+        int iLastPos;
+        WORD wID;
 
         pt = MAKEPOINTS(lParam);
         hti.pt.x = pt.x;
@@ -426,17 +554,58 @@
           item.hItem = hti.hItem;
           TreeView_GetItem(pChildWnd->hTreeWnd, &item);
 
+          /* Set the Expand/Collapse menu item appropriately */
           LoadString(hInst, (item.state & TVIS_EXPANDED) ? IDS_COLLAPSE : IDS_EXPAND, buffer, sizeof(buffer) / sizeof(buffer[0]));
-
           memset(&mii, 0, sizeof(mii));
           mii.cbSize = sizeof(mii);
           mii.fMask = MIIM_STRING | MIIM_STATE | MIIM_ID;
           mii.fState = (item.cChildren > 0) ? MFS_DEFAULT : MFS_GRAYED;
           mii.wID = (item.state & TVIS_EXPANDED) ? ID_TREE_COLLAPSEBRANCH : ID_TREE_EXPANDBRANCH;
-          s = buffer;
-          memcpy(&mii.dwTypeData, &s, sizeof(mii.dwTypeData)); /* arg MinGW */
+          mii.dwTypeData = (LPTSTR) buffer;
           SetMenuItemInfo(hContextMenu, 0, TRUE, &mii);
 
+          /* Remove any existing suggestions */
+          memset(&mii, 0, sizeof(mii));
+          mii.cbSize = sizeof(mii);
+          mii.fMask = MIIM_ID;
+          GetMenuItemInfo(hContextMenu, GetMenuItemCount(hContextMenu) - 1, TRUE, &mii);
+          if ((mii.wID >= ID_TREE_SUGGESTION_MIN) && (mii.wID <= ID_TREE_SUGGESTION_MAX))
+		  {
+            do
+			{
+              iLastPos = GetMenuItemCount(hContextMenu) - 1;
+              GetMenuItemInfo(hContextMenu, iLastPos, TRUE, &mii);
+              RemoveMenu(hContextMenu, iLastPos, MF_BYPOSITION);
+			}
+			while((mii.wID >= ID_TREE_SUGGESTION_MIN) && (mii.wID <= ID_TREE_SUGGESTION_MAX));
+		  }
+
+          /* Come up with suggestions */
+          keyPath = GetItemPath(pChildWnd->hTreeWnd, NULL, &hRootKey);
+          SuggestKeys(hRootKey, keyPath, Suggestions, sizeof(Suggestions) / sizeof(Suggestions[0]));
+          if (Suggestions[0])
+		  {
+            AppendMenu(hContextMenu, MF_SEPARATOR, 0, NULL);
+
+            LoadString(hInst, IDS_GOTO_SUGGESTED_KEY, resource, sizeof(resource) / sizeof(resource[0]));
+
+            s = Suggestions;
+            wID = ID_TREE_SUGGESTION_MIN;
+            while(*s && (wID <= ID_TREE_SUGGESTION_MAX))
+			{
+              _sntprintf(buffer, sizeof(buffer) / sizeof(buffer[0]), resource, s);
+
+              memset(&mii, 0, sizeof(mii));
+              mii.cbSize = sizeof(mii);
+              mii.fMask = MIIM_STRING | MIIM_ID;
+              mii.wID = wID++;
+              mii.dwTypeData = buffer;
+              InsertMenuItem(hContextMenu, GetMenuItemCount(hContextMenu), TRUE, &mii);
+
+              s += _tcslen(s) + 1;
+			}
+		  }
+
           TrackPopupMenu(hContextMenu, TPM_RIGHTBUTTON, pt.x, pt.y, 0, pChildWnd->hWnd, NULL);
         }
       }

Modified: trunk/reactos/subsys/system/regedit/main.h
--- trunk/reactos/subsys/system/regedit/main.h	2005-10-03 12:12:19 UTC (rev 18242)
+++ trunk/reactos/subsys/system/regedit/main.h	2005-10-03 12:39:50 UTC (rev 18243)
@@ -105,6 +105,7 @@
 extern HTREEITEM InsertNode(HWND hwndTV, HTREEITEM hItem, LPTSTR name);
 extern HWND StartKeyRename(HWND hwndTV);
 extern BOOL CreateNewKey(HWND hwndTV, HTREEITEM hItem);
+extern BOOL SelectNode(HWND hwndTV, LPCTSTR keyPath);
 
 /* edit.c */
 extern BOOL ModifyValue(HWND hwnd, HKEY hKey, LPCTSTR valueName, BOOL EditBin);

Modified: trunk/reactos/subsys/system/regedit/resource.h
--- trunk/reactos/subsys/system/regedit/resource.h	2005-10-03 12:12:19 UTC (rev 18242)
+++ trunk/reactos/subsys/system/regedit/resource.h	2005-10-03 12:39:50 UTC (rev 18243)
@@ -133,6 +133,8 @@
 #define IDS_QUERY_DELETE_KEY_ONE        32875
 #define IDS_QUERY_DELETE_KEY_MORE       32876
 #define IDS_QUERY_DELETE_KEY_CONFIRM    32877
+#define ID_TREE_SUGGESTION_MIN          32878
+#define ID_TREE_SUGGESTION_MAX          32887
 
 #define IDS_FLT_REGFILES		31001
 #define IDS_FLT_REGFILES_FLT		31002
@@ -161,6 +163,7 @@
 #define IDS_COLLAPSE                    31125
 #define IDS_NEW_KEY                     31126
 #define IDS_NEW_VALUE                   31127
+#define IDS_GOTO_SUGGESTED_KEY          31128
 
 
 #define IDD_EDIT_STRING			2000

Modified: trunk/reactos/subsys/system/regedit/treeview.c
--- trunk/reactos/subsys/system/regedit/treeview.c	2005-10-03 12:12:19 UTC (rev 18242)
+++ trunk/reactos/subsys/system/regedit/treeview.c	2005-10-03 12:39:50 UTC (rev 18243)
@@ -28,6 +28,8 @@
 #include <tchar.h>
 #include <process.h>
 #include <stdio.h>
+#include <string.h>
+#include <tchar.h>
 
 #include "main.h"
 
@@ -558,3 +560,69 @@
     }
     return hwndTV;
 }
+
+BOOL SelectNode(HWND hwndTV, LPCTSTR keyPath)
+{
+	HTREEITEM hRoot, hItem;
+	HTREEITEM hChildItem;
+	TCHAR szPathPart[128];
+	TCHAR szBuffer[128];
+	LPCTSTR s;
+	TVITEM tvi;
+
+	hRoot = TreeView_GetRoot(hwndTV);
+	hItem = hRoot;
+
+	while(keyPath[0])
+	{
+		s = _tcschr(keyPath, '\\');
+		lstrcpyn(szPathPart, keyPath, s ? s - keyPath + 1 : _tcslen(keyPath) + 1);
+
+		/* Special case for root to expand root key abbreviations */
+		if (hItem == hRoot)
+		{
+			if (!_tcscmp(szPathPart, TEXT("HKCR")))
+				_tcscpy(szPathPart, TEXT("HKEY_CLASSES_ROOT"));
+			else if (!_tcscmp(szPathPart, TEXT("HKCU")))
+				_tcscpy(szPathPart, TEXT("HKEY_CURRENT_USER"));
+			else if (!_tcscmp(szPathPart, TEXT("HKLM")))
+				_tcscpy(szPathPart, TEXT("HKEY_LOCAL_MACHINE"));
+			else if (!_tcscmp(szPathPart, TEXT("HKU")))
+				_tcscpy(szPathPart, TEXT("HKEY_USERS"));
+			else if (!_tcscmp(szPathPart, TEXT("HKCC")))
+				_tcscpy(szPathPart, TEXT("HKEY_CURRENT_CONFIG"));
+			else if (!_tcscmp(szPathPart, TEXT("HKDD")))
+				_tcscpy(szPathPart, TEXT("HKEY_DYN_DATA"));
+		}
+
+		for (hChildItem = TreeView_GetChild(hwndTV, hItem); hChildItem;
+			hChildItem = TreeView_GetNextSibling(hwndTV, hChildItem))
+		{
+			memset(&tvi, 0, sizeof(tvi));
+			tvi.hItem = hChildItem;
+			tvi.mask = TVIF_TEXT;
+			tvi.pszText = szBuffer;
+			tvi.cchTextMax = sizeof(szBuffer) / sizeof(szBuffer[0]);
+
+			TreeView_GetItem(hwndTV, &tvi);
+
+			if (!_tcscmp(szBuffer, szPathPart))
+				break;
+		}
+
+		if (!hChildItem)
+			return FALSE;
+
+		if (!TreeView_Expand(hwndTV, hChildItem, TVE_EXPAND))
+			return FALSE;
+
+		keyPath = s ? s + 1 : "";
+		hItem = hChildItem;
+	}
+
+	TreeView_SelectItem(hwndTV, hItem);
+	TreeView_EnsureVisible(hwndTV, hItem);
+
+	return TRUE;
+}
+