4

I am trying to connect to a DCOM object on a remote machine which is logged in as a different user from a C# application. I have gotten my code working to connect to the same DCOM object while it is running on the same computer, like so:

MyDCOMType dcomObject;
Type remoteSessionContextType = Type.GetTypeFromProgID("ServerApp.MyDCOMType");
dcomObject = (MyDCOMType)Activator.CreateInstance(remoteSessionContextType);
string version = dcomObject.GetVersion();

MyDCOMType is a type implemented in the DCOM application (a VB6 app) that I added as a reference in my project. I have been able to create an instance of it in the C# code and call all of the methods with the expected results. Now I am trying to get it to connect to the same object on the remote machine. I am attempting to impersonate the user on the remote system like so (variable definitions and error handling omitted):

if (LogonUser(
       userName,
       domain,
       password,
       LOGON32_LOGON_NEW_CREDENTIALS,
       LOGON32_PROVIDER_WINNT50,
       out token) != false)
{
      if (DuplicateToken(token, (int)_SECURITY_IMPERSONATION_LEVEL.SecurityDelegation, out tokenDuplicate) != false)
      {
            impersonationContext = WindowsIdentity.Impersonate(tokenDuplicate.DangerousGetHandle());
      }
 }

Which is then followed by similar code to create the object:

MyDCOMType dcomObject;
Type remoteSessionContextType = Type.GetTypeFromProgID("ServerApp.MyDCOMType", ipAddress);
dcomObject = (MyDCOMType)Activator.CreateInstance(remoteSessionContextType);
string version = dcomObject.GetVersion();

Except that the CreateInstance call throws an UnauthorizedAccessException error with error code 80070005 for unauthorized access.

The other thing is that I have C++ code that does the same thing that works perfectly. That code goes like so:

COAUTHINFO      AuthInfo;
COAUTHIDENTITY  AuthIdentity;
COSERVERINFO    ServerInfo;
MULTI_QI        Results;
HRESULT     hr;
BSTR        version;
_MyDCOMType     *pSession = NULL;

AuthIdentity.Domain             = (unsigned short *) w_domain;
AuthIdentity.DomainLength       = wcslen( w_domain);
AuthIdentity.Flags              = SEC_WINNT_AUTH_IDENTITY_UNICODE;
AuthIdentity.Password           = (unsigned short *) w_password;
AuthIdentity.PasswordLength     = wcslen(w_password);
AuthIdentity.User               = (unsigned short *) w_username;
AuthIdentity.UserLength         = wcslen(w_username);

AuthInfo.dwAuthnLevel           = RPC_C_AUTHN_LEVEL_CALL;
AuthInfo.dwAuthnSvc             = RPC_C_AUTHN_WINNT;
AuthInfo.dwAuthzSvc             = RPC_C_AUTHZ_NONE;
AuthInfo.dwCapabilities         = EOAC_NONE;
AuthInfo.dwImpersonationLevel   = RPC_C_IMP_LEVEL_IMPERSONATE;
AuthInfo.pAuthIdentityData      = &AuthIdentity;
AuthInfo.pwszServerPrincName    = NULL;

ServerInfo.dwReserved1  = 0;
ServerInfo.dwReserved2  = 0;
ServerInfo.pAuthInfo    = &AuthInfo;
ServerInfo.pwszName     = w_nodename;

hr = CoCreateInstanceEx(clsid, NULL, CLSCTX_ALL, &ServerInfo, (ULONG) 1, &Results);
hr = CoSetProxyBlanket(Results.pItf, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL,
    RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, &AuthIdentity, EOAC_NONE);
pSession = (_MyDCOMType *)Results.pItf;

hr = pSession->raw_GetVersion(&version);

