--- a/ooDialog/trunk/ooDialog/oodTreeView.cpp
+++ b/ooDialog/trunk/ooDialog/oodTreeView.cpp
@@ -214,9 +214,91 @@
     return NULL;
 }
 
-RexxMethod8(RexxObjectPtr, tv_insert, OPTIONAL_CSTRING, _hItem, OPTIONAL_CSTRING, _hAfter, OPTIONAL_CSTRING, label,
+/**
+ * Returns the lParam user data for the specified tree-view item as a Rexx
+ * object
+ *
+ * @param hTree
+ *
+ * @return The Rexx object set as the user data, or the .nil object if no user
+ *         data is set.
+ */
+static RexxObjectPtr getCurrentTviUserData(HWND hTree, HTREEITEM hTreeItem)
+{
+    TVITEMEX      tvi    = {LVIF_PARAM, hTreeItem};
+    RexxObjectPtr result = TheNilObj;
+
+    if ( TreeView_GetItem(hTree, &tvi) != 0 )
+    {
+        if ( tvi.lParam != 0 )
+        {
+            result = (RexxObjectPtr)tvi.lParam;
+        }
+    }
+    return result;
+}
+
+
+/** TreeView::delete()
+ *
+ *
+ *  @returns  0 on sucees, 1 on error, and -1 if hItem is not valid.
+ *
+ *  @remarks  The return codes for this are not optimal.  But they are what was
+ *            documented and used in the original ooDialog from IBM.
+ *
+ */
+RexxMethod2(RexxObjectPtr, tv_delete, CSTRING, _hItem, CSELF, pCSelf)
+{
+    pCDialogControl pcdc = validateDCCSelf(context, pCSelf);
+    if ( pcdc == NULL )
+    {
+        return TheNegativeOneObj;
+    }
+
+    HTREEITEM hItem = (HTREEITEM)string2pointer(_hItem);
+    if ( hItem == NULL )
+    {
+        return TheNegativeOneObj;
+    }
+    if ( TreeView_GetCount(pcdc->hCtrl) < 1 )
+    {
+        return TheNegativeOneObj;
+    }
+
+    unProtectControlUserData(context, pcdc, getCurrentTviUserData(pcdc->hCtrl, hItem));
+
+    return TreeView_DeleteItem(pcdc->hCtrl, hItem) ? TheZeroObj : TheOneObj;
+}
+
+/** TreeView::deleteAll()
+ *
+ *  @returns  0 on success, 1 on error.  These are the original ooDialog return
+ *            codes
+ *
+ */
+RexxMethod1(RexxObjectPtr, tv_deleteAll, CSELF, pCSelf)
+{
+    pCDialogControl pcdc = validateDCCSelf(context, pCSelf);
+    if ( pcdc == NULL )
+    {
+        return TheOneObj;
+    }
+
+    if ( pcdc->rexxBag != NULL )
+    {
+        context->SendMessage0(pcdc->rexxBag, "EMPTY");
+    }
+
+    return TreeView_DeleteAllItems(pcdc->hCtrl) ? TheZeroObj : TheOneObj;
+}
+
+/** TreeView::insert()
+ *
+ */
+RexxMethod9(RexxObjectPtr, tv_insert, OPTIONAL_CSTRING, _hItem, OPTIONAL_CSTRING, _hAfter, OPTIONAL_CSTRING, label,
             OPTIONAL_int32_t, imageIndex, OPTIONAL_int32_t, selectedImage, OPTIONAL_CSTRING, opts, OPTIONAL_uint32_t, children,
-            CSELF, pCSelf)
+            OPTIONAL_RexxObjectPtr, userData, CSELF, pCSelf)
 {
     HWND hwnd  = getDChCtrl(pCSelf);
 
@@ -288,62 +370,21 @@
         tvi->cChildren = children;
         tvi->mask |= TVIF_CHILDREN;
     }
