Shoutbox

[?] Enumerating through files in Win32 - Printable Version

-Shoutbox (https://shoutbox.menthix.net)
+-- Forum: MsgHelp Archive (/forumdisplay.php?fid=58)
+--- Forum: Messenger Plus! for Live Messenger (/forumdisplay.php?fid=4)
+---- Forum: Scripting (/forumdisplay.php?fid=39)
+----- Thread: [?] Enumerating through files in Win32 (/showthread.php?tid=98483)

[?] Enumerating through files in Win32 by SmokingCookie on 10-27-2011 at 07:54 PM

Seems like Win32's not doing things it's said to be. Anyway, I've worked along the lines of this MSDN article, but somehow I can't get more than 2 valid file names, plus one "dummy" result; that dummy allows one to check if Interop.GetLastError() returns 18 (ERROR_NO_MORE_FILES) or something else is wrong. Indeed, Interop.GetLastError() does return ERROR_NO_MORE_FILES at the dummy, but I'm still getting only 2 useful results. Code:

JScript code:
/* FileSystem object and Print() functions defined elsewhere
furthermore: Paths.Root =  MsgPlus.ScriptFilesPath + "\\";*/

FileSystem.EnumerateFiles = function(Directory) {
    var ret = new Array();
    var result = this.FindFirstFile(Directory);
    if(result.hFind === 0) {
        result.WIN32_FIND_DATA.Size = 0;
        return ret;
    }
    ret.push(result);
    do {
        result = this.FindNextFile(result.hFind);
        ret.push(result);
    } while(result.hFind !== 0);
    return ret;
}

FileSystem.FindClose = function(hFind) {
    return Interop.Call("Kernel32.dll","FindClose",hFind);
}

FileSystem.FindNextFile = function(hFind,pData) {
    ret = new Object();
    ret.WIN32_FIND_DATA = typeof pData === "object" ? pData : Allocate(592); // confirmed working
    ret.hFind = Interop.Call("Kernel32.dll","FindNextFileW",hFind,ret.WIN32_FIND_DATA.DataPtr);
    ret.LastError = Interop.GetLastError();
    return ret;
}

FileSystem.FindFirstFile = function(sFile) {
    if(typeof sFile === "number") sFile = this.GetPathFromHandle(sFile); // confirmed working
    var ret = new Object();
    ret.WIN32_FIND_DATA = Allocate(592); // confirmed working
    ret.hFind = Interop.Call("Kernel32.dll","FindFirstFileW",sFile,ret.WIN32_FIND_DATA.DataPtr);
    ret.LastError = Interop.GetLastError();
    return ret;
}

var FindResult = FileSystem.EnumerateFiles(Paths.Root + "*");
for(var i = 0; i < FindResult.length; i++) {
    Print(FindResult[i].hFind);
    Print(FindResult[i].LastError);
    Print(FindResult[i].WIN32_FIND_DATA.readDWORD(0));
    Print(FindResult[i].WIN32_FIND_DATA.readSTRING(44));
    FindResult[i].WIN32_FIND_DATA.Size = 0;
    FileSystem.FindClose(FindResult[i].hFind);
}

The output is always:

code:
> 322211400 // some handle
> 0 // Interop.GetLastError() result => nothing's wrong
> 16 // dwFileAttributes member from the WIN32_FIND_DATA structure => this result is the current directory
> . // cFileName[MAX_PATH] member from the same struct
> 1 // always the same handle
> 0 // Interop.GetLastError() result => still okay
> 16 // Again a directory
> .. //cFileName[MAX_PATH] => parent directory
> 0 // dummy result with return value 0
> 18 // ERROR_NO_MORE_FILES
> 0 // Attributes
> // NULL

Also, calling the function for, say "Paths.Root + *.js" does something similar: it gives the first 2 .js files and then returns the same dummy. Any advice to get this working is welcome.
RE: [?] Enumerating through files in Win32 by matty on 10-27-2011 at 09:31 PM

js code:
function GetDirectoryStructure(sPath, sPattern, IncludePath) {
        _debug.getfuncname(arguments);
        var aFileNames = [];
        var Win32_Find_Data = Interop.Allocate(592);
        var hSearch = Interop.Call('kernel32', 'FindFirstFileW', '\\\\?\\' + sPath + sPattern, Win32_Find_Data);
        var hResult;
        while (hResult !== 0) {
                if (!(Win32_Find_Data.ReadDWORD(0) & 0x10 /* FILE_ATTRIBUTE_DIRECTORY */ & 0x4 /* FILE_ATTRIBUTE_SYSTEM */) &&
                                 Win32_Find_Data.ReadString(44).charAt(0) !== '.') {
                        aFileNames.push((IncludePath ? sPath : '') + Win32_Find_Data.ReadString(44));
                }
                hResult = Interop.Call('kernel32', 'FindNextFileW', hSearch, Win32_Find_Data)
        }
        Interop.Call('kernel32', 'FindClose', hSearch);
        return aFileNames;
}

That is what we did for SS5. You only need to close the first handle, not all of them.

The problem is that you keep overwriting hFind. hFind should be the handle to the directory not the next file you keep finding. At least that is what it appears. No WLM/Plus! installed to check.

Do something like this:
js code:
FileSystem.EnumerateFiles = function(Directory) {
    var ret = new Array();
>>>    var result;<<<
>>>    var hFind = (result = this.FindFirstFile(Directory)).hFind;<<<
    if(result.hFind === 0) {
        result.WIN32_FIND_DATA.Size = 0;
        return ret;
    }
    ret.push(result);
    do {
>>>        result = this.FindNextFile(hFind);<<<
        ret.push(result);
    } while(result.hFind !== 0);
    return ret;
}

RE: [?] Enumerating through files in Win32 by SmokingCookie on 10-29-2011 at 09:37 AM

JScript code:
FileSystem.EnumerateFiles = function(Directory) {
    var ret = new Array();
    var result = this.FindFirstFile(Directory);
    if(result.hFind === 0) {
        result.WIN32_FIND_DATA.Size = 0;
        return ret;
    }
    do {
        var oResult = this.FindNextFile(result.hFind);
        ret.push(oResult);
    } while(oResult.hFind !== 0);
    return ret;
}

That does it; I guess that using the result object in the loop changes the references stored in the array..?
RE: [?] Enumerating through files in Win32 by matty on 10-31-2011 at 11:10 AM

quote:
Originally posted by SmokingCookie
That does it; I guess that using the result object in the loop changes the references stored in the array..?
Not exactly, you are changing the handle of the directory you are searching.

So you said find me the files in folder XYZ, it finds the first file as "." then you said find me the next file in XYZ and it found ".." but then you changed the handle of the object you were searching from XYZ to "..". Does that make sense?

If it doesn't make sense here is some pseudo since I am now on a computer and not my iPad:

This is what you should be doing

FindFirstFile ('XYZ')
> retval = 1
FindNextFile(1)
> retval = 100
FindNextFile(1)
> retval = 100

What you are doing is this
FindFirstFile ('XYZ')
> retval = 1
FindNextFile(1)
> retval = 100
FindNextFile(100)
> retval = 18 (no more files)

Hope that clears things up a bit.

Post 8000 w00t!
RE: [?] Enumerating through files in Win32 by SmokingCookie on 10-31-2011 at 02:45 PM

It sure does! I thought that FindNextFile() used the previously found handle, while it actually uses the handle retreived with FindFirstFile().

I suggest trying to make 2000 posts between now and December 2012 :P


RE: [?] Enumerating through files in Win32 by matty on 10-31-2011 at 02:53 PM

quote:
Originally posted by SmokingCookie
It sure does! I thought that FindNextFile() used the previously found handle, while it actually uses the handle retreived with FindFirstFile().
After reading the MSDN article I can see why you would think that but no it has to be the original handle for the folder.

quote:
Originally posted by SmokingCookie
I suggest trying to make 2000 posts between now and December 2012 :P
Why is that? 10,000 posts in 10 years?
RE: [?] Enumerating through files in Win32 by SmokingCookie on 10-31-2011 at 03:55 PM

quote:
Originally posted by matty
quote:
Originally posted by SmokingCookie
It sure does! I thought that FindNextFile() used the previously found handle, while it actually uses the handle retreived with FindFirstFile().
After reading the MSDN article I can see why you would think that but no it has to be the original handle for the folder.

Well, at least these details have been cleared up now, and my enumeration function works like a charm :)

quote:
Originally posted by matty
quote:
Originally posted by SmokingCookie
I suggest trying to make 2000 posts between now and December 2012 :P
Why is that? 10,000 posts in 10 years?

Exactly
RE: [?] Enumerating through files in Win32 by matty on 10-31-2011 at 05:36 PM

Glad you got it sorted out!

And I will see what I can do about 2000 1995 posts in a 13 months.