microsoft / windows-rs

Rust for Windows
https://kennykerr.ca/rust-getting-started/
Apache License 2.0
10.42k stars 490 forks source link

Bug: Cannot call ApplicationViewTitleBar.SetBackgroundColor #2542

Closed CXCubeHD closed 1 year ago

CXCubeHD commented 1 year ago

Which crate is this about?

windows

Crate version

0.48.0

Summary

There seems to be no way to call ApplicationViewTitleBar.SetBackgroundColor.

Toolchain version/configuration

Default host: x86_64-pc-windows-msvc rustup home: C:\Users\lukax.rustup

installed toolchains

stable-x86_64-pc-windows-msvc (default) nightly-x86_64-pc-windows-msvc

installed targets for active toolchain

i686-pc-windows-msvc x86_64-pc-windows-msvc

active toolchain

stable-x86_64-pc-windows-msvc (default) rustc 1.67.0 (fc594f156 2023-01-24)

Reproducible example

let color = ColorHelper::FromArgb(255, 31, 19, 226)?;

match ApplicationView::GetForCurrentView()?
    .TitleBar()?
    .SetBackgroundColor(&color) {
    Ok(_) => {}
    Err(_) => {
        println!("Could not set BackgroundColor.");
    }
};

Crate manifest

[dependencies.windows]
version = "0.48.0"
features = [
    "ApplicationModel",
    "ApplicationModel_Core",
    "ApplicationModel_Activation",

    "Data_Xml_Dom",

    "Foundation",

    "Gaming",
    "Gaming_UI",

    "UI",
    "UI_Core",
    "UI_Notifications",
    "UI_ViewManagement",

    "System",

    "Win32_Foundation",
    "Win32_System_Threading",
    "Win32_System_LibraryLoader",
    "Win32_System_ProcessStatus",
    "Win32_System_Console",
    "Win32_System_SystemServices",
    "Win32_System_Threading",
    "Win32_Security",

    "Win32_Graphics",
    "Win32_Graphics_Dxgi",
    "Win32_Graphics_Dxgi_Common",
    "Win32_Graphics_Direct2D",
    "Win32_Graphics_Direct3D",
    "Win32_Graphics_Direct3D11",
    "Win32_Graphics_Direct3D11on12",
    "Win32_Graphics_Direct3D12",

    "Win32_Media_Audio",
    "Win32_Media_Audio_DirectSound",
]

Expected behavior

The code gets compiled.

Actual behavior

error[E0277]: the trait bound `windows::UI::Color: ComInterface` is not satisfied
    --> src\entry\mod.rs:85:37
     |
