Objekte die mit CoCreateInstance erzeugt wurden in mehreren Klassen nutzen



  • Hallo,

    ich hoffe ich bin hier richtig. Ich beschäftige mich erst seit ein paar Wochen mit C++ und habe mein Programm so aufgebaut, das ich in einer Klasse InitializeDecklink und darin mit der Funktion InitDeckLink() ein COM-Objekt mit CoCreateInstance() erzeuge. Mittels CoCreateInstance initialisiere ich den DeckLinkIterator:

    HRESULT InitializeDecklink::InitDeckLink() {
    
    	HRESULT result;
    	result = CoCreateInstance(CLSID_CDeckLinkIterator, nullptr, CLSCTX_ALL, IID_IDeckLinkIterator, (void**)&m_deckLinkIterator);
    	
    	if (result != S_OK) {
    		std::cout << "DeckLink Driver can't be installed." << std::endl;
    	}
    	else {
    		std::cout << "DeckLink Driver installed." << std::endl;
    	}
    
    	return result;
    }
    

    Neben der Klasse InitializeDecklink habe ich auch die Klasse ControlVideo. Hier erhalte ich beim Debuggen die Meldung, das m_deckLink und m_deckLinkIterator NULL sind, was auch logisch ist, da beide Variablen mit nullptr initialisiert sind.
    Laut Entwickler-Dokumentation muss jede Pointervariable eines Interfaces mit CoCreateInstance() initialisiert werden. Leider gelingt mir das nicht. Das ist die Klasse ControlVideo:

    /**
    * Contructor with initializer list
    */
    ControlVideo::ControlVideo(IDeckLink* deckLink) : m_deckLink(deckLink), m_deckLinkInput(nullptr), m_referenceCounter(1), m_previewFrame(deckLink) {}
    
    /**
    * lists the supported display modes
    */
    HRESULT ControlVideo::ListDisplayMode() {
    
    	HRESULT result;
    	int numOfDisplayModes = 0;
    	BSTR bstrDisplayName = nullptr;
    	IDeckLinkDisplayMode* displayMode = nullptr;
    	IDeckLinkDisplayModeIterator* displayModeIterator = nullptr;
    
    	//search for deckLinkInput Interface
    	result = m_deckLink->QueryInterface(IID_IDeckLinkInput, (void**)&m_deckLinkInput);
    	if (result == S_OK) {
    		std::cout << "Get DeckLink Input Interface." << std::endl;
    		return result;
    	}
    
    	//enumerate the available display modes for a DeckLink device.
    	result = m_deckLinkInput->GetDisplayModeIterator(&displayModeIterator);
    	if (result != S_OK) {
    
    		//if there is a next available IDeckLinkDisplayMode interface, add a new interface to the vector at the end of the vector
    		while (displayModeIterator->Next(&displayMode) == S_OK) {
    			m_displayModeVector.push_back(displayMode);
    			++numOfDisplayModes;
    		}
    			
    		//The device’s display name. This allocated string must be freed by caller when no longer required
    		if (m_deckLink->GetDisplayName(&bstrDisplayName) == S_OK) {
    			m_deviceName = CString(bstrDisplayName);
    		}
    		else {
    			m_deviceName = TEXT("---DeckLink---");
    		}
    			
    		for (const auto mode : m_displayModeVector) {
    			std::cout << mode << std::endl;
    		}
    		
    	return result;
    	}
    }
    

    Für mein Verständnis sollte es funktionieren, wenn ich ein Objekt von InitializeDecklink erzeuge und dieses in der Funktion ListDevices aufrufe . Also:

    InitializeDecklink init = new InitializeDecklink();
    init->InitDeckLink();
    

    Leider ändert das nichts an der Situation. Könnte mir jemand mitteilen was ich hier falsch mache? Theoretisch könnte ich im Kontruktor für m_deckLink und m_deckLinkIterator einen Aufruf von CoCreateInstance machen. Aber das sollte wohl nicht Sinn der Sache sein...



  • This post is deleted!


  • Hast du irgendwo CoInitialize(Ex) aufgerufen?



  • Ja, CoInitilizeEx rufe ich in in der main auf:

    int main() {
    	HRESULT result;
    	IDeckLink* deckLink = nullptr;
    	IDeckLinkIterator* deckLinkIterator = nullptr;
    
    	//initializing COM
    	if (FAILED(CoInitializeEx(nullptr, COINIT_MULTITHREADED))) {
    		std::cout << "COM can't be initialized" << std::endl;
    		return 1;
    	}
    
    
    	InitializeDecklink* init = new InitializeDecklink(deckLink);
    	init->InitDeckLink();
    	init->PrintDevice();
    	delete init;
    	
    	ControlVideo* control = new ControlVideo(deckLink);
    	control->ListDisplayMode();
    	delete control;
    
    	CoUninitialize();
    
    	return 0;
    }
    


  • @makopo
    An welcher Stelle schlägt denn was fehlt? Gibt es da einen HRESULT Rückgabecode?



  • @Quiche-Lorraine Der Debugger meldet oberflächlich in Zeile 18 der ControlVideo-Klasse das m_deckLink und m_deckLinkInput NULL sind. Wenn man genauer in Meldung schaut steht dort das der virtual function pointer von IUnknown den Speicher nicht lesen kann.

    Ich bin habe noch keine wirkliche Erfahrung mit der COM-Programmierung (das ganze ist ein Projekt aus dem Studium). Nach allem was ich bisher gelesen habe, muss man ja für jedes weitere Interface das man benutzen möchte, QueryInterface() ausführen. Die Beispiele die ich im Web gefunen habe sind genauso implementiert. Von daher weiß ich nicht wie man da weiter vorgehen kann.
    Bzgl. des virtual function pointers und dem read memory denied hatte ich noch gelesen das ein virtueller Destruktor eingebunden werden sollte. Aber das führt zu dem gleichen Fehler.

    Wenn noch jemand Tipps für gute Dokus oder Literatur zu COM hat gerne her damit. Ein paar Tutorials habe ich schon durchgearbeitet.



  • @Quiche-Lorraine Also CoInitializeEx() und CoCreateInstance() funktionieren.

    Ich hatte testweise jeweils für m_deckLink und m_deckLinkInput ein CoCreateInstance() erstellt und im Konstruktor von ControlVideo aufgerufen. Also:

    CoCreateInstance(CLSID_CDeckLinkIterator, nullptr, CLSCTX_ALL, IID_IDeckLinkIterator, (void**)&m_deckLink);
    CoCreateInstance(CLSID_CDeckLinkIterator, nullptr, CLSCTX_ALL, IID_IDeckLinkIterator, (void**)&m_deckLinkInput);
    

    Danach wurde auch in Zeile 21 S_OK zurückgegeben. Aber das kann ja nicht Sinn der Sache sein, das ich für jede Variable die mit dem nullptr intialisiert CoCreateInstance() aufrufe.



  • @makopo

    Probiere doch mal folgendes:

    int main() {
    	HRESULT result;
    	IDeckLink* deckLink = nullptr;
    	IDeckLinkIterator* deckLinkIterator = nullptr;
    
    	//initializing COM
    	if (FAILED(CoInitializeEx(nullptr, COINIT_MULTITHREADED))) {
    		std::cout << "COM can't be initialized" << std::endl;
    		return 1;
    	}
    
    
    	InitializeDecklink* init = new InitializeDecklink(deckLink);
    	init->InitDeckLink();
    	init->PrintDevice();
    	delete init;
    	
    	//ControlVideo* control = new ControlVideo(deckLink); 
           ControlVideo* control = new ControlVideo(init->m_deckLinkIterator)
    	control->ListDisplayMode();
    	delete control;
    
    	CoUninitialize();
    
    	return 0;
    }
    

    Du bestimmt nämlich einen CLSID_CDeckLinkIterator Zeiger und dieser steht in m_deckLinkIterator. In deckLink steht dagegen immer noch der Nullpointer.

    Bitte lese dich zusätzlich in RAII / std::unique_ptr / std::make_unique ein.



  • @Quiche-Lorraine Danke für den Hinweis. Da wo es geht, habe ich die RAW Pointer durch die Smart Pointer ersetzt. Ich habe da aber noch eine Fehlermeldung die mich ratlos macht.
    m_deckLinkIterator ist bei mir private und ich habe einen Getter erstellt der mir den Wert zurück gibt. Wenn ich den aber mit

    auto control = std::make_unique<ControlVideo>(init->getDeckLinkIterator());
    	control->ListDisplayMode();
    

    den Getter aufrufe und auf der Konsole ausgebe, erhalte ich als Ergebnis trotzdem NULL. Mit dem Debugger erhalte ich den Fehlercode C2664 "ControlVideo::ControlVideo(ATL::CComPtr<InitializeDecklink>)" : Konvertierung von Argument 1 von "_Ty" in "ATL::CComPtr<InitializeDecklink>" nicht möglich.
    Ich habe aber einen zweiten Konstruktor erstellt, der InitializeDecklink entgegen nimmt. Daher verstehe ich das Problem nicht.

    ControlVideo::ControlVideo(CComPtr<IDeckLink> deckLink) 
    	: m_deckLink(deckLink), m_deckLinkInput(nullptr), m_referenceCounter(1), m_previewFrame(deckLink) {
    
    	if (m_deckLinkInput) {
    		std::runtime_error("No DeckLink Input Interface found.");
    	}
    }
    
    ControlVideo::ControlVideo(CComPtr<InitializeDecklink>init) 
    	: m_deckLink(nullptr), m_deckLinkInput(nullptr), m_referenceCounter(1), m_previewFrame(nullptr) {}
    

    Macht das mit dem Getter Aufruf so wie ich das mache überhaupt Sinn? m_deckLinkIterator ja auch mit NULL initialisiert. Dachte erst an einen Setter, um der mit NULL initialisierten m_deckLinkIterator den Rückgabewert aus CoCreateInstance zuzuweisen, aber das funktioniert auch nicht so wirklich.



  • @makopo

    Mit dem Debugger erhalte ich den Fehlercode C2664 "ControlVideo::ControlVideo(ATL::CComPtr<InitializeDecklink>)" : Konvertierung von Argument 1 von "_Ty" in "ATL::CComPtr<InitializeDecklink>" nicht möglich.

    Da hat der Compiler auch recht. Ein Blick in die MSDN Doku zu ATL::CComPtr verrät: A smart pointer class for managing COM interface pointers. Und da InitializeDecklink kein COM Interface Pointer ist, erscheint die Fehlermeldung.

    Denn die entscheidende Frage für dich ist:

    • Wie gibt man einen COM Pointer frei?
    • Wie gibt man ein new char Pointer frei?
    • Wie gibt man einen char char[256] Pointer frei?
    • Wie soll ein CComPtr, std::unique_ptr dies erkennen?

    Macht das mit dem Getter Aufruf so wie ich das mache überhaupt Sinn?

    Aus meiner Sicht eher weniger und gerade deine m_referenceCounter Variable macht mir da Sorgen.

    Ich würde die Klasse InitializeDecklink zu einer Verwaltungsklasse für IDeckLinkIterator entwickeln. Diese Klasse bestimmt den IDeckLinkIterator Zeiger, gibt diesen auch wieder frei und bietet Funktionen zur Manipulation an (ggf. mittels std::function). Einen direkten Zugriff auf den COM Zeiger erlaubt die Klasse nicht.

    Die Klasse ControlVideo nutzt die InitializeDecklink Klasse entweder als Member, Referenz oder ggf. auch als Zeiger und nutzt nur deren Funktionen.



  • @Quiche-Lorraine sagte in Objekte die mit CoCreateInstance erzeugt wurden in mehreren Klassen nutzen:

    Wie gibt man einen COM Pointer frei?
    Wie gibt man ein new char Pointer frei?
    Wie gibt man einen char char[256] Pointer frei?
    Wie soll ein CComPtr, std::unique_ptr dies erkennen?

    Keine Ahnung ob ich deine Fragen richtig verstehe... Wenn ich den COM-Pointer (bzw. einen anderen Smart-Pointer) nutze, muss ich mir um die Speicherfreigabe keine Gedanken machen, da dieser automatisch freigegeben wird. Wenn man den Speicher vor der Funktionsende freigeben will, könnte man noch noch ptr.reset() aufrufen. Wenn du die Fragen aber schon so stellst, werden die nicht so simpel zu beantworten sein...

    @Quiche-Lorraine sagte in Objekte die mit CoCreateInstance erzeugt wurden in mehreren Klassen nutzen:

    Aus meiner Sicht eher weniger und gerade deine m_referenceCounter Variable macht mir da Sorgen.

    Macht dir die referenceCounter Variable Sorgen weil die AddRef() und Release()-Methoden bei den SmartPointern inklusive und im Grunde überflüssig sind?

    Tut mir Leid das ich so viel nachfrage. Ich sitze seit Tagen an der Problematik und verstehe einfach nicht was da los ist. Also C++ Anfänger direkt mit COM-Programmierung zu starten ist anscheinend nicht ganz so sinnvoll...



  • @makopo

    Wenn du die Fragen aber schon so stellst, werden die nicht so simpel zu beantworten sein...

    Nee, leider nicht. Ein new char Pointer wird mittels delete freigegeben, ein new char[256] mittels delete[] und ein COM Pointer mittels Release().

    Dein Code würde nur dann Sinn machen, wenn die Klasse InitializeDecklink ein COM Interface wäre. Dann würde deine Klasse aber wohl eher IInitializeDecklink heißen.

    Aber...

    Also C++ Anfänger direkt mit COM-Programmierung zu starten ist anscheinend nicht ganz so sinnvoll...

    aus meiner Sicht ist COM-Programmierung leider nichts für Anfänger. Dafür ist sehr viel Spezialwissen notwendig.

    Ich möchte es mal so formulieren. Lerne erst einmal ein Programm zu entwickeln. Danach solltest du ab einer gewissen Größe Funktionen in DLLs auslagern. Im Zuge der weiteren Entwicklung entstehen dann weitere Programm- und DLL-Versionen. Und erst wenn du viele Programm und DLL-Versionen hast und die ersten DLL-Hell Probleme auftauchen, kannst du dir COM anschauen.


Log in to reply