This is a part of my own "Search Program".
It is far from beeing finished.
I am puzzled because the progressbar does not start to run when it should ....
Very likely I do not understand some basics.
----
I start the progressbar -(Modeless dialog)...
Immediately after - I start the proc which searches for existing directories in the choosen path...
The progressbar shows up, but starts running only after the search has finished.
Any good ideas ?
PS.
I do know that I have to "hook" the progressbar somehow to the search proc - but first things first.
If your machine goes down - enlarge the dir_array buffer. My C:\ only contents 19000 directories.
You need to send a message to the progress bar from the loop where you find the directories. SetTimer is not the right approach...
Attached a modified example, using a fake WM_TIMER message.
Note that I get a different count with GetFolders() (http://www.webalice.it/jj2006/MasmBasicQuickReference.htm#Mb1058), but no idea why. You might compare them with the WindowsFolders.txt file created with the snippet below (about 2MB).
include \masm32\MasmBasic\MasmBasic.inc ; download (http://masm32.com/board/index.php?topic=94.0)
Init
Let esi=ExpandEnv$("%WINDIR%\") ; 21204 (JJ) vs 18624 (clamicun)
PrintLine "Searching ", esi
GetFolders esi
Print Str$("%i folders found, first 10:\n", eax)
xor ecx, ecx
.Repeat
PrintLine Files$(ecx)
inc ecx
.Until ecx>10
Store "WindowsFolders.txt", Files$()
Inkey "ok?"
Exit
end start
jj2007 thank you.
"You need to send a message to the progress bar from the loop where you find the directories. SetTimer is not the right approach..."
I try to organize the message - not exactely shure what kind of msg..
----------------
I made the directory selection a bit easier...
CreateDirArray proc
pushad
xor eax,eax
mov eax,wfd.dwFileAttributes
AND eax,16
;push eax
;INVOKE MessageBox,0,offset wfd.cFileName,offset cur_path,0
;INVOKE wsprintf,offset wsprintf_msg,offset testintdd,wfd.dwFileAttributes
;INVOKE MessageBox,0,offset wsprintf_msg,offset cur_path,0
;pop eax
;.if eax == 16 || eax == 17 || eax == 18 || eax == 19 || eax == 22 \
; || eax == 48 || eax == 50 || eax == 51 \
; || eax == 8208 || eax == 8212 || eax == 8214 || eax == 8240 || eax == 9238
.if eax != 0
;Above I included AttribValue 8212 - The count is different now - much higher
;INVOKE MessageBox,0,offset wfd.cFileName,offset cur_path,0
;--- Clean array ----
"
"
----------------
Have a good one
The issue is that you only have one thread.
The search keeps the thread busy, so the window doesn't get updated, so the progress bar isn't updated.
Run the search in a separate thread and then the window can continue to be updated.
JJ
Your program creates the textfile - and real fast.
But it does not give out any message and does not end. I have to kill it with the taskmanager !
So I can not compare the result to the result of my very slow proc.
----------
On my computer it works like this...
include \masm32\MasmBasic\MasmBasic.inc ; download
.data
;------------
store_folder TCHAR 'Folders.txt',0
;cur_path TCHAR 'D:\test\',0
;cur_path TCHAR 'D:\arquivo\',0
;cur_path TCHAR 'D:\software\',0
cur_path TCHAR 'C:\windows\',0
.code
Init
mov esi,offset cur_path
PrintLine "Searching ", esi ;No
GetFolders esi
Print Str$("%i folders found, first 10:\n", eax) ;No
;----- ???
;xor ecx, ecx
;.Repeat
PrintLine Files$(ecx) ;No
;inc ecx
;.Until ecx > 1
;Store "WindowsFolders.txt", Files$()
;----- ???
Store offset store_folder, Files$()
;Inkey "ok?" ;No - This causes to not end the program !
INVOKE MessageBox,0,offset cur_path,offset cur_path,0
INVOKE ExitProcess,0
end start
---------------------------------
Tedd
Yes - I already thought on the multithread problem. I think that is it
Quote from: clamicun on December 06, 2014, 01:04:53 AM
JJ
Your program creates the textfile - and real fast.
But it does not give out any message and does not end. I have to kill it with the taskmanager !
In case you are using qEditor or similar: You need to build it as a
console application, otherwise print and inkey won't work.
RichMasm autodetects console apps, but most other IDEs don't, unfortunately.
Speedwise there is not much difference between our codes. According to my timings, GetFolder may be a little bit faster (20%?), but that doesn't really matter. For both, there is a huge difference between the first and the second time you run the program, due to the file cache. A more interesting question is why the folder counts differ - could be linked to attributes like system & hidden.
Quote from: Tedd on December 06, 2014, 12:05:49 AM
The issue is that you only have one thread.
The search keeps the thread busy, so the window doesn't get updated, so the progress bar isn't updated.
Interesting point, Tedd. My example above (console build!) works with a single thread, but the progress bar
does get updated. It seems that SendMessage returns only after the progress bar has been updated.
The bigger problem is that you can't tell beforehand how many folders correspond to 100% :(
There seems no API that can do that, so apparently you need FindFirstFile & FindNextFile to find the total number of folders; which implies that you'll know what 100% means
after the exercise, but
during the search you'll have no idea - which makes the progress bar kind of meaningless. Unless somebody knows a magic API that can ask the NTFS directly "how many subfolders are in %WinDir%?"...
JJ
Here is a fine working proc - made from yours.
S4F.zip
The differences indeed seem to be "Windowsmade". Obviously "getfolders" does not count folders with certain attributes.
On the progressbar I am working. If I find solution, I let you know.
Quote from: clamicun on December 06, 2014, 04:36:34 AM
Here is a fine working proc - made from yours.
Thanks :biggrin:
QuoteThe differences indeed seem to be "Windowsmade". Obviously "getfolders" does not count folders with certain attributes.
My impression was that GetFolders counts more folders than yours, but I could be wrong, of course.
One more, just for fun:
include \masm32\MasmBasic\MasmBasic.inc ; download (http://masm32.com/board/index.php?topic=94.0)
Init
Let esi=FolderOpen$("Pick a folder:", "Masm is great;", "\Masm32\examples\exampl01")+"\*"
GetFolders esi
push eax ; save folder count to stack
xor ecx, ecx
.Repeat
Print Str$("\n%i\t",ecx), Files$(ecx)
inc ecx
.Until ecx>=stack
pop eax
Inkey Str$("\n%i folders found in ", eax), esi
Exit
end start
If call something like this inside loop, GUI may work ?CheckMsgQueue PROC hWnd:DWORD
LOCAL msg:MSG
.WHILE 1
INVOKE PeekMessageA,ADDR msg,hWnd,0,0,1
.BREAK .IF (!eax)
.BREAK .IF (msg.message == 012h) ; WM_QUIT
INVOKE TranslateMessage,ADDR msg
INVOKE DispatchMessageA,ADDR msg
.ENDW
ret
CheckMsgQueue ENDP
Correct this, if there is something wrong.
Quote from: TWell on December 06, 2014, 06:08:11 AM
If call something like this inside loop, GUI may work ?
You should post the complete code to see how it is embedded in the rest of the application. PeekMessage is generally not such a good idea, because it can drive up CPU usage.
In the meantime, GetFolders() (http://www.webalice.it/jj2006/MasmBasicQuickReference.htm#Mb1058) has learnt to accept a callback. Below a very simple example, but you could also implement a file counter, or display all files/paths found or tested etc; edx is current count, edi is path tested with FindFirstFileEx, and eax is the result of the test.
include \masm32\MasmBasic\MasmBasic.inc ; download version 6 December (http://masm32.com/board/index.php?topic=94.0)
Init
Let esi=ExpandEnv$("%WINDIR%\System32") ; usually C:\Windows\System32
Print "Searching ", esi, ": "
GfCallback cbGetFiles ; define a callback function
GetFolders esi
Print Str$(" - %i folders found, first 20:", eax)
xor ecx, ecx
.Repeat
Print Str$("\n%i\t", ecx+1), Files$(ecx)
inc ecx
.Until ecx>=20
; Store "Sys32Folders.txt", Files$() ; in case you need a textfile
Inkey CrLf$, "ok?"
Exit
cbGetFiles:
test edx, 31 ; edx is file or folder counter
.if Zero? ; every once in while
Print "*" ; console mode progress bar ;-)
.endif
ret
end startSimple variant displaying the file counter in a constant position on the screen:
cbGetFiles:
Print Str$(edx), Cr$
ret
Quote from: jj2007 on December 06, 2014, 09:17:23 PM
You should post the complete code to see how it is embedded in the rest of the application. PeekMessage is generally not such a good idea, because it can drive up CPU usage.
No code as i'm not an asm programmer.
I like use that PeekMessage in single threaded program as it make debugging easier.
JJ,
"My impression was that GetFolders counts more folders than yours, but I could be wrong, of course.!
Excuse me - .Of course you were not wrong. GetFolders counted more. Not any more. I found out why.
Windows creates folders like: \.NET , \.!!, \.cache
Because of the line
.if byte ptr wfd.cFileName != '.'
my program did not find them.
Your program GetFolders with callback does not compile on my computer...
Syntax error : gfCallback on line 5.
----------
Tedd,
"The issue is that you only have one thread.Run the search in a separate thread and then the window can continue to be updated."
Could you or someone be a bit more explicit - I do not have the slightest idea how to start a new thread.
Quote from: clamicun on December 08, 2014, 10:04:23 PM
Your program GetFolders with callback does not compile on my computer...
Syntax error : gfCallback on line 5.
You must have an incredibly old version of MasmBasic: Since 6 December, it understands GfCallback (note: uppercase G and C). And since right now (download again, please (http://masm32.com/board/index.php?topic=94.0)), the callback passes in ebx the address of the WIN32_FIND_DATAW structure used to do the search - see example below.
I am curious to see your latest version, to see whether they still differ, and where.
include \masm32\MasmBasic\MasmBasic.inc ; download (http://masm32.com/board/index.php?topic=94.0)
Init
Let esi=ExpandEnv$("%WINDIR%") ; usually C:\Windows
PrintLine "Searching ", esi, ": "
GfCallback cbGetFiles ; define a callback function
GetFolders esi
Print Str$("%i folders found, first 20:", eax)
xor ecx, ecx
.Repeat
Print Str$("\n%i\t", ecx+1), Files$(ecx)
inc ecx
.Until ecx>=20
; Store "Sys32Folders.txt", Files$() ; in case you need a textfile
Inkey CrLf$, "ok?"
Exit
cbGetFiles:
test edx, 1023 ; edx is file or folder counter
.if Zero? ; every once in while
lea edx, [ebx.WIN32_FIND_DATAW.cFileName]
Print edx, CrLf$
.endif
ret
end start
Hello JJ,
here are the 2 versions. My finds 2 folders more on my C-Drive.
I didn't yet see which entries are not there, because the textfiles are 200KB - that is labourious.
Yours is better. I don't know how it finds the folders which start with '.' without explicitly naming them as my does.
What is the difference between WIN32_FIND_DATA and WIN32_FIND_DATAW ?
Quote from: clamicun on December 08, 2014, 10:04:23 PM
"The issue is that you only have one thread.Run the search in a separate thread and then the window can continue to be updated."
Could you or someone be a bit more explicit - I do not have the slightest idea how to start a new thread.
CreateThread (http://msdn.microsoft.com/en-us/library/windows/desktop/ms682453%28v=vs.85%29.aspx) will start a new thread; you provide the offset of your search function for
lpStartAddress, and
lpParameter allows you to pass in a single parameter (a value, or a pointer to something useful.)
This thread will then run in parallel with your main window thread.
So then you can update a progress value from the new thread, and have the window update to reflect that value. But try to keep shared variables to a minimum to avoid weird synchronisation bugs.
Quote from: clamicun on December 10, 2014, 03:36:52 AMWhat is the difference between WIN32_FIND_DATA and WIN32_FIND_DATAW ?
No big difference. I used the Unicode version because ANSI FindFirstFile works with the wide version but not the other way round.
Good and bad news:
- Absolutely no difference for C:\Windows, 20,000 folders
- Your version chokes for my complete C: drive. The culprit is here:
00401313 ³. 3C 40 ³cmp al, 40
00401315 ³. 74 F7 ³je short 0040130E
00401317 ³. AA ³stosbThat is at the beginning of Clean_Dir_Array.
For the comparison of the textfiles, I used this snippet: It loads both files into an array, strips the \* from your version, sorts both arrays alphabetically and then checks if the strings are identical. They are.
include \masm32\MasmBasic\MasmBasic.inc
SetGlobals ctc, ctj
Init
SetGlobals
Recall "Folders_Clam.txt", cl$()
push eax
xor ecx, ecx
.Repeat
mov esi, cl$(ecx)
Let cl$(ecx)=Left$(esi, Len(esi)-2)
inc ecx
.Until ecx>=stack
pop eax
QSort cl$()
mov ctc, eax
Recall "Folders_JJ_Callback.txt", jj$()
QSort jj$()
mov ctj, eax
xor ecx, ecx
.Repeat
.if !Instr_(cl$(ecx), jj$(ecx))
deb 1, "Gotcha", ecx, $cl$(ecx), $jj$(ecx) ; no Gotcha seen for C:\Windows!
.endif
inc ecx
.Until ecx>=ctc
deb 4, "Counts", ctc, ctj
Exit
end startP.S.: For a better comparison e.g. with fc (=file compare), use e.g.
mov ctj, eax
Store "Folders_C.txt", cl$() ; write the sorted and stripped strings to disk
Store "Folders_J.txt", jj$() ; write the sorted strings to disk
xor ecx, ecx
JJ,
this was a stupid mistake in Clean_Dir_Array, which I corrected.
Your "Compare File Routine" is very helpful.
Thank you for everything. I learned a lot.
A last question.
.if byte ptr FileName != '.' || byte ptr FileName+1 == '!' ;works on a folder .!!OIM
Why doesn't this have the same effect?
.if byte ptr wfd.cFileName != '.' || byte ptr wfd.cFileName+1 != ' ' ;shows the old MS-DOS '.' and '..' folders
Am I illogic?
Now I go back and try to organize the progressbar.
Quote from: clamicun on December 11, 2014, 03:51:47 AM
Thank you for everything. I learned a lot.
My pleasure :icon14:
Quote
.if byte ptr FileName != '.' || byte ptr FileName+1 == '!' ;works on a folder .!!OIM
Not quite sure what you are looking at, but dot folders are 2E00h (=current folder aka ".") and 2E2E00h (=parent folder aka "..") - all others are named folders or files. So you might want to check for the position of the nullbyte, e.g. via word ptr []==2E00h
be aware that a valid file or folder name may have a '.' as the second char
so - that test is only good if the first char is also '.' :biggrin:
Quote from: dedndave on December 11, 2014, 10:51:28 AM
be aware that a valid file or folder name may have a '.' as the second char
so - that test is only good if the first char is also '.' :biggrin:
Quote from: jj2007 on December 11, 2014, 04:24:08 AMdot folders are 2E00h (=current folder aka ".") and 2E2E00h (=parent folder aka "..") - all others are named folders or files. So you might want to check for the position of the nullbyte, e.g. via word ptr []==2E00h
From the top secret MasmBasic source:
lea edx, [ebx.WIN32_FIND_DATA.cFileName]
mov eax, [edx] ; might be ., .. or .aname
.if al=="."
shr eax, 8 ; aname or nullbyte?
.if !al
xor eax, eax
.elseif al=="."
shr eax, 8
.if !al
xor eax, eax
.endif
.endif
.endif
.if eax ;)
deleted
Thank's nidud.
Same as C lingoint main(int argc, char **argv)
{
char name[] = "..";
if ((short)'.' != *(short*)&name[0])
if ((short)'.' != *(short*)&name[1])
return 1;
return 0;
}
Quote from: nidud on December 11, 2014, 11:04:13 PM
but not this "x." --> "x"
What exactly do you mean? Chr$(34) is illegal?
Otherwise, your code looks shorter than mine, I might steal it ;-)
deleted
What I meant was this...
I want to catch all filenames which start with '.'
and have in byte ptr+1 whatever except for the second '.'
There are lots on my machine: .!, ._, .NET, .d, .r and more.
That's why I asked if
byte ptr != '.' || byte ptr+1 == '!'
is the same as
byte ptr != '.' || byte ptr+1 != ' ' ;it is not obviously
What is right to catch all filename which are like '.something ? ! _ r N d .....
Quote from: nidud on December 12, 2014, 02:53:22 AM
Quote from: jj2007 on December 12, 2014, 02:05:18 AMWhat exactly do you mean? Chr$(34) is illegal?
I think the OS strips trailing dot's on creation so you wont find a file named "?."
They technically can be created, but you have to use NtCreateFile directly to do it. Of course since practically nothing uses that function directly you can't do anything with the file, because as you said, CreateFile and friends will get rid of the trailing dot.
chr$(34) should be illegal :biggrin:
it's often used to delimit filenames that contain spaces
anyways....
the folders "." and ".." will only show up once, unless you change the current folder
maybe that will simplify your code
this program doesn't do exactly what you want, but the code may be of interest
http://masm32.com/board/index.php?topic=3468.msg36521#msg36521 (http://masm32.com/board/index.php?topic=3468.msg36521#msg36521)
Quote from: clamicun on December 12, 2014, 05:09:45 AMThat's why I asked if
byte ptr != '.' || byte ptr+1 == '!'
is the same as
byte ptr != '.' || byte ptr+1 != ' ' ;it is not obviously
You should look at your code through the eyes of OllyDbg.
' ' is not a nullbyte, it's a space - could be a valid filename
'!' is a dangerous char because it's a MASM special character meant to handle e.g. certain situations with brackets. Depending on how macros are constructed/expanded, you may need up to FOUR exclamation marks until MASM grants you one valid one. Workaround: Chr$(31) or 1Fh.
@nidud+adeyblue: thanks for the excursion into trailing dots ;-)
JJ,
! is dangerous or not...
There are folders on my computer, which start with .!!
So I wrote it like this:
.if byte ptr wfd.cFileName != '.' || byte ptr wfd.cFileName+1 == 21h || byte ptr wfd.cFileName+1 > 2Eh
In case that next week there are folders like .x or.y
I still don' understand why your prog comes to the same result without. It has to do with MasmBasic.inc - hasn't it?
I got curious and installed Microsoft SmallBasic on my Win7-64 machine.
The good news: It runs just fine. The rest is mixed. The syntax is awful, but maybe I just must get used to it. Help is practically unavailable.
Then I stumbled over some awkward behaviour:
dir = "C:\Windows\System32\"
getFiles = File.GetFiles(dir)
ct=0
TextWindow.WriteLine("start")
For i = 1 To Array.GetItemCount(getFiles)
getFile = getFiles[i]
If 1=1 Then '(Text.EndsWith(getFile,".dll")) Then
ct=ct+1
File.AppendContents("TestSB.txt", getFile)
TextWindow.WriteLine(getFile)
EndIf
EndFor
TextWindow.WriteLine(ct+" files found")
TextWindow.Pause()
Very simple, it writes 2750 file paths to TestSB.txt
Problem is, the following yields a somewhat different set of files:
include \masm32\MasmBasic\MasmBasic.inc ; download (http://masm32.com/board/index.php?topic=94.0)
SetGlobals ct, fileMB$="TestMB.txt"
Init
GfNoRecurse=1 ; SmallBasic doesn't search in subfolders
Open "O", #1, fileMB$
GetFiles C:\Windows\System32\*
For_ ecx=0 To eax-1
mov esi, Files$(ecx)
lea eax, [esi+Len(esi)-4]
.if 1 ;Cvl(eax)==Mirror$(".dll")
inc ct
PrintLine #1, esi
.endif
Next
Close
Print Str$("%i files found", ct) ; finds 2225 files
Exit
end start
90% of the files coincide, but MB finds clearly less files than the SmallBasic GetFiles, and different ones. For example, SB finds an Acer.scr that MB doesn't find.
FreeCommander and the DOS prompt go with MB, while Explorer goes with SB. It is as if SB and Explorer used something different from FindFirstFile, with different results.
One more example: SmallBasic GetFiles doesn't find
C:\Windows\System32\12520437.cpx
C:\Windows\System32\12520850.cpx
MasmBasic GetFiles and the cmd prompt finds them.
EDIT: Gotcha! It's the SysWOW64 thing. Apparently FindFirstFile gets SysWOW64 when you ask for System32 on a 64-bit system. Strange though that SmallBasic gets two different results - it's a 32-bit app, too. Maybe there is some hidden Microsoft only flag that you can pass to FFF ::)
:biggrin:
I just had a quick play with small basic and its awful but funny enough it popped a 2.5k exe that only depends on a runtime DLL.
Quote from: hutch-- on December 28, 2014, 10:05:04 AM
:biggrin:
I just had a quick play with small basic and its awful but funny enough it popped a 2.5k exe that only depends on a runtime DLL.
... which has 250k and in turn depends on mscoree.dll. I feel a bit ashamed for MasmBasic's 20k overhead, but compared to that it's still tiny. However, SmallBasic's runtime is really not too big compared to many other bloated stuff. Rumours say a hello world in QT needs 10MB.
I made some tests with string manipulation, it's a factor 5-7 slower than my favourite dialect :bgrin:
Apparently, Microsoft touts this as a free tool to make kids acquainted with object orientation à la VB. I hate it, but it has many fans, and for a reason.
Just for fun, attached a proggie that saves the names of both the redirected 32-bit DLLs and the native 64-bit DLLs to file. Source:
include \masm32\MasmBasic\MasmBasic.inc ; download (http://masm32.com/board/index.php?topic=94.0)
Init
Dll "Kernel32"
Declare void Wow64DisableWow64FsRedirection, 1
Declare void Wow64RevertWow64FsRedirection, 1
GetFiles C:\Windows\System32\*.dll
Print Str$("%i 32-bit DLLs found\n", eax) ; 2806
Store "Sys32_redirected.txt", Files$()
push 0 ; create a DWORD zero on the stack
Wow64DisableWow64FsRedirection(esp)
GetFiles C:\Windows\System32\*.dll
pop eax
Wow64RevertWow64FsRedirection(eax)
Store "Sys32_native64.txt", Files$()
Inkey Str$("%i 64-bit DLLs found", Files$(?)) ; 3195
Exit
end start