locked
How do you properly implement Platform::IDisposable in a C++ / CX WinRT component?

    Question

  • I've tried the following, which compiles (but does give a few Intellisense warnings):

    namespace WinRTComponentDll6
    {
       public ref class WinRTComponent1 sealed : Platform::IDisposable
       {
          private: byte* _buffer;
          private: Platform::Array<byte>^ _array;
          public: WinRTComponent1()
                  {
                      _buffer = (byte*)malloc(100);
                      _array = ref new Platform::Array<byte>(200);
                  }
          public: ~WinRTComponent1()
                  {
                      // delete managed stuff here
                      delete _array;
                      //this->!RasterImage();
                      this->Dispose();
                  }
          //public: !RasterImage(); // error: C3941 - requires /clr
          public: void Dispose()
                  {
                     free(_buffer);
                  }
          public: byte GetByte(int x) { return _buffer[x]; }
       };
    }
     

    However, when I try to use this class in another WinRT C++ / CX component, like this:

    using namespace WinRTComponentDll6;
    
    namespace WinRTComponentDll7
    {
       public ref class WinRTComponent2 sealed
       {
          public: static byte UseWinRTComponent1(WinRTComponent1 ^ component)
                  {
                      return component->GetByte(0);
                  }
       };
    }
     

    I get compiler error:

    error C2535: 'void WinRTComponentDll6::WinRTComponent1::Dispose(void)' : member function already defined or declared
    see declaration of 'WinRTComponentDll6::WinRTComponent1::Dispose'
    This diagnostic occurred while importing type 'WinRTComponentDll6::WinRTComponent1 ' from assembly 'WinRTComponentDll6, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.

    Thursday, May 31, 2012 1:10 PM

Answers

  • You'll want to implement a public virtual destructor for the class. This dtor is called as the IDisposable::Dispose

        public ref class Class1 sealed
        {
        private:
    	uint16* _buffer;
        public:
            Class1()
    	{
    		_buffer = (uint16*)malloc(100);
    	}
    
    	virtual ~Class1() 
    	{
    		free(_buffer);
    	}
        };

    You call delete on the Class1 object handle to do deterministic cleanup

    	WindowsRuntimeComponent1::Class1^ c1 = ref new WindowsRuntimeComponent1::Class1();
    	delete c1;

    The callstack you'll see on 'delete c1', going through IDisposable and calling the dtor.

    > WindowsRuntimeComponent1.dll!WindowsRuntimeComponent1::Class1::~Class1() Line 19 C++
      WindowsRuntimeComponent1.dll!WindowsRuntimeComponent1::Class1::[Platform::IDisposable]::<Dispose>() C++
      WindowsRuntimeComponent1.dll!WindowsRuntimeComponent1::Class1::[Platform::IDisposable]::__abi_Platform_IDisposable____abi_<Dispose>() C++
      App1.exe!Platform::IDisposable::<Dispose>() C++
      App1.exe!App1::App::App() Line 34 C++

    If you look at ILDASM output for the class you'll see that the virtual public dtor causes IClosable to be implemented on your class and IClosable::Close is implemented by the compiler. IClosable::Close calls the dtor. (try comparing the ILDASM output for a class with and without the virtual public dtor). As with all ref classes, the memory for the object is released when the ref count drops to zero for the object.

    IClosable is the windows runtimes way of implementing the IDisposable pattern.

    Wednesday, August 15, 2012 8:35 PM
    Moderator

All replies

  • Hello,

     

    Thanks for your feedback, I will involve more experts to investigate it.

     

    Best regards,

    Jesse


    Jesse Jiang [MSFT]
    MSDN Community Support | Feedback to us

    Friday, June 01, 2012 6:49 AM
  • Were you able to involve enough experts to get a working example?
    Thursday, August 09, 2012 1:14 AM
  • You'll want to implement a public virtual destructor for the class. This dtor is called as the IDisposable::Dispose

        public ref class Class1 sealed
        {
        private:
    	uint16* _buffer;
        public:
            Class1()
    	{
    		_buffer = (uint16*)malloc(100);
    	}
    
    	virtual ~Class1() 
    	{
    		free(_buffer);
    	}
        };

    You call delete on the Class1 object handle to do deterministic cleanup

    	WindowsRuntimeComponent1::Class1^ c1 = ref new WindowsRuntimeComponent1::Class1();
    	delete c1;

    The callstack you'll see on 'delete c1', going through IDisposable and calling the dtor.

    > WindowsRuntimeComponent1.dll!WindowsRuntimeComponent1::Class1::~Class1() Line 19 C++
      WindowsRuntimeComponent1.dll!WindowsRuntimeComponent1::Class1::[Platform::IDisposable]::<Dispose>() C++
      WindowsRuntimeComponent1.dll!WindowsRuntimeComponent1::Class1::[Platform::IDisposable]::__abi_Platform_IDisposable____abi_<Dispose>() C++
      App1.exe!Platform::IDisposable::<Dispose>() C++
      App1.exe!App1::App::App() Line 34 C++

    If you look at ILDASM output for the class you'll see that the virtual public dtor causes IClosable to be implemented on your class and IClosable::Close is implemented by the compiler. IClosable::Close calls the dtor. (try comparing the ILDASM output for a class with and without the virtual public dtor). As with all ref classes, the memory for the object is released when the ref count drops to zero for the object.

    IClosable is the windows runtimes way of implementing the IDisposable pattern.

    Wednesday, August 15, 2012 8:35 PM
    Moderator
  • To add to that:

    If the class doesn’t have any public destructor, its destructor (either 'private' or 'protected private') will only be called on final release (ref-count -> 0).

    In case the user tries to delete an instance of a non-disposable class, they will get a compile-time warning specifying that the operation is a no-op. 

    Marian Luparu
    Visual C++ 

    Wednesday, August 15, 2012 10:33 PM
  • Hi, I meet a big problem with C++/CX. I am developing a APP for WP with C++/CX. When I try to create an indexed property, the error is "Indexed property with a public 'get' or 'set' accessor is not allowed", but in C# there is no such problem. Because I will make a data bounding to that indexed property, so it must be public, what should I do? Thank you very much~~~

     
    Tuesday, September 02, 2014 5:53 AM