Bletch <npwoods@mess.org>:
authorGé van Geldorp <ge@gse.nl>
Thu, 22 Sep 2005 20:54:20 +0000 (20:54 +0000)
committerGé van Geldorp <ge@gse.nl>
Thu, 22 Sep 2005 20:54:20 +0000 (20:54 +0000)
- Implements key and value renaming
- Implements key deleting
- Implements New Key/String/Binary/DWORD option

svn path=/trunk/; revision=17988

reactos/subsys/system/regedit/En.rc
reactos/subsys/system/regedit/childwnd.c
reactos/subsys/system/regedit/framewnd.c
reactos/subsys/system/regedit/listview.c
reactos/subsys/system/regedit/main.c
reactos/subsys/system/regedit/main.h
reactos/subsys/system/regedit/regproc.c
reactos/subsys/system/regedit/regproc.h
reactos/subsys/system/regedit/resource.h
reactos/subsys/system/regedit/security.c
reactos/subsys/system/regedit/treeview.c

index b7f11f2..0bed3d6 100644 (file)
@@ -277,6 +277,9 @@ BEGIN
     IDS_UNSUPPORTED_TYPE    "Can't edit keys of this type (%ld)"
     IDS_TOO_BIG_VALUE       "Value is too big (%ld)"
     IDS_MULTI_SZ_EMPTY_STRING "Data of type REG_MULTI_SZ cannot contain empty strings.\nThe empty strings have been removed from the list."
+    IDS_QUERY_DELETE_KEY_ONE    "Are you sure you want to delete this key?"
+    IDS_QUERY_DELETE_KEY_MORE   "Are you sure you want to delete these keys?"
+    IDS_QUERY_DELETE_KEY_CONFIRM "Confirm Key Delete"
     IDS_QUERY_DELETE_ONE    "Are you sure you want to delete this value?"
     IDS_QUERY_DELETE_MORE   "Are you sure you want to delete these values?"
     IDS_QUERY_DELETE_CONFIRM "Confirm Value Delete"
@@ -284,6 +287,8 @@ BEGIN
     IDS_ERR_DELETEVALUE     "Unable to delete all specified values!"
     IDS_ERR_RENVAL_CAPTION  "Error Renaming Value"
     IDS_ERR_RENVAL_TOEMPTY  "Cannot rename %s. The specified value name is empty. Try another name and try again."
+    IDS_NEW_KEY             "New Key #%d"
+    IDS_NEW_VALUE           "New Value #%d"
 END
 
 STRINGTABLE DISCARDABLE
index 915deb8..bc95878 100644 (file)
@@ -25,6 +25,7 @@
 #include <stdio.h>
 
 #include "main.h"
+#include "regproc.h"
 
 ChildWnd* g_pChildWnd;
 HBITMAP SizingPattern = 0;
@@ -102,6 +103,12 @@ static void OnPaint(HWND hWnd)
 static BOOL _CmdWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
     ChildWnd* pChildWnd = g_pChildWnd;
+    HTREEITEM hSelection;
+    HKEY hRootKey;
+    LPCTSTR keyPath;
+    TCHAR szConfirmTitle[256];
+    TCHAR szConfirmText[256];
+
     switch (LOWORD(wParam)) {
         /* Parse the menu selections: */
     case ID_REGISTRY_EXIT:
@@ -120,6 +127,27 @@ static BOOL _CmdWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
         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);
+
+        LoadString(hInst, IDS_QUERY_DELETE_KEY_CONFIRM, szConfirmTitle, sizeof(szConfirmTitle) / sizeof(szConfirmTitle[0]));
+        LoadString(hInst, IDS_QUERY_DELETE_KEY_ONE, szConfirmText, sizeof(szConfirmText) / sizeof(szConfirmText[0]));
+
+        if (MessageBox(pChildWnd->hWnd, szConfirmText, szConfirmTitle, MB_YESNO) == IDYES)
+        {
+            if (RegDeleteKeyRecursive(hRootKey, keyPath) == ERROR_SUCCESS)
+                TreeView_DeleteItem(pChildWnd->hTreeWnd, hSelection);
+        }
+        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);
@@ -208,7 +236,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;
@@ -253,7 +281,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;
@@ -308,11 +336,19 @@ ChildWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
                break;
             case TVN_ENDLABELEDIT:
                 {
-                  TCHAR msg[32];
-                  _stprintf(msg, _T("rename to %s"), ((NMTVDISPINFO *) lParam)->item.pszText);
-                  MessageBox(pChildWnd->hTreeWnd, msg, NULL, MB_OK);
+                  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;
+                 }
                 }
