10

I thought the problem is inside my C++ function,but I tried this

C++ Function in C++ dll:

bool __declspec( dllexport ) OpenA(std::string file)
{
return true;
}

C# code:

[DllImport("pk2.dll")]
public static extern bool OpenA(string path);

    if (OpenA(@"E:\asdasd\"))

I get an exception that the memory is corrupt,why?

If I remove the std::string parameter,it works great,but with std::string it doesnt work.

Ivan Prodanov
  • 34,634
  • 78
  • 176
  • 248
  • Maybe you can solve it by making a managed c++ bridge that unpacks the string? [Here](http://stackoverflow.com/questions/267057/creating-a-mixed-mode-c-bridge-from-c-to-c) is a SO question about this subject. – FeatureCreep May 17 '09 at 13:11

5 Answers5

16

std::string and c# string are not compatible with each other. As far as I know the c# string corresponds to passing char* or wchar_t* in c++ as far as interop is concerned.
One of the reasons for this is that There can be many different implementations to std::string and c# can't assume that you're using any particular one.

shoosh
  • 76,898
  • 55
  • 205
  • 325
  • 4
    Not to mention that std::string is also a template, which opens another interesting can of worms for the interop. – Timo Geusch May 17 '09 at 13:04
  • 1
    The most proper way is to use char* and create std::string from it. If you want to return a std::string to C#, you must allocate a char* with CoTaskMemAlloc with size of std::string's size()+1, then memcpy std::string's data() into this buffer and return it. Easy. Note: you MUST use CoTaskMemAlloc! – Петър Петров Mar 10 '15 at 00:54
7

Try something like this:

bool __declspec( dllexport ) OpenA(const TCHAR* pFile)
{ 
   std::string filename(pFile);
   ...
   return true;
}

You should also specify the appropriate character set (unicode/ansi) in your DllImport attribute.

As an aside, unrelated to your marshalling problem, one would normally pass a std:string as a const reference: const std:string& filename.

Will Dean
  • 39,055
  • 11
  • 90
  • 118
  • 1
    that std::string will fail compilation if _UNICODE is defined. might be better to do an #ifdef and use std::wstring or simply make a typedef for a tstring depending on _UNICODE. – Idan K May 17 '09 at 16:21
2

std::wstring and System.string can be compatible through below conversion:

C++ :

bool func(std::wstring str, int number)
{
  BSTR tmp_str = SysAllocStringLen(str.c_str(), str.size());
  VARIANT_BOOL ret = VARIANT_FALSE;

  // call c# COM DLL
  ptr->my_com_function(tmp_str, number, &ret);

  SysFreeString(tmp_str);

  return (ret != VARIANT_FALSE) ? true : false;
}
sailfish009
  • 2,561
  • 1
  • 24
  • 31
1

I know this topic is a tad old but for future googlers, this should also work (without using char* in C++)

C#:

public static extern bool OpenA([In, MarshalAs(UnmanagedType.LPStr)] path);

C++:

bool __declspec( dllexport ) OpenA(std::string file);
Nitay
  • 4,193
  • 6
  • 33
  • 42
  • What do you mean? Did you try the code above and it didn't work? – Nitay Mar 03 '15 at 09:45
  • I mean, is there any reference page which states that it should work, and defines requirements for it to work? – vines Mar 03 '15 at 09:47
  • I'm sorry but I can't find the reference for this atm (this was quite a long time ago). However you could try this page: https://msdn.microsoft.com/en-us/library/s9ts558h%28v=vs.110%29.aspx – Nitay Mar 03 '15 at 10:49
1

It's not possible to marshal a C++ std::string in the way you are attempting. What you really need to do here is write a wrapper function which uses a plain old const char* and converts to a std::string under the hood.

C++

extern C { 
  void OpenWrapper(const WCHAR* pName) {
    std::string name = pName;
    OpenA(name);
  }
}

C#

[DllImport("pk2.dll")]
public static extern void OpenWrapper( [In] string name);
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454