3 Stimmen

Warum erwartet der ATL COM Map Scanning Code, dass der erste Eintrag vom Typ _ATL_SIMPLEMAPENTRY ist?

ATL bietet eine Reihe von Makros zur Erstellung so genannter COM-Maps - Ketten von Regeln, wie sich der QueryInterface()-Aufruf auf ein bestimmtes Objekt verhält. Die Map beginnt mit BEGIN_COM_MAP und endet mit END_COM_MAP. Dazwischen können (unter anderem) die folgenden verwendet werden:

  • COM_INTERFACE_ENTRY, COM_INTERFACE_ENTRY2 - um C++ zu bitten, diese Klasse einfach auf die entsprechende COM-Schnittstelle zu übertragen
  • COM_INTERFACE_ENTRY_FUNC - um C++ zu bitten, eine Funktion aufzurufen, die die Schnittstelle abruft

Das Problem ist nun, dass ich COM_INTERFACE_ENTRY_FUNC für jede Schnittstelle, die ich offenlege, verwenden möchte, damit ich alle Aufrufe protokollieren kann - ich glaube, das wird mir beim Debuggen meiner Komponente helfen, wenn sie im Feld eingesetzt wird. Die Implementierung von CComObjectRootBase::InternalQueryInterface enthält ein ATLASSERT:

ATLASSERT(pEntries->pFunc == _ATL_SIMPLEMAPENTRY);

was bedeutet, dass das Folgende in Ordnung ist:

BEGIN_COM_MAP
    COM_INTERFACE_ENTRY( IMyInterface1 )
    COM_INTERFACE_ENTRY_FUNC( __uuidof(IMyInterface2), 0, OnQueryMyInterface2 )
END_COM_MAP

da hier der erste Eintrag zu einem Eintrag vom Typ _ATL_SIMPLEMAPENTRY führt, der folgende jedoch nicht:

BEGIN_COM_MAP
    COM_INTERFACE_ENTRY_FUNC( __uuidof(IMyInterface1), 0, OnQueryMyInterface1 )
    COM_INTERFACE_ENTRY_FUNC( __uuidof(IMyInterface2), 0, OnQueryMyInterface2 )
END_COM_MAP

da hier der Eintragstyp nicht _ATL_SIMPLEMAPENTRY ist.

Das macht überhaupt keinen Sinn. Warum bin ich gezwungen, einen "please, C++, do the static_cast"-Eintrag als ersten Eintrag in der COM-Map zu haben?

Upd: Nach vielen weiteren Stunden der Fehlersuche gelöst, Antwort hinzugefügt.

2voto

sharptooth Punkte 162790

Innerhalb von ATL gibt es die Funktion AtlInternalQueryInterface(), die die COM-Map tatsächlich scannt. Darin befindet sich dieser Code:

if (InlineIsEqualUnknown(iid)) // use first interface
{
    IUnknown* pUnk = (IUnknown*)((INT_PTR)pThis+pEntries->dw);
    // call AddRef on pUnk, copy it to ppvObject, return S_OK
}

dieser Code ist darauf angewiesen, dass der erste Eintrag der Tabelle vom Typ _ATL_SIMPLEMAPENTRY ist, da er erwartet, dass _ATL_INTMAP_ENTRY::dw einen Offset vom aktuellen Objekt speichert este Zeiger auf die erforderliche Schnittstelle. In der in der Frage zitierten Verwendung ist der erste Eintrag dieser:

COM_INTERFACE_ENTRY_FUNC( __uuidof(IMyInterface1), 0, OnQueryMyInterface1 )

wird der Eintrag vom falschen Typ sein, aber _ATL_INTMAP_ENTRY::dw wird Null sein (zweiter Parameter des Makros) und der Code wird jedes Mal problemlos funktionieren, wenn er este Zeiger als IUnknown*. Wenn jedoch der zweite Makroparameter, der einem diesen Wert an die als dritten Parameter angegebene Funktion übergeben nicht Null ist, wird das Programm diesen Wert als Offset verwenden, was zu einem undefinierten Verhalten führen kann.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X