2012-09-15 3 views
3

J'appelle les méthodes C# à partir d'un code non géré C++. J'ai un problème avec l'obtention d'une valeur d'une instance de classe retournée dans le tableau.E_NOINTERFACE lors de la tentative d'obtention d'un pointeur de méthode de classe

J'ai simplifié le code un peu

Cette méthode est la problématique.

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

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

C'est l'interface IScOrder

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

Et ceci est la mise en œuvre de 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; 
    } 
} 

Ceci est le code C++, après une aide de Zdeslav Vojkovic dans mon previous request. Le problème est décrit dans les commentaires

  • Je n'utilise pas ATL ni MFC.
  • Le fichier tlb C++ est généré via regasm.

initialisation COM et appelant la méthode GetOrders fonctionne bien

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); 

Merci à Zdeslav, j'ai découvert que je peux déboguer dans l'ordre (le punk):

IScOrderPtr order(punk); 

Je suis entré dans ordre (punk) pour voir ce qui se passe là-bas. Je suis dans un "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); 

... alors je suis entré dans la mise en œuvre _QueryInterface (p), également 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)); 

Maintenant, le problème ici est que la valeur de "hr" retourné est E_NOINTERFACE ... et ce n'est pas correct.

Je ne suis pas expert C++ ou COM ... s'il vous plaît aider :)

Répondre

1

Votre classe ScOrder ne semble pas être mise en œuvre IScOrder interface sur le côté C#.

Il aurait dû être:

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

Je commente [...] ci-dessus non pas parce qu'elle interfère plutôt parce qu'il ne semble pas nécessaire: il est IScOrder a besoin d'avoir une visibilité COM et devrait être en mesure d'obtenir sur Côté C++

Sans hériter IScOrder vos instances ont une certaine interface mais celle de votre intérêt IScOrder n'est en effet pas accessible sur les pointeurs.

+1

Encore une fois, j'ai été prouvé être un idiot aveugle par les gens dans StackOverflow. Je vais simplement déboguer ceci pour voir si cela fonctionne et ensuite accepter cela comme une réponse. – Mirek

+0

Pour une raison quelconque, GetQuantity renvoie 0 mais c'est un problème différent. Merci :) – Mirek

+1

'E_NOINTERFACE' est un bon indice ici.Vous avez un objet, et vous savez que c'est votre classe de commande. Mais cela ne vous donne pas l'interface dont vous avez besoin, il doit donc y avoir un problème de visibilité de l'interface. –

Questions connexes