2011-01-19 6 views
11

C#을 응용 프로그램에서 사용하기위한 C++ 클래스를 DllExport에 의해 설명 된 바와 같이 다음 코드를 사용하여 수출 DLL하려고합니까 : http://msdn.microsoft.com/en-us/library/a90k134d(v=vs.80).aspx은 내가 클래스 "myCppClass"를 포함하는 C++ DLL 프로젝트를 만든

class __declspec(dllexport) CExampleExport : //public CObject 
{ ... class definition ... }; 

afx.h가 필요하므로 "공용 CObject"가 생략되어 MFC DLL이라는 것을 의미합니다. 이것이 좋은 것인지 아닌지는 모르겠지만 DLL 프로젝트의 기본 설정과 다릅니다.

나는 위의 링크 된 문서에서 모든 "공용 함수 및 멤버 변수"를 가져올 수 있다고 믿게되었습니다. 어떻게하면 C#에서이 작업을 수행 할 수 있습니까? 클래스를 인스턴스화 할 수 있습니까?

편집 : 게시물의 제목이 오도 할 수 있음을 깨달았습니다. C#에서 가져온 Dll 가져 오기와 C++에서 설명서를 제대로 따르는 지 확인해야합니다.

+1

DLL COM을 볼 수있게해야합니다. 나는 더 긴 설명을 할 시간이 없기 때문에 이것을 코멘트로 올린다. –

답변

13

C#은 실제로 이름이 변경된 C 인터페이스 인 C++ 클래스를 직접 가져올 수 없습니다.

옵션을 사용하여 COM을 통해 클래스를 노출하고 C++/CLI를 사용하여 관리되는 래퍼를 만들거나 C 스타일 인터페이스를 노출합니다. 가장 쉬운 유형 안전을 제공 할 것이므로 관리되는 래퍼를 권하고 싶습니다.

같은 것을 보일 것이다

C 스타일 인터페이스 (경고 : 테스트되지 않은 코드) :

extern "C" __declspec(dllexport) 
void* CExampleExport_New(int param1, double param2) 
{ 
    return new CExampleExport(param1, param2); 
} 

extern "C" __declspec(dllexport) 
int CExampleExport_ReadValue(void* this, int param) 
{ 
    return ((CExampleExport*)this)->ReadValue(param) 
} 

C++/CLI 스타일의 래퍼과 같을 것이다 (경고 : 테스트되지 않은 코드) :

ref class ExampleExport 
{ 
private: 
    CExampleExport* impl; 
public: 
    ExampleExport(int param1, double param2) 
    { 
     impl = new CExampleExport(param1, param2); 
    } 

    int ReadValue(int param) 
    { 
     return impl->ReadValue(param); 
    } 

    ~ExampleExport() 
    { 
     delete impl; 
    } 
}; 
+0

'void *'에서'dynamic_cast'를 할 수 없습니다. 실제 포인터 타입을 사용할 수도 있지만, C#은 p/invoke 시그니처에서'IntPtr'를 사용할 것입니다. –

+0

@Ben 네가 맞아. 나는 교정 할 때'(T *)'형에서 그것을 바꿨다 ... 지금 되돌아왔다. 실제 포인터 유형을 사용할 수도 있지만이 방법에서는 안전성이 부족하다는 점을 강조하고 싶습니다. – Zooba

+0

C++ 템플릿 스타일의 캐스트를 선호한다면'static_cast'가 사용됩니다. –

4

C#에서 pinvoke를 통해 C++ 클래스 인스턴스를 만들 수 없습니다. 이것은 성가신 구현 세부 사항입니다. C++ 컴파일러는 얼마나 많은 메모리를 할당해야하는지, 그리고 생성자와 소멸자를 올바르게 호출하는시기와 방법을 알고 있습니다. 물체의 크기는 크랙하기가 가장 힘들며 신뢰할 수있는 방법은 없습니다.

