Пространство имен IADsLargeInteger

Я искал способ преобразовать COM-объект в DateTime и видел много статей об этой проблеме (например, эту - https://msdn.microsoft.com/en-us/library/ms180872(v=vs.80).aspx и этот - Как читать свойство uSNChanged с помощью C # )

Однако все эти статьи говорят об использовании объекта из интерфейса IADsLargeInteger.

Я попытался найти пространство имен этого интерфейса и не смог найти ни одной подсказки.


person neriag    schedule 22.10.2015    source источник
comment
Я нашел ответ. Это пространство имен ActiveDs. Чтобы найти это пространство имен, необходимо добавить ссылку на C: \ Windows \ System32 \ activeds.tlb.   -  person neriag    schedule 22.10.2015


Ответы (3)


Вот пример кода, включающий все, что вам нужно для преобразования из типа AD в DateTime:

using System.DirectoryServices;
using System.DirectoryServices.AccountManagement;
using ActiveDs; // Namespace added via ref to C:\Windows\System32\activeds.tlb

private DateTime? getLastLogin(DirectoryEntry de)
{
    Int64 lastLogonThisServer = new Int64();

    if (de.Properties.Contains("lastLogon"))
    {
        if (de.Properties["lastLogon"].Value != null)
        {
            try
            {
                IADsLargeInteger lgInt =
                (IADsLargeInteger) de.Properties["lastLogon"].Value;
                lastLogonThisServer = ((long)lgInt.HighPart << 32) + lgInt.LowPart;

                return DateTime.FromFileTime(lastLogonThisServer);
            }
            catch (Exception e)
            {
                return null;
            }
        }
    }
    return null;
}
person Shane    schedule 23.02.2016
comment
ActiveDs C: \ Windows \ System32 \ activeds.tlb действительно необходим для работы с ActivieDirectory в .NET ?. Я использую только System.DirectoryServices.AccountManagement - person Kiquenet; 12.07.2016
comment
Нет, это не требуется для работы с ActiveDirectory в целом. Однако, если вы хотите работать со многими типами дат в AD, такими как lastLogon, вам понадобится тип IADsLargeInteger, который включен как часть библиотеки ActiveDs. Я не видел никакого обходного пути, но тоже хотел бы! Вы преобразовали эти даты с помощью System.DirectoryServices.AccountManagement? - person Shane; 13.07.2016
comment
В качестве примера я видел этот исходный код: github.com/egil/PasswordExpireNotification/blob/master/ и другие ссылки в github. maxPwdAge = TimeSpan.FromTicks((long)sr.Properties["maxPwdAge"][0]); - person Kiquenet; 18.07.2016
comment
@Kiquenet, прямое преобразование в long возможно только тогда, когда свойство считывается из ResultPropertyValueCollection, возвращенного DirectorySearcher. Свойства из DirectoryEntry равны PropertyValueCollection и могут содержать другие COM-объекты ADSI, такие как IADsLargeInteger. - person browe; 10.08.2016
comment
Ошибка в коде. Для правильного результата необходимо изменить следующее: lastLogonThisServer = ((long)lgInt.HighPart << 32) | (UInt32)lgInt.LowPart; - person Radka; 04.04.2017
comment
Вы можете объяснить почему? Этот код работает в продукте, но, возможно, в нем есть ошибка. - person Shane; 12.04.2017

В дополнение к предыдущему ответу, в котором показан правильный код для получения значения из переменной IADsLargeInteger, я просто хочу сказать, что нет необходимости добавлять ссылку на библиотеку типов COM, если вам нужен только этот интерфейс.

Для работы с типом COM вы можете определить интерфейс в собственном коде:

[ComImport, Guid("9068270b-0939-11d1-8be1-00c04fd8d503"), InterfaceType(ComInterfaceType.InterfaceIsDual)]
internal interface IAdsLargeInteger
{
    long HighPart
    {
        [SuppressUnmanagedCodeSecurity] get; [SuppressUnmanagedCodeSecurity] set;
    }

    long LowPart
    {
        [SuppressUnmanagedCodeSecurity] get; [SuppressUnmanagedCodeSecurity] set;
    }
}

и используйте его так же:

var largeInt = (IAdsLargeInteger)directoryEntry.Properties[propertyName].Value;
var datelong = (largeInt.HighPart << 32) + largeInt.LowPart;
var dateTime = DateTime.FromFileTimeUtc(datelong);

Также есть хорошая статья, объясняющая как интерпретировать данные ADSI

person Mikhail Tumashenko    schedule 04.12.2018

Вам НЕ нужно ссылаться на ActiveDs.dll - вместо этого вы можете это сделать.

Я убедился, что это работает в .NET Standard 2.0 и .NET 5.

...
Int64 lastLogonThisServer = ConvertADSLargeIntegerToInt64(de.Properties["lastLogon"].Value);
return DateTime.FromFileTime(lastLogonThisServer);
...

public static Int64 ConvertADSLargeIntegerToInt64(object adsLargeInteger)
{
     var highPart = (Int32)adsLargeInteger.GetType().InvokeMember("HighPart", System.Reflection.BindingFlags.GetProperty, null, adsLargeInteger, null);
     var lowPart  = (Int32)adsLargeInteger.GetType().InvokeMember("LowPart",  System.Reflection.BindingFlags.GetProperty, null, adsLargeInteger, null);
     return highPart * ((Int64)UInt32.MaxValue + 1) + lowPart;
}

Благодарим Саймона Гилби за этот ответ.

person Ambrose Leung    schedule 16.04.2021