News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Tree View question.

Started by hutch--, March 24, 2011, 02:04:20 AM

Previous topic - Next topic

hutch--

I have recently been playing with loading a tree view control with complete directory listings for each drive and while its reasonably straight forward code to use FindFirstFile() - FindNextFile() and it is showing the correct results but it takes a lot longer to do the first pass on a large drive than a number of other applications that use a tree view control for the same task. I have set the task in a recursive algo that climbs up and down the directory structure loading the nodes of the tree view control on the fly.

As I don't claim to have done all that much work with tree view controls to list directory structures, I wonder if anyone is familiar with the speed problem I have with the control when loading this much data into it.

These are the two procedures I am using to load the directory tree into the tree view control.


; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

load_tview proc hTree:DWORD,drv:DWORD

  ; arguments
  ; 1 tree view handle
  ; 2 address drive string "c:\" etc ...

    LOCAL tvi   :TV_INSERTSTRUCT
    LOCAL itx   :TV_ITEMEX
    LOCAL hRoot :DWORD
    LOCAL var   :DWORD
    LOCAL hThread   :DWORD

    fn  LoadCursor,NULL,IDC_WAIT
    fn SetCursor,eax

    fn SetCurrentDirectory,drv
    fn SendMessage,hTree,WM_SETREDRAW,FALSE,0
    fn SendMessage,hTree,TVM_DELETEITEM,0,TVI_ROOT

    mov tvi.hParent, TVI_ROOT
    mov tvi.hInsertAfter, TVI_FIRST
    mov tvi.itemex.imask, TVIF_TEXT
    m2m tvi.itemex.pszText, drv
    mov hRoot, rv(SendMessage,hTree,TVM_INSERTITEM,0,ADDR tvi)

    fn recurse_tree,hRoot

    invoke SendMessage,hTree,TVM_EXPAND,TVE_EXPAND,hRoot
    fn SendMessage,hTree,WM_SETREDRAW,TRUE,0

    ret

load_tview endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

recurse_tree proc hParent:DWORD

    LOCAL wfd   :WIN32_FIND_DATA
    LOCAL hFile :DWORD
    LOCAL tvi   :TV_INSERTSTRUCT
    LOCAL itx   :TV_ITEMEX
    LOCAL hItem :DWORD
    LOCAL nfrv  :DWORD
    LOCAL pnam  :DWORD

    mov hFile, rv(FindFirstFile,"*",ADDR wfd)
    cmp hFile, 0
    je overit

    DIRN = FILE_ATTRIBUTE_DIRECTORY
    DIRR = FILE_ATTRIBUTE_DIRECTORY or FILE_ATTRIBUTE_READONLY
    DIRH = FILE_ATTRIBUTE_DIRECTORY or FILE_ATTRIBUTE_HIDDEN
    DHRO = FILE_ATTRIBUTE_DIRECTORY or FILE_ATTRIBUTE_HIDDEN or FILE_ATTRIBUTE_READONLY

    .if wfd.dwFileAttributes == DIRN || wfd.dwFileAttributes == DIRR || \
        wfd.dwFileAttributes == DIRH || wfd.dwFileAttributes == DHRO

      lea eax, wfd.cFileName
      mov pnam, eax
      switch$ pnam
        case$ "."
          jmp nextfile
        case$ ".."
          jmp nextfile
      endsw$

      m2m tvi.hParent, hParent
      mov tvi.hInsertAfter, TVI_LAST
      mov tvi.itemex.imask, TVIF_TEXT
      m2m tvi.itemex.pszText, pnam
      mov hItem, rv(SendMessage,hTview,TVM_INSERTITEM,0,ADDR tvi)

      chdir ADDR wfd.cFileName
      invoke recurse_tree,hItem
    .endif

  nextfile:
    mov nfrv, rv(FindNextFile,hFile,ADDR wfd)
    cmp nfrv, 0
    je overit

    .if wfd.dwFileAttributes == DIRN || wfd.dwFileAttributes == DIRR || \
        wfd.dwFileAttributes == DIRH || wfd.dwFileAttributes == DHRO

      lea eax, wfd.cFileName
      mov pnam, eax
      switch$ pnam
        case$ "."
          jmp nextfile
        case$ ".."
          jmp nextfile
      endsw$

      m2m tvi.hParent, hParent
      mov tvi.hInsertAfter, TVI_LAST
      mov tvi.itemex.imask, TVIF_TEXT
      m2m tvi.itemex.pszText, pnam
      mov hItem, rv(SendMessage,hTview,TVM_INSERTITEM,0,ADDR tvi)

      chdir ADDR wfd.cFileName
      invoke recurse_tree,hItem
    .endif
    jmp nextfile

  overit:
    chdir ".."
    invoke FindClose,hFile

    ret

recurse_tree endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

oex

Is it creation of an index that takes the time?.... This is not the treeview but the filesystem functions....
We are all of us insane, just to varying degrees and intelligently balanced through networking

http://www.hereford.tv

donkey

