Как мне вызвать C ++ / CLI из C #?

У меня есть класс, реализованный на C ++, который отвечает за арифметические вычисления программы, и интерфейс, использующий WPF. Я обрабатываю ввод с помощью C #, но как тогда я могу использовать свой класс C ++?

Я видел некоторые комментарии о создании управляемого класса оболочки C ++ для взаимодействия с ним, но я не знаю, с чего начать. Я также не знаю, как бы я скомпилировал его вместе со всем остальным кодом. Я не могу найти учебник по этому поводу, и то, что Google показывает на управляемом C ++, на самом деле не кажется полезным.

Есть что-нибудь, что могло бы мне помочь? Мне это не кажется необоснованным.

РЕДАКТИРОВАТЬ Пробовал решение m3rLinEz, но оно дает мне исключение BadImageFormatException, я думаю, это потому, что DLL не сгенерирована. Все сделал как сказали, не знаю что случилось. Любые идеи?


person master chief    schedule 06.02.2010    source источник
comment
Здесь есть достойное руководство: codeproject.com/KB/mcpp/quickcppcli.aspx# A8   -  person Hans Passant    schedule 06.02.2010
comment
Я понимаю, что natice C ++ работает быстрее, чем C # / WPF, но каковы накладные расходы на написание оболочки CLI для вашего собственного C ++? Неужели вся эта работа того стоит? C ++ обернут в CLI быстрее, чем просто перенос кода на C ++?   -  person Steve H.    schedule 19.02.2010
comment
Я исправил свое исключение BadImageFormatException, потому что мой проект CLI по умолчанию компилировался в режиме x86, а мое приложение C # находилось в режиме любого процессора. Измените его, это может сработать для вас.   -  person Steve H.    schedule 19.02.2010


Ответы (4)


Вы смотрели C ++ / CLI?

Приведу очень короткий пример. Вот исходный файл из проекта Visual C ++ - ›CLR -› Class Library. Он в основном получает имя пользователя Windows и возвращает его.

Обратите внимание, что для того, чтобы это скомпилировать, вы должны войти в настройки проекта и пометить Дополнительные зависимости как Наследовать от родителя, потому что мы используем эти библиотеки Windows (kernel32.lib, user32.lib, ..)

// 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 String. Я нахожу Быстрый C ++ / CLI - Изучите C ++ / CLI менее чем за 10 минут, чтобы быть здесь полезным.

person Gant    schedule 06.02.2010
comment
Чтобы перейти к настройке дополнительных зависимостей, перейдите в Project - ›Properties -› Configuration Properties - ›Linker - person Kashif; 20.01.2015

Есть как минимум три способа вызвать неуправляемый код из управляемого в одном процессе:

  1. C ++ / CLI
  2. Вызов платформы
  3. Оберните свой C ++ в COM-объект

На работе для этого используем C ++ / CLI, вроде работает.

person Arve    schedule 06.02.2010
comment
А теперь есть CXXI ​​ (произносится сексуально). - person Justin; 12.02.2012
comment
А какой софт вы пишете на работе? Вы пишете высокопроизводительный код там, где важна скорость? - person Aran Mulholland; 04.02.2017
comment
Это старое (более 20 лет) приложение, написанное на C ++. Новый код написан на .NET, в котором использовался старый код на C и C ++. - person Arve; 11.05.2017

Я бы создал стандартную (не управляемую / управляемую) библиотеку динамических ссылок как , описанную здесь, а затем используйте атрибут DllImport (вызов платформы) в коде C # для доступа к экспортированным функциям.

Ключевой момент из этой статьи:

Обратите внимание на модификатор __declspec (dllexport) в объявлениях методов в этом коде. Эти модификаторы позволяют экспортировать метод библиотекой DLL, чтобы его могли использовать другие приложения. Для получения дополнительной информации см. Dllexport, dllimport.

