Zarządzał C++ tworząc pomost między c# i C++
Jestem trochę zardzewiały, właściwie naprawdę zardzewiały z moim C++. Nie tknąłem jej Od pierwszego roku studiów, więc minęło trochę czasu.
W każdym razie, robię odwrotność tego, co większość ludzi robi. Wywołanie kodu C# Z C++. Poszperałem trochę w Internecie i wydaje mi się, że muszę stworzyć jakiś zarządzany C++, aby utworzyć most. Użyj _ _ declspec (dllexport), a następnie utwórz z niego bibliotekę dll i użyj tego wszystkiego jako opakowania.
Ale mój problem polega na tym, że ciężko mi znaleźć przykłady. Znalazłem kilka podstawowych rzeczy, gdzie ktoś chciał użyć wersji C# Do String.ToUpper (), ale to było bardzo proste i było tylko małym fragmentem kodu.
Czy ktoś ma jakieś pomysły gdzie mogę szukać czegoś bardziej konkretnego? Uwaga, nie chcę korzystać z COM. Celem jest, aby w ogóle nie dotykać kodu C#.
2 answers
Podczas gdy lain uprzedził mnie do napisania przykładu, i tak go opublikuję na wszelki wypadek...
Proces pisania wrappera w celu uzyskania dostępu do własnej biblioteki jest taki sam jak dostęp do jednej ze standardowych bibliotek. NET.
Przykładowy kod klasy C# 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);
}
}
}
Możesz utworzyć zarządzany projekt biblioteki klas C++ (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 w referując projekt, potrzebujesz sposobu na użycie odpowiedniego declspec. Można to zrobić definiując dyrektywę preprocesora (CSHARPWRAPPER_EXPORTS
w tym przypadku) i używając #ifdef
do Ustawienia makra eksportu w interfejsie C/C++ w pliku nagłówkowym. Niezarządzany plik nagłówkowy interfejsu musi zawierać niezarządzane rzeczy (lub mieć je odfiltrowane 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żesz utworzyć wewnętrzny plik nagłówka, aby móc dołączyć do twojego zarządzane pliki biblioteczne. Spowoduje to dodanie instrukcji using namespace
i może zawierać potrzebne funkcje pomocnicze.
Zarządzany plik nagłówkowy interfejsu C++ (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;
}
Potem po prostu piszesz kod interfejsu, który robi zawijanie.
Zarządzany plik źródłowy interfejsu C++ (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());
}
Następnie po prostu dołącz nagłówek niezarządzany do niezarządzanego projektu, powiedz linkerowi, aby użył wygenerowanego .plik lib podczas łączenia, i upewnij się, że. Net i biblioteki DLL wrapper 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());
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-01 17:09:56
Utwórz nowy projekt C++ / CLI w visual studio i dodaj odniesienie do C# dll. Załóżmy, że mamy C # dll o nazwie DotNetLib.dll
z tą klasą w:
namespace DotNetLib
{
public class Calc
{
public int Add(int a, int b)
{
return a + b;
}
}
}
Teraz Dodaj klasę CLR C++ do swojego projektu C++/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 # z C++.
Teraz w razie potrzeby możesz dodać natywną klasę C++ do swojego projektu C++/CLI, która może rozmawiać z klasą CLR C++:
// Native.h
#pragma once
class Native
{
public:
Native(void);
int Add(int a, int b);
~Native(void);
};
I:
// 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);
}
Powinieneś być w stanie wywołać natywną klasę z innych natywnych bibliotek C++ jako normalnie.
Zauważ również, że Managed C++ różni się i został zastąpiony przez C++ / CLI. Wikipedia wyjaśnia to najlepiej:
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-01 17:05:20