views:

2741

answers:

1

I'm creating a C++/CLI wrapper DLL that depends on numerous C++ static libraries. Some of the function calls expect unmanaged pointers to be passed in. How do i pass them properly?

Also, other functions expect a "this pointer" to be passed in as a void*. What's the right way to pass "this"?

Here's my class definition...

public ref class RTPClient
{
 public:
  RTPClient();
  ~RTPClient();

  bool Connect();
  void Disconnect();

 private:
  CIsmaClient* mClient;
};

Here's my usage where the pointers in question are used...

RTPClient::RTPClient():
 mClient(NULL)
{
 CIsmaClient::Create(&mClient, NULL, &AllocBuffer, &GetDataPointer, this);
}

The usage of &mClient and "this" cause the following compiler errors... 1>.\VBLoadSimulatorDll.cpp(40) : error C2664: 'CIsmaClient::Create' : cannot convert parameter 1 from 'cli::interior_ptr' to 'CIsmaClient **' 1> with 1> [ 1> Type=CIsmaClient * 1> ]

1>.\VBLoadSimulatorDll.cpp(40) : error C2664: 'CIsmaClient::Create' : cannot convert parameter 5 from 'VBLoadSimulator::RTPClient ^const ' to 'VOID *'

+3  A: 

If you are passing a pointer to a managed class then it is easy to convert the ^ reference into a pointer but you must pin the managed object so that the GC doesn't move it about in memory (thus invalidating the pointer)

This is simple with pin_ptr

However your code is doing two things which won't work

RTPClient::RTPClient():
        mClient(NULL)
{
    CIsmaClient::Create(
        &mClient,          // 1
        NULL, 
        &AllocBuffer, 
        &GetDataPointer, 
        this);            //2
}

1) You are trying to take the address of something on the managed heap (the location of the pointer to the pointer mClient is on the managed heap.

As such it can move in memory, thus the compiler supplier interior pointer (whose value is maintained over GC operations). This needs to be pinned and this will only work if the Create function does not expect to use the pointer after it's scope has ended (if it passes it anywhere else to store it this will lead to bugs).

2) You are passing a handle (the funny hat symbol) rather than a pointer. (Read the wikipedia section on these they are a good overview) This is not (and cannot) be understood by the unmanaged code.

The only reason I can think of for this parameter in this context is as an explicit state variable passed to subsequent function callbacks (correct me if I'm wrong). 'this' in this context is NEVER going to work properly since this can move about in memory once the pin_ptr goes out of scope.

With that in mind here is a (partially) corrected implementation making it clear what can and can't be fixed.

RTPClient::RTPClient():
        mClient(NULL)
{
    // make it clear you want the address of the instance variable
    pin_ptr<CIsmaClient*> pinnedClient = &this->mClient; 
    CIsmaClient::Create(
        pinnedClient,          // fixed
        NULL, 
        &AllocBuffer, 
        &GetDataPointer, 
        x /* pass something else in */);            //2
}

If you supply more information on what the last parameter is used for I can suggest possible solutions

ShuggyCoUk
Here is the correct link:http://msdn.microsoft.com/en-us/library/1dz8byfh.aspx
Juozas Kontvainis
The pointer is to an unmanaged class though...
cjserio
if it's unmanaged then simply passing a plain only C++ pointer is just fine. I don't see what the problem is....
ShuggyCoUk
I get this error...error C2664: 'CIsmaClient::Create' : cannot convert parameter 1 from 'cli::interior_ptr<Type>' to 'CIsmaClient **'.The pointer i'm passing is a member variable of my managed class however it's a pointer to an unmanaged class
cjserio
This is an interior pointer (i.e. it points to a value contained within memory controlled by the GC) thus you must pin it (which pins the containing object) simply use the pin_ptr (but remember the resulting plain pointer will remain valid only as long as the pin_ptr is in scope on the stack
ShuggyCoUk
Actually re-reading that I think you might have a bigger problem. Edit you question to include the class code and the usage code where the compiler error occurs
ShuggyCoUk
I added the class definition
cjserio