DirectoryEntry.MoveTo exceptions: Abstracted by UnsafeNativeMethods but not documented

0

System.DirectoryServices contains the class/method DirectoryEntry.MoveTo(..). The only documented exception is an InvalidOperationException if the target DirectoryEntry isn't a container. I'd expect there to be all sorts of other potential exceptions, especially with permissions.

Under the hood, .MoveTo() calls

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

where DirectoryEntry is the new target location. Which calls:

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);
        ...
    }
    ...
}

The GUID in question refers to the activeds.tlb type library. That library defines IADsContainer.MoveHere as

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

The disconnect is that the activeds.dll returns an HRESULT, and gives the caller a pointer to the object through an out param. But the .NET wrapper has a different signature, and no HRESULT.

Two questions:

  1. How can UnsafeNativeMethods.IAdsContainer.MoveHere map to a COM interface with a different signature?
  2. What's happening to that HRESULT?

Regarding #2... If there's an object in the middle that calls the HRESULT version of MoveHere, that object is likely checking the result and throwing an exception or returning the IAdsContainer it instantiated. But I have no idea what object that might be in the middle, and neither the .NET framework code nor the .tlb file give me any clues. Any exceptions it's throwing aren't documented.

c#
active-directory
pinvoke
comexception
directoryentry
asked on Stack Overflow Dec 19, 2018 by James King • edited Dec 19, 2018 by Gabriel Luci

1 Answer

1

It's taking that last parameter [out, retval] IDispatch** ppObject and making that the return value, and interpreting the returned HRESULT and throwing a COMException if needed. I just haven't seen that actual code that does that.

I suspect it's that [ComImport] attribute that's telling .NET to treat it differently.

In fact, the source code does show there is some special treatment because of that attribute, although I won't pretend I totally understand what's going on.

For example, take the GetCustomMarshaledCOMObject method. It calls GetIUnknown and does some special magic when that returns false.

The GetIUnknown method specifically checks for ComImportAttribute and returns false if it's there.

Even the method that calls GetCustomMarshaledCOMObject says:

// Check for COMObject & do some special custom marshaling
answered on Stack Overflow Dec 19, 2018 by Gabriel Luci • edited Dec 19, 2018 by Gabriel Luci

User contributions licensed under CC BY-SA 3.0