I'm marshalling a native C++ DLL to a C# DLL. I'm not very acknowledged in C/C++, but I've managed to make it work until I got stuck on this problem. Here's a very simplistic code example:
C++
PROASADLL __declspec(dllexport) void outTest(int* number){
int temp = *number + 10;
number = &temp; //*number = 12
}
C#
[DllImport("ProAsaNativeDll.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void outTest(ref int number);
public static int OutTest()
{
int number = 2;
outTest(ref number);
return number; //number = 2
}
Please notice that I'm my real scenario, I'm trying to get this to work with a pointer to pointer to struct but I decided to leave it out as it is not a marshalling issue; not even this simple code will work. The C++ code works but I wouldn't rule out being dumb and having a problem there: like I said, I don't know much C/C++.
The number variable value in the C# wrapper method won't change. Please help.
I think you are getting a bad result because in your C++ code you are actually changing the parameter number by setting it to another pointer.
I believe that your change will only be visible in your function outTest's scope.
However, if you change the value where the pointer ... points... that's should be a different story. Pretty much like this:
*number = *number + 10;
EDIT: This bit is not tested. Oh... and also... I haven't written anything in C++ for ages. Might as well be totally wrong.
Related
I have some c code which i didn't write which does some complicated things, and returns an array. I have been trying to use this code in a dynamic library in xamarin.mac to get this array from an extern function in my c# code, but with no success. I have read elsewhere that i should avoid using pointers in c# wherever possible, but I'm not sure how else i could do it.
My c# code is quite long but I'm using
[DllImport("librp_origin.dylib")]
static extern IntPtr counter(int number);
to import the function from the dll, and
private IntPtr number;
partial void go(NSObject sender)
{
golabel.StringValue = "Doing the thing. . .";
number = counter(2);
golabel.StringValue = string.Format("Thing returned {0}", number);
}
to attempt to access the array.
The c in the above is a simple example program which takes in an integer, and prints out a 20x20 array of that integer to the power x, and x increases each time. I know that printing out a whole pointer to the label is nonsense, but this is as close to the solution as i have. Any help whatsoever would be amazing !
I think i solved the problem in what i was doing, and i realise my question was quite vague. The main issue i had was i needed to use unsafe{} and Marshal.copy
The links i found most helpful were these:
http://www.tutorialspoint.com/csharp/csharp_unsafe_codes.htm
https://msdn.microsoft.com/en-us/library/ms146635(v=vs.110).aspx
So i needed to retrieve the pointer as IntPtr and then convert it to an array to actually access the data in the way i was using it.
I'm calling a c++ dll from my C# program. It appears that, once a variable is passed to unmanaged code, C# doesn't want anything to do with it, as a result my program is leaking memory like crazy.
Here's the C# part of the code:
byte[] bytes = MyData;
int array_lenght = bytes.Length;
DataProcessor(bytes, array_lenght);
DataProcessor is defined as
[DllImport("Processor", EntryPoint = "DataProcessor")]
public static extern void DataProcessor(byte[] array, int ArrayElementCount);
Here's the DLL side of the DataProcessor function:
void DataProcessor (uint8_t* InputArray, int ArrayElementCount)
// do some stuff here
Now it appears I need to delete this array(InputArray) from DLL, however I couldn't find a way to do that. I tried stuff like
delete *(InputArray + i) // inside a for loop
And mapping array to a vector like this and clearing it
std::vector<uint8_t> fckn_vector(InputArray, InputArray + ArrayElementCount);
fckn_vector.clear();
I'm 100% sure that there must be a very simple way to do this, however I'm not good with C++.
You can use the Marshal.FreeCoTaskMem method:
Marshal.FreeCoTaskMem(InputArray);
I have searched stackoverflow for this problem but didn't find this exact one. In particular, I've found a ton of questions regarding retrieving C++ string references (char**) when the C# side is managing the memory but not the other way around.
The situation is as follows. I have a DLL (written on VC++ 2012) which I wrote myself. It loads and parses data from files and then lets anyone using the DLL access this data (by actual direct memory access for performance reasons) in several ways. Any program in C++ using this DLL has obviously no problems doing that. C# as it seems does...
A bit of context:
The DLL provides exported functions accepting char** (arrays of char*) parameters whose elements are being set to memory locations in the DLL and then further processed by the DLL's user after the call.
An example might look like this (examplatory implementation):
int myFunction(char* dataArray[], int row)
{
for (int i= 0; i < _something; ++i)
{
dataArray[i] = _some_char_ptr
}
}
And this is what the callee's implementation might look like in C++:
char** data = new char*[__num_fields];
myFunction(data, __some_row);
for (int i= 0; i < __something; ++i)
{
cout << data[i] << endl;
}
Special - thus different from all questions I found - about this is that the callee allocates a list of char* which after the call point to memory locations allocated by the DLL itself.
Now, I must say, I'm only using C# because you can get quite simple GUIs in notime. The C# GUI tool I'm working on is for integrity testing data the DLL loads. I'm not profound of C# at all. What I've tried so far wasn't successful at all and I'm aware there might be no solution for this problem due to C# not having any sort of pointer concepts. Similar problems I found in Java while using JNA to load DLLs there which led to me not using Java for such testing purposes anymore.
Now a bit of C# stuff I've tried, incl. context:
public static class DLLTest
{
// delegate object for the function:
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate int MyFunction_Type(out string[] dataArray, int row);
public static MyFunction_Type MyFunction { get; private set; }
public static void Load()
{
IntPtr dllAddress = DllUtilities.LoadLibrary(#"__dll_path");
IntPtr procAddress = DllUtilities.GetProcAddress(dllAddress, "myFunction");
MyFunction = (MyFunction_Type)Marshal.GetDelegateForFunctionPointer(procAddress, typeof(MyFunction_Type));
}
}
I'm then calling the function like this:
string[] data = new string[__num_fields];
DLLTest.MyFunction(out data, __row)
Code similar to this using things like normal strings, integers, booleans whatsoever work like a charm. Just these string arrays keep bugging me :-)
Note: I can't change the way the DLL works because I wrote this for my boss and he's using it fine in both C++ and Delphi programs. It performs well and we're not about to change anything on the DLL itself as it really is fine the way it is.
Any help or clarification is highly appreciated, thanks a lot, Greetings
out string[] dataArray
is the wrong translation for the char** parameter. It should be:
IntPtr[] dataArray
The calling C# code then allocates the array before calling the function. Just as the C++ code does.
IntPtr[] data = new IntPtr[__num_fields];
int retval = DLLTest.MyFunction(data, __row);
You can then access the memory to your hearts content using the Marshal class to read the unmanaged memory behind the IntPtr pointers.
The calling convention looks a bit odd. As written, the C++ function is cdecl. As Hans says, there must also be some mechanism for the DLL to know how long the passed in array is.
I recieved some C/C++ code for use in another project. I put it into a DLL and then called the DLL from a C++ test harness. It worked fine and matched the results from when the code was just a function call.
However, I then tried to get the DLL to work from a C# application. I converted the test harness, and made the DLL call but I am recieving a stack overflow exception.
In C++ I added:
#include "proxy_rec_02.h"
#pragma comment(lib,"proxy_rec_02.lib")
And called the function like this:
proxy_rec_main(simtime,mx$gl,mz$gl,ry,start_dig,blytarg_on,blytarg,spread_on,last_call,outputs);
Where the header contains:
void DLL_EXPORT proxy_rec_main(double simtime, double mx$gl, double mz$gl, double ry, int start_dig,
int blytarg_on, double blytarg, int spread_on, int last_call, double *outputs);
In C# I'm using:
using System.Runtime.InteropServices;
and
[DllImport("proxy_rec_02.dll")]
unsafe static extern void proxy_rec_main(double simtime, double mxSgl, double mzSgl, double ry, int start_dig,
int blytarg_on, double blytarg, int spread_on, int last_call, ref double[] outputs);
With a function call like this:
proxy_rec_main(simtime,mxSgl,mzSgl,ry,start_dig,blytarg_on,blytarg,spread_on,last_call,ref outputs);
The DLL function is called many times in a for loop. The C++ code runs just fine. The C# code throws a stack overflow error. I added some debug statemaints to the proxy_rec_main function and it seems to hit each statement before the function returns. But it seems to throw the error on return from the function. Any insights would be welcome.
Thanks.
The CallingConvention property is missing from the [DllImport] declaration. There's no sign of you using __stdcall in the C declaration so CallingConvention.Cdecl is likely to be required. This can indeed cause an SO, the stack doesn't get cleaned-up.
Debug + Windows + Registers and observe the value of the ESP register before and after the call, it should be same. If you disabled the PInvokeStackImbalance managed debugger warning then be sure to turn it back on. Ignoring this warning is not a good idea.
And debug the native code, verify the passed argument values. There are so many arguments that a single bad declaration for one of them is enough to shoot the foot.
The ref double array seems problematic,
Add [MarshalAs] to it and pass IntPtr, not a double array.
.net arrays are not pointers, as they are in C++.
Mark that c# method as private,
wrap with public method that uses Marshal.Copy to transfer returned pointer to .net array.
Example for transferring array when allocated in .net:
[DllImport(EntryPoint="ExternalMethod"]
private static void ExternalMethodInvoke(
[MarshalAs(UnmanagedType.SysInt), In] IntPtr);
public void ManagedWrapper(ref double[] array)
{
IntPtr unmanagedMem = Marshal.AllocHGlobal(1000);
Marshal.Copy(array, unmanagedMem, 0, 1000);
ExternalMethodInvoke(unmanagedMem); // use try finally for freeing
Marshal.Copy(unmanagedMem, array, 1, 1000);
Marshal.FreeHGlobal(unmanagedMem);
}
Example for transferring array when allocated in native:
[DllImport(EntryPoint="ExternalMethod"]
private static void ExternalMethodInvoke(
[MarshalAs(UnmanagedType.SysInt), Out] out IntPtr);
[DllImport(EntryPoint="ExternalDeleteArray"]
private static void ExternalDeleteArrayInvoke(
[MarshalAs(UnmanagedType.SysInt), Out] out IntPtr);
public void ManagedWrapper(ref double[] array)
{
IntPtr unmanagedMem;
ExternalMethodInvoke(out unmanagedMem); // use try finally for freeing
Marshal.Copy(unmanagedMem, array, 1, 1000);
ExternalDeleteArrayInvoke(unmanagedMem);
}
If c# side allocates array, do not forget to allocate and deallocate in c#.
(using marshal's (de)allocate h global methods.)
In C++ allocates, call C++ method to deallocate.
Assuming the glue code is correct, it might just be that the DLL function takes up a lot of stack. I ran into a similar situation myself, and it turned out that there was some very large object allocated on the C++ stack. When called from native code, there was only a little bit stack used before the call so there was enough remaining space on the stack. When called from managed code, a lot of the stack was already consumed so that there wasn't enough space left. If you look at the C++ function that is causing the overflow, you may see that it is trying to put a large object on the stack.
I am importing some c++ dll into a c# project, I am using visual studio 2010. I have succeded to import function that are using built-in type, however I am getting error when I have tried to deal with structure. This is a simple example:
c++ code
typedef long int TDate;
typedef struct _TMDYDate
{
long month; /* In range [1,12] */
long day; /* In range [1-31] */
long year; /* In range [1600-] */
} TMonthDayYear;
int JpmcdsDateToMDY
(TDate date, /* (I) TDate format */
TMonthDayYear *mdyDate);
and I have translated to c# as:
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct TMonthDayYear {
public int month;
public int day;
public int year;
}
public partial class NativeMethods {
[System.Runtime.InteropServices.DllImportAttribute("MyDll.dll", EntryPoint="JpmcdsDateToMDY")]
public static extern int JpmcdsDateToMDY(int date, ref TMonthDayYear mdyDate) ;
}
when I try to run the function in my test program I get this error:
Unhandled Exception: System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt. at CsharpWrapper.NativeMethods.JpmcdsDateToMDY(Int32 date, TMonthDayYear& mdy Date)
The struct are declare in the stack and I thought (maybe) was the problem but I am still getting the same error even though I have change TMonthDayYear to class.
What am I doing wrong?
Thanks for you help.
You have to use the CallingConvention property in the [DllImport] attribute, this is Cdecl since you didn't use __stdcall in the native function declaration. While that's wrong, it is not a great explanation for the AV. You need to debug the C code, the AV suggests it has a pointer bug. Project + Properties, Debug, tick "Enable unmanaged code debugging" and set a breakpoint on the C function.
Frankly, a date conversion like this should be written in pure C#.
TDate type in native code is long int but in managed code it represented as int32 instead int64.
It may or may not be related, but you need the [OutAttribute] on the mdyDate parameter in order to write to it.
If you are an accustomed user in c++ you are probably familiar with pointers addressing the memory directly. Your error looks like a memory read/write protection related problem.
This is prohibited by standard nature of C# and u have to put the compiler in Unsafe mode.
If you code unsafe in c# u have to put code into unsafe mode.
unsafe
{
// unsafe things
}
unsafe class Class1 {}
static unsafe void someMethod ( int* cpi, int lngth) {...}
You also have to check the project configuration (Build-tab) and tack the checkbox for "Allow unsafe code".
I apologize if I was scrolling by some too obvious information. I will also state that this comment only has meaning if the situation is that C# going to address memory.