Ken Maynard
Ken Maynard

Reputation: 55

Convert variant of type (Dispatch)

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 ...]

Upvotes: 1

Views: 2493

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 597205

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;

Upvotes: 1

Related Questions