WINRT : How to remove all the references of WinUI3 control created using copy_to_abi

Harshithraj1871 1,681 Reputation points
2024-08-06T11:07:51.2266667+00:00

Hi,

I'm working on building an desktop application with Using the WinRT XAML hosting API in a C++ desktop (Win32) app. I'm not using any XAML files to build the application. All the widgets are created with C++. When I create a widget object in cpp(say winrt::Windows::UI::Xaml::Controls::Button) im keeping a reference of it as a void* in a cpp object.

I used winrt::copy_to_abi to get the widget pointer as an void *. I read that this will create a copy of the C++/WinRT widget and increase the reference count of the widget. When I use this, when I'm done using the button how to completely deference it (including all the references)?

Example :

    int GetReferenceCount(winrt::Microsoft::UI::Xaml::FrameworkElement const& button)
    {
        // Get the IUnknown interface from the WinRT object
        auto unknown = winrt::get_unknown(button);

        // AddRef to increment the reference count
        unknown->AddRef();

        // Release to get the reference count
        ULONG refCount = unknown->Release();

        // Return the reference count
        return static_cast<int>(refCount) - 1;
    }


        void* store = nullptr;

        {
            Canvas zone0;

            copy_to_abi(zone0, store);

            auto res = GetReferenceCount(zone0); // The reference count is 2
        }

        {
            Canvas zone1 = nullptr;

            copy_from_abi(zone1, store);

            auto res = GetReferenceCount(zone1); // The reference count is 2          
		}
        // reference count is 1 because it holds a copy of the CANVAS in variable store 


Taking the above example how can I dereference the widget which is being pointed by the variable store?

Windows App SDK
Windows App SDK
A set of Microsoft open-source libraries, frameworks, components, and tools to be used in apps to access Windows platform functionality on many versions of Windows. Previously known as Project Reunion.
853 questions
{count} votes

Accepted answer
  1. Darran Rowe 1,516 Reputation points
    2024-08-07T03:20:05.48+00:00

    That is natural, since Viorel was actually referring to ::IUnknown. Not the C++/WinRT projection. Please notice that the type that Viorel mentioned does not have any namespaces, it is the IUnknown interface in the global namespace. Also please notice the *, this is not a mistake. This was a cast to IUnknown *.

    There are two ways to put an ABI instance into Windows.Foundation.IUnknown so that the projection will destroy the instance.

    First, there is winrt::attach_abi.

    winrt::Windows::Foundation::IUnknown unknown{nullptr};
    winrt::attach_abi(unknown, store);
    //Remove this pointer to avoid any usage beyond this point.
    store = nullptr;
    

    winrt::attach_abi will attach the ABI type to the projection instance without incrementing the reference count. This is why the above code snippet instantly resets the pointer. When the projection instance goes out of scope, the object that was attached will have Release automatically called.

    The second option is to use something that is a little less documented. The constructors for the projection types have one constructor that takes a void pointer and a winrt::take_ownership_from_abi_t tag type. This constructs the projection type using the ABI type as a parameter, and the tag tells it to not increment the reference count.

    winrt::Windows::Foundation::IUnknown unknown{store, winrt::take_ownership_from_abi};
    store = nullptr;
    

    The only reference to this that I know of is in Interop between C++/WinRT and the ABI. The direct call to Release that Viorel mentioned is still simpler to write.

    0 comments No comments

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.