Pinning an updateble struct before passing to unmanaged code? - c#

I using some old API and need to pass the a pointer of a struct to unmanaged code that runs asynchronous.
In other words, after i passing the struct pointer to the unmanaged code, the unmanaged code copies the pointer and returns immediately. The unmanaged code can access that struct in background, in another thread. I have no control over the unmanaged code that runs in another thread nor the thread itself.
The fixed { } statement can't be used for pinning because it not designed for async unmanaged pinning.
GCHandle can pin only references, so the struct must be boxed to use GCHandle. I tried it, and it works. The main problem with it, is that you can't update the struct from managed code. To update a struct, first of all we need to unbox it, then update, then box again, but... oops ... box again?!? this means the previous pointer in the memory still point to the old non-up-to-date struct, and the new struct have another pointer, and this means that i need to pass new pointer to the unmanaged code... inapplicable in my case.
How can i pin a struct in the memory without fixed { } statement, and so that i can update it from managed code without change it's pointer?
Thanks.
Edit:
Just thought... is there a way to pin the parent object that contains the struct, and then get the pointer of the struct rather than the container object?

Using pinned memory in this case is not a good idea, given that the memory for the struct needs to be valid for a long time. GCHandle.Alloc() will box the structure and store it on the heap. With it being pinned, it will be a long term burden to the garbage collector as it needs to constantly find a way around the rock in the road.
The simple solution is to allocate memory for the struct in unmanaged memory. Use Marshal.SizeOf() to get the size of the structure and Marshal.AllocCoTaskMem() to allocate the memory. That gets you the pointer you need to pass to the unmanaged code. Initialize the memory with Marshal.StructureToPtr(). And read updates to the structure written by the unmanaged code with PtrToStructure().
If you do this frequently, you'll be constantly copying the structure. That could be expensive, depending on the size of the structure. To avoid that, use an unsafe pointer to access the unmanaged memory directly. Some basic syntax:
using System;
using System.Runtime.InteropServices;
class Program {
unsafe static void Main(string[] args) {
int len = Marshal.SizeOf(typeof(Test));
IntPtr mem = Marshal.AllocCoTaskMem(len);
Test* ptr = (Test*)mem;
ptr->member1 = 42;
// call method
//..
int value = ptr->member1;
Marshal.FreeCoTaskMem(mem);
}
public struct Test {
public int member1;
}
}

Is unsafe code an option?
// allocate unmanaged memory
Foo* foo = (Foo*)Marshal.AllocHGlobal(sizeof(Foo));
// initialize struct
foo->bar = 0;
// invoke unmanaged function which remembers foo
UnsafeNativeMethods.Bar(foo);
Console.WriteLine(foo->bar);
// update struct
foo->bar = 10;
// invoke unmanaged function which uses remembered foo
UnsafeNativeMethods.Qux();
Console.WriteLine(foo->bar);
// free unmanaged memory
Marshal.FreeHGlobal((IntPtr)foo);
This compiles and doesn't throw an exception, but I don't have an unmanaged function at hand to test if it works.
From MSDN:
When AllocHGlobal calls LocalAlloc, it passes a LMEM_FIXED flag, which causes the allocated memory to be locked in place. Also, the allocated memory is not zero-filled.

Instead of pinning, you need to use Marshal.StructureToPtr and Marshal.PtrToStructure to marshal the struct into memory that's usable in native code.

Struct example:
[StructLayout(LayoutKind.Sequential)]
public struct OVERLAPPED_STRUCT
{
public IntPtr InternalLow;
public IntPtr InternalHigh;
public Int32 OffsetLow;
public Int32 OffsetHigh;
public IntPtr EventHandle;
}
How to pin it to the struct and use it:
OVERLAPPED_STRUCT over_lapped = new OVERLAPPED_STRUCT();
// edit struct in managed code
over_lapped.OffsetLow = 100;
IntPtr pinned_overlap_struct = Marshal.AllocHGlobal(Marshal.SizeOf(over_lapped));
Marshal.StructureToPtr(over_lapped, pinned_overlap_struct, true);
// Pass pinned_overlap_struct to your unmanaged code
// pinned_overlap_struct changes ...
// Get resulting new struct
OVERLAPPED_STRUCT nat_ov = (OVERLAPPED_STRUCT)Marshal.PtrToStructure(pinned_overlap_struct, typeof(OVERLAPPED_STRUCT));
// See what new value is
int offset_low = nat_ov.OffsetLow;
// Clean up
Marshal.FreeHGlobal(pinned_overlap_struct);