-                break;
             default:
                 return 0;
             }
@@ -329,6 +365,7 @@ ChildWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
                        {
                                goto def;
                        }
+                       return Result;
                        break;
                }
             }
index 0718b6a..713446f 100644 (file)
@@ -466,6 +466,69 @@ BOOL RefreshView(HWND hWnd)
     return TRUE;
 }
 
+static BOOL CreateNewValue(HKEY hRootKey, LPCTSTR pszKeyPath, DWORD dwType)
+{
+    TCHAR szNewValueFormat[128];
+    TCHAR szNewValue[128];
+    int iIndex = 1;
+    BYTE data[128];
+    DWORD dwExistingType, cbData;
+    LONG lResult;
+    HKEY hKey;
+    LVFINDINFO lvfi;
+
+    if (RegOpenKey(hRootKey, pszKeyPath, &hKey) != ERROR_SUCCESS)
+        return FALSE;    
+
+    LoadString(hInst, IDS_NEW_VALUE, szNewValueFormat, sizeof(szNewValueFormat)
+        / sizeof(szNewValueFormat[0]));
+
+    do
+    {
+        _sntprintf(szNewValue, sizeof(szNewValue) / sizeof(szNewValue[0]),
+            szNewValueFormat, iIndex++);
+
+        cbData = sizeof(data);
+        lResult = RegQueryValueEx(hKey, szNewValue, NULL, &dwExistingType, data, &cbData);
+    }
+    while(lResult == ERROR_SUCCESS);
+
+    switch(dwType) {
+    case REG_DWORD:
+        cbData = sizeof(DWORD);
+        break;
+    case REG_SZ:
+    case REG_EXPAND_SZ:
+        cbData = sizeof(TCHAR);
+        break;
+    case REG_MULTI_SZ:
+        cbData = sizeof(TCHAR) * 2;
+        break;
+    case REG_QWORD:
+        cbData = sizeof(DWORD) * 2;
+        break;
+    default:
+        cbData = 0;
+        break;
+    }
+    memset(data, 0, cbData);
+    lResult = RegSetValueEx(hKey, szNewValue, 0, dwType, data, cbData);
+    if (lResult != ERROR_SUCCESS)
+        return FALSE;
+
+    RefreshListView(g_pChildWnd->hListWnd, hRootKey, pszKeyPath);
+
+    /* locate the newly added value, and get ready to rename it */
+    memset(&lvfi, 0, sizeof(lvfi));
+    lvfi.flags = LVFI_STRING;
+    lvfi.psz = szNewValue;
+    iIndex = ListView_FindItem(g_pChildWnd->hListWnd, -1, &lvfi);
+    if (iIndex >= 0)
+        ListView_EditLabel(g_pChildWnd->hListWnd, iIndex);
+
+    return TRUE;
+}
+
 /*******************************************************************************
  *
  *  FUNCTION: _CmdWndProc(HWND, unsigned, WORD, LONG)
@@ -593,6 +656,15 @@ static BOOL _CmdWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
           }
         }
        break;
+    case ID_EDIT_NEW_STRINGVALUE:
+        CreateNewValue(hKeyRoot, keyPath, REG_SZ);
+        break;
+    case ID_EDIT_NEW_BINARYVALUE:
+        CreateNewValue(hKeyRoot, keyPath, REG_BINARY);
+        break;
+    case ID_EDIT_NEW_DWORDVALUE:
+        CreateNewValue(hKeyRoot, keyPath, REG_DWORD);
+        break;
     }
     case ID_EDIT_COPYKEYNAME:
         CopyKeyName(hWnd, _T(""));
@@ -622,6 +694,9 @@ static BOOL _CmdWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    /*case ID_OPTIONS_TOOLBAR:*/
    /*  toggle_child(hWnd, LOWORD(wParam), hToolBar);*/
    /*    break;*/
+    case ID_EDIT_NEW_KEY:
+        CreateNewKey(g_pChildWnd->hTreeWnd, TreeView_GetSelection(g_pChildWnd->hTreeWnd));
+        break;
     default:
         result = FALSE;
     }
index 0ca2b1d..b696aa6 100644 (file)
@@ -27,6 +27,7 @@
 #include <stdio.h>
 
 #include "main.h"
+#include "regproc.h"
 
 #define CX_ICON    16
 #define CY_ICON    16
