2009-12-01 33 views
11

Tôi hơi bị gỉ, thực sự thực sự bị gỉ với C++ của tôi. Đã không chạm vào nó từ năm thứ nhất của trường đại học nên đã lâu rồi.Được quản lý C++ để tạo thành cầu nối giữa C# và C++

Dù sao, tôi đang làm ngược lại những gì hầu hết mọi người làm. Gọi mã C# từ C++. Tôi đã thực hiện một số nghiên cứu trực tuyến và có vẻ như tôi cần tạo một số C++ được quản lý để tạo thành một cây cầu. Sử dụng __declspec (dllexport) và sau đó tạo một dll từ đó và sử dụng toàn bộ điều như một wrapper.

Nhưng vấn đề của tôi là - Tôi thực sự gặp khó khăn trong việc tìm kiếm các ví dụ. Tôi tìm thấy một số công cụ cơ bản mà ai đó muốn sử dụng phiên bản C# để String.ToUpper() nhưng đó là VERY cơ bản và chỉ là một đoạn mã nhỏ.

Bất kỳ ai có ý tưởng về nơi tôi có thể tìm kiếm thứ gì đó cụ thể hơn một chút? Lưu ý, tôi KHÔNG muốn sử dụng COM. Mục tiêu là không chạm vào mã C#.

+0

Giao diện bạn muốn hiển thị với C/C++ không được quản lý phức tạp đến mức nào? – CuppM

+0

Xem liên kết này để có câu hỏi/câu trả lời tương tự: http://stackoverflow.com/questions/13293888/how-to-call-ac-sharp-library-from-native-c-using-c-cli-and-ijw . – amalgamate

Trả lời

11

Trong khi lain đánh tôi để viết một ví dụ, tôi sẽ đăng nó dù sao đi nữa chỉ trong trường hợp ...

Quá trình viết một wrapper để truy cập thư viện riêng của bạn giống như truy cập một trong các thư viện chuẩn .Net.

Ví dụ C# mã lớp trong một dự án có tên 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); 
     } 
    } 
} 

Bạn sẽ tạo ra một thư viện C++ Dự án lớp quản lý (ví dụ là CsharpWrapper) và thêm dự án # C của bạn như là một tham chiếu đến nó. Để sử dụng cùng một tệp tiêu đề để sử dụng nội bộ và trong dự án tham chiếu, bạn cần một cách để sử dụng đúng declspec. Điều này có thể được thực hiện bằng cách xác định một chỉ thị tiền xử lý (CSHARPWRAPPER_EXPORTS trong trường hợp này) và sử dụng một #ifdef để thiết lập macro xuất khẩu trong giao diện C/C++ của bạn trong một tệp tiêu đề. Tệp tiêu đề giao diện không được quản lý phải chứa nội dung không được quản lý (hoặc đã được bộ lọc tiền lọc lọc ra).

Tệp tiêu đề giao diện C++ không được quản lý (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); 

Sau đó, bạn có thể tạo tệp tiêu đề nội bộ để có thể đưa vào tệp thư viện được quản lý của mình. Điều này sẽ thêm các câu lệnh using namespace và có thể bao gồm các hàm trợ giúp mà bạn cần.

Managed C++ tập tin giao diện Header (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; 
} 

Sau đó, bạn chỉ cần viết mã giao diện của bạn mà không được gói.

Managed tập C++ Interface Nguồn (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()); 
} 

Sau đó chỉ cần bao gồm tiêu đề không được quản lý trong dự án không được quản lý của bạn, hãy cho mối liên kết để sử dụng file .lib tạo ra khi liên kết, và chắc chắn rằng .Net và các wrapper DLL nằm trong cùng thư mục với ứng dụng không được quản lý của bạn.

#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

Bạn đã giải thích nhiều hơn một chút - ước gì tôi có thể chọn cả hai câu trả lời. Cảm ơn! –

+0

Chuỗi là một ví dụ tốt vì chức năng chuyển đổi được yêu cầu ngay sau khi bạn cần marshall một chuỗi từ gốc để quản lý (thường là khá sớm trong hầu hết interop!) – Iain

+0

Đối với "Không có tập tin hoặc thư mục", bạn cần phải hoặc: 1) Thêm 'CppInterface.h' vào ứng dụng không được quản lý. Tôi sẽ không làm điều này nếu tất cả các dự án sống trong cùng một vị trí/kho lưu trữ. Khi bạn có các tệp trùng lặp để duy trì. 2) Thêm đường dẫn đến tệp của dự án trình bao bọc trong thư mục biên dịch của ứng dụng không được quản lý bao gồm thư mục. Đối với Visual Studio, nhấp chuột phải vào dự án và chọn "Properties". Sau đó, trong "Configuration Properties" -> "C/C++" -> "General" -> "Additional Include Directories" thêm đường dẫn đến vị trí của 'CppInterface.h'. – CuppM

10

Tạo dự án C++/CLI mới trong studio trực quan và thêm tham chiếu vào tệp C# dll của bạn. Giả sử chúng ta có một C# dll gọi DotNetLib.dll với lớp này trong:

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

Bây giờ thêm một ++ lớp CLR C đến C dự án ++/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; 
     } 
    }; 
} 

này sẽ gọi C# từ C++.

Bây giờ nếu cần thiết bạn có thể thêm một lớp C++ có nguồn gốc từ C dự án ++/CLI của bạn mà có thể nói chuyện với cáC++ lớp CLR C:

// Native.h 
#pragma once 

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

và:

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

Bạn sẽ có thể gọi lớp Native từ bất kỳ dll gốc C++ nào khác như bình thường.

Cũng lưu ý rằng Managed C++ là khác nhau và đã bị vượt quá bởi C++/CLI. Wikipedia giải thích nó tốt nhất:

Các vấn đề liên quan