How about having the struct include an ActOnMe() interface and method something like:
delegate void ActByRef<T1,T2>(ref T1 p1, ref T2 p2);
interface IActOnMe<TT> {ActOnMe<T>(ActByRef<TT,T> proc, ref T param);}
struct SuperThing : IActOnMe<SuperThing>
{
int this;
int that;
...
void ActOnMe<T>(ActByRef<SuperThing,T>, ref T param)
{
proc(ref this, ref param);
}
}
Because the delegate takes a generic parameter by reference, it should be possible in most cases to avoid the overhead of creating closures by passing a delegate to a static method along with a reference to a struct to carry data to or from that method. Further, casting an already-boxed instance of SuperThing to IActOnMe<SuperThing> and calling ActOnMe<T> on it will expose the fields of that boxed instance for updating, as opposed to creating another copy of them as would occur with a typecast to the struct.

To answer your edit:
Just thought... is there a way to pin the parent object that contains the struct, and then get the pointer of the struct rather than the container object?
I think so. If anything, you should be able to with a managed array of structures (possibly an array of one).
Here is an example code:
[StructLayout(LayoutKind.Sequential)]
struct SomeStructure
{
public int first;
public int second;
public SomeStructure(int first, int second) { this.first=first; this.second=second; }
}
/// <summary>
/// For this question on Stack Overflow:
/// https://stackoverflow.com/questions/1850488/pinning-an-updateble-struct-before-passing-to-unmanaged-code
/// </summary>
private static void TestModifiableStructure()
{
SomeStructure[] objArray = new SomeStructure[1];
objArray[0] = new SomeStructure(10, 10);
GCHandle hPinned = GCHandle.Alloc(objArray, GCHandleType.Pinned);
//Modify the pinned structure, just to show we can
objArray[0].second = 42;
Console.WriteLine("Before unmanaged incrementing: {0}", objArray[0].second);
PlaceholderForUnmanagedFunction(hPinned.AddrOfPinnedObject());
Console.WriteLine("Before unmanaged incrementing: {0}", objArray[0].second);
//Cleanup
hPinned.Free();
}
//Simulates an unmanaged function that accesses ptr->second
private static void PlaceholderForUnmanagedFunction(IntPtr ptr)
{
int secondInteger = Marshal.ReadInt32(ptr, 4);
secondInteger++;
Marshal.WriteInt32(ptr, 4, secondInteger);
}
And its output:
Before unmanaged incrementing: 42
Before unmanaged incrementing: 43

Related

Converting std::vector to array an then p/Invoking it causes a Access Violation Exception in mscorlib.dll during marshalling

