diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml index e5ac894355..7104bf229d 100644 --- a/.github/workflows/clippy.yml +++ b/.github/workflows/clippy.yml @@ -60,6 +60,7 @@ jobs: cargo clippy -p sample_privileges && cargo clippy -p sample_privileges_sys && cargo clippy -p sample_rss && + cargo clippy -p sample_shell && cargo clippy -p sample_simple && cargo clippy -p sample_spellchecker && cargo clippy -p sample_thread_pool_work && diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f945de9eeb..30fa52b2df 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -67,6 +67,7 @@ jobs: cargo test -p sample_privileges && cargo test -p sample_privileges_sys && cargo test -p sample_rss && + cargo test -p sample_shell && cargo test -p sample_simple && cargo test -p sample_spellchecker && cargo test -p sample_thread_pool_work && @@ -100,8 +101,8 @@ jobs: cargo test -p test_enums && cargo test -p test_error && cargo test -p test_event && - cargo test -p test_extensions && cargo clean && + cargo test -p test_extensions && cargo test -p test_handles && cargo test -p test_helpers && cargo test -p test_implement && diff --git a/crates/libs/core/src/variant.rs b/crates/libs/core/src/variant.rs index a0b3e59dfe..b8fdedd2d2 100644 --- a/crates/libs/core/src/variant.rs +++ b/crates/libs/core/src/variant.rs @@ -229,6 +229,18 @@ impl From for PROPVARIANT { } } +impl From<&str> for VARIANT { + fn from(value: &str) -> Self { + BSTR::from(value).into() + } +} + +impl From<&str> for PROPVARIANT { + fn from(value: &str) -> Self { + BSTR::from(value).into() + } +} + impl TryFrom<&VARIANT> for BSTR { type Error = Error; fn try_from(from: &VARIANT) -> Result { diff --git a/crates/samples/windows/shell/Cargo.toml b/crates/samples/windows/shell/Cargo.toml new file mode 100644 index 0000000000..91517c92ac --- /dev/null +++ b/crates/samples/windows/shell/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "sample_shell" +version = "0.0.0" +edition = "2021" +publish = false + +[dependencies.windows] +path = "../../../libs/windows" +features = [ + "Win32_System_Com", + "Win32_System_Ole", + "Win32_UI_Shell", + "Win32_UI_WindowsAndMessaging", +] diff --git a/crates/samples/windows/shell/src/main.rs b/crates/samples/windows/shell/src/main.rs new file mode 100644 index 0000000000..3e4287ef18 --- /dev/null +++ b/crates/samples/windows/shell/src/main.rs @@ -0,0 +1,63 @@ +use windows::{ + core::*, Win32::System::Com::*, Win32::UI::Shell::*, Win32::UI::WindowsAndMessaging::*, +}; + +fn main() -> Result<()> { + unsafe { CoInitialize(None)? }; + + shell_execute_from_explorer( + "https://github.com/microsoft/windows-rs", + "", + "", + "", + SW_SHOWNORMAL, + ) +} + +// Ported from https://devblogs.microsoft.com/oldnewthing/20131118-00/?p=2643 +fn shell_execute_from_explorer( + file: &str, + args: &str, + directory: &str, + operation: &str, + show: SHOW_WINDOW_CMD, +) -> Result<()> { + unsafe { + let view: IShellView = find_desktop_folder_view()?; + let background: IDispatch = view.GetItemObject(SVGIO_BACKGROUND)?; + let folder: IShellFolderViewDual = background.cast()?; + let shell: IShellDispatch2 = folder.Application()?.cast()?; + + shell.ShellExecute( + &BSTR::from(file), + &VARIANT::from(args), + &VARIANT::from(directory), + &VARIANT::from(operation), + &VARIANT::from(show.0), + ) + } +} + +// Ported from https://devblogs.microsoft.com/oldnewthing/20130318-00/?p=4933 +fn find_desktop_folder_view() -> Result { + unsafe { + let windows: IShellWindows = CoCreateInstance(&ShellWindows, None, CLSCTX_ALL)?; + let mut dispatch = None; + let mut handle = 0; + + // TODO: find out why this retval isn't kicking in + windows.FindWindowSW( + &VARIANT::from(CSIDL_DESKTOP), + &VARIANT::default(), + SWC_DESKTOP, + &mut handle, + SWFO_NEEDDISPATCH, + &mut dispatch, + )?; + + let provider: IServiceProvider = dispatch.unwrap().cast()?; + let browser: IShellBrowser = provider.QueryService(&SID_STopLevelBrowser)?; + let view = browser.QueryActiveShellView()?; + view.cast() + } +} diff --git a/crates/tests/variant/tests/tests.rs b/crates/tests/variant/tests/tests.rs index c7b6115080..9a7a558632 100644 --- a/crates/tests/variant/tests/tests.rs +++ b/crates/tests/variant/tests/tests.rs @@ -94,6 +94,11 @@ fn test_variant() -> Result<()> { VARIANT::from(BSTR::from("goodbye")) ); + let v = VARIANT::from("hello"); + assert_eq!(BSTR::try_from(&v)?, "hello"); + assert_eq!(VARIANT::from("hello"), VARIANT::from("hello")); + assert_ne!(VARIANT::from("hello"), VARIANT::from("goodbye")); + let v = VARIANT::from(3.5f64); assert_eq!(BSTR::try_from(&v)?, "3.5"); @@ -205,6 +210,11 @@ fn test_propvariant() -> Result<()> { PROPVARIANT::from(BSTR::from("goodbye")) ); + let v = PROPVARIANT::from("hello"); + assert_eq!(BSTR::try_from(&v)?, "hello"); + assert_eq!(PROPVARIANT::from("hello"), PROPVARIANT::from("hello")); + assert_ne!(PROPVARIANT::from("hello"), PROPVARIANT::from("goodbye")); + let v = PROPVARIANT::from(3.5f64); assert_eq!(BSTR::try_from(&v)?, "3.5");