TreeViewExtender.FLL is a dynamic-link library compiled in Visual FoxPro FLL format.
Combined with this library, a regular TreeView ActiveX control displays shell folders in attractive and convenient way. It can also automatically reflect folder changes happening on the host computer (VFP9).
Features:
a regular TreeView control is used (MSComctlLib.TreeCtrl)
FLL can monitor folder changes in multiple roots
VFP9 forms can receive folder change notifications via window messages (VFP9)
older VFP versions can poll recent folder changes using Timer control
folders are depicted using appropriate system images (no extra graphics required)
the tree displays compressed (zipped) folders (Vista)
no API declarations in VFP code, the complexity moved inside the FLL
the FLL has small footprint -- about 40 KB
Minimal client: Windows XP, VFP8 (7?)
PUBLIC oForm As Explorer
oForm = CREATEOBJECT("Explorer")
oForm.Visible=.T.
* end of mainDEFINECLASS Explorer AsFormWidth=480Height=500AutoCenter=.T.
Caption="Folders"Backcolor=RGB(255,255,255)ShowWindow=2ADD OBJECT tree As ExplorerTree WITH;
Left=20, Top=10, Width=440, Height=440,;
StartPath="c:\"ENDDEFINEDEFINECLASS ExplorerTree AsOleControlOleClass="MSComctlLib.TreeCtrl"
oRoot=NULL&& root node
StartPath=""
hWindow=0
DirectoryWatch_Msg=0
DirectoryWatch_Id=0 * only top level of subfolders to be scanned
FolderEnum_MaxEnumLevel=0 * the FLL populates all following properties * for each subfolder found
FolderEnum_StartPath=""
FolderEnum_Status=0
FolderList_Status=0
FolderEnum_FolderCount=0
FolderEnum_PathValid=.F.
FolderList_FolderIndex=0
FolderList_Foldername=""
FolderList_HasSubfolders=.F.
FolderList_FolderPath=""
FolderList_ParentPath=""
FolderList_FolderLevel=0
FolderList_FolderSFGAOAttributes=0
FolderList_FolderAttributes=0
FolderList_TypeName=""PROCEDUREInitSETLIBRARYTO TreeViewExtender.fllADDITIVEWITHTHIS
.HideSelection=.F.
.PathSeparator="\"
.Style=3
.LineStyle=1
.LabelEdit=1
.Indentation=16
.BorderStyle=0
.Appearance=0
.Sorted=.T.
.hWindow = ThisForm.HWnd * Windows Message ID to be sent to * the window defined by THIS.hWindow
.DirectoryWatch_Msg =;
TVX_GetNotificationMessageId()IFVERSION(5) >= 900&& VFP9+
.Anchor=15
BINDEVENT( .hWindow, .DirectoryWatch_Msg,;
THIS, "WinProc")ENDIF * links TreeView control * to the system image list
TVX_SetImageList( .hwnd)
.RefreshTreeENDWITHPROCEDUREDestroyWITHTHIS
TVX_UnregisterDirectoryWatch(;
.hWindow, .DirectoryWatch_Id)ENDWITHPROCEDURE RefreshTree
IFNOTEMPTY(THIS.StartPath)THIS.StartPath = THIS.StartPathENDIFPROCEDURE StartPath_ASSIGN( cPath AsString)WITHTHIS
.StartPath = m.cPath
.Nodes.Clear
.oRoot = .Nodes.Add(,,;
UPPER(ALLTRIM(.StartPath)),;
"Scanning "+.StartPath+"...")
nResult = TVX_ListFolders( .StartPath, THIS)
.oRoot.Key = UPPER(ALLTRIM(.FolderEnum_StartPath))
.oRoot.Text = .FolderEnum_StartPath
.oRoot.Sorted = .T.
.oRoot.Selected = .T.
.RegisterDirectoryWatchENDWITHPROCEDURE RegisterDirectoryWatch
WITHTHIS
TVX_UnregisterDirectoryWatch(;
.hWindow, .DirectoryWatch_Id)IF .FolderEnum_PathValid
.DirectoryWatch_Id =;
TVX_RegisterDirectoryWatch(;
.FolderEnum_StartPath, .hWindow)ENDIFENDWITHPROCEDURE WinProc(hWindow asInteger, nMsgID asInteger,;
wParam asInteger, lParam asInteger)* ignored for VFP versions before VFP9 * this message notifies about changes in foldersIF nMsgID = THIS.DirectoryWatch_Msg;
AND m.wParam = THIS.DirectoryWatch_IdTHIS.GetDirectoryChangesENDIFRETURN0PROCEDURE GetDirectoryChanges
LOCAL cBuffer
IFNOTUSED("csChanges") * the cursor is for demo purpose onlyCREATECURSOR csChanges ( dirchangedata M )ENDIFDOWHILE .T.
* pulling latest changes while supply lasts
cBuffer = TVX_GetDirectoryChanges(;
THIS.hWindow, THIS.DirectoryWatch_Id)IFEMPTY(m.cBuffer)EXITELSEINSERTINTO csChanges (dirchangedata);
VALUES(m.cBuffer)THIS.RescanTree( m.cBuffer)ENDIFENDDOPROCEDURE RescanTree( cBuffer )LOCAL nActionCount, nActionIndex, cAction,;
cPath, cParentPath, cNewPath, oNode
cNewPath=""
nActionCount = ALINES( arrActions,;
m.cBuffer, CHR(13)+CHR(10)) * scans changes from newest to oldestFOR nActionIndex=nActionCount TO1STEP-1
cAction = SUBSTR(arrActions[nActionIndex], 1, 1)
cPath = SUBSTR(arrActions[nActionIndex], 2)
cPath = STRTRAN(m.cPath, "\\", "\")&& a bug to be pinned
cParentPath = JUSTPATH( m.cPath)DOCASECASEINLIST( m.cAction, "1", "3") * new folder detected * rescanning the parent path
oNode = THIS.GetNodeByKey( m.cParentPath)IFNOTISNULL(m.oNode)
TVX_ListFolders( m.cParentPath, THIS)ENDIFCASE m.cAction="2" * a folder has been deleted * deleting existing node
oNode = THIS.GetNodeByKey( m.cPath)IFNOTISNULL(m.oNode)THIS.Nodes.Remove( oNode.Key)ENDIFCASE m.cAction="4" * a folder has been renamed - storing old name * changing Name and Key of existing node
oNode = THIS.GetNodeByKey( m.cPath)IFNOTISNULL(m.oNode)
oNode.Text = JUSTFNAME(m.cNewPath)
oNode.Key = UPPER(ALLTRIM(m.cNewPath))THIS.RemoveChildren( oNode )
TVX_ListFolders( m.cNewPath, THIS)ENDIF
cNewPath=""CASE m.cAction="5" * a folder has been renamed - storing new name
cNewPath = m.cPathENDCASENEXTPROCEDURE Expand( oNode )IFNOT oNode.CheckedRETURNENDIFTHIS.RescanNode( m.oNode)PROCEDURE RescanNode( oNode )THIS.RemovePlaceholderNode( oNode )
TVX_ListFolders( oNode.Key, THIS)IFNOTTHIS.FolderEnum_PathValidTHIS.Nodes.Remove( m.oNode.Key)ELSE
oNode.Selected=.T.
ENDIFPROCEDURE FolderEnum_Status_ASSIGN( nNewStatus AsNumber)WITHTHIS
.FolderEnum_Status = m.nNewStatusDOCASECASE .FolderEnum_Status = 1 * FLL begins enumerating folder. * Do not clear TreeView nodes here, because * an enumeration may start on expanding a node, * not just on populating the whole treeCASE .FolderEnum_Status = 2 * FLL has finished enumerating foldersCASE .FolderEnum_Status = 5 * FLL begins sending folderes data to the controlCASE .FolderEnum_Status = 6 * FLL has finished sending floders data to the controlENDCASEENDWITHPROCEDURE FolderList_Status_ASSIGN( nNewStatus AsNumber)WITHTHIS
.FolderList_Status = m.nNewStatusDOCASECASE .FolderList_Status = 1 * FLL begins sending data for next folderCASE .FolderList_Status = 2 * FLL has finished sending data for a folder
.AddFolderENDCASEENDWITHPROCEDURE RemoveChildren( oNode )DOWHILE oNode.Children > 0THIS.Nodes.Remove( oNode.Child.Key)ENDDOFUNCTION GetNodeByKey( cKey AsString)LOCAL oNode
TRY
oNode = THIS.Nodes(UPPER(ALLTRIM(m.cKey)))
CATCH
oNode=NULL
ENDTRY
RETURN m.oNodeFUNCTION NodeExists( cKey AsString)RETURNVARTYPE(THIS.GetNodeByKey(m.cKey)) = "O"PROCEDURE GetParentNode( cKey AsString)LOCAL oNode
IFEMPTY(m.cKey)
oNode = NULLELSE
TRY
oNode=THIS.Nodes(UPPER(ALLTRIM(m.cKey)))
CATCH
oNode=NULL
ENDTRY
ENDIFRETURN m.oNodePROCEDURE AddPlaceholderNode( oNode )LOCAL cKey, oPlaceholder
cKey = oNode.Key + "\.."IFNOTTHIS.NodeExists(m.cKey)
oPlaceholder = .Nodes.Add( oNode, 4, m.cKey, "..")DOEVENTSENDIF
oNode.Checked=.T.
PROCEDURE RemovePlaceholderNode( oNode )LOCAL cKey
cKey = oNode.Key + "\.."IFTHIS.NodeExists(m.cKey)THIS.Nodes.Remove( m.cKey)ENDIF
oNode.Checked=.F.
PROCEDURE AddFolder
LOCAL oParentNode, oNode, ex As Exception
WITHTHIS
oNode = .GetNodeByKey( .FolderList_FolderPath)IFVARTYPE(m.oNode)="O"
oNode.Text = .FolderList_FoldernameRETURNENDIF
oParentNode = .GetParentNode( .FolderList_ParentPath)IFISNULL(oParentNode)
oParentNode = THIS.oRootELSE
.RemovePlaceholderNode( oParentNode )ENDIF
TRY
oNode = .Nodes.Add( oParentNode, 4,;
UPPER(ALLTRIM(.FolderList_FolderPath)),;
.FolderList_Foldername)IF .FolderList_HasSubfolders
.AddPlaceholderNode( oNode )ENDIF
oNode.Sorted=.T.
oNode.Selected=.T.
CATCHTO ex
* subfolders in ZIP files * the routine is to be completedACTIVATESCREEN? ex.Message?THIS.FolderList_FolderPath
ENDTRY
ENDWITHENDDEFINE
Note: this is an alpha version of the library. More testing and cleaning to be done. The interface may eventually change.
Library functions:
FUNCTION TVX_ListFolders ( cStartPath As String,
oVFPObject As Object ) As Number
For a given path, enumerates subfolders and sends the data to a TreeView control (2nd parameter). The target control should have a configured set of properties.
For each subfolder found within the start path, the FLL populates certain properties of TreeView control. VFP application uses these properties when adds tree nodes.
FUNCTION TVX_GetNotificationMessageId () As Number
Returns window message Id assigned to notify VFP application about folder changes. Do not replace the call with a constant value. This message id can vary through different computers (see RegisterWindowMessage API).
FUNCTION TVX_RegisterDirectoryWatch ( cStartPath As String,
nHWnd As Number ) As Number
The nHWnd must belong to a VFP form. The function returns the MonitorId to be used in subsequent calls to other library functions.
Upon this call, the FLL starts monitoring specified path, subfolders included, for any folder-related changes. Notifications of such changes are periodically sent to the form through a window message. In VFP9 the messages can be picked up with BINDEVENT() function. The WParam contains MonitorId value. The LParam contains the number of folder change records waiting.
This function can be called multiple times for the same nHWnd, each time with different start path; as well as multiple times for the same start path, each time with different HWnd.
FUNCTION TVX_GetDirectoryChanges ( nHWnd As Number,
MonitorId As Number ) As String
For given HWnd and MonitorId, returns a text buffer containing formatted list of recent folder changes happened within the monitored path. This function should be called in a cycle, until it returns an empty string. VFP application should interpret the folder changes: add, delete and modify TreeView nodes accordingly.
In VFP9 application, this function should be called upon receiving the notification message. While VFP8 application cannot capture window messages natively, it still can obtain folder changes through calling the TVX_GetDirectoryChanges() periodically.
PROCEDURE TVX_UnregisterDirectoryWatch ( nHWnd As Number,
nDirectoryWatchId As Number )
For given HWnd and MonitorId, closes folder changes monitor.
PROCEDURE TVX_SetImageList ( nHWnd As Number )
Links TreeView ActiveX control, specified by its HWnd, to the system image list, enabling system images in tree nodes.
Credits: PHP (4.4.9), an HTML-embedded scripting language,
MySQL (5.1.55-log), the Open Source standard SQL database,
AceHTML Freeware
Version 4, freeware HTML Editor of choice. Hosted by Korax Online Inc.