I am working on a project that puts C# interacting with a previously created DLL in C++.
The code below shows how am I exporting the function I need:
extern "C" __declspec(dllexport) int iterateAndTest(int testSize, char* testHash){
CUDADLL dll;
int ret = dll.iterateAndTest(testSize, testHash);
return ret;
}
The code below shows how I declare the function in C#:
[DllImport("C:\\Users\\BrunoBraga\\Documents\\Visual Studio 2012\\Projects\\CUDADLL\\Debug\\CUDADLL.dll")]
public static extern int iterateAndTest(int testSize, string testHash);
The problem is: the dll function is not returning anything. In fact, the dll once called, never returns to C# and the program simply ends.
I am not sure if I am giving the right code, but i suppose there is something about the dlls I am missing.
Sorry for the delay on response. THere were two problems:
1-When i created the object, i should have used new insted of just CUDADLL dll. I thought i could do this since without the new i was still able to access the inner fields.;
2-The program should run in admin, otherwise, some crashes would ocur;
Thanks again guys.
In Your c++ code insert __stdcall
extern "C" __declspec(dllexport) __stdcall int iterateAndTest(int testSize, char* testHash);
in C#
[DllImport("yourdll.dll", EntryPoint="iterateAndTest", CallingConvention=CallingConvention.StdCall)]
public static extern int iterateAndTest(int testSize, string testHash);
use cout in your C++ function, if the function is called output will be displayed in output window if you are using Visual Studio.
try placing your c++ dll in your output directory
Possible Errors: dll not found or entry point exception will be thrown.
Related
I'm trying to call a minimal C function from C# on Windows 10. I use mingw/g++ to compile the C code into a .dll
It turns out that I have to define opterator new[] or compile the .dll using Visual Studio. Otherwise my C# program crashes with the following error:
The program '[14740] Test.exe' has exited with code -1073741819 (0xc0000005) 'Access violation'.
I'd really love to understand what exactly is happening here and how I can resolve this issue without overriding all the new/delete operators but still using mingw.
Here's the minimal example reproducing the error including a workaround (if AddNewOperator is defined operator new[] will be defined and the resulting .dll will work fine):
Test.cs (compiled/run with Visual Studio 2017):
using System;
using System.Runtime.InteropServices;
class Program
{
[DllImport("libTest", CallingConvention = CallingConvention.StdCall, ExactSpelling = true)]
public static extern int TestFunction();
static void Main(string[] args)
{
Console.WriteLine("!!" + TestFunction());
}
}
Test.cpp compiled with mingw (see below):
#include <new>
#include <cstdlib>
#ifdef AddNewOperator // This will fix the issue
void* operator new[](std::size_t sz){
return std::malloc(sz);
}
#end
extern "C" {
int __stdcall __declspec(dllexport) TestFunction() {
int* test = new int[3]; // removing this line will make everything work when building
return test[2];
}
And here's the build script:
# Remove the following # and the compiled dll will work just fine
g++ -g -s -Wall -c -fmessage-length=0 Test.cpp #-DAddNewOperator
g++ -g -shared -o libTest.dll *.o -Wl,--subsystem,windows
Edit: compiling everything for x86 instead of 64 bit also fixes the issue (which is again no option for me)
TL;DR
You must not mix allocation / deallocation between compilers!
The problem you are facing is quite tricky and actually your program should crash every time, with or without the void* operator new[](size_t){...} definition.
If you debug your program, it actually should crash while deleting your test variable. This variable is created using mingw's new operator, but deleted using MSVC delete operator, and they are not interoperable. So you have to use mingw's delete function.
for a simple test you can just do:
c++ code:
int* test = nullptr;
int __stdcall __declspec(dllexport) TestFunction() {
test = new int[3]; // note test is global
return test[2];
}
void __stdcall _declspec(dllexport) CleanUp() {
delete[] test;
}
c# code:
public static extern int TestFunction();
public static extern int CleanUp();
static void Main(string[] args)
{
Console.WriteLine("!!" + TestFunction());
CleanUp();
}
Why is your program not crashing if you redefine the new operator?!
I actually don't know for sure, but i think, the malloc implementation of mingw uses legacy C runtime which uses HeapAlloc for allocating and HeapFree for deleting your test variable. In short, you are simply lucky/unlucky it is not crashing when you custom defined your operator new and used malloc inside...
However, if you compile it using Visual Studio, both (dll and exe) are using the same runtime, so allocation/deallocation is done within the same memory space organizer. BUT still it is UB and you will run into problems! E.g.: If you create your libary with msvc10 and want to use this library with msvc14 same can happen here! I can remember some issues with code coming from a bug where the memory also was managed wrong; We used a library created with msvc11 but our code was compiled with msvc12...
I've coded a wrapper for CryptoPP which would be used by c# app.
My issue is that when calling to a specific function in my wrapper using PInvoke, throws an exception "Attempted to read or write protected memory...".
Both of them are compiled as x64.
Now.. strange part is that if i compile my wrapper using /MTd or /MDd runtime, the call does not fail and everything works perfectly. But changing the runtime to /MT or /MD would throw the above exception.
I cannot use the /MTd or /MDd option for official use by my customers, as it requires lots of dlls resources to be installed or distributed into the user machine.
cpp code:
extern "C" __declspec(dllexport) int CryptBlock(bool mode, unsigned char type, unsigned char *inData, unsigned char *outData, int dataLen, unsigned char *key, int keyLen);
c# PInvoke:
[DllImport("mydll.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
public static extern int CryptBlock(bool mode, byte type, IntPtr inData, IntPtr outData, int dataLen, IntPtr key, int keyLen);
I have tried modifying my P/Invoke code in various ways:
[In, Out], [Out], ref, ref byte[], byte[] etc... still throwing the exception.
Waiting for my savior...
Thank you.
You are right that you cannot distribute the debug runtime, but in fact the issue is not quite what you think. The license does not permit redistribution of the debug runtime.
The most likely explanation is in fact that your code has a defect. The fact the the defect does not manifest with the debug runtime is simply down to chance. So the correct way to proceed is to track down your defect and fix it.
Consider using a bridge between Managed and Unmanaged code.
It can be debug more easily...
Example:
C++ Unmanaged code:
class ExampleCpp
{
private:
int id;
public:
ExampleCpp();
~ExampleCpp();
const int getId();
};
C++ Managed Code:
public ref class ExampleManagedCpp
{
private:
ExampleCpp* pImpl;
public:
ExampleManagedCpp();
~ExampleManagedCpp();
!ExampleManagedCpp();
};
http://www.codeproject.com/Articles/868230/Cplusplus-CLI-Accessing-a-managed-type-from-unmana
http://blogs.msdn.com/b/soultech/archive/2010/07/27/cli-c_2b002b00_-to-c_2300_-hello-world.aspx
This question already has answers here:
A call to PInvoke function has unbalanced the stack when including a C DLL into C#
(3 answers)
Closed 10 years ago.
I have an unmanged C++ dll that I have written and tested. The unmanged code woks fine when built and run in an unmanged console app. The function declaration is shown below.
#ifndef IMPORT_MYLIB
# define MYLIB_API __declspec(dllexport)
#else
# define MYLIB_API __declspec(dllimport)
#endif
namespace gsod_data_parsing {
extern "C"
{
MYLIB_API int parse_raw_gsod_file_nocb(
const char *path,
int temp_threshold
);
}
}
I am trying to call this from a managed application. I declare the function in my C# file like this:
[DllImport("GSODDLL.dll")]
public static extern int parse_raw_gsod_file_nocb(
[MarshalAs(UnmanagedType.LPStr)] string path,
int temp_threshold
);
These functions are then being executed on a couple parallel tasks like shown below:
// Start a task - this runs on the background thread...
task1 = Task.Factory.StartNew(() =>
{
int t1 = parse_raw_gsod_file_nocb(filePaths[i], this._frostTemp);
return (t1 == 0);
}, this._tokenSource.Token);
It appears to run fine at first but then (I believe when the function has finished executing) I get the following error.
A call to PInvoke function 'Database
Creator!Database_Creator.Form1::parse_raw_gsod_file_nocb' 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.
I saw a similar question here but I don't quite understand the accepted answer.
Anyone have any ideas?
Thanks
So it turns out my problem was due to calling convention mismatch. According to this document the default calling convention in windows for C/C++ programs is Cdecl. Also, according to this document the default calling convention for PInvoke is StdCall. I originally did not specify any calling convention so it was defaulting to StdCall. Since these conventions specify how the stack is cleaned up after the function call, it makes sense that the error was being thrown at the end of the function's execution.
Changing my PInvoke declaration to this fixed my problem:
[DllImport("GSODDLL.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int parse_raw_gsod_file_nocb(
[MarshalAs(UnmanagedType.LPStr)] string path,
int temp_threshold
);
I'm having real troubles trying to use a c++ callback in C# and any help from you would be really appreciated.
The first thing that the code do is to create an event:
uEvent = CreateEvent(NULL, true, false, "EventName");
After that, I've got that c++ function that implements a callback in c++:
int RegisterCallback(TCallbackType CallbackType, void *pLLTProfileCallback, void *pUserData)
The CallbackType is used to specify a stdcall. Then, the pLLTProfileCallback would be the name of the function to call, and finally, the user data.
With that function, I'm able to make a callback to another function by typing the following:
RegisterCallback(STD_CALL, (void*)FunctionName, 0)
Where the other function is:
void __stdcall FunctionName(const unsigned char* pucData, unsigned int uiSize, void* pUserData)
And then, I've got the code to wait for the event:
WaitForSingleObject(uEvent, 1000)
My problem comes when I try to do that in C#. The first thing I do is import the RegisterCallback Function from the dll:
[DllImport(DRIVER_DLL_NAME, EntryPoint = "s_RegisterCallback",CallingConvention = CallingConvention.StdCall)]
internal static extern int RegisterCallback(uint pLLT, TCallbackType CallbackType, IntPtr pLLTProfileCallback, IntPtr pUserData);
But then, I don't know how to proceed. Could you please help me?
Delegates in C# which is equivalent to C++ callback.
Please refer to MSDN Introduction & Syntax and usage for same
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.