- Get autochk, calc, cmd, devmgr, expand, format, gettype, hostname, lsass, msconfig...
[reactos.git] / reactos / subsys / system / regedit / childwnd.c
index f80f86a..956b917 100644 (file)
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#define WIN32_LEAN_AND_MEAN     /* Exclude rarely-used stuff from Windows headers */
-#include <windows.h>
-#include <commctrl.h>
-#include <tchar.h>
-#include <stdio.h>
-
-#include "main.h"
+#include <regedit.h>
 
 ChildWnd* g_pChildWnd;
 HBITMAP SizingPattern = 0;
 HBRUSH  SizingBrush = 0;
+static TCHAR Suggestions[256];
 
 /*******************************************************************************
  * Local module support methods
@@ -41,6 +36,7 @@ static LPCTSTR get_root_key_name(HKEY hRootKey)
     if (hRootKey == HKEY_LOCAL_MACHINE) return _T("HKEY_LOCAL_MACHINE");
     if (hRootKey == HKEY_USERS) return _T("HKEY_USERS");
     if (hRootKey == HKEY_CURRENT_CONFIG) return _T("HKEY_CURRENT_CONFIG");
+    if (hRootKey == HKEY_DYN_DATA) return _T("HKEY_DYN_DATA");
     return _T("UKNOWN HKEY, PLEASE REPORT");
 }
 
@@ -102,7 +98,12 @@ static void OnPaint(HWND hWnd)
 static BOOL _CmdWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
     ChildWnd* pChildWnd = g_pChildWnd;
-    switch (LOWORD(wParam)) {
+    HTREEITEM hSelection;
+    HKEY hRootKey;
+    LPCTSTR keyPath, s;
+    WORD wID = LOWORD(wParam);
+
+    switch (wID) {
         /* Parse the menu selections: */
     case ID_REGISTRY_EXIT:
         DestroyWindow(hWnd);
@@ -110,16 +111,145 @@ static BOOL _CmdWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
     case ID_VIEW_REFRESH:
         /* TODO */
         break;
+    case ID_TREE_EXPANDBRANCH:
+        TreeView_Expand(pChildWnd->hTreeWnd, TreeView_GetSelection(pChildWnd->hTreeWnd), TVE_EXPAND);
+        break;
+    case ID_TREE_COLLAPSEBRANCH:
+        TreeView_Expand(pChildWnd->hTreeWnd, TreeView_GetSelection(pChildWnd->hTreeWnd), TVE_COLLAPSE);
+        break;
+    case ID_TREE_RENAME:
+        SetFocus(pChildWnd->hTreeWnd);
+        TreeView_EditLabel(pChildWnd->hTreeWnd, TreeView_GetSelection(pChildWnd->hTreeWnd));
+        break;
+    case ID_TREE_DELETE:
+        hSelection = TreeView_GetSelection(pChildWnd->hTreeWnd);
+        keyPath = GetItemPath(pChildWnd->hTreeWnd, hSelection, &hRootKey);
+
+        if (keyPath == 0 || *keyPath == 0)
+        {
+           MessageBeep(MB_ICONHAND); 
+        } else 
+        if (DeleteKey(hWnd, hRootKey, keyPath))
+          DeleteNode(g_pChildWnd->hTreeWnd, 0);
+        break;
+       case ID_TREE_EXPORT:
+        ExportRegistryFile(pChildWnd->hTreeWnd);
+        break;
+       case ID_EDIT_FIND:
+        FindDialog(hWnd);
+        break;
+    case ID_EDIT_COPYKEYNAME:
+        hSelection = TreeView_GetSelection(pChildWnd->hTreeWnd);
+        keyPath = GetItemPath(pChildWnd->hTreeWnd, hSelection, &hRootKey);
+        CopyKeyName(hWnd, hRootKey, keyPath);
+        break;
+    case ID_EDIT_NEW_KEY:
+        CreateNewKey(pChildWnd->hTreeWnd, TreeView_GetSelection(pChildWnd->hTreeWnd));
+        break;
+    case ID_EDIT_NEW_STRINGVALUE:
+    case ID_EDIT_NEW_BINARYVALUE:
+    case ID_EDIT_NEW_DWORDVALUE:
+        SendMessage(hFrameWnd, WM_COMMAND, wParam, lParam);
+        break;
     case ID_SWITCH_PANELS:
         pChildWnd->nFocusPanel = !pChildWnd->nFocusPanel;
         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;
 }
 
