Как вызвать C++ / CLI из C#?
У меня есть класс, реализованный на C++, который отвечает за арифметические вычисления программы, и интерфейс с использованием WPF. Я обрабатываю входные данные с помощью C# , но тогда как я могу использовать свой класс C++?
Я видел некоторые комментарии о создании управляемого класса оболочки C++ для взаимодействия с ним, но я не знаю, с чего начать. И я не знаю, как бы я пошел, чтобы скомпилировать его вместе со всем другим кодом. Я не могу найти учебник по этому вопросу, и Google показывает на управляемом c++ на самом деле это не кажется полезным.
ничего там, чтобы помочь мне? Это не кажется мне неразумным.
EDIT пробовал m3rlinez решение, но это дает мне BadImageFormatException, я думаю, это потому, что DLL не генерируется. Я сделал все как сказал, Не знаю, что случилось. Есть идеи?
4 ответов:
вы взглянули на C++ / CLI?
приведу очень короткий пример. Вот исходный файл из проекта библиотеки классов Visual C++ - > CLR ->. Он в основном получает имя пользователя Windows и возвращает его.
обратите внимание, что для того, чтобы получить эту компиляцию, вы должны войти в настройки проекта и пометить "дополнительные зависимости" как "наследовать от родителя", потому что мы используем эти библиотеки Windows (kernel32.lib, user32.библиотека. ,.)
// CSCPP.h #pragma once #include "windows.h" using namespace System; namespace CSCPP { public ref class Class1 { // TODO: Add your methods for this class here. public: String^ GetText(){ WCHAR acUserName[100]; DWORD nUserName = sizeof(acUserName); if (GetUserName(acUserName, &nUserName)) { String^ name = gcnew String(acUserName); return String::Format("Hello {0} !", name); }else{ return gcnew String("Error!"); } } }; }Теперь создан новый Проект C# и добавьте ссылку на наш первый проект библиотеки классов C++/CLI. А затем вызовите метод экземпляра.
namespace CSTester { class Program { static void Main(string[] args) { CSCPP.Class1 instance = new CSCPP.Class1(); Console.WriteLine(instance.GetText()); } } }Это дало следующий результат на моей машине:
Привет m3rlinez !
C++ / CLI-это в основном управляемое расширение по стандарту C++. Он позволяет использовать классы CLR и типы данных в проекте C++/CLI, а также предоставлять их управляемому языку. Вы можете создать управляемую оболочку для своей старой библиотеки C++ с помощью этот. Есть некоторые странные синтаксисы, такие как
String^для определения типа ссылки на строку среды CLR. Я нахожу "быстрый C++ / CLI-узнайте C++ / CLI менее чем за 10 минут" чтобы быть полезным здесь.
есть по крайней мере три способа вызова неуправляемого кода из управляемого в том же процессе:
- C++ / CLI
- Платформа Invoke
- оберните ваш C++ в COM-объект
в работе мы используем C++/CLI для этого, кажется, работает.
Я бы создал стандартную (не COM/управляемую) динамическую библиотеку ссылок как описано здесь и затем использовать атрибут DllImport (вызов платформы) в коде c# для доступа к экспортируемым функциям.
ключевой момент из этой статьи:
обратите внимание на _ _ declspec(dllexport) модификатор в объявлениях методов в настоящий кодекс. Эти модификаторы позволяют метод, который будет экспортирован DLL так что он может быть использован другими приложения. За дополнительной информацией, см. dllexport, dllimport.
Это более легкая альтернатива реальной оболочке com-взаимодействия и позволяет избежать таких проблем, как регистрация и т. д. (DLL можно просто поместить в каталог приложений) .
Другой альтернативой является Работает (IJW). Это, вероятно, лучший выбор, если вы управляли кодом C++ и должны получить доступ к нему с других языков .NET. Но это только вариант, если вы однако вы можете / счастливы преобразовать свой неуправляемый C++ в управляемый C++.
Я бы держался подальше от P/Invoke, поскольку он довольно медленный по сравнению с IJW (он просто работает). Последний позволяет плавно переплетать управляемый и неуправляемый c++. Все, что вам нужно сделать, это создать управляемую сборку c++, написать управляемый класс, который виден из c# и вызвать из него неуправляемый код.
Хм... ЛАДНО. У меня сложилось впечатление, что вызовы P/Invoke были медленнее, чем они по своей сути. Однако, имея явный контроль над маршалингом, вы можете сделайте свою версию C++/CLI более эффективной во многих случаях.
вот статья Microsoft об обоих механизмах:
http://msdn.microsoft.com/en-us/library/ms235282.aspx
преимущества IJW
- нет необходимости писать объявления атрибутов DLLImport для неуправляемые API, используемые программой. Просто включите файл заголовка и ссылку с импорт библиотека.
- механизм IJW немного быстрее (например, заглушки IJW не работают нужно проверить для потребности приколоть или скопируйте элементы данных, потому что это сделано явно разработчиком).
- это ясно иллюстрирует проблемы с производительностью. В данном случае дело в том, что вам нужно перевести из Юникода строка в строку ANSI и что вы наличие сопутствующего выделения памяти и освобождение. В этом случае разработчиков писать код с использованием ijw понял бы, что вызов _putws и использование PtrToStringChars было бы лучше для выполнения.
- если вы вызываете много неуправляемых API, используя одни и те же данные, маршалинг его один раз и передача маршалированной копии гораздо эффективнее, чем повторный маршалинг каждый раз.
есть и эстетические преимущества:
- код C# выглядит как код C# без каких-либо странностей взаимодействия.
вы не должны определить
DLLImportатрибут, вам не нужно определять какие-либо структуры данных (также с конкретными атрибутами P/invoke), которые могут выглядеть следующим образом:[StructLayout(LayoutKind.Последовательный, CharSet = CharSet.кодировка ANSI)] версии devmode общественные структуры { [MarshalAs (UnmanagedType.ByValTStr, SizeConst = 32)] публичная строка dmDeviceName; }
- вам не нужно конвертировать все примитивные типы параметров в их аналоги .NET (есть таблица на этот страница это список того, как управляемые типы сопоставляются с неуправляемыми типами).
- вы можете работать с C++/CLI, который действительно интересно учиться и действительно полируется. Он прошел долгий путь с VS 2003 и теперь является полнофункциональным языком .NET. Документация Microsoft для этого довольно хороша, как и вся информация IJW.
- выполнение взаимодействия C++ в C++ / CLI кажется очень естественным, в отличие от C#. Это полностью субъективно, но я бы предпочел сделать сортировку строк в В C++, что делать
Marshal.PtrToString(ptr).- если вы выставляете API, вы, вероятно, захотите обернуть все вещи P/Invoke в другой слой, поэтому вам не нужно иметь дело с уродством P/Invoke. Таким образом, у вас есть накладные расходы на все маршалинг и слой C# вокруг него. С помощью C++/CLI маршалинг и абстракция взаимодействия находятся в одном месте, и вы можете выбрать, сколько вам нужно маршалинга.
IMHO если вы вызываете нечетную функцию в Windows SDK, перейдите с помощью P / Invoke. Если вы подвергают умеренно сложный C++ API управляемому миру, определенно C++ / CLI.
Comments