Revert "[SHELL32] SHChangeNotify: Use tree for CDirectoryList (#6784)" (#6800)
[reactos.git] / base / applications / regedit / treeview.c
index e1c258a..958aae6 100644 (file)
@@ -18,7 +18,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
-#include <regedit.h>
+#include "regedit.h"
 
 /* Global variables and constants  */
 /* Image_Open, Image_Closed, and Image_Root - integer variables for indexes of the images.  */
@@ -32,9 +32,14 @@ static LPWSTR pathBuffer;
 
 #define NUM_ICONS   3
 
+/* External resources in shell32.dll */
+#define IDI_SHELL_FOLDER             4
+#define IDI_SHELL_FOLDER_OPEN        5
+#define IDI_SHELL_MY_COMPUTER       16
+
 static BOOL get_item_path(HWND hwndTV, HTREEITEM hItem, HKEY* phKey, LPWSTR* pKeyPath, int* pPathLen, int* pMaxLen)
 {
-    TVITEM item;
+    TVITEMW item;
     size_t maxLen, len;
     LPWSTR newStr;
 
@@ -85,14 +90,25 @@ LPCWSTR 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;
+
+    if (!pathBuffer)
+    {
+        pathBuffer = HeapAlloc(GetProcessHeap(), 0, 1024);
+    }
+    if (!pathBuffer)
+    {
+        return NULL;
+    }
+
+    *pathBuffer = UNICODE_NULL;
+
     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))
+
+    if (!hItem)
+    {
+        hItem = TreeView_GetSelection(hwndTV);
+    }
+    if (maxLen == -1 || !hItem || !get_item_path(hwndTV, hItem, phRootKey, &pathBuffer, &pathLen, &maxLen))
     {
         return NULL;
     }
