let installed_apps = platform::list_installed_apps();
let running_apps_offset = installed_apps.len();
let mut incorporable_apps = Self {
inner: installed_apps,
running_apps_offset
};
// SAFETY: The mutable reference to `incorporable_apps` is created inside the function argument,
// therefore it gets moved into the function.
unsafe {
platform::list_running_apps(&mut incorporable_apps);
}
incorporable_apps.inner.shrink_to_fit();
incorporable_apps
// SAFETY: `incorporable_apps` (the mutable reference) must be moved into the function when called,
// and not be reborrowed.
pub unsafe fn list_running_apps(incorporable_apps: &mut IncorporableApps) {
// SAFETY: `lparam` is &mut IncorporableApps casted to LPARAM according to `enum_windows_proc`
// safety requirement. Since `incorporable_apps` is invalid after calling EnumWindows,
// we call drop on it beforehand
let res = unsafe {
let lparam = LPARAM(incorporable_apps as *mut _ as isize);
drop(incorporable_apps);
EnumWindows(Some(enum_windows_proc), lparam)
};
}
// SAFETY: `lparam` must be a valid &mut IncorporableApps casted to a LPARAM
// according to the following process:
// &mut IncorporableApps -> *mut IncorporableApps -> isize -> LPARAM(isize)
unsafe extern "system" fn enum_windows_proc(hwnd: HWND, lparam: LPARAM) -> BOOL {
let skip = BOOL(1);
if !is_window_visible(hwnd) {
return skip;
}
// SAFETY: `lparam` must be a valid &mut IncorporableApps casted to a LPARAM as remarked
let incorporable_apps = unsafe {
&mut *(lparam.0 as *mut IncorporableApps)
};
let exe_path = unsafe {
let mut pid = 0u32;
let is_err = GetWindowThreadProcessId(hwnd, Some(&mut pid)) == 0;
if is_err {
eprintln!("Error getting PID: {}", WinError::from_thread());
return skip;
}
let process_handle = match OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, false, pid) {
Ok(process_handle) => process_handle,
Err(err) => {
eprintln!("Error getting process handle: {err}");
return skip;
}
};
let mut exe_path_buf = [0u16; MAX_PATH as usize];
let mut path_len = exe_path_buf.len() as u32;
let res = {
let win32_path_format = PROCESS_NAME_FORMAT(0);
QueryFullProcessImageNameW(
process_handle, win32_path_format, PWSTR(exe_path_buf.as_mut_ptr()), &mut path_len
)
};
if let Err(err) = res {
eprintln!("Error querying process image name: {err}");
return skip
}
if let Err(err) = CloseHandle(process_handle) {
eprintln!("Error closing process handle: {err}");
return skip;
}
if exe_path_already_exists(incorporable_apps.running_apps(), &exe_path_buf, path_len as usize) {
return skip;
}
String::from_utf16_lossy(&exe_path_buf[..path_len as usize])
};
let name = get_file_elegant_name(exe_path.as_ref())
.expect("`exe_path` resolves to a executable file");
let icon = match fetch_icon_in_bytes2(exe_path.as_ref()) {
Ok(icon_in_bytes) => icon_in_bytes,
Err(err) => {
eprintln!("Error getting icon from lnk;\nPath to lnk: {exe_path:?};\nErr: {err:?}");
return skip;
}
};
let app = App::from(name, exe_path, icon);
let incorporable_app = IncorporableApp::new_with(app);
incorporable_apps.inner.push(incorporable_app);
skip
}
Are the invariants stated by the function enough for soundness? And therefore is my code sound? Ignore the calls to Windows API functions (except EnumWindows)