【问题标题】:Late-bound call to VB6 interface methods对 VB6 接口方法的后期绑定调用
【发布时间】:2016-12-03 06:49:02
【问题描述】:

在我的 C++ 程序中,我使用了一个在 VB6 COM DLL 中实现的 COM 类。我们称这个类为CETicketRA。此类具有 AppliedPromotion 类型的属性 IPositionPromotionIPositionPromotion 是同一个 VB6 COM DLL 定义的接口。它具有我尝试从 C++ 访问的各种属性和方法。

给定以下代码:

IDispatch* pETicketRA = NULL;
DISPPARAMS dispParams = {0};
VARIANT result;
VariantInit(&result);
// Left out: some code to set pETicketRA ...

OLECHAR* strAppliedPromotion = L"AppliedPromotion";
DISPID dispIDAppliedPromotion = -1;
HRESULT hr = pETicketRA->GetIDsOfNames(IID_NULL, &strAppliedPromotion, 1, LOCALE_SYSTEM_DEFAULT, &dispIDAppliedPromotion);
hr = pETicketRA->Invoke(dispIDAppliedPromotion, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, &dispParams, &result, NULL, NULL);
IDispatch* pPromo = NULL;
hr = result.pdispVal->QueryInterface(IID_IDispatch, reinterpret_cast<LPVOID*>(&pPromo));
VariantClear(&result);

现在我尝试读取IPositionPromotion 的属性Foobar

OLECHAR* strFoobar = L"Foobar";
DISPID dispIDFoobar = -1;
hr = pPromo->GetIDsOfNames(IID_NULL, &strFoobar, 1, LOCALE_SYSTEM_DEFAULT, &dispIDFoobar);

很遗憾,最后一次调用失败并显示DISP_E_UNKNOWNNAME

有没有人成功地从 C++(或 C#)调用 VB6 接口成员?

【问题讨论】:

  • 在 C# 中,您可以使用 dynamic 进行 VB6 样式的操作。对于 C++,stackoverflow.com/q/11670175/11683 可能会有所帮助。
  • 不确定 COM 规定是否更严格,但通常 C++ 在尝试在运行时访问对象时会破坏函数名称,从而导致动态错误。 如果是这种情况,请务必按要求extern "C"
  • @GSerg:我已经尝试过动态,它不起作用。但是我发现:在VB6 COM DLL中,在实现IPositionPromotion的类中,实现IPositionPromotion接口的方法通常被声明为Private。他们被命名为IPositionPromotion_Foobar。如果我将它们从Private 更改为Public,我可以在pPromo 对象上调用IPositionPromotion_Foobar。但这是一个相当丑陋的“解决方案”。
  • @TimoKunze 它们应该是私有的,这是 VB6 实现接口和事件处理程序的约定。

标签: c++ interface com vb6


【解决方案1】:

VB6 使用显式接口实现。实现接口的方法不会成为实现对象的公共接口的一部分,为了调用它们,您需要显式地请求接口。如果您愿意,您可以稍后从该接口中询问IDispatch,但您需要先查询该接口,因为IDispatch您从对象本身获得,而IDispatch您从该对象实现的接口获得将是不同的IDispatches。

所以当你有:

' IInterface.cls
Public Sub Method()
End Sub
' Class1.cls
Implements IInterface

Private Sub IInterface_Method()
  MsgBox "!"
End Sub

而您想创建Class1 的实例并调用Method(),以下将工作:

' Complile-time error: method not found
Dim c As Class1
Set c = New Class1

c.Method
' Run-time error: Object does not support this property or method
Dim c As Object    ' IDispatch
Set c = New Class1 ' QueryInterface for IDispatch from Class1

c.Method

以下将起作用:

Dim c As IInterface
Set c = New Class1

c.Method  ' Early binding
Dim c As IInterface
Set c = New Class1

Dim c_as_idispatch As Object   ' IDispatch
Set c_as_idispatch = c         ' QueryInterface for IDispatch from IInterface

c.Method  ' Late binding

您的 C++ 代码与上面的第二个无效示例相同。

要修复它,首先 QueryInterface 获取 IPositionPromotion,然后查询 IDispatch 关闭它。

【讨论】:

  • 稍微调整一下就可以了,是的!我在 C++ 中声明了IPositionPromotion 接口,它派生自IDispatch。我使用 OleView 来获取接口的 IID,因为 ProgID 是指 coclass 的 CLSID。通过这种组合,我确实可以将QueryInterface result.pdispVal 对象用于IPositionPromotion。那我确实可以QueryInterface这个IDispatch。该对象不知道任何Foobar 方法,但是当我可以使用IPositionPromotion 接口时,为什么还要使用IDispatch?我可以用它打电话给Foobar,它可以工作!非常感谢!
猜你喜欢
  • 2018-03-20
  • 2023-03-19
  • 2011-05-11
  • 2011-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-22
  • 1970-01-01
相关资源
最近更新 更多