Search code examples
c#c++pinvokeextern

P/Invoke external method from C# to C++


I have written the following C++ shared library:

#include "iostream"

#if defined(_WIN32) || defined(_WIN64)
    #define Q_DECL_EXPORT __declspec(dllexport)
    #define Q_DECL_IMPORT __declspec(dllimport)
#else
    #define Q_DECL_EXPORT
    #define Q_DECL_IMPORT
#endif

#ifdef MATINCHESS_LIBRARY
#  define MATINCHESS_API Q_DECL_EXPORT
#else
#  define MATINCHESS_API Q_DECL_IMPORT
#endif

using namespace std;

string* memory;

extern "C"
{
    MATINCHESS_API void Initialize();
    MATINCHESS_API void Uninitialize();
    MATINCHESS_API void Put(string text);
    MATINCHESS_API string Get();

    void Initialize()
    {
        memory = new string;
    }

    void Uninitialize()
    {
        delete memory;
    }

    void Put(string text)
    {
        memory->assign(text);
    }

    string Get()
    {
        return *memory;
    }
}

And here is my C# console application:

using System;
using System.Runtime.InteropServices;

namespace MatinChess
{
    class MainClass
    {
        const string MatinChessDLL = "libMatinChessDLL.so";

        [DllImport(MatinChessDLL)]
        public static extern void Initialize();
        [DllImport(MatinChessDLL)]
        public static extern void Uninitialize();

        [DllImport(MatinChessDLL)]
        public static extern void Put(string text);

        [DllImport(MatinChessDLL)]
        public static extern string Get();

        public static void Main (string[] args)
        {
            Console.WriteLine ("Initializing...");
            Initialize ();
            Console.WriteLine ("Initialized");

            Console.WriteLine ("Write: ");
            Put (Console.ReadLine ());
            Console.WriteLine ("Value is put.");

            Console.WriteLine ("You wrote \"" + Get () + "\"");
            Console.ReadKey ();

            Console.WriteLine ("Uninitializing...");
            Uninitialize ();
            Console.WriteLine ("Uninitialized");
        }
    }
}

It safely initializes and puts the string from ReadLine, but when it wants to invoke Get method, it crashes with a long stack trace.

Please help me to find the issue.


Solution

  • You cannot marshal std::string from C++ to C#. You have to use a character buffer. See this question: Passing strings from C# to C++ dll and back -- minimal example