diff options
| author | mo khan <mo@mokhan.ca> | 2025-07-02 18:36:06 -0600 |
|---|---|---|
| committer | mo khan <mo@mokhan.ca> | 2025-07-02 18:36:06 -0600 |
| commit | 8cdfa445d6629ffef4cb84967ff7017654045bc2 (patch) | |
| tree | 22f0b0907c024c78d26a731e2e1f5219407d8102 /vendor/windows-core/src | |
| parent | 4351c74c7c5f97156bc94d3a8549b9940ac80e3f (diff) | |
chore: add vendor directory
Diffstat (limited to 'vendor/windows-core/src')
33 files changed, 4068 insertions, 0 deletions
diff --git a/vendor/windows-core/src/agile_reference.rs b/vendor/windows-core/src/agile_reference.rs new file mode 100644 index 00000000..30554e97 --- /dev/null +++ b/vendor/windows-core/src/agile_reference.rs @@ -0,0 +1,39 @@ +use super::*; +use core::marker::PhantomData; + +/// A type representing an agile reference to a COM/WinRT object. +#[repr(transparent)] +#[derive(Clone, PartialEq, Eq)] +pub struct AgileReference<T>(imp::IAgileReference, PhantomData<T>); + +impl<T: Interface> AgileReference<T> { + /// Creates an agile reference to the object. + pub fn new(object: &T) -> Result<Self> { + // TODO: this assert is required until we can catch this at compile time using an "associated const equality" constraint. + // For example, <T: Interface<UNKNOWN = true>> + // https://github.com/rust-lang/rust/issues/92827 + assert!(T::UNKNOWN); + unsafe { + imp::RoGetAgileReference( + imp::AGILEREFERENCE_DEFAULT, + &T::IID, + core::mem::transmute::<&T, &IUnknown>(object), + ) + .map(|reference| Self(reference, Default::default())) + } + } + + /// Retrieves a proxy to the target of the `AgileReference` object that may safely be used within any thread context in which get is called. + pub fn resolve(&self) -> Result<T> { + unsafe { self.0.Resolve() } + } +} + +unsafe impl<T: Interface> Send for AgileReference<T> {} +unsafe impl<T: Interface> Sync for AgileReference<T> {} + +impl<T> core::fmt::Debug for AgileReference<T> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "AgileReference({:?})", &self.0) + } +} diff --git a/vendor/windows-core/src/array.rs b/vendor/windows-core/src/array.rs new file mode 100644 index 00000000..1dca64f1 --- /dev/null +++ b/vendor/windows-core/src/array.rs @@ -0,0 +1,186 @@ +use super::*; + +/// A WinRT array stores elements contiguously in a heap-allocated buffer. +pub struct Array<T: Type<T>> { + data: *mut T::Default, + len: u32, +} + +impl<T: Type<T>> Default for Array<T> { + fn default() -> Self { + Array { + data: core::ptr::null_mut(), + len: 0, + } + } +} + +impl<T: Type<T>> Array<T> { + /// Creates an empty array. + pub fn new() -> Self { + Self::default() + } + + /// Creates an array of the given length with default values. + pub fn with_len(len: usize) -> Self { + assert!(len < u32::MAX as usize); + let bytes_amount = len + .checked_mul(core::mem::size_of::<T>()) + .expect("Attempted to allocate too large an Array"); + + // WinRT arrays must be allocated with CoTaskMemAlloc. + // SAFETY: the call to CoTaskMemAlloc is safe to perform + // if len is zero and overflow was checked above. + // We ensured we alloc enough space by multiplying len * size_of::<T> + let data = unsafe { imp::CoTaskMemAlloc(bytes_amount) as *mut T::Default }; + + assert!(!data.is_null(), "Could not successfully allocate for Array"); + + // SAFETY: It is by definition safe to zero-initialize WinRT types. + // `write_bytes` will write 0 to (len * size_of::<T>()) + // bytes making the entire array zero initialized. We have assured + // above that the data ptr is not null. + unsafe { + core::ptr::write_bytes(data, 0, len); + } + + let len = len as u32; + Self { data, len } + } + + /// Creates an array by copying the elements from the slice. + pub fn from_slice(values: &[T::Default]) -> Self + where + T::Default: Clone, + { + let mut array = Self::with_len(values.len()); + array.clone_from_slice(values); + array + } + + /// Creates an array from a pointer and length. The `len` argument is the number of elements, not the number of bytes. + /// # Safety + /// The `data` argument must have been allocated with `CoTaskMemAlloc`. + pub unsafe fn from_raw_parts(data: *mut T::Default, len: u32) -> Self { + Self { data, len } + } + + /// Returns a slice containing the entire array. + pub fn as_slice(&self) -> &[T::Default] { + self + } + + /// Returns `true` if the array is empty. + pub fn is_empty(&self) -> bool { + self.len == 0 + } + + /// Returns the length of the array. + pub fn len(&self) -> usize { + self.len as usize + } + + /// Clears the contents of the array. + pub fn clear(&mut self) { + if self.is_empty() { + return; + } + + let mut data = core::ptr::null_mut(); + let mut len = 0; + + core::mem::swap(&mut data, &mut self.data); + core::mem::swap(&mut len, &mut self.len); + + // SAFETY: At this point, self has been reset to zero so any panics in T's destructor would + // only leak data not leave the array in bad state. + unsafe { + // Call the destructors of all the elements of the old array + // SAFETY: the slice cannot be used after the call to `drop_in_place` + core::ptr::drop_in_place(core::slice::from_raw_parts_mut(data, len as usize)); + // Free the data memory where the elements were + // SAFETY: we have unique access to the data pointer at this point + // so freeing it is the right thing to do + imp::CoTaskMemFree(data as _); + } + } + + #[doc(hidden)] + /// Get a mutable pointer to the array's length + /// + /// # Safety + /// + /// This function is safe but writing to the pointer is not. Calling this without + /// a subsequent call to `set_abi` is likely to either leak memory or cause UB + pub unsafe fn set_abi_len(&mut self) -> *mut u32 { + &mut self.len + } + + #[doc(hidden)] + /// Turn the array into a pointer to its data and its length + pub fn into_abi(self) -> (*mut T::Abi, u32) { + let abi = (self.data as *mut _, self.len); + core::mem::forget(self); + abi + } +} + +impl<T: Type<T>> core::ops::Deref for Array<T> { + type Target = [T::Default]; + + fn deref(&self) -> &[T::Default] { + if self.is_empty() { + return &[]; + } + + // SAFETY: data must not be null if the array is not empty + unsafe { core::slice::from_raw_parts(self.data, self.len as usize) } + } +} + +impl<T: Type<T>> core::ops::DerefMut for Array<T> { + fn deref_mut(&mut self) -> &mut [T::Default] { + if self.is_empty() { + return &mut []; + } + + // SAFETY: data must not be null if the array is not empty + unsafe { core::slice::from_raw_parts_mut(self.data, self.len as usize) } + } +} + +impl<T: Type<T>> Drop for Array<T> { + fn drop(&mut self) { + self.clear(); + } +} + +#[doc(hidden)] +pub struct ArrayProxy<T: Type<T>> { + data: *mut *mut T::Default, + len: *mut u32, + temp: core::mem::ManuallyDrop<Array<T>>, +} + +impl<T: Type<T>> ArrayProxy<T> { + pub fn from_raw_parts(data: *mut *mut T::Default, len: *mut u32) -> Self { + Self { + data, + len, + temp: core::mem::ManuallyDrop::new(Array::new()), + } + } + + pub fn as_array(&mut self) -> &mut Array<T> { + &mut self.temp + } +} + +impl<T: Type<T>> Drop for ArrayProxy<T> { + fn drop(&mut self) { + unsafe { + *self.data = self.temp.data; + *self.len = self.temp.len; + } + } +} diff --git a/vendor/windows-core/src/as_impl.rs b/vendor/windows-core/src/as_impl.rs new file mode 100644 index 00000000..75a8b60b --- /dev/null +++ b/vendor/windows-core/src/as_impl.rs @@ -0,0 +1,20 @@ +/// A trait for retrieving the implementation behind a COM or WinRT interface. +/// +/// This trait is automatically implemented when using the `implement` macro. +pub trait AsImpl<T> { + /// # Safety + /// + /// The caller needs to ensure that `self` is actually implemented by the + /// implementation `T`. + unsafe fn as_impl(&self) -> &T { + unsafe { self.as_impl_ptr().as_ref() } + } + + /// Returns a pointer to the implementation object. + /// + /// # Safety + /// + /// The caller needs to ensure that `self` is actually implemented by the + /// implementation `T`. + unsafe fn as_impl_ptr(&self) -> core::ptr::NonNull<T>; +} diff --git a/vendor/windows-core/src/com_object.rs b/vendor/windows-core/src/com_object.rs new file mode 100644 index 00000000..bcd1926a --- /dev/null +++ b/vendor/windows-core/src/com_object.rs @@ -0,0 +1,394 @@ +use crate::imp::Box; +use crate::{IUnknown, IUnknownImpl, Interface, InterfaceRef}; +use core::any::Any; +use core::borrow::Borrow; +use core::ops::Deref; +use core::ptr::NonNull; + +/// Identifies types that can be placed in [`ComObject`]. +/// +/// This trait links types that can be placed in `ComObject` with the types generated by the +/// `#[implement]` macro. The `#[implement]` macro generates implementations of this trait. +/// The generated types contain the vtable layouts and refcount-related fields for the COM +/// object implementation. +/// +/// This trait is an implementation detail of the Windows crates. +/// User code should not deal directly with this trait. +/// +/// This trait is sort of the reverse of [`IUnknownImpl`]. This trait allows user code to use +/// [`ComObject<T>`] instead of `ComObject<T_Impl>`. +pub trait ComObjectInner: Sized { + /// The generated `<foo>_Impl` type (aka the "boxed" type or "outer" type). + type Outer: IUnknownImpl<Impl = Self>; + + /// Moves an instance of this type into a new ComObject box and returns it. + /// + /// # Safety + /// + /// It is important that safe Rust code never be able to acquire an owned instance of a + /// generated "outer" COM object type, e.g. `<foo>_Impl`. This would be unsafe because the + /// `<foo>_Impl` object contains a reference count field and provides methods that adjust + /// the reference count, and destroy the object when the reference count reaches zero. + /// + /// Safe Rust code must only be able to interact with these values by accessing them via a + /// `ComObject` reference. `ComObject` handles adjusting reference counts and associates the + /// lifetime of a `&<foo>_Impl` with the lifetime of the related `ComObject`. + /// + /// The `#[implement]` macro generates the implementation of this `into_object` method. + /// The generated `into_object` method encapsulates the construction of the `<foo>_Impl` + /// object and immediately places it into the heap and returns a `ComObject` reference to it. + /// This ensures that our requirement -- that safe Rust code never own a `<foo>_Impl` value + /// directly -- is met. + fn into_object(self) -> ComObject<Self>; +} + +/// Describes the COM interfaces implemented by a specific COM object. +/// +/// The `#[implement]` macro generates implementations of this trait. Implementations are attached +/// to the "outer" types generated by `#[implement]`, e.g. the `MyApp_Impl` type. Each +/// implementation knows how to locate the interface-specific field within `MyApp_Impl`. +/// +/// This trait is an implementation detail of the Windows crates. +/// User code should not deal directly with this trait. +pub trait ComObjectInterface<I: Interface> { + /// Gets a borrowed interface that is implemented by `T`. + fn as_interface_ref(&self) -> InterfaceRef<'_, I>; +} + +/// A counted pointer to a type that implements COM interfaces, where the object has been +/// placed in the heap (boxed). +/// +/// This type exists so that you can place an object into the heap and query for COM interfaces, +/// without losing the safe reference to the implementation object. +/// +/// Because the pointer inside this type is known to be non-null, `Option<ComObject<T>>` should +/// always have the same size as a single pointer. +/// +/// # Safety +/// +/// The contained `ptr` field is an owned, reference-counted pointer to a _pinned_ `Pin<Box<T::Outer>>`. +/// Although this code does not currently use `Pin<T>`, it takes care not to expose any unsafe semantics +/// to safe code. However, code that calls unsafe functions on [`ComObject`] must, like all unsafe code, +/// understand and preserve invariants. +#[repr(transparent)] +pub struct ComObject<T: ComObjectInner> { + ptr: NonNull<T::Outer>, +} + +impl<T: ComObjectInner> ComObject<T> { + /// Allocates a heap cell (box) and moves `value` into it. Returns a counted pointer to `value`. + pub fn new(value: T) -> Self { + T::into_object(value) + } + + /// Creates a new `ComObject` that points to an existing boxed instance. + /// + /// # Safety + /// + /// The caller must ensure that `ptr` points to a valid, heap-allocated instance of `T::Outer`. + /// Normally, this pointer comes from using `Box::into_raw(Box::new(...))`. + /// + /// The pointed-to box must have a reference count that is greater than zero. + /// + /// This function takes ownership of the existing pointer; it does not call `AddRef`. + /// The reference count must accurately reflect all outstanding references to the box, + /// including `ptr` in the count. + pub unsafe fn from_raw(ptr: NonNull<T::Outer>) -> Self { + Self { ptr } + } + + /// Gets a reference to the shared object stored in the box. + /// + /// [`ComObject`] also implements [`Deref`], so you can often deref directly into the object. + /// For those situations where using the [`Deref`] impl is inconvenient, you can use + /// this method to explicitly get a reference to the contents. + #[inline(always)] + pub fn get(&self) -> &T { + self.get_box().get_impl() + } + + /// Gets a reference to the shared object's heap box. + #[inline(always)] + fn get_box(&self) -> &T::Outer { + unsafe { self.ptr.as_ref() } + } + + // Note that we _do not_ provide a way to get a mutable reference to the outer box. + // It's ok to return `&mut T`, but not `&mut T::Outer`. That would allow someone to replace the + // contents of the entire object (box and reference count), which could lead to UB. + // This could maybe be solved by returning `Pin<&mut T::Outer>`, but that requires some + // additional thinking. + + /// Gets a mutable reference to the object stored in the box, if the reference count + /// is exactly 1. If there are multiple references to this object then this returns `None`. + #[inline(always)] + pub fn get_mut(&mut self) -> Option<&mut T> { + if self.is_reference_count_one() { + // SAFETY: We must only return &mut T, *NOT* &mut T::Outer. + // Returning T::Outer would allow swapping the contents of the object, which would + // allow (incorrectly) modifying the reference count. + unsafe { Some(self.ptr.as_mut().get_impl_mut()) } + } else { + None + } + } + + /// If this object has only a single object reference (i.e. this [`ComObject`] is the only + /// reference to the heap allocation), then this method will extract the inner `T` + /// (and return it in an `Ok`) and then free the heap allocation. + /// + /// If there is more than one reference to this object, then this returns `Err(self)`. + #[inline(always)] + pub fn take(self) -> Result<T, Self> { + if self.is_reference_count_one() { + let outer_box: Box<T::Outer> = unsafe { core::mem::transmute(self) }; + Ok(outer_box.into_inner()) + } else { + Err(self) + } + } + + /// Casts to a given interface type. + /// + /// This always performs a `QueryInterface`, even if `T` is known to implement `I`. + /// If you know that `T` implements `I`, then use [`Self::as_interface`] or [`Self::to_interface`] because + /// those functions do not require a dynamic `QueryInterface` call. + #[inline(always)] + pub fn cast<I: Interface>(&self) -> windows_core::Result<I> + where + T::Outer: ComObjectInterface<IUnknown>, + { + let unknown = self.as_interface::<IUnknown>(); + unknown.cast() + } + + /// Gets a borrowed reference to an interface that is implemented by `T`. + /// + /// The returned reference does not have an additional reference count. + /// You can AddRef it by calling [`InterfaceRef::to_owned`]. + #[inline(always)] + pub fn as_interface<I: Interface>(&self) -> InterfaceRef<'_, I> + where + T::Outer: ComObjectInterface<I>, + { + self.get_box().as_interface_ref() + } + + /// Gets an owned (counted) reference to an interface that is implemented by this [`ComObject`]. + #[inline(always)] + pub fn to_interface<I: Interface>(&self) -> I + where + T::Outer: ComObjectInterface<I>, + { + self.as_interface::<I>().to_owned() + } + + /// Converts `self` into an interface that it implements. + /// + /// This does not need to adjust reference counts because `self` is consumed. + #[inline(always)] + pub fn into_interface<I: Interface>(self) -> I + where + T::Outer: ComObjectInterface<I>, + { + unsafe { + let raw = self.get_box().as_interface_ref().as_raw(); + core::mem::forget(self); + I::from_raw(raw) + } + } + + /// This casts the given COM interface to [`&dyn Any`]. It returns a reference to the "outer" + /// object, e.g. `MyApp_Impl`, not the inner `MyApp` object. + /// + /// `T` must be a type that has been annotated with `#[implement]`; this is checked at + /// compile-time by the generic constraints of this method. However, note that the + /// returned `&dyn Any` refers to the _outer_ implementation object that was generated by + /// `#[implement]`, i.e. the `MyApp_Impl` type, not the inner `MyApp` type. + /// + /// If the given object is not a Rust object, or is a Rust object but not `T`, or is a Rust + /// object that contains non-static lifetimes, then this function will return `Err(E_NOINTERFACE)`. + /// + /// The returned value is an owned (counted) reference; this function calls `AddRef` on the + /// underlying COM object. If you do not need an owned reference, then you can use the + /// [`Interface::cast_object_ref`] method instead, and avoid the cost of `AddRef` / `Release`. + pub fn cast_from<I>(interface: &I) -> crate::Result<Self> + where + I: Interface, + T::Outer: Any + 'static + IUnknownImpl<Impl = T>, + { + interface.cast_object() + } +} + +impl<T: ComObjectInner + Default> Default for ComObject<T> { + fn default() -> Self { + Self::new(T::default()) + } +} + +impl<T: ComObjectInner> Drop for ComObject<T> { + fn drop(&mut self) { + unsafe { + T::Outer::Release(self.ptr.as_ptr()); + } + } +} + +impl<T: ComObjectInner> Clone for ComObject<T> { + #[inline(always)] + fn clone(&self) -> Self { + unsafe { + self.ptr.as_ref().AddRef(); + Self { ptr: self.ptr } + } + } +} + +impl<T: ComObjectInner> AsRef<T> for ComObject<T> { + #[inline(always)] + fn as_ref(&self) -> &T { + self.get() + } +} + +impl<T: ComObjectInner> Deref for ComObject<T> { + type Target = T::Outer; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + self.get_box() + } +} + +// There is no DerefMut implementation because we cannot statically guarantee +// that the reference count is 1, which is a requirement for getting exclusive +// access to the contents of the object. Use get_mut() for dynamically-checked +// exclusive access. + +impl<T: ComObjectInner> From<T> for ComObject<T> { + fn from(value: T) -> ComObject<T> { + ComObject::new(value) + } +} + +// Delegate hashing, if implemented. +impl<T: ComObjectInner + core::hash::Hash> core::hash::Hash for ComObject<T> { + fn hash<H: core::hash::Hasher>(&self, state: &mut H) { + self.get().hash(state); + } +} + +// If T is Send (or Sync) then the ComObject<T> is also Send (or Sync). +// Since the actual object storage is in the heap, the object is never moved. +unsafe impl<T: ComObjectInner + Send> Send for ComObject<T> {} +unsafe impl<T: ComObjectInner + Sync> Sync for ComObject<T> {} + +impl<T: ComObjectInner + PartialEq> PartialEq for ComObject<T> { + fn eq(&self, other: &ComObject<T>) -> bool { + let inner_self: &T = self.get(); + let other_self: &T = other.get(); + inner_self == other_self + } +} + +impl<T: ComObjectInner + Eq> Eq for ComObject<T> {} + +impl<T: ComObjectInner + PartialOrd> PartialOrd for ComObject<T> { + fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> { + let inner_self: &T = self.get(); + let other_self: &T = other.get(); + <T as PartialOrd>::partial_cmp(inner_self, other_self) + } +} + +impl<T: ComObjectInner + Ord> Ord for ComObject<T> { + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + let inner_self: &T = self.get(); + let other_self: &T = other.get(); + <T as Ord>::cmp(inner_self, other_self) + } +} + +impl<T: ComObjectInner + core::fmt::Debug> core::fmt::Debug for ComObject<T> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + <T as core::fmt::Debug>::fmt(self.get(), f) + } +} + +impl<T: ComObjectInner + core::fmt::Display> core::fmt::Display for ComObject<T> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + <T as core::fmt::Display>::fmt(self.get(), f) + } +} + +impl<T: ComObjectInner> Borrow<T> for ComObject<T> { + fn borrow(&self) -> &T { + self.get() + } +} + +/// Enables applications to define COM objects using static storage. This is useful for factory +/// objects, stateless objects, or objects which use need to contain or use mutable global state. +/// +/// COM objects that are defined using `StaticComObject` have their storage placed directly in +/// static storage; they are not stored in the heap. +/// +/// COM objects defined using `StaticComObject` do have a reference count and this reference +/// count is adjusted when owned COM interface references (e.g. `IFoo` and `IUnknown`) are created +/// for the object. The reference count is initialized to 1. +/// +/// # Example +/// +/// ```rust,ignore +/// #[implement(IFoo)] +/// struct MyApp { +/// // ... +/// } +/// +/// static MY_STATIC_APP: StaticComObject<MyApp> = MyApp { ... }.into_static(); +/// +/// fn get_my_static_ifoo() -> IFoo { +/// MY_STATIC_APP.to_interface() +/// } +/// ``` +pub struct StaticComObject<T> +where + T: ComObjectInner, +{ + outer: T::Outer, +} + +// IMPORTANT: Do not expose any methods that return mutable access to the contents of StaticComObject. +// Doing so would violate our safety invariants. For example, we provide a Deref impl but it would +// be unsound to provide a DerefMut impl. +impl<T> StaticComObject<T> +where + T: ComObjectInner, +{ + /// Wraps `outer` in a `StaticComObject`. + pub const fn from_outer(outer: T::Outer) -> Self { + Self { outer } + } +} + +impl<T> StaticComObject<T> +where + T: ComObjectInner, +{ + /// Gets access to the contained value. + pub const fn get(&'static self) -> &'static T::Outer { + &self.outer + } +} + +impl<T> core::ops::Deref for StaticComObject<T> +where + T: ComObjectInner, +{ + type Target = T::Outer; + + fn deref(&self) -> &Self::Target { + &self.outer + } +} diff --git a/vendor/windows-core/src/event.rs b/vendor/windows-core/src/event.rs new file mode 100644 index 00000000..3951ef2c --- /dev/null +++ b/vendor/windows-core/src/event.rs @@ -0,0 +1,144 @@ +use super::*; +use core::{iter::once, mem::transmute_copy}; +use std::sync::{Arc, RwLock}; + +/// A type that you can use to declare and implement an event of a specified delegate type. +/// +/// The implementation is thread-safe and designed to avoid contention between events being +/// raised and delegates being added or removed. +pub struct Event<T: Interface> { + delegates: RwLock<Option<Arc<[Delegate<T>]>>>, +} + +unsafe impl<T: Interface> Send for Event<T> {} +unsafe impl<T: Interface> Sync for Event<T> {} + +impl<T: Interface> Default for Event<T> { + fn default() -> Self { + Self::new() + } +} + +impl<T: Interface> Event<T> { + /// Creates a new, empty `Event<T>`. + pub const fn new() -> Self { + Self { + delegates: RwLock::new(None), + } + } + + /// Registers a delegate with the event object. + pub fn add(&self, delegate: &T) -> Result<i64> { + let new_delegate = Delegate::new(delegate)?; + let token = new_delegate.to_token(); + let new_iter = once(new_delegate); + let mut guard = self.delegates.write().unwrap(); + + let new_list = if let Some(old_delegates) = guard.as_ref() { + Arc::from_iter(old_delegates.iter().cloned().chain(new_iter)) + } else { + Arc::from_iter(new_iter) + }; + + let old_list = guard.replace(new_list); + drop(guard); + drop(old_list); // drop the old delegates _after_ releasing lock + + Ok(token) + } + + /// Revokes a delegate's registration from the event object. + pub fn remove(&self, token: i64) { + let mut guard = self.delegates.write().unwrap(); + let mut old_list = None; + if let Some(old_delegates) = guard.as_ref() { + // `self.delegates` is only modified if the token is found. + if let Some(i) = old_delegates + .iter() + .position(|old_delegate| old_delegate.to_token() == token) + { + let new_list = Arc::from_iter( + old_delegates[..i] + .iter() + .chain(old_delegates[i + 1..].iter()) + .cloned(), + ); + + old_list = guard.replace(new_list); + } + } + drop(guard); + drop(old_list); // drop the old delegates _after_ releasing lock + } + + /// Clears the event, removing all delegates. + pub fn clear(&self) { + let mut guard = self.delegates.write().unwrap(); + let old_list = guard.take(); + drop(guard); + drop(old_list); // drop the old delegates _after_ releasing lock + } + + /// Invokes all of the event object's registered delegates with the provided callback. + pub fn call<F: FnMut(&T) -> Result<()>>(&self, mut callback: F) { + let delegates = { + let guard = self.delegates.read().unwrap(); + if let Some(delegates) = guard.as_ref() { + delegates.clone() + } else { + // No delegates to call. + return; + } + // <-- lock is released here + }; + + for delegate in delegates.iter() { + if let Err(error) = delegate.call(&mut callback) { + const RPC_E_SERVER_UNAVAILABLE: HRESULT = HRESULT(-2147023174); // HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE) + if matches!( + error.code(), + imp::RPC_E_DISCONNECTED | imp::JSCRIPT_E_CANTEXECUTE | RPC_E_SERVER_UNAVAILABLE + ) { + self.remove(delegate.to_token()); + } + } + } + } +} + +/// Holds either a direct or indirect reference to a delegate. A direct reference is typically +/// agile while an indirect reference is an agile wrapper. +#[derive(Clone)] +enum Delegate<T> { + Direct(T), + Indirect(AgileReference<T>), +} + +impl<T: Interface> Delegate<T> { + /// Creates a new `Delegate<T>`, containing a suitable reference to the specified delegate. + fn new(delegate: &T) -> Result<Self> { + if delegate.cast::<imp::IAgileObject>().is_ok() { + Ok(Self::Direct(delegate.clone())) + } else { + Ok(Self::Indirect(AgileReference::new(delegate)?)) + } + } + + /// Returns an encoded token to identify the delegate. + fn to_token(&self) -> i64 { + unsafe { + match self { + Self::Direct(delegate) => imp::EncodePointer(transmute_copy(delegate)) as i64, + Self::Indirect(delegate) => imp::EncodePointer(transmute_copy(delegate)) as i64, + } + } + } + + /// Invokes the delegates with the provided callback. + fn call<F: FnMut(&T) -> Result<()>>(&self, mut callback: F) -> Result<()> { + match self { + Self::Direct(delegate) => callback(delegate), + Self::Indirect(delegate) => callback(&delegate.resolve()?), + } + } +} diff --git a/vendor/windows-core/src/guid.rs b/vendor/windows-core/src/guid.rs new file mode 100644 index 00000000..6b08a9fd --- /dev/null +++ b/vendor/windows-core/src/guid.rs @@ -0,0 +1,199 @@ +use super::*; + +/// A globally unique identifier ([GUID](https://docs.microsoft.com/en-us/windows/win32/api/guiddef/ns-guiddef-guid)) +/// used to identify COM and WinRT interfaces. +#[repr(C)] +#[derive(Clone, Copy, Default, PartialEq, Eq, Hash)] +pub struct GUID { + /// Specifies the first 8 hexadecimal digits. + pub data1: u32, + + /// Specifies the first group of 4 hexadecimal digits. + pub data2: u16, + + /// Specifies the second group of 4 hexadecimal digits. + pub data3: u16, + + /// The first 2 bytes contain the third group of 4 hexadecimal digits. The remaining 6 bytes contain the final 12 hexadecimal digits. + pub data4: [u8; 8], +} + +impl GUID { + /// Creates a unique `GUID` value. + pub fn new() -> Result<Self> { + unsafe { imp::CoCreateGuid() } + } + + /// Creates a `GUID` represented by the all-zero byte-pattern. + pub const fn zeroed() -> Self { + Self { + data1: 0, + data2: 0, + data3: 0, + data4: [0, 0, 0, 0, 0, 0, 0, 0], + } + } + + /// Creates a `GUID` with the given constant values. + pub const fn from_values(data1: u32, data2: u16, data3: u16, data4: [u8; 8]) -> Self { + Self { + data1, + data2, + data3, + data4, + } + } + + /// Creates a `GUID` from a `u128` value. + pub const fn from_u128(uuid: u128) -> Self { + Self { + data1: (uuid >> 96) as u32, + data2: ((uuid >> 80) & 0xffff) as u16, + data3: ((uuid >> 64) & 0xffff) as u16, + data4: (uuid as u64).to_be_bytes(), + } + } + + /// Converts a `GUID` to a `u128` value. + pub const fn to_u128(&self) -> u128 { + ((self.data1 as u128) << 96) + + ((self.data2 as u128) << 80) + + ((self.data3 as u128) << 64) + + u64::from_be_bytes(self.data4) as u128 + } + + /// Creates a `GUID` for a "generic" WinRT type. + pub const fn from_signature(signature: imp::ConstBuffer) -> Self { + let data = imp::ConstBuffer::from_slice(&[ + 0x11, 0xf4, 0x7a, 0xd5, 0x7b, 0x73, 0x42, 0xc0, 0xab, 0xae, 0x87, 0x8b, 0x1e, 0x16, + 0xad, 0xee, + ]); + + let data = data.push_other(signature); + + let bytes = imp::sha1(&data).bytes(); + let first = u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]); + + let second = u16::from_be_bytes([bytes[4], bytes[5]]); + let mut third = u16::from_be_bytes([bytes[6], bytes[7]]); + third = (third & 0x0fff) | (5 << 12); + let fourth = (bytes[8] & 0x3f) | 0x80; + + Self::from_values( + first, + second, + third, + [ + fourth, bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15], + ], + ) + } +} + +impl RuntimeType for GUID { + const SIGNATURE: imp::ConstBuffer = imp::ConstBuffer::from_slice(b"g16"); +} + +impl TypeKind for GUID { + type TypeKind = CopyType; +} + +impl core::fmt::Debug for GUID { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!( + f, + "{:08X?}-{:04X?}-{:04X?}-{:02X?}{:02X?}-{:02X?}{:02X?}{:02X?}{:02X?}{:02X?}{:02X?}", + self.data1, + self.data2, + self.data3, + self.data4[0], + self.data4[1], + self.data4[2], + self.data4[3], + self.data4[4], + self.data4[5], + self.data4[6], + self.data4[7] + ) + } +} + +impl TryFrom<&str> for GUID { + type Error = Error; + + fn try_from(from: &str) -> Result<Self> { + if from.len() != 36 { + return Err(invalid_guid()); + } + + let bytes = &mut from.bytes(); + let mut guid = Self::zeroed(); + + guid.data1 = try_u32(bytes, true)?; + guid.data2 = try_u16(bytes, true)?; + guid.data3 = try_u16(bytes, true)?; + guid.data4[0] = try_u8(bytes, false)?; + guid.data4[1] = try_u8(bytes, true)?; + guid.data4[2] = try_u8(bytes, false)?; + guid.data4[3] = try_u8(bytes, false)?; + guid.data4[4] = try_u8(bytes, false)?; + guid.data4[5] = try_u8(bytes, false)?; + guid.data4[6] = try_u8(bytes, false)?; + guid.data4[7] = try_u8(bytes, false)?; + + Ok(guid) + } +} + +impl From<u128> for GUID { + fn from(value: u128) -> Self { + Self::from_u128(value) + } +} + +impl From<GUID> for u128 { + fn from(value: GUID) -> Self { + value.to_u128() + } +} + +fn invalid_guid() -> Error { + Error::from_hresult(imp::E_INVALIDARG) +} + +fn try_u32(bytes: &mut core::str::Bytes<'_>, delimiter: bool) -> Result<u32> { + next(bytes, 8, delimiter).ok_or_else(invalid_guid) +} + +fn try_u16(bytes: &mut core::str::Bytes<'_>, delimiter: bool) -> Result<u16> { + next(bytes, 4, delimiter) + .map(|value| value as u16) + .ok_or_else(invalid_guid) +} + +fn try_u8(bytes: &mut core::str::Bytes<'_>, delimiter: bool) -> Result<u8> { + next(bytes, 2, delimiter) + .map(|value| value as u8) + .ok_or_else(invalid_guid) +} + +fn next(bytes: &mut core::str::Bytes<'_>, len: usize, delimiter: bool) -> Option<u32> { + let mut value: u32 = 0; + + for _ in 0..len { + let digit = bytes.next()?; + + match digit { + b'0'..=b'9' => value = (value << 4) + (digit - b'0') as u32, + b'A'..=b'F' => value = (value << 4) + (digit - b'A' + 10) as u32, + b'a'..=b'f' => value = (value << 4) + (digit - b'a' + 10) as u32, + _ => return None, + } + } + + if delimiter && bytes.next() != Some(b'-') { + None + } else { + Some(value) + } +} diff --git a/vendor/windows-core/src/handles.rs b/vendor/windows-core/src/handles.rs new file mode 100644 index 00000000..de395e36 --- /dev/null +++ b/vendor/windows-core/src/handles.rs @@ -0,0 +1,46 @@ +/// Custom code to free a handle. +/// +/// This is similar to the [`Drop`] trait, and may be used to implement [`Drop`], but allows handles +/// to be dropped depending on context. +pub trait Free { + /// Calls the handle's free function. + /// + /// # Safety + /// The handle must be owned by the caller and safe to free. + unsafe fn free(&mut self); +} + +/// A wrapper to provide ownership for handles to automatically drop via the handle's [`Free`] trait. +#[repr(transparent)] +#[derive(PartialEq, Eq, Default, Debug)] +pub struct Owned<T: Free>(T); + +impl<T: Free> Owned<T> { + /// Takes ownership of the handle. + /// + /// # Safety + /// + /// The handle must be owned by the caller and safe to free. + pub unsafe fn new(x: T) -> Self { + Self(x) + } +} + +impl<T: Free> Drop for Owned<T> { + fn drop(&mut self) { + unsafe { self.0.free() }; + } +} + +impl<T: Free> core::ops::Deref for Owned<T> { + type Target = T; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl<T: Free> core::ops::DerefMut for Owned<T> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} diff --git a/vendor/windows-core/src/imp/bindings.rs b/vendor/windows-core/src/imp/bindings.rs new file mode 100644 index 00000000..caf8507e --- /dev/null +++ b/vendor/windows-core/src/imp/bindings.rs @@ -0,0 +1,45 @@ +#![allow( + non_snake_case, + non_upper_case_globals, + non_camel_case_types, + dead_code, + clippy::all +)] + +windows_link::link!("ole32.dll" "system" fn CoIncrementMTAUsage(pcookie : *mut CO_MTA_USAGE_COOKIE) -> HRESULT); +windows_link::link!("ole32.dll" "system" fn CoTaskMemAlloc(cb : usize) -> *mut core::ffi::c_void); +windows_link::link!("ole32.dll" "system" fn CoTaskMemFree(pv : *const core::ffi::c_void)); +windows_link::link!("kernel32.dll" "system" fn EncodePointer(ptr : *const core::ffi::c_void) -> *mut core::ffi::c_void); +windows_link::link!("kernel32.dll" "system" fn FreeLibrary(hlibmodule : HMODULE) -> BOOL); +windows_link::link!("kernel32.dll" "system" fn GetProcAddress(hmodule : HMODULE, lpprocname : PCSTR) -> FARPROC); +windows_link::link!("kernel32.dll" "system" fn LoadLibraryExA(lplibfilename : PCSTR, hfile : HANDLE, dwflags : LOAD_LIBRARY_FLAGS) -> HMODULE); +windows_link::link!("api-ms-win-core-winrt-l1-1-0.dll" "system" fn RoGetActivationFactory(activatableclassid : HSTRING, iid : *const GUID, factory : *mut *mut core::ffi::c_void) -> HRESULT); +pub type BOOL = i32; +pub type CO_MTA_USAGE_COOKIE = *mut core::ffi::c_void; +pub type FARPROC = Option<unsafe extern "system" fn() -> isize>; +#[repr(C)] +#[derive(Clone, Copy)] +pub struct GUID { + pub data1: u32, + pub data2: u16, + pub data3: u16, + pub data4: [u8; 8], +} +impl GUID { + pub const fn from_u128(uuid: u128) -> Self { + Self { + data1: (uuid >> 96) as u32, + data2: (uuid >> 80 & 0xffff) as u16, + data3: (uuid >> 64 & 0xffff) as u16, + data4: (uuid as u64).to_be_bytes(), + } + } +} +pub type HANDLE = *mut core::ffi::c_void; +pub type HINSTANCE = *mut core::ffi::c_void; +pub type HMODULE = *mut core::ffi::c_void; +pub type HRESULT = i32; +pub type LOAD_LIBRARY_FLAGS = u32; +pub const LOAD_LIBRARY_SEARCH_DEFAULT_DIRS: LOAD_LIBRARY_FLAGS = 4096u32; +pub type PCSTR = *const u8; +pub type HSTRING = *mut core::ffi::c_void; diff --git a/vendor/windows-core/src/imp/can_into.rs b/vendor/windows-core/src/imp/can_into.rs new file mode 100644 index 00000000..47ee7838 --- /dev/null +++ b/vendor/windows-core/src/imp/can_into.rs @@ -0,0 +1,5 @@ +pub trait CanInto<T>: Sized { + const QUERY: bool = false; +} + +impl<T> CanInto<T> for T where T: Clone {} diff --git a/vendor/windows-core/src/imp/com_bindings.rs b/vendor/windows-core/src/imp/com_bindings.rs new file mode 100644 index 00000000..2c16fbff --- /dev/null +++ b/vendor/windows-core/src/imp/com_bindings.rs @@ -0,0 +1,262 @@ +#![allow( + non_snake_case, + non_upper_case_globals, + non_camel_case_types, + dead_code, + clippy::all +)] + +#[inline] +pub unsafe fn CoCreateGuid() -> windows_core::Result<windows_core::GUID> { + windows_link::link!("ole32.dll" "system" fn CoCreateGuid(pguid : *mut windows_core::GUID) -> windows_core::HRESULT); + unsafe { + let mut result__ = core::mem::zeroed(); + CoCreateGuid(&mut result__).map(|| result__) + } +} +#[inline] +pub unsafe fn RoGetAgileReference<P2>( + options: AgileReferenceOptions, + riid: *const windows_core::GUID, + punk: P2, +) -> windows_core::Result<IAgileReference> +where + P2: windows_core::Param<windows_core::IUnknown>, +{ + windows_link::link!("ole32.dll" "system" fn RoGetAgileReference(options : AgileReferenceOptions, riid : *const windows_core::GUID, punk : * mut core::ffi::c_void, ppagilereference : *mut * mut core::ffi::c_void) -> windows_core::HRESULT); + unsafe { + let mut result__ = core::mem::zeroed(); + RoGetAgileReference(options, riid, punk.param().abi(), &mut result__) + .and_then(|| windows_core::Type::from_abi(result__)) + } +} +pub const AGILEREFERENCE_DEFAULT: AgileReferenceOptions = AgileReferenceOptions(0i32); +#[repr(transparent)] +#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] +pub struct AgileReferenceOptions(pub i32); +pub const CO_E_NOTINITIALIZED: windows_core::HRESULT = windows_core::HRESULT(0x800401F0_u32 as _); +pub const E_INVALIDARG: windows_core::HRESULT = windows_core::HRESULT(0x80070057_u32 as _); +pub const E_NOINTERFACE: windows_core::HRESULT = windows_core::HRESULT(0x80004002_u32 as _); +pub const E_POINTER: windows_core::HRESULT = windows_core::HRESULT(0x80004003_u32 as _); +windows_core::imp::define_interface!( + IAgileObject, + IAgileObject_Vtbl, + 0x94ea2b94_e9cc_49e0_c0ff_ee64ca8f5b90 +); +windows_core::imp::interface_hierarchy!(IAgileObject, windows_core::IUnknown); +#[repr(C)] +#[doc(hidden)] +pub struct IAgileObject_Vtbl { + pub base__: windows_core::IUnknown_Vtbl, +} +pub trait IAgileObject_Impl: windows_core::IUnknownImpl {} +impl IAgileObject_Vtbl { + pub const fn new<Identity: IAgileObject_Impl, const OFFSET: isize>() -> Self { + Self { + base__: windows_core::IUnknown_Vtbl::new::<Identity, OFFSET>(), + } + } + pub fn matches(iid: &windows_core::GUID) -> bool { + iid == &<IAgileObject as windows_core::Interface>::IID + } +} +impl windows_core::RuntimeName for IAgileObject {} +windows_core::imp::define_interface!( + IAgileReference, + IAgileReference_Vtbl, + 0xc03f6a43_65a4_9818_987e_e0b810d2a6f2 +); +windows_core::imp::interface_hierarchy!(IAgileReference, windows_core::IUnknown); +impl IAgileReference { + pub unsafe fn Resolve<T>(&self) -> windows_core::Result<T> + where + T: windows_core::Interface, + { + let mut result__ = core::ptr::null_mut(); + unsafe { + (windows_core::Interface::vtable(self).Resolve)( + windows_core::Interface::as_raw(self), + &T::IID, + &mut result__, + ) + .and_then(|| windows_core::Type::from_abi(result__)) + } + } +} +#[repr(C)] +#[doc(hidden)] +pub struct IAgileReference_Vtbl { + pub base__: windows_core::IUnknown_Vtbl, + pub Resolve: unsafe extern "system" fn( + *mut core::ffi::c_void, + *const windows_core::GUID, + *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT, +} +pub trait IAgileReference_Impl: windows_core::IUnknownImpl { + fn Resolve( + &self, + riid: *const windows_core::GUID, + ppvobjectreference: *mut *mut core::ffi::c_void, + ) -> windows_core::Result<()>; +} +impl IAgileReference_Vtbl { + pub const fn new<Identity: IAgileReference_Impl, const OFFSET: isize>() -> Self { + unsafe extern "system" fn Resolve<Identity: IAgileReference_Impl, const OFFSET: isize>( + this: *mut core::ffi::c_void, + riid: *const windows_core::GUID, + ppvobjectreference: *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + IAgileReference_Impl::Resolve( + this, + core::mem::transmute_copy(&riid), + core::mem::transmute_copy(&ppvobjectreference), + ) + .into() + } + } + Self { + base__: windows_core::IUnknown_Vtbl::new::<Identity, OFFSET>(), + Resolve: Resolve::<Identity, OFFSET>, + } + } + pub fn matches(iid: &windows_core::GUID) -> bool { + iid == &<IAgileReference as windows_core::Interface>::IID + } +} +impl windows_core::RuntimeName for IAgileReference {} +windows_core::imp::define_interface!( + IWeakReference, + IWeakReference_Vtbl, + 0x00000037_0000_0000_c000_000000000046 +); +windows_core::imp::interface_hierarchy!(IWeakReference, windows_core::IUnknown); +impl IWeakReference { + pub unsafe fn Resolve<T>(&self) -> windows_core::Result<T> + where + T: windows_core::Interface, + { + let mut result__ = core::ptr::null_mut(); + unsafe { + (windows_core::Interface::vtable(self).Resolve)( + windows_core::Interface::as_raw(self), + &T::IID, + &mut result__, + ) + .and_then(|| windows_core::Type::from_abi(result__)) + } + } +} +#[repr(C)] +#[doc(hidden)] +pub struct IWeakReference_Vtbl { + pub base__: windows_core::IUnknown_Vtbl, + pub Resolve: unsafe extern "system" fn( + *mut core::ffi::c_void, + *const windows_core::GUID, + *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT, +} +pub trait IWeakReference_Impl: windows_core::IUnknownImpl { + fn Resolve( + &self, + riid: *const windows_core::GUID, + objectreference: *mut *mut core::ffi::c_void, + ) -> windows_core::Result<()>; +} +impl IWeakReference_Vtbl { + pub const fn new<Identity: IWeakReference_Impl, const OFFSET: isize>() -> Self { + unsafe extern "system" fn Resolve<Identity: IWeakReference_Impl, const OFFSET: isize>( + this: *mut core::ffi::c_void, + riid: *const windows_core::GUID, + objectreference: *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + IWeakReference_Impl::Resolve( + this, + core::mem::transmute_copy(&riid), + core::mem::transmute_copy(&objectreference), + ) + .into() + } + } + Self { + base__: windows_core::IUnknown_Vtbl::new::<Identity, OFFSET>(), + Resolve: Resolve::<Identity, OFFSET>, + } + } + pub fn matches(iid: &windows_core::GUID) -> bool { + iid == &<IWeakReference as windows_core::Interface>::IID + } +} +impl windows_core::RuntimeName for IWeakReference {} +windows_core::imp::define_interface!( + IWeakReferenceSource, + IWeakReferenceSource_Vtbl, + 0x00000038_0000_0000_c000_000000000046 +); +windows_core::imp::interface_hierarchy!(IWeakReferenceSource, windows_core::IUnknown); +impl IWeakReferenceSource { + pub unsafe fn GetWeakReference(&self) -> windows_core::Result<IWeakReference> { + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(self).GetWeakReference)( + windows_core::Interface::as_raw(self), + &mut result__, + ) + .and_then(|| windows_core::Type::from_abi(result__)) + } + } +} +#[repr(C)] +#[doc(hidden)] +pub struct IWeakReferenceSource_Vtbl { + pub base__: windows_core::IUnknown_Vtbl, + pub GetWeakReference: unsafe extern "system" fn( + *mut core::ffi::c_void, + *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT, +} +pub trait IWeakReferenceSource_Impl: windows_core::IUnknownImpl { + fn GetWeakReference(&self) -> windows_core::Result<IWeakReference>; +} +impl IWeakReferenceSource_Vtbl { + pub const fn new<Identity: IWeakReferenceSource_Impl, const OFFSET: isize>() -> Self { + unsafe extern "system" fn GetWeakReference< + Identity: IWeakReferenceSource_Impl, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + weakreference: *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + match IWeakReferenceSource_Impl::GetWeakReference(this) { + Ok(ok__) => { + weakreference.write(core::mem::transmute(ok__)); + windows_core::HRESULT(0) + } + Err(err) => err.into(), + } + } + } + Self { + base__: windows_core::IUnknown_Vtbl::new::<Identity, OFFSET>(), + GetWeakReference: GetWeakReference::<Identity, OFFSET>, + } + } + pub fn matches(iid: &windows_core::GUID) -> bool { + iid == &<IWeakReferenceSource as windows_core::Interface>::IID + } +} +impl windows_core::RuntimeName for IWeakReferenceSource {} +pub const JSCRIPT_E_CANTEXECUTE: windows_core::HRESULT = windows_core::HRESULT(0x89020001_u32 as _); +pub const REGDB_E_CLASSNOTREG: windows_core::HRESULT = windows_core::HRESULT(0x80040154_u32 as _); +pub const RPC_E_DISCONNECTED: windows_core::HRESULT = windows_core::HRESULT(0x80010108_u32 as _); +pub const S_OK: windows_core::HRESULT = windows_core::HRESULT(0x0_u32 as _); diff --git a/vendor/windows-core/src/imp/factory_cache.rs b/vendor/windows-core/src/imp/factory_cache.rs new file mode 100644 index 00000000..e60abb3a --- /dev/null +++ b/vendor/windows-core/src/imp/factory_cache.rs @@ -0,0 +1,218 @@ +use super::*; +use crate::Interface; +use core::ffi::c_void; +use core::marker::PhantomData; +use core::mem::{forget, transmute, transmute_copy}; +use core::ptr::null_mut; +use core::sync::atomic::{AtomicPtr, Ordering}; + +pub struct FactoryCache<C, I> { + shared: AtomicPtr<c_void>, + _c: PhantomData<C>, + _i: PhantomData<I>, +} + +impl<C, I> FactoryCache<C, I> { + pub const fn new() -> Self { + Self { + shared: AtomicPtr::new(null_mut()), + _c: PhantomData, + _i: PhantomData, + } + } +} + +impl<C, I> Default for FactoryCache<C, I> { + fn default() -> Self { + Self::new() + } +} + +impl<C: crate::RuntimeName, I: Interface> FactoryCache<C, I> { + pub fn call<R, F: FnOnce(&I) -> crate::Result<R>>(&self, callback: F) -> crate::Result<R> { + loop { + // Attempt to load a previously cached factory pointer. + let ptr = self.shared.load(Ordering::Relaxed); + + // If a pointer is found, the cache is primed and we're good to go. + if !ptr.is_null() { + return callback(unsafe { transmute::<&*mut c_void, &I>(&ptr) }); + } + + // Otherwise, we load the factory the usual way. + let factory = load_factory::<C, I>()?; + + // If the factory is agile, we can safely cache it. + if factory.cast::<IAgileObject>().is_ok() { + if self + .shared + .compare_exchange_weak( + null_mut(), + factory.as_raw(), + Ordering::Relaxed, + Ordering::Relaxed, + ) + .is_ok() + { + forget(factory); + } + } else { + // Otherwise, for non-agile factories we simply use the factory + // and discard after use as it is not safe to cache. + return callback(&factory); + } + } + } +} + +// This is safe because `FactoryCache` only holds agile factory pointers, which are safe to cache and share between threads. +unsafe impl<C, I> Sync for FactoryCache<C, I> {} + +/// Attempts to load the factory object for the given WinRT class. +/// This can be used to access COM interfaces implemented on a Windows Runtime class factory. +pub fn load_factory<C: crate::RuntimeName, I: Interface>() -> crate::Result<I> { + let mut factory: Option<I> = None; + let name = crate::HSTRING::from(C::NAME); + + let code = unsafe { + let mut get_com_factory = || { + crate::HRESULT(RoGetActivationFactory( + transmute_copy(&name), + &I::IID as *const _ as _, + &mut factory as *mut _ as *mut _, + )) + }; + let mut code = get_com_factory(); + + // If RoGetActivationFactory fails because combase hasn't been loaded yet then load combase + // automatically so that it "just works" for apartment-agnostic code. + if code == CO_E_NOTINITIALIZED { + let mut cookie = core::ptr::null_mut(); + CoIncrementMTAUsage(&mut cookie); + + // Now try a second time to get the activation factory via the OS. + code = get_com_factory(); + } + + code + }; + + // If this succeeded then return the resulting factory interface. + if let Some(factory) = factory { + return Ok(factory); + } + + // If not, first capture the error information from the failure above so that we + // can ultimately return this error information if all else fails. + let original: crate::Error = code.into(); + + // Reg-free activation should only be attempted if the class is not registered. + // It should not be attempted if the class is registered but fails to activate. + if code == REGDB_E_CLASSNOTREG { + // Now attempt to find the factory's implementation heuristically. + if let Some(i) = search_path(C::NAME, |library| unsafe { + get_activation_factory(library, &name) + }) { + return i.cast(); + } + } + + Err(original) +} + +// Remove the suffix until a match is found appending `.dll\0` at the end +/// +/// For example, if the class name is +/// "A.B.TypeName" then the attempted load order will be: +/// 1. A.B.dll +/// 2. A.dll +fn search_path<F, R>(mut path: &str, mut callback: F) -> Option<R> +where + F: FnMut(crate::PCSTR) -> crate::Result<R>, +{ + let suffix = b".dll\0"; + let mut library = alloc::vec![0; path.len() + suffix.len()]; + while let Some(pos) = path.rfind('.') { + path = &path[..pos]; + library.truncate(path.len() + suffix.len()); + library[..path.len()].copy_from_slice(path.as_bytes()); + library[path.len()..].copy_from_slice(suffix); + + if let Ok(r) = callback(crate::PCSTR::from_raw(library.as_ptr())) { + return Some(r); + } + } + + None +} + +unsafe fn get_activation_factory( + library: crate::PCSTR, + name: &crate::HSTRING, +) -> crate::Result<IGenericFactory> { + unsafe { + let function = + delay_load::<DllGetActivationFactory>(library, crate::s!("DllGetActivationFactory")) + .ok_or_else(crate::Error::from_win32)?; + let mut abi = null_mut(); + function(transmute_copy(name), &mut abi).and_then(|| crate::Type::from_abi(abi)) + } +} + +unsafe fn delay_load<T>(library: crate::PCSTR, function: crate::PCSTR) -> Option<T> { + unsafe { + let library = LoadLibraryExA( + library.0, + core::ptr::null_mut(), + LOAD_LIBRARY_SEARCH_DEFAULT_DIRS, + ); + + if library.is_null() { + return None; + } + + let address = GetProcAddress(library, function.0); + + if address.is_some() { + return Some(core::mem::transmute_copy(&address)); + } + + FreeLibrary(library); + None + } +} + +type DllGetActivationFactory = + extern "system" fn(name: *mut c_void, factory: *mut *mut c_void) -> crate::HRESULT; + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn dll_search() { + let path = "A.B.TypeName"; + + // Test library successfully found + let mut results = Vec::new(); + let end_result = search_path(path, |library| { + results.push(unsafe { library.to_string().unwrap() }); + if unsafe { library.as_bytes() } == &b"A.dll"[..] { + Ok(42) + } else { + Err(crate::Error::empty()) + } + }); + assert!(matches!(end_result, Some(42))); + assert_eq!(results, vec!["A.B.dll", "A.dll"]); + + // Test library never successfully found + let mut results = Vec::new(); + let end_result = search_path(path, |library| { + results.push(unsafe { library.to_string().unwrap() }); + crate::Result::<()>::Err(crate::Error::empty()) + }); + assert!(end_result.is_none()); + assert_eq!(results, vec!["A.B.dll", "A.dll"]); + } +} diff --git a/vendor/windows-core/src/imp/generic_factory.rs b/vendor/windows-core/src/imp/generic_factory.rs new file mode 100644 index 00000000..1f9ddcee --- /dev/null +++ b/vendor/windows-core/src/imp/generic_factory.rs @@ -0,0 +1,33 @@ +use crate::Interface; +use core::ffi::c_void; +use core::mem::{transmute_copy, zeroed}; + +// A streamlined version of the IActivationFactory interface used by WinRT class factories used internally by the windows crate +// to simplify code generation. Components should implement the `IActivationFactory` interface published by the windows crate. +super::define_interface!( + IGenericFactory, + IGenericFactory_Vtbl, + 0x00000035_0000_0000_c000_000000000046 +); +super::interface_hierarchy!(IGenericFactory, crate::IUnknown, crate::IInspectable); + +impl IGenericFactory { + pub fn ActivateInstance<I: Interface>(&self) -> crate::Result<I> { + unsafe { + let mut result__ = zeroed(); + (Interface::vtable(self).ActivateInstance)( + transmute_copy(self), + &mut result__ as *mut _ as *mut _, + ) + .and_then(|| crate::Type::from_abi(result__)) + .and_then(|interface: crate::IInspectable| interface.cast()) + } + } +} + +#[repr(C)] +pub struct IGenericFactory_Vtbl { + pub base__: crate::IInspectable_Vtbl, + pub ActivateInstance: + unsafe extern "system" fn(this: *mut c_void, instance: *mut *mut c_void) -> crate::HRESULT, +} diff --git a/vendor/windows-core/src/imp/marshaler.rs b/vendor/windows-core/src/imp/marshaler.rs new file mode 100644 index 00000000..2ef9d847 --- /dev/null +++ b/vendor/windows-core/src/imp/marshaler.rs @@ -0,0 +1,268 @@ +use super::*; +use crate::{IUnknown, IUnknown_Vtbl, Interface, GUID, HRESULT}; +use core::ffi::c_void; +use core::mem::{transmute, transmute_copy}; +use core::ptr::null_mut; + +windows_link::link!("ole32.dll" "system" fn CoCreateFreeThreadedMarshaler(punkouter: *mut c_void, ppunkmarshal: *mut *mut c_void) -> HRESULT); + +pub unsafe fn marshaler(outer: IUnknown, result: *mut *mut c_void) -> HRESULT { + unsafe { + let mut marshaler_raw = null_mut(); + _ = CoCreateFreeThreadedMarshaler(null_mut(), &mut marshaler_raw); + assert!(!marshaler_raw.is_null(), "allocation failed"); + let marshaler: IUnknown = transmute(marshaler_raw); + + _ = (marshaler.vtable().QueryInterface)( + transmute_copy(&marshaler), + &IMarshal::IID, + &mut marshaler_raw, + ); + + debug_assert!(!marshaler_raw.is_null()); + let marshaler: IMarshal = transmute(marshaler_raw); + + let marshaler = Marshaler { + vtable: &Marshaler::VTABLE, + outer, + marshaler, + count: RefCount::new(1), + }; + + debug_assert!(!result.is_null()); + *result = transmute::<Box<_>, *mut c_void>(Box::new(marshaler)); + S_OK + } +} + +#[repr(C)] +struct Marshaler { + vtable: *const IMarshal_Vtbl, + outer: IUnknown, + marshaler: IMarshal, + count: RefCount, +} + +impl Marshaler { + const VTABLE: IMarshal_Vtbl = IMarshal_Vtbl { + base__: IUnknown_Vtbl { + QueryInterface: Self::QueryInterface, + AddRef: Self::AddRef, + Release: Self::Release, + }, + GetUnmarshalClass: Self::GetUnmarshalClass, + GetMarshalSizeMax: Self::GetMarshalSizeMax, + MarshalInterface: Self::MarshalInterface, + UnmarshalInterface: Self::UnmarshalInterface, + ReleaseMarshalData: Self::ReleaseMarshalData, + DisconnectObject: Self::DisconnectObject, + }; + + unsafe extern "system" fn QueryInterface( + this: *mut c_void, + iid: *const GUID, + interface: *mut *mut c_void, + ) -> HRESULT { + unsafe { + let this = this as *mut *mut c_void as *mut Self; + + if iid.is_null() || interface.is_null() { + return E_POINTER; + } + + if *iid == IMarshal::IID { + *interface = &mut (*this).vtable as *mut _ as _; + (*this).count.add_ref(); + return S_OK; + } + + ((*this).outer.vtable().QueryInterface)(transmute_copy(&(*this).outer), iid, interface) + } + } + + unsafe extern "system" fn AddRef(this: *mut c_void) -> u32 { + unsafe { + let this = this as *mut *mut c_void as *mut Self; + (*this).count.add_ref() + } + } + + unsafe extern "system" fn Release(this: *mut c_void) -> u32 { + unsafe { + let this = this as *mut *mut c_void as *mut Self; + let remaining = (*this).count.release(); + + if remaining == 0 { + let _ = Box::from_raw(this); + } + + remaining + } + } + + unsafe extern "system" fn GetUnmarshalClass( + this: *mut c_void, + riid: *const GUID, + pv: *const c_void, + dwdestcontext: u32, + pvdestcontext: *const c_void, + mshlflags: u32, + pcid: *mut GUID, + ) -> HRESULT { + unsafe { + let this = this as *mut *mut c_void as *mut Self; + + ((*this).marshaler.vtable().GetUnmarshalClass)( + transmute_copy(&(*this).marshaler), + riid, + pv, + dwdestcontext, + pvdestcontext, + mshlflags, + pcid, + ) + } + } + + unsafe extern "system" fn GetMarshalSizeMax( + this: *mut c_void, + riid: *const GUID, + pv: *const c_void, + dwdestcontext: u32, + pvdestcontext: *const c_void, + mshlflags: u32, + psize: *mut u32, + ) -> HRESULT { + unsafe { + let this = this as *mut *mut c_void as *mut Self; + + ((*this).marshaler.vtable().GetMarshalSizeMax)( + transmute_copy(&(*this).marshaler), + riid, + pv, + dwdestcontext, + pvdestcontext, + mshlflags, + psize, + ) + } + } + + unsafe extern "system" fn MarshalInterface( + this: *mut c_void, + pstm: *mut c_void, + riid: *const GUID, + pv: *const c_void, + dwdestcontext: u32, + pvdestcontext: *const c_void, + mshlflags: u32, + ) -> HRESULT { + unsafe { + let this = this as *mut *mut c_void as *mut Self; + + ((*this).marshaler.vtable().MarshalInterface)( + transmute_copy(&(*this).marshaler), + pstm, + riid, + pv, + dwdestcontext, + pvdestcontext, + mshlflags, + ) + } + } + + unsafe extern "system" fn UnmarshalInterface( + this: *mut c_void, + pstm: *mut c_void, + riid: *const GUID, + ppv: *mut *mut c_void, + ) -> HRESULT { + unsafe { + let this = this as *mut *mut c_void as *mut Self; + + ((*this).marshaler.vtable().UnmarshalInterface)( + transmute_copy(&(*this).marshaler), + pstm, + riid, + ppv, + ) + } + } + + unsafe extern "system" fn ReleaseMarshalData(this: *mut c_void, pstm: *mut c_void) -> HRESULT { + unsafe { + let this = this as *mut *mut c_void as *mut Self; + + ((*this).marshaler.vtable().ReleaseMarshalData)( + transmute_copy(&(*this).marshaler), + pstm, + ) + } + } + + unsafe extern "system" fn DisconnectObject(this: *mut c_void, dwreserved: u32) -> HRESULT { + unsafe { + let this = this as *mut *mut c_void as *mut Self; + + ((*this).marshaler.vtable().DisconnectObject)( + transmute_copy(&(*this).marshaler), + dwreserved, + ) + } + } +} + +#[repr(transparent)] +#[derive(Clone)] +pub struct IMarshal(IUnknown); + +unsafe impl Interface for IMarshal { + type Vtable = IMarshal_Vtbl; + const IID: GUID = GUID::from_u128(0x00000003_0000_0000_c000_000000000046); +} + +#[repr(C)] +pub struct IMarshal_Vtbl { + base__: IUnknown_Vtbl, + + GetUnmarshalClass: unsafe extern "system" fn( + *mut c_void, + *const GUID, + *const c_void, + u32, + *const c_void, + u32, + *mut GUID, + ) -> HRESULT, + + GetMarshalSizeMax: unsafe extern "system" fn( + *mut c_void, + *const GUID, + *const c_void, + u32, + *const c_void, + u32, + *mut u32, + ) -> HRESULT, + + MarshalInterface: unsafe extern "system" fn( + *mut c_void, + *mut c_void, + *const GUID, + *const c_void, + u32, + *const c_void, + u32, + ) -> HRESULT, + + UnmarshalInterface: unsafe extern "system" fn( + *mut c_void, + *mut c_void, + *const GUID, + *mut *mut c_void, + ) -> HRESULT, + + ReleaseMarshalData: unsafe extern "system" fn(*mut c_void, *mut c_void) -> HRESULT, + DisconnectObject: unsafe extern "system" fn(*mut c_void, u32) -> HRESULT, +} diff --git a/vendor/windows-core/src/imp/mod.rs b/vendor/windows-core/src/imp/mod.rs new file mode 100644 index 00000000..036b540b --- /dev/null +++ b/vendor/windows-core/src/imp/mod.rs @@ -0,0 +1,96 @@ +#[cfg(windows)] +include!("windows.rs"); + +mod can_into; +mod com_bindings; +mod ref_count; +mod sha1; +mod weak_ref_count; + +pub use can_into::*; +pub use com_bindings::*; +pub use ref_count::*; +pub use sha1::*; +pub use weak_ref_count::*; + +#[doc(hidden)] +#[macro_export] +macro_rules! interface_hierarchy { + ($child:ident, $parent:ty) => { + impl ::windows_core::imp::CanInto<$parent> for $child {} + impl ::core::convert::From<&$child> for &$parent { + fn from(value: &$child) -> Self { + unsafe { ::core::mem::transmute(value) } + } + } + impl ::core::convert::From<$child> for $parent { + fn from(value: $child) -> Self { + unsafe { ::core::mem::transmute(value) } + } + } + }; + ($child:ident, $first:ty, $($rest:ty),+) => { + $crate::imp::interface_hierarchy!($child, $first); + $crate::imp::interface_hierarchy!($child, $($rest),+); + }; +} + +#[doc(hidden)] +pub use interface_hierarchy; + +#[doc(hidden)] +#[macro_export] +macro_rules! required_hierarchy { + ($child:ident, $parent:ty) => { + impl ::windows_core::imp::CanInto<$parent> for $child { const QUERY: bool = true; } + }; + ($child:ident, $first:ty, $($rest:ty),+) => { + $crate::imp::required_hierarchy!($child, $first); + $crate::imp::required_hierarchy!($child, $($rest),+); + }; +} + +#[doc(hidden)] +pub use required_hierarchy; + +#[doc(hidden)] +#[macro_export] +macro_rules! define_interface { + ($name:ident, $vtbl:ident, $iid:literal) => { + #[repr(transparent)] + #[derive(::core::cmp::PartialEq, ::core::cmp::Eq, ::core::clone::Clone)] + pub struct $name(::windows_core::IUnknown); + unsafe impl ::windows_core::Interface for $name { + type Vtable = $vtbl; + const IID: ::windows_core::GUID = ::windows_core::GUID::from_u128($iid); + } + impl ::core::fmt::Debug for $name { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_tuple(stringify!($name)) + .field(&::windows_core::Interface::as_raw(self)) + .finish() + } + } + }; + ($name:ident, $vtbl:ident) => { + #[repr(transparent)] + #[derive(::core::cmp::PartialEq, ::core::cmp::Eq, ::core::clone::Clone)] + pub struct $name(::core::ptr::NonNull<::core::ffi::c_void>); + unsafe impl ::windows_core::Interface for $name { + type Vtable = $vtbl; + const IID: ::windows_core::GUID = ::windows_core::GUID::zeroed(); + const UNKNOWN: bool = false; + } + impl ::core::fmt::Debug for $name { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_tuple(stringify!($name)).field(&self.0).finish() + } + } + }; +} + +#[doc(hidden)] +pub use define_interface; + +#[doc(hidden)] +pub use alloc::boxed::Box; diff --git a/vendor/windows-core/src/imp/ref_count.rs b/vendor/windows-core/src/imp/ref_count.rs new file mode 100644 index 00000000..97e1f2a6 --- /dev/null +++ b/vendor/windows-core/src/imp/ref_count.rs @@ -0,0 +1,33 @@ +use core::sync::atomic::{fence, AtomicI32, Ordering}; + +#[repr(transparent)] +#[derive(Default)] +pub struct RefCount(pub(crate) AtomicI32); + +impl RefCount { + /// Creates a new `RefCount` with an initial value of `1`. + pub const fn new(count: u32) -> Self { + Self(AtomicI32::new(count as i32)) + } + + /// Increments the reference count, returning the new value. + pub fn add_ref(&self) -> u32 { + (self.0.fetch_add(1, Ordering::Relaxed) + 1) as u32 + } + + /// Decrements the reference count, returning the new value. + /// + /// This operation inserts an `Acquire` fence when the reference count reaches zero. + /// This prevents reordering before the object is destroyed. + pub fn release(&self) -> u32 { + let remaining = self.0.fetch_sub(1, Ordering::Release) - 1; + + match remaining.cmp(&0) { + core::cmp::Ordering::Equal => fence(Ordering::Acquire), + core::cmp::Ordering::Less => panic!("Object has been over-released."), + core::cmp::Ordering::Greater => {} + } + + remaining as u32 + } +} diff --git a/vendor/windows-core/src/imp/sha1.rs b/vendor/windows-core/src/imp/sha1.rs new file mode 100644 index 00000000..deab3ae5 --- /dev/null +++ b/vendor/windows-core/src/imp/sha1.rs @@ -0,0 +1,481 @@ +pub const fn sha1(data: &ConstBuffer) -> Digest { + let state: [u32; 5] = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0]; + let len: u64 = 0; + let blocks = Blocks { + len: 0, + data: [0; 64], + }; + let (blocks, len, state) = process_blocks(blocks, data, len, state); + digest(state, len, blocks) +} + +const BUFFER_SIZE: usize = 1024; + +pub struct ConstBuffer { + data: [u8; BUFFER_SIZE], + head: usize, +} + +impl ConstBuffer { + pub const fn for_class<C: crate::RuntimeName, I: crate::RuntimeType>() -> Self { + Self::new() + .push_slice(b"rc(") + .push_slice(C::NAME.as_bytes()) + .push(b';') + .push_other(I::SIGNATURE) + .push(b')') + } + + pub const fn for_interface<T: crate::Interface>() -> Self { + Self::new().push_guid(&T::IID) + } + + pub const fn from_slice(slice: &[u8]) -> Self { + let s = Self::new(); + s.push_slice(slice) + } + + pub const fn new() -> Self { + Self { + data: [0; BUFFER_SIZE], + head: 0, + } + } + + pub const fn push_slice(self, slice: &[u8]) -> Self { + self.push_amount(slice, slice.len()) + } + + const fn get(&self, index: usize) -> u8 { + self.data[index] + } + + const fn len(&self) -> usize { + self.head + } + + pub fn as_slice(&self) -> &[u8] { + &self.data[..self.head] + } + + pub const fn push_other(self, other: Self) -> Self { + self.push_amount(&other.data, other.len()) + } + + const fn push(mut self, value: u8) -> Self { + self.data[self.head] = value; + self.head += 1; + self + } + + const fn push_hex_u8(self, value: u8) -> Self { + const fn digit(mut value: u8) -> u8 { + value &= 0xF; + + if value < 10 { + b'0' + value + } else { + b'a' + (value - 10) + } + } + + self.push(digit(value >> 4)).push(digit(value)) + } + + const fn push_hex_u16(self, value: u16) -> Self { + self.push_hex_u8((value >> 8) as u8) + .push_hex_u8((value & 0xFF) as u8) + } + + const fn push_hex_u32(self, value: u32) -> Self { + self.push_hex_u16((value >> 16) as u16) + .push_hex_u16((value & 0xFFFF) as u16) + } + + const fn push_amount(mut self, slice: &[u8], amount: usize) -> Self { + let mut i = 0; + while i < amount { + self.data[self.head + i] = slice[i]; + i += 1; + } + self.head += i; + self + } + + const fn push_guid(self, guid: &crate::GUID) -> Self { + self.push(b'{') + .push_hex_u32(guid.data1) + .push(b'-') + .push_hex_u16(guid.data2) + .push(b'-') + .push_hex_u16(guid.data3) + .push(b'-') + .push_hex_u16(((guid.data4[0] as u16) << 8) | guid.data4[1] as u16) + .push(b'-') + .push_hex_u16(((guid.data4[2] as u16) << 8) | guid.data4[3] as u16) + .push_hex_u16(((guid.data4[4] as u16) << 8) | guid.data4[5] as u16) + .push_hex_u16(((guid.data4[6] as u16) << 8) | guid.data4[7] as u16) + .push(b'}') + } +} + +struct Blocks { + len: u32, + data: [u8; 64], +} + +const fn process_blocks( + mut blocks: Blocks, + data: &ConstBuffer, + mut len: u64, + mut state: [u32; 5], +) -> (Blocks, u64, [u32; 5]) { + const fn as_block(input: &ConstBuffer, offset: usize) -> [u32; 16] { + let mut result = [0u32; 16]; + + let mut i = 0; + while i != 16 { + let off = offset + (i * 4); + result[i] = (input.get(off + 3) as u32) + | ((input.get(off + 2) as u32) << 8) + | ((input.get(off + 1) as u32) << 16) + | ((input.get(off) as u32) << 24); + i += 1; + } + result + } + + const fn clone_from_slice_64( + mut data: [u8; 64], + slice: &[u8], + offset: usize, + num_elems: usize, + ) -> [u8; 64] { + let mut i = 0; + while i < num_elems { + data[i] = slice[offset + i]; + i += 1; + } + data + } + + let mut i = 0; + while i < data.len() { + if data.len() - i >= 64 { + let chunk_block = as_block(data, i); + len += 64; + state = process_state(state, chunk_block); + i += 64; + } else { + let num_elems = data.len() - i; + blocks.data = clone_from_slice_64(blocks.data, &data.data, i, num_elems); + blocks.len = num_elems as u32; + break; + } + } + (blocks, len, state) +} + +const fn process_state(mut state: [u32; 5], block: [u32; 16]) -> [u32; 5] { + let a = state[0]; + let b = state[1]; + let c = state[2]; + let d = state[3]; + let e = state[4]; + let (block, b, e) = r0(block, a, b, c, d, e, 0); + let (block, a, d) = r0(block, e, a, b, c, d, 1); + let (block, e, c) = r0(block, d, e, a, b, c, 2); + let (block, d, b) = r0(block, c, d, e, a, b, 3); + let (block, c, a) = r0(block, b, c, d, e, a, 4); + let (block, b, e) = r0(block, a, b, c, d, e, 5); + let (block, a, d) = r0(block, e, a, b, c, d, 6); + let (block, e, c) = r0(block, d, e, a, b, c, 7); + let (block, d, b) = r0(block, c, d, e, a, b, 8); + let (block, c, a) = r0(block, b, c, d, e, a, 9); + let (block, b, e) = r0(block, a, b, c, d, e, 10); + let (block, a, d) = r0(block, e, a, b, c, d, 11); + let (block, e, c) = r0(block, d, e, a, b, c, 12); + let (block, d, b) = r0(block, c, d, e, a, b, 13); + let (block, c, a) = r0(block, b, c, d, e, a, 14); + let (block, b, e) = r0(block, a, b, c, d, e, 15); + let (block, a, d) = r1(block, e, a, b, c, d, 0); + let (block, e, c) = r1(block, d, e, a, b, c, 1); + let (block, d, b) = r1(block, c, d, e, a, b, 2); + let (block, c, a) = r1(block, b, c, d, e, a, 3); + let (block, b, e) = r2(block, a, b, c, d, e, 4); + let (block, a, d) = r2(block, e, a, b, c, d, 5); + let (block, e, c) = r2(block, d, e, a, b, c, 6); + let (block, d, b) = r2(block, c, d, e, a, b, 7); + let (block, c, a) = r2(block, b, c, d, e, a, 8); + let (block, b, e) = r2(block, a, b, c, d, e, 9); + let (block, a, d) = r2(block, e, a, b, c, d, 10); + let (block, e, c) = r2(block, d, e, a, b, c, 11); + let (block, d, b) = r2(block, c, d, e, a, b, 12); + let (block, c, a) = r2(block, b, c, d, e, a, 13); + let (block, b, e) = r2(block, a, b, c, d, e, 14); + let (block, a, d) = r2(block, e, a, b, c, d, 15); + let (block, e, c) = r2(block, d, e, a, b, c, 0); + let (block, d, b) = r2(block, c, d, e, a, b, 1); + let (block, c, a) = r2(block, b, c, d, e, a, 2); + let (block, b, e) = r2(block, a, b, c, d, e, 3); + let (block, a, d) = r2(block, e, a, b, c, d, 4); + let (block, e, c) = r2(block, d, e, a, b, c, 5); + let (block, d, b) = r2(block, c, d, e, a, b, 6); + let (block, c, a) = r2(block, b, c, d, e, a, 7); + let (block, b, e) = r3(block, a, b, c, d, e, 8); + let (block, a, d) = r3(block, e, a, b, c, d, 9); + let (block, e, c) = r3(block, d, e, a, b, c, 10); + let (block, d, b) = r3(block, c, d, e, a, b, 11); + let (block, c, a) = r3(block, b, c, d, e, a, 12); + let (block, b, e) = r3(block, a, b, c, d, e, 13); + let (block, a, d) = r3(block, e, a, b, c, d, 14); + let (block, e, c) = r3(block, d, e, a, b, c, 15); + let (block, d, b) = r3(block, c, d, e, a, b, 0); + let (block, c, a) = r3(block, b, c, d, e, a, 1); + let (block, b, e) = r3(block, a, b, c, d, e, 2); + let (block, a, d) = r3(block, e, a, b, c, d, 3); + let (block, e, c) = r3(block, d, e, a, b, c, 4); + let (block, d, b) = r3(block, c, d, e, a, b, 5); + let (block, c, a) = r3(block, b, c, d, e, a, 6); + let (block, b, e) = r3(block, a, b, c, d, e, 7); + let (block, a, d) = r3(block, e, a, b, c, d, 8); + let (block, e, c) = r3(block, d, e, a, b, c, 9); + let (block, d, b) = r3(block, c, d, e, a, b, 10); + let (block, c, a) = r3(block, b, c, d, e, a, 11); + let (block, b, e) = r4(block, a, b, c, d, e, 12); + let (block, a, d) = r4(block, e, a, b, c, d, 13); + let (block, e, c) = r4(block, d, e, a, b, c, 14); + let (block, d, b) = r4(block, c, d, e, a, b, 15); + let (block, c, a) = r4(block, b, c, d, e, a, 0); + let (block, b, e) = r4(block, a, b, c, d, e, 1); + let (block, a, d) = r4(block, e, a, b, c, d, 2); + let (block, e, c) = r4(block, d, e, a, b, c, 3); + let (block, d, b) = r4(block, c, d, e, a, b, 4); + let (block, c, a) = r4(block, b, c, d, e, a, 5); + let (block, b, e) = r4(block, a, b, c, d, e, 6); + let (block, a, d) = r4(block, e, a, b, c, d, 7); + let (block, e, c) = r4(block, d, e, a, b, c, 8); + let (block, d, b) = r4(block, c, d, e, a, b, 9); + let (block, c, a) = r4(block, b, c, d, e, a, 10); + let (block, b, e) = r4(block, a, b, c, d, e, 11); + let (block, a, d) = r4(block, e, a, b, c, d, 12); + let (block, e, c) = r4(block, d, e, a, b, c, 13); + let (block, d, b) = r4(block, c, d, e, a, b, 14); + let (_, c, a) = r4(block, b, c, d, e, a, 15); + + state[0] = state[0].wrapping_add(a); + state[1] = state[1].wrapping_add(b); + state[2] = state[2].wrapping_add(c); + state[3] = state[3].wrapping_add(d); + state[4] = state[4].wrapping_add(e); + state +} + +const fn digest(mut state: [u32; 5], len: u64, blocks: Blocks) -> Digest { + const fn clone_from_slice_128( + mut data: [u8; 128], + slice: &[u8], + offset: usize, + num_elems: usize, + ) -> [u8; 128] { + let mut i = 0; + while i < num_elems { + data[i] = slice[offset + i]; + i += 1; + } + data + } + + const fn clone_slice_128(mut data: [u8; 128], slice: &[u8], _offset: usize) -> [u8; 128] { + let mut i = 0; + while i < slice.len() { + data[_offset + i] = slice[i]; + i += 1; + } + data + } + + const fn as_block(input: &[u8], offset: usize) -> [u32; 16] { + let mut result = [0u32; 16]; + + let mut i = 0; + while i != 16 { + let off = offset + (i * 4); + result[i] = (input[off + 3] as u32) + | ((input[off + 2] as u32) << 8) + | ((input[off + 1] as u32) << 16) + | ((input[off] as u32) << 24); + i += 1; + } + result + } + + let bits = (len + (blocks.len as u64)) * 8; + let extra = [ + (bits >> 56) as u8, + (bits >> 48) as u8, + (bits >> 40) as u8, + (bits >> 32) as u8, + (bits >> 24) as u8, + (bits >> 16) as u8, + (bits >> 8) as u8, + bits as u8, + ]; + let mut last = [0; 128]; + let blocklen = blocks.len as usize; + last = clone_from_slice_128(last, &blocks.data, 0, blocklen); + last[blocklen] = 0x80; + + if blocklen < 56 { + last = clone_slice_128(last, &extra, 56); + state = process_state(state, as_block(&last, 0)); + } else { + last = clone_slice_128(last, &extra, 120); + state = process_state(state, as_block(&last, 0)); + state = process_state(state, as_block(&last, 64)); + } + Digest { data: state } +} + +const fn rol(value: u32, bits: usize) -> u32 { + (value << bits) | (value >> (32 - bits)) +} + +const fn blk(block: &[u32], i: usize) -> u32 { + let value = block[(i + 13) & 15] ^ block[(i + 8) & 15] ^ block[(i + 2) & 15] ^ block[i]; + rol(value, 1) +} + +const fn r0( + block: [u32; 16], + v: u32, + mut w: u32, + x: u32, + y: u32, + mut z: u32, + i: usize, +) -> ([u32; 16], u32, u32) { + let n = ((w & (x ^ y)) ^ y) + .wrapping_add(block[i]) + .wrapping_add(0x5a82_7999) + .wrapping_add(rol(v, 5)); + z = z.wrapping_add(n); + w = rol(w, 30); + (block, w, z) +} + +const fn r1( + mut block: [u32; 16], + v: u32, + mut w: u32, + x: u32, + y: u32, + mut z: u32, + i: usize, +) -> ([u32; 16], u32, u32) { + block[i] = blk(&block, i); + let n = ((w & (x ^ y)) ^ y) + .wrapping_add(block[i]) + .wrapping_add(0x5a82_7999) + .wrapping_add(rol(v, 5)); + z = z.wrapping_add(n); + w = rol(w, 30); + (block, w, z) +} + +const fn r2( + mut block: [u32; 16], + v: u32, + mut w: u32, + x: u32, + y: u32, + mut z: u32, + i: usize, +) -> ([u32; 16], u32, u32) { + block[i] = blk(&block, i); + let n = (w ^ x ^ y) + .wrapping_add(block[i]) + .wrapping_add(0x6ed9_eba1) + .wrapping_add(rol(v, 5)); + z = z.wrapping_add(n); + w = rol(w, 30); + (block, w, z) +} + +const fn r3( + mut block: [u32; 16], + v: u32, + mut w: u32, + x: u32, + y: u32, + mut z: u32, + i: usize, +) -> ([u32; 16], u32, u32) { + block[i] = blk(&block, i); + let n = (((w | x) & y) | (w & x)) + .wrapping_add(block[i]) + .wrapping_add(0x8f1b_bcdc) + .wrapping_add(rol(v, 5)); + z = z.wrapping_add(n); + w = rol(w, 30); + (block, w, z) +} + +const fn r4( + mut block: [u32; 16], + v: u32, + mut w: u32, + x: u32, + y: u32, + mut z: u32, + i: usize, +) -> ([u32; 16], u32, u32) { + block[i] = blk(&block, i); + let n = (w ^ x ^ y) + .wrapping_add(block[i]) + .wrapping_add(0xca62_c1d6) + .wrapping_add(rol(v, 5)); + z = z.wrapping_add(n); + w = rol(w, 30); + (block, w, z) +} + +pub struct Digest { + data: [u32; 5], +} + +impl Digest { + pub const fn bytes(&self) -> [u8; 20] { + [ + (self.data[0] >> 24) as u8, + (self.data[0] >> 16) as u8, + (self.data[0] >> 8) as u8, + self.data[0] as u8, + (self.data[1] >> 24) as u8, + (self.data[1] >> 16) as u8, + (self.data[1] >> 8) as u8, + self.data[1] as u8, + (self.data[2] >> 24) as u8, + (self.data[2] >> 16) as u8, + (self.data[2] >> 8) as u8, + self.data[2] as u8, + (self.data[3] >> 24) as u8, + (self.data[3] >> 16) as u8, + (self.data[3] >> 8) as u8, + self.data[3] as u8, + (self.data[4] >> 24) as u8, + (self.data[4] >> 16) as u8, + (self.data[4] >> 8) as u8, + self.data[4] as u8, + ] + } +} + +impl core::fmt::Display for Digest { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + for i in self.data.iter() { + write!(f, "{i:08x}")?; + } + Ok(()) + } +} diff --git a/vendor/windows-core/src/imp/weak_ref_count.rs b/vendor/windows-core/src/imp/weak_ref_count.rs new file mode 100644 index 00000000..6ea23635 --- /dev/null +++ b/vendor/windows-core/src/imp/weak_ref_count.rs @@ -0,0 +1,327 @@ +use super::*; +use crate::{IUnknown, IUnknown_Vtbl, Interface, GUID, HRESULT}; +use core::ffi::c_void; +use core::mem::{transmute, transmute_copy}; +use core::ptr::null_mut; +use core::sync::atomic::{AtomicIsize, Ordering}; + +#[repr(transparent)] +#[derive(Default)] +pub struct WeakRefCount(AtomicIsize); + +impl WeakRefCount { + pub const fn new() -> Self { + Self(AtomicIsize::new(1)) + } + + pub fn add_ref(&self) -> u32 { + self.0 + .fetch_update(Ordering::Relaxed, Ordering::Relaxed, |count_or_pointer| { + bool::then_some(!is_weak_ref(count_or_pointer), count_or_pointer + 1) + }) + .map(|u| u as u32 + 1) + .unwrap_or_else(|pointer| unsafe { TearOff::decode(pointer).strong_count.add_ref() }) + } + + #[inline(always)] + pub fn is_one(&self) -> bool { + self.0.load(Ordering::Acquire) == 1 + } + + pub fn release(&self) -> u32 { + self.0 + .fetch_update(Ordering::Release, Ordering::Relaxed, |count_or_pointer| { + bool::then_some(!is_weak_ref(count_or_pointer), count_or_pointer - 1) + }) + .map(|u| u as u32 - 1) + .unwrap_or_else(|pointer| unsafe { + let tear_off = TearOff::decode(pointer); + let remaining = tear_off.strong_count.release(); + + // If this is the last strong reference, we can release the weak reference implied by the strong reference. + // There may still be weak references, so the WeakRelease is called to handle such possibilities. + if remaining == 0 { + TearOff::WeakRelease(&mut tear_off.weak_vtable as *mut _ as _); + } + + remaining + }) + } + + /// # Safety + pub unsafe fn query(&self, iid: &GUID, object: *mut c_void) -> *mut c_void { + unsafe { + if iid != &IWeakReferenceSource::IID { + return null_mut(); + } + + let mut count_or_pointer = self.0.load(Ordering::Relaxed); + + if is_weak_ref(count_or_pointer) { + return TearOff::from_encoding(count_or_pointer); + } + + let tear_off = TearOff::new(object, count_or_pointer as u32); + let tear_off_ptr: *mut c_void = transmute_copy(&tear_off); + let encoding: usize = ((tear_off_ptr as usize) >> 1) | (1 << (usize::BITS - 1)); + + loop { + match self.0.compare_exchange_weak( + count_or_pointer, + encoding as isize, + Ordering::AcqRel, + Ordering::Relaxed, + ) { + Ok(_) => { + let result: *mut c_void = transmute(tear_off); + TearOff::from_strong_ptr(result).strong_count.add_ref(); + return result; + } + Err(pointer) => count_or_pointer = pointer, + } + + if is_weak_ref(count_or_pointer) { + return TearOff::from_encoding(count_or_pointer); + } + + TearOff::from_strong_ptr(tear_off_ptr) + .strong_count + .0 + .store(count_or_pointer as i32, Ordering::SeqCst); + } + } + } +} + +fn is_weak_ref(value: isize) -> bool { + value < 0 +} + +#[repr(C)] +struct TearOff { + strong_vtable: *const IWeakReferenceSource_Vtbl, + weak_vtable: *const IWeakReference_Vtbl, + object: *mut c_void, + strong_count: RefCount, + weak_count: RefCount, +} + +impl TearOff { + #[allow(clippy::new_ret_no_self)] + unsafe fn new(object: *mut c_void, strong_count: u32) -> IWeakReferenceSource { + unsafe { + transmute(Box::new(TearOff { + strong_vtable: &Self::STRONG_VTABLE, + weak_vtable: &Self::WEAK_VTABLE, + object, + strong_count: RefCount::new(strong_count), + weak_count: RefCount::new(1), + })) + } + } + + unsafe fn from_encoding(encoding: isize) -> *mut c_void { + unsafe { + let tear_off = TearOff::decode(encoding); + tear_off.strong_count.add_ref(); + tear_off as *mut _ as *mut _ + } + } + + const STRONG_VTABLE: IWeakReferenceSource_Vtbl = IWeakReferenceSource_Vtbl { + base__: IUnknown_Vtbl { + QueryInterface: Self::StrongQueryInterface, + AddRef: Self::StrongAddRef, + Release: Self::StrongRelease, + }, + GetWeakReference: Self::StrongDowngrade, + }; + + const WEAK_VTABLE: IWeakReference_Vtbl = IWeakReference_Vtbl { + base__: IUnknown_Vtbl { + QueryInterface: Self::WeakQueryInterface, + AddRef: Self::WeakAddRef, + Release: Self::WeakRelease, + }, + Resolve: Self::WeakUpgrade, + }; + + unsafe fn from_strong_ptr<'a>(this: *mut c_void) -> &'a mut Self { + unsafe { &mut *(this as *mut *mut c_void as *mut Self) } + } + + unsafe fn from_weak_ptr<'a>(this: *mut c_void) -> &'a mut Self { + unsafe { &mut *((this as *mut *mut c_void).sub(1) as *mut Self) } + } + + unsafe fn decode<'a>(value: isize) -> &'a mut Self { + unsafe { transmute(value << 1) } + } + + unsafe fn query_interface(&self, iid: *const GUID, interface: *mut *mut c_void) -> HRESULT { + unsafe { + ((*(*(self.object as *mut *mut IUnknown_Vtbl))).QueryInterface)( + self.object, + iid, + interface, + ) + } + } + + unsafe extern "system" fn StrongQueryInterface( + ptr: *mut c_void, + iid: *const GUID, + interface: *mut *mut c_void, + ) -> HRESULT { + unsafe { + let this = Self::from_strong_ptr(ptr); + + if iid.is_null() || interface.is_null() { + return E_POINTER; + } + + // Only directly respond to queries for the the tear-off's strong interface. This is + // effectively a self-query. + if *iid == IWeakReferenceSource::IID { + *interface = ptr; + this.strong_count.add_ref(); + return HRESULT(0); + } + + // As the tear-off is sharing the identity of the object, simply delegate any remaining + // queries to the object. + this.query_interface(iid, interface) + } + } + + unsafe extern "system" fn WeakQueryInterface( + ptr: *mut c_void, + iid: *const GUID, + interface: *mut *mut c_void, + ) -> HRESULT { + unsafe { + let this = Self::from_weak_ptr(ptr); + + if iid.is_null() || interface.is_null() { + return E_POINTER; + } + + // While the weak vtable is packed into the same allocation as the strong vtable and + // tear-off, it represents a distinct COM identity and thus does not share or delegate to + // the object. + + *interface = if *iid == IWeakReference::IID + || *iid == IUnknown::IID + || *iid == IAgileObject::IID + { + ptr + } else { + #[cfg(windows)] + if *iid == IMarshal::IID { + this.weak_count.add_ref(); + return marshaler(transmute::<*mut c_void, IUnknown>(ptr), interface); + } + + null_mut() + }; + + if (*interface).is_null() { + E_NOINTERFACE + } else { + this.weak_count.add_ref(); + HRESULT(0) + } + } + } + + unsafe extern "system" fn StrongAddRef(ptr: *mut c_void) -> u32 { + unsafe { + let this = Self::from_strong_ptr(ptr); + + // Implement `AddRef` directly as we own the strong reference. + this.strong_count.add_ref() + } + } + + unsafe extern "system" fn WeakAddRef(ptr: *mut c_void) -> u32 { + unsafe { + let this = Self::from_weak_ptr(ptr); + + // Implement `AddRef` directly as we own the weak reference. + this.weak_count.add_ref() + } + } + + unsafe extern "system" fn StrongRelease(ptr: *mut c_void) -> u32 { + unsafe { + let this = Self::from_strong_ptr(ptr); + + // Forward strong `Release` to the object so that it can destroy itself. It will then + // decrement its weak reference and allow the tear-off to be released as needed. + ((*(*(this.object as *mut *mut IUnknown_Vtbl))).Release)(this.object) + } + } + + unsafe extern "system" fn WeakRelease(ptr: *mut c_void) -> u32 { + unsafe { + let this = Self::from_weak_ptr(ptr); + + // Implement `Release` directly as we own the weak reference. + let remaining = this.weak_count.release(); + + // If there are no remaining references, it means that the object has already been + // destroyed. Go ahead and destroy the tear-off. + if remaining == 0 { + let _ = Box::from_raw(this); + } + + remaining + } + } + + unsafe extern "system" fn StrongDowngrade( + ptr: *mut c_void, + interface: *mut *mut c_void, + ) -> HRESULT { + unsafe { + let this = Self::from_strong_ptr(ptr); + + // The strong vtable hands out a reference to the weak vtable. This is always safe and + // straightforward since a strong reference guarantees there is at least one weak + // reference. + *interface = &mut this.weak_vtable as *mut _ as _; + this.weak_count.add_ref(); + HRESULT(0) + } + } + + unsafe extern "system" fn WeakUpgrade( + ptr: *mut c_void, + iid: *const GUID, + interface: *mut *mut c_void, + ) -> HRESULT { + unsafe { + let this = Self::from_weak_ptr(ptr); + + this.strong_count + .0 + .fetch_update(Ordering::Acquire, Ordering::Relaxed, |count| { + // Attempt to acquire a strong reference count to stabilize the object for the duration + // of the `QueryInterface` call. + bool::then_some(count != 0, count + 1) + }) + .map(|_| { + // Let the object respond to the upgrade query. + let result = this.query_interface(iid, interface); + // Decrement the temporary reference account used to stabilize the object. + this.strong_count.0.fetch_sub(1, Ordering::Relaxed); + // Return the result of the query. + result + }) + .unwrap_or_else(|_| { + *interface = null_mut(); + HRESULT(0) + }) + } + } +} diff --git a/vendor/windows-core/src/imp/windows.rs b/vendor/windows-core/src/imp/windows.rs new file mode 100644 index 00000000..d8dd81f0 --- /dev/null +++ b/vendor/windows-core/src/imp/windows.rs @@ -0,0 +1,11 @@ +mod factory_cache; +pub use factory_cache::*; + +mod generic_factory; +pub use generic_factory::*; + +mod bindings; +pub use bindings::*; + +mod marshaler; +pub use marshaler::*; diff --git a/vendor/windows-core/src/inspectable.rs b/vendor/windows-core/src/inspectable.rs new file mode 100644 index 00000000..adca8a3c --- /dev/null +++ b/vendor/windows-core/src/inspectable.rs @@ -0,0 +1,123 @@ +use super::*; +use core::ffi::c_void; +use core::ptr::null_mut; + +/// Parent interface for all WinRT interfaces. +/// +/// A WinRT object that may be used as a polymorphic stand-in for any WinRT class, interface, or boxed value. +/// [`IInspectable`] represents the +/// [IInspectable](https://docs.microsoft.com/en-us/windows/win32/api/inspectable/nn-inspectable-iinspectable) +/// interface. +#[repr(transparent)] +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct IInspectable(pub IUnknown); + +interface_hierarchy!(IInspectable, IUnknown); + +impl IInspectable { + /// Returns the canonical type name for the underlying object. + #[cfg(windows)] + pub fn GetRuntimeClassName(&self) -> Result<HSTRING> { + unsafe { + let mut abi = null_mut(); + (self.vtable().GetRuntimeClassName)(core::mem::transmute_copy(self), &mut abi).ok()?; + Ok(core::mem::transmute::<*mut c_void, HSTRING>(abi)) + } + } + + /// Gets the trust level of the current object. + pub fn GetTrustLevel(&self) -> Result<i32> { + unsafe { + let mut value = 0; + (self.vtable().GetTrustLevel)(core::mem::transmute_copy(self), &mut value).ok()?; + Ok(value) + } + } +} + +#[doc(hidden)] +#[repr(C)] +pub struct IInspectable_Vtbl { + pub base: IUnknown_Vtbl, + pub GetIids: unsafe extern "system" fn( + this: *mut c_void, + count: *mut u32, + values: *mut *mut GUID, + ) -> HRESULT, + pub GetRuntimeClassName: + unsafe extern "system" fn(this: *mut c_void, value: *mut *mut c_void) -> HRESULT, + pub GetTrustLevel: unsafe extern "system" fn(this: *mut c_void, value: *mut i32) -> HRESULT, +} + +unsafe impl Interface for IInspectable { + type Vtable = IInspectable_Vtbl; + const IID: GUID = GUID::from_u128(0xaf86e2e0_b12d_4c6a_9c5a_d7aa65101e90); +} + +impl RuntimeType for IInspectable { + const SIGNATURE: imp::ConstBuffer = imp::ConstBuffer::from_slice(b"cinterface(IInspectable)"); +} + +impl RuntimeName for IInspectable {} + +impl IInspectable_Vtbl { + pub const fn new<Identity: IUnknownImpl, Name: RuntimeName, const OFFSET: isize>() -> Self { + unsafe extern "system" fn GetIids( + _: *mut c_void, + count: *mut u32, + values: *mut *mut GUID, + ) -> HRESULT { + unsafe { + if count.is_null() || values.is_null() { + return imp::E_POINTER; + } + // Note: even if we end up implementing this in future, it still doesn't need a this pointer + // since the data to be returned is type- not instance-specific so can be shared for all + // interfaces. + *count = 0; + *values = null_mut(); + HRESULT(0) + } + } + unsafe extern "system" fn GetRuntimeClassName<T: RuntimeName>( + _: *mut c_void, + value: *mut *mut c_void, + ) -> HRESULT { + unsafe { + if value.is_null() { + return imp::E_POINTER; + } + + #[cfg(windows)] + { + *value = core::mem::transmute::<HSTRING, *mut c_void>(T::NAME.into()); + } + + #[cfg(not(windows))] + { + *value = core::ptr::null_mut(); + } + + HRESULT(0) + } + } + unsafe extern "system" fn GetTrustLevel<T: IUnknownImpl, const OFFSET: isize>( + this: *mut c_void, + value: *mut i32, + ) -> HRESULT { + unsafe { + if value.is_null() { + return imp::E_POINTER; + } + let this = (this as *mut *mut c_void).offset(OFFSET) as *mut T; + (*this).GetTrustLevel(value) + } + } + Self { + base: IUnknown_Vtbl::new::<Identity, OFFSET>(), + GetIids, + GetRuntimeClassName: GetRuntimeClassName::<Name>, + GetTrustLevel: GetTrustLevel::<Identity, OFFSET>, + } + } +} diff --git a/vendor/windows-core/src/interface.rs b/vendor/windows-core/src/interface.rs new file mode 100644 index 00000000..cb5f7fcb --- /dev/null +++ b/vendor/windows-core/src/interface.rs @@ -0,0 +1,339 @@ +use super::*; +use core::any::Any; +use core::ffi::c_void; +use core::marker::PhantomData; +use core::mem::{forget, transmute_copy, MaybeUninit}; +use core::ptr::NonNull; + +/// Provides low-level access to an interface vtable. +/// +/// This trait is automatically implemented by the generated bindings and should not be +/// implemented manually. +/// +/// # Safety +pub unsafe trait Interface: Sized + Clone { + #[doc(hidden)] + type Vtable; + + /// The `GUID` associated with the interface. + const IID: GUID; + + #[doc(hidden)] + const UNKNOWN: bool = true; + + /// A reference to the interface's vtable + #[doc(hidden)] + #[inline(always)] + fn vtable(&self) -> &Self::Vtable { + // SAFETY: the implementor of the trait guarantees that `Self` is castable to its vtable + unsafe { self.assume_vtable::<Self>() } + } + + /// Cast this interface as a reference to the supplied interfaces `Vtable` + /// + /// # Safety + /// + /// This is safe if `T` is an equivalent interface to `Self` or a super interface. + /// In other words, `T::Vtable` must be equivalent to the beginning of `Self::Vtable`. + #[doc(hidden)] + #[inline(always)] + unsafe fn assume_vtable<T: Interface>(&self) -> &T::Vtable { + unsafe { &**(self.as_raw() as *mut *mut T::Vtable) } + } + + /// Returns the raw COM interface pointer. The resulting pointer continues to be owned by the `Interface` implementation. + #[inline(always)] + fn as_raw(&self) -> *mut c_void { + // SAFETY: implementors of this trait must guarantee that the implementing type has a pointer in-memory representation + unsafe { transmute_copy(self) } + } + + /// Returns the raw COM interface pointer and releases ownership. It the caller's responsibility to release the COM interface pointer. + #[inline(always)] + fn into_raw(self) -> *mut c_void { + // SAFETY: implementors of this trait must guarantee that the implementing type has a pointer in-memory representation + let raw = self.as_raw(); + forget(self); + raw + } + + /// Creates an `Interface` by taking ownership of the `raw` COM interface pointer. + /// + /// # Safety + /// + /// The `raw` pointer must be owned by the caller and represent a valid COM interface pointer. In other words, + /// it must point to a vtable beginning with the `IUnknown` function pointers and match the vtable of `Interface`. + unsafe fn from_raw(raw: *mut c_void) -> Self { + unsafe { transmute_copy(&raw) } + } + + /// Creates an `Interface` that is valid so long as the `raw` COM interface pointer is valid. + /// + /// # Safety + /// + /// The `raw` pointer must be a valid COM interface pointer. In other words, it must point to a vtable + /// beginning with the `IUnknown` function pointers and match the vtable of `Interface`. + #[inline(always)] + unsafe fn from_raw_borrowed(raw: &*mut c_void) -> Option<&Self> { + unsafe { + if raw.is_null() { + None + } else { + Some(transmute_copy(&raw)) + } + } + } + + /// Attempts to cast the current interface to another interface using `QueryInterface`. + /// + /// The name `cast` is preferred to `query` because there is a WinRT method named query but not one + /// named cast. + #[inline(always)] + fn cast<T: Interface>(&self) -> Result<T> { + // SAFETY: `result` is valid for writing an interface pointer and it is safe + // to cast the `result` pointer as `T` on success because we are using the `IID` tied + // to `T` which the implementor of `Interface` has guaranteed is correct + unsafe { + // If query() returns a failure code then we propagate that failure code to the caller. + // In that case, we ignore the contents of 'result' (which will _not_ be dropped, + // because MaybeUninit intentionally does not drop its contents). + // + // This guards against implementations of COM interfaces which may store non-null values + // in 'result' but still return E_NOINTERFACE. + let mut result = MaybeUninit::<Option<T>>::zeroed(); + self.query(&T::IID, result.as_mut_ptr() as _).ok()?; + + // If we get here, then query() has succeeded, but we still need to double-check + // that the output pointer is non-null. + if let Some(obj) = result.assume_init() { + Ok(obj) + } else { + Err(imp::E_POINTER.into()) + } + } + } + + /// This casts the given COM interface to [`&dyn Any`]. + /// + /// Applications should generally _not_ call this method directly. Instead, use the + /// [`Interface::cast_object_ref`] or [`Interface::cast_object`] methods. + /// + /// `T` must be a type that has been annotated with `#[implement]`; this is checked at + /// compile-time by the generic constraints of this method. However, note that the + /// returned `&dyn Any` refers to the _outer_ implementation object that was generated by + /// `#[implement]`, i.e. the `MyApp_Impl` type, not the inner `MyApp` type. + /// + /// If the given object is not a Rust object, or is a Rust object but not `T`, or is a Rust + /// object that contains non-static lifetimes, then this function will return `Err(E_NOINTERFACE)`. + /// + /// # Safety + /// + /// **IMPORTANT!!** This uses a non-standard protocol for QueryInterface! The `DYNAMIC_CAST_IID` + /// IID identifies this protocol, but there is no `IDynamicCast` interface. Instead, objects + /// that recognize `DYNAMIC_CAST_IID` simply store their `&dyn Any` directly at the interface + /// pointer that was passed to `QueryInterface. This means that the returned value has a + /// size that is twice as large (`size_of::<&dyn Any>() == 2 * size_of::<*const c_void>()`). + /// + /// This means that callers that use this protocol cannot simply pass `&mut ptr` for + /// an ordinary single-pointer-sized pointer. Only this method understands this protocol. + /// + /// Another part of this protocol is that the implementation of `QueryInterface` _does not_ + /// AddRef the object. The caller must guarantee the liveness of the COM object. In Rust, + /// this means tying the lifetime of the IUnknown* that we used for the QueryInterface + /// call to the lifetime of the returned `&dyn Any` value. + /// + /// This method preserves type safety and relies on these invariants: + /// + /// * All `QueryInterface` implementations that recognize `DYNAMIC_CAST_IID` are generated by + /// the `#[implement]` macro and respect the rules described here. + #[inline(always)] + fn cast_to_any<T>(&self) -> Result<&dyn Any> + where + T: ComObjectInner, + T::Outer: Any + 'static + IUnknownImpl<Impl = T>, + { + unsafe { + let mut any_ref_arg: MaybeUninit<&dyn Any> = MaybeUninit::zeroed(); + self.query( + &DYNAMIC_CAST_IID, + any_ref_arg.as_mut_ptr() as *mut *mut c_void, + ) + .ok()?; + Ok(any_ref_arg.assume_init()) + } + } + + /// Returns `true` if the given COM interface refers to an implementation of `T`. + /// + /// `T` must be a type that has been annotated with `#[implement]`; this is checked at + /// compile-time by the generic constraints of this method. + /// + /// If the given object is not a Rust object, or is a Rust object but not `T`, or is a Rust + /// object that contains non-static lifetimes, then this function will return `false`. + #[inline(always)] + fn is_object<T>(&self) -> bool + where + T: ComObjectInner, + T::Outer: Any + 'static + IUnknownImpl<Impl = T>, + { + if let Ok(any) = self.cast_to_any::<T>() { + any.is::<T::Outer>() + } else { + false + } + } + + /// This casts the given COM interface to [`&dyn Any`]. It returns a reference to the "outer" + /// object, e.g. `&MyApp_Impl`, not the inner `&MyApp` object. + /// + /// `T` must be a type that has been annotated with `#[implement]`; this is checked at + /// compile-time by the generic constraints of this method. However, note that the + /// returned `&dyn Any` refers to the _outer_ implementation object that was generated by + /// `#[implement]`, i.e. the `MyApp_Impl` type, not the inner `MyApp` type. + /// + /// If the given object is not a Rust object, or is a Rust object but not `T`, or is a Rust + /// object that contains non-static lifetimes, then this function will return `Err(E_NOINTERFACE)`. + /// + /// The returned value is borrowed. If you need an owned (counted) reference, then use + /// [`Interface::cast_object`]. + #[inline(always)] + fn cast_object_ref<T>(&self) -> Result<&T::Outer> + where + T: ComObjectInner, + T::Outer: Any + 'static + IUnknownImpl<Impl = T>, + { + let any: &dyn Any = self.cast_to_any::<T>()?; + if let Some(outer) = any.downcast_ref::<T::Outer>() { + Ok(outer) + } else { + Err(imp::E_NOINTERFACE.into()) + } + } + + /// This casts the given COM interface to [`&dyn Any`]. It returns a reference to the "outer" + /// object, e.g. `MyApp_Impl`, not the inner `MyApp` object. + /// + /// `T` must be a type that has been annotated with `#[implement]`; this is checked at + /// compile-time by the generic constraints of this method. However, note that the + /// returned `&dyn Any` refers to the _outer_ implementation object that was generated by + /// `#[implement]`, i.e. the `MyApp_Impl` type, not the inner `MyApp` type. + /// + /// If the given object is not a Rust object, or is a Rust object but not `T`, or is a Rust + /// object that contains non-static lifetimes, then this function will return `Err(E_NOINTERFACE)`. + /// + /// The returned value is an owned (counted) reference; this function calls `AddRef` on the + /// underlying COM object. If you do not need an owned reference, then you can use the + /// [`Interface::cast_object_ref`] method instead, and avoid the cost of `AddRef` / `Release`. + #[inline(always)] + fn cast_object<T>(&self) -> Result<ComObject<T>> + where + T: ComObjectInner, + T::Outer: Any + 'static + IUnknownImpl<Impl = T>, + { + let object_ref = self.cast_object_ref::<T>()?; + Ok(object_ref.to_object()) + } + + /// Attempts to create a [`Weak`] reference to this object. + fn downgrade(&self) -> Result<Weak<Self>> { + self.cast::<imp::IWeakReferenceSource>() + .and_then(|source| Weak::downgrade(&source)) + } + + /// Call `QueryInterface` on this interface + /// + /// # Safety + /// + /// `interface` must be a non-null, valid pointer for writing an interface pointer. + #[inline(always)] + unsafe fn query(&self, iid: *const GUID, interface: *mut *mut c_void) -> HRESULT { + unsafe { + if Self::UNKNOWN { + (self.assume_vtable::<IUnknown>().QueryInterface)(self.as_raw(), iid, interface) + } else { + panic!("Non-COM interfaces cannot be queried.") + } + } + } + + /// Creates an `InterfaceRef` for this reference. The `InterfaceRef` tracks lifetimes statically, + /// and eliminates the need for dynamic reference count adjustments (AddRef/Release). + fn to_ref(&self) -> InterfaceRef<'_, Self> { + InterfaceRef::from_interface(self) + } +} + +/// This has the same memory representation as `IFoo`, but represents a borrowed interface pointer. +/// +/// This type has no `Drop` impl; it does not AddRef/Release the given interface. However, because +/// it has a lifetime parameter, it always represents a non-null pointer to an interface. +#[repr(transparent)] +pub struct InterfaceRef<'a, I>(NonNull<c_void>, PhantomData<&'a I>); + +impl<I> Copy for InterfaceRef<'_, I> {} + +impl<I> Clone for InterfaceRef<'_, I> { + fn clone(&self) -> Self { + *self + } +} + +impl<I: core::fmt::Debug + Interface> core::fmt::Debug for InterfaceRef<'_, I> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + <I as core::fmt::Debug>::fmt(&**self, f) + } +} + +impl<I: Interface> InterfaceRef<'_, I> { + /// Creates an `InterfaceRef` from a raw pointer. _This is extremely dangerous, since there + /// is no lifetime tracking at all!_ + /// + /// # Safety + /// The caller must guarantee that the `'a` lifetime parameter is bound by context to a correct + /// lifetime. + #[inline(always)] + pub unsafe fn from_raw(ptr: NonNull<c_void>) -> Self { + Self(ptr, PhantomData) + } + + /// Creates an `InterfaceRef` from an interface reference. This safely associates the lifetime + /// of the interface reference with the `'a` parameter of `InterfaceRef`. This allows for + /// lifetime checking _without_ calling AddRef/Release on the underlying lifetime, which can + /// improve efficiency. + #[inline(always)] + pub fn from_interface(interface: &I) -> Self { + unsafe { + // SAFETY: new_unchecked() should be valid because Interface::as_raw should always + // return a non-null pointer. + Self(NonNull::new_unchecked(interface.as_raw()), PhantomData) + } + } + + /// Calls AddRef on the underlying COM interface and returns an "owned" (counted) reference. + #[inline(always)] + pub fn to_owned(self) -> I { + (*self).clone() + } +} + +impl<'a, 'i: 'a, I: Interface> From<&'i I> for InterfaceRef<'a, I> { + #[inline(always)] + fn from(interface: &'a I) -> InterfaceRef<'a, I> { + InterfaceRef::from_interface(interface) + } +} + +impl<I: Interface> core::ops::Deref for InterfaceRef<'_, I> { + type Target = I; + + #[inline(always)] + fn deref(&self) -> &I { + unsafe { core::mem::transmute(self) } + } +} + +/// This IID identifies a special protocol, used by [`Interface::cast_to_any`]. This is _not_ +/// an ordinary COM interface; it uses special lifetime rules and a larger interface pointer. +/// See the comments on [`Interface::cast_to_any`]. +#[doc(hidden)] +pub const DYNAMIC_CAST_IID: GUID = GUID::from_u128(0xae49d5cb_143f_431c_874c_2729336e4eca); diff --git a/vendor/windows-core/src/lib.rs b/vendor/windows-core/src/lib.rs new file mode 100644 index 00000000..7fa7db45 --- /dev/null +++ b/vendor/windows-core/src/lib.rs @@ -0,0 +1,54 @@ +#![doc = include_str!("../readme.md")] +#![doc(html_no_source)] +#![allow(non_snake_case)] +#![debugger_visualizer(natvis_file = "../windows-core.natvis")] +#![cfg_attr(all(not(feature = "std")), no_std)] + +#[cfg(windows)] +include!("windows.rs"); + +extern crate self as windows_core; + +extern crate alloc; + +use alloc::boxed::Box; + +#[doc(hidden)] +pub mod imp; + +mod as_impl; +mod com_object; +mod guid; +mod inspectable; +mod interface; +mod out_param; +mod out_ref; +mod param; +mod param_value; +mod r#ref; +mod runtime_name; +mod runtime_type; +mod scoped_interface; +mod r#type; +mod unknown; +mod weak; + +pub use as_impl::*; +pub use com_object::*; +pub use guid::*; +pub use inspectable::*; +pub use interface::*; +pub use out_param::*; +pub use out_ref::*; +pub use param::*; +pub use param_value::*; +pub use r#ref::*; +pub use r#type::*; +pub use runtime_name::*; +pub use runtime_type::*; +pub use scoped_interface::*; +pub use unknown::*; +pub use weak::*; +pub use windows_implement::implement; +pub use windows_interface::interface; +pub use windows_result::*; diff --git a/vendor/windows-core/src/out_param.rs b/vendor/windows-core/src/out_param.rs new file mode 100644 index 00000000..828746c1 --- /dev/null +++ b/vendor/windows-core/src/out_param.rs @@ -0,0 +1,63 @@ +use super::*; +use core::mem::{take, transmute_copy, zeroed}; + +/// Provides automatic parameter conversion in cases where the Windows API expects implicit conversion support. +/// +/// This is a mutable version of [Param] meant to support out parameters. +/// There is no need to implement this trait. Blanket implementations are provided for all applicable Windows types. +pub trait OutParam<T: TypeKind, C = <T as TypeKind>::TypeKind>: Sized +where + T: Type<T>, +{ + #[doc(hidden)] + unsafe fn borrow_mut(&self) -> OutRef<'_, T>; +} + +impl<T> OutParam<T, CloneType> for &mut T +where + T: TypeKind<TypeKind = CloneType> + Clone + Default, +{ + unsafe fn borrow_mut(&self) -> OutRef<'_, T> { + unsafe { + let this: &mut T = transmute_copy(self); + take(this); + transmute_copy(self) + } + } +} + +impl<T> OutParam<T, CopyType> for &mut T +where + T: TypeKind<TypeKind = CopyType> + Clone + Default, +{ + unsafe fn borrow_mut(&self) -> OutRef<'_, T> { + unsafe { transmute_copy(self) } + } +} + +impl<T> OutParam<T, InterfaceType> for &mut Option<T> +where + T: TypeKind<TypeKind = InterfaceType> + Clone, +{ + unsafe fn borrow_mut(&self) -> OutRef<'_, T> { + unsafe { + let this: &mut Option<T> = transmute_copy(self); + take(this); + transmute_copy(self) + } + } +} + +impl<T> OutParam<T> for Option<&mut T> +where + T: Type<T>, +{ + unsafe fn borrow_mut(&self) -> OutRef<'_, T> { + unsafe { + match self { + Some(this) => transmute_copy(this), + None => zeroed(), + } + } + } +} diff --git a/vendor/windows-core/src/out_ref.rs b/vendor/windows-core/src/out_ref.rs new file mode 100644 index 00000000..24ba06ca --- /dev/null +++ b/vendor/windows-core/src/out_ref.rs @@ -0,0 +1,31 @@ +use super::*; + +/// A borrowed type with the same memory layout as the type itself that can be used to construct ABI-compatible function signatures. +/// +/// This is a mutable version of [Ref] meant to support out parameters. +#[repr(transparent)] +pub struct OutRef<'a, T: Type<T>>(*mut T::Abi, core::marker::PhantomData<&'a T>); + +impl<T: Type<T>> OutRef<'_, T> { + /// Returns `true` if the argument is null. + pub fn is_null(&self) -> bool { + self.0.is_null() + } + + /// Overwrites a memory location with the given value without reading or dropping the old value. + pub fn write(self, value: T::Default) -> Result<()> { + if self.0.is_null() { + Err(Error::from_hresult(imp::E_POINTER)) + } else { + unsafe { *self.0 = core::mem::transmute_copy(&value) } + core::mem::forget(value); + Ok(()) + } + } +} + +impl<'a, T: Type<T>> From<&'a mut T::Default> for OutRef<'a, T> { + fn from(from: &'a mut T::Default) -> Self { + unsafe { core::mem::transmute(from) } + } +} diff --git a/vendor/windows-core/src/param.rs b/vendor/windows-core/src/param.rs new file mode 100644 index 00000000..5ebf3add --- /dev/null +++ b/vendor/windows-core/src/param.rs @@ -0,0 +1,76 @@ +use super::*; +use core::mem::transmute_copy; +use core::mem::zeroed; + +/// Provides automatic parameter conversion in cases where the Windows API expects implicit conversion support. +/// +/// There is no need to implement this trait. Blanket implementations are provided for all applicable Windows types. +pub trait Param<T: TypeKind, C = <T as TypeKind>::TypeKind>: Sized +where + T: Type<T>, +{ + #[doc(hidden)] + unsafe fn param(self) -> ParamValue<T>; +} + +impl<T> Param<T> for Option<&T> +where + T: Type<T>, +{ + unsafe fn param(self) -> ParamValue<T> { + unsafe { + ParamValue::Borrowed(match self { + Some(item) => transmute_copy(item), + None => zeroed(), + }) + } + } +} + +impl<T> Param<T> for InterfaceRef<'_, T> +where + T: Type<T>, +{ + unsafe fn param(self) -> ParamValue<T> { + unsafe { ParamValue::Borrowed(transmute_copy(&self)) } + } +} + +impl<T, U> Param<T, InterfaceType> for &U +where + T: TypeKind<TypeKind = InterfaceType> + Clone, + T: Interface, + U: Interface, + U: imp::CanInto<T>, +{ + unsafe fn param(self) -> ParamValue<T> { + unsafe { + if U::QUERY { + self.cast() + .map_or(ParamValue::Borrowed(zeroed()), |ok| ParamValue::Owned(ok)) + } else { + ParamValue::Borrowed(transmute_copy(self)) + } + } + } +} + +impl<T> Param<T, CloneType> for &T +where + T: TypeKind<TypeKind = CloneType> + Clone, +{ + unsafe fn param(self) -> ParamValue<T> { + unsafe { ParamValue::Borrowed(transmute_copy(self)) } + } +} + +impl<T, U> Param<T, CopyType> for U +where + T: TypeKind<TypeKind = CopyType> + Clone, + U: TypeKind<TypeKind = CopyType> + Clone, + U: imp::CanInto<T>, +{ + unsafe fn param(self) -> ParamValue<T> { + unsafe { ParamValue::Owned(transmute_copy(&self)) } + } +} diff --git a/vendor/windows-core/src/param_value.rs b/vendor/windows-core/src/param_value.rs new file mode 100644 index 00000000..4500e261 --- /dev/null +++ b/vendor/windows-core/src/param_value.rs @@ -0,0 +1,24 @@ +use super::*; +use core::mem::transmute_copy; + +#[doc(hidden)] +pub enum ParamValue<T: Type<T>> { + Owned(T), + Borrowed(T::Abi), +} + +impl<T: Type<T>> ParamValue<T> { + // TODO: replace with `borrow` in windows-bindgen + pub fn abi(&self) -> T::Abi { + unsafe { + match self { + Self::Owned(item) => transmute_copy(item), + Self::Borrowed(borrowed) => transmute_copy(borrowed), + } + } + } + + pub fn borrow(&self) -> Ref<'_, T> { + unsafe { transmute_copy(&self.abi()) } + } +} diff --git a/vendor/windows-core/src/ref.rs b/vendor/windows-core/src/ref.rs new file mode 100644 index 00000000..fa70852c --- /dev/null +++ b/vendor/windows-core/src/ref.rs @@ -0,0 +1,60 @@ +use super::*; +use core::mem::transmute; + +/// A borrowed type with the same memory layout as the type itself that can be used to construct ABI-compatible function signatures. +#[repr(transparent)] +pub struct Ref<'a, T: Type<T>>(T::Abi, core::marker::PhantomData<&'a T>); + +impl<T: Type<T>> Ref<'_, T> { + /// Returns `true` if the argument is null. + pub fn is_null(&self) -> bool { + T::is_null(&self.0) + } + + /// Converts the argument to a [`Result<&T>`] reference. + pub fn ok(&self) -> Result<&T> { + self.as_ref() + .ok_or_else(|| Error::from_hresult(imp::E_POINTER)) + } + + /// Converts the argument to a [`Option<&T>`] reference. + pub fn as_ref(&self) -> Option<&T> { + if self.is_null() { + None + } else { + unsafe { Some(self.assume_init_ref()) } + } + } + + /// Converts the argument to a `&T` reference. + /// + /// # Panics + /// + /// Panics if the argument is null. + #[track_caller] + pub fn unwrap(&self) -> &T { + self.as_ref().expect("called `Ref::unwrap` on a null value") + } + + /// Converts the argument to an [`Option<T>`] by cloning the reference. + pub fn cloned(&self) -> Option<T> { + self.as_ref().cloned() + } + + unsafe fn assume_init_ref(&self) -> &T { + unsafe { T::assume_init_ref(&self.0) } + } +} + +impl<T: Type<T>> core::ops::Deref for Ref<'_, T> { + type Target = T::Default; + fn deref(&self) -> &Self::Target { + unsafe { transmute(&self.0) } + } +} + +impl<'a, T: Type<T>> From<&'a T::Default> for Ref<'a, T> { + fn from(from: &'a T::Default) -> Self { + unsafe { core::mem::transmute_copy(from) } + } +} diff --git a/vendor/windows-core/src/runtime_name.rs b/vendor/windows-core/src/runtime_name.rs new file mode 100644 index 00000000..c6af26ae --- /dev/null +++ b/vendor/windows-core/src/runtime_name.rs @@ -0,0 +1,5 @@ +#[doc(hidden)] +pub trait RuntimeName { + // TODO: needs to use ConstBuffer like RuntimeType to allow generic interfaces to have names for GetRuntimeClassName + const NAME: &'static str = ""; +} diff --git a/vendor/windows-core/src/runtime_type.rs b/vendor/windows-core/src/runtime_type.rs new file mode 100644 index 00000000..f28ded85 --- /dev/null +++ b/vendor/windows-core/src/runtime_type.rs @@ -0,0 +1,30 @@ +use super::*; + +#[doc(hidden)] +pub trait RuntimeType: Type<Self> { + const SIGNATURE: imp::ConstBuffer; +} + +macro_rules! primitives { + ($(($t:ty, $s:literal)),+) => { + $( + impl RuntimeType for $t { + const SIGNATURE: imp::ConstBuffer = imp::ConstBuffer::from_slice($s); + } + )* + }; +} + +primitives! { + (bool, b"b1"), + (i8, b"i1"), + (u8, b"u1"), + (i16, b"i2"), + (u16, b"u2"), + (i32, b"i4"), + (u32, b"u4"), + (i64, b"i8"), + (u64, b"u8"), + (f32, b"f4"), + (f64, b"f8") +} diff --git a/vendor/windows-core/src/scoped_interface.rs b/vendor/windows-core/src/scoped_interface.rs new file mode 100644 index 00000000..5a701e8c --- /dev/null +++ b/vendor/windows-core/src/scoped_interface.rs @@ -0,0 +1,41 @@ +use super::*; +use core::ffi::c_void; +use core::marker::PhantomData; + +#[doc(hidden)] +#[repr(C)] +pub struct ScopedHeap { + pub vtable: *const c_void, + pub this: *const c_void, +} + +#[doc(hidden)] +pub struct ScopedInterface<'a, T: Interface> { + interface: T, + lifetime: PhantomData<&'a T>, +} + +impl<T: Interface> ScopedInterface<'_, T> { + pub fn new(interface: T) -> Self { + Self { + interface, + lifetime: PhantomData, + } + } +} + +impl<T: Interface> core::ops::Deref for ScopedInterface<'_, T> { + type Target = T; + + fn deref(&self) -> &T { + &self.interface + } +} + +impl<T: Interface> Drop for ScopedInterface<'_, T> { + fn drop(&mut self) { + unsafe { + let _ = Box::from_raw(self.interface.as_raw() as *const _ as *mut ScopedHeap); + } + } +} diff --git a/vendor/windows-core/src/type.rs b/vendor/windows-core/src/type.rs new file mode 100644 index 00000000..a64f191d --- /dev/null +++ b/vendor/windows-core/src/type.rs @@ -0,0 +1,127 @@ +use super::*; + +#[doc(hidden)] +pub trait TypeKind { + type TypeKind; +} + +#[doc(hidden)] +pub struct InterfaceType; + +#[doc(hidden)] +pub struct CloneType; + +#[doc(hidden)] +pub struct CopyType; + +#[doc(hidden)] +pub trait Type<T: TypeKind, C = <T as TypeKind>::TypeKind>: TypeKind + Sized + Clone { + type Abi; + type Default; + + fn is_null(abi: &Self::Abi) -> bool; + unsafe fn assume_init_ref(abi: &Self::Abi) -> &Self; + unsafe fn from_abi(abi: Self::Abi) -> Result<Self>; + fn from_default(default: &Self::Default) -> Result<Self>; +} + +impl<T> Type<T, InterfaceType> for T +where + T: TypeKind<TypeKind = InterfaceType> + Clone, +{ + type Abi = *mut core::ffi::c_void; + type Default = Option<Self>; + + fn is_null(abi: &Self::Abi) -> bool { + abi.is_null() + } + + unsafe fn assume_init_ref(abi: &Self::Abi) -> &Self { + unsafe { core::mem::transmute::<&*mut core::ffi::c_void, &T>(abi) } + } + + unsafe fn from_abi(abi: Self::Abi) -> Result<Self> { + unsafe { + if !abi.is_null() { + Ok(core::mem::transmute_copy(&abi)) + } else { + Err(Error::empty()) + } + } + } + + fn from_default(default: &Self::Default) -> Result<Self> { + default.as_ref().cloned().ok_or(Error::empty()) + } +} + +impl<T> Type<T, CloneType> for T +where + T: TypeKind<TypeKind = CloneType> + Clone, +{ + type Abi = core::mem::MaybeUninit<Self>; + type Default = Self; + + fn is_null(_: &Self::Abi) -> bool { + false + } + + unsafe fn assume_init_ref(abi: &Self::Abi) -> &Self { + unsafe { abi.assume_init_ref() } + } + + unsafe fn from_abi(abi: Self::Abi) -> Result<Self> { + unsafe { Ok(abi.assume_init()) } + } + + fn from_default(default: &Self::Default) -> Result<Self> { + Ok(default.clone()) + } +} + +impl<T> Type<T, CopyType> for T +where + T: TypeKind<TypeKind = CopyType> + Clone, +{ + type Abi = Self; + type Default = Self; + + fn is_null(_: &Self::Abi) -> bool { + false + } + + unsafe fn assume_init_ref(abi: &Self::Abi) -> &Self { + abi + } + + unsafe fn from_abi(abi: Self::Abi) -> Result<Self> { + Ok(abi) + } + + fn from_default(default: &Self) -> Result<Self> { + Ok(default.clone()) + } +} + +impl<T: Interface> TypeKind for T { + type TypeKind = InterfaceType; +} + +impl<T> TypeKind for *mut T { + type TypeKind = CopyType; +} + +macro_rules! primitives { + ($($t:ty),+) => { + $( + impl TypeKind for $t { + type TypeKind = CopyType; + } + )* + }; +} + +primitives!(bool, i8, u8, i16, u16, i32, u32, i64, u64, f32, f64, usize, isize); + +#[doc(hidden)] +pub type AbiType<T> = <T as Type<T>>::Abi; diff --git a/vendor/windows-core/src/unknown.rs b/vendor/windows-core/src/unknown.rs new file mode 100644 index 00000000..12588ceb --- /dev/null +++ b/vendor/windows-core/src/unknown.rs @@ -0,0 +1,187 @@ +use super::*; +use core::ffi::c_void; +use core::ptr::NonNull; + +/// Base interface for all COM interfaces. +/// +/// All COM interfaces (and thus WinRT classes and interfaces) implement +/// [IUnknown](https://docs.microsoft.com/en-us/windows/win32/api/unknwn/nn-unknwn-iunknown) +/// under the hood to provide reference-counted lifetime management as well as the ability +/// to query for additional interfaces that the object may implement. +#[repr(transparent)] +pub struct IUnknown(NonNull<c_void>); + +#[doc(hidden)] +#[repr(C)] +#[allow(non_camel_case_types)] +pub struct IUnknown_Vtbl { + pub QueryInterface: unsafe extern "system" fn( + this: *mut c_void, + iid: *const GUID, + interface: *mut *mut c_void, + ) -> HRESULT, + pub AddRef: unsafe extern "system" fn(this: *mut c_void) -> u32, + pub Release: unsafe extern "system" fn(this: *mut c_void) -> u32, +} + +unsafe impl Interface for IUnknown { + type Vtable = IUnknown_Vtbl; + const IID: GUID = GUID::from_u128(0x00000000_0000_0000_c000_000000000046); +} + +impl Clone for IUnknown { + fn clone(&self) -> Self { + unsafe { + (self.vtable().AddRef)(core::mem::transmute_copy(self)); + } + + Self(self.0) + } +} + +impl Drop for IUnknown { + fn drop(&mut self) { + unsafe { + (self.vtable().Release)(core::mem::transmute_copy(self)); + } + } +} + +impl PartialEq for IUnknown { + fn eq(&self, other: &Self) -> bool { + // First we test for ordinary pointer equality. If two COM interface pointers have the + // same pointer value, then they are the same object. This can save us a lot of time, + // since calling QueryInterface is much more expensive than a single pointer comparison. + // + // However, interface pointers may have different values and yet point to the same object. + // Since COM objects may implement multiple interfaces, COM identity can only + // be determined by querying for `IUnknown` explicitly and then comparing the + // pointer values. This works since `QueryInterface` is required to return + // the same pointer value for queries for `IUnknown`. + core::ptr::eq(self.as_raw(), other.as_raw()) + || self.cast::<IUnknown>().unwrap().0 == other.cast::<IUnknown>().unwrap().0 + } +} + +impl Eq for IUnknown {} + +impl core::fmt::Debug for IUnknown { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_tuple("IUnknown").field(&self.as_raw()).finish() + } +} + +/// The `#[implement]` macro generates implementations of this trait for the types +/// that it generates, e.g. `MyApp_Impl`, +/// +/// `ComObject` uses this trait to interact with boxed COM objects. +#[doc(hidden)] +pub trait IUnknownImpl { + /// The contained user type, e.g. `MyApp`. Also known as the "inner" type. + type Impl; + + /// Get a reference to the backing implementation. + fn get_impl(&self) -> &Self::Impl; + + /// Get a mutable reference to the contained (inner) object. + fn get_impl_mut(&mut self) -> &mut Self::Impl; + + /// Consumes the box and returns the contained (inner) object. This is the opposite of `new_box`. + fn into_inner(self) -> Self::Impl; + + /// The classic `QueryInterface` method from COM. + /// + /// # Safety + /// + /// This function is safe to call as long as the interface pointer is non-null and valid for writes + /// of an interface pointer. + unsafe fn QueryInterface(&self, iid: *const GUID, interface: *mut *mut c_void) -> HRESULT; + + /// Increments the reference count of the interface + fn AddRef(&self) -> u32; + + /// Decrements the reference count causing the interface's memory to be freed when the count is 0 + /// + /// # Safety + /// + /// This function should only be called when the interface pointer is no longer used as calling `Release` + /// on a non-aliased interface pointer and then using that interface pointer may result in use after free. + /// + /// This function takes `*mut Self` because the object may be freed by the time this method returns. + /// Taking `&self` would violate Rust's rules on reference lifetime. + unsafe fn Release(self_: *mut Self) -> u32; + + /// Returns `true` if the reference count of the box is equal to 1. + fn is_reference_count_one(&self) -> bool; + + /// Gets the trust level of the current object. + unsafe fn GetTrustLevel(&self, value: *mut i32) -> HRESULT; + + /// Gets a borrowed reference to an interface that is implemented by this ComObject. + /// + /// The returned reference does not have an additional reference count. + /// You can AddRef it by calling to_owned(). + #[inline(always)] + fn as_interface<I: Interface>(&self) -> InterfaceRef<'_, I> + where + Self: ComObjectInterface<I>, + { + <Self as ComObjectInterface<I>>::as_interface_ref(self) + } + + /// Gets an owned (counted) reference to an interface that is implemented by this ComObject. + #[inline(always)] + fn to_interface<I: Interface>(&self) -> I + where + Self: ComObjectInterface<I>, + { + <Self as ComObjectInterface<I>>::as_interface_ref(self).to_owned() + } + + /// Creates a new owned reference to this object. + /// + /// # Safety + /// + /// This function can only be safely called by `<Foo>_Impl` objects that are embedded in a + /// `ComObject`. Since we only allow safe Rust code to access these objects using a `ComObject` + /// or a `&<Foo>_Impl` that points within a `ComObject`, this is safe. + fn to_object(&self) -> ComObject<Self::Impl> + where + Self::Impl: ComObjectInner<Outer = Self>; +} + +impl IUnknown_Vtbl { + pub const fn new<T: IUnknownImpl, const OFFSET: isize>() -> Self { + unsafe extern "system" fn QueryInterface<T: IUnknownImpl, const OFFSET: isize>( + this: *mut c_void, + iid: *const GUID, + interface: *mut *mut c_void, + ) -> HRESULT { + unsafe { + let this = (this as *mut *mut c_void).offset(OFFSET) as *mut T; + (*this).QueryInterface(iid, interface) + } + } + unsafe extern "system" fn AddRef<T: IUnknownImpl, const OFFSET: isize>( + this: *mut c_void, + ) -> u32 { + unsafe { + let this = (this as *mut *mut c_void).offset(OFFSET) as *mut T; + (*this).AddRef() + } + } + unsafe extern "system" fn Release<T: IUnknownImpl, const OFFSET: isize>( + this: *mut c_void, + ) -> u32 { + unsafe { + let this = (this as *mut *mut c_void).offset(OFFSET) as *mut T; + T::Release(this) + } + } + Self { + QueryInterface: QueryInterface::<T, OFFSET>, + AddRef: AddRef::<T, OFFSET>, + Release: Release::<T, OFFSET>, + } + } +} diff --git a/vendor/windows-core/src/weak.rs b/vendor/windows-core/src/weak.rs new file mode 100644 index 00000000..f89a2315 --- /dev/null +++ b/vendor/windows-core/src/weak.rs @@ -0,0 +1,28 @@ +use super::*; +use core::marker::PhantomData; + +/// `Weak` holds a non-owning reference to an object. +#[derive(Clone, PartialEq, Eq, Default)] +pub struct Weak<I: Interface>(Option<imp::IWeakReference>, PhantomData<I>); + +impl<I: Interface> Weak<I> { + /// Creates a new `Weak` object without any backing object. + pub const fn new() -> Self { + Self(None, PhantomData) + } + + /// Attempts to upgrade the weak reference to a strong reference. + pub fn upgrade(&self) -> Option<I> { + self.0 + .as_ref() + .and_then(|inner| unsafe { inner.Resolve().ok() }) + } + + pub(crate) fn downgrade(source: &imp::IWeakReferenceSource) -> Result<Self> { + let reference = unsafe { source.GetWeakReference().ok() }; + Ok(Self(reference, PhantomData)) + } +} + +unsafe impl<I: Interface> Send for Weak<I> {} +unsafe impl<I: Interface> Sync for Weak<I> {} diff --git a/vendor/windows-core/src/windows.rs b/vendor/windows-core/src/windows.rs new file mode 100644 index 00000000..6f055bbc --- /dev/null +++ b/vendor/windows-core/src/windows.rs @@ -0,0 +1,73 @@ +mod agile_reference; +pub use agile_reference::*; + +mod array; +pub use array::*; + +#[cfg(feature = "std")] +mod event; +#[cfg(feature = "std")] +pub use event::*; + +mod handles; +pub use handles::*; + +pub use windows_strings::*; + +/// Attempts to load the factory object for the given WinRT class. +/// This can be used to access COM interfaces implemented on a Windows Runtime class factory. +pub fn factory<C: RuntimeName, I: Interface>() -> Result<I> { + imp::load_factory::<C, I>() +} + +impl Param<PCWSTR> for &BSTR { + unsafe fn param(self) -> ParamValue<PCWSTR> { + ParamValue::Owned(PCWSTR(self.as_ptr())) + } +} + +impl Param<PCWSTR> for &HSTRING { + unsafe fn param(self) -> ParamValue<PCWSTR> { + ParamValue::Owned(PCWSTR(self.as_ptr())) + } +} + +impl Param<PCWSTR> for PWSTR { + unsafe fn param(self) -> ParamValue<PCWSTR> { + ParamValue::Owned(PCWSTR(self.0)) + } +} + +impl Param<PCSTR> for PSTR { + unsafe fn param(self) -> ParamValue<PCSTR> { + ParamValue::Owned(PCSTR(self.0)) + } +} + +impl RuntimeType for HSTRING { + const SIGNATURE: imp::ConstBuffer = imp::ConstBuffer::from_slice(b"string"); +} + +impl TypeKind for PWSTR { + type TypeKind = CopyType; +} + +impl TypeKind for PSTR { + type TypeKind = CopyType; +} + +impl TypeKind for PCWSTR { + type TypeKind = CopyType; +} + +impl TypeKind for PCSTR { + type TypeKind = CopyType; +} + +impl TypeKind for HSTRING { + type TypeKind = CloneType; +} + +impl TypeKind for BSTR { + type TypeKind = CloneType; +} |
