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.
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.
Here is a topic where string marshaling has been discussed.
It's needed to mark parameter with attribute
[MarshalAs(UnmanagedType.LPSTR)]
                        Here is an example of doing this through C#. I am calling Native function GetWindowText through C# by pInvoking. GetWindowText returns the caption of the window whose handle is passed to it.
    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    static extern int GetWindowTextLength(IntPtr hWnd);
    public static string GetText(IntPtr hWnd)
    {
        // Allocate correct string length first
        int length = GetWindowTextLength(hWnd);
        StringBuilder sb = new StringBuilder(length + 1);
        GetWindowText(hWnd, sb, sb.Capacity);
        return sb.ToString();
    }        
    private void button1_Click(object sender, EventArgs e)
    {
        string str = GetText(this.Handle);
    }
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With