Answered by:
Returning arrays from c++ dll with extern "C" to c#

Question
-
Hello!
I was wondering how on earth you can return an array (or string if possible) from a c++ DLL. This is going to be used with extern "C", so strings don't work it seems.
Here is the code:
1 extern "C" { 2 char* __declspec(dllexport) _fsgf_return_validity(wstring path) { 3 ifstream file; 4 char* validity=new char[4]; 5 file.open(path.c_str(), ios::in|ios::binary); 6 file.read(validity, 4); 7 file.close(); 8 return validity; 9 } 10 }
Many thanks!
(Edit: It seems that it doesn't like underscores. They appear within the function name and before declspec. Cheers!)
DarkzaelusMonday, December 22, 2008 9:01 PM
Answers
-
No, both signatures are wrong.
C++:extern "C" { void __declspec(dllexport) _fsgf_return_validity(const wchar_t* path, char* validity); }
C#:[DllImport("Core.dll")] private static extern void _fsgf_return_validity([MarshalAs(UnmanagedType.LPWStr)] string path, [MarshalAs(UnmanagedType.LPStr)] StringBuilder validity);
To call the function in C#, you'll need to create a StringBuilder with a capacity of at least 5 (to allow for null termination). To make this less error prone, you should wrap the above function with something like:private static string FsgfReturnValidity(string path) { StringBuilder validity = new StringBuilder(5); _fsgf_return_validity(path, validity); return validity.ToString(); }
Monday, December 22, 2008 9:46 PM
All replies
-
First, note that the function cannot take a wstring parameter; that should be const wchar_t* instead.
Second, you can return a char* or a const char* and C# can see it as either a System.String or as a System.Byte[], but with the way you have it coded now you're going to leak memory (who deletes the char* you created?). What you should do instead is have the function take a char* parameter to use as a buffer, so the function does no heap allocation -- the caller must take care of allocating and deallocating the buffer.
Monday, December 22, 2008 9:20 PM -
So if I use this c++ code:
1 void __declspec(dllexport) _fsgf_return_validity(wchar_t* path, char* &validity) { 2 ifstream file; 3 file.open(path, ios::in|ios::binary); 4 file.read(validity, 4); 5 file.close(); 6 }
with this linker:
[DllImport("Core.dll")] private static extern string _fsgf_return_validity(string path, string *buffer);
It should work?
Thanks for your patience,
DarkzaelusMonday, December 22, 2008 9:30 PM -
No, both signatures are wrong.
C++:extern "C" { void __declspec(dllexport) _fsgf_return_validity(const wchar_t* path, char* validity); }
C#:[DllImport("Core.dll")] private static extern void _fsgf_return_validity([MarshalAs(UnmanagedType.LPWStr)] string path, [MarshalAs(UnmanagedType.LPStr)] StringBuilder validity);
To call the function in C#, you'll need to create a StringBuilder with a capacity of at least 5 (to allow for null termination). To make this less error prone, you should wrap the above function with something like:private static string FsgfReturnValidity(string path) { StringBuilder validity = new StringBuilder(5); _fsgf_return_validity(path, validity); return validity.ToString(); }
Monday, December 22, 2008 9:46 PM -
FANTASTIC!
Thank you very much for your time, it works perfectly!
this is brilliant!
Cheers!
DarkzaelusMonday, December 22, 2008 9:51 PM