如何在C#中模拟另一个用户进行DCOM连接?

时间:2012-11-07 21:47:51

标签: c# .net impersonation dcom

我正在尝试连接到远程计算机上的DCOM对象,该远程计算机以与C#应用程序不同的用户身份登录。我已经让我的代码在同一台计算机上运行时连接到同一个DCOM对象,如下所示:

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

MyDCOMType是在DCOM应用程序(VB6应用程序)中实现的类型,我在项目中添加了它作为参考。我已经能够在C#代码中创建它的实例,并使用预期的结果调用所有方法。现在我试图让它连接到远程机器上的同一个对象。我试图像这样模仿远程系统上的用户(省略了变量定义和错误处理):

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

然后是类似的代码来创建对象:

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

除了CreateInstance调用抛出UnauthorizedAccessException错误,错误代码为80070005以进行未经授权的访问。

另一件事是我有C ++代码可以做同样完美的事情。那段代码是这样的:

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

它连接到远程服务器,创建DCO​​M对象,并从中获取数据就好了。我想弄清楚如何让我的C#代码做同样的事情。有任何想法吗?我把其中一个功能搞砸了吗?我错过了一些关键的电话或做错了吗?作为后台,我的计算机和我尝试连接的计算机都在域帐户下登录,但两者都没有权限。 C ++代码模拟远程用户以进行DCOM连接。我试图以这样的方式进行.NET模拟,即在给定手动输入的用户名和密码的情况下,它将对网络连接有效。

或者,如果它不可能,我想我可以编写一个带有相同C ++代码的小C ++ / CLR DLL来处理DCOM连接部分并从C#代码引用它,但我希望避免额外的复杂性。

2 个答案:

答案 0 :(得分:0)

我打了一段时间并没有取得任何进展,所以我放弃并写了一个C ++ / CLR DLL,它完美无缺。代码如下:

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

使用类定义:

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

通常的警告适用 - 我删除了更简单的代码的实际功能和错误检查/处理细节,我真的不太了解C ++ / CLR或COM和DCOM,所以可能有些事情可以完成更轻松。如果您知道在C#中有任何改进或方法,请在适当的时候发表评论/回答。

答案 1 :(得分:0)


我已经在托管代码中实现了一个实现。但是,谢谢你,基于你的实现,我能够理解这些东西是如何运作的。

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