You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将_ComObject转换为Long等原生类型?转换报错求助

解决VB.NET从Active Directory获取LastLogonTimestamp时的类型转换错误

你遇到的Conversion from type '_ComObject' to type 'Long' is not valid错误,核心原因是Active Directory里的lastLogonTimestamp属于64位大整数属性,在COM互操作层被包装成了IADsLargeInteger类型的COM对象,而非直接的数值类型,直接强制转换自然会失败。下面给你两种实用的解决思路:

方法一:用AccountManagement命名空间(推荐,最省心)

如果你的项目基于.NET Framework 3.5及以上,直接用System.DirectoryServices.AccountManagement命名空间下的UserPrincipal类就好——它已经帮你封装好了属性转换逻辑,完全不用手动处理COM对象:

Imports System.DirectoryServices.AccountManagement

' 初始化域上下文
Using domainContext As New PrincipalContext(ContextType.Domain)
    ' 根据用户名查找目标用户
    Dim targetUser As UserPrincipal = UserPrincipal.FindByIdentity(domainContext, IdentityType.SamAccountName, "你的用户名")
    
    If targetUser IsNot Nothing Then
        ' LastLogonTimestamp是可空DateTime类型,先判断是否有值
        If targetUser.LastLogonTimestamp.HasValue Then
            Dim lastLogonTime As DateTime = targetUser.LastLogonTimestamp.Value
            Console.WriteLine($"最后登录时间:{lastLogonTime.ToString("yyyy-MM-dd HH:mm:ss")}")
        Else
            Console.WriteLine("该用户暂无登录时间记录")
        End If
    End If
End Using

方法二:手动处理IADsLargeInteger COM对象

如果必须用DirectorySearcher或DirectoryEntry查询,就需要手动读取COM对象的HighPart和LowPart属性,再组合成正确的64位整数:

方式A:后期绑定(无需额外COM引用)

这种方式不用添加ADSI的COM库依赖,适合轻量化场景:

Imports System.DirectoryServices

Dim searcher As New DirectorySearcher()
searcher.Filter = "(&(objectCategory=person)(objectClass=user)(samAccountName=你的用户名))"
' 只加载需要的属性,提升查询性能
searcher.PropertiesToLoad.Add("lastLogonTimestamp")

Dim searchResult As SearchResult = searcher.FindOne()

If searchResult IsNot Nothing AndAlso searchResult.Properties.Contains("lastLogonTimestamp") Then
    Dim tsProperty As ResultPropertyValueCollection = searchResult.Properties("lastLogonTimestamp")
    If tsProperty.Count > 0 Then
        Dim comObj As Object = tsProperty(0)
        ' 通过反射读取COM对象的HighPart和LowPart属性
        Dim highPart As Integer = comObj.GetType().InvokeMember("HighPart", Reflection.BindingFlags.GetProperty, Nothing, comObj, Nothing)
        Dim lowPart As Integer = comObj.GetType().InvokeMember("LowPart", Reflection.BindingFlags.GetProperty, Nothing, comObj, Nothing)
        
        ' 组合成64位整数,注意处理无符号转换逻辑
        Dim lastLogonTs As Long = CLng(highPart) << 32 Or (lowPart And &HFFFFFFFFL)
        ' 转换为常规DateTime(lastLogonTimestamp是Windows文件时间格式)
        Dim lastLogonTime As DateTime = DateTime.FromFileTime(lastLogonTs)
        
        Console.WriteLine($"最后登录时间:{lastLogonTime.ToString("yyyy-MM-dd HH:mm:ss")}")
    End If
End If

方式B:添加ADSI COM引用(类型更安全)

如果你希望代码类型更严谨,可以添加Active DS Type Library的COM引用(在VS的COM选项卡中查找),然后直接使用IADsLargeInteger接口:

Imports System.DirectoryServices
Imports ActiveDs ' 引用COM库后添加此命名空间

' 查询逻辑和方式A一致,拿到comObj后:
Dim largeInt As IADsLargeInteger = DirectCast(comObj, IADsLargeInteger)
Dim lastLogonTs As Long = CLng(largeInt.HighPart) << 32 Or (largeInt.LowPart And &HFFFFFFFFL)
Dim lastLogonTime As DateTime = DateTime.FromFileTime(lastLogonTs)

关键注意事项

  • lastLogonTimestamp是可选属性,部分用户可能没有该记录,一定要先判断属性是否存在、是否有值,避免空引用错误
  • 该属性存储的是Windows文件时间(从1601年1月1日开始的100纳秒间隔数),必须用DateTime.FromFileTime()转换为常规日期时间格式

内容的提问来源于stack exchange,提问作者Adam Cox

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 06:57:12