Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

will FileLen give an error on very large files?

68 views
Skip to first unread message

RB Smissaert

unread,
Nov 13, 2009, 5:05:52 PM11/13/09
to
Just come across the fact that FileLen has a problem with large files in
that the result will become negative
if the filesize exceeds the range of the Long datatype. Now, will there be
an error if the filesize exceeds twice
the range of the Long datatype? I can't find a file of that size, so I can't
test.
The reason I need to know is to make sure this api code will work with those
large files.
If not then I will just chuck the FileLen out:

Private Declare Sub CopyMemory _
Lib "kernel32" _
Alias "RtlMoveMemory" (Dest As Any, _
Src As Any, _
ByVal cBytes As Long)
Private Declare Function FindFirstFile Lib "kernel32" _
Alias "FindFirstFileA" _
(ByVal lpFileName As String, _
lpFindFileData As WIN32_FIND_DATA)
As Long
Private Declare Function FindClose Lib "kernel32" _
(ByVal hFindFile As Long) As Long

Const MAX_PATH = 260

Private Type FILETIME
dwLowDateTime As Long
dwHighDateTime As Long
End Type

Private Type WIN32_FIND_DATA
dwFileAttributes As Long
ftCreationTime As FILETIME
ftLastAccessTime As FILETIME
ftLastWriteTime As FILETIME
nFileSizeHigh As Long
nFileSizeLow As Long
dwReserved0 As Long
dwReserved1 As Long
cFileName As String * MAX_PATH
cAlternate As String * 14
End Type

Function FileSizeAPI(strFilePath As String) As Variant

Dim hSearch As Long
Dim WFD As WIN32_FIND_DATA

On Error GoTo ERROROUT 'for if strFilePath doesn't exist in FileLen

FileSizeAPI = FileLen(strFilePath)

If FileSizeAPI > 0 Then
Exit Function
End If

'this seems to be the fastest way to get the file handle
'-------------------------------------------------------
hSearch = FindFirstFile(strFilePath, WFD)

If hSearch = -1 Then
FileSizeAPI = -1
Else
FileSizeAPI = LargeInteger(WFD.nFileSizeLow, WFD.nFileSizeHigh)
FindClose hSearch
End If

Exit Function

ERROROUT:
FileSizeAPI = -1

End Function

Public Function LargeInteger(ByVal LoPart As Long, _
ByVal HiPart As Long) As Variant

Dim nResult As Currency

'Copy the parts, appropriately.
CopyMemory ByVal VarPtr(nResult), LoPart, 4
CopyMemory ByVal VarPtr(nResult) + 4, HiPart, 4

'Return the result as VarType Decimal(14).
LargeInteger = nResult * CDec(10000)

End Function


RBS

Karl E. Peterson

unread,
Nov 13, 2009, 8:45:18 PM11/13/09
to
RB Smissaert wrote:
> Just come across the fact that FileLen has a problem with large files in
> that the result will become negative
> if the filesize exceeds the range of the Long datatype. Now, will there be
> an error if the filesize exceeds twice
> the range of the Long datatype?

Sure, could be. Depends how you approach it. You can't fit a LARGE_INTEGER into a
Long, of course.

> I can't find a file of that size, so I can't test.

Every developer owes it to themself to become familiar with virtual machines.
You'll have plenty of files that big real soon, then! :-)

> The reason I need to know is to make sure this api code will work with those
> large files.
> If not then I will just chuck the FileLen out:

Why are you using that? I guess what you're asking is whether FileLen() will toss
an error with a really huge file? Hmmm, dunno. I'll try... Nope! Looks like it
just wraps around and around...

?filelen("m:\vms\vista\vistaU-bare.vhd")
-1787076608

From a DIR listing...

01/23/2008 01:36 PM 6,802,857,984 VistaU-Bare.vhd

--
.NET: It's About Trust!
http://vfred.mvps.org


RB Smissaert

unread,
Nov 14, 2009, 3:44:52 AM11/14/09
to
Thanks for looking at that and yes, should get a virtual machine really.

> Why are you using that?

Great majority of files passed to the function will be small, so I thought I
might save some time
to try the FileLen first.

> I guess what you're asking is whether FileLen() will toss an error with a
> really huge file?

Exactly, as that would be no good.

> I'll try... Nope! Looks like it just wraps around and around...

OK, thanks and that is no good either, so will need to chuck FileLen out
then.
Maybe FileLen uses that API in any case, so trying FileLen first won't gain
any time in that case.
Will do some timing tests to see if that might be the case.


RBS


"Karl E. Peterson" <ka...@exmvps.org> wrote in message
news:eYrdgwM...@TK2MSFTNGP05.phx.gbl...

Patrice

unread,
Nov 14, 2009, 4:56:56 AM11/14/09
to
The range of a 32 bit integer is 4 Go if I'm not mistaken. So find a file a
bit larger (or just create one) and see how it behaves.

In VB.NET FileLen returns a 64 bit integer and uses cached data readen by
FindFirstFile as well to get the value...

--
Patrice

"RB Smissaert" <bartsm...@blueyonder.co.uk> a �crit dans le message de
news:%23Jly71K...@TK2MSFTNGP05.phx.gbl...

RB Smissaert

unread,
Nov 14, 2009, 5:32:20 AM11/14/09
to
All sorted now and I did some timing and the API method with FindFirstFile
and WIN32_FIND_DATA is only some 10% (this is when reading the same file in
a loop)
slower than the FileLen method, so that is fine.

RBS


"Patrice" <http://scribe-en.blogspot.com/> wrote in message
news:%23uLUPDR...@TK2MSFTNGP04.phx.gbl...

Mike Williams

unread,
Nov 14, 2009, 6:02:48 AM11/14/09
to
"Patrice" <http://scribe-en.blogspot.com/> wrote in message
news:%23uLUPDR...@TK2MSFTNGP04.phx.gbl...

> In VB.NET FileLen returns a 64 bit integer and uses cached


> data readen by FindFirstFile as well to get the value...

WTF has that got to do with it! Go play your silly games somewhere else,
troll!

Mike

RB Smissaert

unread,
Nov 14, 2009, 6:16:16 AM11/14/09
to
Yes, I couldn't see either what the point of that posting was.

RBS


"Mike Williams" <Mi...@WhiskyAndCoke.com> wrote in message
news:uDZ38nR...@TK2MSFTNGP04.phx.gbl...

mayayana

unread,
Nov 14, 2009, 10:39:07 AM11/14/09
to

> Yes, I couldn't see either what the point of that posting was.
>

Based on the impersonal but polite posts that
Patrice has posted in the past, and the limited number
of people that Patrice seems to respond to, I thought
he/she was an MS employee answering MSDN subscribers.

It appears that Patrice is either an MS employee
or just a French DotNettiac. The reply-to address in
the post actually goes to an ad/info. page for .Net,
pretending to be a "blog": scribe-en.blogspot.com

Patrice

unread,
Nov 14, 2009, 2:25:12 PM11/14/09
to

>> In VB.NET FileLen returns a 64 bit integer and uses cached
>> data readen by FindFirstFile as well to get the value...
>
> WTF has that got to do with it! Go play your silly games somewhere else,
> troll!

As the OP uses FindFirstFile as a replacement for FileLen, I thought it
could be interesting to let him know this is also how it is done in .NET. Is
this a problem for you ?

And yes I do still have VB6 application so I'm using .NET for new stuff.
And no I don't care you want to stick with VB6 and we do still have VB6 apps
here though we are using .NET for new stuff.

I never thought my response would raise an agressive remark. Seems some
people are really touchy here...

--
Patrice

Mike Williams

unread,
Nov 14, 2009, 3:04:52 PM11/14/09
to
"Patrice" <http://scribe-en.blogspot.com/> wrote in message
news:%23mbQxAW...@TK2MSFTNGP04.phx.gbl...

> As the OP uses FindFirstFile as a replacement for FileLen,
> I thought it could be interesting to let him know this is also
> how it is done in .NET.

Why restrict yourself to NET? Why not tell him how it's done in Delphi and
Java. In fact why restrict yourself to Windows? Why not tell him how it's
done on a Linux machine or on an Apple Mac? Let's face it, you're just
peddling dotnet! You know very well that NET is not the subject of this
group.

Mike

Patrice

unread,
Nov 15, 2009, 4:22:58 AM11/15/09
to
> Why restrict yourself to NET?

I would have checked the VB6 FileLen implementation if I knew how to do
this. Since then (I even later searched how to do that), it seems that using
a debugger with the MS Symbol server could be an possible approach to see
how it is done in the VB6 runtime.

> Why not tell him how it's done in Delphi and Java.

My next best choice was .NET because I knew how to check the implementation
in no time. It could have been something else as well if it were the
quickest path for me...

> In fact why restrict yourself to Windows? Why not tell him how it's done
> on a Linux machine or on an Apple Mac?

Because ultimately it calls into the Windows API.

> Let's face it, you're just peddling dotnet! You know very well that NET is
> not the subject of this group.

I just thought that as the OP wanted a replacement for the FileLen function,
it would be interesting to see how it is currently implemented in whatever
implementation I could check.

I never suggested to switch to .NET. I just talked about how it is
implemented in .NET (and because I don't know yet how to check the VB6
implementation). Seems to be a crime here.

