2010-02-01 37 views
12

Tôi đã thử nhiều thứ khác nhau nhưng tôi phát điên với Interop.Vượt qua chuỗi C# thành C++ và vượt qua kết quả C++ (chuỗi, char * .. bất kỳ) thành C#

(ở đây chuỗi từ không được gọi là loại biến nhưng "bộ sưu tập char"): Tôi có hàm C++ không được quản lý, được định nghĩa trong dll, mà tôi đang cố truy cập từ C#, hàm này có tham số chuỗi và giá trị trả về chuỗi như sau:

string myFunction(string inputString) 
{ 
} 

Chuỗi nên ở bên C++ là gì? và C# một? và những thông số cần DllImport cho điều này?

Trả lời

17

Điều tôi đã tìm được để làm việc tốt nhất là phải rõ ràng hơn về những gì đang diễn ra ở đây. Có một chuỗi như kiểu trả về có lẽ không được khuyến khích trong tình huống này.

Cách tiếp cận chung là để mặt C++ được chuyển qua bộ đệm và kích thước bộ đệm. Nếu nó không đủ lớn cho những gì GetString đã đưa vào nó, biến bufferSize được sửa đổi để chỉ ra kích thước thích hợp sẽ là gì. Chương trình gọi (C#) sau đó sẽ tăng kích thước của bộ đệm lên kích thước phù hợp.

Nếu đây là chức năng dll xuất khẩu của bạn (C++):

extern "C" __declspec void GetString(char* buffer, int* bufferSize); 

Matching C# sẽ là như sau:

void GetString(StringBuilder buffer, ref int bufferSize); 

Vì vậy, để sử dụng điều này trong C# sau đó bạn sẽ làm điều gì đó như sau :

int bufferSize = 512; 
StringBuilder buffer = new StringBuilder(bufferSize); 
GetString(buffer, ref bufferSize); 
+1

Đây là phương pháp chính xác. Lưu ý rằng bạn không phải vượt qua kích thước bộ đệm bằng cách tham chiếu. C/C++ nên chấm dứt chuỗi, buffer.ToString() tạo ra giá trị trả về. –

+0

Cảm ơn tất cả các bạn đã trả lời. Tôi đọc ở đâu đó mà StringBuilder được sử dụng cho chuỗi đầu ra, nhưng tôi cũng cần phải chuyển đến hàm C++ một chuỗi đầu vào .. tôi nên sử dụng loại nào? Ở phía C++ tôi đã đặt chuỗi char * và C#, nhưng nó không hoạt động. Cuối cùng, tôi có thể xác định đầu ra "chuỗi" (bên C++) như là một const char *? Hoặc tôi phải có một char *? – Smjert

+0

@Smjert: Sử dụng const char * là một cách hay để đi nếu bạn không thay đổi nó. Điều này sẽ chỉ tốt cho một chuỗi ở phía C#. Bạn đang thấy loại vấn đề gì? –

2

Cách duy nhất để biết điều này là viết lớp trình bao bọc .NET C++ sử dụng Managed C++ Extensions và trong đối tượng .NET C++ gọi mã C++ gốc của bạn. Có các hàm trong các phần mở rộng được quản lý để chuyển đổi một System.String thành một char * hoặc bất kỳ loại chuỗi không được quản lý nào khác.

Về cơ bản bạn tạo một lớp .NET bằng cách sử dụng C++ và hiển thị nó từ một assembly, và nội bộ đến assembly đó bạn có thể gọi mã C++ gốc của bạn. Cách khác là thêm một hàm C thuần túy vào mã C++ của bạn bằng cách sử dụng P/Invoke và sau đó gọi mã C của bạn từ C# và có hàm C gọi mã C++ của bạn. Điều này sẽ làm việc, nhưng tôi có xu hướng cố gắng sử dụng mã được quản lý càng nhiều càng tốt.

2

Vấn đề lớn nhất khi truyền chuỗi từ C++ về C# là cấp phát bộ nhớ. GC sẽ có thể biết cách dọn dẹp bộ nhớ được phân bổ cho chuỗi này. Vì C# có hỗ trợ interp COm rộng rãi, nó không biết về COM BSTRs và cách phân bổ và deallocate chúng. Do đó, cách dễ nhất để thực hiện việc này là sử dụng BSTR ở mặt C + + và string ở mặt C#.

Lưu ý, việc sử dụng BSTR không hàm ý rằng hàm của bạn phải hiển thị thông qua COM.

2

Giá trị trả về "chuỗi" là vấn đề. P/Invoke marshaller sẽ gọi CoTaskMemFree() trên con trỏ bạn quay trở lại. Điều đó sẽ không hoạt động tốt trừ khi bạn sử dụng CoTaskMemAlloc() trong mã C/C++ của bạn để cấp phát bộ đệm chuỗi. Đó là một điều khá bất thường để làm.

Giải pháp tốt nhất là cho phép người gọi mã của bạn chuyển một con trỏ tới bộ đệm và độ dài bộ đệm cho bạn làm đối số. Bằng cách đó, tất cả sự phân bổ bộ nhớ xảy ra ở một bên. Scott cho bạn thấy làm thế nào để làm điều này.

1

tôi phải chuyển đổi một chuỗi unicode C# để một đại diện nhiều byte để chuyển đổi để char * trong C++ (đây là một phần giải pháp một chiều)

Tôi tìm thấy sau rất hữu ích

string st; 
IntPtr stPtr = Marshal.StringToHGlobalAnsi(st); 
// Do your thing in C++ 

Marshal.FreeHGlobal(stPtr); 

Điều này có thể không hiệu quả và không theo cách C#, tôi mới sử dụng C#, hy vọng điều này sẽ giúp

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