System.Runtime.InteropServices.COMException (0x8000500C) occuring while committing changes to DirectoryEntry in .Net

2

Below is a code in C# where I am trying to add SSL binding of an existing certificate to "Default Website" in IIS Server. But I keep getting

System.Runtime.InteropServices.COMException (0x8000500C) in statement "website.Properties["SSLCertHash"].Add(x509.GetCertHash());".

Do you know the reason why?

string defaultWebsite = "Default Web Site";

foreach (DirectoryEntry website in sites)
{
    if (website.Properties["ServerComment"] != null)
    {
        if (website.Properties["ServerComment"].Value != null)
        {
            SrmLogManager.logMessage(SrmLogMgrLevel.SRM_LOGMGR_LEVEL_INFO, funcName + "Website found" + website.Properties["ServerComment"].Value.ToString());

                PropertyCollection pc = website.Properties;
                IDictionaryEnumerator ide = pc.GetEnumerator();
                ide.Reset();
                while (ide.MoveNext())
                {
                    PropertyValueCollection pvc = ide.Entry.Value as PropertyValueCollection;

                    // Dump out the website properties into the log, can be removed in future
                    SrmLogManager.logMessage(SrmLogMgrLevel.SRM_LOGMGR_LEVEL_INFO,"Name: "+ ide.Entry.Key.ToString());
                    SrmLogManager.logMessage(SrmLogMgrLevel.SRM_LOGMGR_LEVEL_INFO,"Value: " + pvc.Value);
                }
                // Add the Secure (https) binding to port 443 at hostname = localhost
                website.Properties["SecureBindings"].Clear();
                website.Properties["SecureBindings"].Add(":443:localhost");

                // Bind the AppAssure certificate 
                website.Properties["SSLCertHash"].Clear();
                website.Properties["SSLCertHash"].Add(x509.GetCertHash());
                website.CommitChanges();

            if (string.Compare(website.Properties["ServerComment"].Value.ToString(), defaultWebsite) == 0)
            {
                SrmLogManager.logMessage(SrmLogMgrLevel.SRM_LOGMGR_LEVEL_INFO, funcName + "Default Website is : " + website.Properties["ServerComment"].Value.ToString());

            }
        }
    }
}

Here is the exception I am getting:

Exception occured while binding AA cert System.Runtime.InteropServices.COMException (0x8000500C): Exception from HRESULT: 0x8000500C at System.DirectoryServices.Interop.UnsafeNativeMethods.IAds.PutEx(Int32 lnControlCode, String bstrName, Object vProp) at System.DirectoryServices.PropertyValueCollection.OnInsertComplete(Int32 index, Object value) at System.Collections.CollectionBase.System.Collections.IList.Add(Object value) at System.DirectoryServices.PropertyValueCollection.Add(Object value) at AAA.Web.Controllers.Global.importAppAssureSoftwareCert() in c:\Users\Administrator\Documents\AppAssureAppliance2.0\SRMWebClient\AAA.Web\Controllers\Global.cs:line 80

c#
.net
ssl
https
iis-8
asked on Stack Overflow Mar 20, 2013 by paxglobal • edited Mar 20, 2013 by Serg

1 Answer

0

Yep, this is a problem. You have to use the low level COM API, bypassing DirectoryEntry entirely. This is how I did it:

  private static void SetSslCertHash(string siteId, byte[] hash)
  {
    using (var adminBase = TemporaryComObject.Wrap(new MSAdminBase_W()))
    using (var ptrHash = new AllocHGlobal(hash))
    {
      using (var siteKey = new AdminBaseKey(adminBase.Com, adminBase.Com.OpenKey(METADATA_MASTER_ROOT_HANDLE, "/LM/W3SVC/" + siteId, METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE, 1000)))
      {
        var record = new METADATA_RECORD
        {
          dwMDIdentifier = SslCertHashCode,
          dwMDAttributes = METADATA_INHERIT,
          dwMDUserType = IIS_MD_UT_SERVER,
          dwMDDataType = BINARY_METADATA,
          pbMDData = ptrHash.Buffer,
          dwMDDataLen = hash.Length
        };
        adminBase.Com.SetData(siteKey.Handle, string.Empty, ref record);
      }
      adminBase.Com.SaveData();
    }
  }

