2009-12-01 13 views
11

Jestem trochę zardzewiały, naprawdę bardzo zardzewiały z moim C++. Nie tknęłam tego od czasu pierwszego roku studiów, więc minęło trochę czasu.Zarządzane C++ tworząc most między C# i C++

W każdym razie robię odwrotność tego, co robi większość ludzi. Wywołanie kodu C# z C++. Zrobiłem kilka badań online i wydaje mi się, że muszę stworzyć trochę zarządzanego C++, aby utworzyć most. Użyj __declspec (dllexport), a następnie utwórz z niego bibliotekę DLL i użyj jej jako opakowania.

Ale mój problem polega na tym, że trudno mi znaleźć przykłady. Znalazłem podstawowe rzeczy, w których ktoś chciał użyć wersji C# do String.ToUpper(), ale to było BARDZO podstawowe i było tylko małym fragmentem kodu.

Ktoś ma pomysły na to, gdzie mogę szukać czegoś bardziej konkretnego? Uwaga, NIE chcę używać COM. Celem jest, aby w ogóle nie dotykać kodu C#.

+0

Jak skomplikowany jest interfejs, który chcesz eksponować na niezarządzanego C/C++? – CuppM

+0

Zobacz ten link dla podobnego pytania/odpowiedzi: http://stackoverflow.com/questions/13293888/how-to-call-ac-sharp-library-from-native-c-using-c-cli-and-ijw . – amalgamate

Odpowiedz

11

Podczas lain pokonać mnie do pisania przykład, wyślę go zresztą na wszelki wypadek ...

trakcie pisania otoki dostępu do własnej biblioteki jest taki sam jak dostęp do jednej ze standardowych bibliotek .Net.

Przykład kodu C# klasa w projekcie o nazwie CsharpProject:

using System; 

namespace CsharpProject { 
    public class CsharpClass { 
     public string Name { get; set; } 
     public int Value { get; set; } 

     public string GetDisplayString() { 
      return string.Format("{0}: {1}", this.Name, this.Value); 
     } 
    } 
} 

by utworzyć Managed C++ projektu biblioteki klasy (przykładem jest CsharpWrapper) i dodać swój projekt C# jako odniesienie do niego. Aby użyć tego samego pliku nagłówkowego do użytku wewnętrznego i projektu referencyjnego, potrzebny jest sposób użycia odpowiedniego declspec. Można to zrobić, definiując w tym przypadku dyrektywę preprocesora (CSHARPWRAPPER_EXPORTS) i używając #ifdef, aby ustawić makro eksportu w interfejsie C/C++ w pliku nagłówkowym. Plik nagłówka niezarządzanego interfejsu musi zawierać niezarządzane pliki (lub je odfiltrować przez preprocesor).

Niezarządzany plik nagłówkowy interfejsu C++ (CppInterface.h):

#pragma once 

#include <string> 

// Sets the interface function's decoration as export or import 
#ifdef CSHARPWRAPPER_EXPORTS 
#define EXPORT_SPEC __declspec(dllexport) 
#else 
#define EXPORT_SPEC __declspec(dllimport) 
#endif 

// Unmanaged interface functions must use all unmanaged types 
EXPORT_SPEC std::string GetDisplayString(const char * pName, int iValue); 

Następnie można utworzyć wewnętrzny plik nagłówkowy, aby można go było umieścić w zarządzanych plikach biblioteki. Spowoduje to dodanie instrukcji using namespace i może zawierać potrzebne funkcje pomocnicze.

Managed C++ Interfejs plik nagłówka (CsharpInterface.h):

#pragma once 

#include <string> 

// .Net System Namespaces 
using namespace System; 
using namespace System::Runtime::InteropServices; 

// C# Projects 
using namespace CsharpProject; 


////////////////////////////////////////////////// 
// String Conversion Functions 

inline 
String^ToManagedString(const char * pString) { 
return Marshal::PtrToStringAnsi(IntPtr((char *) pString)); 
} 

inline 
const std::string ToStdString(String^strString) { 
IntPtr ptrString = IntPtr::Zero; 
std::string strStdString; 
try { 
    ptrString = Marshal::StringToHGlobalAnsi(strString); 
    strStdString = (char *) ptrString.ToPointer(); 
} 
finally { 
    if (ptrString != IntPtr::Zero) { 
    Marshal::FreeHGlobal(ptrString); 
    } 
} 
return strStdString; 
} 

