Shared memory between C++ DLL and C# code - c#

I am currently working on a project with really short deadline, so I don't have much time to understand everything. Also, I am not an expert in C++ development and memory management.
So, what I am trying to do is to create a DLL in with both C and C++ code. Then, I would like to call this DLL in a C# code. Currently, the communication between C++ and C# is OK. The problem comes up when I try to transfer a string from the DLL to the C# code. The error is this one :
System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
at Microsoft.Win32.Win32Native.CoTaskMemFree(IntPtr ptr)
at System.StubHelpers.CSTRMarshaler.ClearNative(IntPtr pNative)
at NMSPRecognitionWrapper.Program.GetResultsExt()
at NMSPRecognitionWrapper.Program.<Main>b__0() in <my dir>\Program.cs:line 54
at NMSPRecognitionWrapper.Program.StartRecognitionExt()
at NMSPRecognitionWrapper.Program.Main(String[] args) in <my dir>\Program.cs:line 60
Also, I can give you some piece of code below (really simplified !). Actually, the C++ expose two methods : StartRecognition() launch operations to get some data from microphone, then process them and store the results. GetResults() return an instance of the results previously stored. The WrapperCallback() allows the C# part to be called when a Result is able for processing. The C# part, when the Callback is called, will ask to get the results using the GetResults() method.
I know the architecture may seem really inappropriate in this presentation, but I don't want to explain the whole project to validate the model, please be sure everything is correct.
To finish, the problem is when the C# callback call the GetResults() method. Trying to access to the resultsForCS seems to be impossible from the C#.
C++ part - header
// NMSPRecognitionLib.h
#pragma once
#include <iostream>
using namespace std;
extern "C" __declspec(dllexport) char* GetResults();
extern "C" static void DoWork();
extern "C" __declspec(dllexport) void StartRecognition();
C++ part - sources
#include "stdafx.h"
#include "NMSPRecognitionLib.h"
static char * resultsForCS;
static SUCCESS ProcessResult(NMSPCONNECTION_OBJECTS *pNmspConnectionObjects, LH_OBJECT hResult)
{
[...]
char* szResult;
[...]
resultsForCS = szResult;
DoWork();
[...]
return Success;
error:
return Failure;
} /* End of ProcessResult */
extern "C" __declspec(dllexport) char* GetResults()
{
return resultsForCS;
}
extern "C"
{
typedef void (*callback_function)();
callback_function gCBF;
__declspec(dllexport) void WrapperCallback(callback_function callback) {
gCBF = callback;
}
static void DoWork() {
gCBF();
}
}
extern "C" __declspec(dllexport) void StartRecognition()
{
char* argv[] = { "path", "params" };
entryPoint(2, argv);
}
C# part
class Program
{
[DllImport("NMSPRecognitionLib.dll", EntryPoint = "GetResults")]
[return: MarshalAs(UnmanagedType.LPStr)]
public static extern string GetResultsExt();
public delegate void message_callback_delegate();
[DllImport("NMSPRecognitionLib.dll", EntryPoint = "WrapperCallback")]
public static extern void WrapperCallbackExt(message_callback_delegate callback);
[DllImport("NMSPRecognitionLib.dll", EntryPoint = "StartRecognition")]
public static extern void StartRecognitionExt();
static void Main(string[] args)
{
WrapperCallbackExt(
delegate()
{
Console.WriteLine(GetResultsExt());
}
);
StartRecognitionExt();
Console.WriteLine("\nPress any key to finish... ");
var nothing = Console.ReadLine();
}
}
I understand that the problem comes because I am using a pointer to store the results (char *), but I actually don't know how to do this in another way. The szResults type is char * too and I can't change this !

Yes, the return type is the problem. The pinvoke marshaller must do something to release the memory that was allocated for the string. The contract is that memory allocations that need to be released by the caller must be allocated from the COM heap. CoTaskMemAlloc() in native code, also exposed in .NET as Marshal.AllocCoTaskMem().
This rarely comes to a good end, most native code allocates with malloc() or ::operator new, allocating from a heap that's created by the C runtime library. The wrong heap. So inevitably the CoTaskMemFree() call will fail. Ignored silently in Windows XP and earlier, a kaboom on Vista and up.
You must stop the pinvoke marshaller from trying to release the memory. Do so by declaring the return value as IntPtr. And use Marshal.PtrToStringAnsi() to recover the string.
You still have a Big Problem, the kind of problem that bedevils any native code that tries to use this function as well. You still have a string buffer that needs to be released. You cannot do that from C#, you can't pinvoke the correct version of free() or ::operator delete. A memory leak is inevitable. The only thing you can hope for is that the native code takes care of it, somehow. If it doesn't then you must use C++/CLI to interop with it. With the additional requirement that the native code needs to be rebuilt with the same compiler so that it uses the same shared CRT. Code that's difficult to use correctly from native code is also hard to pinvoke. That's a design flaw, always allow the caller to pass a buffer to be filled in so there's never a question who owns the memory.

