Frage

My code has 3 parts: c#, c++/cli, c++.

in c#, I have a struct. The struct is define to pass parameters.

//c#
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, Pack=1)]
public struct NDeviceDest
{
    public uint IP;

    public uint pos;
}

Then in c++/cli, I have a function which use the NDeviceDest

//c++/CLI
byte NDockMaster::Init(NDeviceDest pos, uint param)
{
    m_pDockMaster->Init(static_cast<DeviceDest*>pos, param);
}

*m_pDockMaster* is a pointer to native type.

The member function of Init is defined in c++ as ()

//c++
struct DeviceDest
{
UINT32          IP;     
unsigned int    pos;                                
};

class DockMaster
{
public:
    byte Init(DeviceDest* dest, UINT32 param)
    {
        return 0;
    }
}

DeviceDest is defined as the exact same as NDeviceDest, to pass parameters.

Question:

In my c++/cli code, I'm using *static_cast* to make the type change. but I got compiling error:

error C2440: 'static_cast' : cannot convert from 'NDeviceDest' to 'DeviceDest *'

I'm new to c++/cli, but I think there MUST be a way to let the compiler know that NDeviceDest is DeviceDest and let me code compile and pass value from c# to cli then to c++, but I searched a lot and didn't find the exact answer.

I did find some code, but it's using pointers not structs, I also tried using pointers, but I have same error.

Thanks

War es hilfreich?

Lösung

No, the compiler will not let you do this. Not even a C-style cast or reinterpret_cast<>() will work, the biggest weapons you have available.

This is for a very good reason, managed structs are quite incompatible with unmanaged structs. First issue is layout, the exact order and offset of the members of the struct. Which is technically the smaller problem, the CLR already makes an attempt at keeping them the same. Usually it is a match, not always. You'll find more details in this post.

The much bigger issue is storage, managed structs tend to be allocated at an address that can randomly change. A side-effect of having a garbage collector, one of its duties is not only release unused memory but also compact the heap. Very incompatible with the way your native code is going to use the pointer you pass, it is randomly going to dereference the struct at an incorrect address. Either because it released the enclosing object or because it moved it. Extraordinarily difficult to debug since it happens so rarely and is completely undeterministic since it depends on other managed threads that allocate.

So it just plain forbids it. A structure must be marshaled, copied into unmanaged memory and rearranged to match the native layout. The universal helper function is Marshal::StructureToPtr(). But quite unnecessary for such a small structure, it is much faster and simpler to copy the fields yourself:

  Byte Init(NDeviceDest pos, unsigned param) {
      DeviceDest unmanagedPos = { pos.IP, pos.pos };
      m_pDockMaster->Init(&unmanagedPos, param);
      //...
  }

Which fulfills the requirements, it has guaranteed the correct layout. And is allocated in stable memory, the GC doesn't mess with stack locations and memory is stable for the duration of the method body execution. In case it needs to be said, probably not, be sure that "DockMaster" doesn't store the passed pointer.

Andere Tipps

The error you are seeing is that static_cast is not allowed to cast (convert) from struct to struct *. The correct call in the c++/cli interface would therefore be

m_pDockMaster->Init(static_cast<DeviceDest*>(&pos), param);

If this is a class look-up problem and if you are using pointers and you are sure your marshaling is correct try using reinterpret_cast.

m_pDockMaster->Init(reinterpret_cast<DeviceDest*>pos, param);

But at a first glance you are trying to convert a non-pointer type to a pointer type . You should either use NDeviceDest* pos as input paramater or

m_pDockMaster->Init(static_cast<DevideDest*>&pos,param) .
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top