Any non technical response (such as finding how FileLen is implemented in
VB6) will now be ignored as precisely my goal is not trolling...

--
Patrice

Patrice

unread,
Nov 15, 2009, 4:54:32 AM11/15/09
to
I gave this a look with the IDA tool I downloaded yesterday and found a
rctFileLen function that seems to use FindFirstFileA as well. So VB6 likely
uses the same Windows API than the other runtime I shouldn't have mentioned.

--
Patrice

RB Smissaert

unread,
Nov 15, 2009, 5:52:15 AM11/15/09
to
OK, that might be something interesting.
Could you tell exactly how you did this, so where you downloaded that
application
and how you concluded that FileLen in VB6 uses the FindFirstFile API?

RBS


"Patrice" <http://scribe-en.blogspot.com/> wrote in message

news:ONgcjmdZ...@TK2MSFTNGP05.phx.gbl...

Nobody

unread,
Nov 15, 2009, 10:09:58 AM11/15/09
to
"Patrice" <http://scribe-en.blogspot.com/> wrote in message
news:OEEP6UdZ...@TK2MSFTNGP05.phx.gbl...
> I just talked about how it is implemented in .NxT

<Modified .Nxt word above>

The problem is that this is a classic VB group, and when someone answers
with a .Nxt solution, others who know .Nxt may find fault in the answer, and
post a correction, which may turn into a discussion in what's the proper or
best way to do it in .Nxt.

Also, MS search engine that lists newsgroups would show this group when .Nxt
topics are being discussed. It seems to search post contents. That's why
many here use .Nxt so it doesn't match what the user maybe entering.


Patrice

unread,
Nov 15, 2009, 11:14:58 AM11/15/09
to
> That's why
> many here use .Nxt so it doesn't match what the user maybe entering.

Ok, thanks.

Patrice

unread,
Nov 15, 2009, 11:13:28 AM11/15/09
to
> Could you tell exactly how you did this, so where you downloaded that
> application
> and how you concluded that FileLen in VB6 uses the FindFirstFile API?

I used IDA Pro Freeware which is available from
http://www.hex-rays.com/idapro/idadownfreeware.htm (actually I'm using 4.3 I
downloaded from another site).

Then I loaded msvbvm60.dll and searched for the FileLen text. It should find
a rtcFileLen function which is likely what is called by the VB6 runtime
(mine is 6.0.98.2).

If you double click the sub_72776146 call (or likely the first one in this
routine if you have another version) you'll see that it goes to a routine
that uses a lpFindFileData pointer. If you double click the last jz call in
this routine (I've got jz short loc_72776189 here), you'll see that it calls
FindFirstFileA.

Stepping throught the code could be easier to analyze this in greater
details (and make sure VB gets at rctFileLen first).

--
Patrice

RB Smissaert

unread,
Nov 15, 2009, 11:33:19 AM11/15/09
to
Thanks; will try that out.

RBS


"Patrice" <http://scribe-en.blogspot.com/> wrote in message

news:%23$dxS6gZK...@TK2MSFTNGP02.phx.gbl...

RB Smissaert

unread,
Nov 15, 2009, 3:02:51 PM11/15/09
to
Done this now (but different version 4.5.1.770) and indeed this suggests
that FileLen uses FindFirstFileA. I suppose it was always likely to be the
case.
Interesing and powerful application that IDA!

RBS

"Patrice" <http://scribe-en.blogspot.com/> wrote in message

news:%23$dxS6gZK...@TK2MSFTNGP02.phx.gbl...

Karl E. Peterson

unread,
Nov 16, 2009, 6:50:17 PM11/16/09
to
RB Smissaert wrote:
> Thanks for looking at that and yes, should get a virtual machine really.
>
>> Why are you using that?
> Great majority of files passed to the function will be small, so I thought I
> might save some time to try the FileLen first.

Not the point. You seemed to be using it as way to tell if a file exists. The most
commonly accepted method for that is to use GetAttr.

>> I guess what you're asking is whether FileLen() will toss an error with a
>> really huge file?
> Exactly, as that would be no good.

Nope, it definitely wouldn't.

>> I'll try... Nope! Looks like it just wraps around and around...
> OK, thanks and that is no good either, so will need to chuck FileLen out
> then.
> Maybe FileLen uses that API in any case, so trying FileLen first won't gain
> any time in that case.
> Will do some timing tests to see if that might be the case.

is this what you're looking for?

Public Function FileExists(ByVal FileName As String) As Boolean
Dim nAttr As Long
' Grab this files attributes, and make sure it isn't a folder.
' This test includes cases where file doesn't exist at all.
On Error GoTo NoFile
nAttr = GetAttr(FileName)
If (nAttr And vbDirectory) <> vbDirectory Then
FileExists = True
End If
NoFile:
End Function

Karl E. Peterson

unread,
Nov 16, 2009, 6:52:58 PM11/16/09
to
Patrice wrote:
> I never thought my response would raise an agressive remark. Seems some
> people are really touchy here...

That's often the response to proselytization.

Take the sales pitch elsewhere.

RB Smissaert

unread,
Nov 17, 2009, 3:05:01 AM11/17/09
to
> You seemed to be using it as way to tell if a file exists.

No, I do use GetAttr for that, just as in the function you posted.
The idea was to try the simpler (and faster?) FileLen first before using the
API method.
In any case have this all sorted now and after a minor modification (see
comment in below code)
the API method is now about as fast as the FileLen method:

Public Function FileSizeAPI(strFilePath As String) As Variant

Dim hSearch As Long
Dim WFD As WIN32_FIND_DATA

On Error GoTo ERROROUT

hSearch = FindFirstFile(strFilePath, WFD)

If hSearch = -1 Then
FileSizeAPI = -1
Else

FindClose hSearch 'doing this before the next line makes it faster, not
sure why
FileSizeAPI = LargeInteger(WFD.nFileSizeLow, WFD.nFileSizeHigh)
End If

Exit Function

ERROROUT:
FileSizeAPI = -1

End Function


RBS


"Karl E. Peterson" <ka...@exmvps.org> wrote in message

news:ORpeOex...@TK2MSFTNGP04.phx.gbl...

Karl E. Peterson

unread,
Nov 17, 2009, 1:41:59 PM11/17/09
to
RB Smissaert wrote:
>> You seemed to be using it as way to tell if a file exists.
>
> No, I do use GetAttr for that, just as in the function you posted.
> The idea was to try the simpler (and faster?) FileLen first before using the
> API method.

Ah, I see. Sorry for the quick (mis)reading of the code, there.

> In any case have this all sorted now and after a minor modification (see
> comment in below code) the API method is now about as fast as the FileLen method:

Yeah, I would think. You'd probably see some gains using the W version, too, if
you're so inclined. How many files are you dealing with, that speed is a concern
here?


> Public Function FileSizeAPI(strFilePath As String) As Variant
>
> Dim hSearch As Long
> Dim WFD As WIN32_FIND_DATA
>
> On Error GoTo ERROROUT
>
> hSearch = FindFirstFile(strFilePath, WFD)
>
> If hSearch = -1 Then
> FileSizeAPI = -1
> Else
> FindClose hSearch 'doing this before the next line makes it faster, not
> sure why
> FileSizeAPI = LargeInteger(WFD.nFileSizeLow, WFD.nFileSizeHigh)
> End If
>
> Exit Function
>
> ERROROUT:
> FileSizeAPI = -1
>
> End Function

Another minor, perhaps even negligble, optimization would be to stop comparing a
Long with an Integer in your If test.

Hmmm, also, what's with the error trapping? If speed is an issue, get rid of that,
too. :-)

RB Smissaert

unread,
Nov 17, 2009, 3:41:56 PM11/17/09
to
Usually this will be used just to get the size of one file, so speed is not
an issue, but
I also use it in a loop to read many files, so the faster the better.
This is the optimized version then using your suggestions and it is some 15%
faster than
the posted code:

Private Declare Sub CopyMemory _
Lib "kernel32" _
Alias "RtlMoveMemory" (Dest As Any, _
Src As Any, _
ByVal cBytes As Long)

Private Declare Function FindFirstFile Lib "kernel32" _

Alias "FindFirstFileW" _
(ByVal lpFileName As Long, _


lpFindFileData As WIN32_FIND_DATA) As Long

Private Declare Function FindClose Lib "kernel32" _
(ByVal hFindFile As Long) As Long

Private Const MAX_PATH = 260

Private Type FILETIME
dwLowDateTime As Long
dwHighDateTime As Long
End Type

Private Type WIN32_FIND_DATA
dwFileAttributes As Long
ftCreationTime As FILETIME
ftLastAccessTime As FILETIME
ftLastWriteTime As FILETIME
nFileSizeHigh As Long
nFileSizeLow As Long
dwReserved0 As Long
dwReserved1 As Long

cFileName(0 To (MAX_PATH * 2) - 1) As Byte
cAlternate(0 To 27) As Byte
End Type

Private Function FileSizeAPI(strFilePath As String) As Variant

Dim hSearch As Long
Dim WFD As WIN32_FIND_DATA

hSearch = FindFirstFile(StrPtr(strFilePath), WFD)

