获取快捷方式文件夹的目标路径

24

如何获取快捷方式文件夹的目录路径?我已经到处搜索,只找到了快捷方式文件的目标路径。


1
这与WPF无关,我已经删除了标签。 - Felice Pollano
1
这是我喜欢的解决方案:如何从文件快捷方式获取路径名? - ilcorvo
9个回答

32

我认为你需要使用COM并添加对“Microsoft Shell Control And Automation”的引用,如这篇博客文章所述:

以下是使用该代码提供的示例:

namespace Shortcut
{
    using System;
    using System.Diagnostics;
    using System.IO;
    using Shell32;

    class Program
    {
        public static string GetShortcutTargetFile(string shortcutFilename)
        {
            string pathOnly = System.IO.Path.GetDirectoryName(shortcutFilename);
            string filenameOnly = System.IO.Path.GetFileName(shortcutFilename);

            Shell shell = new Shell();
            Folder folder = shell.NameSpace(pathOnly);
            FolderItem folderItem = folder.ParseName(filenameOnly);
            if (folderItem != null)
            {
                Shell32.ShellLinkObject link = (Shell32.ShellLinkObject)folderItem.GetLink;
                return link.Path;
            }

            return string.Empty;
        }

        static void Main(string[] args)
        {
            const string path = @"C:\link to foobar.lnk";
            Console.WriteLine(GetShortcutTargetFile(path));
        }
    }
}

谢谢!现在我只需要找出如何以编程方式查找快捷方式文件夹 :) - Phu Minh Pham
3
我在使用 Windows 7 64位系统,在查找安装在 C:\Program Files\Oracle\VirtualBoxOSX 的 VirtualBox 快捷方式时失败了。它一直返回目标位置为 C:\Program Files (x86)\Oracle\VirtualBoxOSX\VirtualBox.exe。对此行为有何解释? - swdev
2
使用此方法与Shell32只允许在单线程应用程序中使用。您必须在主入口点中包含[STAThread]。使用此代码进行单元测试会导致异常,因为单元测试不允许STAThread。请参见答案。还有一种解决方案可以在单元测试中运行此代码,请参见http://haacked.com/archive/2014/11/20/xunit-and-sta/。 - yancyn

7
在Windows 10中,需要按照以下步骤进行操作:首先将COM引用添加到“Microsoft Shell Control And Automation”中。
// new way for windows 10
string targetname;
string pathOnly = System.IO.Path.GetDirectoryName(LnkFileName);
string filenameOnly = System.IO.Path.GetFileName(LnkFileName);