85   |                 .SetBackgroundColor(&color) {
     |                  ------------------ ^^^^^^ the trait `ComInterface` is not implemented for `windows::UI::Color`
     |                  |
     |                  required by a bound introduced by this call
     |
     = help: the following other types implement trait `ComInterface`:
               AccessibilitySettings
               ActivationViewSwitcher
               AdaptiveNotificationText
               ApplicationView
               ApplicationViewConsolidatedEventArgs
               ApplicationViewScaling
               ApplicationViewTitleBar
               ApplicationViewTransferContext
             and 1123 others
     = note: required for `&windows::UI::Color` to implement `TryIntoParam<windows::Foundation::IReference<windows::UI::Color>>`
note: required by a bound in `ApplicationViewTitleBar::SetBackgroundColor`
    --> C:\Users\lukax\.cargo\registry\src\github.com-1ecc6299db9ec823\windows-0.48.0\src\Windows\UI\ViewManagement\mod.rs:2212:13
     |
2212 |         P0: ::windows::core::TryIntoParam<super::super::Foundation::IReference<super::Color>>,
     |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `ApplicationViewTitleBar::SetBackgroundColor`

Additional comments

Could not find any other ways to do that. Only thing that worked is &None I think

CXCubeHD commented 1 year ago

It would super helpful if someone shows me a way to convert my color to IReference<windows::UI::Color>> properly

kennykerr commented 1 year ago

This is related to #292 - I'll see if I can find you a workaround for now.

riverar commented 1 year ago

This requires boxing up the Windows.UI.Color value and implementing various interfaces, such as IReference, IPropertyValue, ComInterface, etc. There's no easy way to do that right now.

I'd like to warn you now, however, that using Windows.UI.* APIs for UI is a dead end. Universal Windows Apps are on the way out, so to speak, and these APIs were designed to be consumed by C#. (We recently abandoned an effort to provide bindings for newer/alternate WinUI 3 APIs.) I think you might find it more productive to instead use an alternate UI stack with Rust, such as Tauri (web-based) or Dear ImGui (immediate mode DirectX, Win32 GDI, etc).

CXCubeHD commented 1 year ago

This requires boxing up the Windows.UI.Color value and implementing various interfaces, such as IReference, IPropertyValue, ComInterface, etc. There's no easy way to do that right now.

I will see if I can do a workaround by embedding C++

I'd like to warn you now, however, that using Windows.UI.* APIs for UI is a dead end. Universal Windows Apps are on the way out, so to speak, and these APIs were designed to be consumed by C#. (We recently abandoned an effort to provide bindings for newer/alternate WinUI 3 APIs.) I think you might find it more productive to instead use an alternate UI stack with Rust, such as Tauri (web-based) or Dear ImGui (immediate mode DirectX, Win32 GDI, etc).

I am only using Windows.UI for a really small amount of things like changing the title of a CoreWindow.

kennykerr commented 1 year ago

Today, the windows-core crate provides boxing for primitive types but not arbitrary WinRT types as C++/WinRT does. That shouldn't be too hard to add. Coming soon.

kennykerr commented 1 year ago

workaround by embedding C++

Note that you can use the implement macro to implement IReference<T> and IPropertyValue so there's no need to resort to C++.

The windows-core support I'm working on just means that those IReference parameters, modeling optional values, can be modeled as Option<T> in Rust.

CXCubeHD commented 1 year ago

Note that you can use the implement macro to implement IReference<T> and IPropertyValue so there's no need to resort to C++.

How would I do that with windows::UI::Color?

kennykerr commented 1 year ago

Here's an example:

[dependencies.windows]
version = "0.48"
features = [
    "implement",
    "Foundation",
    "UI",
]
use windows::{core::*, Foundation::*, UI::*};

#[implement(IReference<T>, IPropertyValue)]
struct Reference<T>(T)
where
    T: RuntimeType + Clone + 'static;

impl<T: RuntimeType + Clone> IReference_Impl<T> for Reference<T> {
    fn Value(&self) -> Result<T> {
        Ok(self.0.clone())
    }
}

impl<T: RuntimeType + Clone> IPropertyValue_Impl for Reference<T> {
    fn GetInt16Array(&self, _: &mut Array<i16>) -> Result<()> {
        todo!()
    }
    fn GetUInt16Array(&self, _: &mut Array<u16>) -> Result<()> {
        todo!()
    }
    fn GetInt32Array(&self, _: &mut Array<i32>) -> Result<()> {
        todo!()
    }
    fn GetUInt32Array(&self, _: &mut Array<u32>) -> Result<()> {
        todo!()
    }
    fn GetInt64Array(&self, _: &mut Array<i64>) -> Result<()> {
        todo!()
    }
    fn GetUInt64Array(&self, _: &mut Array<u64>) -> Result<()> {
        todo!()
    }
    fn GetSingleArray(&self, _: &mut Array<f32>) -> Result<()> {
        todo!()
    }
    fn GetDoubleArray(&self, _: &mut Array<f64>) -> Result<()> {
        todo!()
    }
    fn GetChar16Array(&self, _: &mut Array<u16>) -> Result<()> {
        todo!()
    }
    fn GetBooleanArray(&self, _: &mut Array<bool>) -> Result<()> {
        todo!()
    }
    fn GetStringArray(&self, _: &mut Array<HSTRING>) -> Result<()> {
        todo!()
    }
    fn GetInspectableArray(&self, _: &mut Array<IInspectable>) -> Result<()> {
        todo!()
    }
    fn GetGuidArray(&self, _: &mut Array<GUID>) -> Result<()> {
        todo!()
    }
    fn GetDateTimeArray(&self, _: &mut Array<DateTime>) -> Result<()> {
        todo!()
    }
    fn GetTimeSpanArray(&self, _: &mut Array<TimeSpan>) -> Result<()> {
        todo!()
    }
    fn GetPointArray(&self, _: &mut Array<Point>) -> Result<()> {
        todo!()
    }
    fn GetSizeArray(&self, _: &mut Array<Size>) -> Result<()> {
        todo!()
    }
    fn GetRectArray(&self, _: &mut Array<Rect>) -> Result<()> {
        todo!()
    }
    fn GetTimeSpan(&self) -> Result<TimeSpan> {
        todo!()
    }
    fn GetPoint(&self) -> Result<Point> {
        todo!()
    }
    fn GetSize(&self) -> Result<Size> {
        todo!()
    }
    fn GetRect(&self) -> Result<Rect> {
        todo!()
    }
    fn GetUInt8Array(&self, _: &mut Array<u8>) -> Result<()> {
        todo!()
    }
    fn Type(&self) -> Result<PropertyType> {
        todo!()
    }
    fn IsNumericScalar(&self) -> Result<bool> {
        todo!()
    }
    fn GetUInt8(&self) -> Result<u8> {
        todo!()
    }
    fn GetInt16(&self) -> Result<i16> {
        todo!()
    }
    fn GetUInt16(&self) -> Result<u16> {
        todo!()
    }
    fn GetInt32(&self) -> Result<i32> {
        todo!()
    }
    fn GetUInt32(&self) -> Result<u32> {
        todo!()
    }
    fn GetInt64(&self) -> Result<i64> {
        todo!()
    }
    fn GetUInt64(&self) -> Result<u64> {
        todo!()
    }
    fn GetSingle(&self) -> Result<f32> {
        todo!()
    }
    fn GetDouble(&self) -> Result<f64> {
        todo!()
    }
    fn GetChar16(&self) -> Result<u16> {
        todo!()
    }
    fn GetBoolean(&self) -> Result<bool> {
        todo!()
    }
    fn GetString(&self) -> Result<HSTRING> {
        todo!()
    }
    fn GetGuid(&self) -> Result<GUID> {
        todo!()
    }
    fn GetDateTime(&self) -> Result<DateTime> {
        todo!()
    }
}

fn box_value<T: RuntimeType + Clone>(value: T) -> IReference<T> {
    Reference(value).into()
}

fn main() -> Result<()> {
    let red = Colors::Red()?;
    dbg!(red);

    let boxed = box_value(red);
    assert_eq!(boxed.Value()?, red);

    Ok(())
}

Depending on the API you're calling, you may need to implement some of the IPropertyValue methods but most can generally be ignored. Obviously, a production implementation should return E_NOTIMPL for unimplemented methods but this is just a quick sketch that should get you going.

As you can see, it's a bit involved which is why I'd like to just bake this in to accept Option<T>.

CXCubeHD commented 1 year ago

@kennykerr Thank you soo much!

riverar commented 1 year ago

Closing as complete for now; workaround above and we're tracking related work via https://github.com/microsoft/windows-rs/issues/292.