I am trying to pass a double array (its actually a std::vector, but converted at transfer) from a c++ dll into a c# script (unity).
Using the approach outlined here https://stackoverflow.com/a/31418775.
I can successfully get the size of the array printing on my console in unity however I am not able to use "CoTaskMemAlloc" to allocate memory for the array since I am using Xcode and it doesnt seem to have COM.
For a little more background this array is part of a control for a GUI, c++ creates it and the user edits with the c# GUI - so the plan is to be able to pass the array back to c++ when it has been edited.
C++ code
extern "C" ABA_API void getArray(long* len, double **data){
*len = delArray.size();
auto size = (*len)*sizeof(double);
*data = static_cast<double*>(CoTaskMemAlloc(size));
memcpy(*data, delArray.data(), size);
}
C# code
[DllImport("AudioPluginSpecDelay")]
private static extern void getArray (out int length,[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] out double[] array);
int theSize;
double[] theArray;
getArray(out theSize, out theArray);
If I leave out the code concerning the array, the int passes just fine. So I beleive the method to be the right one, its just getting around the lack of CoTaskMemAlloc.
You should be able to allocate memory in XCode using malloc and free it in C# using Marshal.FreeCoTaskMem. To be able to free it however, you need to have the IntPtr for it:
C++ code
extern "C" ABA_API void getArray(long* len, double **data)
{
*len = delArray.size();
auto size = (*len)*sizeof(double);
*data = static_cast<double*>(malloc(size));
memcpy(*data, delArray.data(), size);
}
C# code
[DllImport("AudioPluginSpecDelay")]
private static extern void getArray(out int length, out IntPtr array);
int theSize;
IntPtr theArrayPtr;
double[] theArray;
getArray(out theSize, out theArrayPtr);
Marshal.Copy(theArrayPtr, theArray, 0, theSize);
Marshal.FreeCoTaskMem(theArrayPtr);
// theArray is a valid managed object while the native array is already freed
Edit
From Memory Management I gathered that Marshal.FreeCoTaskMem would most likely be implemented using free(), so the fitting allocator would be malloc().
There are two ways to be really sure:
Allocate the memory in CLI using Marshal.AllocCoTaskMem, pass it to native to have it filled, and then free it in the CLI again using Marshal.FreeCoTaskMem.
Leave it as it is (native allocates memory with malloc()), but do not free the memory in CLI. Instead, have another native function like freeArray(double **data) and have it free() the array for you once CLI is done using it.
I am not an expert on Unity, but it seems that Unity relies on Mono for it's C# scripting support. Take a look at this documentation page:
Memory Management in Mono
We can assume from there that you will need to have platform-dependent code on your C++ side, you will need to use CoTaskMemAlloc/CoTaskMemFree in Windows and GLib memory functions g_malloc() and g_free() for Unix (like iOS, Android etc).
If you have control over all your code, C++ and C#, the easiest way to implement this would be to do all the memory allocation/deallocation in the C# script.
Sample code (untested):
//C++ code
extern "C" ABA_API long getArrayLength(){
return delArray.size();
}
extern "C" ABA_API void getArray(long len, double *data){
if (delArray.size() <= len)
memcpy(data, delArray.data(), delArray.size());
}
// C# code
[DllImport("AudioPluginSpecDelay")]
private static extern int getArrayLength();
[DllImport("AudioPluginSpecDelay")]
private static extern void getArray(int length,[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] double[] array);
int theSize = getArrayLength();
double[] theArray = new double[theSize];
getArray(theSize, theArray);
Related
I have a piece of C# program loading a dll function:
[DllImport("/Users/frk/Workspaces/MySharedLibrary.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto, EntryPoint = "MyCFunction")]
public static extern int MyFunction( [In][MarshalAs(UnmanagedType.I4)]MyFormat format, [In][MarshalAs(UnmanagedType.LPArray)] byte[] myString, [In][MarshalAs(UnmanagedType.I4)] int myStringLength, [MarshalAs(UnmanagedType.LPArray)] byte[] output, ref UIntPtr outputLength);
and calling it
int result = MyFunction(format, inPut, inputLength, outPut, ref outputLength);
on the C++ side, I have:
MyCPPFunction that works perfectly when called from a C test executable. That MyCPPFunction contains somewhere deep in its dependencies a global const variable declared and initialized in an anonymous namespace:
namespace
{
constexpr unsigned RandTileSize = 256;
std::array<unsigned, RandTileSize * RandTileSize> GenerateSamples()
{
std::array<unsigned, RandTileSize * RandTileSize> samples;
std::mt19937 rd(0);
std::uniform_int_distribution<unsigned> distribution(0, 255);
for (unsigned i = 0; i < RandTileSize * RandTileSize; ++i)
{
samples[i] = distribution(rd);
}
return samples;
};
const auto samples = GenerateSamples();<-- Option#1 this causes a stack overflow when loading the dll in C# environment
unsigned Sample(unsigned index)
{
static const auto samples = GenerateSamples();<-- Option#2 this works and dll loads correctly
return samples[index];
}
}
I am confused here since afaik, the option 1 should allocate memory in the code part of the dll, which the C# environment should deal with right ?
How can we have option #1 not to cause memory allocation problems while loading the dll ?
The lifetime of a static variable in a function within a DLL is from the first time the statement is encountered, to the time the DLL unloads.
The lifetime of a class or file scoped variable is from the time the DLL loads until the time the DLL unloads.
The consequence of this is that in the failing case, your initialisation code is running while the DLL is in the process of loading.
It is not generally a good idea to run nontrivial code in class constructors, as there are limits to what can safely be done inside the loader lock.
In particular if you perform any action which requires dynamically loading another DLL (such as LoadLibrary or calling a delay-load linked function) this is likely to cause difficult-to-diagnose issues.
Without diagnosing exactly what has gone wrong in your case the answer is simple: Use option2 or option 3.
Option 3:
void MyDLLInitialize(){
// Initialize the dll here
}
void MyDLLUninitialize(){
// Uninitialize the dll here
}
Then call these functions from C# before you use any other DLL function, and after you have finished with it, respectively.
I'm writing a simple .NET wrapper to C/C++ Pylon library for Basler cameras under linux (Ubuntu) in monodevelop. I'm building a .so (.dll) file in Code::Blocks and P/Invoke it in monodevelop.
I have two simple tasks: get a single image and get a sequence of images.
I managed the first part in this way:
in C++ i have a function:
void GetImage(void* ptr)
{
CGrabResultPtr ptrGrabResult;
//here image is grabbing to ptrGrabResult
camera.GrabOne(5000,ptrGrabResult,TimeoutHandling_ThrowException);
//i'm copying byte array with image to my pointer ptr
memcpy(ptr,ptrGrabResult->GetBuffer(),_width*_height);
if (ptrGrabResult->GrabSucceeded())
return;
else
cout<<endl<<"Grab Failed;"<<endl;
}
and in C#:
[DllImport("libPylonInterface.so")]
private static extern void GetImage(IntPtr ptr);
public static void GetImage(out byte[] arr)
{
//allocating unmanaged memory for byte array
IntPtr ptr = Marshal.AllocHGlobal (_width * _height);
//and "copying" image data to this pointer
GetImage (ptr);
arr = new byte[_width * _height];
//copying from unmanaged to managed memory
Marshal.Copy (ptr, arr, 0, _width * _height);
Marshal.FreeHGlobal(ptr);
}
and after that i can build an image from this byte[] arr.
I have to copy a huge amount of bytes twice (1. in c++ memcpy(); 2. in c# Marshal.Copy()). I tried to use a direct pointer to image buffer ptr = ptrGrabResult -> GetBuffer(), but get a mono environment error, when marshalling bytes.
So here is a question: is it a fine solution? Am i going in right direction?
P.S. Give me please some advices how should i manage with image sequence?
You can get the marshaller to do the work for you. Like this:
[DllImport("libPylonInterface.so")]
private static extern void GetImage([Out] byte[] arr);
....
arr = new byte[_width * _height];
GetImage(arr);
This avoids the second memory copy because the marshaller will pin the managed array and pass its address to the unmanaged code. The unmanaged code can then populate the managed memory directly.
The first copy looks harder to avoid. That is probably forced upon you by the camera library that you are using. I would comment that you should probably only perform that copy if the grab succeeded.
I am developing a C# dll project with C++ dll project.
Let's say that C++ dll logins to a certain web site, and do some query on the web server.
And C++ dll has to return that html code of a web site.
In the same time, C++ dll must save the cookie data from the web site.
So, I passed StringBuilder object to C++ function.
I already know how to get html code from a web site using HttpWebRequest and HttpWebResponse classed in C#, but unfortunately I have to do it in C++ dll project.
So bear in mind, I don't need any C# codes.
I have tried Passing a string variable as a ref between a c# dll and c++ dll.
Passing StringBuilder from C# and get it as LPTSTR.
It works fine, but some strings were missing from the result.
I couldn't find out the reason.
Anyway, here is my code.
C++
extern "C" __declspec(dllexport) BSTR LoginQuery(const char* UserID, const char* UserPW, char Cookies[])
{
std::string html;
try
{
std::map<std::string, std::string> cookies;
MyClass *myclass = new MyClass();
html = myclass->LoginQuery(UserID, UserPW, cookies);
// Response cookies
std::string cookieData;
for (std::map<std::string, std::string>::iterator iterator = cookies.begin(); iterator != cookies.end(); iterator++)
{
cookieData += iterator->first;
cookieData += "=";
cookieData += iterator->second;
cookieData += ";";
}
sprintf(Cookies, cookieData.c_str(), 0);
delete myclass;
}
catch (...)
{
}
return ::SysAllocString(CComBSTR(html.c_str()).Detach());
}
C#
[DllImport(#"MyDll.dll", EntryPoint="LoginQuery", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.BStr)]
private static extern void LoginQuery(string UserID, string UserPW, StringBuilder Cookies);
void SomeThing()
{
StringBuilder _cookies = new StringBuilder(1024);
string result = LoginQuery("test", "1234", _cookies);
}
It works fine.
With the StringBuilder as cookie, I can carry on the next url of the web site.
(I am using libcurl in C++ project.)
But the problem is that I have about 100 ids.
When it runs about 3~40, it returns heap error.
Debug Assertion Failed!
Program: ~~~~mics\dbgheap.c
Line: 1424
Expression: _pFirstBlock == pHead
I cannot click the abort, retry or ignore button.
It looks like C# application hangs.
I read so many articles about debug assertion failed with dbgheap.
Mostly like free memory object from another heap.
I am newbie to C++.
I read Edson's question on http://bytes.com/topic/c-sharp/answers/812465-best-way-interop-c-system-string-c-std-string.
But the error does not always comes out in certain time.
So I came across with a guess, that it happens when .NET runs garbage collector.
.NET garbage collector tries to free some memory which created from C++ dll and I get the heap error.
Am I right?
I think he's suffering same problem as mine.
What is the best way to avoid heap error and return correct string from C++ dll to C# dll?
P/S: And the heap error occurs only when I run it debug mode. I don't get the error when I run release mode.
EDIT
According to WhozCraig answer, I changed my code as below.
//return ::SysAllocString(CComBSTR(html.c_str()).Detach());
CComBSTR res(html.c_str());
return res.Detach();
But no luck, I still get the heap error.
Your question is title asks about passing a string reference from c# to c++, but later in the text you ask how to return a string from C++ to C#. Also, you tell you are new to C++. With this in mind, I'll tell how I did this sort of interaction last time I had to do that. I just made C++ side allocate and free all the memory, passing out to C# only IntPtrs to be Marshal.PtrToStringAnsi(p)ed. In my case, storing recerences thread-local in C++ and freeing them on each function call was enough, but you can make a C++ function that frees whatever ref it is given. Not very intellectual and not necessarily the most efficient way, but it works.
upd:
It does just what they say it does. Some quick googling comes up with this article. I think it's pretty good, so you can refer to it instead of my suggestion. Passing raw IntPtrs is good if the pointer is not okay to be freed by itself (like old Delphi/C++Builder style strings, for example) and you prefer to be bothered more on the managed side than on the native side.
As an example, piece of code doing Delphi interaction (good for C++ Builder as well):
// function Get_TI_TC(AuraFileName:PAnsiChar; var TI,TC:PAnsiChar):Boolean; stdcall; external 'AuraToIec104.dll' name 'Get_TI_TC';
[DllImport("AuraToIec104")]
[return: MarshalAs(UnmanagedType.I1)]
private static extern bool Get_TI_TC(string AuraFileName, out IntPtr TI, out IntPtr TC);
public static bool Get_TI_TC(string AuraFileName, out string TI, out string TC)
{
IntPtr pTI, pTC;
bool result = Get_TI_TC(AuraFileName, out pTI, out pTC);
TI = Marshal.PtrToStringAnsi(pTI);
TC = Marshal.PtrToStringAnsi(pTC);
return result;
}
It looks like your problem is rather simple. You are creating a StringBuilder that can hold as much as 1024 chars. If your C++ function returns more than that, your application will crash (sooner or later).
So to fix your problem, increase the StringBuilder's size to the maximum possible output length. More details: Passing StringBuilder to PInvoke function which quotes:
The only
caveat is that the StringBuilder must
be allocated enough space for the
return value, or the text will
overflow, causing an exception to be
thrown by P/Invoke.
It might actually be better in your case with dynamic string lengths to use a BSTR parameter in the C++ function. You can then use [MarshalAs(UnmanagedType.AnsiBStr), Out] ref string ... in C# and BSTR* in C++.
What I am trying to do is write a C# application to generate pictures of fractals (mandlebrot and julia sets). I am using unmanaged C++ with CUDA to do the heavy lifting, and C# for the user interface. When I try to run this code, I am not able to call the method I wrote in the DLL - I get an unhandled exception error for an invalid parameter.
The C++ DLL is designed to return a pointer to the pixel data for a bitmap, which is used by the .NET Bitmap to create a bitmap and display it in a PictureBox control.
Here is the relevant code:
C++: (CUDA methods omitted for conciseness
extern "C" __declspec(dllexport) int* generateBitmap(int width, int height)
{
int *bmpData = (int*)malloc(3*width*height*sizeof(int));
int *dev_bmp;
gpuErrchk(cudaMalloc((void**)&dev_bmp, (3*width*height*sizeof(int))));
kernel<<<BLOCKS_PER_GRID, THREADS_PER_BLOCK>>>(dev_bmp, width, height);
gpuErrchk(cudaPeekAtLastError());
gpuErrchk(cudaDeviceSynchronize());
cudaFree(dev_bmp);
return bmpData;
}
C#:
public class NativeMethods
{
[DllImport(#"C:\...\FractalMaxUnmanaged.dll")]
public static unsafe extern int* generateBitmap(int width, int height);
}
//...
private unsafe void mandlebrotButton_Click(object sender, EventArgs e)
{
int* ptr = NativeMethods.generateBitmap(FractalBox1.Width, FractalBox1.Height);
IntPtr iptr = new IntPtr(ptr)
fractalBitmap = new Bitmap(
FractalBox1.Width,
FractalBox1.Height,
3,
System.Drawing.Imaging.PixelFormat.Format24bppRgb,
iptr );
FractalBox1.Image = fractalBitmap;
}
Error:
************** Exception Text **************
Managed Debugging Assistant 'PInvokeStackImbalance' has detected a problem in 'C:\...WindowsFormsApplication1.vshost.exe'.
I believe the problem I am having is with the IntPtr - is this the correct method to pass a pointer from unmanaged C++ to a C# application? Is there a better method? Is passing a pointer the best method to accomplish what I am trying to do or is there a better way to pass the pixel data from unmanaged C++ w/ CUDA to C#?
EDIT:
From what I gather from the error I get when I debug the application, PInvokeStackImbalance implies that the signatures for the unmanaged and managed code don't match. However, they sure look like they match to me.
I feel like I'm missing something obvious here, any help or recommended reading would be appreciated.
You need to define the same calling convention in C and C#:
In C:
extern "C" __declspec(dllexport) int* __cdecl generateBitmap(int width, int height)
In C#:
[DllImport(#"C:\...\FractalMaxUnmanaged.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr generateBitmap(int width, int height);
Instead of cdecl you can also use stdcall, it only needs to be the same on both sides.
And handling my self a lot of managed/unmanaged code, I also advise you to pass the image array as an argument and do the memory allocation in C#. Doing so, you don't need to take care of manually freeing memory in managed world.
I'm exploring the idea of building a bridge between a DLL plugin for a 3rd party app and a C# app. I'm writing both the plugin DLL and the C# application. The plugin will be loaded into the 3rd party app and then I want to use call the plugin from C# to indirectly get data from the 3rd party app.
I am able to successfully call an exported function from the DLL from C#. For example:
C++ DLL:
extern "C" __declspec(dllexport) char * HelloFromDll()
{
char *result;
result = "Hello from my DLL";
return result;
}
C#:
using System.Runtime.InteropServices;
[DllImport(#"MyDll.dll")]
private static extern string HelloFromDll();
I can then call this DLL function from C# and display the string in the UI. However, as soon as I create an export function that calls a function from my 3rd party app, I get an AccessViolationException. For example,
extern "C" __declspec(dllexport) char * GetData()
{
char *result;
result = 3rdPartyLibrary::SomeFunction();
return result;
}
Through some testing, the error seems to occur as soon as I make a call to a 3rd party function. How can I fix this?
This function is very difficult to use in a C program as well. Returning strings from functions is a poorly supported scenario. There's a memory management problem, it isn't clear who owns the string. In most cases the caller is expected to take ownership of the string and free it after using it. That's not going to work out well for your function, the program will crash since you returned a string literal.
The .NET pinvoke marshaller needs to solve this problem as well. With the extra problem that it cannot use the allocator that's used by the C code. It is going to call CoTaskMemFree (the COM allocator). That causes an undiagnosable memory leak on XP, a crash on Vista and Win7.
Just don't write C code like this. Always let the caller pass the buffer for the string. Now there's no guessing who owns the memory. Like this:
extern "C" __declspec(dllexport) void HelloFromDll(char* buffer, int bufferSize)
{
strcpy_s(result, bufferSize, "Hello from my DLL");
}
With your C# code like this:
[DllImport("foo.dll", CharSet = CharSet.Ansi)]
private static extern void HelloFromDll(StringBuilder buffer, int bufferSize);
...
var sb = new StringBuilder(666);
HelloFromDll(sb, sb.Capacity);
string result = sb.ToString();
From your question it seems that this is the scenario:
ProcessA (3rd party App) --> loads X.DLL --> initializes the plugin --> does other stuff.
ProcessB (Your C# App) --> loads X.DLL --> calls GetData();
Does X.DLL loaded in ProcessA have any mechanism to talk to X.DLL loaded in ProcessB?
if not then this approach is flawed. Your code probbably crashes because "3rdPartyLibrary" class hasn't been initialised in your C# app as it is completely different copy of the DLL.
For you to extract this data you need a query interface defined by X.DLL which can talk across processes, maybe sockets?
Then ProcessB talks to this interface and extracts the data. if using sockets, then your X.DLL would implement both server and client code, where your GetData() would use this mechanism (maybe sockets) and query the data and return it.
So : X.DLL in ProcessA should act like a server.
And: X.DLL (or write a Y.DLL) in ProcessB should act like a client and get this information from ProcessA.
btw, if the query is only needed to be done once, just hard code this is in X.DLL and dump to disk, and then explore at your convinience :-)
Generally, a returned char* needs to be returned as an IntPtr:
[DllImport(#"MyDll.dll")]
private static IntPtr HelloFromDll();
Then, you'll need to convert that IntPtr into a string:
string retVal=Marshal.PtrToStringAnsi(HelloFromDll());
Strings are a bit difficult in P/Invoke. My general rule of thumb is:
Input char* parameter = c# string
Return char * = IntPtr (use PtrToStringAnsi)
Output char* parameter = c# StringBuilder - and be sure to pre-allocate it large enough
before (ie = new StringBuilder(size)) calling the function.