我正在尝试编写几个 NAnt 任务来与 Microsoft Virtual Server 2005 R2 SP1 交互,并且我已经在 “通过 PowerShell 控制虚拟服务器” 帖子中提取了“Virtual PC Guy's WebLog”上找到的代码.
它不起作用:我在调用 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)
我的代码如下:
var virtualServer = new VMVirtualServerClass();
SetSecurity(virtualServer);
var virtualMachine = virtualServer.CreateVirtualMachine("TEST",
@"D:\Virtual Server\TEST.vmc");
...其中 SetSecurity 定义如下:
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);
如果我编写一个独立程序并添加对
CoInitializeSecurity
的调用,那么它就可以工作。但是,我不需要一个独立的程序——我想要一组 NAnt 任务(因此是一个 DLL),并且我不想调用 CoInitializeSecurity
,因为无法保证其他一些 NAnt 任务不会执行。还没叫过呢。
有人成功了吗?
您可能会遇到有关从托管代码使用 CoSetProxyBlanket 的基本问题。不幸的是,由于 CLR 封送接口的方式,没有可靠的方法可以在托管代码中与此方法进行互操作。
这里有几个描述这个问题的博客条目
GetObjectForIUnknownWithBlanket
(在 System.Runtime.InteropServices.Marshal 下)来帮助解决此问题。来自(测试版)MSDN 文章:
GetObjectForIUnknownWithBlanket 包裹 唯一管理对象中的 IUnknown 并调用 CoSetProxyBlanket 在所有请求的接口上运行。 它确保一个唯一的对象 返回而不是查看 缓存以匹配给定的 IUnknown 一个现有的对象。
我还没有尝试过,但看起来很有希望。
顺便说一句,很好的问题和很好的接受答案!我刚刚遇到了同样的问题,这是我找到正确解释的唯一地方。