If hSearch = -1& Then
FileSizeAPI = -1&
Else
FindClose hSearch


FileSizeAPI = LargeInteger(WFD.nFileSizeLow, WFD.nFileSizeHigh)
End If

End Function

Private Function LargeInteger(ByVal LoPart As Long, _


ByVal HiPart As Long) As Variant

Dim nResult As Currency

'Copy the parts, appropriately.
CopyMemory ByVal VarPtr(nResult), LoPart, 4
CopyMemory ByVal VarPtr(nResult) + 4, HiPart, 4

'Return the result as VarType Decimal(14).
LargeInteger = nResult * CDec(10000)

End Function


Just one thing I don't get and that is that I thought I could do this
(modification suggested by Peter Thornton)
to gain some speed:

If WFD.nFileSizeHigh Then
FileSizeAPI = LargeInteger(WFD.nFileSizeLow, WFD.nFileSizeHigh)
Else
FileSizeAPI = WFD.nFileSizeLow
End If

But that fails now on large files, giving negative figures due to
WFD.nFileSizeHigh = 0
Any idea what I might be doing wrong there?


RBS

"Karl E. Peterson" <ka...@exmvps.org> wrote in message

news:OFM3mW7Z...@TK2MSFTNGP06.phx.gbl...

Karl E. Peterson

unread,
Nov 17, 2009, 4:26:08 PM11/17/09
to
RB Smissaert wrote:
> Usually this will be used just to get the size of one file, so speed is not
> an issue, but
> I also use it in a loop to read many files, so the faster the better.
> This is the optimized version then using your suggestions and it is some 15%
> faster than the posted code:

Nice!

You haven't accounted for the sign bit. You may be able to optimize it, but you'd
need to add 2^32 if it's <0. In the end, the extra tests and math may not pay off.
One possible compromise might be:

If (WFD.nFileSizeHigh = 0) And (WFD.nFileSizeLow > 0) Then
FileSizeAPI = WFD.nFileSizeLow
Else


FileSizeAPI = LargeInteger(WFD.nFileSizeLow, WFD.nFileSizeHigh)
End If

--

RB Smissaert

unread,
Nov 17, 2009, 4:49:53 PM11/17/09
to
One possible compromise might be:

If (WFD.nFileSizeHigh = 0) And (WFD.nFileSizeLow > 0) Then
FileSizeAPI = WFD.nFileSizeLow
Else
FileSizeAPI = LargeInteger(WFD.nFileSizeLow, WFD.nFileSizeHigh)
End If

Yes, that does knock a few percent off.
Actually, let's make that:
If (WFD.nFileSizeHigh = 0&) And (WFD.nFileSizeLow > 0&) Then

Looks we may have the perfect replacement then for FileLen ...


RBS


"Karl E. Peterson" <ka...@exmvps.org> wrote in message

news:%23y%23xVy8Z...@TK2MSFTNGP02.phx.gbl...

Karl E. Peterson

unread,
Nov 17, 2009, 5:13:40 PM11/17/09
to
RB Smissaert wrote:
> One possible compromise might be:
>
> If (WFD.nFileSizeHigh = 0) And (WFD.nFileSizeLow > 0) Then
> FileSizeAPI = WFD.nFileSizeLow
> Else
> FileSizeAPI = LargeInteger(WFD.nFileSizeLow, WFD.nFileSizeHigh)
> End If
>
> Yes, that does knock a few percent off.

Cool.

> Actually, let's make that:
> If (WFD.nFileSizeHigh = 0&) And (WFD.nFileSizeLow > 0&) Then

Heh... touche'

Schmidt

unread,
Nov 18, 2009, 3:48:18 AM11/18/09
to

"RB Smissaert" <bartsm...@blueyonder.co.uk> schrieb im Newsbeitrag
news:O81Av$8ZKHA...@TK2MSFTNGP06.phx.gbl...

> Yes, that does knock a few percent off.

If you can live with the "restriction", that the
routine would work correctly only up to filesizes
of about 922 TeraByte, then you could change the
return-value of the function to Currency instead of Variant,
and another few percentpoints could be gained,
if you omit the LargeInteger-SubRoutine-Call,
as well as doing the CopyMemory-Call only once
(all directly within the FileSizeAPI-Function).
The LargeInteger-Routine can then remain as
correctly as it currently is, it is just not used anymore...

Private Function FileSizeAPI(strFilePath As String) As Currency

Dim hSearch As Long
Dim WFD As WIN32_FIND_DATA

hSearch = FindFirstFile(StrPtr(strFilePath), WFD)

If hSearch = -1& Then
FileSizeAPI = -1&
Else
FindClose hSearch

WFD.dwReserved0 = WFD.nFileSizeHigh
CopyMemory FileSizeAPI, WFD.nFileSizeLow, 8
FileSizeAPI = FileSizeAPI * 10000@
End If

End Function

Olaf


bart.sm...@gmail.com

unread,
Nov 18, 2009, 6:04:12 AM11/18/09
to
Hi Olaf,

On some quick testing it does work, but it looks to be slower than the
last posted code.
Doing this at work and will have a better look at home later.

RBS


On Nov 18, 8:48 am, "Schmidt" <s...@online.de> wrote:
> "RB Smissaert" <bartsmissa...@blueyonder.co.uk> schrieb im Newsbeitragnews:O81Av$8ZKHA...@TK2MSFTNGP06.phx.gbl...

RB Smissaert

unread,
Nov 18, 2009, 8:40:59 AM11/18/09
to
Hi Olaf,

Had a better look now and yes, this knocks a few more percent off, more so
when testing on a large file.
This is the function I will be using then and thanks for the tip.

Function FileSizeAPI(strFilePath As String) As Currency

Dim hFind As Long
Dim WFD As WIN32_FIND_DATA

hFind = FindFirstFile(StrPtr(strFilePath), WFD)

If hFind = -1& Then
FileSizeAPI = -1@
Else
FindClose hFind


If (WFD.nFileSizeHigh = 0&) And (WFD.nFileSizeLow > 0&) Then

FileSizeAPI = WFD.nFileSizeLow
Else
WFD.dwReserved0 = WFD.nFileSizeHigh
CopyMemory FileSizeAPI2, WFD.nFileSizeLow, 8
FileSizeAPI = FileSizeAPI2 * 10000@
End If
End If

End Function


RBS


"Schmidt" <s...@online.de> wrote in message
news:uCisX0C...@TK2MSFTNGP06.phx.gbl...

mayayana

unread,
Nov 18, 2009, 9:06:55 AM11/18/09
to
If it's worth being extremely efficient, couldn't
you also skip the check of the nFileSizeLow? I
assume it can't be < 0.

If (WFD.nFileSizeHigh = 0&) Then
FileSizeAPI = WFD.nFileSizeLow

Also, this is slightly OT -- sorry to hijack your
thread -- but I wonder if someone could explain
why, in an empty folder, FindFirstFile will return
1 valid file handle and 2 names: "." and ".."
It's very strange behavior, making it tricky to
write just a simple "is the folder empty?" routine.

Ian Williams

unread,
Nov 18, 2009, 9:51:55 AM11/18/09
to
RB Smissaert wrote:
> Hi Olaf,
>
> Had a better look now and yes, this knocks a few more percent off, more
> so when testing on a large file.
> This is the function I will be using then and thanks for the tip.
>
> Function FileSizeAPI(strFilePath As String) As Currency
>
> Dim hFind As Long
> Dim WFD As WIN32_FIND_DATA
>
> hFind = FindFirstFile(StrPtr(strFilePath), WFD)
>
> If hFind = -1& Then
> FileSizeAPI = -1@
> Else
> FindClose hFind
> If (WFD.nFileSizeHigh = 0&) And (WFD.nFileSizeLow > 0&) Then
> FileSizeAPI = WFD.nFileSizeLow
> Else
> WFD.dwReserved0 = WFD.nFileSizeHigh
> CopyMemory FileSizeAPI2, WFD.nFileSizeLow, 8
> FileSizeAPI = FileSizeAPI2 * 10000@
> End If
> End If
>
> End Function
>
>
> RBS
<snip>

Here's a slighter simpler version, no CopyMemory involved and no
redundant checking on the nFileSizeHigh value

Public Const INVALID_HANDLE_VALUE = -1
Public Const MAXDWORD = 4294967296#

Function FileSizeApi(ByVal FilePath As String) As Currency
Dim hFile As Long
Dim wfd As WIN32_FIND_DATA
hFile = FindFirstFile(FilePath, wfd)
If hFile <> INVALID_HANDLE_VALUE Then
FindClose hFile
With wfd
FileSizeApi = CCur(.nFileSizeHigh) * MAXDWORD + nFileSizeLow
End With
Else
FileSizeApi = -1
End If
End Function


Ian

Nobody

unread,
Nov 18, 2009, 10:13:19 AM11/18/09
to
"Ian Williams" <i...@kingsoft-dk.com> wrote in message
news:ubufu6Fa...@TK2MSFTNGP06.phx.gbl...

