You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Win10 Rust开发:如何获取启动可执行文件的链接所在目录

问题根因

env::current_dir()返回的是进程启动时的工作目录,和启动程序的快捷方式存储路径没有必然绑定关系:

  • Windows快捷方式(.lnk)自带独立的「起始位置」配置项,默认值为可执行文件自身所在目录,这就是你移动exe后,代码永远返回exe所在路径的直接原因
  • 系统默认不会把快捷方式自身的存储路径传给被启动的程序,标准库没有直接获取该路径的接口
可行方案

方案1:无需改代码(适配现有逻辑,成本最低)

不需要修改任何程序代码,对每个需要放置快捷方式的文件夹,右键对应快捷方式打开「属性」,清空「起始位置」输入框的所有内容后保存。

当快捷方式的「起始位置」为空时,Windows会自动将双击快捷方式启动程序的工作目录设置为.lnk文件自身所在的文件夹,你原有基于env::current_dir()的逻辑可以直接正常运行,不需要存放多份程序副本。

方案2:代码自动识别(无需手动修改快捷方式配置)

如果不想逐个调整快捷方式属性,可以通过Windows Shell API自动识别触发启动的快捷方式位置,实现逻辑如下:

  1. 先在Cargo.toml中添加Windows API依赖:
[dependencies.windows]
version = "0.48"
features = [
    "Win32_UI_Shell",
    "Win32_Foundation",
    "Win32_System_Com",
    "Win32_System_Threading",
]
  1. 实现路径获取逻辑,替换原有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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 23:36:21