1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
use windows_sys::Win32::Foundation::HWND;
use windows_sys::core::{GUID, HRESULT};
use windows_sys::Win32::System::Com::{CoCreateInstance, CLSCTX_ALL};
use windows_sys::Win32::UI::Shell::{
TaskbarList, TBPFLAG, TBPF_NOPROGRESS, TBPF_INDETERMINATE, TBPF_NORMAL, TBPF_ERROR, TBPF_PAUSED
};
type BOOL = i32;
// Manual definition of ITaskbarList3 since it's missing in windows-sys
#[repr(C)]
pub struct ITaskbarList3 {
pub lp_vtbl: *const ITaskbarList3Vtbl,
}
#[repr(C)]
pub struct ITaskbarList3Vtbl {
pub query_interface: unsafe extern "system" fn(*mut ITaskbarList3, *const GUID, *mut *mut std::ffi::c_void) -> HRESULT,
pub add_ref: unsafe extern "system" fn(*mut ITaskbarList3) -> u32,
pub release: unsafe extern "system" fn(*mut ITaskbarList3) -> u32,
pub hr_init: unsafe extern "system" fn(*mut ITaskbarList3) -> HRESULT,
pub add_tab: unsafe extern "system" fn(*mut ITaskbarList3, HWND) -> HRESULT,
pub delete_tab: unsafe extern "system" fn(*mut ITaskbarList3, HWND) -> HRESULT,
pub activate_tab: unsafe extern "system" fn(*mut ITaskbarList3, HWND) -> HRESULT,
pub set_active_alt: unsafe extern "system" fn(*mut ITaskbarList3, HWND) -> HRESULT,
pub mark_fullscreen_window: unsafe extern "system" fn(*mut ITaskbarList3, HWND, BOOL) -> HRESULT,
pub set_progress_value: unsafe extern "system" fn(*mut ITaskbarList3, HWND, u64, u64) -> HRESULT,
pub set_progress_state: unsafe extern "system" fn(*mut ITaskbarList3, HWND, TBPFLAG) -> HRESULT,
// We don't need the rest of the methods for this app
}
const IID_ITASKBAR_LIST3: GUID = GUID {
data1: 0xea1afb91,
data2: 0x9e28,
data3: 0x4b86,
data4: [0x90, 0xe9, 0x9e, 0x9f, 0x8a, 0x5e, 0xef, 0xaf],
};
pub enum TaskbarState {
NoProgress,
Indeterminate,
Normal,
Error,
Paused,
}
pub struct TaskbarProgress {
hwnd: HWND,
taskbar_list: *mut ITaskbarList3,
}
impl TaskbarProgress {
pub fn new(hwnd: HWND) -> Self {
let mut taskbar_list: *mut ITaskbarList3 = std::ptr::null_mut();
unsafe {
// Ensure COM is initialized (though main thread should have done it)
// We don't want to re-init if already done, but CoCreateInstance requires it.
// Main.rs does CoInitializeEx.
let hr = CoCreateInstance(
&TaskbarList,
std::ptr::null_mut(),
CLSCTX_ALL,
&IID_ITASKBAR_LIST3,
&mut taskbar_list as *mut _ as *mut _
);
if hr != 0 {
// Failed
taskbar_list = std::ptr::null_mut();
}
}
Self {
hwnd,
taskbar_list,
}
}
pub fn set_state(&self, state: TaskbarState) {
if !self.taskbar_list.is_null() {
let flags: TBPFLAG = match state {
TaskbarState::NoProgress => TBPF_NOPROGRESS,
TaskbarState::Indeterminate => TBPF_INDETERMINATE,
TaskbarState::Normal => TBPF_NORMAL,
TaskbarState::Error => TBPF_ERROR,
TaskbarState::Paused => TBPF_PAUSED,
};
unsafe {
let vtbl = (*self.taskbar_list).lp_vtbl;
// SetProgressState is the 10th method in ITaskbarList3?
// ITaskbarList (3) -> ITaskbarList2 (1) -> ITaskbarList3 (SetProgressState is offset?)
// Actually windows-sys defines the Vtbl struct:
// IUnknown: QueryInterface, AddRef, Release
// ITaskbarList: HrInit, AddTab, DeleteTab, ActivateTab, SetActiveAlt
// ITaskbarList2: MarkFullscreenWindow
// ITaskbarList3: SetProgressValue, SetProgressState, RegisterTab, UnregisterTab, SetTabOrder, SetTabActive, ThumbBarAddButtons, ThumbBarUpdateButtons, ThumbBarSetImageList, SetOverlayIcon, SetThumbnailTooltip, SetThumbnailClip
// layout:
// 0: QueryInterface
// 1: AddRef
// 2: Release
// 3: HrInit
// 4: AddTab
// 5: DeleteTab
// 6: ActivateTab
// 7: SetActiveAlt
// 8: MarkFullscreenWindow
// 9: SetProgressValue
// 10: SetProgressState
// Call set_progress_state(hwnd, flags)
((*vtbl).set_progress_state)(self.taskbar_list, self.hwnd, flags);
}
}
}
pub fn set_value(&self, completed: u64, total: u64) {
if !self.taskbar_list.is_null() {
unsafe {
let vtbl = (*self.taskbar_list).lp_vtbl;
// Call set_progress_value(hwnd, completed, total)
((*vtbl).set_progress_value)(self.taskbar_list, self.hwnd, completed, total);
}
}
}
}
impl Drop for TaskbarProgress {
fn drop(&mut self) {
if !self.taskbar_list.is_null() {
unsafe {
let vtbl = (*self.taskbar_list).lp_vtbl;
((*vtbl).release)(self.taskbar_list);
}
}
}
}