RSS 读者教程(适用于 Windows 的 Rust 与 VS Code)

上一主题介绍了 Rust for Windows 与 windows crate

现在,让我们通过编写一个简单的控制台应用来试用 Rust for Windows,该应用从简单信息聚合(RSS)源下载博客文章的标题。

  1. 在要保存 Rust 项目的文件夹中启动命令提示符 (cmd.exe) 和 cd

  2. 使用 Cargo 新建一个名为“rss_reader”的 Rust 项目,并使用 cd 转到新创建的文件夹中

    > cargo new rss_reader
    >     Created binary (application) `rss_reader` package
    > cd rss_reader
    
  3. 然后在 VS Code 中打开 rss_reader 项目。

    code .
    
  4. 让我们实现主项目 rss_reader。 首先,在 Cargo.toml 项目的根目录中打开该文件。 文件 Cargo.toml 是描述 Rust 项目的文本文件,包括它拥有的任何依赖项。

    在 windows crate 上添加依赖项,如下面的列表所示。 Windows crate 很大。 为了保持构建时间较短,我们将仅选择此代码所需的 Foundation_CollectionsWeb_Syndication 特性。

    # Cargo.toml
    ...
    
    [dependencies.windows] 
    version = "0.62.0"
    features = [
        "Foundation_Collections",
        "Web_Syndication",
    ]
    

    注释

    windows crate 发布频繁。 检查 crates.io/crates/windows 是否有最新版本并相应地更新。

  5. 然后,打开 rss_reader 项目的 src/main.rs 源代码文件。 你将在那里找到 Cargo 默认的“Hello, world!” 代码。 将以下 use 语句添加到 main.rs 的开头

    // src\main.rs
    use windows::{
        core::*,
        Foundation::Uri,
        Web::Syndication::SyndicationClient
    };
    
    fn main() {
        println!("Hello, world!");
    }
    

    use 声明缩短了我们将要使用的类型的路径。 其有我们前面提到过的 Uri 类型。

  6. 要创建新的 Uri,请使用以下内容替代 Cargo 的默认 main 函数

    // src\main.rs
    ...
    
    fn main() -> Result<()> {
        let uri = Uri::CreateUri(h!("https://blogs.windows.com/feed"))?;
    
        Ok(())
    }
    

    请注意,main 函数的返回类型是来自 windows::core:: 的 Result。 这会让事情变得更简单,因为我们常常需要处理操作系统(OS)API中的错误。 windows::core::Result 有助于我们进行错误传播和简洁的错误处理。

    可以在代码行末尾看到问号运算符。 简而言之,我们这样做是为了利用 Rust 的错误传播和短路逻辑。 这意味着,对于这个简单的示例,我们不必执行一堆手动错误处理。 若要详细了解 Rust 的这项功能,请参阅利用 ? 运算符简化错误处理

    另请注意 windows crate 中的 h! 宏。 可使用它基于 Rust 字符串文本构造 HSTRING 引用。 WinRT API 广泛对字符串值使用 HSTRING

  7. 为了下载此 RSS 源,我们将创建一个新的 SyndicationClient

    // src\main.rs
    ...
    
    fn main() -> windows::core::Result<()> {
        let uri = Uri::CreateUri(h!("https://blogs.windows.com/feed"))?;
        let client = SyndicationClient::new()?;
    
        Ok(())
    }
    

    函数是 Rust 构造函数。 windows crate 中的所有对象都遵循 Rust 约定,并将其构造函数命名为 new

  8. 现在,我们可以使用 SyndicationClient 来检索源

    // src\main.rs
    ...
    
    fn main() -> windows::core::Result<()> {
        let uri = Uri::CreateUri(h!("https://blogs.windows.com/feed"))?;
        let client = SyndicationClient::new()?;
        let feed = client.RetrieveFeedAsync(&uri)?.get()?;
    
        Ok(())
    }
    

    由于 RetrieveFeedAsync 是一个异步 API,因此我们使用阻止 get 函数来保持示例简单。 或者,可以使用 await 函数中的 async 运算符协作等待结果。 具有图形用户界面的更复杂的应用将经常使用 async

  9. 现在,我们可以循环访问结果项,然后只打印标题。 你还将在下面看到几行额外的代码来设置用户代理标头,因为某些 RSS 源需要这样做。

    // src\main.rs
    ...
    
    fn main() -> windows::core::Result<()> {
        let uri = Uri::CreateUri(h!("https://blogs.windows.com/feed"))?;
        let client = SyndicationClient::new()?;
    
        client.SetRequestHeader(
            h!("User-Agent"),
            h!("Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)"),
        )?;
    
        let feed = client.RetrieveFeedAsync(&uri)?.get()?;
    
        for item in feed.Items()? {
            println!("{}", item.Title()?.Text()?);
        }
    
        Ok(())
    }
    
  10. 现在让我们通过单击运行>不带调试运行(或按下 Ctrl+F5)来确认可以生成并运行。 如果看到任何意外消息,请确保已成功完成 Hello, world! 教程(Rust 与 VS Code)

    文本编辑器中也嵌入了“调试”和“运行”命令。 或者,在rss_reader文件夹的命令提示符中键入cargo run,这将构建并运行程序。

    文本编辑器中嵌入的“调试”和“运行”命令

    在下面的 VS Code“终端”窗格中,可以看到 Cargo 成功地下载并编译了 windows crate,缓存结果,并使用它们在更短时间内完成后续的生成操作。 然后,它会生成示例并运行该示例,并显示博客文章标题的列表。

    博客文章标题列表

