Pointer reset once method called second time - c#

Can someone explain why the head and tail is reset to null once second IsAMatch is call even though id pass new pointers to it, the old ones get reset.
I have equivalent script on c++ and it works perfectly.
Any ideas ?
my code
small code example here it prints 10,20 so the second call changes first struct
class Program
{
static unsafe void Main(string[] args)
{
MyStruct* myStruct = null;
ChangeMe(ref myStruct, 10);
Console.WriteLine(myStruct->num);
MyStruct* myStruct2 = null;
ChangeMe(ref myStruct2,20);
Console.WriteLine(myStruct->num);
Console.ReadKey();
}
public static unsafe void ChangeMe(ref MyStruct* h, int v)
{
MyStruct myStructNew = new MyStruct(v);
h = &myStructNew;
}
public unsafe struct MyStruct
{
public int num;
public MyStruct(int n)
{
num = n;
}
}
}

You are basically returning a pointer to a local variable, which is plain wrong.
There is a difference in C# new keyword and C++ new keyword, or rather between it's interaction with class and struct in C#. In C++, new always means allocation on the heap, which you need to manually dealocate. In C#, new call on class means heap allocation, but new call on struct just initializes local variable.
This C# code:
MyStruct myStructNew = new MyStruct(v);
is equivalent to this C++ code
MyStruct myStructNew{v};
C# struct keyword creates a value type, which means in your case it gets allocated on the stack. Then, after return from ChangeMe, the stack is decremented, deallocating local variables. On second call, stack is incremented again, allocating local variables for the second call. As you are calling the same method, the same stack position will be used for the second MyStruct myStructNew.

Related

Memory allocated with C++ and Marshall to C#

