我目前正在开发一个MFC应用程序,该应用程序需要从另一个系统上运行的COM对象中检索数据。当两个系统都运行Windows XP并且相同的手动设置用户帐户(即两个系统上相同的用户名和密码,没有域)时,我们已经有相同的数据交换机制工作并完全支持。问题是我正在尝试设置它,以便我可以从另一台设置了相同用户帐户但以公司域用户帐户登录的计算机访问相同的 DCOM 系统。
现在,如果我使用运行方式手动运行我的应用程序并指定备用用户,它可以工作,但我正在寻找更好的解决方案。当我在CoCreateInstanceEx中为COSERVERINFO设置COAUTHIDENTITY时,我指定了备用帐户的用户名和密码,但这似乎不起作用。我已经在域条目中尝试了各种东西 - 本地计算机的计算机名称,远程计算机的计算机名称,并将其留空 - 但似乎都没有帮助。
我尝试编辑服务器计算机上对象的 DCOM 权限以允许对 Everyone 帐户的完全访问权限,但这似乎没有帮助,并且我无法找到有关真正问题的任何有意义的错误消息。如果我可以在服务器计算机上获得某种日志消息,以准确查看使用运行方式运行时遇到的凭据,可能会有所帮助。有人有什么想法吗?或者,当您从非域帐户建立DCOM连接时,可能知道系统用于域的内容(有些事情意味着使用了计算机名称,但是当我尝试时这不起作用)。
代码如下:
COAUTHINFO AuthInfo;
COAUTHIDENTITY AuthIdentity;
COSERVERINFO ServerInfo;
MULTI_QI Results;
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;
Results.pIID = &_uuidof(_DS_SessionContext);
Results.pItf = NULL;
Results.hr = 0;
hr = CoCreateInstanceEx(clsid, NULL, CLSCTX_ALL, &ServerInfo, (ULONG) 1, &Results);
if(FAILED(hr))
{
m_Error.Format("(0x%x) CoCreateInstanceEx for _DS_DataFrame failed.",hr);
m_Error2.Format("Make sure computer IP address is correct and connected.");
CoUninitialize();
UpdateData(false);
UpdateWindow();
return false;
}
pSession = (_DS_SessionContext *)Results.pItf;
hr = pSession->raw_DS_GetVersion(&DSStatus, &version);
if(FAILED(hr))
{
m_Error.Format("(0x%x)GetVersion",hr);
CoUninitialize();
UpdateData(false);
UpdateWindow();
return false;
}
啊,我想通了。事实证明,在 DCOM 中,创建实例并在其上调用函数不会自动使用相同的安全毯。传递给 CoCreateInstanceEx 的 COSERVERINFO 中的身份验证信息仅适用于创建实例,当我稍后在该实例上调用函数时,它会失败,因为我使用应用程序的凭据调用这些函数。
为了正确地做到这一点,在实例上调用函数之前,我必须首先调用(为清楚起见,省略了错误处理):
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);
这会将用于调用实例的安全毯设置为用于创建实例的同一安全毯,因此一切正常。