@@ -442,11 +443,19 @@ BOOL ListWndNotifyProc(HWND hWnd, WPARAM wParam, LPARAM lParam, BOOL *Result)
                    if(_tcslen(Info->item.pszText) == 0)
                    {
                      LoadString(hInst, IDS_ERR_RENVAL_TOEMPTY, msg, sizeof(msg)/sizeof(TCHAR));
+                     MessageBox(0, msg, NULL, 0);
+                     *Result = TRUE;
                    }
                    else
-                    _stprintf(msg, _T("rename from %s to %s"), lineinfo->name, Info->item.pszText);
-                    MessageBox(0, msg, NULL, 0);
-                   *Result = TRUE;
+                       {
+                         HKEY hKeyRoot;
+                         LPCTSTR keyPath;
+                         LONG lResult;
+                         keyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
+                         lResult = RegRenameValue(hKeyRoot, keyPath, Info->item.pszText, lineinfo->name);
+                     *Result = TRUE;
+                     return (lResult == ERROR_SUCCESS);
+                       }
                  }
                 }
               }
index 11c096d..215e255 100644 (file)
@@ -28,6 +28,8 @@
 #include <process.h>
 #include <stdio.h>
 #include <fcntl.h>
+#include <aclui.h>
+#include <cguid.h>
 
 #include "main.h"
 #include "hexedit.h"
index dcfb374..307559c 100644 (file)
@@ -99,6 +99,7 @@ extern BOOL IsDefaultValue(HWND hwndLV, int i);
 extern HWND CreateTreeView(HWND hwndParent, LPTSTR pHostName, int id);
 extern BOOL OnTreeExpanding(HWND hWnd, NMTREEVIEW* pnmtv);
 extern LPCTSTR GetItemPath(HWND hwndTV, HTREEITEM hItem, HKEY* phRootKey);
+extern BOOL CreateNewKey(HWND hwndTV, HTREEITEM hItem);
 
 /* edit.c */
 extern BOOL ModifyValue(HWND hwnd, HKEY hKey, LPCTSTR valueName, BOOL EditBin);
index 9d597f8..f887a88 100644 (file)
@@ -27,6 +27,8 @@
 #include <winnt.h>
 #include <winreg.h>
 #include <assert.h>
+#include <tchar.h>
+#include <malloc.h>
 #include "regproc.h"
 
 #define REG_VAL_BUF_SIZE        4096
@@ -1501,3 +1503,166 @@ CHAR *getAppName()
 {
     return app_name;
 }