Następnie wystarczy napisać kod interfejsu, który nie opakowanie.

Managed C++ Interfejs plik źródłowy (CppInterface.cpp):

#include "CppInterface.h" 
#include "CsharpInterface.h" 

std::string GetDisplayString(const char * pName, int iValue) { 
CsharpClass^oCsharpObject = gcnew CsharpClass(); 

oCsharpObject->Name = ToManagedString(pName); 
oCsharpObject->Value = iValue; 

return ToStdString(oCsharpObject->GetDisplayString()); 
} 

Wtedy właśnie obejmują niezarządzanej nagłówek w swojej niekontrolowana projektu, powiedz łącznik korzystania z wygenerowanego pliku .lib podczas łączenia, i upewnij się, Pliki .Net i opakowujące biblioteki DLL znajdują się w tym samym folderze, co niezarządzana aplikacja.

#include <stdlib.h> 

// Include the wrapper header 
#include "CppInterface.h" 

void main() { 
// Call the unmanaged wrapper function 
std::string strDisplayString = GetDisplayString("Test", 123); 

// Do something with it 
printf("%s\n", strDisplayString.c_str()); 
} 
+0

Wyjaśniłeś trochę więcej rzeczy - żałuję, że nie mogłem wybrać obu odpowiedzi. Dzięki! –

+0

Struny są dobrym przykładem, ponieważ funkcje konwersji są wymagane, gdy tylko potrzebujesz przekazać ciąg od natywnego do zarządzanego (co normalnie jest całkiem niedługo w większości współdziałania!). – Iain

+0

Dla "Brak takiego pliku lub katalogu", musisz albo: 1) Dodaj 'CppInterface.h' do niezarządzanej aplikacji. Nie zrobiłbym tego, jeśli wszystkie projekty żyją w tej samej lokalizacji/repozytorium. Ponieważ masz wtedy zduplikowane pliki do utrzymania. 2) Dodaj ścieżkę do plików projektu opakowania w folderze dołączania kompilacji niezarządzanej aplikacji. W Visual Studio, kliknij prawym przyciskiem myszy na projekcie i wybierz "Właściwości". Następnie w "Właściwości konfiguracji" -> "C/C++" -> "Ogólne" -> "Dodatkowe katalogi" dodaj ścieżkę do lokalizacji 'CppInterface.h'. – CuppM

10

Utwórz nowy projekt C++/CLI w visual studio i dodaj odwołanie do biblioteki C#. Załóżmy, że mamy C# dll o nazwie DotNetLib.dll z tej klasy w:

namespace DotNetLib 
{ 
    public class Calc 
    { 
     public int Add(int a, int b) 
     { 
      return a + b; 
     } 
    } 
} 

teraz dodać CLR klasy C++ do C projekt ++/CLI:

// TestCPlusPlus.h 

#pragma once 

using namespace System; 
using namespace DotNetLib; 

namespace TestCPlusPlus { 

    public ref class ManagedCPlusPlus 
    { 
    public: 
     int Add(int a, int b) 
     { 
      Calc^ c = gcnew Calc(); 
      int result = c->Add(a, b); 
      return result; 
     } 
    }; 
} 

Wywoła C# od C++.

Teraz w razie potrzeby można dodać natywnej klasy C++ do C projektu ++/CLI, który może rozmawiać z CLR C++ Klasa:

// Native.h 
#pragma once 

class Native 
{ 
public: 
    Native(void); 
    int Add(int a, int b); 
    ~Native(void); 
}; 

oraz:

// Native.cpp 
#include "StdAfx.h" 
#include "Native.h" 
#include "TestCPlusPlus.h" 

Native::Native(void) 
{ 
} 

Native::~Native(void) 
{ 
} 

int Native::Add(int a, int b) 
{ 
    TestCPlusPlus::ManagedCPlusPlus^ c = gcnew TestCPlusPlus::ManagedCPlusPlus(); 
    return c->Add(a, b); 
} 

powinien być w stanie wywołaj klasę Native z innych natywnych bibliotek dll C++, jak zwykle.

Należy również zauważyć, że zarządzany język C++ jest inny i został zastąpiony przez C++/CLI. Wikipedia wyjaśnia to najlepiej: