C++/WinRT 开发入门

说明

C++/WinRT 最初是用来开发 UWP 应用程序的。WinUI3 继承了 UWP 部分API,重新设计了 UI 类型,并新增了 WindowsAppSDK API.
C++/WinRT 可用于 WinUI3 开发。

使用 C++ 的优点:

  1. 方便使用C++标准库。
  2. 方便使用第三方C++库。
  3. 方便直接使用 Windows API。
  4. 编译后的可执行文件目录中没有 .NET dll 库文件, 发布的程序体积比 C# 小很多.

也有这些缺点:

  1. 上手难度会大一点。
  2. 编译后生成的预编译头文件 ProjectName\x64\Debug\pch.pch 大小在 955MB 左右,整个项目容量大小在 1GB 以上。
    在这里插入图片描述
  3. 自定义运行时类型,需要通过 idl 文件(使用的 MIDL 3.0 语言只是接口描述语言, 并不需要实现, 难度并不大)。编写 idl 文件时,不能智能提示,需要查看文档找到所需接口,或类型的完整名称。
  4. 文件比较繁琐,一个 xaml 页面会有四个文件(.xaml, .h, .cpp, .idl)。通过将项目的所有 idl 文件内容集中到一个文件中,可以减少到三个文件。

运行时类型,实现类型

当新建一个 C++/WinRT WinUI3 APP项目时候,假设名称为App1,那么将会看到在三个命名空间中都会出现 MainWindow 类型:

  1. winrt::App1::MainWindow (运行时类型, C++中的运行时类型只是WinRT中对应类型的投影)。
  2. winrt::App1::implementation::MainWindow (实现类型)。
  3. winrt::App1::factory_implementation::MainWindow (这个类型一般是空白的,可以不用特别在意)。

这个运行时类型,是通过 idl 文件定义的,这描述了其中公开的成员(属性,函数,事件),但并不能在 idl 文件中实现这些成员。如果需要实现,C++/WinRT 是通过 implementation:: 下同名类型实现的。

当我们调用一个运行时类型的方法(比如:void Hello()),会被映射到 implementation:: 下同名类型的 void Hello() 。

如果编译时在投影类型中找不到 idl 文件中定义的函数,就会报错,这也是常见的编译错误。

IDL 文件

参考文档
IDL 文件可以定义以下类型:

  1. 委托 (关键字 delegate)
    • 类似于函数指针,与 C# 委托类似。
  2. 结构 (关键字 struct)
    • IDL 文件内的结构会自动生成, 在 Generated Files\winrt\impl\ProjectName.0.h 文件内.
    • 结构定义在idl 好处是可以在 idl文件和c++文件中都能使用。
  3. 枚举(关键字 enum)
    • IDL 文件内的枚举会自动生成, 在 Generated Files\winrt\impl\ProjectName.0.h文件内.
    • 枚举定义在 idl 的好处是可以在 idl 文件和c++文件中都能使用。
  4. 接口 (关键字 interface)
    • 约定了应该实现的属性,方法,事件。
  5. 运行时类型(关键字 runtimeclass)
    • 运行时类型对应着一个头文件和一个源文件, 也会自动生成 (在 Generated Files\Source目录中), 但必须手动复制到项目中.

常见的问题解决方法

  1. FileOpenPicker, FileSavePicker, FolderPicker 在C#中并不需要使用窗口句柄初始化,在 C++/WinRT 中需要用窗口句柄初始化。
#include <microsoft.ui.xaml.window.h>
#include <Shobjidl.h>

IAsyncAction SelectFolderAsync()
{
	FolderPicker picker{}; 
	picker.FileTypeFilter().Append(L"*"); 
	
	// 初始化 picker 
	auto initializeWithWindow {picker.as<::IInitializeWithWindow>()}; 
	initializeWidthWindow->Initialize(hWnd); 
	
	if(StorageFolder folder = co_await folderPicker.PickSingleFolerAsync())
	{
	 	// doSomething()
 	}
}

  1. 现在 WinUI3 应用程序可以不用打包,编译后点击 .exe 文件就能运行。需要在 *.vcxproj 文件中进行以下修改:
  <PropertyGroup Label="Globals">
	
	<!-- 这行是已经存在的,需要将 true 修改为 false.  -->
    <AppxPackage>false</AppxPackage>

	<!-- 这行是新增的。 -->
    <WindowsPackageType>None</WindowsPackageType>
  </PropertyGroup>
  1. 在 C++/WinRT 的 idl 文件中,并不能直接使用 int, float, double, 之类的数据类型,需要使用 WinRT 类型名称替代,可以参考以下表格:
    在这里插入图片描述
  2. 如何在 C++/WinRt 中实现接口 INotifyPropertyChanged?
    第一步:在 idl 文件中,让运行时类型继承 Microsoft.UI.Xaml.Data.INotifyPropertyChanged 接口。
runtimeclass Person : Microsoft.UI.Xaml.Data.INotifyPropertyChanged
{
	String Name{get;set;}; 
}

第二步: 在 implementation::Person 投影类型的 .h 文件中,编写以下内容:

struct Person
{
public:
	hstring Name() const {return m_name;}
	void Name(hstring value) 
	{
		if(value != m_name){
			m_name = value; 
			// 触发事件,Name 属性改变了。
			m_propertyChanged(*this, PropertyChangedEventArgs(L"Name")); 
		}
	}
	winrt::event_token PropertyChanged(winrt::Microsoft::UI::Xaml::Data::PropertyChangedEventHandler const& handler)
	{
		return m_propertyChanged.add(handler); 
	}
	void PropertyChanged(winrt::event_token const& token) noexcept
	{
		m_propertyChanged.remove(token); 
	}

private:
	event<Microsoft::UI::Xaml::Data::PropertyChangedEventHandler> m_propertyChanged {};
	hstring m_name; 
}

如果属性发生改变,需要触发事件可以这样做:

m_propertyChanged(*this, PropertyChangedEventArgs(propertyName));
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DENG-TAO

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值