2012-09-15 48 views
3

我从C++非托管代码调用C#方法。从数组中返回的类实例中获取值时遇到问题。E_NOINTERFACE尝试获取类方法指针

我简化了代码

这是有问题的方法。

[return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_UNKNOWN)] 
    public ScOrder[] GetOrders() 
    { 
     return new ScOrder[] { 

      (new ScOrder(1), 
      (new ScOrder(2) 
     }; 
    } 

这是IScOrder接口

[ComVisible(true)] 
[Guid("B2B134CC-70A6-43CD-9E1E-B3A3D9992C3E")] 
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
public interface IScOrder 
{ 
    long GetQuantity(); 
} 

这是ScOrder实施

[ComVisible(true)] 
[Guid("F739759E-4D00-440E-B0B7-69AAF97FCB6D")] 
[ClassInterface(ClassInterfaceType.None)] 
public class ScOrder 
{ 
    private long quantity = 0; 

    public ScOrder() {} 

    public ScOrder(long quantity) 
    { 
     this.quantity = quantity; 
    } 

    public long GetQuantity() 
    { 
     return this.quantity; 
    } 
} 

这是C++代码,从Zdeslav Vojkovic我previous request帮助后。问题在评论中描述

  • 我没有使用ATL和MFC。
  • C++ tlb文件通过regasm生成。

COM初始化和调用GetOrders方法效果好

IScProxyPtr iPtr; 
CoInitialize(NULL); 
iPtr.CreateInstance(CLSID_ScProxy); 
SAFEARRAY* orders; 
iPtr->GetOrders(&orders); 
LPUNKNOWN* punks; 
HRESULT hr = SafeArrayAccessData(orders, (void**)&punks); 
if(SUCCEEDED(hr)) 
{ 
    long lbound, ubound; 
    SafeArrayGetLBound(orders, 1, &lbound); 
    SafeArrayGetUBound(orders, 1, &ubound); 
    long elements = ubound - lbound + 1; 
    for(int i=0;i<elements;i++) 
    { 
     LPUNKNOWN punk = punks[i]; //the punk seems valid 
     IScOrderPtr order(punk); //unfortunatelly, "order" now points to {0x00000000} 

     //subsequent attempt to get the value will fail 
     long quantity = 0; 
     HRESULT procCall; 
     //GetQuantity will throw an exception 
     procCall = order->GetQuantity((long long *)q); 

    } 
    SafeArrayUnaccessData(orders); 
} 
SafeArrayDestroy(orders); 

感谢Zdeslav,我发现我可以在订单内调试(朋克):

IScOrderPtr order(punk); 

所以我踏进订购(朋克)看看发生了什么。我一个 “comip.h”

// Constructs a smart-pointer from any IUnknown-based interface pointer. 
// 
template<typename _InterfaceType> _com_ptr_t(_InterfaceType* p) 
    : m_pInterface(NULL) 
{ 
    HRESULT hr = _QueryInterface(p); 

内得到了...然后我踏上了_QueryInterface(P)里面执行,也comip.h

// Performs a QI on pUnknown for the interface type returned 
// for this class. The interface is stored. If pUnknown is 
// NULL, or the QI fails, E_NOINTERFACE is returned and 
// _pInterface is set to NULL. 
// 
template<typename _InterfacePtr> HRESULT _QueryInterface(_InterfacePtr p) throw() 
{ 
    HRESULT hr; 

    // Can't QI NULL 
    // 
    if (p != NULL) { 
     // Query for this interface 
     // 
     Interface* pInterface; 
     hr = p->QueryInterface(GetIID(), reinterpret_cast<void**>(&pInterface)); 

现在,这里的问题是,值返回的“hr”是E_NOINTERFACE ...并且不正确。

我没有C++或COM专家......请帮助:)

回答

1

ScOrder类似乎并没有被实施的C#侧IScOrder接口。

它应该是:

//[ComVisible(true)] 
//[Guid("F739759E-4D00-440E-B0B7-69AAF97FCB6D")] 
//[ClassInterface(ClassInterfaceType.None)] 
public class ScOrder : IScOrder 

我评论[...]上面,不是因为它的干扰,而是因为它看起来并不需要:这是IScOrder需要有COM的知名度,应该能够得到它C++方面。

没有继承IScOrder您的实例确实有一些接口,但您的兴趣IScOrder确实无法在指针上访问。

+1

同样,我被StackOverflow中的人证明是一个盲人白痴。我只是要调试,看看是否有效,然后接受这个答案。 – Mirek

+0

出于某种原因,GetQuantity返回0,但这是一个不同的问题。谢谢:) – Mirek

+1

'E_NOINTERFACE'在这里是一个很好的提示。你确实有一些东西,你知道这是你的订单类。但它不会给你所需的界面,所以它只是一个关于界面可见性的问题。 –