+/*******************************************************************************
+ *
+ *  Key suggestion
+ */
+
+#define MIN(a,b)       ((a < b) ? (a) : (b))
+
+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)
+                       {
+                               /* Sanity check this key; it cannot be empty, nor can it be a
+                                * loop back */
+                               if ((szBuffer[0] != '\0') && _tcsicmp(szBuffer, pszKeyPath))
+                               {
+                                       if (RegOpenKey(hRootKey, szBuffer, &hOtherKey) == ERROR_SUCCESS)
+                                       {
+                                               lstrcpyn(pszSuggestions, TEXT("HKCR\\"), iSuggestionsLength);
+                                               i = _tcslen(pszSuggestions);
+                                               pszSuggestions += i;
+                                       iSuggestionsLength -= i;
+
+                                               lstrcpyn(pszSuggestions, szBuffer, iSuggestionsLength);
+                                               i = MIN(_tcslen(pszSuggestions) + 1, iSuggestionsLength);
+                                               pszSuggestions += i;
+                                               iSuggestionsLength -= i;
+                                               RegCloseKey(hOtherKey);
+
+                                               bFound = TRUE;
+                                               _tcscpy(szLastFound, szBuffer);
+                                               pszKeyPath = szLastFound;
+                                       }
+                               }
+                       }
+               }
+               while(bFound && (iSuggestionsLength > 0));
+
+               /* 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 = MIN(_tcslen(pszSuggestions) + 1, iSuggestionsLength);
+                               pszSuggestions += i;
+                               iSuggestionsLength -= i;
+                       }
+                       RegCloseKey(hSubKey);
+               }
+       }
+}
+
 /*******************************************************************************
  *
  *  FUNCTION: ChildWndProc(HWND, unsigned, WORD, LONG)
@@ -131,8 +261,7 @@ static BOOL _CmdWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
  *  WM_DESTROY  - post a quit message and return
  *
  */
-LRESULT CALLBACK
-ChildWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+LRESULT CALLBACK ChildWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
     static short last_split;
     BOOL Result;
@@ -145,13 +274,14 @@ ChildWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
         /* load "My Computer" string */
         LoadString(hInst, IDS_MY_COMPUTER, buffer, sizeof(buffer)/sizeof(TCHAR));
 
-       g_pChildWnd = pChildWnd = HeapAlloc(GetProcessHeap(), 0, sizeof(ChildWnd));
+           g_pChildWnd = pChildWnd = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ChildWnd));
+               
         if (!pChildWnd) return 0;
         _tcsncpy(pChildWnd->szPath, buffer, MAX_PATH);
         pChildWnd->nSplitPos = 250;
         pChildWnd->hWnd = hWnd;
-        pChildWnd->hTreeWnd = CreateTreeView(hWnd, pChildWnd->szPath, TREE_WINDOW);
-        pChildWnd->hListWnd = CreateListView(hWnd, LIST_WINDOW/*, pChildWnd->szPath*/);
+        pChildWnd->hTreeWnd = CreateTreeView(hWnd, pChildWnd->szPath, (HMENU) TREE_WINDOW);
+        pChildWnd->hListWnd = CreateListView(hWnd, (HMENU) LIST_WINDOW/*, pChildWnd->szPath*/);
         SetFocus(pChildWnd->hTreeWnd);
         break;
     }
@@ -175,6 +305,9 @@ ChildWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
         }
         goto def;
     case WM_DESTROY:
+               DestroyTreeView();
+               DestroyListView(pChildWnd->hListWnd);
+               DestroyMainMenu();
         HeapFree(GetProcessHeap(), 0, pChildWnd);
         pChildWnd = NULL;
         PostQuitMessage(0);
