COM-Klassen Implementierung (was: Re: ID_APP_EXIT debuggen)

24/11/2010 - 16:03 von Peter Mairhofer | Report spam
Hallo Martin,

Vielen Dank einmal allgemein, das Problem an sich sollte damit mal
behoben sein.

Am 23.11.2010 21:35, schrieb Martin Richter [MVP]:

Hallo Peter!


Hmm, ich sehe gerade, der Destruktor wird leider einmal fter
aufgerufen als der Konstruktor ...


Den hab' ich schon: Wenn ich CPluggableProtocol m_Protocol; als
Membervariable von CMainFrame nutze, muss ich wohl auch
m_Protocol.AddRef(); im Konstruktor von CMainFrame ausf hren, sonst
wird es doppelt zerst rt ... Seh' ich das richtig? Oder ist es in
diesem Fall kl ger die erste Instanz der Factory irgendwie anders
zu erstellen?



Du benötigst doch gar keine Instanz. Erzeuge die Instanz mit new in
dem Moment in dem Du Sie übergeben musst.



Von was redest du jetzt? Von der Factory oder von einem Pluggable
Protocol Objekt?

Falls 1: Das geht nicht, weil ich den Pointer den ich RegisterNamespace
übergebe auch wieder UnregisterNamespace übergeben muss --> Membervariable.

Falls 2: Das erzeuge ich ja nie selbst, sondern die urlmon.dll über die
Factory die ich übergebe.

BTW: Ist es schöner die Factory in der gleichen Imlementierung
unterzubringen (wie bei mir: CPluggableProtocol) oder ist es schöner
eine eigene Factoryklasse zu schreiben?


Aber auch in diesem Fall
leidet Deine Implementierung daran dass Release einmal zuwenig
aufgerufen wird.



Genau. Finde ich nicht so hübsch.


BTW: Wenn Du eine member Variable in CMainFrame verwendest, dann ist
gar keine Referenzzàhlung nötig. Dein Objekt wird nicht zerstört wenn
es auf 0 fàllt, denn es ist ja Member in CMainFrame. Es wird zersört
wenn das Parent stirbt. COM erlaubt auch so etwas...



Ähm, das versteh ich nicht. Mir ist schon klar, dass wenn das Objekt
eine Membervariable ist es beim Zerstören des Parents zerstört wird.
Aber angenommen ich hole mir einen Pointer auf dieses Objekt und mache
ein delete drauf ist das sicher trotzdem nicht gesund.

Zur Referenzzàhlung: Die Zàhlung direkt vielleicht nicht, aber nach
aussen hin muss sich das Objekt doch so verhalten als ob es ein COM
Objekt wàre. Kurz: Ich muss AddRef, Release, QueryInterface, LockRequest
und CreateInstance dennoch anbieten. Angenommen urlmon würde sich
weitere Referenzen meiner Factory holen soll das Objekt ja trotzdem so
lange leben bis alle diese Referenzen Release'd sind.

Ich glaube gerade dass es sinnvoll wàre den Konstruktor für meine Klasse
auf private zu setzen. Denn die Instanzen für IInternetProtocol & Co
werden von CreateInstance erzeugt.

Und für die Erzeugung der Factory kann ich eine public statische Methode
CreateFactory() anbieten, die das Objekt erstellt und AddRef() ausführt.
Die Membervariable von CMainFrame ist dann doch kein Objekt mehr sondern
ein Pointer:

class CPluggableProtocol : public IClassFactory, public
IInternetProtocol, public IInternetProtocolInfo
{
private:
CPluggableProtocol() : m_lRef(0) { ... }
[...]
public:
static IClassFactory *CreateFactory()
{
IClassFactory *fac = new CPluggableProtocol();
fac->AddRef();
return fac;
}
};

Und dann:

class CMainFrame : public CFrameWnd
{
[...]
private:
CComPtr<IClassFactory> m_spFac;

public:
CMainFrame()
{
m_spFac = CPluggableProtocol::CreateFactory();
}

int OnCreate()
{
RegisterNamespace(m_spFac, ...);
[...]
}
BOOL OnClose()
{
UnregisterNamespace(m_spFac, ...);
}
[...]
};

LG
Peter
 

Lesen sie die antworten

#1 Martin Richter [MVP]
30/11/2010 - 13:51 | Warnen spam
Hallo Peter!

Falls 1: Das geht nicht, weil ich den Pointer den ich RegisterNamespace
übergebe auch wieder UnregisterNamespace übergeben muss --> Membervariable.



Doch! Das geht. Du legst die Factory mit new an. Speicherst den Zeiger
auch in Deinem MainFrameund kannst ihn beliebig benutzten.

Falls 2: Das erzeuge ich ja nie selbst, sondern die urlmon.dll über die
Factory die ich übergebe.



Das ist mir klar!

BTW: Ist es schöner die Factory in der gleichen Imlementierung
unterzubringen (wie bei mir: CPluggableProtocol) oder ist es schöner
eine eigene Factoryklasse zu schreiben?



Geschmacksache!
Wenn man unterschiedliche Factories benötigt trennt man es, und das ist
oft genug bei mir der Fall.

Genau. Finde ich nicht so hübsch.



Da wird man aber nichts dran àndenr können. Deshalb verzichtest Du ja
selbst auf Referenzzàhlung und vernichtest das Objekt nach eigenem
Gutdünken.

BTW: Wenn Du eine member Variable in CMainFrame verwendest, dann ist
gar keine Referenzzàhlung nötig. Dein Objekt wird nicht zerstört wenn
es auf 0 fàllt, denn es ist ja Member in CMainFrame. Es wird zersört
wenn das Parent stirbt. COM erlaubt auch so etwas...



Ähm, das versteh ich nicht. Mir ist schon klar, dass wenn das Objekt
eine Membervariable ist es beim Zerstören des Parents zerstört wird.
Aber angenommen ich hole mir einen Pointer auf dieses Objekt und mache
ein delete drauf ist das sicher trotzdem nicht gesund.



Warum solltest Du ein Delete auf eine Variable mach, die im Stack oder
als Member einer anderen Klasse eingebettet ist?

Zur Referenzzàhlung: Die Zàhlung direkt vielleicht nicht, aber nach
aussen hin muss sich das Objekt doch so verhalten als ob es ein COM
Objekt wàre. Kurz: Ich muss AddRef, Release, QueryInterface, LockRequest
und CreateInstance dennoch anbieten. Angenommen urlmon würde sich
weitere Referenzen meiner Factory holen soll das Objekt ja trotzdem so
lange leben bis alle diese Referenzen Release'd sind.



Ja! Aber dem Nutzer ist es egal, wie Du das Objekt verwaltest. Wichtig
für Dich: Zwischen Register/Unregister ist das Objekt für den anderen
nutzbar, danach eben nicht mehr. Punkt!

Deshalb gibt es auch genug COM Konstrukte, die solche Objekteauf dem
Stack oder als Member anlegen und fiktive interne Usage-Counts haben und
letzten Endes z.B. vernichtet werden, wenn die Anwendung endet.

Martin Richter [MVP] WWJD http://blog.m-ri.de
"A well-written program is its own heaven; a poorly written
program is its own hell!" The Tao of Programming
FAQ: http://www.mpdvc.de Samples: http://www.codeproject.com

Ähnliche fragen