use crate::ffi;
use crate::{Database, Error, Record, Result};
use std::ffi::CString;
#[repr(transparent)]
pub struct Session {
h: ffi::MSIHANDLE,
}
impl Session {
pub fn database(&self) -> Database {
unsafe {
let h = ffi::MsiGetActiveDatabase(self.h);
Database::from_handle(h)
}
}
pub fn do_action(&self, action: Option<&str>) -> Result<()> {
unsafe {
let action = match action {
Some(s) => CString::new(s)?,
None => CString::default(),
};
let ret = ffi::MsiDoAction(self.h, action.as_ptr());
if ret != ffi::ERROR_SUCCESS {
return Err(Error::from_error_code(ret));
}
Ok(())
}
}
pub fn do_deferred_action(&self, action: &str, custom_action_data: &str) -> Result<()> {
self.set_property(action, Some(custom_action_data))?;
self.do_action(Some(action))
}
pub fn language(&self) -> u16 {
unsafe { ffi::MsiGetLanguage(self.h) }
}
pub fn message(&self, kind: MessageType, record: &Record) -> i32 {
unsafe { ffi::MsiProcessMessage(self.h, kind, *record.h) }
}
pub fn mode(&self, mode: RunMode) -> bool {
unsafe { ffi::MsiGetMode(self.h, mode).as_bool() }
}
pub fn property(&self, name: &str) -> Result<String> {
unsafe {
let name = CString::new(name)?;
let mut value_len = 0u32;
let value = CString::default();
let mut ret = ffi::MsiGetProperty(
self.h,
name.as_ptr(),
value.as_ptr() as ffi::LPSTR,
&mut value_len as *mut u32,
);
if ret != ffi::ERROR_MORE_DATA {
return Err(Error::from_error_code(ret));
}
let mut value_len = value_len + 1u32;
let mut value: Vec<u8> = vec![0; value_len as usize];
ret = ffi::MsiGetProperty(
self.h,
name.as_ptr(),
value.as_mut_ptr() as ffi::LPSTR,
&mut value_len as *mut u32,
);
if ret != ffi::ERROR_SUCCESS {
return Err(Error::from_error_code(ret));
}
value.truncate(value_len as usize);
let text = String::from_utf8(value)?;
Ok(text)
}
}
pub fn set_property(&self, name: &str, value: Option<&str>) -> Result<()> {
unsafe {
let name = CString::new(name)?;
let value = match value {
Some(s) => CString::new(s)?,
None => CString::default(),
};
let ret = ffi::MsiSetProperty(
self.h,
name.as_ptr() as ffi::LPCSTR,
value.as_ptr() as ffi::LPCSTR,
);
if ret != ffi::ERROR_SUCCESS {
return Err(Error::from_error_code(ret));
}
Ok(())
}
}
}
#[repr(u32)]
pub enum MessageType {
Error = 0x0100_0000,
Warning = 0x0200_0000,
User = 0x0300_0000,
Info = 0x0400_0000,
Progress = 0x0a00_0000,
CommonData = 0x0b00_0000,
}
#[repr(u32)]
pub enum RunMode {
Admin = 0,
Advertise = 1,
Maintenance = 2,
RollbackEnabled = 3,
LogEnabled = 4,
Operations = 5,
RebootAtEnd = 6,
RebootNow = 7,
Cabinet = 8,
SourceShortNames = 9,
TargetShortNames = 10,
Windows9x = 12,
ZawEnabled = 13,
Scheduled = 16,
Rollback = 17,
Commit = 18,
}