2009-04-28 7 views
9

Trong một hàm trong C++ DLL của tôi, tôi trả về một chuỗi std :: thành ứng dụng C# của tôi. Nó khá nhiều trông như thế này:Trả về một chuỗi std :: từ một DLL C++ thành một chương trình C# -> Địa chỉ không hợp lệ được chỉ định cho RtlFreeHeap

std::string g_DllName = "MyDLL"; 

extern "C" THUNDER_API const char* __stdcall GetDLLName() 
{ 
    return g_DllName.c_str(); 
} 

Nhưng khi C# mã của tôi gọi chức năng này, tôi nhận được tin nhắn này trong cửa sổ đầu ra của tôi:

Invalid Address specified to RtlFreeHeap(00150000, 0012D8D8) 

Các khai báo hàm trong C# trông như thế này:

[DllImport("MyDll", EntryPoint = "GetDLLName")] 
    [return: MarshalAs(UnmanagedType.LPStr)] 
    public static extern string GetDLLName(); 

Từ những gì tôi có thể tìm thấy trực tuyến, đôi khi thông báo này xuất hiện khi có sự không thống nhất giữa phiên bản mới (gỡ lỗi hoặc phát hành, v.v.) đang được sử dụng với xóa. Nhưng tôi không chắc đó có phải là những gì đang xảy ra trong trường hợp của tôi hay không. Vì vậy, tôi không chắc chắn chính xác những gì gây ra nó. Có lẽ MashallAs có thể liên quan gì đến nó?

Bất kỳ ý tưởng nào?

Cảm ơn!

+0

bạn có thể kiểm tra những gì bạn tìm thấy ví dụ a) nếu bạn đang sử dụng debug đúng) thư viện (ví debug xây dựng vv và b) Vấn đề này xảy ra ở cả hai gỡ lỗi và phát hành bản xây dựng và c) thử sử dụng/clr: pure thay vì/clr cho C++ dll của bạn. – dirkgently

Trả lời

12

Tôi đã cố gắng tìm ra sự cố. Đó là cách định nghĩa C# đã được thực hiện. Từ những gì tôi có thể hiểu, bằng cách sử dụng các MarshallAs (UnmanagedType.LPStr) kết hợp với kiểu trả về chuỗi làm cho nó để nó sẽ cố gắng giải phóng chuỗi khi nó được thực hiện. Nhưng vì chuỗi xuất phát từ DLL C++, và rất có thể là một trình quản lý bộ nhớ hoàn toàn khác, nó không thành công. Và ngay cả khi nó không thất bại, tôi cũng không muốn nó được giải phóng.

Giải pháp tôi thấy được thay đổi tuyên bố C# để này (C++ là không thay đổi):

[DllImport("MyDll", EntryPoint = "GetDLLName")] 
public static extern IntPtr GetDLLName(); 

Vì vậy, điều này làm cho nó để nó chỉ trả về một con trỏ đến dữ liệu chuỗi. Và sau đó để thay đổi nó thành một chuỗi, hãy chuyển nó đến Marshal.PtrToStringAnsi()

return Marshal.PtrToStringAnsi(GetDLLName()); 

Và được đưa vào một chức năng khác để làm sạch.

Tôi tìm thấy giải pháp từ trang này: http://discuss.fogcreek.com/dotnetquestions/default.asp?cmd=show&ixPost=1108