转换类型的变体(调度)

Convert variant of type (Dispatch)

我正在尝试使用 Delphi 7 / ADO 为每个用户读取 AD 中的 lastLogonTimeStamp 字段。我的循环可以读取所需的字段。字符串字段很容易使用,但我未能解码时间戳。它的类型是 Variant 和 vartype returns 9 (Dispatch)

我尝试过各种类型转换,包括 INT64(我相信这是时间戳的存储方式)和 varToStr。所有记录都是 vartype 9 除了一个是 vartype 1 可能是因为它是空的。

ADOQuery1: TADOQuery;
ADOQuery1SN: TWideStringField;
ADOQuery1CN: TWideStringField;
ADOQuery1AdsPath: TWideStringField;
ADOQuery1lastLogonTimestamp: TVariantField;
logonfield : variant;

    logonfield := ADOQuery1lastLogonTimestamp.value;
    stringgrid1.Cells[1,i] :=  vartostr(logonfield);

我想获取每个用户的上次登录日期,但程序会过滤掉例外情况。我可以得到字符串字段。但我得到:

错误:无法将类型(调度)转换为类型(字符串) [或我尝试过的任何其他东西! TDateTime, INT64 ...]

变体类型 9 (varDispatch) 表示 COM IDispatch 对象接口。在这种情况下这是有道理的,因为 lastLogonTimeStampFILETIME 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 中的 Integer8 以获取更多详细信息。

尝试这样的事情:

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;