Search code examples
c#c++pinvoke

P/Invoke and .NET Target Framework


This issue is driving me up the wall... Just saying.

My company has a legacy C++ library and I have been tasked to create a .NET wrapper.
I have no experience of C++ or P/Invoke so to start with I am trying a simple method.

I have read the official documentation and I have also found a nice tutorial.
However, I have discovered that the target .NET framework of the consuming app makes a difference.
The P/Invoke code from the tutorial works fine but I have noticed that he is targeting .NET Framework 4 Client Profile.
If I place break points then they are hit and everything works as expected, if I target a framework higher than 4 then the program crashes without exception.

I have a really simple method defined in C++:
framework.h

extern "C" {
    API char* SayHello();
}

dllmain.cpp

char* SayHello() {
    return (char*)"Hello";
}

C#

        [DllImport("PInvokeTest.dll")]
        public static extern string SayHello();

(I have tried setting CallingConvention and CharSet on the attribute in different combinations, I have managed to get Chinese characters, but nothing working higher than Framework 4)

My C++ project has API=__declspec(dllexport) it Preprocessor Definitions set and Calling Convention is _stdcall (\Gz) (I have also tried _cdecl).
The C# project works fine on Framework 4, when I change to anything above that then it just exits without exception.
I have also found Dependencies GUI that is showing me that SayHello is indeed there.

Our company uses 4.6.1, I also came across this article which lead me to PInvokeStackImbalance but that doesn't do anything in my case.

Any help would be greatly appreciated.
I could create a temp GitHub repo if needed.


Solution

  • Now that I know it is a string issue I did a little searching and I found this SO question.
    So in the end I used the BSTR approach.

    BSTR SayHello() {
        return ::SysAllocString(L"Hello");
    }
    
            [DllImport("DBReplicator.Lib.dll")]
            [return: MarshalAs(UnmanagedType.BStr)]
            public static extern string SayHello();
    

    ... Still don't know how I managed to get Chinese characters though.