+    if ( argumentExists(8) && userData != TheNilObj)
+    {
+        protectControlUserData(context, (pCDialogControl)pCSelf, userData);
+
+        tvi->lParam = (LPARAM)userData;
+        tvi->mask |= TVIF_PARAM;
+    }
 
     return pointer2string(context, TreeView_InsertItem(hwnd, &ins));
 }
 
-RexxMethod7(int32_t, tv_modify, OPTIONAL_CSTRING, _hItem, OPTIONAL_CSTRING, label, OPTIONAL_int32_t, imageIndex,
-            OPTIONAL_int32_t, selectedImage, OPTIONAL_CSTRING, opts, OPTIONAL_uint32_t, children, CSELF, pCSelf)
-{
-    HWND hwnd  = getDChCtrl(pCSelf);
-
-    TVITEMEX tvi = {0};
-
-    if ( argumentExists(1) )
-    {
-        tvi.hItem = (HTREEITEM)string2pointer(_hItem);
-    }
-    else
-    {
-        tvi.hItem = TreeView_GetSelection(hwnd);
-    }
-
-    if ( tvi.hItem == NULL )
-    {
-        return -1;
-    }
-    tvi.mask = TVIF_HANDLE;
-
-    if ( argumentExists(2) )
-    {
-        tvi.pszText = (LPSTR)label;
-        tvi.cchTextMax = (int)strlen(label);
-        tvi.mask |= TVIF_TEXT;
-    }
-    if ( argumentExists(3) && imageIndex > -1 )
-    {
-        tvi.iImage = imageIndex;
-        tvi.mask |= TVIF_IMAGE;
-    }
-    if ( argumentExists(4) && imageIndex > -1 )
-    {
-        tvi.iSelectedImage = selectedImage;
-        tvi.mask |= TVIF_SELECTEDIMAGE;
-    }
-    if ( argumentExists(5) && *opts != '\0' )
-    {
-        parseTvModifyOpts(opts, &tvi);
-    }
-    if ( argumentExists(6) )
-    {
-        tvi.cChildren = (children > 0 ? 1 : 0);
-        tvi.mask |= TVIF_CHILDREN;
-    }
-
-    return (TreeView_SetItem(hwnd, &tvi) == 0 ? 1 : 0);
-}
-
-
+
+/** TreeView::itemInfo()
+ *
+ */
 RexxMethod2(RexxObjectPtr, tv_itemInfo, CSTRING, _hItem, CSELF, pCSelf)
 {
     HWND hwnd  = getDChCtrl(pCSelf);
@@ -352,7 +393,7 @@
     char buf[256];
 
     tvi.hItem = (HTREEITEM)string2pointer(_hItem);
-    tvi.mask = TVIF_HANDLE | TVIF_TEXT | TVIF_STATE | TVIF_IMAGE | TVIF_CHILDREN | TVIF_SELECTEDIMAGE;
+    tvi.mask = TVIF_HANDLE | TVIF_TEXT | TVIF_STATE | TVIF_IMAGE | TVIF_CHILDREN | TVIF_SELECTEDIMAGE | TVIF_PARAM;
     tvi.pszText = buf;
     tvi.cchTextMax = 255;
     tvi.stateMask = TVIS_EXPANDED | TVIS_BOLD | TVIS_SELECTED | TVIS_EXPANDEDONCE | TVIS_DROPHILITED | TVIS_CUT;
@@ -382,7 +423,58 @@
     }
     context->SetStemElement(stem, "!STATE", context->String(buf));
 
+    context->SetStemElement(stem, "!USERDATA", tvi.lParam ? (RexxObjectPtr)tvi.lParam : TheNilObj);
+
     return stem;
