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

Support creating apartment when constructing #7

Merged
merged 2 commits into from Jan 14, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 3 additions & 9 deletions src/bin/vswhere/main.rs
Expand Up @@ -7,21 +7,15 @@ extern crate clap;
use clap::{crate_version, App, Arg, ArgMatches};

extern crate vssetup;
use vssetup::{Result, SetupConfiguration};

extern crate com;
use com::runtime::{ApartmentRuntime, ApartmentType};
use vssetup::{ApartmentType, Result, SetupConfiguration};

mod formatter;

fn main() -> Result<()> {
let opts = parse();
let _apartment = ApartmentRuntime::new(ApartmentType::SingleThreaded)?;

let config = SetupConfiguration::new();
if let Some(e) = config.instances(opts.all) {
formatter::print_instances(e)?;
}
let config = SetupConfiguration::with_apartment(ApartmentType::SingleThreaded)?;
formatter::print_instances(config.instances(opts.all)?)?;

Ok(())
}
Expand Down
59 changes: 53 additions & 6 deletions src/errors.rs
Expand Up @@ -7,9 +7,14 @@ use windows::core;

pub type Result<T> = std::result::Result<T, SetupConfigurationError>;

#[derive(Debug)]
pub(crate) const CO_E_DLLNOTFOUND: u32 = 0x8004_01F8;
pub(crate) const E_NOTIMPL: u32 = 0x8000_4001;
pub(crate) const REGDB_E_CLASSNOTREG: u32 = 0x8004_0154;

#[derive(Debug, PartialEq)]
pub enum SetupConfigurationError {
NotInstalled,
NotImplemented,
COM { err: core::Error },
}

Expand All @@ -19,6 +24,9 @@ impl fmt::Display for SetupConfigurationError {
SetupConfigurationError::NotInstalled => {
write!(f, "setup configuration module is not installed")
}
SetupConfigurationError::NotImplemented => {
write!(f, "not implemented")
}
SetupConfigurationError::COM { err } => err.fmt(f),
}
}
Expand All @@ -28,30 +36,40 @@ impl error::Error for SetupConfigurationError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match *self {
SetupConfigurationError::NotInstalled => None,
SetupConfigurationError::NotImplemented => None,
SetupConfigurationError::COM { ref err } => Some(err),
}
}
}

impl From<core::Error> for SetupConfigurationError {
fn from(err: core::Error) -> Self {
SetupConfigurationError::COM { err }
match err.code().0 {
E_NOTIMPL => SetupConfigurationError::NotImplemented,
_ => SetupConfigurationError::COM { err },
}
}
}

impl From<com::sys::HRESULT> for SetupConfigurationError {
fn from(hr: com::sys::HRESULT) -> Self {
let _hr = core::HRESULT(hr as u32);
SetupConfigurationError::COM {
err: core::Error::from(_hr),
match _hr.0 {
E_NOTIMPL => SetupConfigurationError::NotImplemented,
_ => SetupConfigurationError::COM {
err: core::Error::from(_hr),
},
}
}
}

impl From<core::HRESULT> for SetupConfigurationError {
fn from(hr: core::HRESULT) -> Self {
SetupConfigurationError::COM {
err: core::Error::from(hr),
match hr.0 {
E_NOTIMPL => SetupConfigurationError::NotImplemented,
_ => SetupConfigurationError::COM {
err: core::Error::from(hr),
},
}
}
}
Expand All @@ -68,10 +86,39 @@ mod tests {
)
}

#[test]
fn notimplemented_fmt() {
assert_eq!(
"not implemented",
format!("{}", SetupConfigurationError::NotImplemented)
)
}

#[test]
#[cfg(windows)]
fn com_fmt() {
let err: SetupConfigurationError = core::HRESULT(0x80070490).into();
assert_ne!(0, format!("{}", err).len())
}

#[test]
fn from_error_notimplemented() {
let hr = core::HRESULT(E_NOTIMPL);
let err: SetupConfigurationError = core::Error::from(hr).into();
assert_eq!(SetupConfigurationError::NotImplemented, err)
}

#[test]
fn from_com_sys_hresult_notimplemented() {
let hr: com::sys::HRESULT = E_NOTIMPL as i32;
let err: SetupConfigurationError = hr.into();
assert_eq!(SetupConfigurationError::NotImplemented, err)
}

#[test]
fn from_core_hresult_notimplemented() {
let hr = core::HRESULT(E_NOTIMPL);
let err: SetupConfigurationError = hr.into();
assert_eq!(SetupConfigurationError::NotImplemented, err)
}
}
92 changes: 92 additions & 0 deletions src/instance.rs
@@ -0,0 +1,92 @@
// Copyright 2020 Heath Stewart.
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.

use windows::Win32::{
Foundation::{BSTR, FILETIME, SYSTEMTIME},
System::Time::FileTimeToSystemTime,
};

use chrono::{DateTime, TimeZone, Utc};

use crate::errors::*;
use crate::interfaces::ISetupInstance;

pub struct SetupInstance {
pub(crate) instance: ISetupInstance,
}

impl SetupInstance {
pub fn instance_id(&self) -> Result<String> {
let mut bstr = BSTR::default();
unsafe {
self.instance.GetInstanceId(&mut bstr).ok()?;
}

Ok(bstr.to_string())
}

pub fn install_date(&self) -> Result<DateTime<Utc>> {
let mut ft = FILETIME::default();
let mut st = SYSTEMTIME::default();
unsafe {
self.instance.GetInstallDate(&mut ft).ok()?;
FileTimeToSystemTime(&ft, &mut st).ok()?;
}

let dt = Utc
.ymd(st.wYear.into(), st.wMonth.into(), st.wDay.into())
.and_hms_milli(
st.wHour.into(),
st.wMinute.into(),
st.wSecond.into(),
st.wMilliseconds.into(),
);

Ok(dt)
}

pub fn installation_name(&self) -> Result<String> {
let mut bstr = BSTR::default();
unsafe {
self.instance.GetInstallationName(&mut bstr).ok()?;
}

Ok(bstr.to_string())
}

pub fn installation_path(&self) -> Result<String> {
let mut bstr = BSTR::default();
unsafe {
self.instance.GetInstallationPath(&mut bstr).ok()?;
}

Ok(bstr.to_string())
}

pub fn installation_version(&self) -> Result<String> {
let mut bstr = BSTR::default();
unsafe {
self.instance.GetInstallationVersion(&mut bstr).ok()?;
}

Ok(bstr.to_string())
}

pub fn display_name(&self, lcid: u32) -> Result<String> {
let mut bstr = BSTR::default();
unsafe {
self.instance.GetDisplayName(lcid, &mut bstr).ok()?;
}

Ok(bstr.to_string())
}

pub fn description(&self, lcid: u32) -> Result<String> {
let mut bstr = BSTR::default();
unsafe {
self.instance.GetDescription(lcid, &mut bstr).ok()?;
}

Ok(bstr.to_string())
}
}