C++ 클래스를 정적 ​​메서드로 전개 할 수없는 경우 관리되는 래퍼를 작성해야합니다. 그것은 C++/CLI 언어로 끝났습니다. 관리되지 않는 클래스 객체를 포인터로 저장하고 생성자에서 만들고 소멸자 및 종료 자에서 삭제 한 "참조 클래스"를 작성합니다.

9

내가 아는 한, C#은 COM 인터페이스에서만 상호 작용할 수 있습니다. 운좋게도 레지스트리가있는 완전한 COM 객체 일 필요는 없으며 IUnknown을 구현하는 일반 C++ 클래스가 될 수 있습니다.

#include <Windows.h> 

// Generate with from VisualStudio Tools/Create Guid menu 
static const GUID IID_MyInterface = 
{ 0xefbf7d84, 0x3efe, 0x41e0, { 0x95, 0x2e, 0x68, 0xa4, 0x4a, 0x3e, 0x72, 0xca } }; 

struct MyInterface: public IUnknown 
{ 
    // add your own functions here 
    // they should be virtual and __stdcall 
    STDMETHOD_(double, GetValue)() = 0; 
    STDMETHOD(ThrowError)() = 0; 
}; 

class MyClass: public MyInterface 
{ 
    volatile long refcount_; 

public: 
    MyClass(): refcount_(1) { } 

    STDMETHODIMP QueryInterface(REFIID guid, void **pObj) { 
     if(pObj == NULL) { 
      return E_POINTER; 
     } else if(guid == IID_IUnknown) { 
      *pObj = this; 
      AddRef(); 
      return S_OK; 
     } else if(guid == IID_MyInterface) { 
      *pObj = this; 
      AddRef(); 
      return S_OK; 
     } else { 
      // always set [out] parameter 
      *pObj = NULL; 
      return E_NOINTERFACE; 
     } 
    } 

    STDMETHODIMP_(ULONG) AddRef() { 
     return InterlockedIncrement(&refcount_); 
    } 

    STDMETHODIMP_(ULONG) Release() { 
     ULONG result = InterlockedDecrement(&refcount_); 
     if(result == 0) delete this; 
     return result; 
    } 

    STDMETHODIMP_(DOUBLE) GetValue() { 
     return 42.0; 
    } 

    STDMETHODIMP ThrowError() { 
     return E_FAIL; 
    } 
}; 

extern "C" __declspec(dllexport) LPUNKNOWN WINAPI CreateInstance() 
{ 
    return new MyClass(); 
} 

을 그리고 C#을에 당신은 다음과 같이 수행하십시오 :

그래서 C++에서 같은 것을 할

[ComImport] 
[Guid("EFBF7D84-3EFE-41E0-952E-68A44A3E72CA")] 
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
interface MyInterface 
{ 
    [PreserveSig] double GetValue(); 
    void ThrowError(); 
} 

class Program 
{ 
    [DllImport("mylib.dll")] 
    static extern MyInterface CreateInstance(); 

    static void Main(string[] args) 
    { 
     MyInterface iface = CreateInstance(); 
     Console.WriteLine(iface.GetValue()); 
     try { iface.ThrowError(); } 
     catch(Exception ex) { Console.WriteLine(ex); } 
     Console.ReadKey(true); 
    } 
} 

당신은만큼,이 방법을 원하는 거의 아무것도 할 수 C++과 C# 사이의 통신은 가상 인터페이스를 통과합니다.

0

C# 및 C++은 C++ 및 Delphi와 마찬가지로 ABI와 호환되지 않으므로 가상 클래스 멤버 (메서드)를 내보낼 수 없으며 C#에서 vtbl의 C++ 객체를 처리 할 수 ​​없으므로 가상 클래스 멤버를 호출 측에서 가상으로 선언 할 수 없습니다. COM에서 C++ 클래스를 래핑하는 것이 좋습니다. 다른 COM 호환 언어에서도 클래스를 사용할 수있는 또 다른 긍정적 인 효과가 있습니다.

관련 문제