1

After posting a question yesterday I thought I had this cleared up but I'm still having problems, I have a C++/CLI wrapper for a C++ class, some functions of the C++ class take buffers for recv as parameters, the packet structures are defined as C++ structs and that is what is taken as a parameter.

In C# I have replicated these C++ structs using structlayout so that I have equivalent structs in C# which are laid out the same in memory as my C++ structs. In my C++/CLI code I attempted the following

UINT GetValues(value class^ JPVals) // value class, as C# structs are value types
{
IntPtr ptr;
Marshal::StructureToPtr(JPVals,ptr,false);
return m_pComms->GetValues(ptr,0); // m_pComms is a wrapped unmanaged class 
    //GetValues takes a pointer to a C++ struct
}

The error I get is cannot convert parameter 1 from 'System::IntPtr' to 'SJPVal *', why is it not possible to Marshall from value class to C++ struct pointer? And in this case what should I be passing in and how should I be marshalling it?

1
  • You should accept an answer for yesterday's question then. Commented Mar 6, 2012 at 8:02

1 Answer 1

1

You didn't get the serialization process:

// !! Note the % !!
UINT GetValues(value class% JPVals) // value class, as C# structs are value types 
{ 
    // Allocate a buffer for serialization, pointer to NULL otherwise
    IntPtr ptr = Marshal::AllocHGlobal(Marshal::SizeOf(JPVals));

    try {
        // Serialize the managed object to "static" memory (not managed by the GC)
        Marshal::StructureToPtr(JPVals, ptr, false); 

        // Pass it to unmanaged code that will modify it.
        auto ret = m_pComms->GetValues(reinterpret_cast<SJPVal*>(ptr.ToPointer()), 0);

        // Copies the modifications back
        Marshal::PtrToStructure(ptr, JPVals);

        // Free resources
        Marshal::FreeHGlobal(ptr);

        return ret;
    } catch (...) {
        // Make sure we free the memory
        Marshal.FreeHGlobal(ptr);
        throw; 
    }
} 

EDIT: shown how to copy back the value.

As you are using a C# struct you need to pass it by reference to make sure the changes are copied back. Alternatively, the code will work the same with a C# class. The first step (StructureToPtr) is probably useless, now, since you probably don't care about what was in there before your call to GetValues.

By the way your naming convention is a bit bad. You should NOT start variable names by a capital letter in C++.

Sign up to request clarification or add additional context in comments.

6 Comments

Stupid mistake : I meant don't start variable names with a capital letter, sorry, I have edited the answer.
I have one more question actually, the struct passed in is a buffer for a call to winsock recv(), and in the calling function the user needs to be able to pass in the struct then after the function call the struct will be filled with data, since the IntPtr is allocated memory in the function now will this still happen, can the IntPtr point to the same memory as the struct passed in?
No it can't, but you can copy it back using the converse function Marshal::PtrToStructure. I'll edit and show you how.
Please note the % in the argument list.
"The first step (StructureToPtr) is probably useless, now"...so how do I pass it into the C++ function if I no longer do the StructureToPtr?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.