+}
+
+
+/** TreeView::getImageList()
+ *
+ *  Gets the tree-view's specifed image list.
+ *
+ *  @param  type [optional] Identifies which image list to get, normal, or
+ *               state. Normal is the default.
+ *
+ *  @return  The image list, if it exists, otherwise .nil.
+ */
+RexxMethod2(RexxObjectPtr, tv_getImageList, OPTIONAL_uint8_t, type, OSELF, self)
+{
+    if ( argumentOmitted(1) )
+    {
+        type = TVSIL_NORMAL;
+    }
+    else if ( type != TVSIL_STATE && type != TVSIL_NORMAL )
+    {
+        return invalidTypeException(context->threadContext, 2, "TVSIL_XXX flag");
+    }
+
+    RexxObjectPtr result = context->GetObjectVariable(tvGetAttributeName(type));
+    if ( result == NULLOBJECT )
+    {
+        result = TheNilObj;
+    }
+    return result;
+}
+
+
+/** TreeView::getItemData()
+ *
+ *  Returns the user data associated with the specified tree-view item, or .nil
+ *  if there is no user data associated.
+ *
+ *  @param  hItem  [required]  The handle of the item whose user data is to be
+ *                 retrieved.
+ *
+ *  @return  Returns the associated user data, or .nil if there is no associated
+ *           data.
+ */
+RexxMethod2(RexxObjectPtr, tv_getItemData, CSTRING, _hItem, CSELF, pCSelf)
+{
+    HWND      hwnd  = getDChCtrl(pCSelf);
+    HTREEITEM hItem = (HTREEITEM)string2pointer(_hItem);
+
+    return getCurrentTviUserData(hwnd, hItem);
 }
 
 
@@ -410,6 +502,10 @@
 }
 
 
+/** TreeView::getNextItem()
+ *
+ *
+ */
 RexxMethod3(RexxObjectPtr, tv_getNextItem, CSTRING, _hItem, NAME, method, CSELF, pCSelf)
 {
     HWND      hwnd  = getDChCtrl(pCSelf);
@@ -427,9 +523,76 @@
 }
 
 
-/** TreeView::select()
+/** TreeView::modify()
+ *
+ *
+ */
+RexxMethod8(int32_t, tv_modify, OPTIONAL_CSTRING, _hItem, OPTIONAL_CSTRING, label, OPTIONAL_int32_t, imageIndex,
+            OPTIONAL_int32_t, selectedImage, OPTIONAL_CSTRING, opts, OPTIONAL_uint32_t, children,
+            OPTIONAL_RexxObjectPtr, userData, CSELF, pCSelf)
+{
+    HWND hwnd  = getDChCtrl(pCSelf);
+
+    TVITEMEX tvi = {0};
+
+    if ( argumentExists(1) )
+    {
+        tvi.hItem = (HTREEITEM)string2pointer(_hItem);
+    }
+    else
+    {
+        tvi.hItem = TreeView_GetSelection(hwnd);
+    }
+
+    if ( tvi.hItem == NULL )
+    {
+        return -1;
+    }
+    tvi.mask = TVIF_HANDLE;
+
+    if ( argumentExists(2) )
+    {
+        tvi.pszText = (LPSTR)label;
+        tvi.cchTextMax = (int)strlen(label);
+        tvi.mask |= TVIF_TEXT;
+    }
+    if ( argumentExists(3) && imageIndex > -1 )
+    {
+        tvi.iImage = imageIndex;
+        tvi.mask |= TVIF_IMAGE;
+    }
+    if ( argumentExists(4) && selectedImage > -1 )
+    {
+        tvi.iSelectedImage = selectedImage;
+        tvi.mask |= TVIF_SELECTEDIMAGE;
+    }
+    if ( argumentExists(5) && *opts != '\0' )
+    {
+        parseTvModifyOpts(opts, &tvi);
+    }
+    if ( argumentExists(6) )
+    {
+        tvi.cChildren = (children > 0 ? 1 : 0);
+        tvi.mask |= TVIF_CHILDREN;
+    }
+    if ( argumentExists(7) && userData != TheNilObj)
+    {
+        RexxObjectPtr oldData = getCurrentTviUserData(hwnd, tvi.hItem);
+
+        unProtectControlUserData(context, (pCDialogControl)pCSelf, oldData);
+        protectControlUserData(context, (pCDialogControl)pCSelf, userData);
+
+        tvi.lParam = (LPARAM)userData;
+        tvi.mask |= TVIF_PARAM;
+    }
+
+    return (TreeView_SetItem(hwnd, &tvi) == 0 ? 1 : 0);
+}
+
+
+/** TreeView::dropHighLight()
  *  TreeView::makeFirstVisible()
- *  TreeView::dropHighLight()
+ *  TreeView::select()
  */
 RexxMethod3(RexxObjectPtr, tv_selectItem, OPTIONAL_CSTRING, _hItem, NAME, method, CSELF, pCSelf)
 {
@@ -483,7 +646,6 @@
 /** TreeView::find()
  *
  *  Finds the first item with the specified text.
- *
  *
  */
 RexxMethod2(RexxObjectPtr, tv_find, CSTRING, text, CSELF, pCSelf)
@@ -573,6 +735,40 @@
 }
 
 
