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,这将生成并运行程序。

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

    在下面的 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.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 消息框。