Can you even use Rust for Windows GUI programming? Is it a practical choice at all for interfaces?

In theory yes, but there's a lot of quirks and limitations.

The main issues are:

- Rust string types assume UTF-8, but Windows generally uses double-byte Unicode encodings. The Windows string type isn't even UTF16, because it can include invalid code points. This means that at every API call there will be the overhead of converting the string encodings and having to "deal" with invalid strings somehow.

- Rust compilation is still very slow. In C++, it was a simple matter of including "windows.h" and then start typing code. In Rust, trying to do this naively would result in terrible "inner loop" for the developers. There are some fixes, but they're fiddly.

- Enormous API surface with missing metadata. This is a problem with Rust-to-C interop in general, but the Win32 APIs are so huge that it's impractical to solve manually. There have been efforts by Microsoft to produce official and authoritative interface definitions with additional metadata such as tagging "in" and "out" parameters, etc... This isn't sufficient for Rust, which has a much more complex type system than vanilla C pointers. E.g.: lifetimes, non-null by default, etc...

At this time, programming in Rust for Windows is basically writing C++ code in Rust syntax, but with a slower compile time than C++ would have. Arguably, there isn't even much of a safety benefit, because that would require an extensive set of "shims" to be produced to make Win32 act more like Rust and less like C/C++. Take a look at the size of the .NET Framework standard library to get an idea of what that entails. Not impossible, but not a trivial effort either!

The best and most authoritative bindings are: https://github.com/microsoft/windows-rs

The "demo" looks okay at first glance:

    unsafe {
        let event = CreateEventW(None, true, false, None)?;
        SetEvent(event).ok()?;
        WaitForSingleObject(event, 0);
        CloseHandle(event).ok()?;

        MessageBoxA(None, s!("Ansi"), s!("Caption"), MB_OK);
        MessageBoxW(None, w!("Wide"), w!("Caption"), MB_OK);
    }
But if you start digging deeper into callbacks that manipulate structures that include hideous things such as lists of strings separated by null bytes, you're back in "the weeds" just like with C/C++.