> Here's a slighter simpler version, no CopyMemory involved and no redundant
> checking on the nFileSizeHigh value
>
> Public Const INVALID_HANDLE_VALUE = -1
> Public Const MAXDWORD = 4294967296#
>
> Function FileSizeApi(ByVal FilePath As String) As Currency
> Dim hFile As Long
> Dim wfd As WIN32_FIND_DATA
> hFile = FindFirstFile(FilePath, wfd)
> If hFile <> INVALID_HANDLE_VALUE Then
> FindClose hFile
> With wfd
> FileSizeApi = CCur(.nFileSizeHigh) * MAXDWORD + nFileSizeLow
> End With
> Else
> FileSizeApi = -1
> End If
> End Function

Unfortunately, CConvert functions seem to be implemented in VB6 as function
calls. I have seen the assembly output for some of them(From memory CLng),
not CCur in particular. However, I believe that you can do what you want if
you declare the constant As Currency. Example:

Public Const MAXDWORD = 4294967296@

Or

Public Const MAXDWORD As Currency = 4294967296@

Then:

FileSizeApi = MAXDWORD * .nFileSizeHigh + .nFileSizeLow

Bob Butler

unread,
Nov 18, 2009, 10:14:49 AM11/18/09
to

"Ian Williams" <i...@kingsoft-dk.com> wrote in message
news:ubufu6Fa...@TK2MSFTNGP06.phx.gbl...
> RB Smissaert wrote:
<cut>

>> If (WFD.nFileSizeHigh = 0&) And (WFD.nFileSizeLow > 0&) Then
>> FileSizeAPI = WFD.nFileSizeLow
<cut>

> FileSizeApi = CCur(.nFileSizeHigh) * MAXDWORD + nFileSizeLow

If the file size is between &H80000000 and &HFFFFFFFF then won't
nFileSizeLow be a negative value?


Ian Williams

unread,
Nov 18, 2009, 10:32:14 AM11/18/09
to
Nobody wrote:
<
> Unfortunately, CConvert functions seem to be implemented in VB6 as function
> calls. I have seen the assembly output for some of them(From memory CLng),
> not CCur in particular. However, I believe that you can do what you want if
> you declare the constant As Currency. Example:
>
> Public Const MAXDWORD = 4294967296@
>
> Or
>
> Public Const MAXDWORD As Currency = 4294967296@
>
> Then:
>
> FileSizeApi = MAXDWORD * .nFileSizeHigh + .nFileSizeLow
>
>
>

It was the IDE that changed the type declaration to Double.

I've also spotted that the function messes up when checking a file which
is between 2GB & 4GB - you get a negative result, so here's one that works.

Ian

Public Const MAXDWORD As Currency = 4294967296@

Function FileSizeApi(ByVal FilePath As String) As Currency


Dim hFile As Long
Dim wfd As WIN32_FIND_DATA
hFile = FindFirstFile(FilePath, wfd)
If hFile <> INVALID_HANDLE_VALUE Then
FindClose hFile
With wfd

If .nFileSizeLow < 0 Then
FileSizeApi = MAXDWORD + .nFileSizeLow
Else
FileSizeApi = .nFileSizeLow
End If
FileSizeApi = MAXDWORD * .nFileSizeHigh + FileSizeApi
End With
Else
FileSizeApi = INVALID_HANDLE_VALUE
End If
End Function

bart.sm...@gmail.com

unread,
Nov 18, 2009, 11:46:24 AM11/18/09
to
OK, can't remember getting wrong results with the code I posted last,
but maybe I missed that particular range.
Will check it out.
I take it it still makes sense to go with FindFirstFileW

RBS

Nobody

unread,
Nov 18, 2009, 11:58:56 AM11/18/09
to
"Nobody" <nob...@nobody.com> wrote in message
news:Oxaa5GGa...@TK2MSFTNGP04.phx.gbl...

> Unfortunately, CConvert functions seem to be implemented in VB6 as
> function calls.

The above is incorrect. It seems that VB use the most "efficient" method to
convert from the given data type. For example, if you provide an integer
values to CInteger or CLng, little or no conversion is done. But if you
supply a String to CInteger or CLng, a function call is made to do the
conversion. This seems like C++ function templates and/or function
overloading where one or more version of the same function is written to
support each data type, and the compiler picks the one that match the data
type exactly, so the least amount of code is generated, and in cases where
the data types are identical or very similar, a direct assignment is used,
as if you didn't use the conversion function. VB compiler seems to translate
the code to intermediate code that is common with C++. VB's run time error
handling is similar to C++ exception handling, they behave mostly in the
same way.

See this article if you want to know what C++ function templates are:

http://en.wikipedia.org/wiki/C%2B%2B_Templates

Here are some situations that I tested. First the summary, followed by the
source code and assembly output. In the assembly output, skip the first few
lines which is code that VB generates to setup the error handler, even if
the source doesn't have error handler, so it shows the default error handler
message box. Watch for wrapped lines.

Situation 1: Using CLng(7) to convert to Long.
Result 1: Using CLng() has no impact.

Situation 2: Using CLng("7") to convert to Long.
Result 2: VB calls vbaI4Str() to do the conversion. "I4" in "vbaI4Str" seems
to stand for "4 bytes integer", which is Long in VB.

Situation 3: Using CLng(7) to convert to Currency.
Result 3: VB calls vbaCyI4() to do the conversion.

Situation 4: Same as above, but using Long variable instead of 7.
Result 4: Same result as above.

Situation 5: Assigning number 7 to a Currency variable.
Result 5: VB calls vbaCyI2() to do the conversion. "I2" in "vbaCyI2" seems
to stand for "2 bytes integer", which is Long in VB.

Situation 6: Assigning number 33333 to a Currency variable.
Result 6: VB calls vbaCyI4() to do the conversion. Note this has "I4" in the
function name, not "I2" like above. Constants that you use in code without
any type letter are treated as Integer if they fall in the range -32768 to
+32767. If you use "&", VB would treat the number as Long(4 bytes). This is
the same way C++ work, BTW.

Situation 7: Same as Situation 5, but using Long variable instead of 7.
Result 7: Same result as Situation 6.

Situation 8: Assigning number 7 declared as Currency Const to a Currency
variable.
Result 8: VB assigns &H11170 to the variable. &H11170 = 70000. Currency
values are scaled by a factor of 10000, so 70000 means 7.

Situation 9: Using the following formula:

Private Const MAXDWORD As Currency = 4294967296

<CurrencyVar> = MAXDWORD * <LongVar1> + <LongVar2>

Result 9: VB converts <LongVar1> to Currency using vbaCyI4, then multiply it
by MAXDWORD using vbaCyMul function call, then adds <LongVar2> to it using
vbaCyAdd function call.

Situation 10: Using LSet as suggested in this article:

How To Do 64-bit Arithmetic in VBA
http://support.microsoft.com/kb/189862

Sample code:

Private Type MungeCurr
Value As Currency
End Type

Private Type Munge2Long
LoValue As Long
HiValue As Long
End Type

Dim Src As Munge2Long
Dim Dest As MungeCurr

Src.LoValue = <LongVar1>
Src.HiValue = <LongVar2>
LSet Dest = Src
Dest.Value = Dest.Value * 10000


Result 10: VB assigns the Long variables, then calls vbaCopyBytes to perform
what "LSet" does. Then calls vbaCyMulI2 to multiply by 10000.

Situation 1: Using CLng(7) to convert to Long:
==============================================


Option Explicit

Dim i As Long
Dim j As Long
Dim k As Long

Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single,
Y As Single)
i = 3
j = CLng(7)
k = 9
End Sub

24: Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As
Single, Y As Single)
00401980 55 push ebp
00401981 8B EC mov ebp,esp
00401983 83 EC 0C sub esp,0Ch
00401986 68 B6 10 40 00 push offset ___vbaExceptHandler
(004010b6)
0040198B 64 A1 00 00 00 00 mov eax,fs:[00000000]
00401991 50 push eax
00401992 64 89 25 00 00 00 00 mov dword ptr fs:[0],esp
00401999 83 EC 08 sub esp,8
0040199C 53 push ebx
0040199D 56 push esi
0040199E 57 push edi
0040199F 89 65 F4 mov dword ptr [ebp-0Ch],esp
004019A2 C7 45 F8 A0 10 40 00 mov dword ptr [ebp-8],offset
__imp___CIexp+34h (004010a0)
004019A9 8B 75 08 mov esi,dword ptr [Me]
004019AC 8B C6 mov eax,esi
004019AE 83 E0 01 and eax,1
004019B1 89 45 FC mov dword ptr [ebp-4],eax
004019B4 83 E6 FE and esi,0FFFFFFFEh
004019B7 56 push esi
004019B8 89 75 08 mov dword ptr [Me],esi
004019BB 8B 0E mov ecx,dword ptr [esi]
004019BD FF 51 04 call dword ptr [ecx+4]
25: i = 3
004019C0 C7 46 34 03 00 00 00 mov dword ptr [esi+34h],3
26: j = CLng(7)
004019C7 C7 46 38 07 00 00 00 mov dword ptr [esi+38h],7
27: k = 9
004019CE C7 46 3C 09 00 00 00 mov dword ptr [esi+3Ch],9
28: End Sub
004019D5 C7 45 FC 00 00 00 00 mov dword ptr [ebp-4],0
$L26:
004019DC 8B 45 08 mov eax,dword ptr [Me]
004019DF 50 push eax
004019E0 8B 10 mov edx,dword ptr [eax]
004019E2 FF 52 08 call dword ptr [edx+8]
004019E5 8B 45 FC mov eax,dword ptr [ebp-4]
004019E8 8B 4D EC mov ecx,dword ptr [ebp-14h]
004019EB 5F pop edi
004019EC 5E pop esi
004019ED 64 89 0D 00 00 00 00 mov dword ptr fs:[0],ecx
004019F4 5B pop ebx
004019F5 8B E5 mov esp,ebp
004019F7 5D pop ebp
004019F8 C2 14 00 ret 14h

