如何将_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
相关产品推荐
相关产品推荐

