Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 448
Jame Avatar asked Mar 15 '11 07:03

Jame


3 Answers

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.

like image 141
David Heffernan Avatar answered Nov 09 '22 12:11

David Heffernan


Here is a topic where string marshaling has been discussed.

It's needed to mark parameter with attribute

[MarshalAs(UnmanagedType.LPSTR)]
like image 37
Disposer Avatar answered Nov 09 '22 11:11

Disposer


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);
    }
like image 4
Aamir Avatar answered Nov 09 '22 12:11

Aamir