Incorrect value when converting accountExpires to long

S

ssg31415926

According to MSDN, accountExpires contains: 9223372036854775807
(0x7FFFFFFFFFFFFFFF) or 0 when the account is not set to expire. All
of my accounts I've checked are set to 9223372036854775807.

Also according to MSDN
(http://msdn.microsoft.com/library/d...l/frlrfsystemdatetimeclasstofiletimetopic.asp),
the following code should retrieve the value from Active Directory.:
using ActiveDs; //(add a ref to Active DS Type Library (in COM))
using System.DirectoryServices;

System.Int64 largeInt=0;
IADsLargeInteger int64Val = (IADsLargeInteger)
ent.Properties["forceLogoff"].Value;
largeInt = int64Val.HighPart * 0x100000000 + int64Val.LowPart;
Console.WriteLine(largeInt);

where ent is a DirectoryEntry.

I've modified the code slightly and added some Debug statements:

IADsLargeInteger int64Val = (IADsLargeInteger)
this.m_DirectoryEntry.Properties[PropertyName].Value;
Debug.WriteLine("int64Val = " + int64Val.ToString());
Debug.WriteLine("int64Val.HighPart = " + int64Val.HighPart.ToString());
Debug.WriteLine("int64Val.LowPart = " + int64Val.LowPart.ToString());
largeInt = int64Val.HighPart * 0x100000000 + int64Val.LowPart;
Debug.WriteLine("LargeInt = " + largeInt.ToString());
Debug.WriteLine(String.Format("{0:x}, {1:x}, {2:x}",
int64Val.HighPart, int64Val.LowPart, largeInt));

and it produces an incorrect value. These are the results from the
Debug.WriteLine statements:

int64Val = System.__ComObject
int64Val.HighPart = 2147483647
int64Val.LowPart = -1
LargeInt = 9223372032559808511
7fffffff, ffffffff, 7ffffffeffffffff

You can see this, from the HighPart and LowPart values (formatted to
hex, above) that the correct value is retrieved. So, why aren't they
correctly combined to 7fffffffffffffff? The math looks right to me.
 
W

Willy Denoyette [MVP]

ssg31415926 said:
According to MSDN, accountExpires contains: 9223372036854775807
(0x7FFFFFFFFFFFFFFF) or 0 when the account is not set to expire. All
of my accounts I've checked are set to 9223372036854775807.

Also according to MSDN
(http://msdn.microsoft.com/library/d...l/frlrfsystemdatetimeclasstofiletimetopic.asp),
the following code should retrieve the value from Active Directory.:
using ActiveDs; //(add a ref to Active DS Type Library (in COM))
using System.DirectoryServices;

System.Int64 largeInt=0;
IADsLargeInteger int64Val = (IADsLargeInteger)
ent.Properties["forceLogoff"].Value;
largeInt = int64Val.HighPart * 0x100000000 + int64Val.LowPart;
Console.WriteLine(largeInt);

where ent is a DirectoryEntry.

I've modified the code slightly and added some Debug statements:

IADsLargeInteger int64Val = (IADsLargeInteger)
this.m_DirectoryEntry.Properties[PropertyName].Value;
Debug.WriteLine("int64Val = " + int64Val.ToString());
Debug.WriteLine("int64Val.HighPart = " + int64Val.HighPart.ToString());
Debug.WriteLine("int64Val.LowPart = " + int64Val.LowPart.ToString());
largeInt = int64Val.HighPart * 0x100000000 + int64Val.LowPart;
Debug.WriteLine("LargeInt = " + largeInt.ToString());
Debug.WriteLine(String.Format("{0:x}, {1:x}, {2:x}",
int64Val.HighPart, int64Val.LowPart, largeInt));

and it produces an incorrect value. These are the results from the
Debug.WriteLine statements:

int64Val = System.__ComObject
int64Val.HighPart = 2147483647
int64Val.LowPart = -1
LargeInt = 9223372032559808511
7fffffff, ffffffff, 7ffffffeffffffff

You can see this, from the HighPart and LowPart values (formatted to
hex, above) that the correct value is retrieved. So, why aren't they
correctly combined to 7fffffffffffffff? The math looks right to me.

No your math is wrong....
You should not use longs for the low and highorder parts (the are 32
unsigned int's) and the loworder should be treated as unsigned when
comibing.
Here is how to do it, note that I'm using Reflection to late bind against
the IADsLargeInteger COM interface, that means I don't have to set a
reference to activeds.tlb.
Note also that LargeInteger dates having a value -1 (never expires) are
non-valid dates in terms of DateTime (they are no real dates).


long expDate =
LongFromLargeInteger(user.Properties["accountExpires"].Value);
Console.WriteLine("Account expires on: {0:X}" ,expDate );

//decodes IADsLargeInteger objects using reflection
private static long LongFromLargeInteger( object largeInteger )
{
System.Type type = largeInteger.GetType();
int highPart = (int)type.InvokeMember("HighPart",BindingFlags.GetProperty,
null, largeInteger, null);
int lowPart = (int)type.InvokeMember("LowPart",BindingFlags.GetProperty,
null, largeInteger, null);
return (long)highPart << 32 | (uint)lowPart;
}


Willy.
 
S

ssg31415926

Thanks very much for your reply. I'm not sure I understood all of it
but it works!

I started .NET with VB.NET and recently switched to C#. From the books
I'd read, I'd understood that late binding was frowned upon because it
leads to more run-time errors. If you've got the time, could you if
there are any advantages to it other than not having to reference
activeds.tlb, please?
 
W

Willy Denoyette [MVP]

ssg31415926 said:
Thanks very much for your reply. I'm not sure I understood all of it
but it works!

I started .NET with VB.NET and recently switched to C#. From the books
I'd read, I'd understood that late binding was frowned upon because it
leads to more run-time errors. If you've got the time, could you if
there are any advantages to it other than not having to reference
activeds.tlb, please?

The great advantage is versioning, the activeds.dll (and it's .tlb) may
differ from OS version to OS version, so you'll need the corresponding
Interop Assembly when using early binding.
Using late binding you don't depend on a specific version of the tlb.
Not that there is a slight performance penalty when using late bnding
through Reflection, but this isn't realy an issue for simple things like
this.

Willy.
 
S

ssg31415926

The great advantage is versioning, the activeds.dll (and it's .tlb)
may differ from OS version to OS version, so you'll need the
corresponding Interop Assembly when using early binding.
Using late binding you don't depend on a specific version of the
tlb. Not that there is a slight performance penalty when using
late bnding through Reflection, but this isn't realy an issue for
simple things like this.

Okay, thanks. That makes it really clear.

Simon
 
Top