DirectoryEntry.MoveTo исключения: абстрагируется от UnsafeNativeMethods, но не документируется

System.DirectoryServices содержит класс / метод DirectoryEntry.MoveTo(..), Единственное зарегистрированное исключение InvalidOperationException если целевой DirectoryEntry не является контейнером. Я ожидаю, что будут и другие возможные исключения, особенно с разрешениями.

Под капотом, .MoveTo() звонки

DirectoryEntry.ContainerObject.MoveHere(this.Path, newName);

где DirectoryEntry это новое целевое местоположение. Какие звонки:

internal class UnsafeNativeMethods
{
    [Guid("001677D0-FD16-11CE-ABC4-02608C9E7553")]
    [InterfaceType(ComInterfaceType.InterfaceIsDual)]
    [ComImport]
    public interface IAdsContainer
    {
        [SuppressUnmanagedCodeSecurity]
        [return: MarshalAs(UnmanagedType.Interface)]
        object MoveHere([MarshalAs(UnmanagedType.BStr), In] string sourceName, [MarshalAs(UnmanagedType.BStr), In] string newName);
        ...
    }
    ...
}

Указанный GUID относится к activeds.tlb библиотека типов. Эта библиотека определяет IADsContainer.MoveHere как

[id(0x00000009)]
HRESULT MoveHere(
                [in] BSTR SourceName, 
                [in] BSTR NewName, 
                [out, retval] IDispatch** ppObject);

Разрыв в том, что activeds.dll возвращает HRESULT и дает вызывающей стороне указатель на объект через выходной параметр. Но оболочка.NET имеет другую подпись и не содержит HRESULT.

Два вопроса:

  1. Как UnsafeNativeMethods.IAdsContainer.MoveHere может сопоставляться с интерфейсом COM с другой подписью?
  2. Что происходит с этим HRESULT?

Что касается #2... Если в середине есть объект, который вызывает версию MoveHere для HRESULT, то этот объект, скорее всего, проверяет результат и выдает исключение или возвращает IAdsContainer, для которого он создан. Но я понятия не имею, какой объект может быть в середине, и ни код платформы.NET, ни файл.tlb не дают мне никаких подсказок. Любые исключения, которые он создает, не задокументированы.

1 ответ

Решение

Он принимает этот последний параметр [out, retval] IDispatch** ppObject и сделать это возвращаемое значение, и интерпретировать возвращенный HRESULT и бросить COMException если нужно. Я просто не видел тот реальный код, который делает это.

Я подозреваю, что это [ComImport] атрибут, который говорит.NET, чтобы относиться к нему по-другому.

На самом деле, исходный код показывает, что есть какой-то особый подход из-за этого атрибута, хотя я не буду притворяться, что полностью понимаю, что происходит.

Например, возьмите GetCustomMarshaledCOMObject метод. Это вызывает GetIUnknown и делает какую-то особую магию, когда это возвращается false,

GetIUnknown метод специально проверяет ComImportAttribute и возвращается false если это там.

Даже метод, который вызывает GetCustomMarshaledCOMObject говорит:

// Check for COMObject & do some special custom marshaling
Другие вопросы по тегам