Shell shell = new Shell();
Shell32.Folder folder = shell.NameSpace(pathOnly);
FolderItem folderItem = folder.ParseName(filenameOnly);
if (folderItem != null) {
  Shell32.ShellLinkObject link = (Shell32.ShellLinkObject)folderItem.GetLink;
  targetname = link.Target.Path;  // <-- main difference
  if (targetname.StartsWith("{")) { // it is prefixed with {54A35DE2-guid-for-program-files-x86-QZ32BP4}
    int endguid = targetname.IndexOf("}");
    if (endguid > 0) {
      targetname = "C:\\program files (x86)" + targetname.Substring(endguid + 1);
  }
}

Windows 10是一坨垃圾。这可能就是为什么在Windows 10上链接出现那么多问题的原因。 - jeffld
@EJThayer 你使用的是哪个Win 10版本? - Grace

4

0
public static string GetLnkTarget(string lnkPath)
{
    var shl = new Shell();
    var dir = shl.NameSpace(Path.GetDirectoryName(lnkPath));
    var itm = dir.Items().Item(Path.GetFileName(lnkPath));
    var lnk = (ShellLinkObject)itm.GetLink;

    if (!File.Exists(lnk.Path)){
       return lnk.Path.Replace("Program Files (x86)", "Program Files");
    }
    else{
       return lnk.Path;
    }
}

请解释您的解决方案。仅包含代码而没有解释的答案将被标记为低质量。 - cursorrux
请添加更多细节以扩展您的答案,例如工作代码或文档引用。 - Community

0

获取链接路径的更简单的方法是:

private static string LnkToFile(string fileLink)
{
    string link = File.ReadAllText(fileLink);
    int i1 = link.IndexOf("DATA\0");
    if (i1 < 0)
        return null;
    i1 += 5;
    int i2 = link.IndexOf("\0", i1);
    if (i2 < 0)
        return link.Substring(i1);
    else
        return link.Substring(i1, i2 - i1);
}

但是如果lnk文件格式发生变化,它肯定会出现故障。


1
这仅适用于琐碎的 *.lnk 文件 - 它不适用于由 Windows Installer 创建的 *.lnk 文件(它们无论如何都不指向文件),以及某些其他类型的 *.lnk 文件,这些文件不将路径存储为单个字符串 - 不幸的是,二进制文件格式有点复杂:https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-shllink/16cb4ca1-9339-4d0c-a68d-bf1d6cc0f943 - Dai
在我的情况下没有起作用,该函数已经在我的.lnk文件上返回了null。 - Zyo
我觉得.lnk格式已经改变了,我再也找不到lnk文件里面的"DATA"关键字了。唯一有效的解决办法是使用Shell.Application辅助对象,它了解这些讨厌的lnk文件的所有内部格式细节。 - undefined

0
我一直使用这个,基于内置的Windows "Shell.Application" COM对象,但是使用纯粹的后期绑定和反射来实现,因此不需要添加对现有项目的引用,也没有任何依赖关系。
    public static string GetLnkTarget(string lnkPath)
    {
        if (!System.IO.File.Exists(lnkPath))
            throw new FileNotFoundException();

        Type shlType;
        object shl = null;
        object dir = null;
        object items = null;
        object itm = null;
        object lnk = null;

        try
        {
            //var shl = new Shell();
            shlType = Type.GetTypeFromProgID("Shell.Application");
            shl = Activator.CreateInstance(shlType);

            string dirName = Path.GetDirectoryName(lnkPath);
            string lnkFile = Path.GetFileName(lnkPath);

            //var dir = shl.NameSpace(dirName);
            dir = shlType.InvokeMember("NameSpace", System.Reflection.BindingFlags.InvokeMethod, null, shl, new object[] { dirName });

            //var itm = dir.Items().Item(lnkFile);
            items = dir.GetType().InvokeMember("Items", System.Reflection.BindingFlags.InvokeMethod, null, dir, null);
            itm = items.GetType().InvokeMember("Item", System.Reflection.BindingFlags.InvokeMethod, null, items, new object[] { lnkFile });

            //var lnk = (ShellLinkObject)itm.GetLink;
            lnk = itm.GetType().InvokeMember("GetLink", System.Reflection.BindingFlags.GetProperty, null, itm, null);

            //return lnk.Path;
            object path = lnk.GetType().InvokeMember("Path", System.Reflection.BindingFlags.GetProperty, null, lnk, null);
            return (string)path;
        }
        catch (Exception ex)
        {
            throw ex;
        }
        finally
        {
            if (lnk != null) Marshal.ReleaseComObject(lnk);
            if (itm != null) Marshal.ReleaseComObject(itm);
            if (items != null) Marshal.ReleaseComObject(items);
            if (dir != null) Marshal.ReleaseComObject(dir);
            if (shl != null) Marshal.ReleaseComObject(shl);
        }
    }

-1

感谢Mohsen.Sharify的回答,我得到了更整洁的代码:

var fileName = Process.GetCurrentProcess().MainModule.FileName;
var folderName = Path.Combine(fileName, ".."); //origin folder

这并不是直接回答问题,而只是一种获取当前运行可执行文件所在文件夹的方法,我想。 - peSHIr

-2
如果你想找到桌面上的应用程序快捷方式的路径,我使用的一个简单方法是以下内容:
Process.GetCurrentProcess().MainModule.FileName.Substring(0, Process.GetCurrentProcess().MainModule.FileName.LastIndexOf("\\")

这段代码返回正在运行的任何exe路径,不管是谁请求的文件


这并不是一个确切的答案。 - peSHIr

-4
所有文件的快捷方式都有一个 .lnk 文件扩展名,您可以进行检查。例如,您可以使用字符串 string.EndsWith(".lnk") 作为过滤器。
所有 URL 快捷方式都有一个 .url 文件扩展名,因此如果需要,您也需要考虑这些。

2
OP 问如何获取快捷方式的目标目录,而不是如何检查它是否为快捷方式。 - user1618054

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接