Uwp 将comptr设置为winrt::UserControl::Tag()时出错
更新: 我用Richard的建议来修正标签的设置。但是我在使用getter for标记和使用.as/try_as操作符时遇到了一些问题Uwp 将comptr设置为winrt::UserControl::Tag()时出错,uwp,uwp-xaml,c++-winrt,cppwinrt,Uwp,Uwp Xaml,C++ Winrt,Cppwinrt,更新: 我用Richard的建议来修正标签的设置。但是我在使用getter for标记和使用.as/try_as操作符时遇到了一些问题 class DerivedController : public winrt::implements<DerivedController, Controller> { public: DerivedController() {} virtual ~DerivedController() {} static winrt::
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;
}
}
DerivedController过去在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;
}
}
当我尝试将其转换为C++/WinRT时,直接转换如下:
class Controller : public winrt::implements<Controller, winrt::Windows::Foundation::IInspectable> {
Controller::Controller() {
winrt::UserControl container;
1===> container.Tag(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;
}
类控制器:公共winrt::实现{
控制器::控制器(){
winrt::UserControl容器;
1=>container.Tag(这个);
...
...
}
}
Controller是一个手工编写的类(无IDL),其定义如下:
class Controller : public winrt::implements<Controller, winrt::Windows::Foundation::IInspectable> {
Controller::Controller() {
winrt::UserControl container;
1===> container.Tag(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;
}
类控制器:公共winrt::实现
{
...
...
...
}
但我在(1)处得到一个错误:
Error C2664'void winrt::impl::consume\u Windows\u UI\u Xaml\u IFrameworkElement::Tag(const winrt::Windows::Foundation::IInspectable&)const':无法将参数1从“Controller*”转换为“const winrt::Windows::Foundation::IInspectable&”
容器->标记=此
;在C++/CX中,您可以尝试将*this
作为参数传递给C++/WinRT中的相应代码,而不是使用与ABI的互操作,如下所示:
class Controller : public winrt::implements<Controller, winrt::Windows::Foundation::IInspectable> {
Controller::Controller() {
winrt::UserControl container;
1===> container.Tag(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;
}
类控制器:公共winrt::实现
{
公众:
用户控制容器;
控制器::控制器()
{
container.Tag(*这个);
}
……
};
*this
代替this
标记
属性中,则该方法是正确的。您可以尝试以下代码:
控制器cc{};
UserControl uc=cc.container;
auto item1=uc.Tag();
auto item2=item1.try_as();
auto item3=item2.get();
UserControl uc2=item3->container;
如果(uc=uc2)
{
int t=1;
}
更新:
您可以使用static_cast实现从控制器指针到DerivedController指针的转换,并将from方法的返回类型更改为DerivedController*如下:
class Controller : public winrt::implements<Controller, winrt::Windows::Foundation::IInspectable> {
Controller::Controller() {
winrt::UserControl container;
1===> container.Tag(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;
}
您已经了解了大部分方法,但是现在是时候深入了解调用
as()/try\u as()
时在引擎盖下实际发生的情况了。您可能已经知道,它们是的包装。两者之间唯一的区别是as()
将QueryInterface
故障转换为异常,而try\u as()
在故障时返回null。(为简洁起见,其余部分我只参考as()
)
现在我们知道我们调用的是QueryInterface
,但它使用的是GUID
,而不是模板类型参数。C++/WinRT为我们翻译了一个类型特征,WinRT::guid\u of
,它将uuid与类型相关联。当类型To
是一个投影接口,或者是一个用声明的原始ABI接口时,“类型到guid”映射的行为与预期的非常接近
但是,当类型To
是从winrt::implements
派生的实现类型时会发生什么?这里有两个额外的步骤
默认接口
步骤1是的guid\u返回T的默认接口的guid。接口是它们自己的默认接口-default\u接口
与T
相同。对于RuntimeClass,默认接口在winmd中,也可以在MIDL3中,但典型情况是Widget
的默认接口是IWidget
winrt::implements的默认接口
步骤2是,对于从winrt::implements
派生的T
类型,T
的默认接口是提供给模板的第二种类型(CRTP类型之后的第一种类型)的默认接口。比如说,
struct Base:实现{};
//默认接口==默认接口==IBase
严格Derived1:实现{};
//默认_接口==IDerived
struct-Derived2:实现{};
//默认_接口==IBase
struct-Derived1:实现{};
//默认_接口==IBase
记住这一点很重要
在上面的示例中,请注意Derived2
和derived3
具有与Base
相同的默认界面。(上面的Derived3
更糟糕,一点反模式-Derived3
没有实现它自己的任何接口,因此这里不需要使用implements
)这意味着as()
不会像我们想象的那样运行-C++/WinRT将为IBase
提供QueryInterface
,而不是IDerived
,这使得Base
和派生的
在as()
中无法区分。如果编译成功,这将导致运行时歧义和各种混乱
但是,as()
不会编译,因为最后一个问题:as()
需要返回类型。同样,对于投影接口/运行时类,这很简单:返回到。对于原始ABI接口,这也很简单:返回com\u ptr
陷阱
但是对于实现
,我们需要记住查询接口
中的一个细节,返回的指针必须指向请求接口的vtable(它可能在对象的内存布局中偏移)。冒着过分简化的风险,实现
Controller cc{};
DerivedController dController{};
DerivedController* aa = dController.from(cc.container);