2009-07-29 9 views
1

In unserem Code verwenden wir systematisch native COM-Unterstützung. Alles ist in Ordnung, außer dass es uns nicht gefällt, dass bei einem Fehler _com_raise_error() aufgerufen wird, der eine _com_error-Ausnahme auslöst. Da wir eine eigene Hierarchie von Ausnahmen haben, die diesen _com_error fangen, ist das unpraktisch - es ist nicht in unserer Hierarchie und erbt nicht von std :: exception.Wer übernimmt die IErrorInfo?

Also müssen wir die _com_raise_error() überschreiben. Es ist ganz einfach - definieren Sie es einfach in unserem Code, der Linker wird damit verlinkt.

Allerdings ist unklar, wer die IErrorInfo besitzt. Die Signatur ist

void __stdcall _com_raise_error(HRESULT hr, IErrorInfo* info); 

Wer also die Funktion IErrorInfo :: Release für den Aufruf(), nachdem die Funktion zurückkehrt wäre verantwortlich nennt. Aber wie würde die Funktion überhaupt zurückkehren, wenn wir eine Ausnahme werfen und die Kontrolle woanders hin transferiert?

Ich überprüft - aufgerufen AddRef(), dann Release() sofort nach dem Eintritt in diese Funktion - der Referenzzähler ist 1. Später übergeben wir das Eigentum an das konstruierte Ausnahmeobjekt - es ruft AddRef() in seinem Konstruktor und Release () in Destruktor. Ich nehme an, das ist falsch, da AddRef() den Verweiszähler auf 2 erhöht, aber dann nur ein Release() aufgerufen wird (im Ausnahmedestruktor).

Sind ich richtig, dass die AddRef() im Konstruktor einen Speicherverlust verursacht oder gibt es einen internen Mechanismus, die IErrorInfo Objekte nicht erlaubt, überhaupt zu lecken?

Antwort

1

Ich würde mir vorstellen, dass _com_raise_errorSetErrorInfo aufrufen wird, übergibt es Ihre IErrorInfo Objekt. Der Vertrag dafür ist, dass der Verweis auf die Informationen in einem lokalen Thread gespeichert wird. Wenn Sie also eine neue Information festlegen, wird die alte freigegeben. Darüber hinaus wird jedes Mal, wenn jemand GetErrorInfo anruft, der Besitz von Informationen an diesen Anrufer übertragen. Es ist also die Pflicht des Anrufers, nach jedem fehlgeschlagenen Anruf, der ihn einrichten kann, GetErrorInfo anzurufen und das Objekt entsprechend freizugeben.

So SetErrorInfo (wie jeder andere Anruf herkömmlichen COM) wird AddRef auf Ihrem Objekt aufrufen, so dass Sie nicht es mit einem Zähler von 1 initialisieren Sie müssen

2

_com_raise_error() nicht zurückkehren soll. Es muss unabhängig vom Typ eine Ausnahme auslösen. Wenn Sie die Standardimplementierung von _com_raise_error() betrachten, übernimmt das erhöhte _com_error-Objekt den Besitz des angegebenen IErrorInfo-Objekts. _com_error ‚s hat einen Konstruktor fAddRef Parameter, der einen Standardwert false hat, so AddRef() wird nicht aufgerufen. Release() wird dann aufgerufen, wenn das _com_error-Objekt von dem Exception-Handler, der es abfängt, zerstört wird, wodurch das IErrorInfo-Objekt freigegeben wird.

1

zu den anderen Antworten Hinzufügen, sind hier ein paar Gedanken:

  • Die allgemeine COM Regel ist, dass in-Parameter müssen nicht AddRef sein: ed auf jeder Ebene, da Anrufe sind synchron und Die Referenzzählung kann sich während der Ausführung der Methode nicht ändern.

  • Jeder AddRef-Aufruf stellt eine neue stabile Referenz auf das Objekt dar, dh nach dem Aufruf von AddRef können Sie darauf zählen, dass das Objekt immer noch da ist. Das heißt, wenn Sie einen Schnittstellenzeiger für die spätere Lektüre speichern möchten, sollten Sie AddRef nennen. Wenn Sie nicht kümmern mehr um das Überleben des Objekts, rufen Mitteilung.

Also, da Sie ein Ausnahme-Objekt enthält einen IErrorInfo Zeiger werfen wollen, dass Objekt sollte es AddRef, da sie das spitze-to-Objekt braucht, um zu überleben. Sein Destruktor würde normalerweise freigeben.

Ich glaube nicht, dass SetErrorInfo dabei beteiligt sein muss - es ist die C-Alternative zum Auslösen einer Ausnahme.