Search code examples
uwpuwp-xamlc++-winrtcppwinrt

Error setting comptr to winrt::UserControl::Tag()


Update: I used Richard's suggestion to fix the setting of Tag. But I am having some issues using the getter for Tag and using the .as/try_as operator on it.

class DerivedController : public winrt::implements<DerivedController, Controller> {
 public:
    DerivedController() {}

    virtual ~DerivedController() {}

    static winrt::com_ptr<DerivedController> from(const winrt::FrameworkElement& control) {
        return control ? control.Tag().try_as<DerivedController>() : nullptr;
    }
}

This is the error I get:

1>C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\cppwinrt\winrt/base.h(8013): error C2440: 'static_cast': cannot convert from 'winrt::impl::producer<D,I,void> *' to 'D *'
1>        with
1>        [
1>            D=`anonymous-namespace'::DerivedController,
1>            I=winrt::Windows::Foundation::IInspectable
1>        ]
1>        and
1>        [
1>            D=`anonymous-namespace'::DerivedController
1>        ]
1>C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\cppwinrt\winrt/base.h(8013): note: Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
1>C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\cppwinrt\winrt/base.h(8012): note: while compiling class template member function 'D &winrt::impl::produce_base<D,I,void>::shim(void) noexcept'
1>        with
1>        [
1>            D=`anonymous-namespace'::DerivedController,
1>            I=winrt::Windows::Foundation::IInspectable
1>        ]
1>C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\cppwinrt\winrt/base.h(7777): note: see reference to function template instantiation 'D &winrt::impl::produce_base<D,I,void>::shim(void) noexcept' being compiled
1>        with
1>        [
1>            D=`anonymous-namespace'::DerivedController,
1>            I=winrt::Windows::Foundation::IInspectable
1>        ]
1>C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\cppwinrt\winrt/base.h(7737): note: see reference to class template instantiation 'winrt::impl::produce_base<D,I,void>' being compiled
1>        with
1>        [
1>            D=`anonymous-namespace'::DerivedController,
1>            I=winrt::Windows::Foundation::IInspectable
1>        ]
1>C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\cppwinrt\winrt/base.h(7777): note: see reference to class template instantiation 'winrt::impl::produce<D,winrt::Windows::Foundation::IInspectable>' being compiled
1>        with
1>        [
1>            D=`anonymous-namespace'::DerivedController
1>        ]
1>C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\cppwinrt\winrt/base.h(4088): note: see reference to function template instantiation 'D *winrt::get_self<To,winrt::Windows::Foundation::IInspectable>(const I &) noexcept' being compiled
1>        with
1>        [
1>            D=`anonymous-namespace'::DerivedController,
1>            To=`anonymous-namespace'::DerivedController,
1>            I=winrt::Windows::Foundation::IInspectable
1>        ]
1>C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\cppwinrt\winrt/base.h(2387): note: see reference to function template instantiation 'winrt::com_ptr<D> winrt::impl::as<To,winrt::impl::IUnknown>(From *)' being compiled
1>        with
1>        [
1>            D=`anonymous-namespace'::DerivedController,
1>            To=`anonymous-namespace'::DerivedController,
1>            From=winrt::impl::IUnknown
1>        ]
1>note: see reference to function template instantiation 'winrt::com_ptr<D> winrt::Windows::Foundation::IUnknown::as<`anonymous-namespace'::DerivedController>(void) const' being compiled
1>        with
1>        [
1>            D=`anonymous-namespace'::DerivedController
1>        ]
1>note: see reference to class template instantiation 'winrt::com_ptr<D>' being compiled
1>        with
1>        [
1>            D=Controller
1>        ]
1>C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\cppwinrt\winrt/base.h(10615): note: see reference to class template instantiation 'winrt::com_ptr<winrt::impl::IContextCallback>' being compiled (compiling source file
1>C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\cppwinrt\winrt/base.h(10349): note: see reference to class template instantiation 'winrt::com_ptr<winrt::impl::IServerSecurity>' being compiled
1>C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\cppwinrt\winrt/base.h(10308): note: see reference to class template instantiation 'std::chrono::time_point<winrt::clock,winrt::Windows::Foundation::TimeSpan>' being compiled
1>C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\cppwinrt\winrt/base.h(6462): note: see reference to class template instantiation 'winrt::com_ptr<winrt::impl::IMarshal>' being compiled
1>C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\cppwinrt\winrt/base.h(210): note: see reference to class template instantiation 'std::array<uint8_t,8>' being compiled

Controller is constructor as:

auto controller = winrt::make<Controller>().as<Controller>();

DerivedController is constructed as:

DerivedController dController{};

DerivedController used to be like this in c++/cx:

ref class DerivedController sealed : public Controller {
    internal : explicit DerivedController(Windows::UI::Xaml::FrameworkElement ^ &control)    
        : Controller(control) {}   

    static DerivedController ^   
        from(Windows::UI::Xaml::FrameworkElement ^ control) {   
            return control ? dynamic_cast<SvgCanvasController ^>(control->Tag) : nullptr;   
        }
}

Not sure what I am doing wrong, the error seems to be related to how the classes are defined. Would appreciate any thoughts on it!

Original: In C++/CX, I used to be able to do:

ref class Controller {
    Controller() {
        container = ref new UserControl();
        container->Tag = this;
        ...
        ...
    }
}

When I try to convert this to C++/WinRT, direct conversion would like this:

class Controller : public winrt::implements<Controller, winrt::Windows::Foundation::IInspectable> {
    Controller::Controller() {
        winrt::UserControl container;
1===>    container.Tag(this);
        ...
        ...
    }
}

Controller is a hand-authored class (no idls) whose definition looks like this:

class Controller : public winrt::implements<Controller, winrt::Windows::Foundation::IInspectable> 
{
    ...
    ...
    ...
}

But I get an error at (1):

Error   C2664   'void winrt::impl::consume_Windows_UI_Xaml_IFrameworkElement<D>::Tag(const winrt::Windows::Foundation::IInspectable &) const': cannot convert argument 1 from 'Controller *' to 'const winrt::Windows::Foundation::IInspectable &'
  1. Is it possible to set a Com pointer to Tag using some interop with ABI?
  2. Is there anything else I am missing?
  3. Is this the right approach? Or is there a way around it?

Solution

    1. Is it possible to set a Com pointer to Tag using some interop with ABI?

    If you want to convert the code container->Tag=this; in C++/CX to the corresponding code in C++/WinRT, you could try to pass *this as the parameter instead of using interop with ABI , like this:

    class Controller : public winrt::implements<Controller, winrt::Windows::Foundation::IInspectable>
    {
        public:
            UserControl container;
            Controller::Controller()
            {
                container.Tag(*this);
            }
            ……
    };
    
    1. Is there anything else I am missing?

    You did a good job, but maybe we can pay attention to the defference of this between C++/CX and C++/WinRT. Here we use *this instead this.

    1. Is this the right approach? Or is there a way around it?

    If you want to get the object added into Tag property, then the approach is right. You can try this code:

    Controller cc{};
    UserControl uc = cc.container;
    auto item1 = uc.Tag();
            
    auto item2=  item1.try_as<Controller>();
    auto item3 = item2.get();
    UserControl uc2 = item3->container;
    if (uc = uc2)
    {
       int t = 1;
    }
    

    Update:

    You can use static_cast to implement the conversion from Controller pointer to DerivedController pointer and change the return type of from method as DerivedController* like this:

    static DerivedController* from(winrt::Windows::UI::Xaml::FrameworkElement const& control) 
    {
        auto con = static_cast<winrt::Windows::UI::Xaml::FrameworkElement>(control);
        if (con != nullptr)
        {
            auto it1=con.Tag();
            auto it2 = it1.try_as<Controller>();
            Controller* cc = it2.get();
            DerivedController* der = static_cast< DerivedController* >(cc);
            return der;
        }
        return nullptr;
    }
    

    Then call the from method:

    Controller cc{};
    DerivedController dController{};
    DerivedController* aa = dController.from(cc.container);