Looking at:
at Microsoft.Win32.Win32Native.CoTaskMemFree(IntPtr ptr)
at System.StubHelpers.CSTRMarshaler.ClearNative(IntPtr pNative)
at NMSPRecognitionWrapper.Program.GetResultsExt()
I can see that your callback is called, but the runtime tries to free some memory. I think it assumes your pointer would be to com memory. Try converting the string yourself, it is easy!
[DllImport("NMSPRecognitionLib.dll", EntryPoint = "GetResults")]
public static extern IntPtr GetResultsExt();
[...]
string result = Marshal.PtrToStringAnsi(GetResultsExt())
No 100% guarantee, but worth a try.

I have found that it is usually easier to write a wrapper in C++/CLI around the C++ native code. A C++/CLI class can directly call and use native C++, but is accessible from C# (and any .Net language). In my experience, using DLLImport as you do leads to hard to debug and find errors.

Related

Crash when passing an UnmanagedCallersOnly function pointer to C++ via P/Invoke call decorated with SuppressGCTransition

Suppose we have the following C++ code:
typedef int (*getIntPtr)(void);
extern "C" __declspec(dllexport) void InvokeFuncPtr(getIntPtr funcPtr) {
std::wcout << funcPtr();
}
We can match this definition in C#:
[DllImport("NativeLib.dll", CallingConvention = CallingConvention.Cdecl), SuppressGCTransition]
public static unsafe extern void InvokeFuncPtr(delegate* unmanaged[Cdecl]<int> funcPtr);
And then we can use this function like so:
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
public static int ReturnInt() => 123;
// ... Elsewhere:
unsafe {
InvokeFuncPtr(&ReturnInt);
}
When InvokeFuncPtr is marked with SuppressGCTransition this results in the program crashing with the error "Fatal error. Invalid Program: attempted to call a UnmanagedCallersOnly method from managed code.". If we remove the SuppressGCTransition attribute it works as expected, and 123 is printed to the console.
Is this expected behaviour? I imagine it amounts to the runtime seeing ReturnInt() as being invoked from managed code, simply with a couple of extra steps of indirection. If so, is there any way around this, or should I simply leave the SuppressGCTransition attribute off?
Yes, you should leave off SuppressGCTransition, as the stack is what the runtime uses to identify whether the caller is managed or unmanaged.
If there is no transition in the stack, there is no way for the runtime to tell that the stack transitioned to unmanaged.
Alternatively, you can leave off UnmanagedCallersOnly, and instead marshal the delegate with Marshal.GetFunctionPointerForDelegate.

A call to PInvoke function has unbalanced the stack in debug mode [duplicate]