Situation 2: Using CLng("7") to convert to Long:
================================================


Option Explicit

Dim i As Long
Dim j As Long
Dim k As Long

Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single,
Y As Single)
i = 3
j = CLng("7")
k = 9
End Sub

24: Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As
Single, Y As Single)
004019A0 55 push ebp
004019A1 8B EC mov ebp,esp
004019A3 83 EC 0C sub esp,0Ch
004019A6 68 B6 10 40 00 push offset ___vbaExceptHandler
(004010b6)
004019AB 64 A1 00 00 00 00 mov eax,fs:[00000000]
004019B1 50 push eax
004019B2 64 89 25 00 00 00 00 mov dword ptr fs:[0],esp
004019B9 83 EC 08 sub esp,8
004019BC 53 push ebx
004019BD 56 push esi
004019BE 57 push edi
004019BF 89 65 F4 mov dword ptr [ebp-0Ch],esp
004019C2 C7 45 F8 A0 10 40 00 mov dword ptr [ebp-8],offset
__imp___CIexp+30h (004010a0)
004019C9 8B 75 08 mov esi,dword ptr [Me]
004019CC 8B C6 mov eax,esi
004019CE 83 E0 01 and eax,1
004019D1 89 45 FC mov dword ptr [ebp-4],eax
004019D4 83 E6 FE and esi,0FFFFFFFEh
004019D7 56 push esi
004019D8 89 75 08 mov dword ptr [Me],esi
004019DB 8B 0E mov ecx,dword ptr [esi]
004019DD FF 51 04 call dword ptr [ecx+4]
25: i = 3
26: j = CLng("7")
004019E0 68 68 16 40 00 push offset ___vba@03EE01E0 (00401668)
004019E5 C7 46 34 03 00 00 00 mov dword ptr [esi+34h],3
004019EC FF 15 54 10 40 00 call dword ptr [__imp____vbaI4Str
(00401054)]
004019F2 89 46 38 mov dword ptr [esi+38h],eax
27: k = 9
004019F5 C7 46 3C 09 00 00 00 mov dword ptr [esi+3Ch],9
28: End Sub
004019FC C7 45 FC 00 00 00 00 mov dword ptr [ebp-4],0
$L26:
00401A03 8B 45 08 mov eax,dword ptr [Me]
00401A06 50 push eax
00401A07 8B 10 mov edx,dword ptr [eax]
00401A09 FF 52 08 call dword ptr [edx+8]
00401A0C 8B 45 FC mov eax,dword ptr [ebp-4]
00401A0F 8B 4D EC mov ecx,dword ptr [ebp-14h]
00401A12 5F pop edi
00401A13 5E pop esi
00401A14 64 89 0D 00 00 00 00 mov dword ptr fs:[0],ecx
00401A1B 5B pop ebx
00401A1C 8B E5 mov esp,ebp
00401A1E 5D pop ebp
00401A1F C2 14 00 ret 14h


Situation 3: Using CLng(7) to convert to Currency:
==================================================

Option Explicit

Dim i As Long
Dim j As Long
Dim k As Currency
Dim m As Long

Private Sub Form_Load()
i = 7
End Sub

Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single,
Y As Single)
j = 3
k = CLng(7)
m = 9
End Sub

29: Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As
Single, Y As Single)
00401A30 55 push ebp
00401A31 8B EC mov ebp,esp
00401A33 83 EC 0C sub esp,0Ch
00401A36 68 B6 10 40 00 push offset ___vbaExceptHandler
(004010b6)
00401A3B 64 A1 00 00 00 00 mov eax,fs:[00000000]
00401A41 50 push eax
00401A42 64 89 25 00 00 00 00 mov dword ptr fs:[0],esp
00401A49 83 EC 08 sub esp,8
00401A4C 53 push ebx
00401A4D 56 push esi
00401A4E 57 push edi
00401A4F 89 65 F4 mov dword ptr [ebp-0Ch],esp
00401A52 C7 45 F8 A8 10 40 00 mov dword ptr [ebp-8],offset
__imp___CIexp+38h (004010a8)
00401A59 8B 75 08 mov esi,dword ptr [Me]
00401A5C 8B C6 mov eax,esi
00401A5E 83 E0 01 and eax,1
00401A61 89 45 FC mov dword ptr [ebp-4],eax
00401A64 83 E6 FE and esi,0FFFFFFFEh
00401A67 56 push esi
00401A68 89 75 08 mov dword ptr [Me],esi
00401A6B 8B 0E mov ecx,dword ptr [esi]
00401A6D FF 51 04 call dword ptr [ecx+4]
30: j = 3
31: k = CLng(7)
00401A70 6A 07 push 7
00401A72 C7 46 38 03 00 00 00 mov dword ptr [esi+38h],3
00401A79 FF 15 28 10 40 00 call dword ptr [__imp_@__vbaCyI4
(00401028)]
00401A7F 89 46 3C mov dword ptr [esi+3Ch],eax
00401A82 89 56 40 mov dword ptr [esi+40h],edx
32: m = 9
00401A85 C7 46 44 09 00 00 00 mov dword ptr [esi+44h],9
33: End Sub
00401A8C C7 45 FC 00 00 00 00 mov dword ptr [ebp-4],0
$L32:
00401A93 8B 45 08 mov eax,dword ptr [Me]
00401A96 50 push eax
00401A97 8B 10 mov edx,dword ptr [eax]
00401A99 FF 52 08 call dword ptr [edx+8]
00401A9C 8B 45 FC mov eax,dword ptr [ebp-4]
00401A9F 8B 4D EC mov ecx,dword ptr [ebp-14h]
00401AA2 5F pop edi
00401AA3 5E pop esi
00401AA4 64 89 0D 00 00 00 00 mov dword ptr fs:[0],ecx
00401AAB 5B pop ebx
00401AAC 8B E5 mov esp,ebp
00401AAE 5D pop ebp
00401AAF C2 14 00 ret 14h


Situation 4: Same as above, but using Long variable instead of 7:
=================================================================


Option Explicit

Dim i As Long
Dim j As Long
Dim k As Currency
Dim m As Long

Private Sub Form_Load()
i = 7
End Sub

Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single,
Y As Single)
j = 3
k = CLng(i)
m = 9
End Sub


29: Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As
Single, Y As Single)
00401A30 55 push ebp
00401A31 8B EC mov ebp,esp
00401A33 83 EC 0C sub esp,0Ch
00401A36 68 B6 10 40 00 push offset ___vbaExceptHandler
(004010b6)
00401A3B 64 A1 00 00 00 00 mov eax,fs:[00000000]
00401A41 50 push eax
00401A42 64 89 25 00 00 00 00 mov dword ptr fs:[0],esp
00401A49 83 EC 08 sub esp,8
00401A4C 53 push ebx
00401A4D 56 push esi
00401A4E 57 push edi
00401A4F 89 65 F4 mov dword ptr [ebp-0Ch],esp
00401A52 C7 45 F8 A8 10 40 00 mov dword ptr [ebp-8],offset
__imp___CIexp+38h (004010a8)
00401A59 8B 75 08 mov esi,dword ptr [Me]
00401A5C 8B C6 mov eax,esi
00401A5E 83 E0 01 and eax,1
00401A61 89 45 FC mov dword ptr [ebp-4],eax
00401A64 83 E6 FE and esi,0FFFFFFFEh
00401A67 56 push esi
00401A68 89 75 08 mov dword ptr [Me],esi
00401A6B 8B 0E mov ecx,dword ptr [esi]
00401A6D FF 51 04 call dword ptr [ecx+4]
30: j = 3
31: k = CLng(i)
00401A70 8B 56 34 mov edx,dword ptr [esi+34h]
00401A73 C7 46 38 03 00 00 00 mov dword ptr [esi+38h],3
00401A7A 52 push edx
00401A7B FF 15 28 10 40 00 call dword ptr [__imp____vbaCyI4
(00401028)]
00401A81 89 46 3C mov dword ptr [esi+3Ch],eax
00401A84 89 56 40 mov dword ptr [esi+40h],edx
32: m = 9
00401A87 C7 46 44 09 00 00 00 mov dword ptr [esi+44h],9
33: End Sub
00401A8E C7 45 FC 00 00 00 00 mov dword ptr [ebp-4],0
$L32:
00401A95 8B 45 08 mov eax,dword ptr [Me]
00401A98 50 push eax
00401A99 8B 08 mov ecx,dword ptr [eax]
00401A9B FF 51 08 call dword ptr [ecx+8]
00401A9E 8B 45 FC mov eax,dword ptr [ebp-4]
00401AA1 8B 4D EC mov ecx,dword ptr [ebp-14h]
00401AA4 5F pop edi
00401AA5 5E pop esi
00401AA6 64 89 0D 00 00 00 00 mov dword ptr fs:[0],ecx
00401AAD 5B pop ebx
00401AAE 8B E5 mov esp,ebp
00401AB0 5D pop ebp
00401AB1 C2 14 00 ret 14h

