Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/129.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用自定义标识调用QueryInterface_C++_Com_Dcom_Opc - Fatal编程技术网

C++ 使用自定义标识调用QueryInterface

C++ 使用自定义标识调用QueryInterface,c++,com,dcom,opc,C++,Com,Dcom,Opc,问题: 我成功地在代理上调用CoSetProxyBlanket(如果这是正确的术语),然后在同一个代理上调用QueryInterface,但我收到一个结果0x80070005(“拒绝访问”)。但是,如果我首先使用相同的凭据调用CoInitializeSecurity(我正在尝试避免),那么调用将成功 问题: 如何在不调用CoInitializeSecurity的情况下成功获得所需的接口?据我所知,一个进程只能调用此方法一次,因此它与生成dll不兼容,通常可以用调用CoSetProxyBlanke

问题:

我成功地在代理上调用CoSetProxyBlanket(如果这是正确的术语),然后在同一个代理上调用QueryInterface,但我收到一个结果0x80070005(“拒绝访问”)。但是,如果我首先使用相同的凭据调用CoInitializeSecurity(我正在尝试避免),那么调用将成功

问题:

如何在不调用CoInitializeSecurity的情况下成功获得所需的接口?据我所知,一个进程只能调用此方法一次,因此它与生成dll不兼容,通常可以用调用CoSetProxyBlanket来代替

详细信息:

我正在尝试构建自己的OPC客户端,它可以与运行在不同域上的计算机进行通信,而无需匹配用户帐户

首先,我使用在服务器上有效的域、用户名和密码创建一个标识结构:

COAUTHINFO      authInfo;
COAUTHIDENTITY  authIdentity;

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.pAuthInfo = &authInfo;
然后,我可以使用此服务器信息调用
CoCreateInstanceEx
,获取OPC服务器(
IID\U IOPCServer
)的句柄(
m_IOPCServer

在获得句柄后,我发现有必要再次设置此调用的更多权限(请参阅):

hr = CoSetProxyBlanket(m_IOPCServer, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, 
         NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, 
         &authIdentity, EOAC_NONE);
在此之后,我能够成功获得OPC项目组的句柄:

hr = m_IOPCServer->AddGroup(L"", FALSE, reqUptRate, clientHandle, 
         NULL, NULL, lcid, &m_hServerGroup, &revisedUptRate, 
         IID_IOPCItemMgt,(LPUNKNOWN*)&m_IOPCItemMgt);
但是,当我尝试使用此代码时:

hr = m_IOPCItemMgt->QueryInterface(IID_IOPCSyncIO, (void**)&m_IOPCSyncIO);
结果为0x80070005(“访问被拒绝”)。即使我在m_IOPCItemMgt上成功调用CoSetProxyBlanket,情况也是如此。但是,如果我首先调用CoInitializeSecurity,则调用将成功

我认为与之相关的问题在于QueryInterface函数是对象创建的一种形式,因此它不使用与其他方法调用(如AddGroup)相同的安全性。然而,在Microsoft参考资料中,在“实施者注意事项”下,它听起来像QueryInterface不应该检查ACL,在“返回值”下,不可能提到拒绝访问。我不认为这个问题是具体实现的,因为我已经在一些著名的商业OPC服务器(例如Matrikon Simulation Server)以及未实现任何额外安全性的开源LightOPC上尝试了我的代码

我猜我需要做的是找到一种方法来复制这个命令

hr = m_IOPCItemMgt->QueryInterface(IID_IOPCSyncIO, (void**)&m_IOPCSyncIO);

但在提供
authIdentity
的同时也要这样做。这可能吗?是否可以使用CoCreateInstanceEx或CoGetClassObject或其他COM调用完成此操作?

无需太多详细说明:每个进程至少调用一次CoInitializeSecurity。这可以隐式或显式地完成。如果您的代码没有进行显式调用,DCOM运行时将使用从注册表填充的参数为您执行此操作。您可以尝试调整适当的注册表值,以强制DCOm使用与显式调用中使用的值类似的值。保存这些值的注册表项是“HKEY\U LOCAL\U MACHINE\SOFTWARE\Classes\AppID{AppID\U GUID}”。这里描述了此项:

您必须在每个新COM对象实例上调用
CoSetProxyBlanket
,因此,在您的情况下,即使对于
m\u IOPCItemMgt

您也必须调用它。在使用
QueryInterface
之前,您需要在
IUnknown
界面中调用
CoSetProxyBlanket

CComPtr<IUnknown> pUnknown;
hr = m_IOPCItemMgt->QueryInterface(IID_IUnknown, (void**)&pUnknown);
hr = CoSetProxyBlanket(pUnknown, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, 
         NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, 
         &authIdentity, EOAC_NONE);
hr = pUnknown->QueryInterface(IID_IOPCSyncIO, (void**)&m_IOPCSyncIO);
CComPtr-punnown;
hr=m_IOPCItemMgt->QueryInterface(IID_IUnknown,(void**)和pUnknown);
hr=CoSetProxyBlanket(pUnknown,RPC_C_AUTHN_WINNT,RPC_C_AUTHZ_NONE,
NULL,RPC\u C\u AUTHN\u LEVEL\u调用,RPC\u C\u IMP\u LEVEL\u模拟,
&authIdentity,EOAC_无);
hr=pUnknown->QueryInterface(IID_IOPCSyncIO,(void**)和m_IOPCSyncIO);

您可以查看更多信息。

这对我没有帮助。如何使用与进程不同的安全上下文调用QueryInterface?例如,我如何创建一个程序,使用不同的凭证连接到多个OPC服务器?请注意“在返回值下,拒绝访问不被视为可能”:在COM中,一组成功代码被视为接口合同的一部分,而错误代码集则不被视为。也就是说,允许接口方法返回它想要的任何错误,即使没有记录,也不会破坏“接口契约”。几乎任何(D)COM方法都可以返回许多错误代码(如RPC_xxxx错误代码),并且每个方法都没有记录这些错误代码。因此,记录的错误代码是“为了说明”,这些代码值得解释,但仅此而已。在QueryInterface调用中,您对安全上下文没有太多控制权。您可能可以实现自定义代理并在代理中调整CoInitializeSecurity,但每个代理都有一个安全上下文。有关自定义代理的详细信息,请参见此处: