enable gui
This commit is contained in:
Родитель
fac6ce8dd8
Коммит
351021a5b1
|
@ -11,6 +11,9 @@ crc = "^1.0.0"
|
|||
version = "^2.29.1"
|
||||
default-features = false
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
winapi = { version = "^0.3.3", features = ["winuser", "libloaderapi", "commctrl", "processthreadsapi"] }
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
panic = 'abort'
|
|
@ -0,0 +1,7 @@
|
|||
@echo off
|
||||
|
||||
SET cargoargs=
|
||||
IF "%~1"=="--release" SET cargoargs=--release
|
||||
|
||||
cargo build %cargoargs%
|
||||
CALL .\enable-visual-styles.bat
|
|
@ -0,0 +1,7 @@
|
|||
@echo off
|
||||
|
||||
SET target=debug
|
||||
IF "%~1"=="--release" SET target=release
|
||||
|
||||
CALL .\cargo-build.bat %*
|
||||
.\target\%target%\inno_updater.exe
|
|
@ -0,0 +1,6 @@
|
|||
@echo off
|
||||
|
||||
SET target=debug
|
||||
IF "%~1"=="--release" SET target=release
|
||||
|
||||
.\tools\mt.exe -nologo -manifest main.manifest -outputresource:"target\%target%\inno_updater.exe;#1"
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<assemblyIdentity version="1.0.0.0" processorArchitecture="*" name="Microsoft.VSCode.InnoUpdater" type="win32" />
|
||||
<description>VS Code update helper</description>
|
||||
<dependency>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity
|
||||
type="win32"
|
||||
name="Microsoft.Windows.Common-Controls"
|
||||
version="6.0.0.0"
|
||||
processorArchitecture="*"
|
||||
publicKeyToken="6595b64144ccf1df"
|
||||
language="*"
|
||||
/>
|
||||
</dependentAssembly>
|
||||
</dependency>
|
||||
</assembly>
|
|
@ -0,0 +1,186 @@
|
|||
use std::mem;
|
||||
use std::ptr;
|
||||
use winapi::shared::windef::HWND;
|
||||
use winapi::shared::minwindef::{DWORD, LPARAM, LRESULT, UINT, WPARAM};
|
||||
use winapi::um::libloaderapi::GetModuleHandleW;
|
||||
|
||||
fn utf16(value: &str) -> Vec<u16> {
|
||||
use std::ffi::OsStr;
|
||||
use std::os::windows::ffi::OsStrExt;
|
||||
use std::iter::once;
|
||||
|
||||
OsStr::new(value).encode_wide().chain(once(0u16)).collect()
|
||||
}
|
||||
|
||||
unsafe extern "system" fn wndproc(hwnd: HWND, msg: UINT, w: WPARAM, l: LPARAM) -> LRESULT {
|
||||
use winapi::um::winuser::{BeginPaint, DefWindowProcW, EndPaint, PostQuitMessage, PAINTSTRUCT,
|
||||
WM_DESTROY, WM_PAINT};
|
||||
use winapi::um::wingdi::{GetStockObject, SelectObject, SetBkMode, TextOutW, ANSI_VAR_FONT,
|
||||
TRANSPARENT};
|
||||
use winapi::ctypes::c_int;
|
||||
|
||||
match msg {
|
||||
WM_PAINT => {
|
||||
let mut ps = PAINTSTRUCT {
|
||||
hdc: mem::uninitialized(),
|
||||
fErase: 0,
|
||||
rcPaint: mem::uninitialized(),
|
||||
fRestore: 0,
|
||||
fIncUpdate: 0,
|
||||
rgbReserved: [0; 32],
|
||||
};
|
||||
|
||||
let hdc = BeginPaint(hwnd, &mut ps);
|
||||
SetBkMode(hdc, TRANSPARENT as c_int);
|
||||
|
||||
let font = GetStockObject(ANSI_VAR_FONT as c_int);
|
||||
SelectObject(hdc, font);
|
||||
|
||||
let text = utf16("Updating VS Code...");
|
||||
TextOutW(hdc, 15, 15, text.as_ptr(), text.len() as c_int);
|
||||
|
||||
EndPaint(hwnd, &ps);
|
||||
|
||||
0
|
||||
}
|
||||
WM_DESTROY => {
|
||||
PostQuitMessage(0);
|
||||
0
|
||||
}
|
||||
_ => DefWindowProcW(hwnd, msg, w, l),
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn create_window_class(name: *const u16) {
|
||||
use winapi::um::winuser::{LoadCursorW, RegisterClassExW, COLOR_WINDOW, CS_HREDRAW, CS_VREDRAW,
|
||||
IDC_ARROW, WNDCLASSEXW};
|
||||
|
||||
let class = WNDCLASSEXW {
|
||||
cbSize: mem::size_of::<WNDCLASSEXW>() as UINT,
|
||||
style: CS_HREDRAW | CS_VREDRAW,
|
||||
lpfnWndProc: Some(wndproc),
|
||||
cbClsExtra: 0,
|
||||
cbWndExtra: 0,
|
||||
hInstance: GetModuleHandleW(ptr::null_mut()),
|
||||
hIcon: ptr::null_mut(),
|
||||
hCursor: LoadCursorW(ptr::null_mut(), IDC_ARROW),
|
||||
hbrBackground: mem::transmute(COLOR_WINDOW as usize),
|
||||
lpszMenuName: ptr::null_mut(),
|
||||
lpszClassName: name,
|
||||
hIconSm: ptr::null_mut(),
|
||||
};
|
||||
|
||||
let result = RegisterClassExW(&class);
|
||||
|
||||
if result == 0 {
|
||||
panic!("Could not create window");
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ProgressWindow {
|
||||
ui_thread_id: DWORD,
|
||||
}
|
||||
|
||||
unsafe impl Send for ProgressWindow {}
|
||||
|
||||
impl ProgressWindow {
|
||||
pub fn exit(&self) {
|
||||
use winapi::um::winuser::{PostThreadMessageW, WM_QUIT};
|
||||
|
||||
unsafe {
|
||||
PostThreadMessageW(self.ui_thread_id, WM_QUIT, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_progress_window() -> ProgressWindow {
|
||||
use winapi::shared::windef::RECT;
|
||||
use winapi::um::winuser::{CreateWindowExW, GetClientRect, GetDesktopWindow, GetWindowRect,
|
||||
SendMessageW, SetWindowPos, ShowWindow, UpdateWindow, CW_USEDEFAULT,
|
||||
HWND_TOPMOST, SW_SHOW, WS_CAPTION, WS_CHILD, WS_EX_COMPOSITED,
|
||||
WS_OVERLAPPED, WS_VISIBLE};
|
||||
use winapi::um::processthreadsapi::GetCurrentThreadId;
|
||||
use winapi::um::commctrl::{PBM_SETMARQUEE, PBS_MARQUEE, PROGRESS_CLASS};
|
||||
|
||||
unsafe {
|
||||
let class_name = utf16("mainclass").as_ptr();
|
||||
create_window_class(class_name);
|
||||
|
||||
let width = 280;
|
||||
let height = 90;
|
||||
|
||||
let window = CreateWindowExW(
|
||||
WS_EX_COMPOSITED,
|
||||
class_name,
|
||||
utf16("VS Code").as_ptr(),
|
||||
WS_OVERLAPPED | WS_CAPTION,
|
||||
CW_USEDEFAULT,
|
||||
CW_USEDEFAULT,
|
||||
width,
|
||||
height,
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
GetModuleHandleW(ptr::null()),
|
||||
ptr::null_mut(),
|
||||
);
|
||||
|
||||
if window.is_null() {
|
||||
panic!("Could not create window");
|
||||
}
|
||||
|
||||
ShowWindow(window, SW_SHOW);
|
||||
UpdateWindow(window);
|
||||
|
||||
let mut rect: RECT = mem::uninitialized();
|
||||
GetClientRect(window, &mut rect);
|
||||
|
||||
let width = width + width - rect.right;
|
||||
let height = height + height - rect.bottom;
|
||||
|
||||
let desktop_window = GetDesktopWindow();
|
||||
GetWindowRect(desktop_window, &mut rect);
|
||||
|
||||
SetWindowPos(
|
||||
window,
|
||||
HWND_TOPMOST,
|
||||
rect.right / 2 - width / 2,
|
||||
rect.bottom / 2 - height / 2,
|
||||
width,
|
||||
height,
|
||||
0,
|
||||
);
|
||||
|
||||
let pbar = CreateWindowExW(
|
||||
0,
|
||||
utf16(PROGRESS_CLASS).as_ptr(),
|
||||
ptr::null(),
|
||||
WS_CHILD | WS_VISIBLE | PBS_MARQUEE,
|
||||
15,
|
||||
45,
|
||||
250,
|
||||
22,
|
||||
window,
|
||||
ptr::null_mut(),
|
||||
GetModuleHandleW(ptr::null()),
|
||||
ptr::null_mut(),
|
||||
);
|
||||
|
||||
SendMessageW(pbar, PBM_SETMARQUEE, 5, 0);
|
||||
|
||||
let ui_thread_id = GetCurrentThreadId();
|
||||
ProgressWindow { ui_thread_id }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn event_loop() {
|
||||
use winapi::um::winuser::{DispatchMessageW, GetMessageW, TranslateMessage, MSG};
|
||||
|
||||
unsafe {
|
||||
let mut msg: MSG = mem::uninitialized();
|
||||
|
||||
while GetMessageW(&mut msg, ptr::null_mut(), 0, 0) != 0 {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageW(&msg);
|
||||
}
|
||||
}
|
||||
}
|
37
src/main.rs
37
src/main.rs
|
@ -1,15 +1,17 @@
|
|||
// #![windows_subsystem = "windows"]
|
||||
|
||||
extern crate byteorder;
|
||||
extern crate clap;
|
||||
extern crate crc;
|
||||
extern crate winapi;
|
||||
|
||||
mod blockio;
|
||||
mod strings;
|
||||
mod model;
|
||||
mod gui;
|
||||
|
||||
use std::fs;
|
||||
use std::{env, fs, io, thread};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::io;
|
||||
use std::env;
|
||||
use std::io::prelude::*;
|
||||
use std::vec::Vec;
|
||||
use std::collections::HashMap;
|
||||
|
@ -156,12 +158,17 @@ fn move_update(uninstdat_path: &Path, update_folder_name: &str) -> Result<(), io
|
|||
fs::remove_dir_all(old_path)
|
||||
}
|
||||
|
||||
fn update(uninstdat_path: &Path, update_folder_name: &str, header: &Header, recs: Vec<FileRec>) {
|
||||
fn do_update(
|
||||
uninstdat_path: PathBuf,
|
||||
update_folder_name: String,
|
||||
header: Header,
|
||||
recs: Vec<FileRec>,
|
||||
) {
|
||||
let root_path = uninstdat_path.parent().expect("parent");
|
||||
let mut update_path = PathBuf::from(root_path);
|
||||
update_path.push(update_folder_name);
|
||||
update_path.push(&update_folder_name);
|
||||
|
||||
if let Err(err) = move_update(&uninstdat_path, update_folder_name) {
|
||||
if let Err(err) = move_update(&uninstdat_path, &update_folder_name) {
|
||||
println!("Failed to apply update: {:?}", err);
|
||||
return;
|
||||
}
|
||||
|
@ -179,6 +186,17 @@ fn update(uninstdat_path: &Path, update_folder_name: &str, header: &Header, recs
|
|||
write_file(&uninstdat_path, &header, recs);
|
||||
}
|
||||
|
||||
fn update(uninstdat_path: PathBuf, update_folder_name: String, header: Header, recs: Vec<FileRec>) {
|
||||
let window = gui::create_progress_window();
|
||||
|
||||
thread::spawn(move || {
|
||||
do_update(uninstdat_path, update_folder_name, header, recs);
|
||||
window.exit();
|
||||
});
|
||||
|
||||
gui::event_loop();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let app = App::new("VSCode Update Helper Tool")
|
||||
.version("1.0")
|
||||
|
@ -208,7 +226,12 @@ fn main() {
|
|||
let (header, recs) = read_file(&uninstdat_path);
|
||||
|
||||
match m.value_of("apply-update") {
|
||||
Some(name) => update(&uninstdat_path, name, &header, recs),
|
||||
Some(name) => update(
|
||||
PathBuf::from(uninstdat_path),
|
||||
String::from(name),
|
||||
header,
|
||||
recs,
|
||||
),
|
||||
_ => {
|
||||
println!("{:?}", header);
|
||||
print_statistics(&recs);
|
||||
|
|
Двоичный файл не отображается.
Загрузка…
Ссылка в новой задаче