From 60f9e456952f9ef46aaf603cdde0a05e2e8a7de7 Mon Sep 17 00:00:00 2001 From: Kenny Kerr Date: Mon, 15 Jan 2024 10:01:48 -0600 Subject: [PATCH] Expand WMI sample for `ExecQuery` and `ExecMethod` (#2794) --- crates/libs/core/src/strings/bstr.rs | 20 ++++++-- crates/libs/core/src/variant.rs | 12 +++++ crates/samples/windows/wmi/src/main.rs | 65 +++++++++++++++++++------- crates/tests/variant/tests/tests.rs | 2 + 4 files changed, 77 insertions(+), 22 deletions(-) diff --git a/crates/libs/core/src/strings/bstr.rs b/crates/libs/core/src/strings/bstr.rs index 13a06138f2..91197ebd12 100644 --- a/crates/libs/core/src/strings/bstr.rs +++ b/crates/libs/core/src/strings/bstr.rs @@ -29,11 +29,17 @@ impl BSTR { /// Get the string as 16-bit wide characters (wchars). pub fn as_wide(&self) -> &[u16] { - if self.0.is_null() { - return &[]; - } + unsafe { std::slice::from_raw_parts(self.as_ptr(), self.len()) } + } - unsafe { std::slice::from_raw_parts(self.0, self.len()) } + /// Returns a raw pointer to the `BSTR` buffer. + pub fn as_ptr(&self) -> *const u16 { + if !self.is_empty() { + self.0 + } else { + const EMPTY: [u16; 1] = [0]; + EMPTY.as_ptr() + } } /// Create a `BSTR` from a slice of 16 bit characters (wchars). @@ -105,6 +111,12 @@ impl TryFrom for String { } } +impl IntoParam for &BSTR { + unsafe fn into_param(self) -> Param { + Param::Owned(PCWSTR(self.as_ptr())) + } +} + impl Default for BSTR { fn default() -> Self { Self(std::ptr::null_mut()) diff --git a/crates/libs/core/src/variant.rs b/crates/libs/core/src/variant.rs index b8fdedd2d2..e7885ee30a 100644 --- a/crates/libs/core/src/variant.rs +++ b/crates/libs/core/src/variant.rs @@ -84,6 +84,18 @@ impl std::fmt::Debug for PROPVARIANT { } } +impl std::fmt::Display for VARIANT { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::write!(f, "{}", BSTR::try_from(self).unwrap_or_default()) + } +} + +impl std::fmt::Display for PROPVARIANT { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::write!(f, "{}", BSTR::try_from(self).unwrap_or_default()) + } +} + impl PartialEq for VARIANT { fn eq(&self, other: &Self) -> bool { unsafe { diff --git a/crates/samples/windows/wmi/src/main.rs b/crates/samples/windows/wmi/src/main.rs index a7c4553a45..3397885517 100644 --- a/crates/samples/windows/wmi/src/main.rs +++ b/crates/samples/windows/wmi/src/main.rs @@ -1,7 +1,4 @@ -use windows::{ - core::*, Win32::System::Com::*, Win32::System::Ole::*, Win32::System::Variant::*, - Win32::System::Wmi::*, -}; +use windows::{core::*, Win32::System::Com::*, Win32::System::Wmi::*}; fn main() -> Result<()> { unsafe { @@ -24,6 +21,10 @@ fn main() -> Result<()> { let server = locator.ConnectServer(&BSTR::from("root\\cimv2"), None, None, None, 0, None, None)?; + // + // ExecQuery example + // + let query = server.ExecQuery( &BSTR::from("WQL"), &BSTR::from("select Caption from Win32_LogicalDisk"), @@ -37,26 +38,54 @@ fn main() -> Result<()> { query.Next(WBEM_INFINITE, &mut row, &mut returned).ok()?; if let Some(row) = &row[0] { - let mut value = Default::default(); + let mut value = VARIANT::default(); row.Get(w!("Caption"), 0, &mut value, None, None)?; - println!( - "{}", - VarFormat( - &value, - None, - VARFORMAT_FIRST_DAY_SYSTEMDEFAULT, - VARFORMAT_FIRST_WEEK_SYSTEMDEFAULT, - 0 - )? - ); - - // TODO: workaround for https://github.com/microsoft/windows-rs/issues/539 - VariantClear(&mut value)?; + println!("{value}",); } else { break; } } + // + // ExecMethod example + // + + let class_name = BSTR::from("Win32_Process"); + let method_name = BSTR::from("Create"); + + let mut class = None; + server.GetObject( + &class_name, + Default::default(), + None, + Some(&mut class), + None, + )?; + let class = class.unwrap(); + + let mut input = None; + class.GetMethod(&method_name, 0, &mut input, std::ptr::null_mut())?; + let input = input.unwrap(); + + let object = input.SpawnInstance(0)?; + object.Put(w!("CommandLine"), 0, &VARIANT::from("notepad.exe"), 0)?; + + let mut output = None; + server.ExecMethod( + &class_name, + &method_name, + Default::default(), + None, + &object, + Some(&mut output), + None, + )?; + let output = output.unwrap(); + + let mut value = VARIANT::default(); + output.Get(w!("ReturnValue"), 0, &mut value, None, None)?; + println!("`Create` method return value: {value}"); + Ok(()) } } diff --git a/crates/tests/variant/tests/tests.rs b/crates/tests/variant/tests/tests.rs index 9a7a558632..b348a15cc6 100644 --- a/crates/tests/variant/tests/tests.rs +++ b/crates/tests/variant/tests/tests.rs @@ -103,6 +103,7 @@ fn test_variant() -> Result<()> { assert_eq!(BSTR::try_from(&v)?, "3.5"); assert_eq!(format!("{v:?}"), "VARIANT { type: 5, value: 3.5 }"); + assert_eq!(format!("{v}"), "3.5"); let clone = v.clone(); assert_eq!(v, clone); @@ -219,6 +220,7 @@ fn test_propvariant() -> Result<()> { assert_eq!(BSTR::try_from(&v)?, "3.5"); assert_eq!(format!("{v:?}"), "PROPVARIANT { type: 5, value: 3.5 }"); + assert_eq!(format!("{v}"), "3.5"); let clone = v.clone(); assert_eq!(v, clone);