Non-managed referenced code strangely, "magically" changes its state for no reason when wrapped in managed

95 views Asked by At

I have a very strange problem:

My unmanaged third-party library has a class, let's call it Foo which has a method bar() which returns an object of type Bar, like:

Foo* foo = new Foo();
Bar bar = foo -> bar();

Now, this Bar has a method which is supposed to initially return true when it is obtained via the above means. In unmanaged code, this works as desired:

Foo* foo = new Foo();
Bar bar = foo -> bar(); // yes, bar() returns the object, not a pointer
bool b = bar.shouldBeTrue(); // b is true

Now, I wrote a managed wrapper for Foo and Bar which is very simple:

Managed.h:

namespace Managed {

    public ref class ManagedBar {
    private:
        ThirdParty::Bar* _delegate;

    public:
        ManagedBar(ThirdParty::Bar* delegate);

        ~ManagedBar();

        bool shouldBeTrue();
    };

    public ref class ManagedFoo {
    private:
        ThirdParty::Foo* _delegate;

    public:
        ManagedFoo();

        ~ManagedFoo();

        ManagedBar^ bar();
    };
}

ManagedBar.cpp (includes stripped):

namespace Managed {

    ManagedBar::ManagedBar(ThirdParty::Bar* delegate) {
        _delegate = delegate;
    }

    ManagedBar::~ManagedBar() {
        delete _delegate;
    }

    bool ManagedBar::shouldBeTrue() {
        return _delegate -> shouldBeTrue();
    }
}

ManagedFoo.cpp:

namespace Managed {

    ManagedFoo::ManagedFoo() {
        _delegate = new ThirdParty::Foo();
    }

    ManagedFoo::~ManagedFoo() {
        delete _delegate;
    }

    ManagedBar^ ManagedFoo:bar() {
        ThirdParty::Bar tpb = delegate -> bar();
        //for test/debugging:
        bool b = tpb.shouldBeTrue(); // b is true
        return gcnew ManagedBar(&tpb);
    }
}

Now, when I call this the following in VB.NET (in a Unit test):

Imports Managed

<TestClass()>
Public Class MyTest

    <TestMethod()>
    Public Sub TestBarReturnsTrue()
        Dim f as ManagedFoo = New ManagedFoo()
        Dim b as ManagedBar = f.bar()
        Assert.IsTrue(b.shouldBeTrue())
    End Sub

End Class

But the assert now fails because it is false. When I step into my ManagedBar, the _delegate -> shouldBeTrue() is called without any errors. This behaviour is very strange. Could it be that I did something wrong with my wrapping, or do I have to ask the supplier of the third-party DLL for advice?

1

There are 1 answers

0
durkmurder On BEST ANSWER

The problem is in:

    ManagedBar^ ManagedFoo:bar() {
    ThirdParty::Bar tpb = delegate -> bar();
    //for test/debugging:
    bool b = tpb.shouldBeTrue(); // b is true
    return gcnew ManagedBar(&tpb);
}

tpb is destroyed after the function call. You should allocate tpb on the heap(you will need to manually free it), save it somewhere(as member) or pass it by value to the ManagedBar.

Hope that will help you.