The MASM Forum

General => The Workshop => Windows API => Topic started by: NoCforMe on April 05, 2024, 10:36:19 AM

Title: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 05, 2024, 10:36:19 AM
(putting this in the Windows API forum since it deals mostly with Win32 API topics)

Note: Long post. If you don't like to read much, you might want to move on to something shorter.

Someone suggested to me an idea for an application that would let them annotate pictures, basically associate a block of text with a picture. That sounded intriguing to me, so I started thinking about the design of such a program. I imagined an Explorer-like interface showing folders and picture files, and it seemed to me that a treeview control might be the way to go.

I'd never used a treeview before; I've seen them, of course, and was familiar with the basic idea. But given the horrors of dealing with certain Windows controls (listview, here's looking at you!), I was kind of hesitant to jump into this new thing to me.

Turns out I shouldn't have been worried: the whole project (so far) has been extremely pleasurable, with success after success, including implementing the treeview. You know how some projects just fight you every step of the way? The documentation is sketchy, missing or downright wrong; things don't work the way they're supposed to; there are lots of hidden "gotchas" to make life interesting for you. None of that here.

In fact, the treeview control worked perfectly the first time I coded it! That hardly ever happens.

I thought a treeview would be appropriate since it follows the structure of a file system, folders and files, and this is in fact the case. (Of course, that's one of the classic uses of a treeview, to show directory structures.) I thought that perhaps this could be done with some other control type, like, say, a listbox with a lot of custom-draw stuff added to it. But the treeview was an absolute pleasure to work with. This is obviously a very well-designed and well implemented piece of work. It's complex: just think about all the code behind all that drawing and placement, and the capability of expanding or collapsing sections. I'd say it's somewhere between a listview and a RichEdit control in terme of complexity.

So: first task was to do a directory scan to feed the treeview. I'd done this previously with my file-finder program, using FindFirstFile() and FindNextFile() to dive into a directory structure. After not too much trouble I came up with a simple and reliable function to do this, called GetAllDirsAndFiles(). Turns out, of course, that recursion is your friend here. In fact, with recursion, it's dead simple to do this.

In pseudocode:
Start @ "root" folder:
GetAllDirsAndFiles (root)

while ! NoMoreFiles
(  FindFirstFile()
  if NoMoreFiles
      exit
  filter files (exclude ".", "..", and non-image files)
  add folder or file to file list
  FindNextFile()
)
if AnyFilesFound
(  for each folder found
  GetAllDirsAndFiles (folder found)
)

That's it, minus a couple details. (Complete code and explanation below.)

I use a list of structures to store folders and files:
FILEINFO    STRUC
  pathName    DB MAX_PATH DUP(?)
  rootLoc    DD ?
  textPtr    DD ?
  parent    DD ?
  tvHandle    HWND ?
  flag        DD ?
FILEINFO    ENDS

Now, that first item causes me some concern about memory requirements, as MAX_PATH is 240 bytes. That's a lot of memory if you're dealing with thousands (or tens of thousands) of files. I thought of alternative schemes, where only the "root" name would be stored in the FILEINFO entry, and you could construct the full pathname by following the parent pointers. But besides being a pain in the ass to code, you'd still probably need MAX_PATH characters to store even just a filename, let alone a full pathname. So at the end of the day, since our computers have so much memory available nowadays, maybe this shouldn't be a source of worry. So I'm OK with this scheme.

OK, now we have an in-memory list of all our files and folders. But how to get this into a treeview? My first thought was to integrate populating the treeview with the directory scan, creating treeview entries from each folder or file found.

Long story short, it turns out to be much easier to break this process into two parts: first scanning the directory structure, then creating the treeview from this list. And it turned out to be so easy!

All that needs to be done is to go through the file list sequentially, creating treeview items from each item. Because of the sequence of scanning, the treeview will be perfect. For each folder found, create a treeview item with children; for each file, create one without children. (Well, almost; read on for details.) Because each file list entry has a parent pointer, this gives us the handle of the parent treeview item we need to create a new treeview item. Perfect!

Well, almost perfect. My first design gave me the right directory structure, except for one thing: instead of all folders being listed first and then files, the two were intermixed in alpha-sort order. Not what I wanted. This was due to the fact that folders and files arrive in alpha-sort order, not folders first, then files.

Hmmm; scratch my head a few minutes. Hey, what if I ... rearrange the file list so that folders are first? This turned out to be trivially easy, and gives the correct order of folders and files.

See the before and after shots of file order below.

(https://i.postimg.cc/m1BLrSfC/Bad-folder-order.jpg) (https://postimg.cc/m1BLrSfC)

(https://i.postimg.cc/NytBD4FV/Good-folder-order.jpg) (https://postimg.cc/NytBD4FV)

Another thing: since I was telling Windows that all folders had children while all files didn't, all folders looked as if they could be expanded, even if they were empty. Hmmm, not sure how to fix that; it seems like a time machine would come in handy here, since how do I know whether there are any children in a folder until I come to them?

This problem was also trivially easy to solve: that's where the flag member of FILEINFO comes in. As I'm processing a folder in GetAllDirsAndFiles(), I have access to both the parent (the folder being processed) and any children (folders and files found in the parent). So what I do is initially create all folders with "no children", but then when I find any items within (folders or files), I change the flag to "has children". And then in the 2nd phase, populating the treeview, each folder item gets created corrrectly.

Here's before and after for that problem.

(https://i.postimg.cc/9DWLBwVb/Bad-empty-folders.jpg) (https://postimg.cc/9DWLBwVb)

(https://i.postimg.cc/N5tDg2yt/Good-empty-folders.jpg) (https://postimg.cc/N5tDg2yt)

Here's the code for the folder/file scanner:
;============================================
; GetAllDirsAndFiles (fiPtr)
;
; New version (1 pass/folder instead of 2)
;============================================

GetAllDirsAndFiles PROC fiPtr:DWORD
LOCAL findHandle:HANDLE, folderCount:DWORD, fiSavePtr:DWORD, rootLoc:DWORD
LOCAL totalCountThisDir:DWORD, fi:FILEINFO, fd:WIN32_FIND_DATA, pathBuffer[256]:BYTE

CMP NoMoreObjectsFlag, TRUE
JE exit99

; Get location for all appendages to incoming pathname (folder & filenames):
MOV EDX, fiPtr
LEA EAX, [EDX].FILEINFO.pathName
CALL strlen
INC EAX ;+1 for "\".
MOV rootLoc, EAX

MOV folderCount, 0
MOV totalCountThisDir, 0
MOV EAX, NextFileEntryPtr
MOV fiSavePtr, EAX ;Save place where these dirs. will be stored.

MOV EDX, fiPtr
INVOKE strcpy, ADDR [EDX].FILEINFO.pathName, ADDR pathBuffer
INVOKE _strcat, OFFSET WildcardStr, ADDR pathBuffer
INVOKE FindFirstFile, ADDR pathBuffer, ADDR fd
CMP EAX, ERROR_NO_MORE_FILES
JE exit99
TEST EAX, EAX
JZ exit99
MOV findHandle, EAX

; Filter out "." and ".." folders:
filter: INVOKE strcmpi, ADDR fd.cFileName, OFFSET OneDotDirStr
TEST EAX, EAX
JNZ nxtfil
INVOKE strcmpi, ADDR fd.cFileName, OFFSET TwoDotDirStr
TEST EAX, EAX
JNZ nxtfil

; Filter out any bogus files whose name is (or starts with) ':'"
CMP fd.cFileName, ':'
JE nxtfil

; If it's a file, filter on valid extensions:
TEST fd.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY
JNZ @F
LEA EAX, fd.cFileName
CALL FilterFiles
TEST EAX, EAX ;Result of extension match.
JZ nxtfil

; Add folder or file to file list:
; Check for too many objects:
@@: CMP TotalObjectCount, $maxObjects
JNE @F
INVOKE MessageBox, NULL, OFFSET TooManyObjectsMsg, NULL, MB_OK
MOV NoMoreObjectsFlag, TRUE
JMP exit99 ;That's it, folks.

@@: PUSH EBX
MOV EBX, NextFileEntryPtr
MOV EAX, rootLoc
MOV [EBX].FILEINFO.rootLoc, EAX
MOV EDX, fiPtr ;Get ptr. to parent.
MOV [EBX].FILEINFO.parent, EDX
OR [EDX].FILEINFO.flag, $hasKids ;Indicate that the parent has children.
INVOKE strcpy, ADDR [EDX].FILEINFO.pathName, ADDR [EBX].FILEINFO.pathName
INVOKE _strcat, OFFSET BackslashStr, ADDR [EBX].FILEINFO.pathName
INVOKE _strcat, ADDR fd.cFileName, ADDR [EBX].FILEINFO.pathName

; Folder or file?
TEST fd.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY
JZ isfile

; It's a folder:
INC folderCount
MOV EAX, $folder
JMP SHORT @F

; It's a file:
isfile: INC FileCount
XOR EAX, EAX

@@: MOV [EBX].FILEINFO.flag, EAX
POP EBX

INC TotalObjectCount
INC totalCountThisDir

ADD NextFileEntryPtr, SIZEOF FILEINFO

; Get next file:
nxtfil: INVOKE FindNextFile, findHandle, ADDR fd
TEST EAX, EAX
JZ dodirs
CMP EAX, ERROR_NO_MORE_FILES
JNE filter

; Reorder list so that folders are first, then files:
dodirs: MOV EAX, totalCountThisDir
TEST EAX, EAX
JZ @F
MOV EDX, fiSavePtr
CALL ReorderFilist

@@: MOV ECX, folderCount
ADD TotalFolderCount, ECX
JECXZ exit99

PUSH EBX
MOV EBX, fiSavePtr ;Pt. to list of new folders & files.

dofldr: PUSH ECX

; Now recurse into folders:
foldlp: TEST [EBX].FILEINFO.flag, $folder
JZ skipfl

INVOKE GetAllDirsAndFiles, ADDR [EBX].FILEINFO.pathName
POP ECX
ADD EBX, SIZEOF FILEINFO
LOOP dofldr
POP EBX
JMP SHORT exit99

skipfl: ADD EBX, SIZEOF FILEINFO
JMP foldlp

exit99: RET

GetAllDirsAndFiles ENDP

There's more to the story. I'm going to stop here and continue with another post for Part 2.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 05, 2024, 11:00:03 AM
Some juicy details about using treeview controls:

To create a treeview item:

To clear a treeview control:
Easy-peasy; just use the TVM_DELETEITEM message with a value of TVI_ROOT (or zero).

To expand (or collapse) a treeview at any point in the tree:
Use the TVM_EXPAND message, naturally. (If you don't expand the control it'll come up collapsed when you create it.)

Treeview styles:
You probably want all these styles:

So how do you track treeview items to your data structures, like my folder/file list? Well, like so many Win32 structures or functions, TVITEM(EX) contains a handy-dandy lParam element, which is just a DWORD. I use this to hold a pointer to the corresponding FILEINFO element for each treeview item. Works like a charm.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 05, 2024, 11:25:02 AM
Issues:

After coming up with a working demo of at least part of this app (a picture & text associator, remember), several issues have emerged:


I'll cover the speed considerations here.

Interesting detail: my first version of the folder/file scanner (code posted in 1st post above) was more complicated: I did two passes through each folder I was scanning, first for folders, then for files. Not only was this overly complex, but more importantly it was slower than hell! On a path containing a little more than 4,000 files it took about 45 seconds to grind through all that data! But when I simplified it to the one-pass version posted here, the time went down ... to less than 1 second! I must have been tripping up the file-search process something terrible; it may be that it expects a certain sequence of searching (getting all folders and files in a folder in one batch), and gets all screwed up with another sequence.

Even now it can take a long time with a lot of files. If I scan my entire working disk (~28,000 files in ~16,000 folders) it still takes almost 30 seconds.

Which is way too long to leave a user looking at an unresponsive program (which will probably show "Not responding" in its title bar). I know how to fix this: run the directory scan in a separate thread. And give the user some indication of activity, like a progress bar.

Oh well, this probably is never going to be a commercial product anyway ...

I wonder if those newfangled "shell" functions are any faster?
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: sinsi on April 05, 2024, 11:42:14 AM
pathName should be easy enough to get, assuming the node text is the directory name.

GetNodeFullPath PROC USES EBX path:PTR,node:HTREEITEM
    ;path = buffer large enough (MAX_PATH presumably)
    ;node = the node with the file name
    mov     ebx,node
 @@:
    INVOKE  PrependNodeText,ebx,path
    INVOKE  SendMessage,treeview,TVM_GETNEXTITEM,TVGN_PARENT,ebx
    mov     ebx,eax
    test    eax,eax
    jnz     @b
    ret
GetNodeFullPath ENDP
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 05, 2024, 12:00:28 PM
Yes, that's another way it could be done; really 6 of one/half a dozen of the other, as I have those (partial) pathnames in my file list, and all I have to do is access my parent pointer.

Quote from: sinsi on April 05, 2024, 11:42:14 AMpathName should be easy enough to get, assuming the node text is the directory name.
Actually, it's not: I'm only storing the "root" name (name + .ext), at least in the treeview (for display). But I store the entire pathname for the node in my own file list. And I'd only have to go back one level to a file's parent to construct the entire pathname, not all the way back to the root. (That's what all those MAX_PATH elements are used for.)

Pet peeve: I hate that word "prepend". So programmer-ish. The right word would be prefix.

Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 05, 2024, 12:07:26 PM
Issue: Data Storage

By this I mean storing the whole shebang, file list and associated text, after scanning and user input. Now it's easy enough to come up with a file format for this; it's essentially a database with a tree structure having pointers into a text heap of some kind.

What's a much more serious problem is what you're going to do with that database once you load it. Say the user picks an entry point in the directory structure on their disk, scans it, inputs a bunch of text to go with pictures and saves it. Later they start the program and reload the database. But in the meantime pictures have been moved, deleted and added; how the hell do you synchronize that mess? Ugh.

I suppose my first pass will only work with files (pictures) that are where they were before, and just ignore the others. But even this will mean having to confirm that those files still exist in their original locations.

Design; it's a bitch, but it's absolutely necessary. (Unless you don't mind a program that was obviously designed by a programmer!)
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: sinsi on April 05, 2024, 12:09:00 PM
QuoteAlthough it sounds correct, prepend is not an English word. It was created to sound like the opposite of "append," which means to add to the end.
Every day we learn a new thing  :cool:
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 05, 2024, 12:18:19 PM
Hopefully, yes.

OK, I'm re-attaching the demo executable here. I found the problem, a very stupid error made by one of our low-level workers here (they have been severely reprimanded and hopefully won't make that mistake again!). So give it a try; you can click on anything without it crashing. (I'm pretty sure.)
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: sinsi on April 05, 2024, 01:28:31 PM
(4ad0.4fc): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000001 ebx=00000001 ecx=00000001 edx=00000000 esi=004010f0 edi=00550a52
eip=00401183 esp=0019f144 ebp=0019f490 iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010202
PixOrg+0x1183:
00401183 f7821401000001000000 test dword ptr [edx+114h],1 ds:002b:00000114=????????
Click the + to open a node, bang!
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 05, 2024, 01:33:34 PM
Yikes. Sorry about that.

Looks like I was testing the "folder" bit there with EDX=0. Hmmmm ... back to the lab.

Well, folks, looks like development is at a standstill until we get this bug report resolved here at NoCforMe Laboratories, GmbH.

Found what I think was the problem (I didn't set the pointer to my file list for the root treeview item, and I must have never clicked on that). Updated version attached to reply #7 above.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: sinsi on April 05, 2024, 02:13:03 PM
(2b24.a20): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
*** WARNING: Unable to verify checksum for e:\Desktop\PixOrg.exe
eax=00000001 ebx=00000001 ecx=00000001 edx=00000000 esi=004010f0 edi=00240aea
eip=00401183 esp=0019f144 ebp=0019f490 iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010202
PixOrg+0x1183:
00401183 f7821401000001000000 test dword ptr [edx+114h],1 ds:002b:00000114=????????
Not a cut'n'paste  :biggrin:
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: sinsi on April 05, 2024, 02:24:42 PM
Further playing
 - if I select a node before trying to open it, all is OK
 - I can open a node that isn't selected, subject to the above
 - image preview works
 - clicking the root node is an instant crash at the same code address, irrespective of the above
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: Greenhorn on April 05, 2024, 03:22:01 PM
Quote from: NoCforMe on April 05, 2024, 11:25:02 AM
  • Speed:  Scanning directory structures takes some time. Sometimes lots of time.
  • Text storage:  Storing all that text to associate with pictures is not going to be trivial. I'm still throwing around ideas for how this will work.
  • Data storage:  By which I mean storing the whole shebang to disk so it can be loaded later. All kinds of problems here!
  • Stack considerations

What I would try to do ...

Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 05, 2024, 03:42:02 PM
Ah, incremental loading; interesting. I'll think about that.

That's pretty much what I had in mind for storing the whole mess on disk.

I re-attached the demo (fixed the crash bug) in post #7 above if anyone wants to play with this.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: sinsi on April 05, 2024, 04:02:54 PM
OK, it works, but...there's no indication that a node is a folder or a picture file.
I can expand everything, there are 10 pages in the tree, but what are pictures? Data overload.
Use a listview. I found them easier to use than a treeview  :biggrin:
Or an imagelist for the nodes.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 05, 2024, 04:45:45 PM
Yes, it would be nice to see at a glance what kind of "object" that is. I'm curious about attaching li'l images anyhow.

I must say that I'm still liking this project. So far all the problems have been self-inflicted, and when they're fixed there's no real mystery about how things work. Even if nothing more comes of this, it's a good learning experience.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 05, 2024, 06:56:55 PM
OK, last post for tonight. You say you wanted images? You got images. I think it makes it a lot easier to use. LMK what you think.

(The "picture" bitmap is a bit ugly, best I could come up with on short notice. They're all 16x16 bitmaps. Oh, and be sure to scan a directory that has at least 1 empty folder.)
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: jj2007 on April 05, 2024, 07:18:57 PM
Quote from: NoCforMe on April 05, 2024, 10:36:19 AMNote: Long post

Yes indeed :thumbsup:

But very helpful. PixOrg.zip (reply #7) works like a charm, compliments :thup:
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: sinsi on April 05, 2024, 08:08:25 PM
 :thumbsup:
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 06, 2024, 04:09:45 AM
Moving on to other issues:

Stack usage:
Since this program uses recursion (omigod!), stack size becomes an issue, although after thinking about it, maybe not that much of an issue: after all, the depth of recursion is limited in my case to the depth of folder nesting in the file system. Let's say that it can get up to 12 or 15 deep, or maybe even 20: that doesn't seem like a huge amount of stack space is needed. (On the other hand, I did get a couple failures when testing due to stack overflow.)

So I'm thinking about doing some testing to try to determine how much stack space is actually needed. One idea is to mark the stack at program start, then scan the stack after running to see how much actually got used. Maybe something like this to mark it:

MOV EBX, ESP ;save it
MOV EDX, ESP
MOV ECX, <stack size - a little something>
sloop: MOV DWORD PTR [EDX]. 0BADF00D ;"PUSH"
SUB EDX, 4
LOOP sloop
MOV ESP, EBX ;restore it

then later I can scan the stack looking for the first marked value (0BADF00D) which will give me at least an approximate number for usage.

This won't mess up my program, will it? (Just for research, won't be in the "release" version if that ever happens.)
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 06, 2024, 05:26:48 AM
Hmm; I tried it. No harm to the program. Looks like stack usage was right around 4,000 DWORDs, so not far from what I had guessed (I set .stack to 20K, 20 * 1,024).

I actually got a stack overflow when it was set to half of that.

Stack checking code:
mov edx, esp
sub edx, 256
mov ecx, ($stackSize / 4) - 256
xor eax, eax
cloop: cmp dword ptr [edx], 0BADF00Dh
je xxx
inc eax
sub edx, 4
loop cloop
xxx: invoke wsprintf, addr buffer, offset stackfmt, eax
invoke MessageBox, NULL, addr buffer, NULL, MB_OK
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 07, 2024, 10:31:08 AM
New version attached. Bugs fixed, made more bulletproof. I think. I hope.

I made one change that should help the "takes a long time to grind through a disk" problem. I won't tell you what it is, so you'll need to at least be curious enough to download it and try it. (Right, JJ?) Comments welcome as always. (I didn't use Greenhorn's suggestion of doing incremental scans; although sounds like it has merit, it would be complicated to implement. Maybe later?)

Development is at a standstill at this point, since I'm not sure where I'm going next. I need to talk to the "customer" (a friend who casually mentioned they might like such a program) to find out what they really want. No problem, as I've been having fun with this project.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: jj2007 on April 07, 2024, 10:45:02 AM
Quote from: NoCforMe on April 07, 2024, 10:31:08 AMI made one change that should help the "takes a long time to grind through a disk" problem.

The MsgBox "Maximum # of folders + files (100,000) hit."?
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 07, 2024, 11:31:20 AM
Uh, yeah, another Issue.

I've got to allocate some finite amount of memory to start, right? Chose enough for 100,000 "objects" (files/folders). Now, in a Real Product, one wouldn't just throw one's hands up when that limit is hit: one would allocate some more memory and continue on.

Coming in version 2 ... hey, at least it didn't crash on you!
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: sinsi on April 07, 2024, 12:12:23 PM
Do you ever release memory? The usage only increases, even if I selected a drive and then reselected it.
It got to about 350MB before I tried to scan C: and got the limit message.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 07, 2024, 12:20:47 PM
I'm pretty sure that memory is being used by the treeview, since I only do one allocation for my file list heap at the start. Not sure how to release treeview memory: destroy and re-create the control each time? (I'm using TVM_DELETEITEM to clear the control at each new search, but there are other ways to do that.)

Just found this article (https://ftp.zx.net.nz/pub/Patches/ftp.microsoft.com/MISC/KB/en-us/130/697.HTM) (a Microsoft knowledge base posting) which says that you can reduce treeview memory usage by using the LPSTR_TEXTCALLBACK value instead of explicitly passing a string for text display; that way the caller is responsible for the string storage space, not the control. Since each treeview item has a pointer to my file list, that should be easy to implement.

Not sure if that would help the cumulative memory usage problem, though.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 07, 2024, 02:44:37 PM
Well, I did the LPSTR_TEXTCALLBACK thing (easy, just had to add a handler and fill in the NMTVDISPINFO structure). It made a tiny improvement in memory usage. But it didn't solve the problem of increasing memory usage every time you do a new folder scan. I'm thinking that's gonna require destroying and re-creating the control every time. Ugh.

Drive scanned  Non-callback  Callback
C:115,260112,136
D:216,852214,828
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 07, 2024, 02:51:40 PM
Maybe the answer is simple. Found this in an online forum:
QuoteDisplaying half a million records in a treeview is not a great idea.

But it's such a nice control. I really like it. Hate to have to give it up.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: daydreamer on April 07, 2024, 03:17:12 PM
Quote from: NoCforMe on April 07, 2024, 12:20:47 PMI'm pretty sure that memory is being used by the treeview, since I only do one allocation for my file list heap at the start. Not sure how to release treeview memory: destroy and re-create the control each time? (I'm using TVM_DELETEITEM to clear the control at each new search, but there are other ways to do that.)

Just found this article (https://ftp.zx.net.nz/pub/Patches/ftp.microsoft.com/MISC/KB/en-us/130/697.HTM) (a Microsoft knowledge base posting) which says that you can reduce treeview memory usage by using the LPSTR_TEXTCALLBACK value instead of explicitly passing a string for text display; that way the caller is responsible for the string storage space, not the control. Since each treeview item has a pointer to my file list, that should be easy to implement.

Not sure if that would help the cumulative memory usage problem, though.
Doesn't it suggest there is a bug like not reset pointer to start of allocated memory or something ?
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 07, 2024, 03:34:06 PM
Quote from: daydreamer on April 07, 2024, 03:17:12 PMDoesn't it suggest there is a bug like not reset pointer to start of allocated memory or something ?
First of all, daydreamer, you really need to learn to write coherent English. It's sometimes very difficult to figure out what you're trying to say.

Resetting pointer? Bug? But who?--me, or Windows? I'm not doing anything with memory (I make one big allocation at the start for my file list, and that's it), so it's not my fault. So far as Windows goes, the treeview seems like a pretty robust and well-tested control, except that it's a real memory hog. (This seems confirmed by the number of posts you find online about memory problems with it.) If only there were some way to "reset pointer to start of allocated memory", or something. But there are apparently no such hooks into the code.

I'm really thinking destroying/re-creating is the only way to go. It's not that hard; I just have been reluctant to code it. (It's not that fun.)
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: sinsi on April 07, 2024, 03:49:10 PM
QuoteFirst of all, daydreamer, you really need to learn to write coherent English. It's sometimes very difficult to figure out what you're trying to say.
Don't be a dick. You don't use emojis, which makes some of your posts dick-ish :rolleyes:

If you re-scan a drive that you have already scanned, do you replace/free the previous "objects" or just add them all again to your list? There's no way that a treeview uses that much memory for 100 items, whereas if you are adding a new object to your list, that's at least MAX-PATH plus.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 07, 2024, 04:04:40 PM
Quote from: sinsi on April 07, 2024, 03:49:10 PM
QuoteFirst of all, daydreamer, you really need to learn to write coherent English. It's sometimes very difficult to figure out what you're trying to say.
Don't be a dick. You don't use emojis, which makes some of your posts dick-ish :rolleyes:
Thank you for sharing that with me. (Again, I don't use emojis; read between the lines.)

QuoteIf you re-scan a drive that you have already scanned, do you replace/free the previous "objects" or just add them all again to your list? There's no way that a treeview uses that much memory for 100 items, whereas if you are adding a new object to your list, that's at least MAX-PATH plus.
Every new scan fills my list from the beginning, so that's not the problem. Besides, I'm only allocating memory (heap) once at the start of the program.

Specifically:

Did you get that much memory usage (you said 350 MB) with only 100 items? Weird.

Judging from what I'm reading in lots of other forums, treeviews are notorious memory hogs.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: sinsi on April 07, 2024, 04:31:25 PM
How much memory is 100K objects?
A scan of my C: (Windows and programs only, users are on a different drive) gives 527,708 files and 174,068 folders, a bit more than your 100,000 limit  :sad:

Quote from: NoCforMeread between the lines
I'm a native english speaker and sometimes I don't even see your lines :biggrin:
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 07, 2024, 04:38:55 PM
Quote from: sinsi on April 07, 2024, 04:31:25 PMHow much memory is 100K objects?
Welll, since FILEINFO is thus:
FILEINFO STRUC
  pathName DB MAX_PATH DUP(?)
  rootLoc DD ?
  textPtr DD ?
  parent DD ?
  tvHandle HWND ?
  flag DD ?
FILEINFO ENDS
then it's 26,000,000 bytes.

QuoteA scan of my C: (Windows and programs only, users are on a different drive) gives 527,708 files and 174,068 folders, a bit more than your 100,000 limit  :sad:
Yes; well, obviously I've got a ways to go until this is "professional grade". Memory re-allocation is next up on my list.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: sinsi on April 07, 2024, 04:46:07 PM
[pedant]28,000,000[/pedant]
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 07, 2024, 05:11:17 PM
No, you're absolutely right. Why was I thinking MAX_PATH = 240?

Anyhow.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 08, 2024, 05:40:21 AM
Memory Issues

Now this is starting to bug me.

I changed the program so it now destroys and re-creates the treeview from scratch each and every time a new scan (selecting a new path) is done. So you'd think this would eliminate the control as the source of escalating memory usage. (DestroyWindow() should completely wipe out any memory allocated by the control, right?

Memory usage still increases with each scan. ?????

Again: I am not allocating any memory apart from a large initial allocation at the beginning. So where is this memory leak? It must be Windows, not me, right? But where?

Another weirdness: My heap allocation is 280,000,000 bytes, and yet when I first run the program, Task Manager only shows a usage of 1.6 MB. Now I read something recently that said that what TM reports isn't completely reliable, but this is not even in the ballpark.

Anyone have any clues as to what's going on here?

BTW, it's easy to re-create the control: GetWindowInfo() is your friend. However, there's yet another needed thing missing from the MASM32 include files:
WINDOWINFO STRUCT
  cbSize DD ?
  rcWindow RECT <>
  rcClient RECT <>
  dwStyle DD ?
  dwExStyle DD ?
  dwWindowStatus DD ?
  cxWindowBorders DD ?
  cyWindowBorders DD ?
  atomWindowType ATOM ? ;WORD
  wCreatorVersion DW ?
WINDOWINFO ENDS
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: fearless on April 08, 2024, 06:26:47 AM
Using any images? icons? bitmaps?
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 08, 2024, 06:42:29 AM
Only the ones that are used in the treeview's image lists (3 little itty-bitty 16x16 bitmaps). I just made sure that I was removing both image lists when re-creating the control (using TVM_GETIMAGELIST to get them and then destroying them with ImageList_Destroy(); made absolutely no difference.

I'm displaying bitmap images, sure, using GDI+, but the memory leak persists even if I never show a single image. Other than that, no images (other than the one icon used by the program, and there's no way that's gonna be responsible for a multi-megabyte memory leak!).

Check out this memory-leak report (https://github.com/microsoft/microsoft-ui-xaml/issues/8275), as well as this one (https://memprofiler.com/articles/treeview-resource-leak). They're all over the place!

Maybe I need to use a good profiler here? Anyone have any suggestions in that regard?
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 08, 2024, 06:47:40 AM
Plan B:

Maybe use a different control. Not a listview! I hate, hate, hate dealing with that hot mess of a control.

Maybe an owner-drawn listbox. The lowly listbox is one of the most primitive Windows controls, has been there since Petzold days, so it's proven and simple. It wouldn't give the nice sexy appearance that the treeview gives us, but I could probably simulate the tree-structure view with indentation (using owner draw).

Ugh. Not ready to go down that road yet, but may have to soon ...
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: sinsi on April 08, 2024, 07:46:38 AM
A listbox can only have 32767 items :sad: that's how primitive it is
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 08, 2024, 08:33:59 AM
Then Plan C: write my own custom control. (I've done it before.) Could be fun.

I'm even thinking of maybe trying to implement my own treeview ...
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: fearless on April 08, 2024, 08:36:51 AM
I couldnt download your previous examples as they flagged by AV. If you have some working example code that someone can look at, might be worth posting that first, to see if anything can be spotted, and it might mean you dont have to go down that road of writing your own control.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 08, 2024, 09:07:22 AM
Well, here's everything. Have at it. I seriously doubt you'll find a memory leak in here. Of course, you may find any number of other problems ...

It does work, doesn't crash, has a hard limit of 100,000 "objects" (folders+files). Play around with it.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: jj2007 on April 08, 2024, 11:02:17 AM
Quote from: NoCforMe on April 07, 2024, 02:44:37 PMI did the LPSTR_TEXTCALLBACK thing

That should have solved all your memory problems, as now you only have some minimal "infrastructure" that gets used over and over. The question is what went wrong.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: sinsi on April 08, 2024, 11:51:36 AM
Here's one example of what happend if we don't clean up after ourselves  :biggrin:
exit99: invoke FindClose,findHandle ;<<add this and all is good
   REt
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 08, 2024, 12:09:44 PM
Quote from: sinsi on April 08, 2024, 11:51:36 AMHere's one example of what happend if we don't clean up after ourselves  :biggrin:
exit99:    invoke FindClose,findHandle ;<<add this and all is good
  REt

You dog you. You dirty dog.

That did it. Memory goes up to ~20 MB, stays there.

I had no idea that function even existed. (Probably a holdover from my old DOS days; "Back then we didn't have to close no find handles!")

Thanks!
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 08, 2024, 12:45:18 PM
Well, it's been real. It is now time to put this project aside. I talked to my friend today, and it turns out they had something completely different in mind. So I've turned this into a simple picture viewer; I've come to like it in this function. Nice way to browse through pictures on disk. (And I learned how to use a new control.)

So thanks to all who helped on this. On to the next project!
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: lingo on April 08, 2024, 10:20:57 PM
Thank you NoCforMe,

It is my very old 32bits Dirs Tree View from:
https://www.masmforum.com/board/index.php?topic=16421.msg143124 (https://www.masmforum.com/board/index.php?topic=16421.msg143124)

Pls, try to open \Windows\winsxs with your program, after that  with my dt.exe.
See the different times....  :biggrin:
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: jj2007 on April 08, 2024, 11:21:42 PM
Quote from: lingo on April 08, 2024, 10:20:57 PMPls, try to open \Windows\winsxs with your program, after that  with my dt.exe.
See the different times...

Yep, that is clever: the first algo has to load all the files into the cache, then the second one kicks in and does it in milliseconds :thumbsup:
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: lingo on April 08, 2024, 11:33:55 PM
Put a stop to that nonsense, will you? :nie:

1. Start one program , test it against \Windows\winsxs
2. Restart Windows to clean the cache
3. Start next program , test it against \Windows\winsxs.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: jj2007 on April 08, 2024, 11:34:57 PM
Quote from: lingo on April 08, 2024, 10:20:57 PMIt is my very old 32bits Dirs Tree View from:
https://www.masmforum.com/board/index.php?topic=16421.msg143124

Where are the attachments? I can't see any. I'd like to see the source.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: lingo on April 08, 2024, 11:43:03 PM
https://www.masmforum.com/board/index.php?topic=16421.msg143124 (https://www.masmforum.com/board/index.php?topic=16421.msg143124)
post  #39
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: jj2007 on April 09, 2024, 12:04:58 AM
Compliments, that code is fast indeed :thumbsup:

June 2000 (https://community.osr.com/t/is-there-a-zw-routine-like-findfirstfile/1103): Is there a Zw() routine like FindFirstFile()? Try to use ZwQueryDirectoryFile routine.

Jan 12, 2011: (https://stackoverflow.com/questions/4672040/iterating-files-in-a-directory-without-using-findfirstfile) There are NT API functions (ZwQueryDirectoryFile and similar), which are called by FindFirstFile

Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 09, 2024, 05:06:50 AM
Back to my project.

Now I need help with memory allocation. I'm trying to implement incremental allocations so I don't have to fail with a stupid message like "I've hit my limit of 100,000 folders + files".

I tried using HeapReAlloc() to do this, and it failed, because (I think) the new allocation address was different from the original one. In any case, I'm not sure this is even the appropriate route to take to allocation. (So far in my programming experience I've only ever used heap allocation to get memory.)

First of all, even if I could use HeapAlloc() and friends, I'm not sure I could get enough memory. I'm a bit confused by this statement in the Micro$oft docs for this function:
QuoteIf the heap specified by the hHeap parameter is a "non-growable" heap, dwBytes must be less than 0x7FFF8. You create a non-growable heap by calling the HeapCreate function with a nonzero value.
Which means the maximum allocation would be 524,280 bytes, not enough for my purposes.

But is it possible to create a "growable" heap? and if so, would you create such a heap by making a zero allocation first? That isn't clear at all.

So what I would like, if possible, would be an allocation method that always returns the allocated block at the same memory location. Otherwise it would be a nightmare, as all of my pointers in that file list would become invalid.

Looking at this page (https://learn.microsoft.com/en-us/windows/win32/memory/memory-management-functions?redirectedfrom=MSDN#heap-functions), I see there are the following flavors of memory allocation:

My requirements (or at least my wish list):

So which flavor should I be using?

Further testing here at NoC Laboratories, GmbH reveals that a HeapReAlloc() does use the same address as the original allocation. The problem is I hit the size limit (7FFF8h). So HeapXXXX() seems to be out as a choice for me.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: daydreamer on April 09, 2024, 05:14:24 AM
Quote from: sinsi on April 07, 2024, 03:49:10 PM
QuoteFirst of all, daydreamer, you really need to learn to write coherent English. It's sometimes very difficult to figure out what you're trying to say.
Don't be a dick. You don't use emojis, which makes some of your posts dick-ish :rolleyes:
Sorry,sometimes i post from old phone browser :( with problem using the boards emojis
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: daydreamer on April 09, 2024, 05:19:41 AM
About what kind of memory to use,what kind of memory allocation is under the hood of c linked list code that reallocate to bigger memory when you add nodes ?
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 09, 2024, 05:26:09 AM
Quote from: daydreamer on April 09, 2024, 05:19:41 AMAbout what kind of memory to use,what kind of memory allocation is under the hood of c linked list code that reallocate to bigger memory when you add nodes ?
Good question, the answer to which might be the answer I'm looking for.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: jj2007 on April 09, 2024, 06:23:07 AM
The default heap has no limit
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 09, 2024, 06:55:34 AM
So how do I access the "default heap"? And what about that note that says the allocation is limited to 7FFF8h bytes? (I just ran up against that limit.) And what about "non-growable" vs. grow-able heaps?
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: sinsi on April 09, 2024, 07:04:22 AM
The default heap is the one that comes with your program, set by the linker.
A non-growable heap is one you use CreateHeap for, which isn't used much.
You get the default heap with GetProcessHeap and use the return handle for allocating and reallocating heap memory. The default heap is growable, so the only memory limit is available address space.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 09, 2024, 08:42:41 AM
Thank you, thank you. So nice to get a clear and complete answer!
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: jj2007 on April 09, 2024, 09:05:35 AM
Quote from: jj2007 on April 09, 2024, 06:23:07 AMThe default heap has no limit

Quote from: NoCforMe on April 09, 2024, 08:42:41 AMSo nice to get a clear and complete answer!

You are welcome :thup:

With you, I always have to balance the absolutely necessary against your willingness to read longer text like this one (https://learn.microsoft.com/en-us/previous-versions/ms810627(v=msdn.10)) (let alone downloads). Besides, I was on my smartphone ;-)

@FreeSpeechBrigade: this is friendly banter. Don't call the police :cool:
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 09, 2024, 09:48:05 AM
Aaaargh.

I'm already using GetProcessHeap(). I didn't realize that this gives me the "default heap" (I didn't even know what that was, which is why I found your first reply less than helpful, JJ).

Anyhow. The problem is that HeapReAlloc() gives me a different pointer to the allocated memory than the original allocation from HeapAlloc(). Is this the expected behavior? I was hoping that reallocating would simply enlarge the heap at the same location.

I tried using the HEAP_REALLOC_IN_PLACE_ONLY flag so that the re-allocation would be in the same place as the original one. But then HeapReAlloc() failed.

I really don't understand how this is supposed to work. Say I allocate space for 100K objects with HeapAlloc() and get back a pointer, let's say 23D0020h (that's the actual base address from my last run). Then I do a HeapRealloc() and get a different address back. Does that mean that the original allocation is now invalid? or can I copy my data from the original heap to the "new" heap?

This is bullshit. There's got to be an easier way.

Again, is this (heap allocation) really the way to go here? What about using virtual memory instead?
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: sinsi on April 09, 2024, 10:01:26 AM
Maybe you should read the documentation?
Quote from: MicrosoftHeapReAlloc is guaranteed to preserve the content of the memory being reallocated, even if the new memory is allocated at a different location.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 09, 2024, 10:14:10 AM
Goddamnit, I fucking read that! what, you think I'm a total idiot? Don't condescend ...

OK, so it preserves the content of the memory being re-allocated. But where is that memory? At the address of the original allocation? or the address of the re-allocation?

And if the re-allocation is at a different location, wouldn't that mean that you now have two allocated chunks, one at the original location of the original size, the other at the new location at the new size?

Or does this just mean that the new allocation includes all of the old allocation, and that the original allocation is now invalid? Which gets back to the major problem of having to go through my list and rejigger it. (I guess maybe it wouldn't be that hard if I knew the offset from the original allocation to the new one, and then could just readjust all the pointers using this offset. But still a pain in the ass.)

They (Micro$oft) really do not make this clear. Unless I'm having some kind of mental block here ...
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: sinsi on April 09, 2024, 10:29:16 AM
You allocate some memory and save its address in MyPointer.
You later resize the block, passing it MyPointer and receiving a pointer.
If there was enough memory after your block, it just extends it and returns the MyPointer you gave it.
If there wasn't enough, it allocates a new block, copies the existing data, frees the old block and returns the new block's address, which you should store in MyPointer, because what's there now is an invalid pointer.

You are mad if you have stored pointers in every one of your objects, they should be offsets from the base address (MyPointer).
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 09, 2024, 10:41:59 AM
OK, good answer.

It was easier just to store absolute pointers, because I didn't realize that they could change due to reallocation. Ackshooly, it turns out to be trivially easy to adjust the pointers, so kind of 6 of one, half a dozen of the other.

Coding it up now ...

Your way is better. This is new to me, but after thinking about it a minute or three it makes more sense to store offsets than absolute pointers. Takes a little more arithmetic (you've got to add in the base address each time you access a pointer), but requires no readjustments.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: TimoVJL on April 09, 2024, 11:28:59 AM
Basic vectors are usable in many ways and perhaps in this site we have seen those in asm code too.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 09, 2024, 12:19:46 PM
Here's the latest, now going by the name of "PicView", your basic picture viewer. Heap allocation stuff all worked out.

sinsi, since you have a nice big fat drive, could you try this out to make sure it scans the whole disk? It should, but none of my drives have that many "objects". (Keep in mind that I'm only counting as objects either folders or files that match my filter: .jpg, .gif, .bmp, .png and .ico. Other files are skipped.)
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: stoo23 on April 09, 2024, 12:38:11 PM
Just had a quick 'play', seemed to work fine as far as I can tell  :smiley:  :thumbsup:
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 09, 2024, 12:48:19 PM
So how many file+dirs ("objects") on your fattest drive?
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: sinsi on April 09, 2024, 12:59:35 PM
Windows has a stupid habit nowadays of just terminating a program so all the uer sees is the window disappear.
WinDbg will usually use a special stack, which is why it worked OK under the debugger, 255000 objects, but crashed from the desktop with STATUS_STACK_OVERFLOW.

Recursion is your enemy in this case I would imagine.

Faulting application name: PicView.exe, version: 0.0.0.0, time stamp: 0x6614a47e
Faulting module name: ntdll.dll, version: 10.0.22621.3374, time stamp: 0x3fddb55c
Exception code: 0xc00000fd
Fault offset: 0x0004b5a1
Faulting process ID: 0x0x2354
Faulting application start time: 0x0x1DA8A2842A677D1
Faulting application path: e:\Desktop\PicView.exe
Faulting module path: C:\WINDOWS\SYSTEM32\ntdll.dll
Report ID: 267ff532-a26f-4da7-9953-5b7bb825e6e5
Faulting package full name:
Faulting package-relative application ID:
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 09, 2024, 01:07:09 PM
Hate to ask you, but would you mind testing again? I increased stack size to 64K DWORDs, attached to post #69 (https://masm32.com/board/index.php?msg=128916) above.

I'll assume no news is good news.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: stoo23 on April 09, 2024, 01:39:52 PM
QuoteSo how many file+dirs ("objects") on your fattest drive?
Nothing even close to what 'sinsi' had, mine was about a 3rd of that size.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: sinsi on April 09, 2024, 01:42:46 PM
Looking at you original code, you might want to put those 2 big locals (fd:WIN32_FIND_DATA, pathBuffer[256]:BYTE) into an allocated buffer and just keep a local pointer to it so you can free it when the pro returns.

Faulting application name: PicView.exe, version: 0.0.0.0, time stamp: 0x6614b05f
Faulting module name: ntdll.dll, version: 10.0.22621.3374, time stamp: 0x3fddb55c
Exception code: 0xc00000fd
Fault offset: 0x0004b5a1
Faulting process ID: 0x0x3088
Faulting application start time: 0x0x1DA8A2EE32DFEC1
Faulting application path: C:\Users\xxxxx\AppData\Local\Temp\7zO400FDA49\PicView.exe
Faulting module path: C:\WINDOWS\SYSTEM32\ntdll.dll
Report ID: 991abc49-4d49-4380-bf64-f577108901da
Faulting package full name:
Faulting package-relative application ID:
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 09, 2024, 01:55:20 PM
Dang, forgot all about those locals taking up stack space!

New one attached to #69 as before.

BTW, no need to "allocate" anything; I just put those two in .data.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: sinsi on April 09, 2024, 02:03:11 PM
Time for some source code to get any further.
Faulting application name: PicView.exe, version: 0.0.0.0, time stamp: 0x6614bbd8
Faulting module name: ntdll.dll, version: 10.0.22621.3374, time stamp: 0x3fddb55c
Exception code: 0xc00000fd
Fault offset: 0x0004a9ba
Faulting process ID: 0x0x28C8
Faulting application start time: 0x0x1DA8A31FD971CFB
Faulting application path: C:\Users\xxx\AppData\Local\Temp\7zOCFE6E6EE\PicView.exe
Faulting module path: C:\WINDOWS\SYSTEM32\ntdll.dll
Report ID: fa3dea85-810f-459b-afff-17ea8e182972
Faulting package full name:
Faulting package-relative application ID:
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 09, 2024, 03:42:58 PM
Here 'tis. Happy to have you poke around in it.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: jj2007 on April 09, 2024, 05:06:41 PM
Builds by simply hitting F6, and works like a charm :thumbsup:

Task Manager: Gdi and user objects are stable, but working memory leaks a bit.

Sinsi, how did you make it crash?
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: sinsi on April 09, 2024, 06:40:49 PM
Quote from: jj2007 on April 09, 2024, 05:06:41 PMSinsi, how did you make it crash?
Selected my C:. Maybe it's the depth of the directory tree. One thought I had was what happens if you try and search a junction/reparse point?
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: sinsi on April 09, 2024, 07:51:14 PM
You really need to read up on the functions you use, not just assume they are all the same.

FindFirstFile returns a handle if it succeeds.
If it fails, it returns INVALID_HANDLE_VALUE (which is -1, not 0 as you seem to have assumed) and GetLastError returns an error code, the one you are interested in is ERROR_FILE_NOT_FOUND.

FindNextFile returns a BOOL, so non-zero if it succeeds.
If it fails, it returns 0 and GetLastError returns an error code, the one you are interested in is ERROR_NO_MORE_FILES.

Now, when your code gets to FindFirstFile, it will never throw an error because of how you are testing for one.
The problem is when you hit a directory you don't have access to. If you checked GetLastError you would get error 5 (ACCESS_DENIED) but your code just keeps adding the failed directory name to the end of the search string, so you get something like
"C:\Windows\appcompat\appraiser\UA\UA\UA\UA\UA\UA\UA\UA"and eventually run out of stack.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 10, 2024, 03:40:25 AM
Quote from: sinsi on April 09, 2024, 07:51:14 PMThe problem is when you hit a directory you don't have access to. If you checked GetLastError you would get error 5 (ACCESS_DENIED) but your code just keeps adding the failed directory name to the end of the search string, so you get something like
"C:\Windows\appcompat\appraiser\UA\UA\UA\UA\UA\UA\UA\UA"and eventually run out of stack.
OK, just to address this one case: I'm trying to understand the proper sequence here. Are you saying that even if FindFirstFile() returns successfully after finding a directory, that the directory may be inaccessible? Meaning that FindFirstFile() will return a valid search handle but that GetLastError() will return an error code?

If that's the case then I would need to call GetLastError() every time I get a valid result from FindFirstFile(), correct?

BTW, you may have noticed what looks like a weird quirk in my code, which is comparing a folder/file returned to the character ':'. This is because earlier when I was using FindFirstFile() to scan a disk, I was getting these weird entities, never did find out what exactly they were, that either consisted of or started with that character, which of course is an illegal folder/filename character.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: zedd on April 10, 2024, 04:08:13 AM
Quote from: NoCforMe on April 10, 2024, 03:40:25 AMAre you saying that even if FindFirstFile() returns successfully after finding a directory, that the directory may be inaccessible?
You need to check the file/directory attributes.  :icon_idea: I had to tinker with that some time ago while creating an exhaustive recursive file list. The details of which attributes escape me at the moment though. Further research necessary. I do remember though that some were marked 'Hidden' or 'Archived' I think those gave some issues...
Use
wfd.dwFileAttributes to get the attributes

Some others to check for:

FILE_ATTRIBUTE_REPARSE_POINT    The file has an associated reparse point.
FILE_ATTRIBUTE_SYSTEM

attached "lister5" for your amusement
this one is hard coded to scan for all files/folders in C:
It outputs file "files.txt" in the program folder, and is not not a command line tool

I have another version that outputs 2 files, dirs.txt and files.txt.
One for directory listings (dir.txt) and the other for files (files.txt)
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: fearless on April 10, 2024, 04:13:41 AM
You will probably need to check for "." and ".." in file listings as they are used as shortcuts - originally under DOS to indicate current directory "." and parent directory ".." hence why you can sometimes use a reference like ".\file_in_this_folder.txt" or "..\file_in_parent_folder.txt" or even more indirect references with multiple ones like "..\..\some_folder\some_file.txt".

Each sub-folder from the root drive will have a "." and ".."

Open a dos command prompt, goto a folder "cd c:\windows", type "dir" and see the dot references:

C:\Windows>dir
 Volume in drive C is Windows
 Volume Serial Number is 8A6D-FA9C

 Directory of C:\Windows

02/04/2024  17:56    <DIR>          .
02/04/2024  17:56    <DIR>          ..
07/12/2019  15:52    <DIR>          addins
10/05/2023  09:53        2,482,672 ampa.exe
08/06/2021  12:14            1,328 ampa.ini
27/07/2023  01:59    <DIR>          appcompat
24/01/2024  21:42    <DIR>          apppatch


Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 10, 2024, 04:46:23 AM
Quote from: fearless on April 10, 2024, 04:13:41 AMYou will probably need to check for "." and ".." in file listings as they are used as shortcuts
You obviously haven't looked at my source; that's the very first thing I do after finding a folder.

I've known about those since DOS days.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 10, 2024, 04:50:10 AM
Quote from: sudoku on April 10, 2024, 04:08:13 AMSome others to check for:
FILE_ATTRIBUTE_REPARSE_POINT    The file has an associated reparse point.
FILE_ATTRIBUTE_SYSTEM
That first one looks like something I should be checking for and eliminating from further search. I didn't know about that attribute.

Then there's FILE_ATTRIBUTE_VIRTUAL, of which Micro$oft says "This value is reserved for system use.".
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: zedd on April 10, 2024, 05:01:35 AM
Quote from: NoCforMe on April 10, 2024, 04:50:10 AMThen there's FILE_ATTRIBUTE_VIRTUAL, of which Micro$oft says "This value is reserved for system use.".
I didn't know about that one.  :tongue:
I wonder what hard linked files are attributed as.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: sinsi on April 10, 2024, 05:05:19 AM
You can search C:\Windows and find a folder called appcompat
On your next recursive call you search C:\Windows\appcompat and will get an access denied error.

Your function should return an error code (0 to continue the search, GetLastError if an error occured) so you can skip the search - ejecting a CD in the middle of a search, losing a network connection etc.

    invoke FindFirstFile,...
    cmp eax,INVALID_HANDLE_VALUE
    jnz @f
        call GetLastError
        cmp eax,ERROR_FILE_NOT_FOUND
        jnz finished ;return the error
        xor eax,eax
        jmp finished ;return "all ok"
@@: ;process it
    invoke FindNextFile,...
    test eax,eax
    jnz @b
        call GetLastError
        cmp eax,ERROR_NO_MORE_FILES
        jnz finished ;return the error
        xor eax,eax
finished:
    ret
Since you build your list first, you would have to delete the object from the list, or just leave it there.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: sinsi on April 10, 2024, 05:13:28 AM
You won't be able to tell if you have access to a folder until you actually try and access it, looking at dwFileAttributes won't tell you since it's an NTFS permission, not a file attribute.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 10, 2024, 08:19:30 AM
Quote from: sinsi on April 10, 2024, 05:05:19 AMYou can search C:\Windows and find a folder called appcompat
On your next recursive call you search C:\Windows\appcompat and will get an access denied error.
I was going to say I'll run tests on that, but I just now checked: I can view the contents of this folder (C:\Windows\AppCompat) in Explorer; there's a folder called "Programs" within it. (And I can go even deeper.) So how will I get an access denied error from my program if I can view it with Explorer? What happens if you go there w/Explorer?

I just ran PicView against C:\, and it showed me C:\Windows\AppCompat, down to the folder Programs within, which showed up as an empty folder. Is it possible I have different permissions or something set on my system?

BTW, first time I tried that I got a stack overflow. I lied; stack was not set to 64K DWORDS, but only to 64K bytes. Changed to the former and it worked OK.

Speaking of stack size: can someone tell me what a "typical" stack size is for a Win32 GUI program? (and specifically one that uses recursion). And what is the default stack size if I don't declare a size (using ML.exe)? I'm surprised I don't know these things after all these years.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: sinsi on April 10, 2024, 08:26:10 AM
(https://i.postimg.cc/qgdXWTPr/Untitled.png) (https://postimg.cc/qgdXWTPr)
That was just an example, I couldn't remember the exact string in the [hint]debugger[/hint]
It was C:\Windows\appcompat\appraiser
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 10, 2024, 08:34:22 AM
Yargh: I was hoping to use this folder to test my dir scan, rather than post new versions and have you test them. (That game could get old fast!) My C:\Windows\AppCompat folder has 2 files: AEINV_PREVIOUS.xml and RecentFileCache.bcf, both of which I can access (and both of which have today's timestamp ???).

Any way you know of to create a folder that's "off limits" and is guaranteed to give an access-denied error?

"
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: sinsi on April 10, 2024, 08:47:51 AM
Have you tried to scan your C:\ ?

The other way would be to make a directory and change owner and permissions so that only Administrators have access.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 13, 2024, 07:21:15 AM
OK, folks, we here at NoC Laboratories, GmbH have come up with what we think is a good solid working app, package attached below.

sinsi, I incorporated some of your suggested changes to checking results of FindXXXXFile(), but not all: I'm not bailing out of the GetAllDirsAndFiles() function if I encounter a folder with access denied, because I don't need to. I've tested this, and it turns out that I do have a folder on my D: drive, System Volume Information, which gives me an access-denied error if I try to open it, so I'm pretty sure this works OK. (You'll have to be the judge of that.)

I made another improvement: since this is now a picture viewer, I prune the treeview of any paths that don't contain pictures, so what you'll see is a truncated version of your file system.

There is one little bug which I haven't yet been able to track down: on some scans there's a leftover empty folder at the end. It's annoying but not a show-stopper, so I'm putting this out there.

I think my pruning routine is interesting. When I first coded it, it was too aggressive and ended up eliminating valid paths (those which contained pictures somewhere along the path). What I was doing was scanning my file list from the bottom up, and marking any empty folders (those without any pictures) with the flag bit $prune, meaning that the treeview-construction code would skip over them. I then followed the chain of parent folders up the tree, marking all non-picture-containing folders as $prune until finding one that did contain pictures.

Problem was, I was wrongly eliminating some paths that did contain pictures. My 2nd attempt worked, in that it included all those paths, except that now the treeview structure was flattened out, and everything was all jumbled together.

Finally figured it out: in addition to pruning empty paths, I added another flag bit, $keep. If I found a path that did contain pictures, I flagged the entire path up to the root with $keep, thus "protecting" it. In the treeview-construction code, $keep takes precedence over $prune, so everything works fine.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: zedd on April 13, 2024, 07:33:24 AM
At first glance, it looks good so far.
But then I selected the root of drive E:, nothing happened. Then It dawned on me to enter the directory (by double clicking), and voila. It works as advertised. :)

28,172 pictures found.  :dazzled:
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 13, 2024, 07:44:35 AM
So you're talking about what happens in the folder-selection dialog, right? Yes, it's a slightly non-standard usage of that facility: if you look at the code I had to jump through a bunch of hoops to make it select only folders, not files (had to add a hook procedure and subclass the dialog).

Thanks for checking it out!

One interesting use of this is seeing how many image files are stashed away here and there in your file system. I had no idea there were so many.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: zedd on April 13, 2024, 07:57:10 AM
Quote from: NoCforMe on April 13, 2024, 07:44:35 AMSo you're talking about what happens in the folder-selection dialog, right? Yes, it's a slightly non-standard usage of that facility
Yup, but it works. Might want to include a short instruction manual.  :greensml:
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: jj2007 on April 13, 2024, 08:01:09 AM
Quote from: NoCforMe on April 13, 2024, 07:44:35 AMSo you're talking about what happens in the folder-selection dialog, right?

The attached example uses SHBrowseForFolder. The behaviour is somewhat different.

Your version will confuse some Windows users. Besides, the picview dialog is far too high. I suspect there is a button at the bottom, but I can't see it.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: zedd on April 13, 2024, 08:15:45 AM
Quote from: NoCforMe on April 13, 2024, 07:44:35 AMI had to jump through a bunch of hoops to make it select only folders, not files (had to add a hook procedure and subclass the dialog).
Have you thought about using a tree for directory selection? Or would that get overly complicated?
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 13, 2024, 09:16:42 AM
Quote from: jj2007 on April 13, 2024, 08:01:09 AMBesides, the picview dialog is far too high. I suspect there is a button at the bottom, but I can't see it.
Oh, you mean the entire dialog? No, nothing on the bottom (except a status bar), but if this were production grade, then I should be determining the size of the user's screen and adjusting accordingly.

Next version.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 13, 2024, 09:25:26 AM
Quote from: sudoku on April 13, 2024, 08:15:45 AM
Quote from: NoCforMe on April 13, 2024, 07:44:35 AMI had to jump through a bunch of hoops to make it select only folders, not files (had to add a hook procedure and subclass the dialog).
Have you thought about using a tree for directory selection? Or would that get overly complicated?
No, because 1) it would be extremely complicated and 2) I think the interface I chose is much more appropriate, easier for me to code and easier for the user to navigate.

My usage of the GetOpenFilename() dialog to select folders isn't original with me: I got the idea from this CodeProject article (https://www.codeproject.com/Articles/20853/Win32-Tips-and-Tricks#browse2), which explains how to slightly re-jigger that function to display folders only instead of folders and files. (It's actually not really that nonstandard: I have other software that uses this same functionality.) As the article points out, this interface is actually better for this job than SHBrowseForFolder().
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: jj2007 on April 13, 2024, 10:53:09 AM
Quote from: NoCforMe on April 13, 2024, 09:25:26 AMI got the idea from this CodeProject article (https://www.codeproject.com/Articles/20853/Win32-Tips-and-Tricks#browse2),

Worth reading indeed :thumbsup:
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: sinsi on April 13, 2024, 11:43:12 AM
Crashed :biggrin: if you try and open the tree while a search is taking place.
Put it on its own thread (hard) or disable the tree (easy)

Choose Folder, when opening the combobox for the first time it (the combobox) closes immediately

It would be nice to have an image count in the tree node's text e.g. "Images (44)" as an indication that this folder has images in it.

One more for the wish list, the ability to zoom the picture. On a 4K screen an icon is barely 1cm wide :smiley:


Good job  :thumbsup:
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 13, 2024, 12:41:36 PM
Quote from: sinsi on April 13, 2024, 11:43:12 AMCrashed :biggrin: if you try and open the tree while a search is taking place.
Put it on its own thread (hard) or disable the tree (easy)
The disk-scan code is in its own thread (not hard, ackshooly).
But the treeview-handling code isn't, hence the crash.
Easy fix, though: I just used my "busy" flag which I already had to lock out any treeview selection clicks. If you try it now you'll get a system "ding" until the treeview is safely populated. (I already do this for clicking on the "Choose Folder" button.)
I never tried clicking on the treeview while it was grinding away on folders ... gotta say you're pretty good at breaking code, sinsi (and that's a compliment).
QuoteChoose Folder, when opening the combobox for the first time it (the combobox) closes immediately
Which combobox--the "Look in" one? That one works fine for me.
QuoteIt would be nice to have an image count in the tree node's text e.g. "Images (44)" as an indication that this folder has images in it.
That would be a nice li'l feature, thanks.
QuoteOne more for the wish list, the ability to zoom the picture. On a 4K screen an icon is barely 1cm wide :smiley:
Yes, I've certainly thought of that. Version x+2?

Oh, and JJ, the dialog window is now resizeable, so you should be able to size it to your screen. (I'm not resizing the controls yet, but soon ...)

.exe only attached here
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: sinsi on April 13, 2024, 01:08:35 PM
QuoteWhich combobox--the "Look in" one? That one works fine for me.
Correct
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 13, 2024, 01:22:01 PM
Quote from: sinsi on April 13, 2024, 01:08:35 PM
QuoteWhich combobox--the "Look in" one? That one works fine for me.
Correct
That's weird; works here. It doesn't drop down for you the 1st time? I'll have to "look in"to that.

In the meantime, your wish is my command: check out this version:

It was a very easy add.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: sinsi on April 13, 2024, 01:43:45 PM
QuoteThat's weird; works here. It doesn't drop down for you the 1st time? I'll have to "look in"to that.
First click, drops down then immediately closes. after that behaves normally

QuoteIn the meantime, your wish is my command
:biggrin:
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 13, 2024, 02:03:37 PM
Quote from: sinsi on April 13, 2024, 01:43:45 PM
QuoteThat's weird; works here. It doesn't drop down for you the 1st time? I'll have to "look in"to that.
First click, drops down then immediately closes. after that behaves normally
Ugh. I'm guessing that might be some kind of Windows version problem. Win 7 here; you?
Also maybe due to my subclassing/hooking of the GetOpenFile() proc ...
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 14, 2024, 04:57:56 AM
Quote from: jj2007 on April 13, 2024, 08:01:09 AMBesides, the picview dialog is far too high. I suspect there is a button at the bottom, but I can't see it.
JJ, I'm curious: what's your display resolution?
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: jj2007 on April 14, 2024, 05:48:35 AM
Quote from: NoCforMe on April 14, 2024, 04:57:56 AMwhat's your display resolution?

1920*1080
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 19, 2024, 02:04:19 PM
New version (.exe only) attached here. Everything is implemented that I think I want except for image zooming (coming real soon now ...). And I fixed some problems that were causing extreme flakiness and crashing.

The flakiness apparently had a very simple cause. A while back sinsi advised me that I needed to close the find handle that was returned by FindFirstFile(). Well, I did that, and it solved some problems at the time. However, stupid me; I was just calling CloseFindHandle() without checking whether the handle I was trying to close was valid or not! Now I guess I have to plead guilty to being kind of careless here; a lot of Win32 CloseXXX() functions are very forgiving if you pass them a bogus handle; they just ignore it. Not CloseFindHandle()! It stands for no nonsense. Anyhow, after fixing this, no more crashes or odd behavior (like the app closing when I click on the "Choose Folder" button).

There are two remaining problems, though, neither one a show-stopper, but annoying:

1. The progress bar: For long disk scans, I put up a "Waiting:" prompt and a progress bar that's supposed to move continuously in "marquee" mode. Except that it doesn't. It just sits there.

This all has to do with my use of a separate thread for the disk-scanning code. At this point I'm not sure at all I'm doing the right thing here. Let me explain what's going on in my code.

In pseudocode:
start a new scan:
  BusyFindingFlag = TRUE    ;locks out controls while scan is in progress
  create "root" item in treeview
  PutUpProgressBar():
      show "Waiting:" (static text)
      show progress bar
      set progress bar in marquee mode (PBM_SETMARQUEE)
  CreateThread() for FillFileList():
      (everything at this level is in the new thread)
      FindAllDirsAndFiles()    ;this is the recursive routine that takes a lot of time
      Send $MSG_FillTreeview to the dialog
        which calls FillTreeview() to populate the treeview
      ExitThread()
Hopefully that makes sense. It works find so far as the application goes, but the progress bar control never moves. From reading a lot of stuff online about this (none of it on Micro$oft Learn, however!), it seems that what's happening is that the main thread of the program isn't getting enough cycles to service the progress bar. (My next move is to monitor the messages going to that control.)

Can anyone tell me from looking at this scheme whether I'm doing the right thing here so far as threading goes? The idea is to isolate the code which has to grind away at the disk scan so that the user interface doesn't go unresponsive, which is working. But if the UI is responsive, why isn't that damn progress bar moving?

2. Resizing blues: I came up with some pretty fancy resizing code; try it out. It keeps the widths of the treeview and pic-display windows proportional while maintaining the spacing between controls and the edge of the dialog; that part works great.

What's not so great is the intense flicker that results from resizing, especially if a good-sized image is being displayed. (It's not as bad with a small image or no image.) Any suggestions? Keep in mind that I'm moving or resizing 3 windows in addition to the dialog window (plus the status bar).



     
 
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: sinsi on April 19, 2024, 02:22:50 PM
Does your message pump use GetMessage or PeekMessage?
How do you know when the thread is finished?

Source code, source code, source code  :rolleyes:
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 19, 2024, 02:36:26 PM
No message loop in my code, I'm using a dialog as the main window, so the dialog manager is running the message loop. (Could that be part of the problem?)

The thread finishes when GetAllDirsAndFiles() finishes the disk scan.

I'm trying to avoid getting into the details of the source at this point; would like to deal with this on a conceptual level.

I will give you the complete routine that's running as a separate thread:
FillFileList PROC

INVOKE GetAllDirsAndFiles, 0 ;Start @ file entry[0] ("root").
INVOKE SendMessage, DialogHandle, $MSG_FillTreeview, 0, 0
INVOKE ExitThread, 0
RET

FillFileList ENDP
BTW, is that RET even ever reached? can I remove it?
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: sinsi on April 19, 2024, 03:39:16 PM
If FillFileList is your ThreadProc it takes one argument, you have none.
Lucky for you, you use ExitThread instead of a RET.

FillTreeView should be on the main GUI thread, it has nothing to do with the spawned thread.

Of course a dialog has a message pump, surely (DlgProc)?

Concepts are fine, it's the implementation that matters. Source code is that implementation.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 19, 2024, 06:44:12 PM
None of which explains why my progress bar doesn't marquee, does it?
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: sinsi on April 19, 2024, 06:52:52 PM
I'm not a fucking mind reader.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 19, 2024, 07:05:19 PM
Well hey, don't get sore there. Nobody expects you to read minds. And your advice above was good. Just doesn't seem to address my immediate problem.

Any other ideas? I'll post source later, but in the meantime, what would cause a progress bar not to animate? (And yes, I verified that it does have the PBS_MARQUEE style bit set.) Since my thread frees the UI from the computation-heavy disk scan, you'd think there'd be plenty of cycles to make that marquee thing happen.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: sinsi on April 19, 2024, 07:15:18 PM
What happens after you create the thread?
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 19, 2024, 07:28:28 PM
All I know is what happens visually: the progress bar appears but is static.

I'm thinking of subclassing the progress bar and logging all the messages sent to it after it gets put up.

The sequence of events I wrote in pseudocode above should give you a good idea of what's happening in the program:
During the time when the thread is still active you can click on either the "Choose Folder" button or the treeview and it'll ding at you (intentionally, using INVOKE MessageBeep, MB_ICONASTERISK), which proves that the UI is active and receptive during this time.

That's pretty much it. What else can I tell you?
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: sinsi on April 19, 2024, 07:39:12 PM
Quote from: NoCforMe on April 19, 2024, 07:28:28 PMThe sequence of events I wrote in pseudocode above should give you a good idea of what's happening in the program:
So now you can read my mind?

Quote from: NoCforMe on April 19, 2024, 07:28:28 PMProgress bar and "Waiting:" text appear
What, like magic?

Quote from: NoCforMe on April 19, 2024, 07:28:28 PMThat's pretty much it. What else can I tell you?
:rolleyes: Don't tell me, show me
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: TimoVJL on April 19, 2024, 10:55:19 PM
Use OutputDebugString with variables to see, what really happens.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 20, 2024, 04:13:34 AM
Quote from: TimoVJL on April 19, 2024, 10:55:19 PMUse OutputDebugString with variables to see, what really happens.
Oh, I can do better than that with my LogBuddy®© logging accessory. Shows incoming messages to window procs, displays variable values.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 20, 2024, 07:18:16 AM
I went ahead and plugged my pic viewer into LogBuddy (specifically, the subclassed window proc for the progress bar), and here's what it gave me:
Message: WM_GETDLGCODE hWin: 10484h, wParam: 0h, lParam: 0h
Message: WM_SHOWWINDOW hWin: 10484h, wParam: 1h, lParam: 0h
Message: WM_WINDOWPOSCHANGING hWin: 10484h, new X: 0, new Y: 0
Message: WM_NCPAINT hWin: 10484h, wParam: 1h, lParam: 0h
Message: WM_ERASEBKGND hWin: 10484h, wParam: 29010CBEh, lParam: 0h
Message: WM_WINDOWPOSCHANGED hWin: 10484h, new X: 165, new Y: 9
Message: (Unknown: value = 1034) hWin: 10484h, wParam: 1h, lParam: 64h
Message: WM_PAINT hWin: 10484h, wParam: 0h, lParam: 0h
Message: (Unknown: value = 1034) hWin: 10484h, wParam: 0h, lParam: 0h
Message: WM_SHOWWINDOW hWin: 10484h, wParam: 0h, lParam: 0h
Message: WM_WINDOWPOSCHANGING hWin: 10484h, new X: 0, new Y: 0
Message: WM_WINDOWPOSCHANGED hWin: 10484h, new X: 165, new Y: 9
Message: WM_GETDLGCODE hWin: 10484h, wParam: 0h, lParam: 0h
That was it for one long disk scan during which the progress bar was put up.

I wonder what that "unknown" (to me) message (1034 decimal) is? Welll, according to this page (https://wiki.winehq.org/List_Of_Windows_Messages), it could be any of these:
040a        1034        CBEM_HASEDITCHANGED
040a        1034        RB_INSERTBANDW
040a        1034        SB_GETRECT
040a        1034        TB_ISBUTTONCHECKED
040a        1034        TBM_SETSEL
040a        1034        TTM_HITTESTA
040a        1034        WIZ_QUERYNUMPAGES

Seems like I should be getting a lot more messages than these.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 20, 2024, 07:31:05 AM
Message 1034 is just PBM_SETMARQUEE (makes sense), according to this useful page (https://www.magnumdb.com/search?q=1034).
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: zedd on April 20, 2024, 07:38:52 AM
Before WM_PAINT, wParam is 1, lParam 100
After WM_PAINT, wParam 0 and lParam 0...

Hmmm.... it's been a long time that I worked with progress bars...
But that doesn't look right.

The static progress bar, any indicators 'lit up' or just showing the bar and nothing else.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 20, 2024, 07:42:57 AM
The progress bar shows nothing. Completely blank.

For WM_PAINT, neither wParam nor lParam are used. (All the needed info is in the PAINTSTRUCT structure that's filled out by BeginPaint().)
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: zedd on April 20, 2024, 07:50:31 AM
Quote from: NoCforMe on April 20, 2024, 07:42:57 AMThe progress bar shows nothing. Completely blank.

For WM_PAINT, neither wParam nor lParam are used. (All the needed info is in the PAINTSTRUCT structure that's filled out by BeginPaint().)


quote from stack overflow (https://stackoverflow.com/questions/5681467/pbs-marquee-progressbar-winapi)
QuoteOne final hunch at why your marquee progress bar is not working. Did you include a manifest for common controls v6? The marquee style is only supported in common controls v6 and up.
manifest issue? Just a shot in the dark on my part...
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 20, 2024, 07:53:34 AM
I have that manifest, so no.

  <?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
- <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity version="1.0.0.0" processorArchitecture="*" name="FearNoEvil.DialogGen.1.0" type="win32" />
  <description />
- <dependency>
- <dependentAssembly>
  <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*" />
  </dependentAssembly>
  </dependency>
  </assembly>

God, I hate XML ...
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: zedd on April 20, 2024, 08:00:05 AM
 from codeguru  (https://forums.codeguru.com/showthread.php?324262-PBM_SETMARQUEE-(Marquee-Animation)-not-working-for-Progressbar-!)
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 20, 2024, 08:03:28 AM
Thanks. Read that a long time ago, along with pretty much every other article on Stack Overflow and elsewhere. No help.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: zedd on April 20, 2024, 08:06:17 AM
It is probably something simple but overlooked.
Have you tried making a test program? A simple window and only the progress bar?

I gotta go walk the dogs, I might make a little test proggy myself when I get back...


Later:
I got shanghai'd into doing something else... I'll look at making a test program later this evening...
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: jj2007 on April 20, 2024, 09:04:11 AM
Quote from: NoCforMe on April 20, 2024, 08:03:28 AMNo help

It worked for me, see attached exe
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 20, 2024, 10:33:05 AM
Your does work indeed. But Jochen, do you have a separate thread running in that program? That seems to be the source of my problems.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: jj2007 on April 20, 2024, 10:46:06 AM
Quote from: NoCforMe on April 20, 2024, 10:33:05 AMdo you have a separate thread running in that program?

No, but a WM_TIMER handler:

  GuiControl Progress, "progressbar", y0+88, h0+29, w700, style PBS_MARQUEE
...
Event Timer
  sub rv(GetTickCount), ticks
  invoke SendMessage, hProgress, PBM_SETPOS, eax, 0
  SetWin$ hTimeMs=fTime$(0, "HH:mm:ss.fff") ; shows milliseconds

Event Message
  .if uMsg_==WM_HSCROLL ; horizontal trackbar sends this message
mov eax, lParam_
.if eax==hTrack
mov ticks, rv(GetTickCount) ; try to sync with progressbar ;-)
shl rv(SendMessage, lParam_, TBM_GETPOS, 0, 0), 9
sub ticks, eax
.endif
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 20, 2024, 01:02:34 PM
But it looks like you're using PBM_SETPOS, not PBM_SETMARQUEE. So how does that help me?
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: TimoVJL on April 20, 2024, 02:59:11 PM
Minimal example in C
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <commctrl.h>
// https://stackoverflow.com/questions/30135497/pbm-setmarquee-is-not-working-for-vertical-processbars
#define DLG_MAIN 1001
#pragma comment(linker,"\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")

LRESULT CALLBACK MainDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);

INITCOMMONCONTROLSEX initCtrlEx = {sizeof(INITCOMMONCONTROLSEX), ICC_PROGRESS_CLASS};
HWND hProcessBar;

int __cdecl WinMainCRTStartup(void)
{
    HINSTANCE hInstance = GetModuleHandle(NULL);
    InitCommonControlsEx(&initCtrlEx);
    ExitProcess(DialogBoxParam(hInstance, MAKEINTRESOURCE(DLG_MAIN), NULL, (DLGPROC)MainDlgProc, 0));
}

LRESULT CALLBACK MainDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
        case WM_INITDIALOG:
            hProcessBar = GetDlgItem(hwndDlg, 4001);
            SendMessageA(hProcessBar, PBM_SETMARQUEE, TRUE, (LPARAM)30);//enable marquee mode
            return TRUE;
        case WM_CLOSE:
            EndDialog(hwndDlg, 0);
            return TRUE;
    }
    return FALSE;
}
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 20, 2024, 03:35:03 PM
1. That tells me nothing I don't already know or that isn't already in my code. Absolutely nothing.
2. Dang it, don't you ever post assembly-language code? Sheesh; this is an asm forum, you know?
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: six_L on April 20, 2024, 03:44:08 PM
Hi,NoCforMe
QuotePBS_MARQUEE
   Version 6.0 or later. The progress indicator does not grow in size but instead moves repeatedly along the length of the bar, indicating activity without specifying what proportion of the progress is complete.
Note: Comctl32.dll version 6 is not redistributable but it is included in Windows or later. To use Comctl32.dll version 6, specify it in a manifest. For more information on manifests, see Enabling Visual Styles.
+manifest.xml to rc
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
    version="1.0.0.0"
    processorArchitecture="*"
    name="CompanyName.ProductName.YourApplication"
    type="win32"
/>
<description>Your application description here.</description>
<dependency>
    <dependentAssembly>
        <assemblyIdentity
            type="win32"
            name="Microsoft.Windows.Common-Controls"
            version="6.0.0.0"
            processorArchitecture="*"
            publicKeyToken="6595b64144ccf1df"
            language="*"
        />
    </dependentAssembly>
</dependency>
</assembly>
.elseif eax == WM_TIMER
.if pFlag == TRUE
;off
invoke  SendDlgItemMessage, hMain, ID_PROGRESS,PBM_SETMARQUEE,FALSE,0
mov pFlag,FALSE
.else
;on
invoke  SendDlgItemMessage, hMain, ID_PROGRESS,PBM_SETMARQUEE,TRUE,0
mov pFlag,TRUE
.endif

regard

Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 20, 2024, 03:52:03 PM
1. I already said somewhere up there that I already have a manifest included as a resource.
2. I'm curious about the code you posted: Why are you putting the calls to PBM_SETMARQUEE inside a WM_TIMER handler? Are you saying you have to set up a timer to run the progress bar? My understanding is that all you need to do is to send that message with wParam = TRUE and the control takes care of the animation all on its own. Or is that not correct?

This is from the Microsoft documentation for that message:
QuoteSets the progress bar to marquee mode. This causes the progress bar to move like a marquee.

Parameters:
wParam
Indicates whether to turn the marquee mode on or off.
lParam
Time, in milliseconds, between marquee animation updates. If this parameter is zero, the marquee animation is updated every 30 milliseconds.

Use this message when you do not know the amount of progress toward completion but wish to indicate that progress is being made.
Notice it doesn't say anything about having to constantly toggle the control to make it move; the PBM_SETMARQUEE(TRUE) message is supposed to be sufficient to animate it.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: TimoVJL on April 20, 2024, 04:55:55 PM
Quote from: NoCforMe on April 20, 2024, 03:35:03 PM1. That tells me nothing I don't already know or that isn't already in my code. Absolutely nothing.
2. Dang it, don't you ever post assembly-language code? Sheesh; this is an asm forum, you know?
pFile    Data    Description    Value
00001F9C    0000360A    Hint/Name RVA    0005 CreateStatusWindowA
00001FA0    00003630    Hint/Name RVA    0031 ImageList_Create
00001FA4    00003620    Hint/Name RVA    002C ImageList_Add
00001FA8    00000000    End of Imports    comctl32.dll
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 20, 2024, 05:04:57 PM
OK, I'm curious: is that from my .exe? What's that supposed to tell me? I recognize those 3 functions that are in my program. Is that everything imported from comctl32.dll? Is something missing?
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: TimoVJL on April 20, 2024, 05:12:10 PM
I don't see InitCommonControlsEx
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 20, 2024, 05:38:58 PM
Not needed.
That initialization is done by the dialog manager.
Just for laughs, I put it in just now and tried it. Made no damn difference. Progress bar still doesn't animate.
I stopped using that (InitCommonControlsEx) a long time ago.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: sinsi on April 20, 2024, 05:44:38 PM
All of these theories, wouldn't it be good if we had some source code... :rolleyes:
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: jj2007 on April 20, 2024, 05:56:38 PM
Quote from: NoCforMe on April 20, 2024, 01:02:34 PMBut it looks like you're using PBM_SETPOS, not PBM_SETMARQUEE

Oops, that's right - the timer handler with PBM_SETPOS is no longer necessary :thumbsup:

Quote from: NoCforMe on April 20, 2024, 03:52:03 PMWhy are you putting the calls to PBM_SETMARQUEE inside a WM_TIMER handler? Are you saying you have to set up a timer to run the progress bar? My understanding is that all you need to do is to send that message with wParam = TRUE and the control takes care of the animation all on its own

Your understanding is correct. Strangely enough, I can see the effect of PBM_SETMARQUEE in spite of the timer handler, but the latter can definitely go. It seems that I simulated the marquee effect with the timer...
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 20, 2024, 05:57:16 PM
Here it is. Go to it, tear it apart. Complete package attached.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 20, 2024, 06:00:56 PM
Quote from: jj2007 on April 20, 2024, 05:56:38 PM
Quote from: NoCforMe on April 20, 2024, 01:02:34 PMBut it looks like you're using PBM_SETPOS, not PBM_SETMARQUEE
Oops, that's right - the timer handler with PBM_SETPOS is no longer necessary :thumbsup:
Which gets us back to what six_l posted above (https://masm32.com/board/index.php?msg=129411): is it necessary to put the PBM_SETMARQUEE message call in a timer handler like he did? Again, the Micro$oft docs say nothing at all about this.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: sinsi on April 20, 2024, 07:11:54 PM
A couple of things, the open folder dialog shows a blank list and doesn't like being resized (see pic)
The second, a bit more serious
(37f4.461c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=6e020f93 ebx=6e020f93 ecx=0003ba50 edx=00000000 esi=00a21145 edi=001404a2
eip=00a235bb esp=006fedd0 ebp=006fedd8 iopl=0        nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b            efl=00210206
PicView!PruneFileList+0x5b:
00a235bb f7831401000010000000 test dword ptr [ebx+114h],10h ds:002b:6e0210a7=????????

; Prune back the chain until we find a folder w/pictures:
    MOV    EAX, [EBX].FILEINFO.parent
    TEST    EAX, EAX            ;Hit the root?
    JZ    next                ;  Yep, go to next prev. entry.
    ADD    EAX, FileHeap
    MOV    EBX, EAX
    TEST    [EBX].FILEINFO.flag, $keep ;<<<<<< crash <<<<<<

(https://i.postimg.cc/TK9h3WxF/Untitled.png) (https://postimg.cc/TK9h3WxF)

Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: six_L on April 20, 2024, 10:15:09 PM
Hi,NoCforMe
QuoteWhy are you putting the calls to PBM_SETMARQUEE inside a WM_TIMER handler?
show you the effect of ProgressBar with PBS_MARQUEE style again and again.

1) toggle the control to make it move.
invoke  SendDlgItemMessage, hMain, ID_PROGRESS,PBM_SETMARQUEE,TRUE,0

2) toggle the control to make it stop.
invoke  SendDlgItemMessage, hMain, ID_PROGRESS,PBM_SETMARQUEE,FALSE,0
the attachment is the demo exe(x64).
regard.
Title: PBM_SETMARQUEE progress bar
Post by: zedd on April 21, 2024, 01:25:42 AM
Since no one else supplied a easy 32 bit masm32 example... with only the needed code
Easy peasy

A simple dialog box with a marquee type of progress bar.

The progress bar placement, etc.,  courtesy TimoVJL's... c example. I simply plugged in two lines of his code into my template.

NoCforMe is correct, no INITCOMMONCONTROLSEX needed, nor InitCommonControls it appears.

Tested only on Windows 7, need feedback on Windows 10/11, or even xp...


    include \masm32\include\masm32rt.inc
        DlgProc    proto :dword, :dword, :dword, :dword

    .data
        hWnd        dd 0
        hInstance  dd 0
        DisplayName db "Dialog Box", 0

    .code
    start:
        invoke GetModuleHandle, 0
        mov hInstance, eax
        invoke DialogBoxParamA, hInstance, 1000, 0, addr DlgProc, 0
        invoke ExitProcess, eax

    DlgProc proc hWin:dword, uMsg:dword, wParam:dword, lParam:dword
    local rct:RECT, hProcessBar:dword
      .if uMsg == WM_INITDIALOG
        mov hProcessBar, rv(GetDlgItem,hWin, 4001)
        invoke SendMessageA, hProcessBar, PBM_SETMARQUEE, TRUE, 30
      .elseif uMsg == WM_COMMAND
      .elseif uMsg == WM_CLOSE
        invoke EndDialog, hWin, 0
        xor eax, eax
        ret
      .endif
        xor eax, eax
        ret
    DlgProc endp

    end start
Slight update. mov eax, 1 and ret not needed in WM_INITDIALOG  removed from code.
I said I would get back to this yesterday, but real life interfered.

Example replaced in This thread  (https://masm32.com/board/index.php?topic=11864.0)a more polished example. Attachment removed
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: TimoVJL on April 21, 2024, 02:29:26 AM
Things seems to changed in NT era.
Progressbar don't even need commctrl32.dll, so manifest is useless in that case too.

Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: zedd on April 21, 2024, 02:32:13 AM
Quote from: TimoVJL on April 21, 2024, 02:29:26 AMThings seems to changed in NT era.
Progressbar don't even need commctrl32.dll, so manifest is useless in that case too.
Thanks for the tip.  :thumbsup:

Nevermind. Read following posts...
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: TimoVJL on April 21, 2024, 02:35:02 AM
Quote from: sudoku on April 21, 2024, 02:32:13 AM
Quote from: TimoVJL on April 21, 2024, 02:29:26 AMThings seems to changed in NT era.
Progressbar don't even need commctrl32.dll, so manifest is useless in that case too.
Thanks for the tip.  :thumbsup:
Forgot to test, as i didn't renamed local manifest file, so that was still needed with Windows 7.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: zedd on April 21, 2024, 02:36:43 AM
You're right TimoVJL, I just tested without manifest... didn't work.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: zedd on April 21, 2024, 02:59:12 AM
a little more testing...

invoke SendMessageA, hProcessBar, PBM_SETMARQUEE, TRUE, 30

lParam sets the speed of the animation. higher = slower. zero = fastest.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 21, 2024, 03:15:46 AM
Quote from: sudoku on April 21, 2024, 02:59:12 AMinvoke SendMessageA, hProcessBar, PBM_SETMARQUEE, TRUE, 30

lParam sets the speed of the animation. higher = slower. zero = fastest.
Zero = default:
QuoteIf this parameter is zero, the marquee animation is updated every 30 milliseconds.
You could make it faster by setting it to 30 > value > 0.

Anyhow. Your demo proves that we absolutely do not need to mess around with timers to make PBM_SETMARQUEE work, so let's just drop that, OK?

There's still some confusion over the XML manifest and calling InitCommonControlsEx(). I have that manifest included in my resource file, as it gives me the Vista-like "visual styles" (otherwise you get the boxy square controls). But what I still insist is not needed is the call to InitCommonControlsEx(). I've been writing programs for the past several years without using that, and they all work fine (at least as control rendering and processing goes).
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 21, 2024, 03:24:50 AM
Quote from: sinsi on April 20, 2024, 07:11:54 PMThe second, a bit more serious
(37f4.461c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=6e020f93 ebx=6e020f93 ecx=0003ba50 edx=00000000 esi=00a21145 edi=001404a2
eip=00a235bb esp=006fedd0 ebp=006fedd8 iopl=0        nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b            efl=00210206
PicView!PruneFileList+0x5b:
00a235bb f7831401000010000000 test dword ptr [ebx+114h],10h ds:002b:6e0210a7=????????

; Prune back the chain until we find a folder w/pictures:
    MOV    EAX, [EBX].FILEINFO.parent
    TEST    EAX, EAX            ;Hit the root?
    JZ    next                ;  Yep, go to next prev. entry.
    ADD    EAX, FileHeap
    MOV    EBX, EAX
    TEST    [EBX].FILEINFO.flag, $keep ;<<<<<< crash <<<<<<
Dang.
I wish I could replicate this on my system, I really do. Since fixing that CloseFindHandle() problem I've had zero crashes or faults, so it's very difficult for me to say how this is happening.
I'll keep looking into it, though.

Ditto for that weird problem you're having with the select-folder dialog; I've never seen that happen. What OS are you running?
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: TimoVJL on April 21, 2024, 04:02:06 AM
Quote from: NoCforMe on April 21, 2024, 03:15:46 AMThere's still some confusion over the XML manifest and calling InitCommonControlsEx(). I have that manifest included in my resource file, as it gives me the Vista-like "visual styles" (otherwise you get the boxy square controls). But what I still insist is not needed is the call to InitCommonControlsEx(). I've been writing programs for the past several years without using that, and they all work fine (at least as control rendering and processing goes).
That InitCommonControlsEx() isn't needed, as that control doesn't even need comctl32.dll in Windows 7
Some controls have moved silently to other dlls.
Perhaps some OllyDbg users check that dll thing.
Some controls needs a reference to comctrl32.dll in some cases, but Progressbar don't.


Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: zedd on April 21, 2024, 04:28:43 AM
So, NoCforMe...

Did you get it working in your program??
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 21, 2024, 04:38:57 AM
Quote from: sudoku on April 21, 2024, 04:28:43 AMSo, NoCforMe...
Did you get it working in your program??
No! What would give you that idea?
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: zedd on April 21, 2024, 04:51:15 AM
Quote from: NoCforMe on April 21, 2024, 04:38:57 AM
Quote from: sudoku on April 21, 2024, 04:28:43 AMSo, NoCforMe...
Did you get it working in your program??
No! What would give you that idea?
Just asking, jeez.

Have you tried calling SendMessage in a different manner than in your program? Or from a different location.
Is the handle somehow getting overwritten?

Just want to help you debug this thing. Gotta be something simple...methinks.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: sinsi on April 21, 2024, 05:08:42 AM
OK, tracked down the crash
INVOKE strcpy, ADDR [EDX].FILEINFO.pathName, ADDR [EBX].FILEINFO.pathName
INVOKE _strcat, OFFSET BackslashStr, ADDR [EBX].FILEINFO.pathName
INVOKE _strcat, OFFSET FD.cFileName, ADDR [EBX].FILEINFO.pathName
;*** added ***
lea eax,[EBX].FILEINFO.pathName
call strlen
cmp eax,MAX_PATH
jbe @f
 int 3
@@:
;*************
Run in the debugger, stops at the breakpoint with EAX=0115 (277, well over MAX_PATH)
This overwrites some pretty important data in your structure  :biggrin:

The select folder happens for any program that uses the old-style dialog, not just yours.



Quote from: WindowsEdition    Windows 11 Pro
Version    23H2
OS build 22631.3447
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: zedd on April 21, 2024, 05:48:17 AM
Something weird is happening...

I changed the code to always show the progress bar (from just getting the handle from eax), and hide the others next to it.
The bar displays but does not animate, and it should.
    INVOKE    GetDlgItem, hWin, $progbar
    MOV    ProgressBarHandle, EAX
    INVOKE    SendMessage, ProgressBarHandle, PBM_SETMARQUEE, TRUE, 0
    INVOKE    ShowWindow, ProgressBarHandle, SW_SHOW
Now scroll the window closed from the bottom then open it.
A frozen animation should now appear... it did for me. I repeated this several times to be sure.

Somehow it is not getting painted properly
attachment no longer needed - removed
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 21, 2024, 05:50:00 AM
Now that is interesting, and certainly related to what's happening to my program. Will look at it shortly.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: zedd on April 21, 2024, 05:52:56 AM
Quote from: NoCforMe on April 21, 2024, 05:50:00 AMNow that is interesting, and certainly related to what's happening to my program. Will look at it shortly.
:thumbsup:
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 21, 2024, 05:53:43 AM
Quote from: sinsi on April 21, 2024, 05:08:42 AMOK, tracked down the crash
    INVOKE    strcpy, ADDR [EDX].FILEINFO.pathName, ADDR [EBX].FILEINFO.pathName
    INVOKE    _strcat, OFFSET BackslashStr, ADDR [EBX].FILEINFO.pathName
    INVOKE    _strcat, OFFSET FD.cFileName, ADDR [EBX].FILEINFO.pathName
;*** added ***
lea eax,[EBX].FILEINFO.pathName
call strlen
cmp eax,MAX_PATH
jbe @f
 int 3
@@:
;*************
Run in the debugger, stops at the breakpoint with EAX=0115 (277, well over MAX_PATH)
This overwrites some pretty important data in your structure  :biggrin:
Aha, so it's basically an overlength pathname somewhere in your directory structure, that apparently I don't have on any of my drives.

You don't happen to know the actual pathname that's causing this, do you?

I suppose that your fix is all that can be done at this time to avoid this. Otherwise I'd have to increase the size of all my pathname buffers, further increasing my already large memory requirements. (Which raises the question: how long should the longest expected pathname on a Windows file system be? Apparently MAX_PATH isn't sufficient always.)
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: zedd on April 21, 2024, 06:17:57 AM
from codeguru  (https://forums.codeguru.com/showthread.php?324262-PBM_SETMARQUEE-(Marquee-Animation)-not-working-for-Progressbar-!)

Quote from: codegurus websiteRe: PBM_SETMARQUEE (Marquee Animation) not working for Progressbar?!?
Actually i figured it out...Turns out since i had the progress bar as a resource instead of using the CreateWindowEx(..) i had to use SetWindowLongPtr(..) to set the PBS_MARQUEE style for this control...now it works  Yipeee to me!

worth a try??? But actually, it doesnt make sense. It worked in my example without any acrobatics... so nevermind.
Not a lot of information out there regarding this kind of issue.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: zedd on April 21, 2024, 06:31:23 AM
oops. quoted above post, instead of modify post..   :eusa_snooty:
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 21, 2024, 07:22:05 AM
Quote from: sudoku on April 21, 2024, 06:17:57 AMfrom codeguru  (https://forums.codeguru.com/showthread.php?324262-PBM_SETMARQUEE-(Marquee-Animation)-not-working-for-Progressbar-!)
Quote from: codegurus websiteRe: PBM_SETMARQUEE (Marquee Animation) not working for Progressbar?!?
Actually i figured it out...Turns out since i had the progress bar as a resource instead of using the CreateWindowEx(..) i had to use SetWindowLongPtr(..) to set the PBS_MARQUEE style for this control...now it works  Yipeee to me!

worth a try???
No. Somewhere up there I mentioned that I explicitly checked to see that this style was set in the progress bar control, and indeed it was. Got nothing to do with being a resource or not. (It's true that the dialog manager does screw with some control styles, like removing borders that are explicitly set with WS_BORDER, but this isn't one of them.)
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: sinsi on April 21, 2024, 07:47:12 AM
Quote from: NoCforMe on April 21, 2024, 05:53:43 AMYou don't happen to know the actual pathname that's causing this, do you?
The path to the parent folder is 257 characters and a folder in the parent is 20.
I imagine that if you tried FindFirstFile on the full parent\folder\spec you would get an error.

Reparse points can be tricky too, if you follow the rabbit.


There used to be a nasty trick where Windows would let you create a path that was a real PITA to remove, a batch file with
:again
md x
cd x
goto again
or something similar.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 21, 2024, 09:31:02 AM
Quote from: sinsi on April 21, 2024, 07:47:12 AMReparse points can be tricky too, if you follow the rabbit.
So how do I identify one of those critters so I can avoid it?

When I was developing an earlier app (a file finder) that used a similar recursive technique, I ran across some files (or folders?) that either started with ":" or consisted only of that character (which of course is an illegal character outside of drive letter identifiers). Any idea what those were?

(That's why I filter out those things, whatever they are.)
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: zedd on April 21, 2024, 10:00:44 AM
NoCforMe:

In the modified version of PicView that I attached above, in post #163 - if the program is in a folder that has images or that folder has a subfolder that has images in it, click on an image icon in the tree view. The animation starts up!!

I noticed this by pure accident.

I still haven't found what is causing this though.
Something in your program is interfering with the painting of the progress bar. I am tempted to remove all the other controls one by one, to see if any of them are causing this naughty misbehaviour.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 21, 2024, 10:40:58 AM
OK, I'm curious: what did you do to my program to make it do this odd thing?

Of course, it doesn't animate at the right time, but it does do the marquee thing for sure ...
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: zedd on April 21, 2024, 10:47:28 AM
Quote from: NoCforMe on April 21, 2024, 10:40:58 AMOK, I'm curious: what did you do to my program to make it do this odd thing?

Of course, it doesn't animate at the right time, but it does do the marquee thing for sure ...
Your program does the odd thing, by misbehaving in the first place.
See the code in #163. That is all I did, beside changing SW_SHOW to SW_HIDE for the other controls, to get them out of the way.

The modified source attached - 8 changes in the source, all marked ";;;;;;;;;;;;;;;;;; changed"
      This was done in an attempt to make the progress bar marquee animate.
     
attachment no longer needed - removed
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: zedd on April 21, 2024, 12:03:37 PM
I think I found something...
In your (resource) include file:


Never mind. I tried it again (the inc file changes), but failed. No joy.  :sad:  I'm done with this for now...
If I had the time and patience ( I have time, but little patience), I would comment everything out of the program except for the dialog box code and the progress bar code. Progress bar should be marqueeing then. Then little by little, introduce the other controls, and associated functions. Until the marquee stops working. I cant think of any other way to find the culprit.
I'll chew on some other ideas for a while... it is obvious that something in the code isn't playing nice with the progress bar.
I'll take another look at it tomorrow. You have a bigger issue with paths it seems.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: sinsi on April 21, 2024, 12:32:02 PM
Quote from: NoCforMe on April 21, 2024, 09:31:02 AM
Quote from: sinsi on April 21, 2024, 07:47:12 AMReparse points can be tricky too, if you follow the rabbit.
So how do I identify one of those critters so I can avoid it?

When I was developing an earlier app (a file finder) that used a similar recursive technique, I ran across some files (or folders?) that either started with ":" or consisted only of that character (which of course is an illegal character outside of drive letter identifiers). Any idea what those were?

(That's why I filter out those things, whatever they are.)
There is a file attribute to show directory junctions and file links, FILE_ATTRIBUTE_REPARSE_POINT.
The colon character is used with NTFS streams.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 21, 2024, 01:02:29 PM
Thank you. They're now filtered out:
; Eliminate reparse point entries:
filter: TEST FD.dwFileAttributes, FILE_ATTRIBUTE_REPARSE_POINT
JNZ nxtfil
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: zedd on April 21, 2024, 01:46:11 PM
I found something. Using a pristine (freshly extracted from your .zip file in post #146) "PicView package" folder, open the executable. Images must be in the folder where the program is located

1. click on any icon displayed in the file tree.  <--- it just works this way
2. Then choose a large folder or directory. (large so it takes some time, too small & bar won't display - takes very little time to process the list)
3. Then click 'Select'

voila! it works that way. Very similar to what I had found earlier, but no changes to the source code this time.
Its not the solution, but may give you a clue that you need to trigger the progress bar display elsewhere (or some other change).

I couldnt sleep, this was nagging me...

Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 21, 2024, 02:10:56 PM
Goldang, you're 150% right! For some really weird reason, that works!
Hmmm, scratching my head here ...

Thanks!

Somehow, selecting a picture to display at the get-go (that's what does it) somehow initializes things so the progress bar works. And it works every time after that.

Ackshooly, anytime you click on a pic, thereafter the progress bar works. Hmmmm ... something in the pic display proc, methinks ... perhaps something related to GDI+ ...

Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: zedd on April 21, 2024, 02:21:06 PM
Quote from: NoCforMe on April 21, 2024, 02:10:56 PMThanks!

I'll be looking for that big fat check in the mail.   :greensml:
Now go fix the other (bigger) problem first. You can narrow this one down later.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 21, 2024, 02:36:07 PM
My guess is the answer may lie somewhere in this code: this is what happens when the user clicks on a treeview item containing a picture:
; Apparently someone clicked on our treeview: EDX--> NMTREEVIEW structure:
; No can do if we're busy:
CMP BusyFindingFlag, TRUE
JNE @F
INVOKE MessageBeep, MB_ICONASTERISK
JMP zero_exit

@@: LEA EAX, [EDX].NMTREEVIEW.itemNew ;Point to the TVITEM struct. within it.
MOV [EAX].TVITEM._mask, TVIF_PARAM or TVIF_HANDLE
PUSH EAX ;Save ptr.
INVOKE SendMessage, TreeviewHandle, TVM_GETITEM, 0, EAX
POP EDX ;EDX--> TVITEM
MOV EDX, [EDX].TVITEM.lParam ;EDX--> our FILEINFO element.
PUSH EDX
INVOKE SetWindowText, PathDisplayHandle, ADDR [EDX].FILEINFO.pathName
POP EDX

; Is it a folder or a file?
TEST [EDX].FILEINFO.flag, $folder
JNZ zero_exit

; It's a file, so show the picture--must make filename Unicode:
MOV fiOffset, EDX ;Save ptr. for later.
INVOKE MakeUnicodeName, ADDR [EDX].FILEINFO.pathName, ADDR unicodeName

; Load image:
INVOKE GdipLoadImageFromFile, ADDR unicodeName, OFFSET GdiHbitmap

; Get width & height of bitmap:
INVOKE GdipGetImageWidth, GdiHbitmap, OFFSET ImgStruct.imgW
INVOKE GdipGetImageHeight, GdiHbitmap, OFFSET ImgStruct.imgH

; Get width & height of display window:
INVOKE GetClientRect, PicDisplayHandle, ADDR gpRect
MOV EAX, gpRect.right
SUB EAX, gpRect.left
SUB EAX, $imgBorder * 2
MOV ImgStruct.winW, EAX
MOV EAX, gpRect.bottom
SUB EAX, gpRect.top
SUB EAX, $imgBorder * 2
MOV ImgStruct.winH, EAX

; Scale image to our window:
INVOKE ScaleImg2Win, OFFSET ImgStruct

; Show it:
INVOKE InvalidateRect, PicDisplayHandle, NULL, TRUE

; Show pic info below preview:
MOV EDX, fiOffset
LEA EAX, [EDX].FILEINFO.pathName
ADD EAX, [EDX].FILEINFO.rootLoc
INVOKE wsprintf, ADDR buffer, OFFSET PicInfoFmt, EAX, ImgStruct.imgW, ImgStruct.imgH
INVOKE SetWindowText, PicInfoHandle, ADDR buffer
MOV PictureIsUp, TRUE
JMP zero_exit

Something here has a beneficial effect on the progress bar and makes it work thereafter. Somehow. Notice that nowhere does the handle to that control (ProgressBarHandle) appear.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: zedd on April 21, 2024, 03:05:35 PM
It's just after midnight here, I gotta go. I'll look into this further, tomorrow. Or should I say later today.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: zedd on April 21, 2024, 10:22:33 PM
Using another pristine source code: (from attachment in post #146)


DisplayWindowProc   PROC hWin:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD
   LOCAL   hDC:HDC, gdiHgraphics:DWORD, ps:PAINTSTRUCT, gpRect:RECT

   MOV   EAX, uMsg
 ;    CMP   EAX, WM_PAINT  ;;;changed
 ;    JE   do_paint       ;;;changed
   CMP   EAX, $MSG_ClearPicWindow
   JE   do_clear


I commented out the "je do_paint"...
Getting closer to a real solution.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: zedd on April 21, 2024, 10:46:21 PM
From a clean unmodified source: (from attachment in post #146)

;==============================
;  WM_PAINT handler
;==============================
do_paint:
 ;    CMP    PictureIsUp, FALSE  ;; <--- commented out
 ;    JE    zero_exit            ;; <--- commented out

marquee is 'marqueeing' now --- when it is supposed to...
You will have to test NoCforMe, how this affects anything else...


Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 22, 2024, 06:25:52 AM
Well, OK, you're obviously on the right track: I just tried displaying a picture in that window before the initial disk scan, and it made the progress bar marquee work.

But you know me: I'm not satisfied, because we still don't know why that makes the dang thing work. I could add a "splash screen" which would make it work, but I still wouldn't know what caused the underlying problem.

Apparently there's some kind of interaction between the progress bar control and GDI+. But what?

I don't like that as a "fix", because it ends up going through the WM_PAINT handler even if there's not a valid GDI+ bitmap handle (GdiHbitmap) to display.

Good work on your part, though.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: zedd on April 22, 2024, 06:28:39 AM
Seems that the code must flow through the WM_PAINT handler for the marquee to animate. At any rate, I'm done with that for now. Maybe I will look more into it at another time.

You could bypass anything there that would use any handle (test for valid handle) allowing the progress bar to work. Shouldn't be necessary to bypass WM_PAINT altogether....  I might could try a couple things along that line if I have time later tonite.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 22, 2024, 06:36:20 AM
A Martian programmer reading this thread might scratch his head and say "WTF are these hue-mons obsessing so much over a little itty-bitty rectangle that shows a moving blob?". And they might be right at that.

But look at the lengths that some people will go to (https://www.codeproject.com/Articles/31906/Progress-O-Doom) in order to get the progress bar they like. Wow.

Heh; maybe I should adapt my own barber-pole control (https://masm32.com/board/index.php?msg=117217) for this program.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: zedd on April 22, 2024, 06:38:47 AM
Quote from: NoCforMe on April 22, 2024, 06:36:20 AMA Martian programmer reading this thread might scratch his head and say "WTF are these hue-mons obsessing so much over a little itty-bitty rectangle that shows a moving blob?". And they might be right at that.

But look at the lengths that some people will go to (https://www.codeproject.com/Articles/31906/Progress-O-Doom) in order to get the progress bar they like. Wow.

Heh; maybe I should adapt my own barber-pole control (https://masm32.com/board/index.php?msg=117217) for this program.

:rofl:  :rofl:
That's what happens with too much time on your hands...   :biggrin:
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 22, 2024, 08:18:38 AM
Further research here at NoC Laboratories, GmbH shows that all that's needed to make the progress bar work in "marquee" mode is to invoke the paint routine of the picture-display window proc, by first disabling the "gate" at the top of the WM_PAINT handler:

;==============================
;  WM_PAINT handler
;==============================
do_paint:
; CMP PictureIsUp, FALSE
; JE zero_exit

INVOKE BeginPaint, hWin, ADDR ps
MOV hDC, EAX

; Get graphics "object" from DC handle:
INVOKE GdipCreateFromHDC, hDC, ADDR gdiHgraphics

; Display image at (X,Y) with dimensions (W,H):
; Many thanks to "mabdelouahab" from the MASM32 forum for this.
INVOKE GdipDrawImageRectI, gdiHgraphics, GdiHbitmap,
ImgStruct.imgX, ImgStruct.imgY, ImgStruct.imgWscaled, ImgStruct.imgHscaled
INVOKE EndPaint, hWin, ADDR ps
JMP zero_exit

and then by forcing a repaint, even though there's no valid bitmap to show:

INVOKE InvalidateRect, PicDisplayHandle, NULL, FALSE

What bothers me is that I still don't know why this works ...
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: zedd on April 22, 2024, 08:31:28 AM
Quote from: NoCforMe on April 22, 2024, 08:18:38 AMWhat bothers me is that I still don't know why this works ...
Is GDI+ taking over all of the graphics functions, I.e. Painting, redrawing, etc...  Must be something with GDI+ I think.

Don't spend too much time on this though, those martians are watching.  :tongue:
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 22, 2024, 08:31:54 AM
The progress bar marquee animation also works if I just clip out all of the GDI+ stuff from the program. So I think I've proven that the problem is definitely an interaction of the progress bar control with GDI+.

I find nothing at all about this on the intertubes, btw.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: zedd on April 22, 2024, 08:38:08 AM
If nothing else, at least you narrowed the problem down.
What about using createwindowex for the progress bar, and give it its own wndproc??
Or even run the progress bar in its own thread?

Type correction fubarring my post (iPad post) ...  but you should get the idea.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 22, 2024, 09:41:14 AM
Quote from: sinsi on April 21, 2024, 05:08:42 AMOK, tracked down the crash
    INVOKE    strcpy, ADDR [EDX].FILEINFO.pathName, ADDR [EBX].FILEINFO.pathName
    INVOKE    _strcat, OFFSET BackslashStr, ADDR [EBX].FILEINFO.pathName
    INVOKE    _strcat, OFFSET FD.cFileName, ADDR [EBX].FILEINFO.pathName
;*** added ***
lea eax,[EBX].FILEINFO.pathName
call strlen
cmp eax,MAX_PATH
jbe @f
 int 3
@@:
;*************
Run in the debugger, stops at the breakpoint with EAX=0115 (277, well over MAX_PATH)
This overwrites some pretty important data in your structure  :biggrin:

The version attached here (.exe only) will log any overlength pathnames and prevent them from being processed. sinsi, could you run this against the path that caused the crash? The program will create a log file (PicView.log) in the folder containing the .exe, and it should contain any overlength pathnames.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: sinsi on April 22, 2024, 10:42:06 AM
Interesting...running the program from home, the log is empty and everything works
 - the dialog combo doesn't close when I first click on it, and shows a list
 - the marquee works from the start

I can't check the work PC until tomorrow night (that's where the problems are).

Weird.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 22, 2024, 11:04:59 AM
At this point I'd like to give debugging awards to those whose efforts were really helpful to me:


Couldn't have done it without you.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: zedd on April 22, 2024, 02:18:43 PM
Latest bugfix attempt?
    CMP    PictureIsUp, FALSE
    JE    dodefault
   

jump to default, rather than zero_exit
seems to work, without commenting out needed code.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 22, 2024, 02:29:35 PM
AAAAAARGH!

How do you keep finding these things?

Guess what: that's not the "latest bugfix". That was the reason the progress bar marquee didn't work all along! Has nothing at all to do with GDI+. Never did.

Like I figured it would be, just another stupid mistake on some programmer's part.

(Explanation: if you get a WM_PAINT message, you'd better handle it properly--either go through BeginPaint() and EndPaint() and return zero, or return non-zero if you don't handle it. Otherwise the paint message queue will get all screwed up.)
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: zedd on April 22, 2024, 02:35:19 PM
Quote from: NoCforMe on April 22, 2024, 02:29:35 PMHow do you keep finding these things?
Persistence and trial and error mostly.


Quote from: NoCforMe on April 22, 2024, 02:29:35 PMLike I figured it would be, just another stupid mistake on some programmer's part.
I wonder what the martians would make of that... :joking:
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 22, 2024, 02:36:09 PM
They'd incinerate me with a laser death-ray.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: zedd on April 22, 2024, 02:49:08 PM
I just knew all along, that it had to be something simple.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: zedd on April 23, 2024, 12:56:16 AM
I just tested the long path version of the program in Windows 10.  :dazzled:

The very first few .png images that I clicked on did not appear.  :sad:
Low and behold, they were white images and did appear but against a white background, seemed that they did not.  Perhaps a different (patterned) background might be better?

Otherwise no issues with long path names for me on Windows 10.
ooops!! I forgot to check the log... attached

But no crash due to long paths
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 23, 2024, 06:05:15 AM
Quote from: sudoku on April 23, 2024, 12:56:16 AMOtherwise no issues with long path names for me on Windows 10.
ooops!! I forgot to check the log... attached

As they used to say on "Laugh-In", verrry eenteresting ... All of those files start with C:\Windows\servicing\LCU\Package_for_RollupFix~ .... Does anyone have any idea where those files come from? Are they a Windows component, or are they part of some other package? ("RollupFix"? What is that?) In any case, they violate MAX_PATH egregiously.

QuoteBut no crash due to long paths
That's because I caught them and logged them, rather than let them overwrite my data structures.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: zedd on April 23, 2024, 06:09:39 AM
Where those files came from I have no clue. I would have thought that 'winsxs' would have had the longest paths. (Very long folder names there, too iirc)
After I posted I thought to check the log. Whoops!
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: sinsi on April 23, 2024, 07:46:13 AM
You have always been able to make unicode paths upto 32K in size
Maximum Path Length Limitation (https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=registry)

Just to make life a little bit more interesting
Enable Long Paths in Windows 10, Version 1607, and Later (https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=registry#enable-long-paths-in-windows-10-version-1607-and-later)
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 23, 2024, 09:34:44 AM
Wellll, that certainly is a can o'worms. As the project manager for this program, I'm making an executive decision here: fuggedabout Unicode filenames, or any pathname over MAX_PATH long. It would be waaay too much trouble to fix this properly (as a production-grade piece of software ought to): would probably have to dynamically allocate each and every pathname, which would be a fucking nightmare. No thanks. I'll live with the occasional ignored file. (Interesting that all the files that were in Sudoku's log were image files that the program could've displayed, .pngs to be exact. Oh, well.)

As a Windows 7 user, I can simply shut the door to anyone with a more modren OS. And since this is not a commercial product, I get to do that. Windows 11? That's your problem. This app is for the Windows Retro Club only.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: zedd on April 23, 2024, 09:50:00 AM
Quote from: NoCforMe on April 23, 2024, 09:34:44 AMWindows 11? That's your problem. This app is for the Windows Retro Club only.
Can I use that quote, or is it copyrighted?  :tongue:

You should not call it an app. It's a Program or Application.
Apps are for smartphones, tablets, and windows 8/10/11 (I.e. Metro Apps)  :wink2:
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 23, 2024, 09:53:04 AM
I can call it what I damn well please.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: zedd on April 23, 2024, 09:54:10 AM
Ok, was just a suggestion...  :sad:
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: jj2007 on April 23, 2024, 10:05:02 AM
Quote from: sinsi on April 23, 2024, 07:46:13 AMYou have always been able to make unicode paths upto 32K in size

Indeed. And Unicode API calls are generally a tick faster, too, because the Ansi versions are just wrappers around the Unicode versions.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: sinsi on April 23, 2024, 11:41:58 AM
One more point, mainly for future reference, if you send the main window a message from the thread, be aware than SendMessage waits for processing, blocking your thread, but PostMessage returns immediately.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: NoCforMe on April 23, 2024, 11:53:58 AM
Thanks. Still unsure of all the details and differences between all those different message functions (SendMessage(), PostMessage(), PeekMessage(), etc.) I'm guessing that this has probably been covered by our friend Raymond Chen at some point.

Will make that change.
Title: Re: Adventures in programming: Treeviews, directory scanning, recursion
Post by: sinsi on April 23, 2024, 12:07:08 PM
Searching for GDI+ background thread found a few interesting things too.