6

I am trying to write a small library which will use DirectShow. This library is to be utilised by a .NET application so I thought it would be best to write it in C++/CLI.

I am having trouble with this line however:

    HRESULT hr = CoCreateInstance(  CLSID_FilterGraph,
                                    NULL,
                                    CLSCTX_INPROC_SERVER,
                                    IID_IGraphBuilder,
                                    (void**)(&graphBuilder) );  //error C2440:

Where graphBuilder is declared:

public ref class VideoPlayer
{
public:
    VideoPlayer();
    void Load(String^ filename);

    IGraphBuilder*  graphBuilder;

};

If I am understanding this page correctly, I can use */& as usual to denote 'native' pointers to unmanaged memory in my C++/CLI library; ^ is used to denote a pointer to a managed object. However, this code produces:

error C2440: 'type cast' : cannot convert from 'cli::interior_ptr' to 'void **'

The error suggests that graphBuilder is considered to be a 'cli::interior_ptr<Type>'. That is a pointer/handle to managed memory, isn't it? But it is a pure native pointer. I am not trying to pass the pointer to a method expecting a handle or vice versa - I simply want to store it in my managed class) If so, how do I say graphBuilder is to be a 'traditional' pointer?

(This question is similar but the answer, to use a pin_ptr, I do not see helping me, as it cannot be a member of my class)

Community
  • 1
  • 1
sebf
  • 2,831
  • 5
  • 32
  • 50

1 Answers1

11

The error message is a bit cryptic, but the compiler is trying to remind you that you cannot pass a pointer to a member of a managed class to unmanaged code. That cannot work by design, disaster strikes when the garbage collector kicks in while the function is executing and moves the managed object. Invalidating the pointer to the member in the process and causing the native code to spray bytes into the gc heap at the wrong address.

The workaround is simple, just declare a local variable and pass a pointer to it instead. Variables on the stack can't be moved. Like this:

void init() {
    IGraphBuilder* builder;    // Local variable, okay to pass its address
    HRESULT hr = CoCreateInstance(CLSID_FilterGraph,
        NULL,
        CLSCTX_INPROC_SERVER,
        IID_IGraphBuilder,
        (void**)(&builder) );
    if (SUCCEEDED(hr)) {
        graphBuilder = builder;
        // etc...
    }
}
Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • The pointer itself could move while being set - I completely missed that! Thank You Hans! – sebf May 06 '12 at 19:06
  • So, just to be clear, you're saying that you cannot keep an unmanaged pointer as even an internal member of a managed class? Trying to wrap my head around how I'm supposed to bridge between managed and unmanaged types in any coherent manner if this is true.. –  Oct 12 '14 at 18:58
  • No, that's fine. The OP created a pointer to a member of the object, &graphBuilder. – Hans Passant Oct 12 '14 at 19:02
  • Just wanted to add the complete error code: `error argument of type "interior_pointer<>" is incompatible with parameter of type ""` as it took me a while to find this answer. – Roy T. Jan 26 '15 at 09:38