What happens when I allocate memory (structs within double pointer) in C++ and use it via Marshall with C#?
Do I have to clean up the memory or does the C# GarbageCollection do it for me? Marshall.FreeHGlobal(vsResult); doesn't work.
[StructLayout(LayoutKind.Sequential)]
public struct MyCppResults
{
[MarshalAs(UnmanagedType.I4)] public int ResultSize;
public unsafe double* Result;
}
[DllImport("SomeVeryFastAlgorithm.dll")]
public static extern double[] LoadResults()
{
var resultsPtr = GetResults();
var vsResult = Marshal.PtrToStructure<MyCppResults>(resultsPtr);
var resultMatrix = new double[vsResult.ResultSize];
unsafe
{
for (var i = 0; i < resultMatrix.Length; i++)
resultMatrix[i] = vsResult.Result[i];
}
return resultMatrix;
}
As Marshall.FreeHGlobal notes, this works in conjunction with AllocHGlobal. It doesn't work in conjunction with C++ new[].
The memory allocated by new[] is almost certainly allocated by the C++ Standard Library (if not, it's owned by a user-defined override). This must be returned by delete[].
You can call back from C# to C++ to tell it to call delete[]. A logical location would be the C# destructor (finalizer).

Getting address of a struct

Here is my code:
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;
using System;
using System.IO;
public class CarMove : MonoBehaviour
{
public unsafe struct TrafficRoadSystem { };
public unsafe struct CarsSimulation { };
public unsafe struct CarPostion
{
double position_x;
double position_y;
double position_z;
};
// Use this for initialization
[DllImport("Assets/traffic.dll", CharSet = CharSet.Ansi)]
public unsafe static extern int traffic_import_osm([MarshalAs(UnmanagedType.LPStr)] string osm_pbf_path, TrafficRoadSystem** out_road_system);
[DllImport("Assets/traffic.dll")]
public unsafe static extern int create_simulation(TrafficRoadSystem* road_system, CarsSimulation** out_simulation, double speed, int cars_count);
[DllImport("Assets/traffic.dll")]
public static extern void update_simulation(ref CarsSimulation simulation, double time);
[DllImport("Assets/traffic.dll")]
public static extern CarPostion get_car_postion(ref CarsSimulation simulation, int car_number);
unsafe CarsSimulation* carSimulation;
unsafe TrafficRoadSystem* trafficRoadSystem;
void Start()
{
unsafe
{
string osmPath = "Assets/Resources/map.osm.pbf";
int results;
results = traffic_import_osm(osmPath, &trafficRoadSystem);
}
}
// Update is called once per frame
void Update()
{
}
}
This is from dll C library. Function int traffic_import_osm() works on TrafficRoadSystem* trafficRoadSystem; object as reference and I want to have in access to object in void Update(). This works well in one function but I cannot get address of a class variable and I get error
Error CS0212 You can only take the address of an unfixed expression inside of a fixed statement initializer
in line results = traffic_import_osm(osmPath, &trafficRoadSystem);
I try to use this solution
https://msdn.microsoft.com/en-us/library/29ak9b70(v=vs.90).aspx
I wrote this:
TrafficRoadSystem trafficRoadSystem;
void Start()
{
unsafe
{
string osmPath = "Assets/Resources/map.osm.pbf";
CarMove carMove = new CarMove();
int results;
fixed( TrafficRoadSystem* ptr = &carMove.trafficRoadSystem)
{
results = traffic_import_osm(osmPath, &ptr);
}
}
}
and I get error CS0459 Cannot take the address of a read-only local variable in line
results = traffic_import_osm(osmPath, &ptr);
Making a C or C++ plugin in Unity requires extensive knowledge of these languages. This means you should spend time learning pointers before attempting to use raw pointer in Unity. Because even if you get it to compile, you may also run into hard to fix crashes.
You have:
unsafe TrafficRoadSystem* trafficRoadSystem;
and want to pass it to the function below:
public unsafe static extern int traffic_import_osm(..., TrafficRoadSystem** out_road_system);
1.The trafficRoadSystem variable is a pointer and you will need to make another pointer that points to trafficRoadSystem. This is called "pointers to pointer"
TrafficRoadSystem** addressOfTrafficRoadSystem = &trafficRoadSystem;
Notice the double "**".
2.You must use fixed keyword to do what I mentione in #1.
fixed (TrafficRoadSystem** addressOfTrafficRoadSystem = &trafficRoadSystem)
{
}
3.You can pass that pointer to pointer address to the traffic_import_osm function.
The whole new Start function:
void Start()
{
unsafe
{
fixed (TrafficRoadSystem** addressOfTrafficRoadSystem = &trafficRoadSystem)
{
string osmPath = "Assets/Resources/map.osm.pbf";
int results;
results = traffic_import_osm(osmPath, addressOfTrafficRoadSystem);
}
}
}
Unrelated possible future issues:
1.I noticed that you did CarMove carMove = new CarMove(); in your updated question. Don't use the new keyword here because CarMove inherits from MonoBehaviour. See this answer for what to do.
2.I also noticed you used "Assets/Resources/map.osm.pbf";. This path will be invalid when you build your project. Consider using the StreamingAssets folder instead of the Resources folder which only works with the Resources API. You use Application.streamingAssetsPath with the StreamingAssets folder.
An alternative to using raw Pointers is to use Marshalling. Marshalling allows you to take C# data structures and transform them to C-understandable data without the need of any unsafe-keywords.
Mono has a document describing how to properly interact with native libraries using PInvoke (which is the search term you're looking for).
Here, here and here you can also find an introduction into PInvoke and Marshalling.
Basically you replace the pointer signatures with the IntPtr-type, which is a managed version of a pointer. To transform your managed struct variable you'll first need to allocate a memory region and use it for your struct
IntPtr ptr;
TrafficRoadSystem _struct;
try {
ptr = Marshal.AllocHGlobal(Marshal.SizeOf(_struct));
Marshal.StructureToPtr(_struct, ptr, false);
} finally {
Marshal.FreeHGlobal(ptr);
}
I don't know how to properly deal with double pointers though..

Pointer of a C# object for unmanaged interop

I am currently writing a wrapper for the PhysFS library, and I stumbled across a bit of troubles regarding the marshalling of managed objects. Take for example the PHYSFS_enumerateFilesCallback method, which takes a function pointer and a user-defined pointer as its arguments. How can I pass managed objects to this method? This is what I am currently doing:
// This is the delegate signature
public delegate void EnumFilesCallback(IntPtr data, string origdir, string fname);
// This is the method signature
[DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
public static extern void PHYSFS_enumerateFilesCallback(string dir, EnumFilesCallback c, IntPtr d);
Finally, this is what I'm doing to pass an arbitrary object to the method:
// I use the unsafe keyword because the whole Interop class is declared so.
// This code was taken from https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.gchandle(VS.71).aspx
public static void EnumerateFilesCallback(string dir, EnumFilesCallback c, object data)
{
unsafe
{
GCHandle objHandle = GCHandle.Alloc(data);
Interop.PHYSFS_enumerateFilesCallback(dir, c, (IntPtr)objHandle);
objHandle.Free();
}
}
When I run this code:
static void Enum(IntPtr d, string origdir, string fname )
{
System.Runtime.InteropServices.GCHandle handle = (System.Runtime.InteropServices.GCHandle)d;
TestClass c = (TestClass)handle.Target;
Console.WriteLine("{0} {1}", origdir, fname);
}
static void Main(string[] args)
{
PhysFS.Init("");
PhysFS.Mount("D:\\", "/hello", true);
TestClass x = new TestClass() { a = 3, b = 4 }; // This can be any gibberish object
PhysFS.EnumerateFilesCallback("/hello/", Enum, x);
}
The delegate gets called 4 times with legit data, the fifth time it contains garbage data and then it throws an AccessViolationException
I suspect this is because the object gets GCed in between the calls to the delegate. Can anyone shed light on this?
UPDATE: Changing the mounted directory eliminates the rubbish data, yet the exception is still thrown, and still before all the data can be consumed
Have you tried to create the callback and store it as a class static field?
private static EnumFilesCallback callback = new EnumFilesCallback(Enum);
And in your main method:
PhysFS.EnumerateFilesCallback("/hello/", callback, x);
This should probably avoid the GC to collect the local variable holding the delegate object.
Thanks to everyone who invested their time trying to provide an answer! I've finally found the source of the problem and solved it!
The problem was... I am a bit ashamed of it... calling convention.
All the PInvoked methods were declared as cdecl while I forgot to declare the delegates as such, so it created unbalanced stacks and mayhem and whatnot...

Safe and Correct Struct Marshalling

Unmanaged and Managed Memory Regions
I am attempting to execute unmanaged code from a C-library. One of the methods takes a void* as a parameter but under the hood it's cast to a struct of type nc_vlen_t
C struct for nc_vlen_t
/** This is the type of arrays of vlens. */
typedef struct {
size_t len; /**< Length of VL data (in base type units) */
void *p; /**< Pointer to VL data */
} nc_vlen_t;
Executing the method is correct and it works, I am concerned more about the pinning and safe handling of managed and unmanaged memory regions. I want to be as certain as possible that I am not going to cause memory leaks or a SEGFAULT. I wrote a struct that will be marshalled to and from the nc_vlen_t when I execute the C-library method calls.
C# struct
[StructLayout(LayoutKind.Sequential)]
public struct VlenStruct {
public Int32 len;
public IntPtr p; // Data
}
The struct consists of a size_t that indicates the array length and a void * to the data. Inside the library it has attributes that allow it to cast the (void*) to the appropriate numeric types and I've had great success with that so far.
What I want to understand is the best way to handle the memory regions. After reading some articles and other SO questions this is my best guess for how to handle it. I have a class that acts as an arbiter for creating and managing the structs and their memory. I rely on a destructor to free the handle which will unpin the array so that the GC can do it's job.
C# Vlen Helper
public class Vlen {
private GCHandle handle;
private VlenStruct vlen_t;
public Vlen() {
isNull = true;
}
public Vlen(Array t) {
isNull = false;
handle = GCHandle.Alloc(t, GCHandleType.Pinned); // Pin the array
vlen_t.len = t.Length;
vlen_t.p = Marshal.UnsafeAddrOfPinnedArrayElement(t, 0); // Get the pointer for &t[0]
}
~Vlen() {
if(!isNull) {
handle.Free(); // Unpin the array
}
}
public VlenStruct ToStruct() {
VlenStruct retval = new VlenStruct();
retval.len = vlen_t.len;
retval.p = vlen_t.p;
return retval;
}
private bool isNull;
}
C Method Declaration
//int cmethod(const int* typep, void *data)
// cmethod copies the array contents of the vlen struct to a file
// returns 0 after successful write
// returns -1 on fail
[DllImport("somelib.dll", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true, CallingConvention=CallingConvention.Cdecl)]
public static extern Int32 cmethod(ref Int32 typep, ref VlenStruct data);
If I use this class to create the struct is there a possibility that the GC will clean the array before the C-library is called in this situation:
C# Use-case
{
double[] buffer vlenBuffer = new double[] { 0, 12, 4};
Vlen data = new Vlen(vlenBuffer); // The instance now pins buffer
VlenStruct s = data.ToStruct()
Int32 type = VLEN_TYPE;
cmethod(ref type, ref s);
}
Is it possible for the data instance to be cleaned and thereby unpin buffer which could cause unpredictable behavior when executing the external library method?
Yes, you certainly have a problem here. As far as the jitter is concerned, the lifetime of your "data" object ends just before the ToStruct() method returns. Check this answer for the reason why. Which permits the finalizer to run while your unmanaged code is running. Which unpins your array. It would actually take another garbage collection to corrupt the data that the unmanaged code uses. Very rare indeed but not impossible. You are not likely to get an exception either, just random data corruption.
One workaround is to extend the lifetime of the Vlen object beyond the call, like this:
Vlen data = ...
...
cmethod(ref type, ref s);
GC.KeepAlive(data);
Which works but doesn't win any prizes, easy to forget. I would do this differently:
public static void CallHelper<T>(int type, T[] data) {
var hdl = GCHandle.Alloc(data, GCHandleType.Pinned);
try {
var vlen = new nc_vlen();
vlen.len = data.Length;
vlen.data = hdl.AddrOfPinnedObject();
cmethod(ref type, ref vlen);
}
finally {
hdl.Free();
}
}
Usage:
var arr = new int[] { 1, 2, 3 };
CallHelper(42, arr);
Which, beyond avoiding the early collection problem, also keeps the array pinned as short as possible. Do note that ref on the first argument of this function is pretty strange, you would not expect this function to alter the data type.

Calling a C DLL from a C# Program

I need to pass a pointer to a structure to my DLL, any ideas how would I go about doing that?
In my C DLL:
typedef struct
{
int length;
unsigned char *value;
} Sample;
__declspec(dllexport) void __stdcall helloWorld( Sample *sample );
In my C# code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace CSharpConsole
{
class Program
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
private struct Sample
{
public Int32 length;
// What Should I Declare Here?
}
[DllImport("C:\\CTestDLL.dll")]
private static extern void helloWorld( Sample sample ); // How would I make this a pointer?
void HelloWorld()
{
Sample sample = new Sample();
sample .length = 20;
// How can I fill up the values of value?
helloWorld( sample ); // How should I pass it inside here
return;
}
static void Main(string[] args)
{
Program program = new Program();
program.HelloWorld();
}
}
}
To pass a pointer to a value type into a P/Invoke function just declare the parameter as a ref or out. This implicitly takes a reference to the parameter and passes that:
[DllImport("C:\\CTestDLL.dll")]
private static extern void helloWorld(ref Sample sample);
Since your structure has an array in it, you'll have to take care to declare it properly for this to work. I strongly recommend, if possible, that you turn it into a fixed-length array, as it will make the marshaler much, much happier:
typedef struct
{
int length;
unsigned char value[MAX_LENGTH];
} Sample;
This becomes:
public struct Sample
{
int length;
[MarshalAs(UnmanagedType.LPArray, SizeConst = MAX_LENGTH)] byte[] value;
}
If that is not possible, then the runtime has no way of knowing how much data to marshal back; in that case, you probably will have to resort to manual marshaling of your data:
public struct Sample
{
int length;
IntPtr value;
}
var sample = new Sample();
helloWorld(ref sample);
byte[] value = new byte[sample.length];
Marshal.Copy(sample.value, value, 0, sample.Length);
However, based on your comment to another answer, it looks like you just need to get a block of bytes out of the C DLL into C#. For that you don't really need a structure at all, and eliminating it would simplify things a lot. If you just want to pass in an array and have it filled in and returned to you, try something like this:
(This assumes you have control over both C and C# code bases; if not then the ref suggestion is the way to accomplish what you need.)
// In C# code:
[DllImport(#"C:\CTestDll.dll")]
private static extern void helloWorld(
int length,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] byte[] buffer);
byte[] buffer = new byte[1024 * 8];
helloWorld(1024 * 8, buffer);
// In C:
__declspec(dllexport) void __stdcall helloWorld(int, unsigned char *);
void helloWorld(int cb, unsigned char *buf)
{
memcpy(buf, DATASRC, cb);
}
In C, an unsigned char is, by definition, the same size as a C# byte - 8 bits, no sign. In C#, a char is actually two bytes. The runtime will automatically "convert" an unsigned char * to a byte[] for you. (There's not really a conversion at all; they are just different names for the same type.)
Default Marshaling for Value Types - gives some information on marshalling structs.
Calling Win32 DLLs in C# with P/Invoke - a little over half way down the page there's a table showing the type conversions between the standard unmanaged and managed types.
There are a few ways to pass around and convert the types.
As Michael Edenfield pointed out you can generally just use the ref keyword to indicate that a parameter should by passed by reference which is basically a pointer.
However sometimes things don't cooperate, particularly when it comes to strings or complex data types so this is where the IntPtr type comes in.
You have a couple of options for using IntPtrs.
You can create an IntPtr to a block of unmanaged memory of a specified size using:
IntPtr pointer = Marshal.AllocHGlobal(sizeOfBufferInBytes);
//Do stuff with the pointer
Marshal.FreeHGlobal(pointer); //Don't forget to release the memory
This is obviously a bit dangerous because you're manually allocating unmanaged memory.
You'll need to Marshal the data from the buffer back into a managed type, using something like Marshal.Copy(), Marshal.PtrToStructure(), Buffer.BlockCopy(), etc.
Alternatively you can create a managed object and pin it in memory while you need to, get a pointer to it and pass that to your method.
MyObject instance = new MyObject();
GCHandle gch = GCHandle.Alloc(instance, GCHandleType.Pinned);
importedMethod(gch.AddrOfPinnedObject()); //AddrOfPinnedObject() gives you an IntPtr
gch.Free(); //Release the pinned memory so the garbage collector can deal with it
This avoids the necessity for manually marshalling back to the correct data type but this is not always an option depending on the type of MyObject and whether it's blittable.
This works for me:
DLL:
typedef struct
{
int length;
unsigned char *value;
} Sample;
extern "C" __declspec(dllexport) void __stdcall helloWorld( Sample *sample )
{
MessageBoxA(NULL, (LPCSTR) sample->value, (LPCSTR) sample->value, 0);
}
C#:
class Program
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
private class Sample
{
public Int32 length;
public String value;
}
[DllImport("C:\\Users\\Kep\\Documents\\Visual Studio 2010\\Projects\\SODLL\\Debug\\DLL.dll")]
private static extern void helloWorld(Sample sample);
static void Main(string[] args)
{
Sample s = new Sample();
s.length = 10;
s.value = "Huhu";
helloWorld(s);
}
}
Important thing is to mark it as a class, not a struct in C#.
With this, you could also use constructors etc. in C#:
class Program
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
private class Sample
{
public Int32 length;
public String value;
public Sample(String s)
{
length = s.Length;
value = s;
}
}
[DllImport("C:\\Users\\Kep\\Documents\\Visual Studio 2010\\Projects\\SODLL\\Debug\\DLL.dll")]
private static extern void helloWorld(Sample sample);
static void Main(string[] args)
{
Sample s = new Sample("Huhu");
helloWorld(s);
}
}

Categories