RSS-Reader-Tutorial (Rust für Windows mit VS Code)

Im vorherigen Thema wurden Rust für Windows und die Kiste „windows“ vorgestellt.

Jetzt probieren wir Rust für Windows aus, indem wir eine einfache Konsolen-App schreiben, die die Titel von Blogbeiträgen aus einem RSS-Feed (Really Simple Syndication) herunterlädt.

  1. Starten Sie eine Eingabeaufforderung (cmd.exe), und wechseln (cd) Sie zu einem Ordner, in dem Sie Ihre Rust-Projekte aufbewahren möchten.

  2. Erstellen Sie mithilfe von Cargo ein neues Rust-Projekt namens rss_reader, und wechseln Sie mithilfe von cd in den neu erstellten Ordner:

    > cargo new rss_reader
    >     Created binary (application) `rss_reader` package
    > cd rss_reader
    
  3. Öffnen Sie dann das rss_reader Projekt in VS Code.

    code .
    
  4. Implementieren Sie nun das Hauptprojekt rss_reader. Öffnen Sie zunächst die Cargo.toml Datei im Stammverzeichnis des Projekts. Eine Cargo.toml Datei ist eine Textdatei, die ein Rust-Projekt beschreibt, einschließlich aller Abhängigkeiten, die es hat.

    Fügen Sie eine Abhängigkeit von der Kiste windows hinzu, wie im folgenden Listing gezeigt. Die Kiste windows ist groß. Um die Erstellungszeiten kurz zu halten, wählen wir nur die Funktionen Foundation_Collections und Web_Syndication aus, die wir für diesen Code benötigen.

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

    Note

    Das windows Crate veröffentlicht häufig. Überprüfen Sie crates.io/crates/windows auf die neueste Version, und aktualisieren Sie sie entsprechend.

  5. Öffnen Sie anschließend die Quellcodedatei src/main.rs des Projekts rss_reader. Dort finden Sie den Cargo-Standardcode "Hello, world!". Fügen Sie am Anfang von main.rs die folgende use-Anweisung hinzu:

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

    Durch die use-Deklaration wird der Pfad zu den von uns verwendeten Typen verkürzt. Hier sehen Sie auch den zuvor erwähnten Typ Uri.

  6. Um einen neuen URI zu erstellen, ersetzen Sie die standardmäßige main-Funktion von Cargo durch Folgendes:

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

    Beachten Sie, dass der Rückgabetyp der main-Funktion ein Result-Wert aus windows::core:: ist. Dies dient der Vereinfachung, da häufig Fehler von Betriebssystem-APIs behandelt werden müssen. windows::core::Result ist für die Fehlerweitergabe sowie für eine präzise Fehlerbehandlung hilfreich.

    Haben Sie den Fragezeichen-Operator am Ende der Codezeile bemerkt? Er wird verwendet, um weniger eingeben zu müssen und die Fehlerweitergabe und Kurzschlusslogik von Rust zu verwenden. Das bedeutet, dass wir für dieses einfache Beispiel nicht eine Reihe manueller Fehlerbehandlungen ausführen müssen. Weitere Informationen zu dieser Funktion von Rust finden Sie unter Der ?-Operator für eine einfachere Fehlerbehandlung.

    Beachten Sie auch das Makro h! aus der windows-Kiste. Es wird verwendet, um einen HSTRING-Verweis aus einem Rust-Zeichenfolgenliteral zu erstellen. Die WinRT-API verwendet HSTRING sehr häufig für Zeichenfolgenwerte.

  7. Um den RSS-Feed herunterzuladen, erstellen wir einen neuen SyndicationClient.

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

    Die Funktion new ist ein Rust-Konstruktor. Alle Objekte in der windows-Kiste halten die Rust-Konvention und nennen ihre Konstruktoren new.

  8. Nun können Sie SyndicationClient verwenden, um den Feed abzurufen.

    // 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(())
    }
    

    Da es sich bei RetrieveFeedAsync um eine asynchrone API handelt, verwenden wir die blockierende Funktion get, um das Beispiel einfach zu halten. Alternativ könnten wir den await Operator innerhalb einer async Funktion verwenden, um kooperativ auf die Ergebnisse zu warten. Eine komplexere App mit einer grafischen Benutzeroberfläche wird häufig async verwenden.

  9. Nun können Sie die resultierenden Elemente durchlaufen und die Ausgabe auf die Titel beschränken. Sie werden außerdem unten einige zusätzliche Codezeilen sehen, um einen User-Agent-Header festzulegen, da einige RSS-Feeds dies erfordern.

    // 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. Überprüfen Sie als Nächstes, ob das Erstellen und Ausführen funktioniert. Klicken Sie hierzu auf Ausführen>Ohne Debuggen ausführen (oder drücken Sie STRG+F5). Wenn unerwartete Nachrichten angezeigt werden, stellen Sie sicher, dass Sie das Hello, world! Tutorial (Rust mit VS Code)erfolgreich abgeschlossen haben.

    Befehle zum Debuggen und Ausführen stehen auch im Text-Editor zur Verfügung. Geben Sie alternativ an einer Eingabeaufforderung rss_reader im Ordner cargo run ein, um das Programm zu erstellen und dann auszuführen.

    Die Befehle

    Weiter unten im Terminalbereich von VS Code sehen Sie, dass Cargo die Kiste windows erfolgreich herunterlädt und kompiliert, die Ergebnisse zwischenspeichert und so nachfolgende Buildvorgänge beschleunigt. Anschließend wird das Beispiel erstellt und ausgeführt, und es wird eine Liste mit Blogbeitragstiteln angezeigt.

    Liste der Blogbeitragstitel

