revert winsafe (bugs)

This commit is contained in:
Caelan Sayler
2024-06-02 15:51:10 +01:00
parent bbda38c953
commit 173ef5ea12
5 changed files with 116 additions and 73 deletions

4
src/Rust/Cargo.lock generated
View File

@@ -2081,9 +2081,9 @@ dependencies = [
[[package]]
name = "winsafe"
version = "0.0.21"
version = "0.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c4afa7176f9fadc45817419f5fe481b9e8b90299c62af90e8c19486d0320274"
checksum = "a40369220be405a294b88b13ccc3d916fac12423250b30092c8c4ea19001f7f1"
[[package]]
name = "xml"

View File

@@ -89,8 +89,8 @@ libc = "0.2"
[target.'cfg(windows)'.dependencies]
fs_extra = "1.2"
memmap2 = "0.9"
winsafe = { version = "0.0.21", features = ["version", "user", "gui"] }
image = { version = "0.25.1", default-features = false, features = [
winsafe = { version = "0.0.20", features = ["version", "user", "gui"] }
image = { version = "0.25", default-features = false, features = [
"gif",
"jpeg",
"png",

View File

@@ -1,7 +1,7 @@
use super::{bundle::Manifest, dialogs_common::*, dialogs_const::*};
use anyhow::Result;
use std::path::PathBuf;
use winsafe::{self as w, co, prelude::*};
use winsafe::{self as w, co, prelude::*, WString};
pub fn show_restart_required(app: &Manifest) {
show_warn(
@@ -46,32 +46,32 @@ pub fn show_uninstall_complete_with_errors_dialog(app: &Manifest, log_path: Opti
return;
}
let setup_name = format!("{} Uninstall", app.title);
let instruction = format!("{} uninstall has completed with errors.", app.title);
let content =
"There may be left-over files or directories on your system. You can attempt to remove these manually or re-install the application and try again.";
let mut setup_name = WString::from_str(format!("{} Uninstall", app.title));
let mut instruction = WString::from_str(format!("{} uninstall has completed with errors.", app.title));
let mut content = WString::from_str(
"There may be left-over files or directories on your system. You can attempt to remove these manually or re-install the application and try again.",
);
let mut config: w::TASKDIALOGCONFIG = Default::default();
config.flags = co::TDF::ENABLE_HYPERLINKS | co::TDF::SIZE_TO_CONTENT;
config.common_buttons = co::TDCBF::OK;
config.main_icon = w::IconIdTd::Td(co::TD_ICON::WARNING);
config.window_title = Some(setup_name.as_str());
config.main_instruction = Some(instruction.as_str());
config.content = Some(content);
config.dwFlags = co::TDF::ENABLE_HYPERLINKS | co::TDF::SIZE_TO_CONTENT;
config.dwCommonButtons = co::TDCBF::OK;
config.set_pszMainIcon(w::IconIdTdicon::Tdicon(co::TD_ICON::WARNING));
config.set_pszWindowTitle(Some(&mut setup_name));
config.set_pszMainInstruction(Some(&mut instruction));
config.set_pszContent(Some(&mut content));
let footer_path = log_path.map(|p| p.to_string_lossy().to_string()).unwrap_or("".to_string());
let footer = format!("Log file: '<A HREF=\"na\">{}</A>'", footer_path);
let mut footer = WString::from_str(format!("Log file: '<A HREF=\"na\">{}</A>'", footer_path));
if let Some(log_path) = log_path {
if log_path.exists() {
config.footer_icon = w::IconId::Id(co::TD_ICON::INFORMATION.into());
config.footer_text = Some(footer.as_str());
config.callback_data = log_path as *const PathBuf as usize;
config.callback = Some(task_dialog_callback);
config.set_pszFooterIcon(w::IconId::Id(co::TD_ICON::INFORMATION.into()));
config.set_pszFooter(Some(&mut footer));
config.lpCallbackData = log_path as *const PathBuf as usize;
config.pfCallback = Some(task_dialog_callback);
}
}
let _ = w::TaskDialogIndirect(&config);
let _ = w::TaskDialogIndirect(&config, None);
}
pub fn show_overwrite_repair_dialog(app: &Manifest, root_path: &PathBuf, root_is_default: bool) -> bool {
@@ -81,50 +81,63 @@ pub fn show_overwrite_repair_dialog(app: &Manifest, root_path: &PathBuf, root_is
// these are the defaults, if we can't detect the current app version - we call it "Repair"
let mut config: w::TASKDIALOGCONFIG = Default::default();
config.main_icon = w::IconIdTd::Td(co::TD_ICON::WARNING);
config.set_pszMainIcon(w::IconIdTdicon::Tdicon(co::TD_ICON::WARNING));
let mut setup_name = format!("{} Setup {}", app.title, app.version);
let mut instruction = format!("{} is already installed.", app.title);
let mut content = "This application is installed on your computer. If it is not functioning correctly, you can attempt to repair it.".to_owned();
let mut btn_yes_txt = format!("Repair\nErase the application and re-install version {}.", app.version);
let btn_cancel_txt = "Cancel\nBackup or save your work first";
let mut setup_name = WString::from_str(format!("{} Setup {}", app.title, app.version));
let mut instruction = WString::from_str(format!("{} is already installed.", app.title));
let mut content = WString::from_str("This application is installed on your computer. If it is not functioning correctly, you can attempt to repair it.");
let mut btn_yes_txt = WString::from_str(format!("Repair\nErase the application and re-install version {}.", app.version));
let mut btn_cancel_txt = WString::from_str("Cancel\nBackup or save your work first");
// if we can detect the current app version, we call it "Update" or "Downgrade"
let possible_update = root_path.join("Update.exe");
let old_app = super::detect_manifest_from_update_path(&possible_update).map(|v| v.1).ok();
if let Some(old) = old_app {
if old.version < app.version {
instruction = format!("An older version of {} is installed.", app.title);
content = format!("Would you like to update from {} to {}?", old.version, app.version);
btn_yes_txt = format!("Update\nTo version {}", app.version);
config.main_icon = w::IconIdTd::Td(co::TD_ICON::INFORMATION);
instruction = WString::from_str(format!("An older version of {} is installed.", app.title));
content = WString::from_str(format!("Would you like to update from {} to {}?", old.version, app.version));
btn_yes_txt = WString::from_str(format!("Update\nTo version {}", app.version));
config.set_pszMainIcon(w::IconIdTdicon::Tdicon(co::TD_ICON::INFORMATION));
} else if old.version > app.version {
instruction = format!("A newer version of {} is installed.", app.title);
content = format!("You already have {} installed. Would you like to downgrade this application to an older version?", old.version);
btn_yes_txt = format!("Downgrade\nTo version {}", app.version);
instruction = WString::from_str(format!("A newer version of {} is installed.", app.title));
content = WString::from_str(format!(
"You already have {} installed. Would you like to downgrade this application to an older version?",
old.version
));
btn_yes_txt = WString::from_str(format!("Downgrade\nTo version {}", app.version));
}
}
let mut footer = if root_is_default {
format!("The install directory is '<A HREF=\"na\">%LocalAppData%\\{}</A>'", app.id)
WString::from_str(format!("The install directory is '<A HREF=\"na\">%LocalAppData%\\{}</A>'", app.id))
} else {
format!("The install directory is '<A HREF=\"na\">{}</A>'", root_path.display())
WString::from_str(format!("The install directory is '<A HREF=\"na\">{}</A>'", root_path.display()))
};
let btn_yes_txt = btn_yes_txt.as_str();
let buttons = [(co::DLGID::YES.into(), btn_yes_txt), (co::DLGID::CANCEL.into(), btn_cancel_txt)];
config.buttons = &buttons;
let mut btn_yes = w::TASKDIALOG_BUTTON::default();
btn_yes.set_nButtonID(co::DLGID::YES.into());
btn_yes.set_pszButtonText(Some(&mut btn_yes_txt));
config.flags = co::TDF::ENABLE_HYPERLINKS | co::TDF::USE_COMMAND_LINKS;
config.window_title = Some(&mut setup_name);
config.main_instruction = Some(&mut instruction);
config.content = Some(&mut content);
config.footer_icon = w::IconId::Id(co::TD_ICON::INFORMATION.into());
config.footer_text = Some(&mut footer);
config.callback_data = root_path as *const PathBuf as usize;
config.callback = Some(task_dialog_callback);
let mut btn_cancel = w::TASKDIALOG_BUTTON::default();
btn_cancel.set_nButtonID(co::DLGID::CANCEL.into());
btn_cancel.set_pszButtonText(Some(&mut btn_cancel_txt));
let (btn, _, _) = w::TaskDialogIndirect(&config).ok().unwrap_or_else(|| (co::DLGID::YES, 0, true));
let mut custom_btns = Vec::with_capacity(2);
custom_btns.push(btn_yes);
custom_btns.push(btn_cancel);
config.dwFlags = co::TDF::ENABLE_HYPERLINKS | co::TDF::USE_COMMAND_LINKS;
config.set_pButtons(Some(&mut custom_btns));
config.set_pszWindowTitle(Some(&mut setup_name));
config.set_pszMainInstruction(Some(&mut instruction));
config.set_pszContent(Some(&mut content));
config.set_pszFooterIcon(w::IconId::Id(co::TD_ICON::INFORMATION.into()));
config.set_pszFooter(Some(&mut footer));
config.lpCallbackData = root_path as *const PathBuf as usize;
config.pfCallback = Some(task_dialog_callback);
let (btn, _) = w::TaskDialogIndirect(&config, None).ok().unwrap_or_else(|| (co::DLGID::YES, 0));
return btn == co::DLGID::YES;
}
@@ -141,24 +154,40 @@ extern "system" fn task_dialog_callback(_: w::HWND, msg: co::TDN, _: usize, _: i
pub fn generate_confirm(title: &str, header: Option<&str>, body: &str, ok_text: Option<&str>, btns: DialogButton, ico: DialogIcon) -> Result<DialogResult> {
let hparent = w::HWND::GetDesktopWindow();
let hwnd = unsafe { hparent.raw_copy() };
let custom_btns: Vec<(u16, &str)> = if ok_text.is_some() { vec![(co::DLGID::OK.into(), ok_text.unwrap())] } else { vec![] };
let mut ok_text_buf = WString::from_opt_str(ok_text);
let mut custom_btns = if ok_text.is_some() {
let mut td_btn = w::TASKDIALOG_BUTTON::default();
td_btn.set_nButtonID(co::DLGID::OK.into());
td_btn.set_pszButtonText(Some(&mut ok_text_buf));
let mut custom_btns = Vec::with_capacity(1);
custom_btns.push(td_btn);
custom_btns
} else {
Vec::<w::TASKDIALOG_BUTTON>::default()
};
let mut tdc = w::TASKDIALOGCONFIG::default();
tdc.hwnd_parent = Some(&hwnd);
tdc.flags = co::TDF::ALLOW_DIALOG_CANCELLATION | co::TDF::POSITION_RELATIVE_TO_WINDOW;
tdc.common_buttons = btns.to_win();
tdc.main_icon = w::IconIdTd::Td(ico.to_win());
tdc.hwndParent = unsafe { hparent.raw_copy() };
tdc.dwFlags = co::TDF::ALLOW_DIALOG_CANCELLATION | co::TDF::POSITION_RELATIVE_TO_WINDOW;
tdc.dwCommonButtons = btns.to_win();
tdc.set_pszMainIcon(w::IconIdTdicon::Tdicon(ico.to_win()));
if ok_text.is_some() {
tdc.buttons = &custom_btns;
tdc.set_pButtons(Some(&mut custom_btns));
}
tdc.window_title = Some(title);
tdc.main_instruction = header;
tdc.content = Some(body);
let mut title_buf = WString::from_str(title);
tdc.set_pszWindowTitle(Some(&mut title_buf));
let result = w::TaskDialogIndirect(&tdc).map(|(dlg_id, _, _)| dlg_id)?;
let mut header_buf = WString::from_opt_str(header);
if header.is_some() {
tdc.set_pszMainInstruction(Some(&mut header_buf));
}
let mut body_buf = WString::from_str(body);
tdc.set_pszContent(Some(&mut body_buf));
let result = w::TaskDialogIndirect(&tdc, None).map(|(dlg_id, _)| dlg_id)?;
Ok(DialogResult::from_win(result))
}

View File

@@ -56,7 +56,11 @@ pub fn wait_for_parent_to_exit(ms_to_wait: u32) -> Result<()> {
}
fn get_pid_start_time(process: w::HPROCESS) -> Result<u64> {
let (creation, _, _, _) = process.GetProcessTimes()?;
let mut creation = w::FILETIME::default();
let mut exit = w::FILETIME::default();
let mut kernel = w::FILETIME::default();
let mut user = w::FILETIME::default();
process.GetProcessTimes(&mut creation, &mut exit, &mut kernel, &mut user)?;
Ok(((creation.dwHighDateTime as u64) << 32) | creation.dwLowDateTime as u64)
}

View File

@@ -8,10 +8,12 @@ use std::{
sync::mpsc::{self, Receiver, Sender},
thread,
};
use winsafe::{self as w, co, guard::DeleteObjectGuard, gui, msg, prelude::*};
use w::WString;
use winsafe::{self as w, co, guard::DeleteObjectGuard, gui, prelude::*};
const TMR_GIF: usize = 1;
const MSG_NOMESSAGE: i16 = -99;
pub const MSG_CLOSE: i16 = -1;
// pub const MSG_INDEFINITE: i16 = -2;
@@ -166,7 +168,7 @@ impl SplashWindow {
if msg == MSG_NOMESSAGE {
break;
} else if msg == MSG_CLOSE {
unsafe { self2.wnd.hwnd().SendMessage(msg::wm::Close {}) };
self2.wnd.hwnd().SendMessage(w::msg::wm::Close {});
return Ok(());
} else if msg >= 0 {
let mut p = self2.progress.borrow_mut();
@@ -289,14 +291,22 @@ pub struct ComCtlProgressWindow {
}
fn show_com_ctl_progress_dialog(rx: Receiver<i16>, window_title: &str, content: &str) {
let buttons = vec![(co::DLGID::OK.into(), "Hide")];
let mut window_title = WString::from_str(window_title);
let mut content = WString::from_str(content);
let mut ok_text_buf = WString::from_str("Hide");
let mut td_btn = w::TASKDIALOG_BUTTON::default();
td_btn.set_nButtonID(co::DLGID::OK.into());
td_btn.set_pszButtonText(Some(&mut ok_text_buf));
let mut custom_btns = Vec::with_capacity(1);
custom_btns.push(td_btn);
let mut config: w::TASKDIALOGCONFIG = Default::default();
config.flags = co::TDF::SIZE_TO_CONTENT | co::TDF::SHOW_PROGRESS_BAR | co::TDF::CALLBACK_TIMER;
config.main_icon = w::IconIdTd::Td(co::TD_ICON::INFORMATION);
config.window_title = Some(window_title);
config.main_instruction = Some(content);
config.buttons = &buttons;
config.dwFlags = co::TDF::SIZE_TO_CONTENT | co::TDF::SHOW_PROGRESS_BAR | co::TDF::CALLBACK_TIMER;
config.set_pszMainIcon(w::IconIdTdicon::Tdicon(co::TD_ICON::INFORMATION));
config.set_pszWindowTitle(Some(&mut window_title));
config.set_pszMainInstruction(Some(&mut content));
config.set_pButtons(Some(&mut custom_btns));
// if (_icon != null) {
// config.dwFlags |= TASKDIALOG_FLAGS.TDF_USE_HICON_MAIN;
@@ -304,10 +314,10 @@ fn show_com_ctl_progress_dialog(rx: Receiver<i16>, window_title: &str, content:
// }
let me = ComCtlProgressWindow { rx: Rc::new(rx) };
config.callback_data = &me as *const ComCtlProgressWindow as usize;
config.callback = Some(task_dialog_callback);
config.lpCallbackData = &me as *const ComCtlProgressWindow as usize;
config.pfCallback = Some(task_dialog_callback);
let _ = w::TaskDialogIndirect(&config);
let _ = w::TaskDialogIndirect(&config, None);
}
extern "system" fn task_dialog_callback(hwnd: w::HWND, msg: co::TDN, _: usize, _: isize, lp_ref_data: usize) -> co::HRESULT {
@@ -328,7 +338,7 @@ extern "system" fn task_dialog_callback(hwnd: w::HWND, msg: co::TDN, _: usize, _
}
}
if progress > 0 {
unsafe { hwnd.SendMessage(MsgSetProgressPos { pos: progress as usize }); }
hwnd.SendMessage(MsgSetProgressPos { pos: progress as usize });
}
}