Hinweis: Dieser Beitrag repräsentiert die erste Frage meiner Anfrage. Der Einführungsblock (der gesamte Text, bis die Zahlen erreicht sind) wird in beiden Fragen wiederholt, da es Hintergrundinformationen sind, die zur Beantwortung der Frage benötigt werden.
Ich habe eine nicht verwaltete C ++ - Bibliothek, die Klassen und Funktionen enthält, die mehreren "höheren" Bibliotheken gemeinsam sind und von diesen gemeinsam genutzt werden. Ich muss nun Zugriff auf die gemeinsame Bibliothek für C # / .Net-Anwendungen bereitstellen. Um dies zu tun, muss ich die allgemeine Bibliothek mit C ++ / CLI-Wrapper-Klassen umhüllen.
Die in der allgemeinen Bibliothek enthaltenen Klassen können komplexe Klassen mit geschachtelten Klassendefinitionen und Elementvariablen sein, die Sammlungen anderer Klassenobjekte sind. Die Auflistungsvariablen sind Instanzen von typedefs einer benutzerdefinierten Listenklasse zum Verwalten der Auflistung. Die allgemeine Bibliothek enthält auch Klassen, die die geparste Struktur einer benutzerdefinierten Skriptdatei darstellen, die mit FLEX / BISON erstellt wurde. Die allgemeine Bibliothek und die "höheren" Bibliotheken sind alle so geschrieben, dass sie plattformübergreifend (Linux und GCC) kompiliert und verwendet werden können. Alle Änderungen, die ich mache, müssen dies noch zulassen.
Die C ++ / CLI-Wrapper-Klassen benötigen zunächst nur Lesefähigkeiten. Aber während das Projekt voranschreitet, muss ich schließlich in der Lage sein, die Objekte auch zu erstellen und zu modifizieren.
Ich kenne C ++ / CLI und habe mehrere Wrapper für andere nicht-verwaltete C / C ++ - Projekte erstellt und dieser gemeinsamen Bibliothek abstrahierte Funktionalität zur Verfügung gestellt. So habe ich bereits die Grundlagen (und einige fortgeschrittene Kenntnisse).
Ich habe zwei Fragen zur Ausführung dieser Aufgabe und da sie beide ihre eigenen Diskussionen und Lösungen hervorbringen können, teile ich meine Fragen in separate Beiträge auf. Ich werde den Link zu der anderen Frage in jedem Beitrag einfügen.
Wie strukturiere ich meine Dateien innerhalb des Projekts?
Die Namespace- und Klassennamen zwischen den nicht verwalteten und C ++ / CLI-Projekten stehen nicht in Konflikt. Da das nicht verwaltete Projekt das Präfix "C" für Klassennamen verwendet, nicht das C ++ / CLI. Die nicht verwaltete Klasse CWidget
wird also nur Widget
. Und sie verwenden verschiedene Root-Namensraumnamen.
Das Problem tritt auf, wenn Dateinamen betroffen sind. Als mein Standardbenennungsmuster würde Widget.h
und Widget.cpp
sowohl für nicht verwaltetes als auch für C ++ / CLI verwendet werden.
Die Projekte werden derzeit so eingerichtet, dass sich alle Dateien des Projekts im Stammverzeichnis des Projektordners befinden. Includes für Header-Dateien erfolgen nur als Name des Headers (z. B. #include "Widget.h"
). Um die Includes für Dateien eines anderen Projekts entsprechend aufzulösen, wird der Pfad des anderen Projekts zur Additional Include Directories
-Eigenschaft des verwendeten Projekts hinzugefügt.
Wenn ich meine Additional Include Directories
-Eigenschaft zum Stamm der Lösung ( ..\
) ändere und mein Include für den nicht verwalteten Header als #include "Unmanaged\Widget.h
verwende, habe ich ein neues Problem mit auflösenden Headern in der nicht verwalteter Header Um diese Option verwenden zu können, müsste ich all include-Anweisungen ändern, um ihr Projektverzeichnis voranzustellen. Ich kenne andere Projekte
Die offensichtlichste / schnellste Lösung für das Problem doppelter Dateinamen besteht darin, das Benennungsmuster für eine der Bibliotheken zu ändern. Also für das C ++ / CLI-Projekt, anstatt Widget.h
und Widget.cpp
für Präfix oder Suffix m
(verwaltet) oder w
(Wrapper) zu verwenden. Die C ++ / CLI-Dateien wären also mWidget.h
, wWidget.h
, WidgetM.h
oder WidgetW.h
. Dann könnte ich einfach mein bestehendes Muster wiederholen und gut sein.
Aber gibt es eine bessere Möglichkeit, die Dateien so zu organisieren, dass ich meine prä- / suffixlosen Dateinamen bei minimalen Änderungen des vorhandenen Codes behalten kann?
Einpacken einer nicht verwalteten C ++ - Klassenbibliothek mit C ++ / CLI - Frage 2 - Sammlungen
Ich habe etwas sehr Ähnliches gemacht, als ich eine unmanaged C ++ API umbrachte. In meinem Fall waren sogar die Klassennamen identisch. Hier ist, was ich mit meinem Projekt gemacht habe:
C:\Foo
C:\Foo\api
bar.h
) wurde mit #include "api/bar.h"
Api::Bar
In meinem Fall war die meiste Zeit für das Projekt die Automatisierung der Erstellung der verwalteten C ++ - Dateien. Ich habe ein Pärchen mit der Hand gemacht, mir klar gemacht, wie viel Zeit es dauern würde, um alles auf diese Weise zu machen, und den Prozess automatisiert.
Meine Bibliotheken waren noch getrennt. Ich hatte eine unmanaged DLL und eine gemanagte DLL. Ich habe gerade das nicht verwaltete Projekt unter dem verwalteten gespeichert.
Wie für die Automatisierung würde es jede nicht verwaltete .h-Datei lesen und meine verwaltete .h-Datei wie folgt erstellen:
#include "api/bar.h"
-Zeile hinzu. #include
-Zeilen. GetInner()
hinzu, um den nicht verwalteten Klassenzeiger zu erhalten. Erstellen Sie dann die verwalteten .cpp-Dateien wie folgt:
GetInner()
jedes Mal, wenn eine Klasse als Funktionsparameter enthalten ist Dies funktionierte für die Mehrheit der Klassen mit nur ein wenig manuellen Optimierungen. Der einzige Bereich, in dem es nicht funktionierte, war mit Sammelklassen. Nun, ich denke, ich hatte Glück, denn jede Inkasso-Klasse war im Grunde ein Wrapper um std::vector
. Ich habe alle meine verwalteten Versionen auf CollectionBase
, mit einem Konstruktor, der die nicht verwaltete Collection-Klasse verwendet, und einer Methode mit der folgenden Signatur erstellt:
Um also von einer nicht verwalteten Sammlung zu einer verwalteten Sammlung zu wechseln, war nur ein gcnew
, und umgekehrt:
Diese Art der Sache wurde auch in die Klassengenerierung .cpp für die Nicht-Collection-Klassen eingebaut.
Der Code für ToFoo
würde nur die nicht verwaltete Auflistung löschen, durch die verwaltete Auflistung iterieren und jedes nicht verwaltete Element über GetInner()
hinzufügen. Meine Kollektionen waren nicht so groß, das funktionierte perfekt.
Wenn ich die Collection-Klassen noch einmal wiederholen müsste, würde ich sie wahrscheinlich nicht auf CollectionBase
gründen. Ich würde viel eher auf List<T>
basieren oder etwas Ähnliches tun, was in den aktuellen Antworten auf Ihre Frage # 2 diskutiert wurde. Mein Code wurde mit .Net 1.1 (keine Generika) gestartet, daher war CollectionBase
für mich zu diesem Zeitpunkt am sinnvollsten.
Es wurde mit Regex von Hand gerollt. Da die Bibliothek sehr konsistent geschrieben wurde, konnte ich die gesamte Datei einlesen, Regex verwenden, um Kommentare und andere Dinge zu entfernen, die Probleme verursachen könnten (Inline-Funktionen), dann einfach jede Zeile und Regex lesen, um herauszufinden, was drin war. Ich hatte Dinge wie eine Liste aller Sammlungen (um zu wissen, wann ich die Sammlung aufrufen musste), abnormale Klassen (string / std :: wstring) und andere Dinge, an die ich mich nicht erinnern kann. Ich werde sehen müssen, ob es in unsere neue Quellcodeverwaltung gelangt ist, da das Projekt vor ein paar Jahren aufgegeben wurde.
Tags und Links .net visual-c++ c++-cli wrapper code-organization