In C++ I have the following struct from 3rd-party code:
typedef struct NodeInfoTag
{
long lResult;
int bComplete;
char *pszNodeAddr;
char *pszParentAddr;
RTS_WCHAR *pwszNodeName;
RTS_WCHAR *pwszDeviceName;
RTS_WCHAR *pwszVendorName;
unsigned long ulTargetType;
unsigned long ulTargetId;
unsigned long ulTargetVersion;
unsigned short wMaxChannels;
}NodeInfotyp;
And the definition to RTS_WCHAR:
# ifndef RTS_WCHAR_DEFINED
# define RTS_WCHAR_DEFINED
typedef wchar_t RTS_WCHAR; /* wide character value */
# endif
(So it's basically a wchar_t)
Then I have my own class called CScanNetworkCallback, which extends the CPLCHandlerCallback class, a class from the same vendor:
.h file:
class CScanNetworkCallback : public CPLCHandlerCallback
{
public:
bool bScanComplete;
NodeInfotyp* pNodeInfo;
NodeInfotyp* pNodeInfoList;
std::vector<NodeInfotyp> vList;
CScanNetworkCallback();
virtual ~CScanNetworkCallback(void);
virtual long Notify(CPLCHandler *pPlcHandler, CallbackAddInfoTag CallbackAdditionalInfo);
};
The implementation follows their own guidelines with some of my own stuff thrown in:
CScanNetworkCallback::CScanNetworkCallback(void) : CPLCHandlerCallback()
{
bScanComplete = false;
}
CScanNetworkCallback::~CScanNetworkCallback()
{
delete pNodeInfo;
delete pNodeInfoList;
}
long CScanNetworkCallback::Notify(CPLCHandler *pPlcHandler, CallbackAddInfoTag CallbackAdditionalInfo)
{
if (pPlcHandler != NULL)
{
if (CallbackAdditionalInfo.ulType == PLCH_SCAN_NETWORK_CALLBACK)
{
pNodeInfo = CallbackAdditionalInfo.AddInf.pNodeInfo;
if (pNodeInfo->lResult == RESULT_OK)
{
vList.push_back(*pNodeInfo);
bScanComplete = false;
}
else
{
pNodeInfoList = &vList[0]; //New pointer points to the vector elements, which will be used as an array later on
// I have also tried copying it, to the same result:
//std::copy(vList.begin(), vList.end(), pNodeInfoList);
bScanComplete = true;
}
}
}
return RESULT_OK;
}
So basically, the Notify method in the class above is called every time a "node" is found in the network, assigning the node's information to pNodeInfo (please disregard what a node is, it isn't relevant ATM). Since it is called to every node in the network during the scanning process and I must send this information to C++, I couldn't find any other way to do so other than using a std::vector to store every callback info for latter use, as I don't know how many nodes there will be at compile time. The else part is called after all nodes have been found. In order to make sense out of the C# code, I must describe the implementation of some other C++ methods that are p/Invoked:
PROASADLL __declspec(dllexport) void scanNetwork(){
pScanHandler->ScanNetwork(NULL, &scanNetworkCallback);
}
The object scanNetworkCallback is static. pScanHandler is a pointer to another class from the 3rd party vendor and its ScanNetwork method runs on a separate thread. Internally (and I only know that due to this API Guidelines, I don't have its source code), it calls the Notify method whenever a node is found in the network, or something to that effect
And finally:
PROASADLL __declspec(dllexport) NodeInfotyp* getScanResult(int* piSize) {
*piSize = scanNetworkCallback.vList.size();
return scanNetworkCallback.pNodeInfoList;
}
That returns the pointer that points to all nodes' information and the amount in as an out parameter. Now let's take a look at the C# code:
public static List<NodeInfoTag> AsaScanNetworkAsync()
{
Console.WriteLine("SCANNING NETWORK");
scanNetwork(); // C++ Method
while (!isScanComplete()) // Holds the C# thread until the scan is complete
Thread.Sleep(50);
int size = 0;
IntPtr pointer = getScanResult(out size); // works fine, I get some IntPtr and the correct size
List<NodeInfoTag> list = Marshaller.MarshalPointerToList<NodeInfoTag>(pointer, size); // PROBLEM!!!
// Continue doing stuff
}
This is the class NodeInfoTag, to match the C++ NodeInfotyp struct:
[StructLayout(LayoutKind.Sequential)]
public class NodeInfoTag
{
public int Result;
public int Complete;
[MarshalAs(UnmanagedType.LPStr)] //char*
public string NodeAddress;
[MarshalAs(UnmanagedType.LPStr)] //char*
public string ParentAddress;
[MarshalAs(UnmanagedType.LPWStr)] //wchar_t
public string VendorName;
public uint TargetType;
public uint TargetId;
public uint TargetVersion;
public short MaxChannels;
}
And this is where I get my Memory Access Violation:
internal class Marshaller
{
public static List<T> MarshalPointerToList<T>(IntPtr pointer, int size)
{
if (size == 0)
return null;
List<T> list = new List<T>();
var symbolSize = Marshal.SizeOf(typeof(T));
for (int i = 0; i < size; i++)
{
var current = (T)Marshal.PtrToStructure(pointer, typeof(T));
list.Add(current);
pointer = new IntPtr(pointer.ToInt32() + symbolSize);
}
return list;
}
}
The error occurs specifically when marshaling should take place, at the line var current = (T)Marshal.PtrToStructure(pointer, typeof(T));. This C# code used to work just fine, but the C++ part was terrible, convoluted and error-prone, so I decided to make things more simple but I can't figure out for the life of me why I'm getting this Exception as I'm making sure that all C++ resources are available for C#, since for testing purposes, I don't delete anything in C++ and I'm only using variables with global scope within the class, which is allocated to static memory. So, what did I miss?
Edit: I removed pNodeInfoList = &vList[0]; and rewrote getScanResult as follows:
static NodeInfotyp pNodeInfoList;
//(...)
PROASADLL __declspec(dllexport) NodeInfotyp* getScanResult(int* piSize) {
*piSize = scanNetworkCallback.vList.size();
std::move(scanNetworkCallback.vList.begin(),
scanNetworkCallback.vList.end(), &pNodeInfoList);
return &pNodeInfoList;
}
No dice. I don't use new or malloc in any of the variables involved, and even changed pNodeInfoList (the array) from a class member to a global variable. Also, I'm using move, as I've been told, could be used to solve ownership problems. Any other tips?
Ownership is not part of the naive C++ type system, so you will not get an error when you delete a pointer you do not own or transfer ownership away without giving it up.
However, semantically certain values and pointers and data blocks are owned by certain types or values.
In this case the vector owns its block of memory. There is no way to ask it or make it give up ownership.
Calling .data() onky provides you a pointer, it does not give that pointer semantic ownership.
You store the return value of .data() in a member variable. You later call delete on that member variable. This indicates to me that member variable is supposed to own its data. So you double delete (as both the vector and the pointer think they own the data pointed to), and your compiler crashes the program for you.
You need to rewite your code taking into account liefetime and ownership of every block of memory you are working with. One approach is to never ever call new, malloc or delete or free directly, and always use memory managing types like vector and unique ptr. Avoid persisting raw pointers, as their ownership semantics are not clear from the type.

Exception when calling C++ function from managed code

Let's imagine C++ function in DLL:
typedef struct
{
int number;
void *list;
} clist_t;
extern "C" DLL_API clist_t GetItems(int a);
DLL_API clist_t GetItems(int a)
{
static clist_t list;
list.number = a;
list.list = sth();
return list;
}
And the C# code which calls this function:
[StructLayout(LayoutKind.Sequential)]
public struct CList
{
public int number;
public IntPtr ptr;
};
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate CList GetItemsDelegate(int a);
int func = Win32APIWrapper.GetProcAddress(m_dllHndl, "GetItems");
private GetItemsDelegate GeItemsFunc =
(GetItmsDelegate)Marshal.GetDelegateForFunctionPointer((IntPtr)func, typeof(GetItemsDelegate));
CList list = GetItemsFunc(12); // <--- here we got exception
The last function throws exception: "Attempted to read or write protected memory. This is often an indication that other memory is corrupt."
I noticed that removing second field in CList function causes exception to disappear and returned struct has correct value of number field.
So why the original code does not work? The alignment of structures seems to be correct. Also calling convention is properly set to cdecl.
Any ideas? Both types in struct are blittable, so there is no need to even marshal them (C# and dll are compiled to 32bit).
EDIT:
Why returning smaller struct does not throw exception? I noticed that struct smaller then 4 bytes are returned ok. On the other hand the same function but without parameters allows returning the original struct without exception.

C# ref is it like a pointer in C/C++ or a reference in C++?

I'm working with the ref and don't understand clearly "Is it like a pointer as in C/C++ or it's like a reference in C++?"
Why did I ask such a weak question as you thought for a moment?
Because, when I'm reading C#/.NET books, msdn or talking to C# developers I'm becoming confused by the following reasons:
C# developers suggest NOT to use ref in the arguments of a function, e.g. ...(ref Type someObject) doesn't smell good for them and they suggest ...(Type someObject), I really don't understand clearly this suggestion. The reasons I heard: better to work with the copy of object, then use it as a return value, not to corrupt memory by a reference etc... Often I hear such explanation about DB connection objects. As on my plain C/C++ experience, I really don't understand why to use a reference is a bad stuff in C#? I control the life of object and its memory allocations/re-allocations etc... I read in books and forums only advises it's bad, because you can corrupt your connection and cause a memory leak by a reference lose, so I control the life of object, I may control manually what I really want, so why is it bad?
Nowadays reading different books and talk to different people, I don't clearly understand is ref a pointer (*) or a reference like in C++ by & ? As I remember pointers in C/C++ always do allocate a space with a size of void* type - 4 bytes (the valid size depends on architecture), where hosts an address to a structure or variable. In C++ by passing a reference & there is no new allocations from the heap/stack and you work with already defined objects in memory space and there is no sub-allocating memory for a pointer externally like in plain C. So what's the ref in C#? Does .NET VM handle it like a pointer in plain C/C++ and its GC allocates temporary space for a pointer or it does a work like reference in C++? Does ref work only with a managed types correctly or for value types like bool, int it's better to switch an unsafe code and pass through a pointer in unmanaged style?
In C#, when you see something referring to a reference type (that is, a type declared with class instead of struct), then you're essentially always dealing with the object through a pointer. In C++, everything is a value type by default, whereas in C# everything is a reference type by default.
When you say "ref" in the C# parameter list, what you're really saying is more like a "pointer to a pointer." You're saying that, in the method, that you want to replace not the contents of the object, but the reference to the object itself, in the code calling your method.
Unless that is your intent, then you should just pass the reference type directly; in C#, passing reference types around is cheap (akin to passing a reference in C++).
Learn/understand the difference between value types and reference types in C#. They're a major concept in that language and things are going to be really confusing if you try to think using the C++ object model in C# land.
The following are essentially semantically equivalent programs:
#include <iostream>
class AClass
{
int anInteger;
public:
AClass(int integer)
: anInteger(integer)
{ }
int GetInteger() const
{
return anInteger;
}
void SetInteger(int toSet)
{
anInteger = toSet;
}
};
struct StaticFunctions
{
// C# doesn't have free functions, so I'll do similar in C++
// Note that in real code you'd use a free function for this.
static void FunctionTakingAReference(AClass *item)
{
item->SetInteger(4);
}
static void FunctionTakingAReferenceToAReference(AClass **item)
{
*item = new AClass(1729);
}
};
int main()
{
AClass* instanceOne = new AClass(6);
StaticFunctions::FunctionTakingAReference(instanceOne);
std::cout << instanceOne->GetInteger() << "\n";
AClass* instanceTwo;
StaticFunctions::FunctionTakingAReferenceToAReference(&instanceTwo);
// Note that operator& behaves similar to the C# keyword "ref" at the call site.
std::cout << instanceTwo->GetInteger() << "\n";
// (Of course in real C++ you're using std::shared_ptr and std::unique_ptr instead,
// right? :) )
delete instanceOne;
delete instanceTwo;
}
And for C#:
using System;
internal class AClass
{
public AClass(int integer)
: Integer(integer)
{ }
int Integer { get; set; }
}
internal static class StaticFunctions
{
public static void FunctionTakingAReference(AClass item)
{
item.Integer = 4;
}
public static void FunctionTakingAReferenceToAReference(ref AClass item)
{
item = new AClass(1729);
}
}
public static class Program
{
public static void main()
{
AClass instanceOne = new AClass(6);
StaticFunctions.FunctionTakingAReference(instanceOne);
Console.WriteLine(instanceOne.Integer);
AClass instanceTwo = new AClass(1234); // C# forces me to assign this before
// it can be passed. Use "out" instead of
// "ref" and that requirement goes away.
StaticFunctions.FunctionTakingAReferenceToAReference(ref instanceTwo);
Console.WriteLine(instanceTwo.Integer);
}
}
A ref in C# is equivalent to a C++ reference:
Their intent is pass-by-reference
There are no null references
There are no uninitialized references
You cannot rebind references
When you spell the reference, you are actually denoting the referred variable
Some C++ code:
void foo(int& x)
{
x = 42;
}
// ...
int answer = 0;
foo(answer);
Equivalent C# code:
void foo(ref int x)
{
x = 42;
}
// ...
int answer = 0;
foo(ref answer);
Every reference in C# is pointer to objects on heap as pointer in C++ and ref of C# is same as & in C++
The reason ref should be avoided is, C# works on fundamental that method should not change the object passed in parameter, because for someone who does not have source of method may not know if it will result in loss of data or not.
String a = " A ";
String b = a.Trim();
In this case I am confident that a remains intact. In mathematics change should be seen as an assignment that visually tells is that b is changed here by programmer's consent.
a = a.Trim();
This code will modify a itself and the coder is aware of it.
To preserve this method of change by assignment ref should be avoided unless it is exceptional case.
C# has no equvalent of C++ pointers and works on references. ref adds a level of indirection. It makes value type argument a reference and when used with reference type it makes it a reference to a reference.
In short it allows to carry any changes to a value type outside a method call. For reference type it allows to replace the original reference to a totally different object (and not just change object content). It can be used if you want to re-initialize an object inside a method and the only way to do it is to recreate it. Although I would try avoid such an approach.
So to answer your question ref would be like C++ reference to a reference.
EDIT
The above is true for safe code. Pointers do exist in unsafe C# and are used in some very specific cases.
This seems like a disposing/eventing nightmare. If I have an object who's events are registered for and pass it into a function by reference and that reference is then reallocated, the dispose should be called or the memory will be allocated until the program is closed. If the dispose is called everything registered to the objects events will no longer be registered for and everything it is registered for will no longer be registered for. How would someone keep this straight? I guess you could compare memory addresses and try to bring things back to sanity if you don't go insane.
in c# you can check run unsafe in your project properties
and then you can run this code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Exercise_01
{
public struct Coords
{
public int X;
public int Y;
public override string ToString() => $"({X}, {Y})";
}
class Program
{
static unsafe void Main(string[] args)
{
int n = 0;
SumCallByRefPointer(1, 2, &n);
Console.Clear();
Console.WriteLine("call by refrence {0}",n);
n = 0;
SumCallByValue(3, 4, n);
Console.WriteLine("call by Value {0}", n);
n = 0;
SumCallByRef(5, 6, ref n);
Console.WriteLine("call by refrence {0}", n);
Pointer();
Console.ReadLine();
}
private static unsafe void SumCallByRefPointer(int a, int b, int* c)
{
*c = a + b;
}
private static unsafe void SumCallByValue(int a, int b, int c)
{
c = a + b;
}
private static unsafe void SumCallByRef(int a, int b, ref int c)
{
c = a + b;
}
public static void Pointer()
{
unsafe
{
Coords coords;
Coords* p = &coords;
p->X = 3;
p->Y = 4;
Console.WriteLine(p->ToString()); // output: (3, 4)
}
}
}
}

Marshalling an array of strings from managed to native code

I have a managed function with the following declaration (both interface and implementation):
[return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_BSTR)]
String[] ManagedFunction()
{
String[] foo = new String[1];
foo[0] = "bar";
return foo;
}
There is also a native C++ interface with the same methods as the managed interface, inside of that interface, this method has the following declaration:
void ManagedFunction(SAFEARRAY* foo);
This function is called by native code in the following way:
void NativeFunction(ManagedBinding binding)
{
CComSafeArray<BSTR> cComSafeArray;
cComSafeArray.Create();
LPSAFEARRAY safeArray = cComSafeArray.Detach();
binding.comObject->ManagedFunction(safeArray);
}
I'm not sure what I'm doing wrong but after my managed function has been called, safeArray appears to have garbage values, somethings going wrong while marshalling the return value back to native code. Could someone with more experience than me with .Net interop please shed some light on this? Also, It might be relevant to mention that I haven't had problems with returning ValueTypes from my managed function (boolean if you're curious), something about returning a String array is messing things up. Thanks!
1) Your function return a SAFEARRAY, so why you allocate it before calling function?
2) ManagedFunction supposed to return a SAFEARRAY, so it should get a SAFEARRAY* to be able to return it! so you should say:
LPSAFEARRAY lpsa;
binding.comObject->ManagedFunction(&lpsa);
CComSafeArray<BSTR> cComSafeArray;
cComSafeArray.Attach(lpsa);
Well I finally got it to work. I created a managed representation of SAFEARRAY called ManagedSafeArray (stolen from here : http://social.msdn.microsoft.com/Forums/en-US/clr/thread/6641abfc-3a9c-4976-a523-43890b2b79a2/):
[StructLayout(LayoutKind.Sequential)]
struct ManagedSafeArray
{
public ushort dimensions; // Count of dimensions in the SAFEARRAY
public ushort features; // Flags to describe SAFEARRAY usage
public uint elementSize; // Size of an array element
public uint locks; // Number of times locked without unlocking
public IntPtr dataPtr; // Pointer to the array data
public uint elementCount; // Element count for first (only) dimension
public int lowerBound; // Lower bound for first (only) dimension
}
I changed the signature of my method to:
void ManagedMethod(ref ManagedSafeArray foo);
Inside my method, I manually updated the dataPtr field by calling Marshal.AllocCoTaskMem(...) and then copied over the strings I wanted the SAFEARRAY to contain.
I have no idea as to why the CLR wasn't able to automatically marshal the parameters to and from native code and I'd still appreciate it if someone could try to explain that.

How can I marshall a vector<int> from a C++ dll to a C# application?

I have a C++ function that produces a list of rectangles that are interesting. I want to be able to get that list out of the C++ library and back into the C# application that is calling it.
So far, I'm encoding the rectangles like so:
struct ImagePatch{
int xmin, xmax, ymin, ymax;
}
and then encoding some vectors:
void MyFunc(..., std::vector<int>& rectanglePoints){
std::vector<ImagePatch> patches; //this is filled with rectangles
for(i = 0; i < patches.size(); i++){
rectanglePoints.push_back(patches[i].xmin);
rectanglePoints.push_back(patches[i].xmax);
rectanglePoints.push_back(patches[i].ymin);
rectanglePoints.push_back(patches[i].ymax);
}
}
The header for interacting with C# looks like (and works for a bunch of other functions):
extern "C" {
__declspec(dllexport) void __cdecl MyFunc(..., std::vector<int>& rectanglePoints);
}
Are there some keywords or other things I can do to get that set of rectangles out? I found this article for marshalling objects in C#, but it seems way too complicated and way too underexplained. Is a vector of integers the right way to do this, or is there some other trick or approach?
The STL is a C++ specific library, so you cant directly get it across as one object to C#.
The one thing that is guaranteed about std::vector is that &v[0] points to the first element and all the elements lie linearly in memory (in other words, its just like a C array in terms of memory layout)
So marshal as array of int... which shouldn't be hard - There are lot of examples on the web.
Added
Assuming you only pass the data from C++ to C# :
C# cannot handle a C++ vector object, so do not try passing it by reference : Instead your C++ code must return a pointer to an array of ints...
If you are not going to be using this function from multiple threads, you can use static storage :
int *getRects(bool bClear)
{
static vector<int> v; // This variable persists across invocations
if(bClear)
{
v.swap(vector<int>());
}
else
{
v.clear();
// Fill v with data as you wish
}
return v.size() ? &v[0] : NULL;
}
call getRects(true) if the returned data is significant in size, so you release the memory in v.
For simplicity, instead of passing out the size of the vector data too, just put a sentinel value at the end (like say -1) so the C# code can detect where the data ends.
Yes. You can. Actually, not just std::vector, std::string, std::wstring, any standard C++ class or your own classes can be marshaled or instantiated and called from C#/.NET.
Wrapping a std::vector<any_type> in C# is indeed possible with just regular P/Invoke Interop, it is complicated though. even a std::map of any type can be done in C#/.NET.
public class SampleClass : IDisposable
{
[DllImport("YourDll.dll", EntryPoint="ConstructorOfYourClass", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.ThisCall)]
public extern static void SampleClassConstructor(IntPtr thisObject);
[DllImport("YourDll.dll", EntryPoint="DestructorOfYourClass", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.ThisCall)]
public extern static void SampleClassDestructor(IntPtr thisObject);
[DllImport("YourDll.dll", EntryPoint="DoSomething", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.ThisCall)]
public extern static void DoSomething(IntPtr thisObject);
[DllImport("YourDll.dll", EntryPoint="DoSomethingElse", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.ThisCall)]
public extern static void DoSomething(IntPtr thisObject, int x);
IntPtr ptr;
public SampleClass(int sizeOfYourCppClass)
{
this.ptr = Marshal.AllocHGlobal(sizeOfYourCppClass);
SampleClassConstructor(this.ptr);
}
public void DoSomething()
{
DoSomething(this.ptr);
}
public void DoSomethingElse(int x)
{
DoSomethingElse(this.ptr, x);
}
public void Dispose()
{
if (this.ptr != IntPtr.Zero)
{
// The following 2 calls equals to "delete object" in C++
// Calling the destructor of the C++ class will free the memory allocated by the native c++ class.
SampleClassDestructor(this.ptr);
// Free the memory allocated from .NET.
Marshal.FreeHGlobal(this.ptr);
this.ptr = IntPtr.Zero;
}
}
}
Please see the below link,
C#/.NET PInvoke Interop SDK
(I am the author of the SDK tool)
Once you have the C# wrapper class for your C++ class ready, it is easy to implement ICustomMarshaler so that you can marshal the C++ object from .NET.
http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.icustommarshaler.aspx
I'm pretty sure you can't do this. You have to be able to translate the C++ code directly to a C# class, so you would at least have to replicate the internals of the vector class to marshall it correctly. I'm also pretty sure you won't be able to move references across the boundary, you'll have to use IntPtr (raw pointers). The approach that i know works is to marshall a raw array of the structs.

Categories

Resources