Situation 5: Assigning number 7 to a Currency variable:
=======================================================

Option Explicit

Dim i As Long
Dim j As Long
Dim k As Currency
Dim m As Long

Private Sub Form_Load()
'i = 7
End Sub

Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single,
Y As Single)
j = 3
k = 7
m = 9
End Sub

29: Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As
Single, Y As Single)
00401A30 55 push ebp
00401A31 8B EC mov ebp,esp
00401A33 83 EC 0C sub esp,0Ch
00401A36 68 B6 10 40 00 push offset ___vbaExceptHandler
(004010b6)
00401A3B 64 A1 00 00 00 00 mov eax,fs:[00000000]
00401A41 50 push eax
00401A42 64 89 25 00 00 00 00 mov dword ptr fs:[0],esp
00401A49 83 EC 08 sub esp,8
00401A4C 53 push ebx
00401A4D 56 push esi
00401A4E 57 push edi
00401A4F 89 65 F4 mov dword ptr [ebp-0Ch],esp
00401A52 C7 45 F8 A8 10 40 00 mov dword ptr [ebp-8],offset
__imp___CIexp+38h (004010a8)
00401A59 8B 75 08 mov esi,dword ptr [Me]
00401A5C 8B C6 mov eax,esi
00401A5E 83 E0 01 and eax,1
00401A61 89 45 FC mov dword ptr [ebp-4],eax
00401A64 83 E6 FE and esi,0FFFFFFFEh
00401A67 56 push esi
00401A68 89 75 08 mov dword ptr [Me],esi
00401A6B 8B 0E mov ecx,dword ptr [esi]
00401A6D FF 51 04 call dword ptr [ecx+4]
30: j = 3
31: k = 7
00401A70 6A 07 push 7
00401A72 C7 46 38 03 00 00 00 mov dword ptr [esi+38h],3
00401A79 FF 15 28 10 40 00 call dword ptr [__imp_@__vbaCyI2
(00401028)]
00401A7F 89 46 3C mov dword ptr [esi+3Ch],eax
00401A82 89 56 40 mov dword ptr [esi+40h],edx
32: m = 9
00401A85 C7 46 44 09 00 00 00 mov dword ptr [esi+44h],9
33: End Sub
00401A8C C7 45 FC 00 00 00 00 mov dword ptr [ebp-4],0
$L32:
00401A93 8B 45 08 mov eax,dword ptr [Me]
00401A96 50 push eax
00401A97 8B 10 mov edx,dword ptr [eax]
00401A99 FF 52 08 call dword ptr [edx+8]
00401A9C 8B 45 FC mov eax,dword ptr [ebp-4]
00401A9F 8B 4D EC mov ecx,dword ptr [ebp-14h]
00401AA2 5F pop edi
00401AA3 5E pop esi
00401AA4 64 89 0D 00 00 00 00 mov dword ptr fs:[0],ecx
00401AAB 5B pop ebx
00401AAC 8B E5 mov esp,ebp
00401AAE 5D pop ebp
00401AAF C2 14 00 ret 14h

Situation 6: Assigning number 33333 to a Currency variable:
===========================================================

Option Explicit

Dim i As Long
Dim j As Long
Dim k As Currency
Dim m As Long

Private Sub Form_Load()
'i = 7
End Sub

Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single,
Y As Single)
j = 3
k = 33333
m = 9
End Sub


29: Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As
Single, Y As Single)
00401A30 55 push ebp
00401A31 8B EC mov ebp,esp
00401A33 83 EC 0C sub esp,0Ch
00401A36 68 B6 10 40 00 push offset ___vbaExceptHandler
(004010b6)
00401A3B 64 A1 00 00 00 00 mov eax,fs:[00000000]
00401A41 50 push eax
00401A42 64 89 25 00 00 00 00 mov dword ptr fs:[0],esp
00401A49 83 EC 08 sub esp,8
00401A4C 53 push ebx
00401A4D 56 push esi
00401A4E 57 push edi
00401A4F 89 65 F4 mov dword ptr [ebp-0Ch],esp
00401A52 C7 45 F8 A8 10 40 00 mov dword ptr [ebp-8],offset
__imp___CIexp+38h (004010a8)
00401A59 8B 75 08 mov esi,dword ptr [Me]
00401A5C 8B C6 mov eax,esi
00401A5E 83 E0 01 and eax,1
00401A61 89 45 FC mov dword ptr [ebp-4],eax
00401A64 83 E6 FE and esi,0FFFFFFFEh
00401A67 56 push esi
00401A68 89 75 08 mov dword ptr [Me],esi
00401A6B 8B 0E mov ecx,dword ptr [esi]
00401A6D FF 51 04 call dword ptr [ecx+4]
30: j = 3
31: k = 33333
00401A70 68 35 82 00 00 push 8235h
00401A75 C7 46 38 03 00 00 00 mov dword ptr [esi+38h],3
00401A7C FF 15 28 10 40 00 call dword ptr [__imp_@__vbaCyI4
(00401028)]
00401A82 89 46 3C mov dword ptr [esi+3Ch],eax
00401A85 89 56 40 mov dword ptr [esi+40h],edx
32: m = 9
00401A88 C7 46 44 09 00 00 00 mov dword ptr [esi+44h],9
33: End Sub
00401A8F C7 45 FC 00 00 00 00 mov dword ptr [ebp-4],0
$L32:
00401A96 8B 45 08 mov eax,dword ptr [Me]
00401A99 50 push eax
00401A9A 8B 10 mov edx,dword ptr [eax]
00401A9C FF 52 08 call dword ptr [edx+8]
00401A9F 8B 45 FC mov eax,dword ptr [ebp-4]
00401AA2 8B 4D EC mov ecx,dword ptr [ebp-14h]
00401AA5 5F pop edi
00401AA6 5E pop esi
00401AA7 64 89 0D 00 00 00 00 mov dword ptr fs:[0],ecx
00401AAE 5B pop ebx
00401AAF 8B E5 mov esp,ebp
00401AB1 5D pop ebp
00401AB2 C2 14 00 ret 14h


Situation 7: Same as Situation 5, but using Long variable instead of 7:
=======================================================================

Option Explicit

Dim i As Long
Dim j As Long
Dim k As Currency
Dim m As Long

Private Sub Form_Load()
i = 7
End Sub

Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single,
Y As Single)
j = 3
k = i
m = 9
End Sub

29: Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As
Single, Y As Single)
00401A30 55 push ebp
00401A31 8B EC mov ebp,esp
00401A33 83 EC 0C sub esp,0Ch
00401A36 68 B6 10 40 00 push offset ___vbaExceptHandler
(004010b6)
00401A3B 64 A1 00 00 00 00 mov eax,fs:[00000000]
00401A41 50 push eax
00401A42 64 89 25 00 00 00 00 mov dword ptr fs:[0],esp
00401A49 83 EC 08 sub esp,8
00401A4C 53 push ebx
00401A4D 56 push esi
00401A4E 57 push edi
00401A4F 89 65 F4 mov dword ptr [ebp-0Ch],esp
00401A52 C7 45 F8 A8 10 40 00 mov dword ptr [ebp-8],offset
__imp___CIexp+38h (004010a8)
00401A59 8B 75 08 mov esi,dword ptr [Me]
00401A5C 8B C6 mov eax,esi
00401A5E 83 E0 01 and eax,1
00401A61 89 45 FC mov dword ptr [ebp-4],eax
00401A64 83 E6 FE and esi,0FFFFFFFEh
00401A67 56 push esi
00401A68 89 75 08 mov dword ptr [Me],esi
00401A6B 8B 0E mov ecx,dword ptr [esi]
00401A6D FF 51 04 call dword ptr [ecx+4]
30: j = 3
31: k = i
00401A70 8B 56 34 mov edx,dword ptr [esi+34h]
00401A73 C7 46 38 03 00 00 00 mov dword ptr [esi+38h],3
00401A7A 52 push edx
00401A7B FF 15 28 10 40 00 call dword ptr [__imp_@__vbaCyI4
(00401028)]
00401A81 89 46 3C mov dword ptr [esi+3Ch],eax
00401A84 89 56 40 mov dword ptr [esi+40h],edx
32: m = 9
00401A87 C7 46 44 09 00 00 00 mov dword ptr [esi+44h],9
33: End Sub
00401A8E C7 45 FC 00 00 00 00 mov dword ptr [ebp-4],0
$L32:
00401A95 8B 45 08 mov eax,dword ptr [Me]
00401A98 50 push eax
00401A99 8B 08 mov ecx,dword ptr [eax]
00401A9B FF 51 08 call dword ptr [ecx+8]
00401A9E 8B 45 FC mov eax,dword ptr [ebp-4]
00401AA1 8B 4D EC mov ecx,dword ptr [ebp-14h]
00401AA4 5F pop edi
00401AA5 5E pop esi
00401AA6 64 89 0D 00 00 00 00 mov dword ptr fs:[0],ecx
00401AAD 5B pop ebx
00401AAE 8B E5 mov esp,ebp
00401AB0 5D pop ebp
00401AB1 C2 14 00 ret 14h


