none
Marshal wchar_t**

    Question

  • In C++ I have:

    extern "C" __declspec(dllexport) int myfunct(wchar_t** mystring)
    
    {	
    
    	*mystring = new wchar_t[wcslen(_T("hello world"));
    
    	wcscpy(*mystring,_T("hello world"));
    
    	return 1;
    
    }
    
    

    In C#

    [DllImport("myDll.dll")]
    
    internal static extern int myfunct([MarshalAs(UnmanagedType.LPWStr)]out string ec);
    
    
    
    public void test()
    
    {
    
    	string str = null;
    
    	int y = myfunct(out str);
    
    }
    
    
    
    





    In windows Xp it works, but in windows Vista I get
    "Attempted to read or write protected memory. This is often an indication that other memory is corrupt"

    Then I changed C# code in :

    [DllImport("myDll.dll")]
    
    internal static extern int myfunct(out IntPtr ec);
    
    
    
    public void test()
    
    {
    
    	IntPtr str;
    
    	int y = myfunct(out str);
    
    	string mystr =  Marshal.PtrToStringUni(str);
    
    }
    
    


    In this way it works on windows Vista, but is it right? is it just luck?
    Do I forget something? should I free the memory?



     

    Wednesday, August 26, 2009 2:48 PM

Answers

  • There's another big problem.  The callee of this function must release the string.  The C# code cannot do this, it doesn't have access to the unmanaged C/C++ heap allocator.  You'll leak memory for every call.

    The C/C++ code must look like this:

    extern "C" __declspec(dllexport) int myfunct(wchar_t* buffer, size_t bufsize)
    {   
        wcscpy_s(buffer, bufsize, L"Hello world");
        return 1;
    }

    And your C# code like this:

      [DllExport("something.dll", CharSet = CharSet.Unicode)]
      private static extern int myfunct(StringBuilder buffer, int bufsize);
    ...
        sb = new StringBuilder(666);
        int retval = myfunct(sb, sb.Capacity);
        string s = sb.ToString();

     

    Hans Passant.
    • Marked as answer by chiara1990 Thursday, August 27, 2009 3:22 PM
    Wednesday, August 26, 2009 4:36 PM
    Moderator

All replies

  • The C/C++ code is buggy. You need to allocate memory for the terminating NULL. So that'd be wcslen(...) + 1.


    http://blog.voidnish.com
    Wednesday, August 26, 2009 2:53 PM
    Moderator
  • The C/C++ code is buggy. You need to allocate memory for the terminating NULL. So that'd be wcslen(...) + 1.


    http://blog.voidnish.com

    uops. Thank you ;)

    insead for the marshal operation could you say me if there are possible problems?
    Wednesday, August 26, 2009 2:58 PM
  • There's another big problem.  The callee of this function must release the string.  The C# code cannot do this, it doesn't have access to the unmanaged C/C++ heap allocator.  You'll leak memory for every call.

    The C/C++ code must look like this:

    extern "C" __declspec(dllexport) int myfunct(wchar_t* buffer, size_t bufsize)
    {   
        wcscpy_s(buffer, bufsize, L"Hello world");
        return 1;
    }

    And your C# code like this:

      [DllExport("something.dll", CharSet = CharSet.Unicode)]
      private static extern int myfunct(StringBuilder buffer, int bufsize);
    ...
        sb = new StringBuilder(666);
        int retval = myfunct(sb, sb.Capacity);
        string s = sb.ToString();

     

    Hans Passant.
    • Marked as answer by chiara1990 Thursday, August 27, 2009 3:22 PM
    Wednesday, August 26, 2009 4:36 PM
    Moderator
  • Hey Hans,

    I have not verified this, but I have this vague memory that if you use CoTaskMemAlloc (instead of directly using new/malloc), the interop marshaller may free the memory before marshaling to a System.String.
    http://blog.voidnish.com
    Wednesday, August 26, 2009 6:56 PM
    Moderator