locked
Returning arrays from c++ dll with extern "C" to c# RRS feed

  • 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!)

    Darkzaelus
    Monday, 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(); 

    • Proposed as answer by ildjarn Monday, December 22, 2008 9:53 PM
    • Marked as answer by nobugz Tuesday, December 23, 2008 2:06 AM
    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,

    Darkzaelus
    Monday, 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(); 

    • Proposed as answer by ildjarn Monday, December 22, 2008 9:53 PM
    • Marked as answer by nobugz Tuesday, December 23, 2008 2:06 AM
    Monday, December 22, 2008 9:46 PM
  • FANTASTIC!

    Thank you very much for your time, it works perfectly!

    this is brilliant!

    Cheers!

    Darkzaelus
    Monday, December 22, 2008 9:51 PM