If you're using a treeview simply to display the contents of the drive then recursing it will be very slow indeed. There could be 100's of thousands of files to find and if you access anything about them, even just their name, they could be indexed. The way Windows Explorer does it is to use "Just In Time" this is also the technique I used in WinExplorer. The idea is to read the contents of the root folder and display only that. When someone expands a folder you read that folder, adding its contents to the treeview, and so on. This will make it appear that you have read the entire drive contents in the blink of an eye and no one will be the wiser. This is the only practical way I have found to do a Treeview Directory, on a system like mine at home which has 1 Terabyte of drive space and probably around 600,000 files and folders, it would be impractical to recurse through the whole drive. Windows search which is the fastest recurser I know takes nearly 3 minutes.
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

hutch--

Yes, I guess that makes sense, the info is a bit thin on the ground with a Google search but I did find one Microsoft article that described the "Just in time" approach.

Unrelated I have a small application from the old forum called WinExplorer dated about 2004, no menu, a set of buttons along the top and a combo box control to set the drives. It works OK but has no name on it. Written in MASM.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

oex

You will most likely come across the problem again if you add search functionality that searches the drive.... Just a heads up, again as Edgar suggested a more narrow approach helps ie defining lower level root folders....

Still if there is a fix for this somehow it would be nice.... Atm I can only think to maintain my own index and monitor the hard drive for any use where the delay between broad searches is too large....

With your own index you would be able to recurse extremely fast but it is also a lot more work.... I have not attempted it with ASM only in VB years ago....

I believe file system monitoring also slows your system however so there is some tradeoff here also....
We are all of us insane, just to varying degrees and intelligently balanced through networking

http://www.hereford.tv

donkey

Quote from: hutch-- on March 24, 2011, 03:02:28 AM
Unrelated I have a small application from the old forum called WinExplorer dated about 2004, no menu, a set of buttons along the top and a combo box control to set the drives. It works OK but has no name on it. Written in MASM.

I think that that might be EWayne's, haven't heard from him in a while though.

BTW WinExplorer (mine) is available on my website if you want to take a look. The code for Just In Time is pretty winding but you can take a look at how it performs and decide whether its right for your application. If you just want to try the app, I've attached the executable.
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

hutch--

Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

lingo

It works for me too...but when I pressed the last icon (Most recently used) it doesn't works..Win7 64bit here.

donkey

I wrote that something like 6 years ago, it is what it is. 64 bit Windows also has problems with the show imports/exports function, the structure was wrong I think or something like that, when it was written there weren't any examples I had access to to test it and I never bothered to take it up again. Just a quick peek at the source shows that it predates the header project and I used the MASM32 definitions for structures (ie imask instead of mask), that makes it pretty old. In the end it was never much more than a platform for me to test shell and gui ideas.

EDIT: A quick peek at the version on my website shows that the MRU button isn't even there, must have been looking into it then decided against it. There's no handler for it that I can find in the source. I uploaded my working copy to this thread so it probably has a lot of potential errors.
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

hutch--

having played with a tree view control in my spare time over the last couple of days, I am surprised at how they actually work. The WM_NOTIFY interface is reasonably straight forward but I am fascinated by the effect that within a number of the notification message handlers you get instant GP faults if you attempt to either send or post a number of tree view control messages. Recovering the path back to root was easy enough to do from the TVN_SELCHANGED notification but try it anywhere else and BANG.

This code is an instant GP fault.


            case TVN_ITEMEXPANDED
              push esi

              mov esi, rv(SendMessage,hTview,TVM_GETNEXTITEM,TVGN_CARET,0)

              invoke PostMessage,hTview,TVM_SELECTITEM,TVGN_CARET,0
              invoke PostMessage,hTview,TVM_SELECTITEM,TVGN_CARET,esi

              pop esi


I have one working example written in MASM and I have just had a look at Edgar's GoAsm code and they both use a technique that I did not expect, basically a hit test approach on the visible portion of the tree view window. It looks like I will have to redesign the test pieces I have to do this as the messaging has unusual overlaps that cause GP faults.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

Tedd

Set the lParam value of each inserted node to the handle of its parent (NULL for root items.) Tracing a path to the root is then a sequence of TVM_GETITEM calls, which I would hope shouldn't cause any issues since it requires no modification of the treeview state.

Also, I'd respond to TVN_ITEMEXPANDING for inserting your new child nodes (before the branch actually expands.)

Plus a small hint about WM_SETREDRAW when inserting any potentially large number of items :wink
No snowflake in an avalanche feels responsible.

hutch--

Gratsie,

I have been getting unusual results, did the WM_SETREDRAW with no problems and can load the tree in one pass from a recursive directory algo but have had problems trying to do the "just in time" version. The complete version works fine but is slow when it crawls an entire directory tree. Where I have tried partial listings I have had the problem that when I click on the unexpanded branch and try and recurse the directory tree from that location I get an instant GP fault.

I have the TVN_ITEMEXPANDING and TVN_ITEMEXPANDED notifications working correctly and both indicate expanding and collapsing the tree but as soon as I try and modify the tree from those notifications it goes BANG. Tried posting a message to WM_COMMAND but same result.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

Tedd

It's your lucky day - have a working example :bg

No snowflake in an avalanche feels responsible.

dedndave


hutch--

 :bg

A gentleman and a scholar and if that offends you at least a scholar.  :U
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php