It connects to the remote server, creates the DCOM object, and gets data from it just fine. I'd like to figure out how to get my C# code to do the same. Any ideas? Did I mess up one of the enums going to the functions? Am I missing some critical call or doing something all wrong? As background, my computer and the computer I am trying to connect to are both logged in under domain accounts, but neither has permissions on the other. The C++ code impersonates the remote user for the purpose of the DCOM connection. I am trying to do a .NET impersonation in such a way that it will be valid for the network connection given a manually entered username and password.

Alternatively, if it just isn't possible, I suppose I could write a small C++/CLR DLL with the same C++ code to handle the DCOM connection part and reference it from the C# code, but I'm hoping to avoid the extra complexity.

Mason
  • 703
  • 6
  • 20
  • Would the answers for [this question](http://stackoverflow.com/questions/1491123/system-unauthorizedaccessexception-retrieving-the-com-class-factory-for-compone) help you? – PinnyM Nov 07 '12 at 22:15
  • Afraid not... I already know that the DCOM permissions on the remote computer are set up properly because the C++ application that does the same thing connects to it with no problem. – Mason Nov 07 '12 at 22:36

2 Answers2

0

I banged away on it for a while and made no progress, so I gave up and wrote a C++/CLR DLL, which works perfectly. Code is as follows:

MyDCOMTalker::MyDCOMTalker(String ^ipAddress, String ^username, String ^password, String ^domain)
{
    COAUTHINFO      AuthInfo;
    COSERVERINFO    ServerInfo;
    MULTI_QI        Results;
    CLSID           clsid;
    AuthIdentity = new COAUTHIDENTITY;

    long        DSStatus;
    BSTR        umVersion;

    AuthIdentity->Domain            = (unsigned short *)Marshal::StringToHGlobalAuto(domain).ToPointer();
    AuthIdentity->DomainLength      = domain->Length;
    AuthIdentity->Flags             = SEC_WINNT_AUTH_IDENTITY_UNICODE;
    AuthIdentity->Password          = (unsigned short *)Marshal::StringToHGlobalAuto(password).ToPointer();
    AuthIdentity->PasswordLength    = password->Length;
    AuthIdentity->User              = (unsigned short *)Marshal::StringToHGlobalAuto(username).ToPointer();
    AuthIdentity->UserLength        = username->Length;

    AuthInfo.dwAuthnLevel           = RPC_C_AUTHN_LEVEL_CALL;
    AuthInfo.dwAuthnSvc             = RPC_C_AUTHN_WINNT;
    AuthInfo.dwAuthzSvc             = RPC_C_AUTHZ_NONE;
    AuthInfo.dwCapabilities         = EOAC_NONE;
    AuthInfo.dwImpersonationLevel   = RPC_C_IMP_LEVEL_IMPERSONATE;
    AuthInfo.pAuthIdentityData      = AuthIdentity;
    AuthInfo.pwszServerPrincName    = NULL;

    ServerInfo.dwReserved1  = 0;
    ServerInfo.dwReserved2  = 0;
    ServerInfo.pAuthInfo    = &AuthInfo;
    ServerInfo.pwszName     = (LPWSTR)Marshal::StringToHGlobalAuto(ipAddress).ToPointer();

    Results.pIID = &_uuidof(_MyDCOMType);
    Results.pItf = NULL;
    Results.hr   = 0;

    CoInitialize(NULL);
    Marshal::ThrowExceptionForHR(CLSIDFromProgID(L"MyDcomDLL.MyDCOMType", &clsid));
    Marshal::ThrowExceptionForHR(CoCreateInstanceEx(clsid, NULL, CLSCTX_ALL, &ServerInfo, (ULONG) 1, &Results));
    Marshal::ThrowExceptionForHR(CoSetProxyBlanket(Results.pItf, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, 
        RPC_C_IMP_LEVEL_IMPERSONATE, AuthIdentity, EOAC_NONE));
    pSession = (_MyDCOMType*)Results.pItf;
    Marshal::ThrowExceptionForHR(pSession->raw_GetVersion(&DSStatus, &umVersion));
    if (DSStatus == 0 && umVersion != NULL)
        version = Marshal::PtrToStringBSTR((System::IntPtr)umVersion);
    else
        version = String::Empty;
}

With class definition:

public ref class MyDCOMTalker
{
private:
    _MyDCOMType *pSession;
    String ^version;
    COAUTHIDENTITY  *AuthIdentity;
public: 
    MyDCOMTalker(String ^ipAddress, String ^username, String ^password, String ^domain);
};

The usual caveats apply - I chopped out the actual functionality and error checking/disposal details for simpler code, and I don't really know C++/CLR or COM and DCOM that well, so there may be things that could be done easier. If you know of any improvements or a way to do it in C#, please comment/answer as appropriate.

Mason
  • 703
  • 6
  • 20
  • 1
    It's good that you've wrapped the functionality. http://blogs.msdn.com/b/mbend/archive/2007/04/18/cosetproxyblanket-not-supported-from-managed-code.aspx suggests bad things would have happened otherwise. – ta.speot.is Nov 13 '12 at 22:09
  • Interesting! Thanks for the reference, that would have been nice to find before I got started with this. The wrapper does seem to work well, though it took a bit more than 10 minutes to get working right. – Mason Nov 13 '12 at 22:14
0


I have made an implementation in managed code for you. But thank you, based on your implementation I was able to understand how these things work.

using System;
using System.Runtime.InteropServices;
using System.Net;

namespace PM.Runtime.InteropServices {
    [Flags]
    public enum CLSCTX : uint {
        INPROC_SERVER          = 0x1,
        INPROC_HANDLER         = 0x2,
        LOCAL_SERVER           = 0x4,
        INPROC_SERVER16        = 0x8,
        REMOTE_SERVER          = 0x10,
        INPROC_HANDLER16       = 0x20,
        RESERVED1              = 0x40,
        RESERVED2              = 0x80,
        RESERVED3              = 0x100,
        RESERVED4              = 0x200,
        NO_CODE_DOWNLOAD       = 0x400,
        RESERVED5              = 0x800,
        NO_CUSTOM_MARSHAL      = 0x1000,
        ENABLE_CODE_DOWNLOAD   = 0x2000,
        NO_FAILURE_LOG         = 0x4000,
        DISABLE_AAA            = 0x8000,
        ENABLE_AAA             = 0x10000,
        FROM_DEFAULT_CONTEXT   = 0x20000,
        ACTIVATE_32_BIT_SERVER = 0x40000,
        ACTIVATE_64_BIT_SERVER = 0x80000,
        ENABLE_CLOAKING        = 0x100000,
        APPCONTAINER           = 0x400000,
        ACTIVATE_AAA_AS_IU     = 0x800000,
        PS_DLL                 = 0x80000000,
        INPROC = INPROC_SERVER | INPROC_HANDLER,
        SERVER = INPROC_SERVER | LOCAL_SERVER | REMOTE_SERVER,
        ALL    = SERVER        | INPROC_HANDLER
    }

    #region Native Pointers
    public abstract class PtrHandle : IDisposable {
        ~PtrHandle() { Dispose(false); }
        public void Dispose() {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        protected abstract void Dispose(bool disposing);
        public abstract IntPtr Handle { get; }
        public static implicit operator IntPtr(PtrHandle managedPtr) {
            return managedPtr != null ? managedPtr.Handle : IntPtr.Zero;
        }
    }

    public class PinnedObject<T> : PtrHandle {
        private GCHandle _handle;
        public PinnedObject(ref T obj) { 
            _handle = GCHandle.Alloc(obj, GCHandleType.Pinned);
        }
        protected override void Dispose(bool disposing) { 
            _handle.Free(); 
        }
        public override IntPtr Handle { 
            get { return _handle.AddrOfPinnedObject(); } 
        }
    }

    public class GlobalPtr : PtrHandle {
        private IntPtr _handle = IntPtr.Zero;
        protected GlobalPtr() {}
        protected override void Dispose(bool disposing) {
            Free(ref _handle); // always release unmanaged memory...
        }

        protected void SetHandle(IntPtr handle) { 
            Free(ref _handle);
            _handle = handle; 
        }
        // get handle back with: Marshal.PtrToStructure<T>(nativePtr.Handle, T value); 
        protected void SetHandle<T>(ref T value, bool deleteOld = false) where T: struct {
            Free(ref _handle);
            _handle = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(T)));
            try {
                Marshal.StructureToPtr(value, _handle, deleteOld); 
            } catch { 
                Free(ref _handle);
                throw;
            }
        }
        public sealed override IntPtr Handle { 
            get { return _handle; } 
        }

        public static void Free<T>(ref T handle) where T: GlobalPtr {
            if (handle != null) {
                handle.Dispose();
                handle = null;
            }
        }
        public static void Free(ref IntPtr handle) {
            if (handle != IntPtr.Zero) {
                Marshal.FreeHGlobal(handle);
                handle = IntPtr.Zero;
            }
        }
    }

    public class LPAStr : GlobalPtr {
        public LPAStr(string value) { 
            SetHandle(Marshal.StringToHGlobalAnsi(value));
        }
    }
    public class LPWStr : GlobalPtr {
        public LPWStr(string value) { 
            SetHandle(Marshal.StringToHGlobalUni(value));
        }
    }
    public class PinnedStruct<T> : GlobalPtr where T: struct {
        public PinnedStruct(ref T value) {
            SetHandle<T>(ref value);
        }
    }
    #endregion

    public class WINNTAuthnInfo {
        public NetworkCredential Credential;
        public uint              AuthnLevel;
        public uint              ImpersonationLevel;
        public WINNTAuthnInfo(NetworkCredential Credential,
            uint AuthnLevel         = ComUtils.RPC_C_AUTHN_LEVEL_DEFAULT,
            uint ImpersonationLevel = ComUtils.RPC_C_IMP_LEVEL_IMPERSONATE) {
            this.Credential         = Credential;
            this.AuthnLevel         = AuthnLevel;
            this.ImpersonationLevel = ImpersonationLevel;
        }
        public static explicit operator WINNTAuthnInfo(NetworkCredential credential) {
            return new WINNTAuthnInfo(credential);
        }
    }

    public static class ComUtils {
        private static class Guids {
            public const string IID_IUnknown  = "00000000-0000-0000-C000-000000000046";
            public const string IID_IDispatch = "00020400-0000-0000-C000-000000000046";
        }
        // IID constants...
        public static readonly Guid IID_IUnknown  = new Guid(Guids.IID_IUnknown);
        public static readonly Guid IID_IDispatch = new Guid(Guids.IID_IDispatch);

        #region Constants
        // HResult codes...
        public  const int S_OK           = 0;
        public  const int E_ABORT        = -2147467260;
        public  const int E_ACCESSDENIED = -2147024891;
        public  const int E_FAIL         = -2147467259;
        public  const int E_HANDLE       = -2147024890;
        public  const int E_INVALIDARG   = -2147024809;
        public  const int E_NOINTERFACE  = -2147467262;
        public  const int E_NOTIMPL      = -2147467263;
        public  const int E_OUTOFMEMORY  = -2147024882;
        public  const int E_POINTER      = -2147467261;
        public  const int E_UNEXPECTED   = -2147418113;
        public  const int REGDB_E_CLASSNOTREG
                                         = -2147221164;

        // Some private values...
        private const int SEC_WINNT_AUTH_IDENTITY_ANSI    = 1;
        private const int SEC_WINNT_AUTH_IDENTITY_UNICODE = 2;

        public const uint RPC_C_AUTHN_NONE                = 0;
        public const uint RPC_C_AUTHN_DCE_PRIVATE         = 1;
        public const uint RPC_C_AUTHN_DCE_PUBLIC          = 2;
        public const uint RPC_C_AUTHN_DEC_PUBLIC          = 4;
        public const uint RPC_C_AUTHN_GSS_NEGOTIATE       = 9;
        public const uint RPC_C_AUTHN_WINNT               = 10;
        public const uint RPC_C_AUTHN_GSS_SCHANNEL        = 14;
        public const uint RPC_C_AUTHN_GSS_KERBEROS        = 16;
        public const uint RPC_C_AUTHN_DPA                 = 17;
        public const uint RPC_C_AUTHN_MSN                 = 18;
        public const uint RPC_C_AUTHN_KERNEL              = 20;
        public const uint RPC_C_AUTHN_DIGEST              = 21;
        public const uint RPC_C_AUTHN_NEGO_EXTENDER       = 30;
        public const uint RPC_C_AUTHN_PKU2U               = 31;
        public const uint RPC_C_AUTHN_MQ                  = 100;
        public const uint RPC_C_AUTHN_DEFAULT             = 0xFFFFFFFF;

        public const uint RPC_C_AUTHZ_NONE                = 0;
        public const uint RPC_C_AUTHZ_NAME                = 1;
        public const uint RPC_C_AUTHZ_DCE                 = 2;
        public const uint RPC_C_AUTHZ_DEFAULT             = 0xFFFFFFFF;

        public const uint RPC_C_AUTHN_LEVEL_DEFAULT       = 0;
        public const uint RPC_C_AUTHN_LEVEL_NONE          = 1;
        public const uint RPC_C_AUTHN_LEVEL_CONNECT       = 2;
        public const uint RPC_C_AUTHN_LEVEL_CALL          = 3;
        public const uint RPC_C_AUTHN_LEVEL_PKT           = 4;
        public const uint RPC_C_AUTHN_LEVEL_PKT_INTEGRITY = 5;
        public const uint RPC_C_AUTHN_LEVEL_PKT_PRIVACY   = 6;

        public const uint RPC_C_IMP_LEVEL_DEFAULT         = 0;
        public const uint RPC_C_IMP_LEVEL_ANONYMOUS       = 1;
        public const uint RPC_C_IMP_LEVEL_IDENTIFY        = 2;
        public const uint RPC_C_IMP_LEVEL_IMPERSONATE     = 3;
        public const uint RPC_C_IMP_LEVEL_DELEGATE        = 4;
        public const uint EOAC_NONE                       = 0;
        #endregion

        #region Internal unmanaged pointers...
        private class WINNTAuthidEntityPtr : GlobalPtr {
            public LPWStr _hdomain = null;
            public LPWStr _huser   = null;
            public LPWStr _hpass   = null;
            public static WINNTAuthidEntityPtr Create(NetworkCredential credential) {
                return credential != null
                    ? new WINNTAuthidEntityPtr(credential) : null;
            }
            public WINNTAuthidEntityPtr(NetworkCredential credential) {
                if (credential == null)
                    throw new ArgumentNullException("Credential");
                try {
                    string pasword = credential.Password;
                    var authIdentity = new NativeMethods.COAUTHIDENTITY() {
                        User           = (_huser   = new LPWStr(credential.UserName)),
                        Domain         = (_hdomain = new LPWStr(credential.Domain)),
                        Password       = (_hpass   = new LPWStr(pasword)),
                        UserLength     = (credential.UserName == null ? 0 : credential.UserName.Length),
                        DomainLength   = (credential.Domain   == null ? 0 : credential.Domain  .Length),
                        PasswordLength = (credential.Password == null ? 0 : pasword            .Length),
                        Flags          = SEC_WINNT_AUTH_IDENTITY_UNICODE
                    };

                    SetHandle<NativeMethods.COAUTHIDENTITY>(ref authIdentity);
                } catch { 
                    Free<LPWStr>(ref _hpass);
                    Free<LPWStr>(ref _hdomain);
                    Free<LPWStr>(ref _huser);
                    throw;
                }
            }
            protected override void Dispose(bool disposing) {
                base.Dispose(disposing);
                Free<LPWStr>(ref _hpass);
                Free<LPWStr>(ref _hdomain);
                Free<LPWStr>(ref _huser);
            }
        }

        private class WINNTAuthInfoPtr : GlobalPtr {
            private WINNTAuthidEntityPtr _identity   = null;
            public static WINNTAuthInfoPtr Create(WINNTAuthnInfo authInfo) {
                return authInfo != null
                    ? new WINNTAuthInfoPtr(authInfo.Credential, authInfo.AuthnLevel, authInfo.ImpersonationLevel) : null;
            }
            public WINNTAuthInfoPtr(NetworkCredential credential = null,
                uint AuthnLevel         = RPC_C_AUTHN_LEVEL_DEFAULT,
                uint ImpersonationLevel = RPC_C_IMP_LEVEL_IMPERSONATE) {
                _identity = WINNTAuthidEntityPtr.Create(credential);
                try {
                    var authInfo = new NativeMethods.COAUTHINFO() {
                        dwAuthnSvc           = RPC_C_AUTHN_WINNT,
                        dwAuthzSvc           = RPC_C_AUTHZ_NONE,
                        pwszServerPrincName  = IntPtr.Zero,
                        dwAuthnLevel         = AuthnLevel,
                        dwImpersonationLevel = ImpersonationLevel,
                        pAuthIdentityData    = _identity,
                        dwCapabilities       = EOAC_NONE
                    };

                    SetHandle<NativeMethods.COAUTHINFO>(ref authInfo);
                } catch { 
                    Free<WINNTAuthidEntityPtr>(ref _identity);
                    throw;
                }
            }
            protected override void Dispose(bool disposing) {
                base.Dispose(disposing);
                Free<WINNTAuthidEntityPtr>(ref _identity);
            }

            internal IntPtr Identity { get { return _identity; } }
        }
        #endregion

        public static object CreateInstance(
            string progId, 
            object pUnkOuter = null, CLSCTX dwClsContext = CLSCTX.SERVER) {
            return CreateInstanceEx(
                NativeMethods.CLSIDFromProgID(progId), IID_IUnknown, 
                pUnkOuter, dwClsContext);
        }
        public static object CreateInstance2(
            string progId, Guid intfId, 
            object pUnkOuter = null, CLSCTX dwClsContext = CLSCTX.SERVER) {
            return CreateInstanceEx(
                NativeMethods.CLSIDFromProgID(progId), intfId, 
                pUnkOuter, dwClsContext);
        }
        public static object CreateRemoteInstance(string remoteServer, 
            string progId, WINNTAuthnInfo authInfo = null,
            object pUnkOuter = null, CLSCTX dwClsContext = CLSCTX.REMOTE_SERVER) {
            return CreateRemoteInstanceEx(remoteServer,
                NativeMethods.CLSIDFromProgID(progId), IID_IUnknown, authInfo,
                pUnkOuter, dwClsContext);
        }
        public static object CreateRemoteInstance2(string remoteServer, 
            string progId, Guid intfId, WINNTAuthnInfo authInfo = null,
            object pUnkOuter = null, CLSCTX dwClsContext = CLSCTX.REMOTE_SERVER) {
            return CreateRemoteInstanceEx(remoteServer, 
                NativeMethods.CLSIDFromProgID(progId), intfId, authInfo,
                pUnkOuter, dwClsContext);
        }

        public static object CreateInstanceEx(
            Guid classId, Guid intfId, 
            object pUnkOuter = null, CLSCTX dwClsContext = CLSCTX.SERVER) {
            return NativeMethods.CoCreateInstance(
                classId, pUnkOuter, dwClsContext, intfId);
        }
        public static object CreateRemoteInstanceEx(string remoteServer,
            Guid classId, Guid intfId, WINNTAuthnInfo authInfo = null,
            object pUnkOuter = null, CLSCTX dwClsContext = CLSCTX.REMOTE_SERVER) {
            using (var authInfoPtr = WINNTAuthInfoPtr.Create(authInfo))
            using (var intfIdPtr   = new PinnedObject<Guid>(ref intfId)) {
                NativeMethods.COSERVERINFO si = new NativeMethods.COSERVERINFO() {
                    dwReserved1 = 0,
                    pwszName    = remoteServer,
                    pAuthInfo   = authInfoPtr,
                    dwReserved2 = 0
                };

                NativeMethods.MULTI_QI[] moi = new NativeMethods.MULTI_QI[1];
                moi[0] = new NativeMethods.MULTI_QI() {
                    pIID = intfIdPtr,
                    pItf = null,
                    hr   = 0
                };

                NativeMethods.CoCreateInstanceEx(classId, pUnkOuter, dwClsContext, ref si, 1, moi);
                if (moi[0].hr < 0)
                    Marshal.ThrowExceptionForHR(moi[0].hr);
                if (moi[0].pItf == null)
                    Marshal.ThrowExceptionForHR(E_POINTER);
                if (authInfoPtr != null && authInfo != null)
                    SetSecurity(moi[0].pItf, authInfoPtr.Identity, authInfo.AuthnLevel, authInfo.ImpersonationLevel);
                return moi[0].pItf;
            }
        }

        private static object SetSecurity(object objDCOM, 
            IntPtr authidEntity,
            uint   AuthnLevel         = RPC_C_AUTHN_LEVEL_DEFAULT,
            uint   ImpersonationLevel = RPC_C_IMP_LEVEL_IMPERSONATE) {
            //IntPtr ptrInterface = Marshal.GetIUnknownForObject(objDCOM);
            NativeMethods.CoSetProxyBlanket(
                objDCOM,            // pProxy
                RPC_C_AUTHN_WINNT,  // dwAuthnSvc
                RPC_C_AUTHZ_NONE,   // dwAuthzSvc
                IntPtr.Zero,        // pServerPrincName
                AuthnLevel,         // dwAuthnLevel
                ImpersonationLevel, // dwImpLevel
                authidEntity,       // pAuthInfo
                EOAC_NONE);         // dwCapabilities
            return objDCOM;
        }
        public static object SetSecurity(object objDCOM, WINNTAuthnInfo authInfo) {
            if (authInfo == null) 
                throw new ArgumentNullException("Authentication-Info");
            using (var authidEntity = WINNTAuthidEntityPtr.Create(authInfo.Credential))
                return SetSecurity(objDCOM, 
                    authidEntity, authInfo.AuthnLevel, authInfo.ImpersonationLevel);
        }
        public static object SetSecurity(object objDCOM, 
            NetworkCredential credential,
            uint   AuthnLevel         = RPC_C_AUTHN_LEVEL_DEFAULT,
            uint   ImpersonationLevel = RPC_C_IMP_LEVEL_IMPERSONATE) {
            using (var authidEntity = WINNTAuthidEntityPtr.Create(credential))
                return SetSecurity(objDCOM, 
                    authidEntity, AuthnLevel, ImpersonationLevel);
        }

        private static class NativeMethods {
            public static Guid CLSIDFromProgID(string progId) {
                Guid classId;
                int hr = NativeMethods.CLSIDFromProgID(progId, out classId);
                if (hr < 0)
                    Marshal.ThrowExceptionForHR(hr);
                return classId;
            }

            [DllImport("ole32.dll")]
            public static extern int ProgIDFromCLSID(
                [In] ref Guid clsid, [MarshalAs(UnmanagedType.LPWStr)]out string lplpszProgID);
            [DllImport("ole32.dll")]
            public static extern int CLSIDFromProgID(
                [MarshalAs(UnmanagedType.LPWStr)]string lpszProgID, out Guid pclsid);

            [DllImport("ole32.dll", ExactSpelling=true, PreserveSig=false)]
            [return: MarshalAs(UnmanagedType.Interface)]
            public static extern object CoCreateInstance(
                [In, MarshalAs(UnmanagedType.LPStruct)] Guid rclsid,
                [MarshalAs(UnmanagedType.IUnknown)] object pUnkOuter,
                CLSCTX dwClsContext,
                [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid);

            [StructLayout(LayoutKind.Sequential)] 
            public struct COAUTHIDENTITY {
                //[MarshalAs(UnmanagedType.LPWStr)] 
                public IntPtr User;
                public int    UserLength;
                //[MarshalAs(UnmanagedType.LPWStr)] 
                public IntPtr Domain;
                public int    DomainLength;
                //[MarshalAs(UnmanagedType.LPWStr)] 
                public IntPtr Password;
                public int    PasswordLength;
                public int    Flags;
            };

            [StructLayout(LayoutKind.Sequential)]
            public struct COAUTHINFO {
                public uint   dwAuthnSvc;
                public uint   dwAuthzSvc;
                //[MarshalAs(UnmanagedType.LPWStr)] 
                public IntPtr pwszServerPrincName;
                public uint   dwAuthnLevel;
                public uint   dwImpersonationLevel;
                public IntPtr pAuthIdentityData;
                public uint   dwCapabilities;
            }

            [StructLayout(LayoutKind.Sequential)]
            public struct COSERVERINFO {
                public uint   dwReserved1;
                [MarshalAs(UnmanagedType.LPWStr)]
                public string pwszName;
                public IntPtr pAuthInfo;
                public uint   dwReserved2;
            }

            [StructLayout(LayoutKind.Sequential)]
            public struct MULTI_QI {
                public IntPtr pIID;
                [MarshalAs(UnmanagedType.Interface)] public object pItf;
                public int hr;
            }

            [DllImport("ole32.dll", ExactSpelling=true, PreserveSig=false)]
            [return: MarshalAs(UnmanagedType.Interface)]
            public static extern void CoCreateInstanceEx(
                [In, MarshalAs(UnmanagedType.LPStruct)] Guid rclsid,
                [MarshalAs(UnmanagedType.IUnknown)] object pUnkOuter, 
                CLSCTX dwClsCtx,
                [In]ref COSERVERINFO pServerInfo, 
                uint cmq, 
                [In, Out] MULTI_QI[] pResults);

            [DllImport("Ole32.dll", PreserveSig = false)]
            public static extern void CoSetProxyBlanket(
                [MarshalAs(UnmanagedType.Interface)]
                object pProxy,           // IntPtr pProxy, 
                uint   dwAuthnSvc, 
                uint   dwAuthzSvc,
                IntPtr pServerPrincName, 
                uint   dwAuthLevel,
                uint   dwImpLevel, 
                IntPtr pAuthInfo,
                uint   dwCapabilities);
        }
    }
}
marian.pascalau
  • 193
  • 1
  • 5
  • Hi, I got this error trying to call `ComUtils.CreateRemoteInstance(hostname, "Microsoft.Update.Session")`: A call to PInvoke function 'Cmc.Installer.Core!Cmc.Installer.Core.Interop.ComUtils+NativeMethods::CoCreateInstanceEx' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature. – Mark Richman May 02 '16 at 17:20
  • Hi There, sorry for not answering to your post. Somehow, I have lost track in this issue. I believe you are right, I have not time to check, but the error is probably caused by the fact that in my original version the NativeMethods.CoCreateInstanstanceEx had a return value and in reality has none (code changed, hope it helps). – marian.pascalau Nov 17 '19 at 01:28