Win10 Rust开发:如何获取启动可执行文件的链接所在目录
问题根因
env::current_dir()返回的是进程启动时的工作目录,和启动程序的快捷方式存储路径没有必然绑定关系:
- Windows快捷方式(.lnk)自带独立的「起始位置」配置项,默认值为可执行文件自身所在目录,这就是你移动exe后,代码永远返回exe所在路径的直接原因
- 系统默认不会把快捷方式自身的存储路径传给被启动的程序,标准库没有直接获取该路径的接口
可行方案
方案1:无需改代码(适配现有逻辑,成本最低)
不需要修改任何程序代码,对每个需要放置快捷方式的文件夹,右键对应快捷方式打开「属性」,清空「起始位置」输入框的所有内容后保存。
当快捷方式的「起始位置」为空时,Windows会自动将双击快捷方式启动程序的工作目录设置为.lnk文件自身所在的文件夹,你原有基于
env::current_dir()的逻辑可以直接正常运行,不需要存放多份程序副本。
方案2:代码自动识别(无需手动修改快捷方式配置)
如果不想逐个调整快捷方式属性,可以通过Windows Shell API自动识别触发启动的快捷方式位置,实现逻辑如下:
- 先在
Cargo.toml中添加Windows API依赖:
[dependencies.windows] version = "0.48" features = [ "Win32_UI_Shell", "Win32_Foundation", "Win32_System_Com", "Win32_System_Threading", ]
- 实现路径获取逻辑,替换原有
env::current_dir()调用即可:
use std::{env, io}; use windows::{ Win32::Foundation::*, Win32::System::Com::*, Win32::System::Threading::*, Win32::UI::Shell::*, }; fn get_shortcut_dir() -> io::Result<std::path::PathBuf> { unsafe { CoInitializeEx(None, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE) .ok() .map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?; // 获取当前运行的exe绝对路径 let mut exe_path_buf = [0u16; MAX_PATH as usize]; let exe_path_len = GetModuleFileNameW(None, &mut exe_path_buf); let current_exe = String::from_utf16_lossy(&exe_path_buf[..exe_path_len as usize]).to_ascii_lowercase(); // 遍历资源管理器窗口,查找选中的、目标为当前exe的快捷方式 let shell_windows: IShellWindows = CoCreateInstance(&ShellWindows, None, CLSCTX_ALL)?; let window_count = shell_windows.Count()?; for idx in 0..window_count { let dispatch = shell_windows.Item(idx as i32)?; let folder_view: IFolderView2 = dispatch.Document()?.cast()?; let selected_items = folder_view.SelectedItems(0)?; let sel_count = selected_items.Count()?; for sel_idx in 0..sel_count { let sel_dispatch = selected_items.Item(sel_idx as i32)?; let shell_item: IShellItem2 = sel_dispatch.cast()?; let lnk_path = shell_item.GetDisplayName(SIGDN_FILESYSPATH)?.to_string()?; if !lnk_path.to_ascii_lowercase().ends_with(".lnk") { continue; } // 解析快捷方式目标路径 let shell_link: IShellLinkW = CoCreateInstance(&ShellLink, None, CLSCTX_ALL)?; let persist_file: IPersistFile = shell_link.cast()?; persist_file.Load(&lnk_path, STGM_READ)?; let mut target_path_buf = [0u16; MAX_PATH as usize]; shell_link.GetPath(&mut target_path_buf, std::ptr::null_mut(), SLGP_UNCPRIORITY)?; let target_path = String::from_utf16_lossy(&target_path_buf.split(|&c| c == 0).next().unwrap_or(&[])) .to_ascii_lowercase(); if target_path == current_exe { return Ok(std::path::PathBuf::from(lnk_path).parent().unwrap().to_path_buf()); } } } // 未匹配到快捷方式时 fallback 到当前工作目录 env::current_dir() } }
该实现会自动识别双击启动当前程序的快捷方式位置,无论快捷方式的「起始位置」如何配置都能返回正确路径。
内容的提问来源于stack exchange,提问作者Mecki
相关产品推荐
相关产品推荐