+
+LONG RegDeleteKeyRecursive(HKEY hKey, LPCTSTR lpSubKey)
+{
+    LONG lResult;
+    HKEY hSubKey = NULL;
+    DWORD dwIndex, cbName;
+    TCHAR szSubKey[256];
+    FILETIME ft;
+
+    lResult = RegOpenKeyEx(hKey, lpSubKey, 0, KEY_ALL_ACCESS, &hSubKey);
+    if (lResult == ERROR_SUCCESS)
+    {
+        dwIndex = 0;
+        do
+        {
+            cbName = sizeof(szSubKey) / sizeof(szSubKey[0]);
+            lResult = RegEnumKeyEx(hSubKey, dwIndex++, szSubKey, &cbName, NULL, NULL, NULL, &ft);
+            if (lResult == ERROR_SUCCESS)
+                RegDeleteKeyRecursive(hSubKey, szSubKey);
+        }
+        while(lResult == ERROR_SUCCESS);
+
+        RegCloseKey(hSubKey);
+    }
+
+    return RegDeleteKey(hKey, lpSubKey);
+}
+
+LONG RegCopyKey(HKEY hDestKey, LPCTSTR lpDestSubKey, HKEY hSrcKey, LPCTSTR lpSrcSubKey)
+{
+    LONG lResult;
+    DWORD dwDisposition;
+    HKEY hDestSubKey = NULL;
+    HKEY hSrcSubKey = NULL;
+    DWORD dwIndex, dwType, cbName, cbData;
+    TCHAR szSubKey[256];
+    TCHAR szValueName[256];
+    BYTE szValueData[512];
+
+    FILETIME ft;
+
+    /* open the source subkey, if specified */
+    if (lpSrcSubKey)
+    {
+        lResult = RegOpenKeyEx(hSrcKey, lpSrcSubKey, 0, KEY_ALL_ACCESS, &hSrcSubKey);
+        if (lResult)
+            goto done;
+        hSrcKey = hSrcSubKey;
+    }
+
+    /* create the destination subkey */
+    lResult = RegCreateKeyEx(hDestKey, lpDestSubKey, 0, NULL, 0, KEY_WRITE, NULL,
+        &hDestSubKey, &dwDisposition);
+    if (lResult)
+        goto done;
+
+    /* copy all subkeys */
+    dwIndex = 0;
+    do
+    {
+        cbName = sizeof(szSubKey) / sizeof(szSubKey[0]);
+        lResult = RegEnumKeyEx(hSrcKey, dwIndex++, szSubKey, &cbName, NULL, NULL, NULL, &ft);
+        if (lResult == ERROR_SUCCESS)
+        {
+            lResult = RegCopyKey(hDestSubKey, szSubKey, hSrcKey, szSubKey);
+            if (lResult)
+                goto done;
+        }
+    }
+    while(lResult == ERROR_SUCCESS);
+
+    /* copy all subvalues */
+    dwIndex = 0;
+    do
+    {
+        cbName = sizeof(szValueName) / sizeof(szValueName[0]);
+        cbData = sizeof(szValueData) / sizeof(szValueData[0]);
+        lResult = RegEnumValue(hSrcKey, dwIndex++, szValueName, &cbName, NULL, &dwType, szValueData, &cbData);
+        if (lResult == ERROR_SUCCESS)
+        {
+            lResult = RegSetValueEx(hDestSubKey, szValueName, 0, dwType, szValueData, cbData);
+            if (lResult)
+                goto done;
+        }
+    }
+    while(lResult == ERROR_SUCCESS);
+
+    lResult = ERROR_SUCCESS;
+
+done:
+    if (hSrcSubKey)
+        RegCloseKey(hSrcSubKey);
+    if (hDestSubKey)
+        RegCloseKey(hDestSubKey);
+    if (lResult != ERROR_SUCCESS)
+        RegDeleteKeyRecursive(hDestKey, lpDestSubKey);
+    return lResult;
+
+}
+
+LONG RegMoveKey(HKEY hDestKey, LPCTSTR lpDestSubKey, HKEY hSrcKey, LPCTSTR lpSrcSubKey)
+{
+    LONG lResult;
+
+    if (!lpSrcSubKey)
+        return ERROR_INVALID_FUNCTION;
+
+    lResult = RegCopyKey(hDestKey, lpDestSubKey, hSrcKey, lpSrcSubKey);
+    if (lResult == ERROR_SUCCESS)
+        RegDeleteKeyRecursive(hSrcKey, lpSrcSubKey);
+
+    return lResult;
+}
+
+LONG RegRenameKey(HKEY hKey, LPCTSTR lpSubKey, LPCTSTR lpNewName)
+{
+    LPCTSTR s;
+    LPTSTR lpNewSubKey;
+
+    s = _tcsrchr(lpSubKey, '\\');
+    if (s)
+    {
+        s++;
+        lpNewSubKey = (LPTSTR) alloca((s - lpSubKey + _tcslen(lpNewName) + 1) * sizeof(TCHAR));
+        memcpy(lpNewSubKey, lpSubKey, (s - lpSubKey) * sizeof(TCHAR));
+        _tcscpy(lpNewSubKey + (s - lpSubKey), lpNewName);
+        lpNewName = lpNewSubKey;
+    }
+    return RegMoveKey(hKey, lpNewName, hKey, lpSubKey);
+}
+
+LONG RegRenameValue(HKEY hKey, LPCTSTR lpSubKey, LPCTSTR lpDestValue, LPCTSTR lpSrcValue)
+{
+    LONG lResult;
+    HKEY hSubKey = NULL;
+    DWORD dwType, cbData;
+    BYTE data[512];
+
+    if (lpSubKey)
+    {
+        lResult = RegOpenKey(hKey, lpSubKey, &hSubKey);
+        if (lResult != ERROR_SUCCESS)
+            goto done;
+        hKey = hSubKey;
+    }
+
+    cbData = sizeof(data);
+    lResult = RegQueryValueEx(hKey, lpSrcValue, NULL, &dwType, data, &cbData);
+    if (lResult != ERROR_SUCCESS)
+        goto done;
+
+    lResult = RegSetValueEx(hKey, lpDestValue, 0, dwType, data, cbData);
+    if (lResult != ERROR_SUCCESS)
+        goto done;
+
+    RegDeleteValue(hKey, lpSrcValue);
+
+done:
+    if (hKey)
+        RegCloseKey(hKey);
+    return lResult;
+}
+
index 72a41b2..ca1e6c2 100644 (file)
@@ -82,4 +82,13 @@ BOOL InitializeAclUiDll(VOID);
 VOID UnloadAclUiDll(VOID);
 BOOL RegKeyEditPermissions(HWND hWndOwner, HKEY hKey, LPCTSTR lpMachine, LPCTSTR lpKeyName);
 
