This commit is contained in:
Joao Moreno 2018-01-17 12:02:47 +01:00
Родитель fac6ce8dd8
Коммит 351021a5b1
8 изменённых файлов: 256 добавлений и 7 удалений

Просмотреть файл

@ -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'

7
cargo-build.bat Normal file
Просмотреть файл

@ -0,0 +1,7 @@
@echo off
SET cargoargs=
IF "%~1"=="--release" SET cargoargs=--release
cargo build %cargoargs%
CALL .\enable-visual-styles.bat

7
cargo-run.bat Normal file
Просмотреть файл

@ -0,0 +1,7 @@
@echo off
SET target=debug
IF "%~1"=="--release" SET target=release
CALL .\cargo-build.bat %*
.\target\%target%\inno_updater.exe

6
enable-visual-styles.bat Normal file
Просмотреть файл

@ -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"

17
main.manifest Normal file
Просмотреть файл

@ -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>

186
src/gui.rs Normal file
Просмотреть файл

@ -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);
}
}
}

Просмотреть файл

@ -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);

Двоичные данные
tools/mt.exe Normal file

Двоичный файл не отображается.