Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make runtime (un-)initialization implicit in most cases #72

Merged
merged 1 commit into from
Jun 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ use winrt::*; // import various helper types
use winrt::windows::system::diagnostics::*; // import namespace Windows.System.Diagnostics

fn main() {
let rt = RuntimeContext::init(); // initialize the Windows Runtime
let infos = ProcessDiagnosticInfo::get_for_processes().unwrap().unwrap();
println!("Currently executed processes ({}):", infos.get_size().unwrap());
for p in &infos {
Expand Down
8 changes: 1 addition & 7 deletions examples/hexdump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,10 @@ use winrt::*;
use winrt::windows::foundation::*;
use winrt::windows::storage::*;

fn main() {
let rt = RuntimeContext::init();
run();
rt.uninit();
}

const BYTES_PER_ROW: usize = 24;
const CHUNK_SIZE: usize = 4096;

fn run() {
fn main() {
// Use the current executable as source file (because we know that will exist).
let exe_path = ::std::env::current_exe().expect("current_exe failed");
let exe_path_str = exe_path.to_str().expect("invalid unicode path");
Expand Down
8 changes: 1 addition & 7 deletions examples/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,6 @@ use winrt::windows::devices::midi::*;
use winrt::windows::storage::*;

fn main() {
let rt = RuntimeContext::init();
run();
rt.uninit();
}

fn run() {
let base = FastHString::new("https://github.com");
let relative = FastHString::new("contextfree/winrt-rust");
let uri = Uri::create_with_relative_uri(&base, &relative).unwrap();
Expand Down Expand Up @@ -44,7 +38,7 @@ fn run() {
let res = DeviceInformation::find_all_async_aqs_filter(&wrong_deviceselector);
if let Err(e) = res {
println!("HRESULT (FindAllAsyncAqsFilter) = {:?}", e);
let mut error_info = {
let error_info = {
let mut res = ptr::null_mut();
assert_eq!(GetRestrictedErrorInfo(&mut res), S_OK);
ComPtr::wrap(res)
Expand Down
6 changes: 0 additions & 6 deletions examples/toast_notify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,6 @@ use winrt::windows::data::xml::dom::*;
use winrt::windows::ui::notifications::*;

fn main() {
let rt = RuntimeContext::init();
run();
rt.uninit();
}

fn run() {
// Get a toast XML template
let toast_xml = ToastNotificationManager::get_template_content(ToastTemplateType::ToastText02).unwrap().unwrap();

Expand Down
1 change: 0 additions & 1 deletion src/comptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@ impl<T> ComPtr<T> {
/// use winrt::*;
/// use winrt::windows::foundation::Uri;
///
/// # let rt = winrt::RuntimeContext::init();
/// let uri = FastHString::new("https://www.rust-lang.org");
/// let uri = Uri::create_uri(&uri).unwrap();
/// assert_eq!("Windows.Foundation.Uri", uri.get_runtime_class_name().to_string());
Expand Down
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
//! use winrt::windows::system::diagnostics::*; // import namespace Windows.System.Diagnostics
//!
//! fn main() {
//! let rt = RuntimeContext::init(); // initialize the Windows Runtime
//! let infos = ProcessDiagnosticInfo::get_for_processes().unwrap().unwrap();
//! println!("Currently executed processes ({}):", infos.get_size().unwrap());
//! for p in &infos {
Expand Down Expand Up @@ -66,7 +65,8 @@ pub use cominterfaces::{ComInterface, ComIid, IUnknown, IRestrictedErrorInfo, IA
mod rt;
pub use rt::{RtInterface, RtClassInterface, RtNamedClass, RtValueType, RtType, RtActivatable,
RtDefaultConstructible, IInspectable, IInspectableVtbl, IActivationFactory,
IMemoryBufferByteAccess, Char, RuntimeContext, IteratorAdaptor};
IMemoryBufferByteAccess, Char, IteratorAdaptor,
ApartmentType, init_apartment, uninit_apartment};
pub use rt::async::{RtAsyncAction, RtAsyncOperation};

mod result;
Expand Down
63 changes: 31 additions & 32 deletions src/rt/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use std::marker::PhantomData;
use std::ptr;

use super::{ComInterface, HString, HStringReference, HStringArg, ComPtr, ComArray, ComIid, Guid};
Expand All @@ -9,7 +8,8 @@ use w::shared::winerror::{S_OK, S_FALSE, CO_E_NOTINITIALIZED, REGDB_E_CLASSNOTRE
use w::shared::guiddef::IID;
use w::um::unknwnbase::IUnknownVtbl;
use w::winrt::hstring::HSTRING;
use w::winrt::roapi::{RO_INIT_MULTITHREADED, RoInitialize, RoUninitialize, RoGetActivationFactory};
use w::winrt::roapi::{RO_INIT_MULTITHREADED, RO_INIT_SINGLETHREADED, RoInitialize, RoUninitialize, RoGetActivationFactory};
use w::um::combaseapi::CoIncrementMTAUsage;

use self::gen::windows::foundation::collections::{
IIterable,
Expand Down Expand Up @@ -116,11 +116,14 @@ pub trait RtActivatable<Interface> : RtNamedClass {
fn get_activation_factory() -> ComPtr<Interface> where Interface: RtInterface + ComIid {
let mut res = ptr::null_mut();
let class_id = unsafe { HStringReference::from_utf16_unchecked(Self::name()) };
let hr = unsafe { RoGetActivationFactory(class_id.get(), <Interface as ComIid>::iid().as_ref(), &mut res as *mut *mut _ as *mut *mut VOID) };
let mut hr = unsafe { RoGetActivationFactory(class_id.get(), <Interface as ComIid>::iid().as_ref(), &mut res as *mut *mut _ as *mut *mut VOID) };
if hr == CO_E_NOTINITIALIZED {
let mut cookie = ptr::null_mut();
unsafe { CoIncrementMTAUsage(&mut cookie); }
hr = unsafe { RoGetActivationFactory(class_id.get(), <Interface as ComIid>::iid().as_ref(), &mut res as *mut *mut _ as *mut *mut VOID) };
}
if hr == S_OK {
unsafe { ComPtr::wrap(res) }
} else if hr == CO_E_NOTINITIALIZED {
panic!("WinRT is not initialized")
} else if hr == REGDB_E_CLASSNOTREG {
let name = Self::name();
panic!("WinRT class \"{}\" not registered", String::from_utf16_lossy(&name[0..name.len()-1]))
Expand Down Expand Up @@ -779,35 +782,31 @@ impl IMemoryBufferByteAccess {
}
}


/// Manages initialization and uninitialization of the Windows Runtime.
pub struct RuntimeContext {
token: PhantomData<*mut ()> // only allow construction from inside this module, and make it !Send/!Sync.
/// Determines the concurrency model used for incoming calls to the objects created by a thread
/// that was initialized with a given apartment type (see also `init_apartment`).
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[repr(u32)]
pub enum ApartmentType {
/// Initializes the thread in the multi-threaded apartment (MTA).
MTA = RO_INIT_MULTITHREADED,

/// Initializes the thread as a single-threaded apartment (STA).
STA = RO_INIT_SINGLETHREADED
}

impl RuntimeContext {
/// Initializes the Windows Runtime. This must be called before any other operations can use
/// the Windows Runtime. The Windows Runtime will be unitilized when the returned `RuntimeContext`
/// is dropped or `uninit` is called explicitly. You have to make sure that this does not happen
/// as long as any Windows Runtime object is still alive.
#[inline]
pub fn init() -> RuntimeContext {
let hr = unsafe { RoInitialize(RO_INIT_MULTITHREADED) };
assert!(hr == S_OK || hr == S_FALSE, "failed to call RoInitialize: error {}", hr);
RuntimeContext { token: PhantomData }
}

/// Unitializes the Windows Runtime. This must not be called as long as any Windows Runtime
/// object is still alive.
#[inline]
pub fn uninit(self) {
drop(self);
}
/// Initializes the current thread for use with the Windows Runtime. This is usually not needed,
/// because winrt-rust ensures that threads are implicitly assigned to the multi-threaded apartment (MTA).
/// However, if you need your thread to be initialized as a single-threaded apartment (STA), you can
/// call `init_apartment(ApartmentType::STA)`. Only call this when you own the thread!
pub fn init_apartment(apartment_type: ApartmentType) {
let hr = unsafe { RoInitialize(apartment_type as u32) };
assert!(hr == S_OK || hr == S_FALSE, "failed to call RoInitialize: error {}", hr);
}

impl Drop for RuntimeContext {
#[inline]
fn drop(&mut self) {
unsafe { RoUninitialize() };
}
/// Uninitializes the Windows Runtime in the current thread. This is usually not
/// needed, because uninitialization happens automatically on process termination.
/// Make sure that you never call this from a thread that still has references to
/// Windows Runtime objects.
pub fn uninit_apartment() {
unsafe { RoUninitialize() };
}