+/** TreeView::removeItemData()
+ *
+ */
+RexxMethod2(RexxObjectPtr, tv_removeItemData, CSTRING, _hItem, CSELF, pCSelf)
+{
+    pCDialogControl pcdc = validateDCCSelf(context, pCSelf);
+    if ( pcdc == NULL )
+    {
+        return TheNilObj;
+    }
+
+    HTREEITEM hItem = (HTREEITEM)string2pointer(_hItem);
+
+    RexxObjectPtr oldUserData = getCurrentTviUserData(pcdc->hCtrl, hItem);
+
+    RexxObjectPtr result = getCurrentTviUserData(pcdc->hCtrl, hItem);
+    if ( result != TheNilObj )
+    {
+        TVITEMEX tvi = {TVIF_PARAM, hItem};
+
+        if ( TreeView_SetItem(pcdc->hCtrl, &tvi) )
+        {
+            unProtectControlUserData(context, pcdc, result);
+        }
+        else
+        {
+            // Not removed, set result back to the .nil ojbect.
+            result = TheNilObj;
+        }
+    }
+
+    return result;
+}
+
 /** TreeView::setImageList()
  *
  *  Sets or removes one of a tree-view's image lists.
@@ -661,32 +857,80 @@
     return NULLOBJECT;
 }
 
-/** TreeView::getImageList()
- *
- *  Gets the tree-view's specifed image list.
- *
- *  @param  type [optional] Identifies which image list to get, normal, or
- *               state. Normal is the default.
- *
- *  @return  The image list, if it exists, otherwise .nil.
- */
-RexxMethod2(RexxObjectPtr, tv_getImageList, OPTIONAL_uint8_t, type, OSELF, self)
-{
-    if ( argumentOmitted(1) )
-    {
-        type = TVSIL_NORMAL;
-    }
-    else if ( type != TVSIL_STATE && type != TVSIL_NORMAL )
-    {
-        return invalidTypeException(context->threadContext, 2, "TVSIL_XXX flag");
-    }
-
-    RexxObjectPtr result = context->GetObjectVariable(tvGetAttributeName(type));
-    if ( result == NULLOBJECT )
-    {
-        result = TheNilObj;
-    }
-    return result;
+
+/** TreeView::setItemData()
+ *
+ *  Assigns a user data value to the specified tree-view item.
+ *
+ *  @param  hItem  [required]  The handle of the item whose user data is to be
+ *                 set.
+ *
+ *  @param  data   [optional]  The user data to be set. If this argument is
+ *                 omitted, the current user data, if any, is removed.
+ *
+ *  @return  Returns the previous user data object for the specified tree-view
+ *           item, if there was a user data object, or .nil if there wasn't.
+ *
+ *           On error, .nil is returned.  An error is very unlikely.  An error
+ *           can be checked for by examining the .systemErrorCode object.
+ *
+ *  @notes  Sets the .systemErrorCode.  On error set to:
+ *
+ *          156  ERROR_SIGNAL_REFUSED The recipient process has refused the
+ *          signal.
+ *
+ *          This is not a system error, the code is just used here to indicate a
+ *          tree-view error when setting the user data.  The tree-view provides
+ *          no information on why it failed.
+ */
+RexxMethod3(RexxObjectPtr, tv_setItemData, CSTRING, _hItem, OPTIONAL_RexxObjectPtr, data, CSELF, pCSelf)
+{
+    oodResetSysErrCode(context->threadContext);
+
+    pCDialogControl pcdc = validateDCCSelf(context, pCSelf);
+    if ( pcdc == NULL )
+    {
+        return TheNilObj;
+    }
+
+    HTREEITEM hItem = (HTREEITEM)string2pointer(_hItem);
+
+    RexxObjectPtr oldUserData = getCurrentTviUserData(pcdc->hCtrl, hItem);
+
+    TVITEMEX tvi = {0};
+    tvi.hItem  = hItem;
+    tvi.mask   = TVIF_PARAM;
+
+    if ( argumentExists(2) )
+    {
+        tvi.lParam = (LPARAM)data;
+
+        if ( TreeView_SetItem(pcdc->hCtrl, &tvi) )
+        {
+            unProtectControlUserData(context, pcdc, oldUserData);
+            protectControlUserData(context, pcdc, data);
+        }
+        else
+        {
+            oldUserData = TheNilObj;
+            oodSetSysErrCode(context->threadContext, 156);
+        }
+    }
+    else
+    {
+        if ( TreeView_SetItem(pcdc->hCtrl, &tvi) )
+        {
+            unProtectControlUserData(context, pcdc, oldUserData);
+        }
+        else
+        {
+            oldUserData = TheNilObj;
+            oodSetSysErrCode(context->threadContext, 156);
+        }
+
+    }
+
+    return oldUserData;
 }
 
 
@@ -757,6 +1001,7 @@
         pctvcds->item      = (HTREEITEM)tvcd->nmcd.dwItemSpec;
         pctvcds->id        = (uint32_t)((NMHDR *)lParam)->idFrom;
         pctvcds->level     = tvcd->iLevel;
+        pctvcds->userData  = tvcd->nmcd.lItemlParam ? (RexxObjectPtr)tvcd->nmcd.lItemlParam : TheNilObj;
 
         RexxObjectPtr custDrawSimple = c->SendMessage1(TheTvCustomDrawSimpleClass, "NEW", tvcdsBuf);
         if ( custDrawSimple != NULLOBJECT )
@@ -773,7 +1018,7 @@
                 {
                     // An example I've seen deletes the old font.  Doesn't seem
                     // appropriate for ooRexx.  The user would need to save the
-                    // list-view font and then add it back in.  Not sure if
+                    // tree-view font and then add it back in.  Not sure if
                     // there is a resource leak here.
                     HFONT hOldFont = (HFONT)SelectObject(tvcd->nmcd.hdc, pctvcds->hFont);
                 }
@@ -883,9 +1128,10 @@
 
 /** TvCustomDrawSimple::userData   [attribute]
  */
-RexxMethod2(RexxObjectPtr, tvcds_getUserData, uint32_t, reply, CSELF, pCSelf)
-{
-    return ((pCTvCustomDrawSimple)pCSelf)->userData;
-}
-
-
+RexxMethod1(RexxObjectPtr, tvcds_getUserData, CSELF, pCSelf)
+{
+    RexxObjectPtr data = (RexxObjectPtr)((pCTvCustomDrawSimple)pCSelf)->userData;
+    return data == NULLOBJECT ? TheNilObj : data;
+}
+
+