I am trying to use Delphi 7 / ADO to read the lastLogonTimeStamp field in AD for each user. My loop can read the fields required. The string fields are easy to use, but I have failed to decode the timestamp. It is of type Variant and vartype returns 9 (Dispatch)
I've tried various typecasts, including INT64 (which I believe is how the timestamp is stored), and varToStr. All the records are vartype 9 except one which is vartype 1 probably because it is empty.
ADOQuery1: TADOQuery;
ADOQuery1SN: TWideStringField;
ADOQuery1CN: TWideStringField;
ADOQuery1AdsPath: TWideStringField;
ADOQuery1lastLogonTimestamp: TVariantField;
logonfield : variant;
logonfield := ADOQuery1lastLogonTimestamp.value;
stringgrid1.Cells[1,i] := vartostr(logonfield);
I want to get date of last logon for each user, with exceptions filtered by the program. I can get the string fields OK. But I get:
Error: could not convert type (dispatch) into type (string) [or anything else I tried! TDateTime, INT64 ...]
Variant type 9 (varDispatch
) represents a COM IDispatch
object interface. Which makes sense in this situation because lastLogonTimeStamp
is an Integer8
in FILETIME
UTC format, wrapped in a COM object to expose access to its LowPart
and HighPart
members. See Attributes for AD Users : lastLogonTimestamp and Acitve Directory: Handling attributes with LARGE_INTEGER / INTEGER8 syntax for more details.
Try something like this:
function LargeIntegerToDate(value: Variant): TDateTime;
var
ftUTC, ftLocal: TFileTime;
st: TSystemTime;
begin
Result := 0;
if VarIsNull(value) then
Exit;
if not VarIsType(varDispatch) then
raise Exception.Create('Unsupported type');
ftUTC.dwHighDateTime := value.HighPart;
ftUTC.dwLowDateTime := value.LowPart;
if (ftUTC.dwLowDateTime = 0) and (ftUTC.dwHighDateTime = 0) then
begin
Result := EncodeDate(1601, 1, 1);
Exit;
end;
try
FileTimeToLocalFileTime(ftUTC, ftLocal);
FileTimeToSystemTime(ftLocal, st);
Result := SystemTimeToDateTime(st);
except
end;
end;
...
var
logonfield : Variant;
begin
logonfield := ADOQuery1lastLogonTimestamp.Value;
StringGrid1.Cells[1, i] := DateToStr(LargeIntegerToDate(logonfield));
end;