Problem with the HighPart and LowPart property methods

A good way to demonstrate the problem encountered with these property methods is to use ADSI Edit to update the maxStorage attribute of a test user object.

ADSI Edit is part of the "Windows 2000 Support Tools" found on any Windows 2000 Server CD. It can be installed on any client with Windows 2000 or above by running Setup.exe in the \Support\Tools folder on the CD.

With ADSI Edit you can browse all objects in your Active Directory and the attributes of each object. The maxStorage attribute is used to specify the maximum amount of disk space the user is allowed to use. This attribute is Integer8. ADSI Edit allows you to enter a large 64-bit number as the value for this attribute. The VBScript program below will then reveal the values returned by the HighPart and LowPart property methods exposed by the IADsLargeInteger interface:

strUserDN = "cn=TestUser,ou=Sales,dc=MyDomain,dc=com")
Set objUser = GetObject("LDAP://" & strUserDN)
Set objMax = objUser.maxStorage
lngHigh = objMax.HighPart
lngLow = objMax.LowPart
lngValue = lngHigh * (2^32) + lngLow
Wscript.Echo "HighPart: " & lngHigh
Wscript.Echo "LowPart: " & lngLow
Wscript.Echo "Value: " & lngValue

By selecting a test user, setting various values for the maxStorage attribute, then finding the resulting values returned by the HighPart and LowPart methods, you can verify that LowPart always returns values between –2^31 and 2^31 – 1 (2^31 = 2,147,483,648). This reveals that these methods perform unsigned arithmetic on the 64-bit numbers. For example, the following table shows the HighPart and LowPart values corresponding to critical values for maxStorage. The values are shown below with commas for legibility, but commas are not allowed in the actual values:

maxStorage HighPart LowPart Value
10,737,418,238 2 2,147,483,646 10,737,418,238
10,737,418,239 2 2,147,483,647 10,737,418,239
10,737,418,240 2 -2,147,483,648 6,442,450,944

Notice in the last example, when the LowPart property method returns a negative value, the standard formula for determining the value of maxStorage is wrong by 4,294,967,296 which is 2^32. Because VB and VBScript do not support unsigned numbers, we must correct the value returned by the LowPart property method by adding 2^32. This is the same as increasing the value returned by the HighPart property method by one.

The following C code demonstrates the same issue:

_int64 i64;
i64 = -10;
i64 = i64 << 32;
i64 = i64 + -10;

You might expect the hex value of i64 to be

0xfffffff6fffffff6

but it will actually be

0xfffffff5fffffff6

In the last step of the program, the value

0xfffffff600000000

is added to –10. When the lower 32 bits (4 bytes) underflow, the upper 32 bits are decremented by one. This can be avoided in C by using unsigned numbers:

_int64 i64;
i64 = (ULONG)-10;
i64 = i64 << 32;
i64 = i64 + (ULONG)-10;

You can also assign negative values to the maxStorage attribute (even though these values make no sense). The same formula applies to calculate the value from the HighPart and LowPart methods. When the Integer8 value is negative, the HighPart method returns a negative value.

Examples of Integer8 attributes include the following: accountExpires, badPasswordTime, lastLogon, lockoutTime, maxStorage, pwdLastSet, uSNChanged, uSNCreated, lockoutDuration, lockoutObservationWindow, maxPwdAge, minPwdAge, and modifiedCount.