如何在没有 property/function 的情况下获得派生接口 returns 它 (OLE/COM)
How to get derived interface without having a property/function that returns it (OLE/COM)
我正在使用 C++ 客户端代码与 VB 应用程序交互。我在这方面完全是新手(我只是一名化学工程师),所以如果问题很愚蠢,请原谅。
因此VB中的以下代码需要访问"BackDoor"接口,我可以获得所有其他接口,因为我遵循层次结构(如strm = hyApp.ActiveDocument.Flowsheet.Streams.Item(strmName)
但是正如您在下面的代码中看到的,BackDoor 接口等于 ProcessStream 接口!!我不明白这一点,也不知道如何在 C++ 中实现...你能帮忙吗?
VB中的代码:
Function GetMassExergy(strmName As String) As Double
GetMassExergy = EmptyValue_enum.HEmpty 'initialize to empty
Dim strm As ProcessStream
Dim bd As BackDoor
Dim corrNamesVar As TextFlexVariable
Dim corrNames() As String
Dim i As Integer
Dim exergMoniker As String
Dim exerg As RealVariable
Dim Bval As Double
strm = hyApp.ActiveDocument.Flowsheet.Streams.Item(strmName)
bd = strm
corrNamesVar = bd.BackDoorTextVariable("HysysCorrelation.300.[]:Name.0").Variable
corrNames = corrNamesVar.Values
For i = 0 To corrNames.Count - 1
If corrNames(i) = "Mass Exergy" Then
Exit For
End If
Next i
If i = corrNames.Count Then
'failed to find Mass Exergy Correlation
Exit Function
End If
exergMoniker = String.Format("HysysCorrelation.300.{0}:ExtraData.550.0", i)
exerg = bd.BackDoorVariable(exergMoniker).Variable
Bval = exerg.GetValue("kJ/kg")
GetMassExergy = Bval
End Function
C++ 代码:
void ConnectToHYSYS::GetBackDoor() {
//HyStream is already acquired using Hierarchy
IDispatch* hyStream;
// Try to Query BackDoor from hyCase interface
HRESULT hr = hyStream->QueryInterface(__uuidof(hyBackDoor), (void**)&hyBackDoorDisp);
//Last hr returns S_OK
if (SUCCEEDED(hr))
{
cout << "Got the BackDoor safely" << endl;
//Get BackDoor Text Variable,
VARIANT result;
VariantInit(&result);
// Try to Get a property from BackDoor interface (to make sure that it returned //an actual interface)
hr = COMMethod(DISPATCH_PROPERTYGET, &result, hyBackDoorDisp, L"BackDoorTextVariable", 1, "HysysCorrelation.300.[]:Name.0");
CheckForHr(hr);
BackDoorTextVariable = result.pdispVal;
if (SUCCEEDED(hr))
{
cout << "Got the BackDoor Text Variable safely" << endl;
}
if (FAILED(hr)) {
cout << "Couldnt get the BackDoor Text Variable" << endl;
}
}
if (FAILED(hr)) {
cout << "Couldnt get the BackDoor" << endl;
}
}
以下是我用来访问接口内部属性的 COMMethod(它可以与所有其他接口一起正常工作)
HRESULT ConnectToHYSYS::COMMethod(int nType, VARIANT * pvResult, IDispatch * pDisp, LPOLESTR ptName, int cArgs...)
{
if (!pDisp) return E_FAIL;
va_list marker;
va_start(marker, cArgs);
DISPPARAMS dp = { NULL, NULL, 0, 0 };
DISPID dispidNamed = DISPID_PROPERTYPUT;
DISPID dispID;
char szName[200];
// Convert down to ANSI
WideCharToMultiByte(CP_ACP, 0, ptName, -1, szName, 256, NULL, NULL);
// Get DISPID for name passed...
HRESULT hr = pDisp->GetIDsOfNames(IID_NULL, &ptName, 1, LOCALE_USER_DEFAULT, &dispID);
if (FAILED(hr)) {
return hr;
}
// Allocate memory for arguments...
VARIANT * pArgs = new VARIANT[cArgs + 1];
// Extract arguments...
for (int i = 0; i < cArgs; i++) {
pArgs[i] = va_arg(marker, VARIANT);
}
// Build DISPPARAMS
dp.cArgs = cArgs;
dp.rgvarg = pArgs;
// Handle special-case for property-puts!
if (nType & DISPATCH_PROPERTYPUT) {
dp.cNamedArgs = 1;
dp.rgdispidNamedArgs = &dispidNamed;
}
// Make the call!
hr = pDisp->Invoke(dispID, IID_NULL, LOCALE_SYSTEM_DEFAULT, nType, &dp, pvResult, NULL, NULL);
if (FAILED(hr)) {
return hr;
}
// End variable-argument section...
va_end(marker);
delete[] pArgs;
return hr;
}
我调用的那一行是唯一 returns 错误“0x80020008 错误的变量类型”...我的意思是我在 COMMethod 中写的最后一小时行 "hr = pDisp->Invoke(dispID, IID_NULL, LOCALE_SYSTEM_DEFAULT, nType, &dp, pvResult, NULL, NULL);"
您的 VB 代码使用的是早期绑定,而您的 C++ 代码使用的是后期绑定。
将您的 C++ 代码切换为与您的 VB 代码类似的代码,例如:
void ConnectToHYSYS::GetBackDoor() {
IDispatch* hyStream = ...;
// Use an actual hyBackDoor
hyBackDoor* hyBackDoorDisp;
HRESULT hr = hyStream->QueryInterface(IID_PPV_ARGS(&hyBackDoorDisp));
if (SUCCEEDED(hr)) {
cout << "Got the BackDoor safely" << endl;
// From the VB code, it seems BackDoorTextVariable is a TextFlexVariable
hr = hyBackDoorDisp->get_BackDoorTextVariable(&BackDoorTextVariable);
CheckForHr(hr);
if (SUCCEEDED(hr)) {
cout << "Got the BackDoor Text Variable safely" << endl;
}
if (FAILED(hr)) {
cout << "Couldnt get the BackDoor Text Variable" << endl;
}
}
if (FAILED(hr)) {
cout << "Couldnt get the BackDoor" << endl;
}
}
您获得的调度对象不起作用的原因是通常只有第一个接口由标准调度程序处理。即使对于处理多个接口的自定义或手动调度程序,通常它们也不会调度 hidden(或以其他方式供私人使用)接口。
Igor 先生和 Acelent 先生的回答都成功了(抱歉,我不知道如何接受 Igor 先生的评论作为回答,所以我将其复制到这里并接受它作为对其他人的回答面临同样的问题。
pArgs[i] = va_arg(marker, VARIANT);这表现出未定义的行为,因为您传递给 COMMethod 的实际参数实际上不是 VARIANT:COMMethod(..., 1, "HysysCorrelation.300.[]:Name.0"); – 伊戈尔·坦德尼克
谢谢大家..
我正在使用 C++ 客户端代码与 VB 应用程序交互。我在这方面完全是新手(我只是一名化学工程师),所以如果问题很愚蠢,请原谅。
因此VB中的以下代码需要访问"BackDoor"接口,我可以获得所有其他接口,因为我遵循层次结构(如strm = hyApp.ActiveDocument.Flowsheet.Streams.Item(strmName)
但是正如您在下面的代码中看到的,BackDoor 接口等于 ProcessStream 接口!!我不明白这一点,也不知道如何在 C++ 中实现...你能帮忙吗?
VB中的代码:
Function GetMassExergy(strmName As String) As Double
GetMassExergy = EmptyValue_enum.HEmpty 'initialize to empty
Dim strm As ProcessStream
Dim bd As BackDoor
Dim corrNamesVar As TextFlexVariable
Dim corrNames() As String
Dim i As Integer
Dim exergMoniker As String
Dim exerg As RealVariable
Dim Bval As Double
strm = hyApp.ActiveDocument.Flowsheet.Streams.Item(strmName)
bd = strm
corrNamesVar = bd.BackDoorTextVariable("HysysCorrelation.300.[]:Name.0").Variable
corrNames = corrNamesVar.Values
For i = 0 To corrNames.Count - 1
If corrNames(i) = "Mass Exergy" Then
Exit For
End If
Next i
If i = corrNames.Count Then
'failed to find Mass Exergy Correlation
Exit Function
End If
exergMoniker = String.Format("HysysCorrelation.300.{0}:ExtraData.550.0", i)
exerg = bd.BackDoorVariable(exergMoniker).Variable
Bval = exerg.GetValue("kJ/kg")
GetMassExergy = Bval
End Function
C++ 代码:
void ConnectToHYSYS::GetBackDoor() {
//HyStream is already acquired using Hierarchy
IDispatch* hyStream;
// Try to Query BackDoor from hyCase interface
HRESULT hr = hyStream->QueryInterface(__uuidof(hyBackDoor), (void**)&hyBackDoorDisp);
//Last hr returns S_OK
if (SUCCEEDED(hr))
{
cout << "Got the BackDoor safely" << endl;
//Get BackDoor Text Variable,
VARIANT result;
VariantInit(&result);
// Try to Get a property from BackDoor interface (to make sure that it returned //an actual interface)
hr = COMMethod(DISPATCH_PROPERTYGET, &result, hyBackDoorDisp, L"BackDoorTextVariable", 1, "HysysCorrelation.300.[]:Name.0");
CheckForHr(hr);
BackDoorTextVariable = result.pdispVal;
if (SUCCEEDED(hr))
{
cout << "Got the BackDoor Text Variable safely" << endl;
}
if (FAILED(hr)) {
cout << "Couldnt get the BackDoor Text Variable" << endl;
}
}
if (FAILED(hr)) {
cout << "Couldnt get the BackDoor" << endl;
}
}
以下是我用来访问接口内部属性的 COMMethod(它可以与所有其他接口一起正常工作)
HRESULT ConnectToHYSYS::COMMethod(int nType, VARIANT * pvResult, IDispatch * pDisp, LPOLESTR ptName, int cArgs...)
{
if (!pDisp) return E_FAIL;
va_list marker;
va_start(marker, cArgs);
DISPPARAMS dp = { NULL, NULL, 0, 0 };
DISPID dispidNamed = DISPID_PROPERTYPUT;
DISPID dispID;
char szName[200];
// Convert down to ANSI
WideCharToMultiByte(CP_ACP, 0, ptName, -1, szName, 256, NULL, NULL);
// Get DISPID for name passed...
HRESULT hr = pDisp->GetIDsOfNames(IID_NULL, &ptName, 1, LOCALE_USER_DEFAULT, &dispID);
if (FAILED(hr)) {
return hr;
}
// Allocate memory for arguments...
VARIANT * pArgs = new VARIANT[cArgs + 1];
// Extract arguments...
for (int i = 0; i < cArgs; i++) {
pArgs[i] = va_arg(marker, VARIANT);
}
// Build DISPPARAMS
dp.cArgs = cArgs;
dp.rgvarg = pArgs;
// Handle special-case for property-puts!
if (nType & DISPATCH_PROPERTYPUT) {
dp.cNamedArgs = 1;
dp.rgdispidNamedArgs = &dispidNamed;
}
// Make the call!
hr = pDisp->Invoke(dispID, IID_NULL, LOCALE_SYSTEM_DEFAULT, nType, &dp, pvResult, NULL, NULL);
if (FAILED(hr)) {
return hr;
}
// End variable-argument section...
va_end(marker);
delete[] pArgs;
return hr;
}
我调用的那一行是唯一 returns 错误“0x80020008 错误的变量类型”...我的意思是我在 COMMethod 中写的最后一小时行 "hr = pDisp->Invoke(dispID, IID_NULL, LOCALE_SYSTEM_DEFAULT, nType, &dp, pvResult, NULL, NULL);"
您的 VB 代码使用的是早期绑定,而您的 C++ 代码使用的是后期绑定。
将您的 C++ 代码切换为与您的 VB 代码类似的代码,例如:
void ConnectToHYSYS::GetBackDoor() {
IDispatch* hyStream = ...;
// Use an actual hyBackDoor
hyBackDoor* hyBackDoorDisp;
HRESULT hr = hyStream->QueryInterface(IID_PPV_ARGS(&hyBackDoorDisp));
if (SUCCEEDED(hr)) {
cout << "Got the BackDoor safely" << endl;
// From the VB code, it seems BackDoorTextVariable is a TextFlexVariable
hr = hyBackDoorDisp->get_BackDoorTextVariable(&BackDoorTextVariable);
CheckForHr(hr);
if (SUCCEEDED(hr)) {
cout << "Got the BackDoor Text Variable safely" << endl;
}
if (FAILED(hr)) {
cout << "Couldnt get the BackDoor Text Variable" << endl;
}
}
if (FAILED(hr)) {
cout << "Couldnt get the BackDoor" << endl;
}
}
您获得的调度对象不起作用的原因是通常只有第一个接口由标准调度程序处理。即使对于处理多个接口的自定义或手动调度程序,通常它们也不会调度 hidden(或以其他方式供私人使用)接口。
Igor 先生和 Acelent 先生的回答都成功了(抱歉,我不知道如何接受 Igor 先生的评论作为回答,所以我将其复制到这里并接受它作为对其他人的回答面临同样的问题。
pArgs[i] = va_arg(marker, VARIANT);这表现出未定义的行为,因为您传递给 COMMethod 的实际参数实际上不是 VARIANT:COMMethod(..., 1, "HysysCorrelation.300.[]:Name.0"); – 伊戈尔·坦德尼克
谢谢大家..