2016-07-28 112 views
0

在我的C++程序中,我使用了一个在VB6 COM DLL中实现的COM类。我们称这个类为CETicketRA。本课程有IPositionPromotion类型的房产AppliedPromotionIPositionPromotion是由相同的VB6 COM DLL定义的接口。它具有各种属性和方法,我尝试从C++访问。VB6接口方法的延迟调用

考虑下面的代码:

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接口成员?

+0

在C#中,您可以使用'dynamic'来实现VB6风格。对于C++,http://stackoverflow.com/q/11670175/11683可能会有所帮助。 – GSerg

+0

不确定COM规则是否更严格,但通常C++会在运行时尝试访问对象时导致导致动态错误的函数名称。 _IF_就是这种情况,请务必根据需要'extern“C”'。 – M4rc

+0

@GSerg:我已经尝试过动态,它不起作用。但是我发现了一些东西:在VB6 COM DLL中,在实现“IPositionPromotion”的类中,实现“IPositionPromotion”接口的方法通常被声明为“Private”。它们被命名为“IPositionPromotion_Foobar”。如果我将它们从'Private'改为'Public',我可以在'pPromo'对象上调用'IPositionPromotion_Foobar'。 但这是一个相当丑陋的“解决方案”。 –

回答

0

VB6使用明确的接口实现。实现接口的方法不会成为实现对象的公共接口的一部分,为了调用它们,您需要明确地询问接口。如果你愿意,你可以在后面询问IDispatch,但是你需要首先查询接口,因为你从对象本身获得的IDispatch和你从这个对象实现的接口获得的IDispatch将不同于IDispatch es。

因此,当您有:

' 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++代码是相同的上述第二非工作示例。

要修复它,首先QueryInterfaceIPositionPromotion,然后查询IDispatch关闭。

+0

得到它与一个小调整工作,是的! 我在C++中声明了'IPositionPromotion'接口,从'IDispatch'派生。我使用OleView来获取接口的IID,因为ProgID引用了coclass的CLSID。通过这种组合,我的确可以'QueryInterface'为'IPositionPromotion'的'result.pdispVal'对象。那么我确实可以'QueryInterface'这个'IDispatch'。这个对象不知道任何'Foobar'方法,但是为什么我应该在使用'IPositionPromotion'接口时使用'IDispatch'?我可以用它来调用Foobar,它可以工作! 非常感谢! –