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#.

Author: Bill the Lizard, 2009-12-01

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());
}
 11
Author: CuppM,
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:

Http://en.wikipedia.org/wiki/C%2B%2B/CLI

 10
Author: Iain,
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