@@ -198,7 +331,7 @@ ChildWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
             POINTS pt;
             pt = MAKEPOINTS(lParam);
             GetClientRect(hWnd, &rt);
-            pt.x = min(max(pt.x, SPLIT_MIN), rt.right - SPLIT_MIN);
+            pt.x = (SHORT) min(max(pt.x, SPLIT_MIN), rt.right - SPLIT_MIN);
             draw_splitbar(hWnd, last_split);
             last_split = -1;
             pChildWnd->nSplitPos = pt.x;
@@ -243,7 +376,7 @@ ChildWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
 
             pt = MAKEPOINTS(lParam);
             GetClientRect(hWnd, &rt);
-            pt.x = min(max(pt.x, SPLIT_MIN), rt.right - SPLIT_MIN);
+            pt.x = (SHORT) min(max(pt.x, SPLIT_MIN), rt.right - SPLIT_MIN);
             if(last_split != pt.x)
             {
               rt.left = last_split-SPLIT_WIDTH/2;
@@ -289,6 +422,20 @@ ChildWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
                            _stprintf(fullPath, _T("%s\\%s"), rootName, keyPath);
                            SendMessage(hStatusBar, SB_SETTEXT, 0, (LPARAM)fullPath);
                            HeapFree(GetProcessHeap(), 0, fullPath);
+
+                           {
+                               HKEY hKey;
+                               TCHAR szBuffer[MAX_PATH];                       
+                               _sntprintf(szBuffer, sizeof(szBuffer) / sizeof(szBuffer[0]), _T("My Computer\\%s\\%s"), rootName, keyPath);
+
+                               if (RegOpenKey(HKEY_CURRENT_USER,
+                                       _T("Software\\Microsoft\\Windows\\CurrentVersion\\Applets\\Regedit"),
+                                   &hKey) == ERROR_SUCCESS)
+                               {
+                                   RegSetValueEx(hKey, _T("LastKey"), 0, REG_SZ, (LPBYTE) szBuffer, _tcslen(szBuffer) * sizeof(szBuffer[0]));
+                                   RegCloseKey(hKey);
+                               }
+                           }
                        }
                    }
                 }
@@ -296,6 +443,21 @@ ChildWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
            case NM_SETFOCUS:
                pChildWnd->nFocusPanel = 0;
                break;
+            case TVN_ENDLABELEDIT:
+                {
+                  LPCTSTR keyPath;
+                  HKEY hRootKey;
+                  LPNMTVDISPINFO ptvdi;
+                  LONG lResult;
+
+                  ptvdi = (LPNMTVDISPINFO) lParam;
+                  if (ptvdi->item.pszText)
+                  {
+                    keyPath = GetItemPath(pChildWnd->hTreeWnd, ptvdi->item.hItem, &hRootKey);
+                    lResult = RegRenameKey(hRootKey, keyPath, ptvdi->item.pszText);
+                    return lResult == ERROR_SUCCESS;
+                 }
+                }
             default:
                 return 0;
             }
@@ -312,6 +474,7 @@ ChildWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
                        {
                                goto def;
                        }
+                       return Result;
                        break;
                }
             }
@@ -347,6 +510,91 @@ ChildWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
           TrackPopupMenu(mnu, TPM_RIGHTBUTTON, pt.x, pt.y, 0, hFrameWnd, NULL);
         }
       }
+      else if ((HWND)wParam == pChildWnd->hTreeWnd)
+      {
+        TVHITTESTINFO hti;
+        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;
+        hti.pt.y = pt.y;
+        ScreenToClient(pChildWnd->hTreeWnd, &hti.pt);
+        TreeView_HitTest(pChildWnd->hTreeWnd, &hti);
+
+        if ((hti.flags & TVHT_ONITEM) != 0)
+        {
+          hContextMenu = GetSubMenu(hPopupMenus, PM_TREECONTEXT);
+          TreeView_SelectItem(pChildWnd->hTreeWnd, hti.hItem);
+
+          memset(&item, 0, sizeof(item));
+          item.mask = TVIF_STATE | TVIF_CHILDREN;
+          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;
+          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);
+        }
+      }
       break;
     }