Situation 8: Assigning number 7 declared as Currency Const to a Currency
variable:
==================================================================================

Option Explicit

Private Const C As Currency = 7

Dim i As Long
Dim j As Long
Dim k As Currency
Dim m As Long

Private Sub Form_Load()
'i = 7
End Sub

Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single,
Y As Single)
j = 3
k = C
m = 9
End Sub


31: Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As
Single, Y As Single)
00401A10 55 push ebp
00401A11 8B EC mov ebp,esp
00401A13 83 EC 0C sub esp,0Ch
00401A16 68 B6 10 40 00 push offset ___vbaExceptHandler
(004010b6)
00401A1B 64 A1 00 00 00 00 mov eax,fs:[00000000]
00401A21 50 push eax
00401A22 64 89 25 00 00 00 00 mov dword ptr fs:[0],esp
00401A29 83 EC 08 sub esp,8
00401A2C 53 push ebx
00401A2D 56 push esi
00401A2E 57 push edi
00401A2F 89 65 F4 mov dword ptr [ebp-0Ch],esp
00401A32 C7 45 F8 A8 10 40 00 mov dword ptr [ebp-8],offset
__imp___CIexp+3Ch (004010a8)
00401A39 8B 75 08 mov esi,dword ptr [Me]
00401A3C 8B C6 mov eax,esi
00401A3E 83 E0 01 and eax,1
00401A41 89 45 FC mov dword ptr [ebp-4],eax
00401A44 83 E6 FE and esi,0FFFFFFFEh
00401A47 56 push esi
00401A48 89 75 08 mov dword ptr [Me],esi
00401A4B 8B 0E mov ecx,dword ptr [esi]
00401A4D FF 51 04 call dword ptr [ecx+4]
32: j = 3
33: k = C
00401A50 33 C0 xor eax,eax
00401A52 C7 46 3C 70 11 01 00 mov dword ptr [esi+3Ch],11170h
00401A59 C7 46 38 03 00 00 00 mov dword ptr [esi+38h],3
00401A60 89 46 40 mov dword ptr [esi+40h],eax
34: m = 9
00401A63 C7 46 44 09 00 00 00 mov dword ptr [esi+44h],9
35: End Sub
00401A6A 89 45 FC mov dword ptr [ebp-4],eax
$L32:
00401A6D 8B 45 08 mov eax,dword ptr [Me]
00401A70 50 push eax
00401A71 8B 10 mov edx,dword ptr [eax]
00401A73 FF 52 08 call dword ptr [edx+8]
00401A76 8B 45 FC mov eax,dword ptr [ebp-4]
00401A79 8B 4D EC mov ecx,dword ptr [ebp-14h]
00401A7C 5F pop edi
00401A7D 5E pop esi
00401A7E 64 89 0D 00 00 00 00 mov dword ptr fs:[0],ecx
00401A85 5B pop ebx
00401A86 8B E5 mov esp,ebp
00401A88 5D pop ebp
00401A89 C2 14 00 ret 14h


Situation 9: Using a formula:
=============================

Option Explicit

Private Const MAXDWORD As Currency = 4294967296#
Private Const C As Currency = 7

Dim i As Long
Dim j As Long
Dim k As Currency
Dim m As Long
Dim n As Long

Private Sub Form_Load()
i = 7
j = 3
End Sub

Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single,
Y As Single)
n = 5
k = MAXDWORD * i + j
m = 9
End Sub


34: Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As
Single, Y As Single)
00401A70 55 push ebp
00401A71 8B EC mov ebp,esp
00401A73 83 EC 0C sub esp,0Ch
00401A76 68 B6 10 40 00 push offset ___vbaExceptHandler
(004010b6)
00401A7B 64 A1 00 00 00 00 mov eax,fs:[00000000]
00401A81 50 push eax
00401A82 64 89 25 00 00 00 00 mov dword ptr fs:[0],esp
00401A89 83 EC 08 sub esp,8
00401A8C 53 push ebx
00401A8D 56 push esi
00401A8E 57 push edi
00401A8F 89 65 F4 mov dword ptr [ebp-0Ch],esp
00401A92 C7 45 F8 A8 10 40 00 mov dword ptr [ebp-8],offset
__imp___CIexp+30h (004010a8)
00401A99 8B 75 08 mov esi,dword ptr [Me]
00401A9C 8B C6 mov eax,esi
00401A9E 83 E0 01 and eax,1
00401AA1 89 45 FC mov dword ptr [ebp-4],eax
00401AA4 83 E6 FE and esi,0FFFFFFFEh
00401AA7 56 push esi
00401AA8 89 75 08 mov dword ptr [Me],esi
00401AAB 8B 0E mov ecx,dword ptr [esi]
00401AAD FF 51 04 call dword ptr [ecx+4]
35: n = 5
36: k = MAXDWORD * i + j
00401AB0 8B 56 38 mov edx,dword ptr [esi+38h]
00401AB3 8B 3D 30 10 40 00 mov edi,dword ptr [__imp_@__vbaCyI4
(00401030)]
00401AB9 52 push edx
00401ABA C7 46 48 05 00 00 00 mov dword ptr [esi+48h],5
00401AC1 FF D7 call edi
00401AC3 52 push edx
00401AC4 50 push eax
00401AC5 8B 46 34 mov eax,dword ptr [esi+34h]
00401AC8 50 push eax
00401AC9 FF D7 call edi
00401ACB 52 push edx
00401ACC 50 push eax
00401ACD 68 10 27 00 00 push 2710h
00401AD2 6A 00 push 0
00401AD4 FF 15 08 10 40 00 call dword ptr [__imp_@__vbaCyMul
(00401008)]
00401ADA 52 push edx
00401ADB 50 push eax
00401ADC FF 15 18 10 40 00 call dword ptr [__imp____vbaCyAdd
(00401018)]
00401AE2 89 46 3C mov dword ptr [esi+3Ch],eax
00401AE5 89 56 40 mov dword ptr [esi+40h],edx
37: m = 9
00401AE8 C7 46 44 09 00 00 00 mov dword ptr [esi+44h],9
38: End Sub
00401AEF C7 45 FC 00 00 00 00 mov dword ptr [ebp-4],0
$L32:
00401AF6 8B 45 08 mov eax,dword ptr [Me]
00401AF9 50 push eax
00401AFA 8B 08 mov ecx,dword ptr [eax]
00401AFC FF 51 08 call dword ptr [ecx+8]
00401AFF 8B 45 FC mov eax,dword ptr [ebp-4]
00401B02 8B 4D EC mov ecx,dword ptr [ebp-14h]
00401B05 5F pop edi
00401B06 5E pop esi
00401B07 64 89 0D 00 00 00 00 mov dword ptr fs:[0],ecx
00401B0E 5B pop ebx
00401B0F 8B E5 mov esp,ebp
00401B11 5D pop ebp
00401B12 C2 14 00 ret 14h

Situation 10: Using LSet
========================


Option Explicit

Private Const MAXDWORD As Currency = 4294967296#
Private Const c As Currency = 7

Private Type MungeCurr
Value As Currency
End Type

Private Type Munge2Long
LoValue As Long
HiValue As Long
End Type

Dim i As Long
Dim j As Long
Dim k As Currency
Dim m As Long
Dim n As Long

Private Sub Form_Load()
i = 7
j = 3
End Sub

Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single,
Y As Single)
Dim Src As Munge2Long
Dim Dest As MungeCurr

n = 5
Src.LoValue = i
Src.HiValue = j
LSet Dest = Src
Dest.Value = Dest.Value * 10000
m = 9
End Sub