It is annoying that DirectoryEntry API is broken for this particular property. Anyway, more help on the low level COM API is here - http://support.microsoft.com/kb/313624/en-US

Of course, you will need the .NET declaration of the MSAdminBase_W COM class. At the time I wrote this code I could not find anything ready, so I just opened "c:\Program Files\Microsoft SDKs\Windows\v7.1\Include\Iadmw.h" and extracted all the pieces from there. Here it is, for you to copy and enjoy:

using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace MSAdminBaseLib
{
  [StructLayout(LayoutKind.Sequential)]
  public struct _FILETIME
  {
    public uint dwLowDateTime;
    public uint dwHighDateTime;
  }

  [ComImport, Guid("70B51430-B6CA-11D0-B9B9-00A0C922E750"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
  public interface IMSAdminBase_W
  {
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    void AddKey([In] int hMDHandle, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMDPath);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    void DeleteKey([In] int hMDHandle, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMDPath);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    void DeleteChildKeys([In] int hMDHandle, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMDPath);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    void EnumKeys([In] int hMDHandle, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMDPath, [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0, SizeConst = 0x100)] ushort[] szMDName, [In] int dwMDEnumObjectIndex);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    void CopyKey([In] int hMDSourceHandle, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMDSourcePath, [In] int hMDDestHandle, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMDDestPath, [In] int bMDOverwriteFlag, [In] int bMDCopyFlag);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    void RenameKey([In] int hMDHandle, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMDPath, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMDNewName);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    void SetData([In] int hMDHandle, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMDPath, [In] ref METADATA_RECORD pmdrMDData);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    void GetData([In] int hMDHandle, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMDPath, [In, Out] ref METADATA_RECORD pmdrMDData, out int pdwMDRequiredDataLen);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    void DeleteData([In] int hMDHandle, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMDPath, [In] int dwMDIdentifier, [In] int dwMDDataType);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    void EnumData([In] int hMDHandle, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMDPath, [In, Out] ref METADATA_RECORD pmdrMDData, [In] int dwMDEnumDataIndex, out int pdwMDRequiredDataLen);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    void GetAllData([In] int hMDHandle, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMDPath, [In] int dwMDAttributes, [In] int dwMDUserType, [In] int dwMDDataType, out int pdwMDNumDataEntries, out int pdwMDDataSetNumber, [In] int dwMDBufferSize, out byte pbMDBuffer, out int pdwMDRequiredBufferSize);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    void DeleteAllData([In] int hMDHandle, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMDPath, [In] int dwMDUserType, [In] int dwMDDataType);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    void CopyData([In] int hMDSourceHandle, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMDSourcePath, [In] int hMDDestHandle, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMDDestPath, [In] int dwMDAttributes, [In] int dwMDUserType, [In] int dwMDDataType, [In] int bMDCopyFlag);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    void GetDataPaths([In] int hMDHandle, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMDPath, [In] int dwMDIdentifier, [In] int dwMDDataType, [In] int dwMDBufferSize, out ushort pszBuffer, out int pdwMDRequiredBufferSize);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    int OpenKey([In] int hMDHandle, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMDPath, [In] int dwMDAccessRequested, [In] int dwMDTimeOut);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    void CloseKey([In] int hMDHandle);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    void ChangePermissions([In] int hMDHandle, [In] int dwMDTimeOut, [In] int dwMDAccessRequested);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    void SaveData();
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    void GetHandleInfo([In] int hMDHandle, out METADATA_HANDLE_INFO pmdhiInfo);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    void GetSystemChangeNumber(out int pdwSystemChangeNumber);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    void GetDataSetNumber([In] int hMDHandle, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMDPath, out int pdwMDDataSetNumber);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    void SetLastChangeTime([In] int hMDHandle, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMDPath, [In] ref _FILETIME pftMDLastChangeTime, [In] int bLocalTime);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    void GetLastChangeTime([In] int hMDHandle, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMDPath, out _FILETIME pftMDLastChangeTime, [In] int bLocalTime);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), TypeLibFunc(TypeLibFuncFlags.FRestricted)]
    void KeyExchangePhase1();
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), TypeLibFunc(TypeLibFuncFlags.FRestricted)]
    void KeyExchangePhase2();
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    void Backup([In, MarshalAs(UnmanagedType.LPWStr)] string pszMDBackupLocation, [In] int dwMDVersion, [In] int dwMDFlags);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    void Restore([In, MarshalAs(UnmanagedType.LPWStr)] string pszMDBackupLocation, [In] int dwMDVersion, [In] int dwMDFlags);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    void EnumBackups([In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0, SizeConst = 0x100)] ushort[] szMDBackupLocation, out int pdwMDVersion, out _FILETIME pftMDBackupTime, [In] int dwMDEnumIndex);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    void DeleteBackup([In, MarshalAs(UnmanagedType.LPWStr)] string pszMDBackupLocation, [In] int dwMDVersion);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    void UnmarshalInterface([MarshalAs(UnmanagedType.Interface)] out MSAdminBase_W piadmbwInterface);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), TypeLibFunc(TypeLibFuncFlags.FRestricted)]
    void GetServerGuid();
  }

  [StructLayout(LayoutKind.Sequential)]
  public struct METADATA_HANDLE_INFO
  {
    public int dwMDPermissions;
    public int dwMDSystemChangeNumber;
  }

  [StructLayout(LayoutKind.Sequential)]
  public struct METADATA_RECORD
  {
    public int dwMDIdentifier;
    public int dwMDAttributes;
    public int dwMDUserType;
    public int dwMDDataType;
    public int dwMDDataLen;
    public IntPtr pbMDData;
    public int dwMDDataTag;
  }

  [ComImport, Guid("70B51430-B6CA-11D0-B9B9-00A0C922E750"), CoClass(typeof(MSAdminBase_WClass))]
  public interface MSAdminBase_W : IMSAdminBase_W
  {
  }

  [ComImport, TypeLibType(TypeLibTypeFlags.FCanCreate), ClassInterface(ClassInterfaceType.None), Guid("A9E69610-B80D-11D0-B9B9-00A0C922E750")]
  public class MSAdminBase_WClass : MSAdminBase_W
  {
    // Methods
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    public virtual extern void AddKey([In] int hMDHandle, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMDPath);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    public virtual extern void Backup([In, MarshalAs(UnmanagedType.LPWStr)] string pszMDBackupLocation, [In] int dwMDVersion, [In] int dwMDFlags);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    public virtual extern void ChangePermissions([In] int hMDHandle, [In] int dwMDTimeOut, [In] int dwMDAccessRequested);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    public virtual extern void CloseKey([In] int hMDHandle);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    public virtual extern void CopyData([In] int hMDSourceHandle, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMDSourcePath, [In] int hMDDestHandle, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMDDestPath, [In] int dwMDAttributes, [In] int dwMDUserType, [In] int dwMDDataType, [In] int bMDCopyFlag);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    public virtual extern void CopyKey([In] int hMDSourceHandle, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMDSourcePath, [In] int hMDDestHandle, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMDDestPath, [In] int bMDOverwriteFlag, [In] int bMDCopyFlag);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    public virtual extern void DeleteAllData([In] int hMDHandle, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMDPath, [In] int dwMDUserType, [In] int dwMDDataType);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    public virtual extern void DeleteBackup([In, MarshalAs(UnmanagedType.LPWStr)] string pszMDBackupLocation, [In] int dwMDVersion);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    public virtual extern void DeleteChildKeys([In] int hMDHandle, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMDPath);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    public virtual extern void DeleteData([In] int hMDHandle, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMDPath, [In] int dwMDIdentifier, [In] int dwMDDataType);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    public virtual extern void DeleteKey([In] int hMDHandle, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMDPath);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    public virtual extern void EnumBackups([In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0, SizeConst = 0x100)] ushort[] szMDBackupLocation, out int pdwMDVersion, out _FILETIME pftMDBackupTime, [In] int dwMDEnumIndex);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    public virtual extern void EnumData([In] int hMDHandle, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMDPath, [In, Out] ref METADATA_RECORD pmdrMDData, [In] int dwMDEnumDataIndex, out int pdwMDRequiredDataLen);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    public virtual extern void EnumKeys([In] int hMDHandle, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMDPath, [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0, SizeConst = 0x100)] ushort[] szMDName, [In] int dwMDEnumObjectIndex);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    public virtual extern void GetAllData([In] int hMDHandle, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMDPath, [In] int dwMDAttributes, [In] int dwMDUserType, [In] int dwMDDataType, out int pdwMDNumDataEntries, out int pdwMDDataSetNumber, [In] int dwMDBufferSize, out byte pbMDBuffer, out int pdwMDRequiredBufferSize);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    public virtual extern void GetData([In] int hMDHandle, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMDPath, [In, Out] ref METADATA_RECORD pmdrMDData, out int pdwMDRequiredDataLen);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    public virtual extern void GetDataPaths([In] int hMDHandle, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMDPath, [In] int dwMDIdentifier, [In] int dwMDDataType, [In] int dwMDBufferSize, out ushort pszBuffer, out int pdwMDRequiredBufferSize);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    public virtual extern void GetDataSetNumber([In] int hMDHandle, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMDPath, out int pdwMDDataSetNumber);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    public virtual extern void GetHandleInfo([In] int hMDHandle, out METADATA_HANDLE_INFO pmdhiInfo);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    public virtual extern void GetLastChangeTime([In] int hMDHandle, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMDPath, out _FILETIME pftMDLastChangeTime, [In] int bLocalTime);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), TypeLibFunc(TypeLibFuncFlags.FRestricted)]
    public virtual extern void GetServerGuid();
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    public virtual extern void GetSystemChangeNumber(out int pdwSystemChangeNumber);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), TypeLibFunc(TypeLibFuncFlags.FRestricted)]
    public virtual extern void KeyExchangePhase1();
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), TypeLibFunc(TypeLibFuncFlags.FRestricted)]
    public virtual extern void KeyExchangePhase2();
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    public virtual extern int OpenKey([In] int hMDHandle, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMDPath, [In] int dwMDAccessRequested, [In] int dwMDTimeOut);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    public virtual extern void RenameKey([In] int hMDHandle, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMDPath, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMDNewName);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    public virtual extern void Restore([In, MarshalAs(UnmanagedType.LPWStr)] string pszMDBackupLocation, [In] int dwMDVersion, [In] int dwMDFlags);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    public virtual extern void SaveData();
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    public virtual extern void SetData([In] int hMDHandle, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMDPath, [In] ref METADATA_RECORD pmdrMDData);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    public virtual extern void SetLastChangeTime([In] int hMDHandle, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMDPath, [In] ref _FILETIME pftMDLastChangeTime, [In] int bLocalTime);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    public virtual extern void UnmarshalInterface([MarshalAs(UnmanagedType.Interface)] out MSAdminBase_W piadmbwInterface);
  }
}

