Я сделал нечто очень похожее, когда оборачивал неуправляемый API C ++.В моем случае даже имена классов были идентичны.Вот что я сделал с моим проектом:
- Мое решение C ++ / CLI было на
C:\Foo
- Неуправляемый API C ++ был на
C:\Foo\api
- Каждый файл .h (
bar.h
) начинался с #include "api/bar.h"
- Все использование неуправляемых классов было через
Api::Bar
В моем случае большая часть времени, потраченного на проект, была связана с автоматизацией создания управляемых файлов C ++.Я сделал пару вручную, понял, сколько времени потребуется, чтобы все сделать таким образом, и начал автоматизировать процесс.
Мои библиотеки все еще были отдельными.У меня был один неуправляемый dll и один управляемый dll.Я просто сохранил неуправляемый проект в управляемом.
Что касается автоматизации, он будет читать каждый неуправляемый файл .h и создавать мой управляемый файл .h следующим образом:
- Добавить мою
#include "api/bar.h"
строку. - Скопировать все
#include
строки. - Добавить мое управляемое пространство имен.
- Дублировать класс какуправляемый класс, включая базовый класс.
- Добавить защищенный указатель на неуправляемый класс.
- Добавить функцию
GetInner()
, чтобы получить указатель неуправляемого класса. - Добавитьфинализатор для удаления неуправляемого класса.
- Добавление нескольких функций, когда функция имеет параметры по умолчанию.
Затем создайте управляемые файлы .cpp, например:
- Заполнить большинство функций вызовами неуправляемых функций
- Использовать
GetInner()
каждый раз, когда класс включался в качестве параметров функции - Делать marshal_as для преобразования между строками и std :: wstrings
Это работало для большинства классов с небольшой ручной настройкой.Единственная область, где это не работало, была с коллекционными классами.Теперь я думаю, что мне повезло, так как каждый класс коллекции был просто оберткой вокруг std::vector
.Я основал все свои управляемые версии на CollectionBase
, с конструктором, принимающим класс неуправляемой коллекции, и методом со следующей сигнатурой:
void ToFoo(Api::Foo& v);
Таким образом, перейти из неуправляемой коллекции в управляемую коллекцию было просто gcnew
, а пойти другим путем было:
Foo* foo; //most likely a function parameter, already assigned.
Api::Foo apifoo; //name just "api" + the name of the managed Foo.
foo->ToFoo(apifoo);
Это тоже быловстроенный в генерацию классов .cpp для классов, не являющихся коллекциями.
Код для ToFoo
просто очищает неуправляемую коллекцию, выполняет итерацию по управляемой коллекции и добавляет каждый неуправляемый элемент с помощью GetInner()
.Мои коллекции были не такими большими, так что это работало на отлично.
Если бы мне пришлось снова делать классы коллекций, я бы, скорее всего, не стал бы основывать их на CollectionBase
сейчас.Я бы с большей вероятностью основал их на List<T>
или сделал бы нечто подобное тому, что обсуждалось в текущих ответах, опубликованных на ваш вопрос №2.Мой код был запущен с .Net 1.1 (без обобщений), поэтому в то время CollectionBase
имел для меня наибольшее значение.
Он был обработан вручную с помощью Regex.Поскольку библиотека была написана очень последовательно, я смог прочитать весь файл, использовать Regex для удаления комментариев и других вещей, которые могут вызвать проблемы (встроенные функции), а затем просто прочитать каждую строку и Regex, чтобы выяснить, что в ней было.У меня были такие вещи, как список всех коллекций (чтобы знать, когда делать вызовы коллекций выше), ненормальные классы (string / std :: wstring) и другие вещи, которые я не помню.Я собираюсь посмотреть, войдет ли он в наш новый источник контроля, так как проект был заброшен пару лет назад.