Using Microsoft Virtual Server with C #: CoSetProxyBlanket does nothing

I'm trying to write a couple of NAnt tasks to interact with Microsoft Virtual Server 2005 R2 SP1, and I've brought up the code I found in "Virtual PC Guy WebLog" under "Managing a Virtual Server with PowerShell" .

It doesn't work: I always get a crash when calling CreateVirtualMachine:

System.Runtime.InteropServices.COMException (0x80070542): Either a required impersonation level was not provided, or the provided impersonation level is invalid. (Exception from HRESULT: 0x80070542)

at Microsoft.VirtualServer.Interop.VMVirtualServerClass.CreateVirtualMachine(String configurationName, String configurationPath)

My code looks like this:

var virtualServer = new VMVirtualServerClass();
SetSecurity(virtualServer);
var virtualMachine = virtualServer.CreateVirtualMachine("TEST",
    @"D:\Virtual Server\TEST.vmc");

      

... where SetSecurity is defined like this:

    private static void SetSecurity(object dcomObject)
    {
        IntPtr pProxy = Marshal.GetIUnknownForObject(dcomObject);
        int hr = CoSetProxyBlanket(pProxy,
            RPC_C_AUTHN_DEFAULT,
            RPC_C_AUTHZ_DEFAULT,
            IntPtr.Zero,
            RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
            RPC_C_IMP_LEVEL_IMPERSONATE,
            IntPtr.Zero,
            EOAC_DYNAMIC_CLOAKING);
        Marshal.ThrowExceptionForHR(hr);
    }

    private const uint RPC_C_AUTHN_NONE = 0;
    private const uint RPC_C_AUTHN_WINNT = 10;
    private const uint RPC_C_AUTHN_DEFAULT = 0xFFFFFFFF;

    private const uint RPC_C_AUTHZ_NONE = 0;
    private const uint RPC_C_AUTHZ_DEFAULT = 0xFFFFFFFF;

    private const uint RPC_C_AUTHN_LEVEL_DEFAULT = 0;
    private const uint RPC_C_AUTHN_LEVEL_PKT_PRIVACY = 6;

    private const uint RPC_C_IMP_LEVEL_IDENTIFY = 2;
    private const uint RPC_C_IMP_LEVEL_IMPERSONATE = 3;

    private const uint EOAC_NONE = 0;
    private const uint EOAC_DYNAMIC_CLOAKING = 0x40;
    private const uint EOAC_DEFAULT = 0x0800;

    [DllImport("Ole32.dll")]
    public static extern int CoSetProxyBlanket(IntPtr pProxy,
            UInt32 dwAuthnSvc,
            UInt32 dwAuthzSvc,
            IntPtr pServerPrincName,
            UInt32 dwAuthnLevel,
            UInt32 dwImpLevel,
            IntPtr pAuthInfo,
            UInt32 dwCapabilities);

      

If I write a standalone program and add a call CoInitializeSecurity

, then it works. However, I don't need a separate program - I want a set of NAnt tasks (so a DLL), and I don't want to call CoInitializeSecurity

because there is no way to ensure that some other NAnt task won't have already called it.

Has anyone got this job?

+1


source to share


2 answers


You may be facing a fundamental problem using CoSetProxyBlanket from managed code. Unfortunately, there is no reliable way to interact with this method in managed code due to the way the CLR interfaces interact.

Here are some blog posts describing this issue.



+1


source


For what it's worth, it looks like .NET 4.0 will add a new method GetObjectForIUnknownWithBlanket

(in System.Runtime.InteropServices. Marshal) to help resolve this issue. From the (Beta) MSDN article:

GetObjectForIUnknownWithBlanket wraps IUnknown in a unique managed object and calls CoSetProxyBlanket on all requested interfaces. This ensures that a unique object is returned instead of looking in the cache to match the given IUnknown for an existing object.



I haven't tried it yet, but it looks promising.

And by the way, a great question and a great answer! I just ran into the same problem and this was the only place where I found the correct explanation.

+1


source







All Articles