This question already has answers here:
A call to PInvoke function has unbalanced the stack. This is likely because the managed PInvoke .. (.NET 4)
(2 answers)
Closed 7 years ago.
I've started recently to work on the project that involves communication between C# and native code and thus I'm trying to understand how it works. I've loaded one of the samples from msdn, tried to launch it and I see that it works in Release mode and crashes in debug mode. Does somebody know why?
// PInvokeTest.cs
using System;
using System.Runtime.InteropServices;
class PlatformInvokeTest
{
[DllImport("msvcrt.dll")]
public static extern int puts(string c);
[DllImport("msvcrt.dll")]
internal static extern int _flushall();
public static void Main()
{
puts("Test");
_flushall();
}
}
Error:
Additional information: A call to PInvoke function 'ConsoleApplication6!PlatformInvokeTest::puts' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.
This code is from following site: https://msdn.microsoft.com/en-us/library/aa288468(v=vs.71).aspx
Quoting this well detailed answer:
A stack imbalance occurs when the data structure used to keep track of
called functions, arguments, and return values becomes corrupted or
misaligned.
Most times, the stack is a memory pointer that stores the address
where control will resume when the current function call exits back to
the caller. There are different variants on this, sometimes the
arguments to a function are also appended to the stack, as well as the
return value. What is most important here is that the caller and
callee should agree upon how to restore it back to the prior state
when the callee exits. This agreement is frequently known as the
Calling Convention.
You forgot to specify the calling convention:
class PlatformInvokeTest
{
[DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int puts(string c);
[DllImport("msvcrt.dll")]
internal static extern int _flushall();
public static void Main()
{
puts("Test");
_flushall();
}
}
Read more about x86 calling conventions

PInvoke: Error in returing text from C++ to C#

I am using Pinvoke for Interoperability between Native(C++) code and Managed(C#) code. What i want to achieve is get some text from native code into my managed code as a retrun value i.e My C# Code calls my C++ function which returns some text back to C#. Following is my code for this.
C++ Code:
static std::wstring WSTR_TEMP;
wchar_t* cppReturnSomeText()
{
UnicodeString usText ("Some Text Here");
WSTR_TEMP = ECUtilsICU::UniCodeStringToWString(usText);
return (wchar_t *)(WSTR_TEMP.c_str());
}
C# Code:
[DllImport(MY_DLL_NAME]
[return: MarshalAs(UnmanagedType.LPWStr)]
private static extern string cppReturnSomeText();
public static string GetSomeText()
{
string s = cppReturnSomeText();
return s;
}
Every thing was working fine as expected. Now i simply change my operating system from WinXP(32Bit) to Win7(64Bit). And when i run this code following error occurred:
"Attempted to read or write protected memory. This is often an indication that other memory is corrupt."
I guess the problem is that you are allocating memory with your C++ runtime's allocator but then the C# marshaller attempts to deallocate it. That cannot work. You need to allocate and deallocate with the same allocator.
The best way I know to solve your problem is to marshal with a BSTR. That uses the COM allocator which is happy to be shared between native and managed modules.
#include <comutil.h>
BSTR cppReturnSomeText()
{
UnicodeString usText("Some Text Here");
std::wstring result = ECUtilsICU::UniCodeStringToWString(usText);
return ::SysAllocString(result.c_str());
}
On the C# side you do this:
[DllImport(MY_DLL_NAME, CallingConvention=CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.BStr)]
private static extern string cppReturnSomeText();
One other benefit of this is that your code is now thread-safe because you no longer need a global variable.

error during dll-function call from C# code

I created dll in c++ and wanted to call function from it using c#. I has an error if function, which program calls, returns string.
Dll code:
#include <string>
using namespace std;
#define EXPORT_API extern "C" __declspec(dllexport)
EXPORT_API void DllFunc()
{
MessageBoxA(0,"DDL box", "Yeah!", 0);
}
EXPORT_API string DllFuncStr()
{
return "testStr";
}
C# application code:
[DllImport("dllka.dll")]
static extern void DllFunc();
[DllImport("dllka.dll")]
static extern string DllFuncStr();
private void btnStart_Click(object sender, RoutedEventArgs e)
{
DllFunc();
string str = DllFuncStr();
}
"DllFunc();" - works nice, but on line "string str = DllFuncStr();" i had an error:
The runtime has encountered a fatal error. The address of the error was at 0x5e6dceca, on thread 0x16b0. The error code is 0xc0000005. This error may be a bug in the CLR or in the unsafe or non-verifiable portions of user code. Common sources of this bug include user marshaling errors for COM-interop or PInvoke, which may corrupt the stack.
What is wrong with string type? How to fix this problem?
You can't marshal std::string from C++ to C#. Instead either use a zero-terminated string marshalled with StringBuilder, or return a BSTR.
The BSTR approach is quite simple. If you prefer zero-terminated string then look on the web for sample P/Invokes from Win32 APIs, e.g. GetWindowText().
You are exporting from C++ with cdecl calling convention, but using stdcall in the C# code. You'll need to match those up once you have sorted the data type marshalling out. It doesn't matter which you use, so long as it's the same at both ends.
You will also need to broach the fact that your C++ code uses char (8 bit encoding) and C# uses Windows native UTF-16.
If it was me, I'd do it with a BSTR, as I outline in this answer to another question.
As David said, c++ std::string and c# string are different things. I did it following way in my application:
c++ DLL code:
EXPORT_API void DllFuncStr(char* sRetText, int nCapacity)
{
if(!sRetText)
return;
std::string sRetTextStr("testStr");
strcpy_s(sRetText, nCapacity, sRetTextStr.c_str());
return;
}
c# application code:
[DllImport("dllka.dll")]
static extern bool DllFuncStr(StringBuilder sStrBuilder, int nCapacity);
private void btnStart_Click(object sender, RoutedEventArgs e)
{
StringBuilder strBuilder = new StringBuilder(50);
DllFuncStr(strBuilder, strBuilder.Capacity);
string str = strBuilder.ToString();
}
(Thank you Hans for suggestions. I will repair this thing in my application, too)

Pain free way to call a managed c# function (with no return value) from unmanaged c++?

I have been tasked with maintaining a legacy unmanaged c++ system. I do not have access to the source of the entire system but I do have the source to a number of extension dlls that, when included in the same directory as the core system, will be loaded instead of the built in defaults.
I have used the extensions in the past for small changes without problems. My issue now, however, is that I'm being asked to overhaul one of the extension dlls with a substantial amount of extra functionality. Creating this extra functionality in C# is going to be significantly faster (time-to-develop) and more maintainable (our team is primarily composed of C# devs).
The extension dll only has two functions that get called by the core system. The two functions take a bool, int, uint, RECT, Point, CString and return void. Some of the parameters they accept are const.
I'm really keen to find a solid way to bridge these extension functions to C# (.NET 4). So far I've put considerable effort into researching COM Visible, Regasm, c++ mixed mode and interop wrapping libraries. I've also lost a considerable amount of time on proof of concept projects during this research and so far I do not have a working 'bridge'.
What is the most pain free method to get this up and running?
I'm under considerably more pressure on this project than normal - I'm literally starting the C# now and assuming I will get this working somehow.
Really appreciate help and feedback.
Here is the .h and .def files:
modeldll.h
#ifndef INC_MODELDLL_H
#define INC_MODELDLL_H
#ifdef MODELDLL_EXPORTS
#define MODELDLL_API __declspec(dllexport)
#else
#define MODELDLL_API __declspec(dllimport)
#endif
typedef int (*model_updatemodel_t)(const bool update_model, const HWND hwnd, const RECT rect, const POINT next_point, const CString title);
MODELDLL_API int UpdateModel(const bool update_model, const HWND hwnd, const RECT rect, const POINT next_point, const CString title);
typedef int (*model_updatemodelpoint_t)(const bool update_model, const HWND hwnd, const RECT rect, UINT update, const POINT next_point);
MODELDLL_API int UpdateModelPoint(const bool update_model, const HWND hwnd, const RECT rect, UINT update, const POINT next_point);
typedef void (*model_process_message_t)(const char *message, const void *param);
MODELDLL_API void ProcessMessage(const char *message, const void *param);
#endif // INC_MODELDLL_H
modeldll.def:
LIBRARY model.dll
EXPORTS
ProcessMessage #1
UpdateModel #2
UpdateModelPoint #3
I've investigated this topic couple of years ago: I want to use log4net and Npgsql libraries from native code that compiles even withour /clr key.
The main idea behind this technique described by Paul DiLascia in his two remarkable articles:
Managed Code in Visual Studio 2005
Use Our ManWrap Library to Get the Best of .NET in Native C++ Code
For example, here some code snippets that uses log4net library from native code (this code resides in simple non-managed dll, but you should compile this with /clr, but it's not nessary to compile with /clr key code that would use this dll from native code):
// Log4NetWrapper.h
#pragma once
using namespace System;
//facade for log4net library (you may create something like this too)
ref class Log4NetWrapper
{
public:
//I intentionally remove additional methods, because
//I'm trying to show the main principle
static void ReportDebugMessage(char* msg);
private:
static property log4net::ILog^ Logger
{
log4net::ILog^ get();
}
static Object^ syncObject_ = gcnew Object();
static String^ loggerName_ = "";
};
//C-interface that could be accessed from native code
extern "C"
{
_declspec(dllexport) void ReportDebugMessage(char* msg)
{
Log4NetWrapper::ReportDebugMessage(msg);
}
}
// This is the main DLL file.
#include "stdafx.h"
#include "Log4NetWrapper.h"
void Log4NetWrapper::ReportDebugMessage(char* msg)
{
String^ data = gcnew String(msg);
Logger->Debug(data);
}
log4net::ILog^ Log4NetWrapper::Logger::get()
{
if ( loggerName_ == nullptr )
return log4net::LogManager::GetLogger("");
return log4net::LogManager::GetLogger(loggerName_);
}
Compile this code as native dll, than add this dll to your native project, add something like this to that project:
#pragma once
#pragma comment(lib, "Log4NetWrapper")
extern "C"
{
_declspec(dllimport) void ReportDebugMessage(char* msg);
}
And use ReportDebugMessage to access managed code from native code.
Without further information there's not much to go on but I would suggest that you have the following.
Extension Dll (unmanaged code) -> Managed C++ (wrapper) -> C# dll
The first jump is explained in this example:
http://www.codeproject.com/KB/mcpp/cpptomancpp.aspx
You can then load the c# assembly from the managed c++ fairly easily using
using namespace YourNameSpace; // the namespace of the c# routines
In time you may be able to merge the first two.
As Preet suggested, this can be done using a Managed C++ wrapper that will do the bridging you need.
This article explains the entire process:
http://www.codeproject.com/KB/mcpp/unmanaged_to_managed.aspx
I've actually done these sort of things quite a lot several years ago, and all direction work pretty well - C# calling C++ code, C++ code calling C# (via a Managed C++ proxy) and C# passing delegate to a C++ code treating them as function pointers and calling them. I've had some example projects for this, I'll try and find them.

Categories

Resources