I want to use PInvoke to bring to managed side something this:
(C code)
typedef struct{
//some fields...
} A;
type struct{
A* a;
} B;
int getB(B* destination){ //destionation will be an output parameter to C#
//puts an B in 'destination'
return 0;
}
Now, I need a way to tell managed side how to marshalling B from C to C# structure or class. I've tryed many things such as IntPtr fields, MarchalAs atributes, but with no success. I will not expose here the code that I've tryed to keep the question simple. However i could do it as long answers arrive.
If it were me, I would just use unsafe code and use pointers on the C# side:
public unsafe class UnmanagedStuff {
public struct A {
// some fields
}
public struct B {
public A* a;
}
// Add appropriate PInvoke attribute here
public static extern int getB(B* destination);
public static void UseBForSomething() {
B b;
getB(&b);
// Do something with b
}
}
You can do that using the Marshal class.
// Define a C# struct to match the unmanaged one
struct B
{
IntPtr a;
}
[DllImport("dllName")]
extern int getB(IntPtr destination);
B GetB()
{
IntPtr ptrToB = IntPtr.Zero;
getB(ptrToB);
return (B)Marshal.PtrToStructure(ptrToB, typeof(B));
}
Related
I have a c++ struct as follow:
struct Vehicle
{
u32 something;
Info *info;
u8 something2[ 0x14 ];
Vector3f location;
Template* data;
};
struct Info
{
u32 speed;
std::string name;
BuffCollection** buffCollection;
void* sectionPtr;
};
struct Template
{
u32 templateID;
};
From this question, I figured out the meaning of the u32, u8, and so on, or so I think I did.
Then I tried to make my own C# struct out of it:
[StructLayout(LayoutKind.Sequential)]
public struct Vehicle
{
public uint Something;
public Info Info;
public byte Something2;
public Vector3f Location;
public Template Data;
}
[StructLayout(LayoutKind.Sequential)]
public struct Info
{
public uint Speed;
public string Name;
public byte[] BuffCollection;
public IntPtr SectionPointer;
}
[StructLayout(LayoutKind.Sequential)]
public struct Template
{
public uint TemplateId;
}
public struct Vector3f
{
public float X, Y, Z;
public Vector3f(float x, float y, float z)
{
X = x;
Y = y;
Z = z;
}
}
However, when I try to read the Vehicle:
[DllImport("Core.dll")]
static extern Vehicle GetVehicle();
static void Main()
{
var vehicle = GetVehicle();
Console.WriteLine(vehicle.Info.Name);
Console.ReadKey();
}
I get the following error:
System.Runtime.InteropServices.MarshalDirectiveException: Method's type signature is not PInvoke compatible
From the search I did on it, it lead me to believe that my structure conversion is wrong.
What is wrong with my converted structures?
Regarding structures:
Vehicle.Info is a pointer, so you need to declare it as IntPtr Info, and then use Marshal.PtrToStructure / Marshal.StructureToPtr to read/write its value in managed code;
Vehicle.something2 is a byte array, not a byte, so you need to declare it this way:
[MarshalAs(UnmanagedType.ByValArray, SizeConst=20)]
byte[] something2=new byte[20];
Vehicle.Data - see #1, the same problem
Info.Name - .NET does not provide marshalling for std::string, so you will either need to write your own marshaler (see this: Custom Marshaler for PInvoke with std::string) or change the type to something like char* in your c++ library.
Info.BuffCollection should also be an IntPtr or BuffCollection[] (depending on what the BuffCollection type is about - it's not provided in your question)
Regarding the signature and invocation of GetVehicle(); method:
it is likely that the method returns the pointer to the structure, not the structure itself (just speculating, please double check). If so, you need to declare it as
static extern IntPtr GetVehicle();
and then use Marshal.PtrToStructure to convert it to your structure like this:
var vehiclePtr=GetVehicle();
var vehicle = (Vehicle)Marshal.PtrToStructure(vehiclePtr, typeof(Vehicle));
I have an unmanaged DLL that exports only a C style factory method that returns a new instance of a class (simplified here to look simple).
hello.h
#if defined(HWLIBRARY_EXPORT) // inside DLL
# define HWAPI __declspec(dllexport)
#else // outside DLL
# define HWAPI __declspec(dllimport)
#endif
struct HelloWorld{
public:
virtual void sayHello() = 0;
virtual void release() = 0;
};
extern "C" HWAPI HelloWorld* GetHW();
hello.cpp
#include "hello.h"
struct HelloWorldImpl : HelloWorld
{
void sayHello(){
int triv;
std::cout<<"Hello World!";
std::cin>>triv;
};
void release(){
this->HelloWorldImpl::~HelloWorldImpl();
};
HelloWorld* GetHW(){
HelloWorld* ptr = new HelloWorldImpl();
return ptr;
};
Now, I can use dllimport to access GetHW() but is there a way to access the member functions of the returned 'struct'... ie, sayHello and release?
I was also stuck with the same problem. This question was asked a while before. I commented to it for any better solution but didn't get any reply yet. So, reposting it.
When i googled, able to find out two solutions.
Solution1: Expose all the member functions in the C-style for the existing dll. Which i cant do, as it is a 3rd party dll.
Solution2: Write a managed C++ dll exposing the functionality of native C++ dll, which later can be used in your C# dll. Here many classes/functions are present. So, creating would take most of the time.
i got the above solutions from the link below.
How To Marshall
Please let me know if there is any better solution other than the above two solutions?
i have the source code for C++ solution. But what i though was not to touch C++ dll. If there is any possibility to do it in C#, it would be great.
If there is no alternative, i need to follow any one of the specified two solutions.
The C++ code is using the way abstract classes are implemented by the Visual C++ compiler. http://blogs.msdn.com/b/oldnewthing/archive/2004/02/05/68017.aspx. This memory layout is "fixed" because it is used for implementing COM interfaces. The first member of the struct in memory will be a pointer to a vtable containing the function pointers of your methods. So for a
struct HelloWorldImpl : public HelloWorld
{
public:
int value1;
int value2;
}
the "real" layout in memory would be:
struct HelloWorldImpl
{
HelloWorldVtbl *vtbl;
int value1;
int value2;
}
where vtbl would be:
struct HelloWorldVtbl
{
void *sayHello;
void *release;
}
Just for the sake of doing a complete response, I'm writing the example for this signatures:
struct HelloWorld {
public:
virtual int sayHello(int v1, int v2, int v3) = 0;
virtual void release() = 0;
};
C# code:
[DllImport("NativeLibrary.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr GetHW();
[StructLayout(LayoutKind.Sequential)]
struct HelloWorldVtbl
{
public IntPtr sayHello;
public IntPtr release;
}
Your functions are void Func(void) or int Func(int, int, int), but in truth they have a hidden parameter, this, so you can write them as:
int sayHello(HelloWorld*, int, int, int);
void release(HelloWorld*);
so in C# the delegate is
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
public delegate int Int32MethodInt32Int32Int32(IntPtr ptr, int v1, int v2, int v3);
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
public delegate void VoidMethodVoid(IntPtr ptr);
Then you can use
IntPtr ptr = GetHW();
IntPtr vtbl = Marshal.ReadIntPtr(ptr, 0);
HelloWorldVtblhw = (HelloWorldVtbl)Marshal.PtrToStructure(vtbl, typeof(HelloWorldVtbl));
Int32MethodInt32Int32Int32 sayHello = (Int32MethodInt32Int32Int32)Marshal.GetDelegateForFunctionPointer(hw.sayHello, typeof(Int32MethodInt32Int32Int32));
int res = sayHello(ptr, 1, 2, 3);
Console.WriteLine(res);
VoidMethodVoid release = (VoidMethodVoid)Marshal.GetDelegateForFunctionPointer(hw.release, typeof(VoidMethodVoid));
release(ptr);
int Set(CANMsg &CANObj)
I have to call the method above, from c#. Untill now i have defined a wrapper :
extern "C" __declspec(dllexport) int SetWrapper(CANMsg CANObj);
CANMsg CANObj --- is this parameter ok or should i use CANMsg *CANObj ?
and here i implement the wrapper:
extern "C" __declspec(dllexport) int SetWrapper(CANMsg CANObj)
{
return Set(CANObj);
}
I am creating this wrapper because this is an overloaded version of the function and i had to make a difference somehow.
Here is the CANMsg class:
class CANMsg
{
public:
CANMsg();
~CANMsg();
void AddRef() const;
void Release() const;
unsigned int MsgId;
unsigned int DLC;
unsigned int Handle;
unsigned int Interval;
unsigned int TimeStamp;
unsigned char Data0;
unsigned char Data1;
unsigned char Data2;
unsigned char Data3;
unsigned char Data4;
unsigned char Data5;
unsigned char Data6;
unsigned char Data7;
protected:
mutable int refCount;
};
Now, in C# i have the following :
[StructLayout(LayoutKind.Sequential)]
public class CANmsg
{
public int MsgId;
public int DLC;
public int Handle;
public int Interval;
public int TimeStamp;
public char Data0;
public char Data1;
public char Data2;
public char Data3;
public char Data4;
public char Data5;
public char Data6;
public char Data7;
}
and the import is like this :
[DllImport("engine.dll", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I4)]
public static extern int SetWrapper(IntPtr canMSGObject);
I am a bit confused about that CANMsg object, am I declaring it ok as an IntPtr, is the marshal ok, or the types ? If i let it like so, with the IntPtr, what kind of instantiation should i perform there? If i send a CANMsg object, i get an error regarding some invalid arguments.
Let me know if you need some more details about this.
When I see your C++ class definition, I ask myself "what happens in the constructor and the destructor?" and "what do AddRef() and Release() do?" These are important questions because you can't simply project data from a C# object onto that IntPtr and hope for the best. Instead, you should think about making a helper dll that does this work for you. You might need methods something like this:
public ref class MyLibraryHelper {
public:
IntPtr MakeCANMsg() { return gcnew IntPtr(new CANMsg()); }
void DestroyCANMsg(IntPtr msgPtr) {
CANMsg *msg = reinterpret_cast<CANMsg *>(msgPtr.ToPointer());
if (msg) delete msg;
}
void ProjectTo(CSharpCANMsg ^csh, IntPtr msgPtr)
{
CANMsg *msg = reinterpret_cast<CANMsg *>(msgPtr.ToPointer());
if (!msg) return;
msg->MsgId = csh->get_MsgId();
// etc
}
void ProjectFrom(IntPtr msgPtr, CSharpCANMsg ^csh)
{
CANMsg *msg = reinterpret_cast<CANMsg *>(msgPtr.ToPointer());
if (!msg) return;
csh->set_MsgId(msg->MsgId);
// etc
}
}
My C++/CLI is rusty, so expect some issues. If this looks like hand-marshalling, well, it is because given the class that you've exposed, it seems like you need it.
Now honestly, you probably don't want this. Really, you want a C++/CLI class that constructs a CANMsg and keeps it as a private member and then maps .NET properties onto the lower level object. This type of class will have to be disposable and the !ClassName() destructor will be responsible for deleting the underlying object.
You can not pass a C# object to native C++ like this. Marshal.StructureToPtr is what you need, the details and examples are here
I'd like to create Foo objects in C# from an unmanaged array of Foo structs created in C++.
This is how I think it should work:
On the C++ side:
extern "C" __declspec(dllexport) void* createFooDetector()
{
return new FooDetector();
}
extern "C" __declspec(dllexport) void releaseFooDetector(void* fooDetector)
{
FooDetector *fd = (FooDetector*)fooDetector;
delete fd;
}
extern "C" __declspec(dllexport) int detectFoo(void* fooDetector, Foo **detectedFoos)
{
FooDetector *fd = (FooDetector*)fooDetector;
vector<Foo> foos;
fd->detect(foos);
int numDetectedFoos = foos.size();
Foo *fooArr = new Foo[numDetectedFoos];
for (int i=0; i<numDetectedFoos; ++i)
{
fooArr[i] = foos[i];
}
detectedFoos = &fooArr;
return numDetectedFoos;
}
extern "C" __declspec(dllexport) void releaseFooObjects(Foo* fooObjects)
{
delete [] fooObjects;
}
On C# side:
(I ommitted some fancy code making it possible to call the C++ functions from within C# for better readability);
List<Foo> detectFooObjects()
{
IntPtr fooDetector = createFooDetector();
IntPtr detectedFoos = IntPtr.Zero;
detectFoo(fooDetector, ref detectedFoos);
// How do I get Foo objects from my IntPtr pointing to an unmanaged array of Foo structs?
releaseFooObjects(detectedFoos);
releaseFooDetector(fooDetector);
}
But I don't know how to retrieve the objects from the IntPtr detectedFoos. It should be possible somehow...
Any hints?
UPDATE
Let's assume, Foo is a simple detection rectangle.
C++:
struct Foo
{
int x;
int y;
int w;
int h;
};
C#:
[StructLayout(LayoutKind.Sequential)]
public struct Foo
{
public int x;
public int y;
public int width;
public int height;
}
Is it possible to read from unmanaged memory and create new managed objects from it before releasing the unmanaged memory?
I don't know how may Foo objects will be detected, so I don't know, how much memory to allocate in C# before calling detectFoo(). That's why I alloc/free memory in C++ and just pass a pointer to it. But somehow I can't retrieve the detectedFoos pointer address under C#. How do I do that?
You must re-declare Foo in your C# project. Assuming you know the count of Foos and the value of sizeof(Foo) you should be able to use System.Runtime.Interopservices.Marshal.PtrToStructure() to retrieve your Foo structures one at a time.
You have to define your struct again in C#, and it depends on your stuct. Your struct have to be blitable (the memory layout of the C# struct ave to be the same as it is for the C struct)
Have a look at "Marshalling structs"
Or post your real "Foo" struct and i can show you the C# version
UPDATE:
Because your struct seems to be blitable, you can simple cast the pointer to unmanaged memory to a pointer to the struct defined in c#:
If it is ok for your application to use unsafe code you can write:
unsafe List<Foo> detectFooObjects()
{
List<Foo> res = new List<Foo>()
IntPtr fooDetector = createFooDetector();
IntPtr detectedFoos = IntPtr.Zero;
int nNumFoos = detectFoo(fooDetector, ref detectedFoos );
for(int i=0;i<nNumFoos;i++)
{
Foo** ppDetectedFoos = detectedFoos.ToPointer();
Foo* pFoo = *ppDetectedFoos
res.Add(*pFoo); //copies the struct because is a struct
ppDetectedFoos++:
}
releaseFooObjects(detectedFoos);
releaseFooDetector(fooDetector);
return res;
}
I ended up solving my problem by using a C++/CLI wrapper class.
I suppose I have to create a managed C++ code to wrap the native C++. But I have the problem while trying to wrap an array used in function parameter whose type is defined in native C++. The native C++ code is as follows:
//unmanageCPP.h
class __declspec(dllexport) unmanageMoney
{
public:
unmanageMoney(int a, int b) { rmb = a; dollar = b; }
unmanageMoney() { rmb = 0; dollar = 0; }
int rmb;
int dollar;
};
class __declspec(dllexport) unmanageSum
{
public:
//how to wrap this funciton?
int addDollar(unmanageMoney a[], unmanageMoney b[]);
};
//unmanageCPP.cpp
#include "unmanaged.h"
int unmanageSum::adddollar(unmanageMoney a[], unmanageMoney b[])
{
return a[0].dollar + b[0].dollar;
}
Could anyone tell me how to write the manageCPP.h? Thanks very much!
Update
I compose the manageCPP.h as follows, but I don't know how to write addDollar()
//first, I wrap the class unmanageMoney for use in manageSum::addDollar()
public ref class manageMoney
{
private:
unmanageMoney* mMoney;
public:
unmanageMoney getMoney()
{
return *mMoney;
}
manageMoney(int a, int b) { mMoney = new unmanageMoney(a, b); }
~manageMoney() { delete mMoney; }
};
public ref class manageSum
{
// TODO: Add your methods for this class here.
private:
unmanageSum *mSum;
public:
manageSum()
{
mSum = new unmanageSum();
}
~manageSum()
{
delete mSum;
}
//it must be wrong if I code like this, for unmanageSun::adddollar() only
// receives unmanageMoney as arguments. So what should I do?
int adddollar(manageMoney a[], manageMoney b[])
{
return mSum->adddollar(a, b);
}
};
You create a C++/CLI source file with
public ref class SomethingOrOther
{
//...
};
and set the compile options to use the /clr option.
Beyond that, it's almost the same as writing native C++. You'll #include the header file for the class you want to reuse, create instances and call their member functions, just the same as normal C++. But anything inside that ref class will be visible to C#.
And you do NOT put __declspec(dllexport) on the class. Not ever. It's useful for functions, but creates misery when used with classes.