首页 > 解决方案 > 转换类型的变体(调度)

问题描述

我正在尝试使用 Delphi 7 / ADO 为每个用户读取 AD 中的 lastLogonTimeStamp 字段。我的循环可以读取所需的字段。字符串字段易于使用,但我未能解码时间戳。它是 Variant 类型,vartype 返回 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 ...]

标签: delphiado

解决方案


变体类型 9 ( varDispatch) 表示 COMIDispatch对象接口。在这种情况下这是有道理的,因为它lastLogonTimeStamp是UTC 格式,包装在 COM 对象中以公开对其和成员的访问。有关更多详细信息,请参阅AD 用户的属性:lastLogonTimestampAcitve 目录:使用 LARGE_INTEGER / INTEGER8 语法处理属性Integer8FILETIMELowPartHighPart

尝试这样的事情:

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;

推荐阅读