Das ist so einfach wie das Programmieren von Rust für Windows. Im Hintergrund wird jedoch viel Arbeit in die Erstellung der Tools investiert, damit Rust Dateien vom Typ .winmd auf der Grundlage von ECMA-335 (Common Language Infrastructure, CLI) analysieren sowie zur Laufzeit ordnungsgemäß die COM-basierte binäre Anwendungsschnittstelle (Application Binary Interface, ABI) unter Berücksichtigung von Sicherheits- und Effizienzaspekten nutzen kann.

Anzeigen eines Nachrichtenfelds

Wir haben gesagt, dass Rust für Windows jede Windows-API aufrufen kann (Vergangenheit, Gegenwart und Zukunft). In diesem Abschnitt werden also einige Windows-Meldungsfelder angezeigt.

  1. Genau wie beim RSS-Projekt wechseln Sie in der Eingabeaufforderung cd in den Ordner mit Ihren Rust-Projekten.

  2. Erstellen Sie ein neues Projekt mit dem Namen message_box, und öffnen Sie es in VS Code:

    > cargo new message_box
    >     Created binary (application) `message_box` package
    > cd message_box
    > code .
    
  3. Öffnen Sie Cargo.toml in VS Code, und fügen Sie die Windows-Abhängigkeiten für dieses Projekt hinzu:

     # message_box\Cargo.toml
     ...
    
     [dependencies.windows]
     version = "0.62.0"
     features = [
         "Win32_Foundation",
         "Win32_UI_WindowsAndMessaging",
     ]
    
  4. Öffnen Sie nun die src/main.rs-Datei des Projekts und fügen Sie die use-Deklarationen mit den neuen „Namespaces“ hinzu (siehe unten). Fügen Sie schließlich Code hinzu, um die Funktionen MessageBoxA und MessageBoxW aufzurufen. Die Windows-API-Dokumente sind hauptsächlich in C/C++ geschrieben, daher ist es hilfreich, die API-Dokumente mit den Dokumenten für die Rust-Projektionen in der windows-Kiste zu vergleichen: MessageBoxA (Rust) und 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);
        }
    }
    

    Wie Sie sehen können, müssen wir diese Win32-APIs in einem unsafe Block verwenden (siehe unsichere Blöcke). Beachten Sie auch die Makros s! und w!, die die Argumente LPCSTR und LPCWSTR aus Rust-UTF-8-Zeichenfolgenliteralen erstellen, ähnlich wie Sie ein HSTRING-Element mit dem Makro h! für rss_reader erstellt haben. Rust ist nativer Unicode-Text mit UTF-8-Zeichenfolgen. Daher wird die Verwendung der Windows-APIs für Unicode-Doppelbytezeichen (W-Suffix) den ANSI-APIs (A-Suffix) vorgezogen. Dies kann wichtig sein, wenn Sie nicht englischen Text in Ihrem Code verwenden.

Dieses Mal, wenn Sie erstellen und ausführen, zeigt Rust zwei Windows-Meldungsfelder an.