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.43.0"
    features = [
        "Foundation_Collections",
        "Web_Syndication",
    ]
    
  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(())
    }
    

    new 函数是 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 函数来简化此示例。 此外,也可在 async 函数内使用 await 运算符以协作方式等待结果。 对于具有图形用户界面的更复杂应用,将经常使用 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,这将生成并运行程序。

    The Debug and Run commands embedded in the text editor

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

    List of blog post titles

这和为 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.43.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 API(请参阅不安全块)。 另请注意 s! 和 w! 宏,它们基于 Rust UTF-8 字符串文本创建 LPCSTR​​ 和 LPCWSTR 参数;就像我们为 rss_reader 使用 h! 宏创建 HSTRING 一样。 Rust 是带有 UTF-8 字符串的本机 Unicode,因此使用宽 Unicode(W 后缀)Windows API 优于 ANSI(A 后缀)API。 如果在代码中使用非英语文本,应注意这一点。

这次当你生成并运行时,Rust 会显示两个 Windows 消息框。