Search code examples
c#c++stringpinvoke

How to return text from Native (C++) code


I am using Pinvoke for Interoperability between Native(C++) code and Managed(C#) code. What i want to achieve is get some text from native code into my managed code. For this i try lot lot of things,e.g passing string/stringbuilder by ref, using [IN] and [OUT], Marshaling to LPSTR, returning string from function etc. but nothing works in my case. Any help with some small code would be highly appreciated.


Solution

  • I'd do it with a BSTR since it means you don't have to call into native twice per string, once to get the length and then once to get the contents.

    With a BSTR the marshaller will take care of deallocating the BSTR with the right memory manager so you can safely pass it out of your C++ code.

    C++

    #include <comutil.h>
    BSTR GetSomeText()
    {
        return ::SysAllocString(L"Greetings from the native world!");
    }
    

    C#

    [DllImport(@"test.dll", CallingConvention = CallingConvention.Cdecl)]
    [return: MarshalAs(UnmanagedType.BStr)]
    private static extern string GetSomeText();
    

    There is one minor drawback of the BSTR, namely that it carries a UTF-16 payload but your source data may well be char*.

    To overcome this you can wrap up the conversion from char* to BSTR like this:

    BSTR ANSItoBSTR(const char* input)
    {
        BSTR result = NULL;
        int lenA = lstrlenA(input);
        int lenW = ::MultiByteToWideChar(CP_ACP, 0, input, lenA, NULL, 0);
        if (lenW > 0)
        {
            result = ::SysAllocStringLen(0, lenW);
            ::MultiByteToWideChar(CP_ACP, 0, input, lenA, result, lenW);
        } 
        return result;
    }
    

    That's the hardest one out of the way, and now it's easy to add other wrappers to convert to BSTR from LPWSTR, std::string, std::wstring etc.