2009-12-01 2 views
11

저는 약간 녹슬었고 실제로 C++로 녹슬 었습니다. 대학 1 학년 때부터 만져 본적이 없으므로 오래되었습니다.C#과 C++ 사이에 다리를 형성하는 관리되는 C++

어쨌든, 나는 대부분의 사람들이하는 것과는 반대로하고 있습니다. C++에서 C# 코드 호출. 나는 온라인에서 몇 가지 연구를 해봤고 다리를 형성하기 위해 관리되는 C++을 만들어야 할 것처럼 보입니다. __declspec (dllexport)을 사용하고 그로부터 dll을 생성하고 전체를 래퍼로 사용하십시오.

하지만 내 문제는 - 실제로 예제를 찾는 데 어려움을 겪고 있습니다. 누군가가 C# 버전을 String.ToUpper()에 사용하려고하지만 기본적인 것은 아주 작은 코드 스 니펫 (snippet)이었습니다.

누구나 내가 뭔가 좀 더 구체적으로 볼 수있는 아이디어가 있습니까? COM을 사용하고 싶지는 않습니다. 목표는 C# 코드를 전혀 건드리지 않는 것입니다.

+0

관리되지 않는 C/C++에 노출하려는 인터페이스는 얼마나 복잡합니까? – CuppM

+0

비슷한 질문/답변은이 링크를 참조하십시오. http://stackoverflow.com/questions/13293888/how-to-call-ac-sharp-library-from-native-c-using-c-cli-and-ijw . – amalgamate

답변

11

, 나는 단지의 경우 어쨌든 게시거야 ...

자신의 라이브러리에 액세스 할 수있는 래퍼를 작성하는 과정을 표준 .Net 라이브러리 중 하나에 액세스하는 것과 동일합니다. CsharpProject라는 프로젝트

예 C# 클래스 코드 :

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); 
     } 
    } 
} 

당신은 관리되는 C++ 클래스 라이브러리 프로젝트를 만들고 (예 CsharpWrapper이다)과에 대한 참조로 C# 프로젝트를 추가합니다. 내부 사용과 참조 프로젝트에서 동일한 헤더 파일을 사용하려면 올바른 declspec을 사용하는 방법이 필요합니다. 이것은 사전 처리기 지시문 (이 경우에는 CSHARPWRAPPER_EXPORTS)을 정의하고 #ifdef을 사용하여 헤더 파일의 C/C++ 인터페이스에서 내보내기 매크로를 설정하여 수행 할 수 있습니다. 관리되지 않는 인터페이스 헤더 파일에는 관리되지 않는 항목이 포함되어야합니다 (또는 전 처리기로 필터링되어 제외되어야 함).

관리되지 않는 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); 

그런 다음 관리되는 라이브러리 파일에 포함 할 수 있도록 내부 헤더 파일을 만들 수 있습니다. 그러면 using namespace 문이 추가되고 필요한 도우미 함수를 포함 할 수 있습니다.

관리되는 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; 
} 

그런 다음 당신은 단지 포장을 수행하여 인터페이스 코드를 작성합니다.

관리되는 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()); 
} 

그런 다음 당신의 관리되지 않는 프로젝트 관리되지 않는 헤더, 링크 할 때 생성 된 lib 디렉토리 파일을 사용하도록 링커 얘기하고, 확인을 포함 .NET 및 래퍼 DLL은 관리되지 않는 응용 프로그램과 동일한 폴더에 있습니다.

#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

당신은 더 많은 것들을 설명했습니다. 나는 두 답을 모두 선택할 수 있었으면 좋겠습니다. 감사! –

+0

네이티브에서 매니페스트로 문자열을 마샬링해야하는 즉시 변환 함수가 필요하기 때문에 문자열을 사용하는 것이 좋습니다 (대부분의 interop에서는 일반적으로 꽤 빠릅니다). – Iain

+0

"No such file or directory"의 경우 중 하나 : 1) 관리되지 않는 응용 프로그램에'CppInterface.h'을 추가하십시오. 모든 프로젝트가 동일한 위치/저장소에 있으면이 작업을 수행하지 않습니다. 그런 다음 유지 관리 할 중복 파일이 있습니다. 2) 비 관리 응용 프로그램의 컴파일 포함 폴더 아래에있는 래퍼 프로젝트의 파일 경로를 추가합니다. Visual Studio의 경우 프로젝트를 마우스 오른쪽 단추로 클릭하고 "속성"을 선택하십시오. 그런 다음 "구성 등록 정보"-> "C/C++"-> "일반"-> "추가 포함 디렉토리"에서 경로를'CppInterface.h'의 위치에 추가하십시오. – CuppM

10

Visual Studio에서 새 C++/CLI 프로젝트를 만들고 C# dll에 대한 참조를 추가하십시오.

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

는 이제 C에 + +/CLI 프로젝트를 CLR은의 C++ 클래스를 추가 :

// 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; 
     } 
    }; 
} 

이 C에서 C 번호를 호출 ++ 우리는이 클래스와 DotNetLib.dll라는 C#을 DLL을 가정합니다.

이제 CLR C++ 클래스로 이야기 할 수 있습니다 C++/CLI 프로젝트에 네이티브 C++ 클래스를 추가 할 수 있습니다 필요한 경우 :

// Native.h 
#pragma once 

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

과 :

// 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); 
} 

당신은 할 수 있어야 다른 네이티브 C++ dll에서 정상적으로 Native 클래스를 호출하십시오.

Managed C++가 C++/CLI와 다르다는 점에 유의하십시오. 위키 백과 가장 잘 설명 : 영하는 예를 작성하는 날 이길 동안

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