+/*
+ * Processing
+ */
+LONG RegDeleteKeyRecursive(HKEY hKey, LPCTSTR lpSubKey);
+LONG RegCopyKey(HKEY hDestKey, LPCTSTR lpDestSubKey, HKEY hSrcKey, LPCTSTR lpSrcSubKey);
+LONG RegMoveKey(HKEY hDestKey, LPCTSTR lpDestSubKey, HKEY hSrcKey, LPCTSTR lpSrcSubKey);
+LONG RegRenameKey(HKEY hKey, LPCTSTR lpSubKey, LPCTSTR lpNewName);
+LONG RegRenameValue(HKEY hKey, LPCTSTR lpSubKey, LPCTSTR lpDestValue, LPCTSTR lpSrcValue);
+
 /* EOF */
index 24dc657..27a64bc 100644 (file)
 #define ID_EDIT_PERMISSIONS            32872
 #define ID_TREE_DELETE                  32873
 #define ID_TREE_RENAME                  32874
+#define IDS_QUERY_DELETE_KEY_ONE        32875
+#define IDS_QUERY_DELETE_KEY_MORE       32876
+#define IDS_QUERY_DELETE_KEY_CONFIRM    32877
 
 #define IDS_FLT_REGFILES               31001
 #define IDS_FLT_REGFILES_FLT           31002
 #define IDS_INHERIT_SUBKEYSONLY                31123
 #define IDS_EXPAND                      31124
 #define IDS_COLLAPSE                    31125
+#define IDS_NEW_KEY                     31126
+#define IDS_NEW_VALUE                   31127
 
 
 #define IDD_EDIT_STRING                        2000
index 3ac338c..3cce258 100644 (file)
@@ -28,6 +28,8 @@
 #include <objbase.h>
 #include <basetyps.h>
 #include <unknwn.h>
+#include <aclui.h>
+#include <cguid.h>
 #include "security.h"
 #include "regproc.h"
 #include "resource.h"
index f8c221a..c5b22f6 100644 (file)
@@ -260,6 +260,55 @@ done:
 }
 
 
+BOOL CreateNewKey(HWND hwndTV, HTREEITEM hItem)
+{
+    TCHAR szNewKeyFormat[128];
+    TCHAR szNewKey[128];
+    LPCTSTR pszKeyPath;
+    int iIndex = 1;
+    HKEY hRootKey;
+    HKEY hKey = NULL;
+    HKEY hNewKey = NULL;
+    BOOL bSuccess = FALSE;
+    LONG lResult;
+    DWORD dwDisposition;
+    HTREEITEM hNewItem;
+
+    pszKeyPath = GetItemPath(g_pChildWnd->hTreeWnd, hItem, &hRootKey);
+    if (RegOpenKey(hRootKey, pszKeyPath, &hKey) != ERROR_SUCCESS)
+        goto done;
+
+    if (LoadString(hInst, IDS_NEW_KEY, szNewKeyFormat, sizeof(szNewKeyFormat) / sizeof(szNewKeyFormat[0])) <= 0)
+        goto done;
+
+    do
+    {
+        _sntprintf(szNewKey, sizeof(szNewKey) / sizeof(szNewKey[0]), szNewKeyFormat, iIndex++);
+        lResult = RegCreateKeyEx(hKey, szNewKey, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hNewKey, &dwDisposition);
+        if (hNewKey && (dwDisposition == REG_OPENED_EXISTING_KEY))
+        {
+            RegCloseKey(hNewKey);
+            hNewKey = NULL;
+        }
+    }
+    while(!hNewKey);
+
+    hNewItem = AddEntryToTree(hwndTV, hItem, szNewKey, NULL, 0, NULL);
+    if (!hNewItem)
+        goto done;
+    TreeView_EditLabel(hwndTV, hNewItem);
+
+    bSuccess = TRUE;
+
+done:
+    if (hKey)
+        RegCloseKey(hKey);
+    if (hNewKey)
+        RegCloseKey(hNewKey);
+    return bSuccess;
+}
+
+
 /*
  * CreateTreeView - creates a tree view control.
  * Returns the handle to the new control if successful, or NULL otherwise.