@@ -109,8 +125,8 @@ BOOL DeleteNode(HWND hwndTV, HTREEITEM hItem)
 /* Add an entry to the tree. Only give hKey for root nodes (HKEY_ constants) */
 static HTREEITEM AddEntryToTree(HWND hwndTV, HTREEITEM hParent, LPWSTR label, HKEY hKey, DWORD dwChildren)
 {
-    TVITEM tvi;
-    TVINSERTSTRUCT tvins;
+    TVITEMW tvi;
+    TVINSERTSTRUCTW tvins;
 
     if (hKey)
     {
@@ -140,7 +156,7 @@ BOOL RefreshTreeItem(HWND hwndTV, HTREEITEM hItem)
     LPCWSTR KeyPath;
     DWORD dwCount, dwIndex, dwMaxSubKeyLen;
     LPWSTR Name = NULL;
-    TVITEM tvItem;
+    TVITEMW tvItem;
     LPWSTR pszNodes = NULL;
     BOOL bSuccess = FALSE;
     LPWSTR s;
@@ -332,7 +348,7 @@ HTREEITEM InsertNode(HWND hwndTV, HTREEITEM hItem, LPWSTR name)
 {
     WCHAR buf[MAX_NEW_KEY_LEN];
     HTREEITEM hNewItem = 0;
-    TVITEMEX item;
+    TVITEMEXW item;
 
     /* Default to the current selection */
     if (!hItem)
@@ -348,7 +364,7 @@ HTREEITEM InsertNode(HWND hwndTV, HTREEITEM hItem, LPWSTR name)
     if (!TreeView_GetItem(hwndTV, &item))
         return FALSE;
 
-    if ((item.state & TVIS_EXPANDEDONCE) && (item.cChildren > 0))
+    if (item.state & TVIS_EXPANDEDONCE)
     {
         hNewItem = AddEntryToTree(hwndTV, hItem, name, 0, 0);
         SendMessageW(hwndTV, TVM_SORTCHILDREN, 0, (LPARAM) hItem);
@@ -370,7 +386,7 @@ HTREEITEM InsertNode(HWND hwndTV, HTREEITEM hItem, LPWSTR name)
             item.mask = TVIF_HANDLE | TVIF_TEXT;
             item.hItem = hNewItem;
             item.pszText = buf;
-            item.cchTextMax = COUNT_OF(buf);
+            item.cchTextMax = ARRAY_SIZE(buf);
             if (!TreeView_GetItem(hwndTV, &item)) continue;
             if (wcscmp(name, item.pszText) == 0) break;
         }
@@ -390,8 +406,8 @@ HWND StartKeyRename(HWND hwndTV)
 
 static BOOL InitTreeViewItems(HWND hwndTV, LPWSTR pHostName)
 {
-    TVITEM tvi;
-    TVINSERTSTRUCT tvins;
+    TVITEMW tvi;
+    TVINSERTSTRUCTW tvins;
     HTREEITEM hRoot;
 
     tvi.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_CHILDREN | TVIF_PARAM;
@@ -439,48 +455,45 @@ static BOOL InitTreeViewImageLists(HWND hwndTV)
 {
     HIMAGELIST himl;  /* handle to image list  */
     HICON hico;       /* handle to icon  */
+    INT cx = GetSystemMetrics(SM_CXSMICON);
+    INT cy = GetSystemMetrics(SM_CYSMICON);
+    HMODULE hShell32 = GetModuleHandleW(L"shell32.dll");
 
     /* Create the image list.  */
-    if ((himl = ImageList_Create(GetSystemMetrics(SM_CXSMICON),
-                                 GetSystemMetrics(SM_CYSMICON),
-                                 ILC_MASK | ILC_COLOR32,
-                                 0,
-                                 NUM_ICONS)) == NULL)
-    {
+    if ((himl = ImageList_Create(cx, cy, ILC_MASK | ILC_COLOR32, 0, NUM_ICONS)) == NULL)
         return FALSE;
-    }
 
     /* Add the open file, closed file, and document bitmaps.  */
-    hico = LoadImageW(hInst,
-                      MAKEINTRESOURCEW(IDI_OPEN_FILE),
+    hico = LoadImageW(hShell32,
+                      MAKEINTRESOURCEW(IDI_SHELL_FOLDER_OPEN),
                       IMAGE_ICON,
-                      GetSystemMetrics(SM_CXSMICON),
-                      GetSystemMetrics(SM_CYSMICON),
-                      0);
+                      cx,
+                      cy,
+                      LR_DEFAULTCOLOR);
     if (hico)
     {
         Image_Open = ImageList_AddIcon(himl, hico);
         DestroyIcon(hico);
     }
 
-    hico = LoadImageW(hInst,
-                      MAKEINTRESOURCEW(IDI_CLOSED_FILE),
+    hico = LoadImageW(hShell32,
+                      MAKEINTRESOURCEW(IDI_SHELL_FOLDER),
                       IMAGE_ICON,
-                      GetSystemMetrics(SM_CXSMICON),
-                      GetSystemMetrics(SM_CYSMICON),
-                      0);
+                      cx,
+                      cy,
+                      LR_DEFAULTCOLOR);
     if (hico)
     {
         Image_Closed = ImageList_AddIcon(himl, hico);
         DestroyIcon(hico);
     }
 
-    hico = LoadImageW(hInst,
-                      MAKEINTRESOURCEW(IDI_ROOT),
+    hico = LoadImageW(hShell32,
+                      MAKEINTRESOURCEW(IDI_SHELL_MY_COMPUTER),
                       IMAGE_ICON,
-                      GetSystemMetrics(SM_CXSMICON),
-                      GetSystemMetrics(SM_CYSMICON),
-                      0);
+                      cx,
+                      cy,
+                      LR_DEFAULTCOLOR);
     if (hico)
     {
         Image_Root = ImageList_AddIcon(himl, hico);
@@ -586,14 +599,14 @@ BOOL CreateNewKey(HWND hwndTV, HTREEITEM hItem)
     else if (RegOpenKeyW(hRootKey, pszKeyPath, &hKey) != ERROR_SUCCESS)
         goto done;
 
-    if (LoadStringW(hInst, IDS_NEW_KEY, szNewKeyFormat, COUNT_OF(szNewKeyFormat)) <= 0)
+    if (LoadStringW(hInst, IDS_NEW_KEY, szNewKeyFormat, ARRAY_SIZE(szNewKeyFormat)) <= 0)
         goto done;
 
     /* Need to create a new key with a unique name */
     do
     {
         wsprintf(szNewKey, szNewKeyFormat, iIndex++);
-        nResult = RegCreateKeyExW(hKey, szNewKey, 0, NULL, 0, KEY_WRITE, NULL, &hNewKey, &dwDisposition);
+        nResult = RegCreateKeyExW(hKey, szNewKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hNewKey, &dwDisposition);
         if (hNewKey && dwDisposition == REG_OPENED_EXISTING_KEY)
         {
             RegCloseKey(hNewKey);
@@ -625,6 +638,111 @@ done:
     return bSuccess;
 }
 
+BOOL TreeWndNotifyProc(HWND hWnd, WPARAM wParam, LPARAM lParam, BOOL *Result)
+{
+    UNREFERENCED_PARAMETER(wParam);
+    *Result = TRUE;
+
+    switch (((LPNMHDR)lParam)->code)
+    {
+        case TVN_ITEMEXPANDING:
+            *Result = !OnTreeExpanding(g_pChildWnd->hTreeWnd, (NMTREEVIEW*)lParam);
+            return TRUE;
+        case TVN_SELCHANGED:
+        {
+            NMTREEVIEW* pnmtv = (NMTREEVIEW*)lParam;
+            /* Get the parent of the current item */
+            HTREEITEM hParentItem = TreeView_GetParent(g_pChildWnd->hTreeWnd, pnmtv->itemNew.hItem);
+
+            UpdateAddress(pnmtv->itemNew.hItem, NULL, NULL, TRUE);
+
+            /* Disable the Permissions and new key menu items for 'My Computer' */
+            EnableMenuItem(hMenuFrame, ID_EDIT_PERMISSIONS, MF_BYCOMMAND | (hParentItem ? MF_ENABLED : MF_GRAYED));
+            EnableMenuItem(hMenuFrame, ID_EDIT_NEW_KEY, MF_BYCOMMAND | (hParentItem ? MF_ENABLED : MF_GRAYED));
+
+            /*
+             * Disable Delete/Rename menu options for 'My Computer' (first item so doesn't have any parent)
+             * and HKEY_* keys (their parent is 'My Computer' and the previous remark applies).
+             */
+            if (!hParentItem || !TreeView_GetParent(g_pChildWnd->hTreeWnd, hParentItem))
+            {
+                EnableMenuItem(hMenuFrame , ID_EDIT_DELETE, MF_BYCOMMAND | MF_GRAYED);
+                EnableMenuItem(hMenuFrame , ID_EDIT_RENAME, MF_BYCOMMAND | MF_GRAYED);
+                EnableMenuItem(hPopupMenus, ID_TREE_DELETE, MF_BYCOMMAND | MF_GRAYED);
+                EnableMenuItem(hPopupMenus, ID_TREE_RENAME, MF_BYCOMMAND | MF_GRAYED);
+            }
+            else
+            {
+                EnableMenuItem(hMenuFrame , ID_EDIT_DELETE, MF_BYCOMMAND | MF_ENABLED);
+                EnableMenuItem(hMenuFrame , ID_EDIT_RENAME, MF_BYCOMMAND | MF_ENABLED);
+                EnableMenuItem(hPopupMenus, ID_TREE_DELETE, MF_BYCOMMAND | MF_ENABLED);
+                EnableMenuItem(hPopupMenus, ID_TREE_RENAME, MF_BYCOMMAND | MF_ENABLED);
+            }
+
+            return TRUE;
+        }
+        case NM_SETFOCUS:
+            g_pChildWnd->nFocusPanel = 0;
+            break;
+        case TVN_BEGINLABELEDIT:
+        {
+            LPNMTVDISPINFO ptvdi = (LPNMTVDISPINFO)lParam;
+            /* cancel label edit for rootkeys */
+            if (!TreeView_GetParent(g_pChildWnd->hTreeWnd, ptvdi->item.hItem) ||
+                !TreeView_GetParent(g_pChildWnd->hTreeWnd, TreeView_GetParent(g_pChildWnd->hTreeWnd, ptvdi->item.hItem)))
+            {
+                *Result = TRUE;
+            }
+            else
+            {
+                *Result = FALSE;
+            }
+            return TRUE;
+        }
+        case TVN_ENDLABELEDIT:
+        {
+            LPCWSTR keyPath;
+            HKEY hRootKey;
+            HKEY hKey = NULL;
+            LPNMTVDISPINFO ptvdi = (LPNMTVDISPINFO)lParam;
+            LONG nRenResult;
+            LONG lResult = TRUE;
+            WCHAR szBuffer[MAX_PATH];
+            WCHAR Caption[128];
+
+            if (ptvdi->item.pszText)
+            {
+                keyPath = GetItemPath(g_pChildWnd->hTreeWnd, TreeView_GetParent(g_pChildWnd->hTreeWnd, ptvdi->item.hItem), &hRootKey);
+                if (wcslen(keyPath))
+                    _snwprintf(szBuffer, ARRAY_SIZE(szBuffer), L"%s\\%s", keyPath, ptvdi->item.pszText);
+                else
+                    _snwprintf(szBuffer, ARRAY_SIZE(szBuffer), L"%s", ptvdi->item.pszText);
+                keyPath = GetItemPath(g_pChildWnd->hTreeWnd, ptvdi->item.hItem, &hRootKey);
+                if (RegOpenKeyExW(hRootKey, szBuffer, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
+                {
+                    lResult = FALSE;
+                    RegCloseKey(hKey);
+                    TreeView_EditLabel(g_pChildWnd->hTreeWnd, ptvdi->item.hItem);
+                }
+                else
+                {
+                    nRenResult = RenameKey(hRootKey, keyPath, ptvdi->item.pszText);
+                    if (nRenResult != ERROR_SUCCESS)
+                    {
+                        LoadStringW(hInst, IDS_ERROR, Caption, ARRAY_SIZE(Caption));
+                        ErrorMessageBox(hWnd, Caption, nRenResult);
+                        lResult = FALSE;
+                    }
+                    else
+                        UpdateAddress(ptvdi->item.hItem, hRootKey, szBuffer, FALSE);
+                }
+                *Result = lResult;
+            }
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
 
 /*
  * CreateTreeView - creates a tree view control.
@@ -639,9 +757,11 @@ HWND CreateTreeView(HWND hwndParent, LPWSTR pHostName, HMENU id)
     /* Get the dimensions of the parent window's client area, and create the tree view control.  */
     GetClientRect(hwndParent, &rcClient);
     hwndTV = CreateWindowExW(WS_EX_CLIENTEDGE, WC_TREEVIEW, NULL,
-                            WS_VISIBLE | WS_CHILD | WS_TABSTOP | TVS_HASLINES | TVS_HASBUTTONS | TVS_LINESATROOT | TVS_EDITLABELS,
+                            WS_VISIBLE | WS_CHILD | WS_TABSTOP | TVS_HASLINES | TVS_HASBUTTONS | TVS_LINESATROOT | TVS_EDITLABELS | TVS_SHOWSELALWAYS,
                             0, 0, rcClient.right, rcClient.bottom,
                             hwndParent, id, hInst, NULL);
+    if (!hwndTV) return NULL;
+
     /* Initialize the image list, and add items to the control.  */
     if (!InitTreeViewImageLists(hwndTV) || !InitTreeViewItems(hwndTV, pHostName))
     {
@@ -651,10 +771,15 @@ HWND CreateTreeView(HWND hwndParent, LPWSTR pHostName, HMENU id)
     return hwndTV;
 }
 
-void DestroyTreeView()
+void DestroyTreeView(HWND hwndTV)
 {
-    if (pathBuffer)
-        HeapFree(GetProcessHeap(), 0, pathBuffer);
+    HIMAGELIST himl;
+
+    if (pathBuffer) HeapFree(GetProcessHeap(), 0, pathBuffer);
+
+    /* Destroy the image list associated with the tree view control */
+    himl = TreeView_GetImageList(hwndTV, TVSIL_NORMAL);
+    if (himl) ImageList_Destroy(himl);
 }
 
 BOOL SelectNode(HWND hwndTV, LPCWSTR keyPath)
@@ -664,11 +789,11 @@ BOOL SelectNode(HWND hwndTV, LPCWSTR keyPath)
     WCHAR szPathPart[128];
     WCHAR szBuffer[128];
     LPCWSTR s;
-    TVITEM tvi;
+    TVITEMW tvi;
 
     /* Load "My Computer" string... */
-    LoadStringW(hInst, IDS_MY_COMPUTER, szBuffer, COUNT_OF(szBuffer));
-    wcscat(szBuffer, L"\\");
+    LoadStringW(hInst, IDS_MY_COMPUTER, szBuffer, ARRAY_SIZE(szBuffer));
+    StringCbCatW(szBuffer, sizeof(szBuffer), L"\\");
 
     /* ... and remove it from the key path */
     if (!_wcsnicmp(keyPath, szBuffer, wcslen(szBuffer)))
@@ -682,24 +807,33 @@ BOOL SelectNode(HWND hwndTV, LPCWSTR keyPath)
 
     while(keyPath[0])
     {
+        size_t copyLength;
         s = wcschr(keyPath, L'\\');
-        wcsncpy(szPathPart, keyPath, s ? s - keyPath + 1 : wcslen(keyPath) + 1);
+        if (s != NULL)
+        {
+            copyLength = (s - keyPath) * sizeof(WCHAR);
+        }
+        else
+        {
+            copyLength = sizeof(szPathPart);
+        }
+        StringCbCopyNW(szPathPart, sizeof(szPathPart), keyPath, copyLength);
 
         /* Special case for root to expand root key abbreviations */
         if (hItem == hRoot)
         {
-            if (!wcsicmp(szPathPart, L"HKCR"))
-                wcscpy(szPathPart, L"HKEY_CLASSES_ROOT");
-            else if (!wcsicmp(szPathPart, L"HKCU"))
-                wcscpy(szPathPart, L"HKEY_CURRENT_USER");
-            else if (!wcsicmp(szPathPart, L"HKLM"))
-                wcscpy(szPathPart, L"HKEY_LOCAL_MACHINE");
-            else if (!wcsicmp(szPathPart, L"HKU"))
-                wcscpy(szPathPart, L"HKEY_USERS");
-            else if (!wcsicmp(szPathPart, L"HKCC"))
-                wcscpy(szPathPart, L"HKEY_CURRENT_CONFIG");
-            else if (!wcsicmp(szPathPart, L"HKDD"))
-                wcscpy(szPathPart, L"HKEY_DYN_DATA");
+            if (!_wcsicmp(szPathPart, L"HKCR"))
+                StringCbCopyW(szPathPart, sizeof(szPathPart), L"HKEY_CLASSES_ROOT");
+            else if (!_wcsicmp(szPathPart, L"HKCU"))
+                StringCbCopyW(szPathPart, sizeof(szPathPart), L"HKEY_CURRENT_USER");
+            else if (!_wcsicmp(szPathPart, L"HKLM"))
+                StringCbCopyW(szPathPart, sizeof(szPathPart), L"HKEY_LOCAL_MACHINE");
+            else if (!_wcsicmp(szPathPart, L"HKU"))
+                StringCbCopyW(szPathPart, sizeof(szPathPart), L"HKEY_USERS");
+            else if (!_wcsicmp(szPathPart, L"HKCC"))
+                StringCbCopyW(szPathPart, sizeof(szPathPart), L"HKEY_CURRENT_CONFIG");
+            else if (!_wcsicmp(szPathPart, L"HKDD"))
+                StringCbCopyW(szPathPart, sizeof(szPathPart), L"HKEY_DYN_DATA");
         }
 
         for (hChildItem = TreeView_GetChild(hwndTV, hItem); hChildItem;
@@ -709,11 +843,11 @@ BOOL SelectNode(HWND hwndTV, LPCWSTR keyPath)
             tvi.hItem = hChildItem;
             tvi.mask = TVIF_TEXT | TVIF_CHILDREN;
             tvi.pszText = szBuffer;
-            tvi.cchTextMax = COUNT_OF(szBuffer);
+            tvi.cchTextMax = ARRAY_SIZE(szBuffer);
 
             (void)TreeView_GetItem(hwndTV, &tvi);
 
-            if (!wcsicmp(szBuffer, szPathPart))
+            if (!_wcsicmp(szBuffer, szPathPart))
                 break;
         }