Bill Walton
Bill Walton

Reputation: 823

Passing C# struct to C++/CLI for C++ wrapper

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?

Upvotes: 1

Views: 4408

Answers (1)

J.N.
J.N.

Reputation: 8431

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++.

Upvotes: 1

Related Questions