43: Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As
Single, Y As Single)
00401A70 55 push ebp
00401A71 8B EC mov ebp,esp
00401A73 83 EC 0C sub esp,0Ch
00401A76 68 B6 10 40 00 push offset ___vbaExceptHandler
(004010b6)
00401A7B 64 A1 00 00 00 00 mov eax,fs:[00000000]
00401A81 50 push eax
00401A82 64 89 25 00 00 00 00 mov dword ptr fs:[0],esp
00401A89 83 EC 18 sub esp,18h
00401A8C 53 push ebx
00401A8D 56 push esi
00401A8E 57 push edi
00401A8F 89 65 F4 mov dword ptr [ebp-0Ch],esp
00401A92 C7 45 F8 A8 10 40 00 mov dword ptr [ebp-8],offset
__imp___CIexp+34h (004010a8)
00401A99 8B 75 08 mov esi,dword ptr [Me]
00401A9C 8B C6 mov eax,esi
00401A9E 83 E0 01 and eax,1
00401AA1 89 45 FC mov dword ptr [ebp-4],eax
00401AA4 83 E6 FE and esi,0FFFFFFFEh
00401AA7 56 push esi
00401AA8 89 75 08 mov dword ptr [Me],esi
00401AAB 8B 0E mov ecx,dword ptr [esi]
00401AAD FF 51 04 call dword ptr [ecx+4]
44: Dim Src As Munge2Long
45: Dim Dest As MungeCurr
46:
47: n = 5
48: Src.LoValue = i
00401AB0 8B 4E 34 mov ecx,dword ptr [esi+34h]
00401AB3 33 C0 xor eax,eax
00401AB5 89 45 DC mov dword ptr [Src],eax
00401AB8 33 D2 xor edx,edx
00401ABA 89 45 E0 mov dword ptr [ebp-20h],eax
00401ABD 89 55 E4 mov dword ptr [Dest],edx
00401AC0 89 4D DC mov dword ptr [Src],ecx
49: Src.HiValue = j
50: LSet Dest = Src
00401AC3 8D 45 DC lea eax,[Src]
00401AC6 8D 4D E4 lea ecx,[Dest]
00401AC9 89 55 E8 mov dword ptr [ebp-18h],edx
00401ACC 8B 56 38 mov edx,dword ptr [esi+38h]
00401ACF 50 push eax
00401AD0 51 push ecx
00401AD1 6A 08 push 8
00401AD3 C7 46 48 05 00 00 00 mov dword ptr [esi+48h],5
00401ADA 89 55 E0 mov dword ptr [ebp-20h],edx
00401ADD FF 15 10 10 40 00 call dword ptr [__imp_@__vbaCopyBytes
(00401010)]
51: Dest.Value = Dest.Value * 10000
00401AE3 8B 55 E8 mov edx,dword ptr [ebp-18h]
00401AE6 8B 45 E4 mov eax,dword ptr [Dest]
00401AE9 52 push edx
00401AEA 50 push eax
00401AEB 68 10 27 00 00 push 2710h
00401AF0 FF 15 50 10 40 00 call dword ptr [__imp_@__vbaCyMulI2
(00401050)]
00401AF6 89 45 E4 mov dword ptr [Dest],eax
00401AF9 89 55 E8 mov dword ptr [ebp-18h],edx
52: m = 9
00401AFC C7 46 44 09 00 00 00 mov dword ptr [esi+44h],9
53: End Sub
00401B03 C7 45 FC 00 00 00 00 mov dword ptr [ebp-4],0
$L34:
00401B0A 8B 45 08 mov eax,dword ptr [Me]
00401B0D 50 push eax
00401B0E 8B 08 mov ecx,dword ptr [eax]
00401B10 FF 51 08 call dword ptr [ecx+8]
00401B13 8B 45 FC mov eax,dword ptr [ebp-4]
00401B16 8B 4D EC mov ecx,dword ptr [ebp-14h]
00401B19 5F pop edi
00401B1A 5E pop esi
00401B1B 64 89 0D 00 00 00 00 mov dword ptr fs:[0],ecx
00401B22 5B pop ebx
00401B23 8B E5 mov esp,ebp
00401B25 5D pop ebp
00401B26 C2 14 00 ret 14h

Schmidt

unread,
Nov 18, 2009, 2:08:52 PM11/18/09
to

<bart.sm...@gmail.com> schrieb im Newsbeitrag
news:903c92a8-06e1-4fe0...@d5g2000yqm.googlegroups.com...

> OK, can't remember getting wrong results with the code
> I posted last, but maybe I missed that particular range.

No need, that was right already...

> I take it it still makes sense to go with FindFirstFileW

Yep, definitely - this way you avoid unnecessary
WString-to-ANSI-to-WString conversions (before and
after the API-Call), VB-Strings *are* already "wide",
so with StrPtr (...) you're passing the right thing already.

Also just checked, if Ians multiply-version is faster
than the "copy-over" - in the IDE (or within VBA) it
is not faster - native compiled it is, but only a little bit.
What I forgot (since the Procedure-local type is a quite
large) - you can gain more than with the direct multiply,
if you make WFD static within the Function.
But all these effects are not that large compared with
the FindFirstFile-CallOverhead - you can measure
the differences of the "post-processing-lines" only,
if you comment out the FindFirstxxx related stuff,
setting only dummy-values on WFD.

Last thing (already mentioned by Nobody) -
LSet is a bit faster than CopyMemory, with that
change you will have a bit faster code, if native
compiled (compared with CopyMemory) - but if you
use the function mainly within VBA, then this change
does not worth it.

Olaf


Karl E. Peterson

unread,
Nov 18, 2009, 3:48:08 PM11/18/09
to
mayayana wrote:
> If it's worth being extremely efficient, couldn't
> you also skip the check of the nFileSizeLow? I
> assume it can't be < 0.

No, it definitely can, because it's unsigned. So anything between 2-4GB is
"negative" to VB.

Ralph

unread,
Nov 18, 2009, 4:23:15 PM11/18/09
to

"Nobody" <nob...@nobody.com> wrote in message
news:OsB16BHa...@TK2MSFTNGP02.phx.gbl...

> "Nobody" <nob...@nobody.com> wrote in message
> news:Oxaa5GGa...@TK2MSFTNGP04.phx.gbl...
> > Unfortunately, CConvert functions seem to be implemented in VB6 as
> > function calls.
>
> The above is incorrect. It seems that VB use the most "efficient" method
to
> convert from the given data type. For example, if you provide an integer
> values to CInteger or CLng, little or no conversion is done. But if you
> supply a String to CInteger or CLng, a function call is made to do the
> conversion. This seems like C++ function templates and/or function
> overloading where one or more version of the same function is written to
> support each data type, and the compiler picks the one that match the data
> type exactly, so the least amount of code is generated, and in cases where
> the data types are identical or very similar, a direct assignment is used,
> as if you didn't use the conversion function. VB compiler seems to
translate
> the code to intermediate code that is common with C++. VB's run time error
> handling is similar to C++ exception handling, they behave mostly in the
> same way.
>


It is good to see someone get curious and go peeking. (However, be prepared
to lose some hair if you plan to continue. <g>)

Here are some hints.

Don't confuse VB's handling of Variants with C++ templates. Your observation
that it appears similar is just that - an 'appearance'. Templates used by
C++ are code constructs that can used at compile time to instruct the
compiler on how to create a specific object. "Types" and how they are to be
handled is determined in VB/VBA when parsed and converted to opcode.

VB opcode is stack-oriented, not function-oriented - ie, there is far more
Forth in VB than C++. (Dusting off some Forth books is not a bad idea.)

Viewing VB generated code via the native code output is going to give a "C
view", since opcode is converted to preprocessed C before being submitted to
the C2 compiler for conversion to native code. You will see better what is
going on if you use several sources simultaneously.
1) Compile to P-Code and examine the output
2) Temporarily replace the C2.exe, second pass compiler, with an executable
that captures the command line and then exits.
This will leave "OBJ" files in the project folder. These are the
preprocessed C files created by VB.exe, less tainted by the C compiler's
additional passes. Gives a much better view of the multiple structs, caches
and dictionaries VB uses.
3) Load up WinDbg and view the actual "pcode" within the VB.exe. You can
also view pcode caches and dictionaries in the /temp folder. This is real
fun. <g>

There is a lot of interesting information available at the various Crack
sites. Most of the archives will deal with VB 3, as that is the last version
of VB it was practical to de-compile, but learning how pcode worked,
pre-VBA, is very useful. (In fact you might consider installing VB3 and
playing with it.)

However, before you go visiting, make sure you have an extremely isolated,
protected box, with nothing of value on it, or borrow someone else's. <g>

hth
-ralph


Dee Earley

unread,
Nov 19, 2009, 8:34:50 AM11/19/09
to
On 18/11/2009 14:06, mayayana wrote:
> Also, this is slightly OT -- sorry to hijack your
> thread -- but I wonder if someone could explain
> why, in an empty folder, FindFirstFile will return
> 1 valid file handle and 2 names: "." and ".."
> It's very strange behavior, making it tricky to
> write just a simple "is the folder empty?" routine.

Because that's what it contains.
"." and ".." are real entries that exist in every folder (Except the
drive root).
"." is the current folder and ".." is the parent.

Directory of H:\WorkArea

19/11/2009 10:27 <DIR> .
19/11/2009 10:27 <DIR> ..

--
Dee Earley (dee.e...@icode.co.uk)
i-Catcher Development Team

iCode Systems

Jim Mack

unread,
Nov 19, 2009, 10:46:37 AM11/19/09
to
Dee Earley wrote:
>
> "." and ".." are real entries that exist in every folder (Except the
> drive root).
> "." is the current folder and ".." is the parent.

Anyone who might encounter a Novell network has to be aware of the
possibility of "..." entries too.

I haven't seen a Netware system in a while so the 'triple dot' entries
might be a thing of the past. You could turn them off with a policy,
IIRC.

--
Jim

mayayana

unread,
Nov 19, 2009, 10:51:06 AM11/19/09
to

>
> Because that's what it contains.
> "." and ".." are real entries that exist in every folder (Except the
> drive root).
> "." is the current folder and ".." is the parent.
>
> Directory of H:\WorkArea
>
> 19/11/2009 10:27 <DIR> .
> 19/11/2009 10:27 <DIR> ..
>

Thanks. Frankly that explanation doesn't make
any sense to me, but I have seen the notation.
My FTP program, for instance, uses an icon marked
".." in lieu of an up arrow for navigation. I guess
I need to read up on the details of filesystem
structure.


0 new messages