Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conversion from void* to object in C#

In a C# project, I need to pass object parameters by putting references in a structure. i.e. I have a structure passed to a dispatcher

struct SOMESTRUCT
{
    public int lpObject;
}

Where lpObject holds a pointer to a custom object like

class SomeClass
{
    private string foo;
}

And the SOMESTRUCT structure is passed from method to method to finally reach my code. I cannot modify the execution flow nor the strange SOMSTRUCT system, so I guessed the only solution was to cast my object to a pointer like this :

var myObject = new SomeClass();
GCHandle GC = GCHandle.Alloc(myObject, GCHandleType.Pinned);
int myRef = GC.AddrOfPinnedObject().ToInt32();
GC.Free();

SOMESTRUCT struct;
struct.lpObject = myRef;
someMethod(struct);

However, I can't figure out how to retrieve the myObject members from the lpObject fields. Something like this:

SomeClass myObject = CastPointerToObject(struct.myRef) as SomeClass;

Is there a way to do it, or is it impossible ? How can I tell the garbage collector to handle the object ? Should I create a new Garbage-collected object and copy the data field by field ?

TYIA,

like image 548
slaphappy Avatar asked Jun 29 '10 14:06

slaphappy


2 Answers

no No NO NO NO!!!

This

struct SOMESTRUCT
{
    public SomeClass object_ref;
}

Is the correct way to store a reference in a struct.

The code you have written, and the accepted answer, are 100% broken.

The address returned by GC.AddrOfPinnedObject(GCHandle) is only valid while the GCHandle is intact. You must not call GCHandle.Free, and you must not let the GCHandle get collected. In your code, the address is already meaningless by the time you store it.

But you should just let .NET take care of managing the pointer during garbage collection, by using a variable of reference type. Then you don't need to jump through hoops. The only reason to take the address of a managed object is when passing it to an existing native DLL function that will save the pointer after it returns. For example, it's necessary with OpenGL buffer arrays. It is NOT necessary, ever, when calling other C# methods.

If SOMESTRUCT is actually a native data type used by some DLL function you haven't mentioned, then you'll need to make sure to keep the GCHandle alive. Only as long as the GCHandle exists will the pointer you got remain valid.

like image 58
Ben Voigt Avatar answered Oct 08 '22 15:10

Ben Voigt


Do you mean you want to cast the returned pointer back to a struct?

Similar to:

lvHitTestInfo = (LVHITTESTINFO)Marshal.PtrToStructure(lP, typeof(LVHITTESTINFO));

Where lvHitTestInfo is a structure and lp a pointer.

Or i didn't understand your question properly. Maybe you can explain more (more complete code sample).

like image 24
Jeroen Avatar answered Oct 08 '22 16:10

Jeroen