Archiv für Januar 2011

ALM mit Redmine, Teil 1

Kürzlich war ich auf der Suche nach einem guten Bugtracker, um den Support in unserer Firma etwas zu unterstützen und um so eine Art Wissensdatenbank aufzubauen. Zur Zeit werden bei uns Fehlermeldungen und Probleme von Kunden unserer Produkte vom Support-Mitarbeiter entgegengenommen und so weit geholfen wie möglich. Wenn unser Support-Mitarbeiter nicht mehr weiter weiß, wird das Problem telefonisch oder per E-Mail an den entsprechenden Entwickler dieser Software weitergeleitet. Der bearbeitet dann das Ganze und schickt dem Kunden eine Lösung bzw. verweist ihn auf ein kommendes Update der Software. Es ist natürlich ungünstig für den Entwickler, wenn ähnliche Probleme immer wieder bei ihm auf den Tisch landen und ihn von der eigentlichen Arbeit abhalten.

Um diesen Missstand zu beheben wollen wir jetzt einen Bugtracker einführen welcher den Support-Mitarbeiter bei der Fehlerbehebung unterstützt. Einmal aufgetauchte Fehler oder auch nur Anfragen werden in den Bugtracker eingetragen und kategorisiert. Wenn der Fehler nicht gleich behoben werden kann, kümmert sich der entsprechende Entwickler darum und trägt die Lösung ein bzw. verweist auf die Programmversion, in der der Fehler behoben ist. So weit der Plan jedenfalls!

Bei meiner Suche nach entsprechenden Lösungen bin ich natürlich auf tausende von Systemen und Programme gestoßen. Da das Ganze aber so kostengünstig wie möglich sein soll, blieben nur ein paar wenige Open-Source Programme übrig. Die da wären Bugzilla, Mantis, Trac und schließlich Redmine.

Von den ganzen Programmen hat mir Redmine am besten gefallen. Bugzilla war zwar gut, aber die Installation ist einfach unmöglich. Mantis ist vom Umfang her auch recht gut, aber die Oberfläche sieht einfach altbacken aus. Und Trac schließlich hat keine wirklich zufriedenstellende Multi-Projekt-Unterstützung und eine zu komplizierte Oberfläche. Redmine war mir vorher total unbekannt, aber dank Bitnami und ihren fertigen All-in-one-Installern bzw. ihren fertigen Virtuellen Maschinen konnte ich den Bugtracker ohne Probleme ausprobieren.

Also läuft jetzt bei uns erst mal eine VM mit Ubuntu 10.10, Apache, MySql, Ruby und Redmine zum Testeinsatz. Dank der Weboberfläche war es das schon fast mit der Installation der Software im Unternehmen. Jetzt bracht nur noch jeder Mitarbeiter ein Login und den Link mit der IP der VM und dem Programm. Die Weitere Einrichtung des Programmes sowie unsere Erfahrungen damit, werden in den kommenden Teilen beschrieben.

Advertisements

, , ,

Hinterlasse einen Kommentar

gemanagte Referenzen in einer nicht gemanagten Klasse speichern

Wenn man C++ CLI und normales C++ in einem Projekt zusammen einsetzt, tauchen früher oder später scheinbar unlösbare Probleme auf. Bei einem Videoplayer den wir zur Zeit programmieren, war es nun soweit.

Um den Programmcode etwas zu entschlacken und den darunter liegenden Algorithmus zur Erstellung eines DirectShow Aufnahmegraphen wieder sichtbar zu machen, wurde es endlich Zeit eine Referenz auf ein gemanagtes Objekt in einer nativen Klasse zu speichern.

Im WPF-Frontend (C#) stellt der Nutzer ein, von welcher Kamera er aufnehmen will und in welches Format das geschehen soll. Diese Konfiguration wird an das Backend (C++) übergeben, in dem schließlich der Aufnahmegraph aufgebaut wird. Dabei kann es sehr viele unterschiedliche Kombination der Konfigurationsparameter geben. Die Art der Kamera (DV, USB, …), die Audioquelle, TimeShift (darüber werde ich bei Gelegenheit auch noch einen Blog-Eintrag schreiben => das war meine Diplomarbeit!) und noch einige mehr spielen hierbei eine Rolle.

Der Aufbau des Aufnahmegraphen erfolgte in einer großen Klasse mit etlichen Funktionen, und immer wieder wurde als Parameter dieser Funktionen ein Parameter vom Typ ICaptureConfiguration^ übergeben. Also habe ich das ganze aufgeflochten und in mehrere Klassen verteilt. Eine abstrakte Basisklasse mit statischen Hilfsfunktionen und einem Interface mit den wichtigsten Methoden, welche dann durch die Detail-Klassen abgedeckt sein müssen. Und um nicht ständig die Konfiguration als Parameter übergeben zu müssen, wird dieser Kontraktur als Member gespeichert.

Doch oh Schreck, was ist das: “Der Typ ICaptureConfiguration^ kann nicht als Membervariable einer nicht C++ CLI Klasse verwendet werden!” Ist ja eigentlich auch logisch, wie soll sonst der Speichermanager der CLR mitbekommen, wann die Referenz nicht mehr gebraucht wird und er das Objekt wieder freigeben kann. Oder noch schlimmer, wenn der Speichermanager des Objekt in seinem Speicher an eine andere Adresse schiebt um Platz zu schaffen, wäre die Referenz plötzlich ungültig! Es gibt nun nur zwei Möglichkeiten: entweder alles auf C++ CLI umstellen, was mindesten 100 Tage oder mehr dauern würde oder aber doch einen Weg finden, die Referenz zu speichern.

Dank google, der MSDN und anderen Seiten ist es mir zum Glück schließlich doch gelungen die Referenz zu speichern. Genau dafür gibt es nämlich das Template gcroot<T>. Es sorgt dafür, dass die zugewiesene Referenz immer erreichbar ist. Da man solch eine Referenz immer mit delete wieder freigeben müsste, ist es besser man nutzt auto_gcroot<T>. Das wird nämlich wie alle Wrapper dieser Art automatisch freigegeben. Im Code sieht das ganze dann in etwa so aus:

#include <msclr\auto_gcroot.h>
#using <mscorlib.dll>

using namespace System;
...

class CCaptureMgrBase
{
    CCaptureMgrBase(ICaptureConfiguration^ captureConfig)
    {
        m_captureConfig = captureConfig;
    }
    ...
    msclr::auto_gcroot<ICaptureConfiguration^> m_captureConfig; 
}

Mit –> kann man nun ganz normal auf die Referenz zugreifen und Funktionen aufrufen.

Eine kleine Anmerkung habe ich allerdings noch. Man kann m_captureConfig nicht mehr einfach so an eine Funktion übergeben, welche ein ICaptureConfiguration^ als Parameter erwarte! Dafür muss man nun m_captureConfig.get() aufrufen.

class CCaptureMgrBase
{
    ...
    void Render()
    {
        // geht nicht:
        CCaptureMgrBase::Helper(m_captureConfig);

        // so ist es richtig
        CCaptureMgrBase::Helper(m_captureConfig.get());
    }

    static void Helper(ICaptureConfiguration^ captureConfig) { ... }
}

,

Hinterlasse einen Kommentar