2008-10-01 28 views
7

Tôi có một chức năng trong một DLL bản địa quy định như sau:Marshal C++ "chuỗi" class trong C# P/Gọi

#include <string> 
void SetPath(string path); 

Tôi cố gắng để đặt điều này trong Microsoft P/Invoke Interop Assistant, nhưng nó cuộn cảm trên lớp "chuỗi" (mà tôi nghĩ là từ MFC?).

Tôi đã thử marshaling nó như là một loạt các loại khác nhau (C# String, char [], byte []) nhưng mỗi lần tôi nhận được NotSupportedException hoặc Native Assembly Exception (tùy thuộc vào marshaling tôi đã thử).

Như bất kỳ ai đã từng thực hiện Native/Managed Interop trong đó lớp chuỗi gốc được sử dụng? Có cách nào để soái này không? Tôi sẽ phải viết Marshaler của riêng tôi?

+0

Câu hỏi hay; Tôi đã rất ngạc nhiên khi nó không hoạt động. http://msdn.microsoft.com/en-us/library/1b4az623.aspx –

+0

Tôi cũng ngạc nhiên ... không có lý do chính đáng nên không ... nhưng có vẻ như STL sẽ không làm việc với nó ... Ngoài ra ... Tôi sẽ chỉ thay đổi chức năng để sử dụng WCHAR, nhưng nó không phải là một DLL tôi có thể thay đổi. –

Trả lời

6

Có vẻ như bạn đang cố gắng sử dụng lớp chuỗi thư viện chuẩn C++. Tôi nghi ngờ rằng sẽ dễ dàng đối với Marshal. Tốt hơn để gắn bó với một char * và Marshal là StringBuilder. Đó là những gì tôi thường làm. Bạn sẽ phải thêm một trình bao bọc để tạo chuỗi C++ cho bạn.

+0

Tôi sợ rằng ... con số –

2

Trợ lý tương tác PInvoke chỉ hỗ trợ C not C++. Thật không may là lớp MFC String (CString tôi tin?) Là C++ và sẽ không hoạt động thông qua trợ lý. Thay vào đó, hãy thử sử dụng sau đây

void SetPath(__in const WCHAR* path); 
0

Có. Bạn có thể. Trên thực tế, không chỉ std::string, std::wstring, bất kỳ lớp C++ chuẩn nào hoặc các lớp của riêng bạn có thể được sắp xếp hoặc khởi tạo và được gọi từ C# /. NET. Ý tưởng cơ bản của việc khởi tạo một đối tượng C++ từ .NET world là phân bổ kích thước chính xác của đối tượng C++ từ .NET, sau đó gọi hàm tạo được xuất từ ​​DLL C++ để khởi tạo đối tượng, sau đó bạn sẽ có thể để gọi bất kỳ hàm nào để truy cập đối tượng C++ đó, ​​nếu bất kỳ phương thức nào liên quan đến các lớp C++ khác, bạn sẽ cần bọc chúng trong lớp C#, với các kiểu có kiểu nguyên thủy, bạn có thể đơn giản là P/Gọi chúng. Nếu bạn chỉ có một vài phương pháp để gọi, nó sẽ đơn giản, mã hóa thủ công sẽ không mất nhiều thời gian. Khi bạn hoàn thành với đối tượng C++, bạn gọi phương thức destructor của đối tượng C++, cũng là một hàm xuất khẩu. nếu nó không có, thì bạn chỉ cần giải phóng bộ nhớ của bạn từ .NET.

Đây là một ví dụ.

public class SampleClass : IDisposable 
{  
    [DllImport("YourDll.dll", EntryPoint="ConstructorOfYourClass", CharSet=CharSet.Ansi,   CallingConvention=CallingConvention.ThisCall)] 
    public extern static void SampleClassConstructor(IntPtr thisObject); 

    [DllImport("YourDll.dll", EntryPoint="DoSomething", CharSet=CharSet.Ansi,  CallingConvention=CallingConvention.ThisCall)] 
    public extern static void DoSomething(IntPtr thisObject); 

    [DllImport("YourDll.dll", EntryPoint="DoSomethingElse", CharSet=CharSet.Ansi,  CallingConvention=CallingConvention.ThisCall)] 
    public extern static void DoSomething(IntPtr thisObject, int x); 

    IntPtr ptr; 

    public SampleClass(int sizeOfYourCppClass) 
    { 
     this.ptr = Marshal.AllocHGlobal(sizeOfYourCppClass); 
     SampleClassConstructor(this.ptr); 
    } 

    public void DoSomething() 
    { 
     DoSomething(this.ptr); 
    } 

    public void DoSomethingElse(int x) 
    { 
     DoSomethingElse(this.ptr, x); 
    } 

    public void Dispose() 
    { 
     Marshal.FreeHGlobal(this.ptr); 
    } 
} 

Đối với các chi tiết, vui lòng xem link dưới đây,

C#/.NET PInvoke Interop SDK

(Tôi là tác giả của công cụ SDK)

Một khi bạn có C# wrapper class cho C++ lớp đã sẵn sàng, rất dễ thực hiện ICustomMarshaler để bạn có thể so sánh đối tượng C++ từ .NET.

http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.icustommarshaler.aspx