Это более легкая альтернатива реальной оболочке COM-взаимодействия, позволяющая избежать таких проблем, как регистрация и т. Д. (DLL можно просто поместить в каталог приложения).

Другой альтернативой является It Just Works (IJW). Вероятно, это лучший выбор, если вы управляли кодом C ++ и вам нужно получить к нему доступ из других языков .NET. Но это вариант только в том случае, если вы можете / счастливы преобразовать свой неуправляемый C ++ в управляемый C ++.

person Ash    schedule 06.02.2010
comment
p / invoke - это термин, используемый для описания этого. - person ; 06.02.2010
comment
Я читал во многих статьях, что это медленно, поэтому я предлагаю использовать его с осторожностью. Я бы рекомендовал использовать C ++ \ CLI и смешанные сборки. - person MasterMastic; 19.10.2012

Я бы держался подальше от P / Invoke, поскольку он довольно медленный по сравнению с IJW (It Just Works). Последний позволяет легко переплетать управляемый и неуправляемый C ++. Все, что вам нужно сделать, это создать управляемую сборку C ++, написать управляемый класс, видимый из C #, и вызвать из него неуправляемый код.

Эээ ... Хорошо. У меня создалось впечатление, что вызовы P / Invoke были медленнее, чего не было изначально. Однако, обладая явным контролем над маршалингом, вы можете улучшить работу своей версии C ++ / CLI во многих случаях.

Вот статья Microsoft об обоих механизмах:

http://msdn.microsoft.com/en-us/library/ms235282.aspx

Преимущества IJW

  • Нет необходимости писать объявления атрибутов DLLImport для неуправляемых API-интерфейсов, используемых программой. Просто включите файл заголовка и свяжите его с библиотекой импорта.
  • Механизм IJW немного быстрее (например, заглушкам IJW не нужно проверять необходимость закрепления или копирования элементов данных, потому что это явно делается разработчиком).
  • Это ясно показывает проблемы с производительностью. В данном случае это тот факт, что вы переводите из строки Unicode в строку ANSI и что у вас есть сопутствующее выделение и освобождение памяти. В этом случае разработчик, пишущий код с использованием IJW, поймет, что вызов _putws и использование PtrToStringChars будет лучше для производительности.
  • Если вы вызываете множество неуправляемых API-интерфейсов с использованием одних и тех же данных, их однократный маршалинг и передача маршалированной копии намного эффективнее, чем повторный маршалинг каждый раз.

Есть и эстетические преимущества:

  • Код C # выглядит как код C # без каких-либо странностей взаимодействия.
  • Вам не нужно определять атрибут DLLImport, вам не нужно определять какие-либо структуры данных (также с определенными атрибутами p / invoke), которые могут выглядеть следующим образом:

    [StructLayout (LayoutKind.Sequential, 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.

person Igor Zevaka    schedule 06.02.2010
comment
За исключением того, что OP говорит о создании управляемой оболочки, которая, как я читал, говорит о том, что у них уже есть неуправляемый код. Я предполагаю, что перезапись на управляемом C ++ может быть вариантом. - person Ash; 06.02.2010
comment
Вы имеете в виду, что вызов P / Invoke сравнительно медленный, или это скорее препятствие для производительности, чем просто это? - person John K; 06.02.2010
comment
Согласно странице Mono на C ++, IJW выполняет вызовы ARE p / invoke. mono-project.com/CPlusPlus - person Matthew Olenik; 06.02.2010
comment
Microsoft, похоже, говорит то же самое о IJW & P / Invoke msdn .microsoft.com / en-us / library / aa712981 (VS.71) .aspx И IJW, и атрибут DLLImport PInvoke используют один и тот же базовый механизм. - person John K; 06.02.2010
comment
@John: Весь код на вашем компьютере использует один и тот же базовый механизм (процессор x86). Это не значит, что нет разницы в эффективности. - person Ben Voigt; 22.03.2013
comment