2016-07-28 92 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,它可以工作! 非常感謝! –