1

I am using C# code and need to call this method inside a C++ dll.

static std::wstring DecryptData(const std::wstring& strKey);

I've read many things and my best guess would be to pass something that is easier to read for both languages, like char-array or even byte-array and build the wstring in C++ and the string in C# afterwards.

Did anyone do that already?

Edit:

I read the linkes Topic but none of the answers helps me: Using const didn't help.

This is what I have now: C#

 [DllImport(DLL_PATH, CharSet = CharSet.Unicode)]
        [return: MarshalAs(UnmanagedType.LPWStr)]
        public static extern string DecryptData([MarshalAs(UnmanagedType.LPWStr)]string strKey);

C++

extern "C" __declspec(dllexport) const std::wstring DecryptData(const std::wstring& strKey) {
    return WlanHelper::CWirelessHelper::DecryptData(strKey);
}

This gives me a PInvokeStackImbalance =/

ecth
  • 1,215
  • 1
  • 16
  • 33
  • Possible duplicate of [Return a std::wstring from C++ into C#](http://stackoverflow.com/questions/7051097/return-a-stdwstring-from-c-into-c-sharp) – kevindeleon Dec 19 '15 at 17:40
  • This soolves the second half of my question. But I also need to put in a C# string and the method expects a wstring atm. – ecth Dec 19 '15 at 17:52
  • `[DllImport("path.dll", CharSet=CharSet.Unicode)] static extern string DecryptData([MarshalAs(UnmanagedType.LPWStr)]string strKey);` ? – drf Dec 19 '15 at 17:57
  • @drf It would be better to add the DLL as a reference – Sophie Coyne Dec 19 '15 at 18:05
  • Do you have the option to change the c++ function? – Barmak Shemirani Dec 19 '15 at 18:09
  • I tried the piece of code of drf and now I have StackImbalance. @Barmak Shemirani: It's a bigger lib, so I'l like to keep that method as it is BUT I can change the method which uses it. That's what I am asking for. Any way to make it use byteArrays or something and then cast it to a wstring, use the inner method, cast to an array and give it out to c#. – ecth Dec 19 '15 at 18:32
  • Also, what is the parameter in `DecryptData(const std::wstring& strKey);`? If `strKey` is binary data (such that it may include a zero byte) then you cannot pass it as string, you have to pass the key and key length. Otherwise the answer given by drf should work, where strKey is string or wide string, and the end of the string can be determined by null terminating zero. – Barmak Shemirani Dec 20 '15 at 04:04

1 Answers1

5

You may find this question and this question to be relevant. There are two issues:

  1. P/Invoke does not natively marshal std::string/std::wstring, and
  2. Possible memory lifetime issues (depends on implementation of CWirelessHelper::DecryptData).

An approach is to copy the string to a plain wchar_t* buffer allocated using CoTaskMemAlloc (the framework will handle the string conversion and free the allocated memory).

On the unmanaged side, the code becomes:

extern "C" __declspec(dllexport) const wchar_t* DecryptData( wchar_t* strKey) {
    std::wstring retstr = WlanHelper::CWirelessHelper::DecryptData(std::wstring(strKey));
    const wchar_t* ret = retstr.c_str();
    size_t bufsize = wcslen(ret) + 1;
    wchar_t* buffer = (wchar_t*)CoTaskMemAlloc(bufsize * sizeof(wchar_t));
    wcscpy_s(buffer, bufsize, ret);
    return buffer;
}

And on the managed side:

[DllImport(DLL_PATH, 
    CharSet = CharSet.Unicode, 
    CallingConvention = CallingConvention.Cdecl)]
static extern string DecryptData(string strKey);
Community
  • 1
  • 1
drf
  • 8,461
  • 32
  • 50