Next, the easy part - auxiliary .NET types to implement a C# version of RAII:

TemporaryComObject:

  public class TemporaryComObject
  {
    public static TemporaryComObject<T> Wrap<T>(T com) where T : class
    {
      return new TemporaryComObject<T>(com);
    }
  }

  public class TemporaryComObject<T> : IDisposable where T : class
  {
    public TemporaryComObject(T com)
    {
      Com = com;
    }

    public T Com { get; private set; }

    #region IDisposable Members

    public void Dispose()
    {
      if (Com != null)
      {
        Marshal.FinalReleaseComObject(Com);
        Com = null;
      }
    }

    #endregion
  }

AllocHGlobal:

  public class AllocHGlobal : IDisposable
  {
    public readonly IntPtr Buffer;
    public AllocHGlobal(int len)
    {
      Buffer = Marshal.AllocHGlobal(len);
    }
    public AllocHGlobal(byte[] data) :
      this(data.Length)
    {
      Marshal.Copy(data, 0, Buffer, data.Length);
    }

    #region Implementation of IDisposable

    public void Dispose()
    {
      Marshal.FreeHGlobal(Buffer);
    }

    #endregion
  }

AdminBaseKey:

  public class AdminBaseKey : IDisposable
  {
    private readonly IMSAdminBase_W m_adminBase;
    public readonly int Handle;

    public AdminBaseKey(IMSAdminBase_W adminBase, int handle)
    {
      m_adminBase = adminBase;
      Handle = handle;
    }

    #region Implementation of IDisposable

    public void Dispose()
    {
      m_adminBase.CloseKey(Handle);
    }

    #endregion
  }

That's it. Works for me.

answered on Stack Overflow Apr 26, 2013 by mark

User contributions licensed under CC BY-SA 3.0