这与为 Windows 编程 Rust 一样简单。 但实际上,很多开发人员都喜欢生成这个工具,这样 Rust 既可以解析基于 ECMA-335(公共语言基础结构 (CLI))的 .winmd 文件,也可以在运行时如实地使用基于 COM 的应用程序二进制接口 (ABI),同时兼顾安全性和效率。

显示消息框

我们确实说,Rust for Windows 允许你调用任何 Windows API(过去、现在和将来)。 因此,在本部分中,我们将显示几个 Windows 消息框。

  1. 就像我们对 RSS 项目执行的操作一样,应在包含 Rust 项目的文件夹的命令提示符 cd 下进行。

  2. 创建名为 message_box的新项目,并在 VS Code 中打开它:

    > cargo new message_box
    >     Created binary (application) `message_box` package
    > cd message_box
    > code .
    
  3. 在 VS Code 中打开 Cargo.toml,然后为该项目添加 Windows 依赖项。

     # message_box\Cargo.toml
     ...
    
     [dependencies.windows]
     version = "0.62.0"
     features = [
         "Win32_Foundation",
         "Win32_UI_WindowsAndMessaging",
     ]
    
  4. 现在打开项目 src/main.rs 的文件,并使用新命名空间添加 use 声明(如下所示)。 最后添加代码以调用 MessageBoxAMessageBoxW 函数。 Windows API 文档主要是用 C/C++ 编写的,因此将 API 文档与 windows crate 中的 Rust 投影文档进行比较很有用:MessageBoxA (Rust)MessageBoxW (Rust)

    // src\main.rs
    use windows::{
        core::*,
        Win32::UI::WindowsAndMessaging::*
    };
    
    fn main() {
        unsafe {
            MessageBoxA(None, s!("Ansi"), s!("World"), MB_OK);
            MessageBoxW(None, w!("Wide"), w!("World"), MB_OK);
        }
    }
    

    如你所见,我们必须在 unsafe 块中使用这些 Win32 应用程序接口(Win32 API)(请参阅 不安全块)。 另请注意 s!w! 宏,它们用于从 Rust UTF-8 字符串字面量创建 LPCSTRLPCWSTR 参数;就像我们使用 h! 宏为 rss_reader创建 HSTRING 一样。 Rust 本地支持 Unicode 和 UTF-8 字符串,因此优先使用带有 W 后缀的宽 Unicode Windows API,而不是带有 A 后缀的 ANSI API。 如果在代码中使用非英语文本,这一点非常重要。

生成和运行时,Rust 会显示两个 Windows 消息框。