【问题标题】:ShellLink returning an old locationShellLink 返回旧位置
【发布时间】:2019-06-21 16:19:45
【问题描述】:

在 C# 程序中,我希望能够识别 LNK 文件的文件位置(实际文件位置,而不是 LNK 位置)。但有时 ShellLink 会返回文件的旧位置。例如,它返回“C:\Program Files (x86)\XXX\xxx.exe”而不是“C:\Program Files\XXX\xxx.exe”(LNK 文件中的实际文本)。 我认为旧位置可能缓存在注册表中,但找不到该字符串。 关于如何确保 ShellLink 识别正确位置或修复此特定“坏”链接的任何想法?我重新创建了链接并重新启动,但这没有帮助。

/// <summary>Given a LNK file, return the file that it points to.</summary>
public static string ResolveShortcut(string filename)
{
    ShellLink link = new ShellLink();
    ((IPersistFile)link).Load(filename, STGM_READ);
    StringBuilder sb = new StringBuilder(MAX_PATH);
    WIN32_FIND_DATAW data = new WIN32_FIND_DATAW();
    ((IShellLinkW)link).GetPath(sb, sb.Capacity, out data, 0);
    if (sb.Length == 0 && !filename.EndsWith(".LNK", StringComparison.OrdinalIgnoreCase)) sb.Append(filename);
    return sb.ToString();
}

【问题讨论】:

  • 你能贴出你用来从 ShellLink 拉取文件位置的代码吗?
  • 如果Program Files 的路径被环境变量(%programfiles%) 引用,则扩展变量(如Environment.ExpandEnvironmentVariables())会根据可执行文件的位数返回路径。即,如果您以 x86 为目标或选择了 Prefer 32-bit,则环境变量将返回 [Drive]:\Program Files (x86)
  • LNK 中的路径没有使用任何环境变量。这基本上就是我在问题中指定的内容。
  • this之类的东西验证物理内容。

标签: c# shell32 lnk


【解决方案1】:

在 cmets 中,Jimi 给出了部分答案,也就是深入了解 LNK 内容的链接:https://blez.wordpress.com/2013/02/18/get-file-shortcuts-target-with-c/

不过,这似乎有点危险,希望微软在以后的 Windows 更新中永远不要修改这个。

另外,我很想听听为什么“官方”的做法会失败的解释。这些 .NET 类如何/为什么报告链接的旧位置而不是链接文件中实际存在的位置? Jimi 指出的另一个解决方案以与我相同的方式失败,使用 Shell、Folder、FolderItem 和 ShellLinkObject 类。

如果 Jimi 提交的是答案而不是评论,我会投赞成票。相反,我只想说 muchas gracias、domo arigato 和非常感谢!

【讨论】:

  • 我不能让它失败。您是如何更改修改后链接的目标路径的?另外,尝试将SLGP_RAWPATH = 0x04SLGP_UNCPRIORITY = 0x08 (我知道,文档说不支持;不要使用,但无论如何你都可以使用它)而不是0 传递给[IShellLinkW].GetPath() 而是0[IPersistFile].Load()
  • 另外,尝试调用SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, 0, 0),然后调用IntPtr envPtr = Marshal.StringToHGlobalUni("Environment"); SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, envPtr, SMTO_ABORTIFHUNG, 5000),看看缓存是否重建。
【解决方案2】:

我使用 WMIWin32_ShortcutFile

得到了正确的结果

在 Windows 10 VS 2015 上使用给定快捷方式进行的测试,部分代码由 WMI Code Creator =>

// Add reference to System.Management
// using System.Management;
string sLinkPath = "C:\\Users\\Christian\\Desktop";
string sLinkName = "MpCmdRun.lnk";
string sRequest = "SELECT * FROM Win32_ShortcutFile where Name=\"" + sLinkPath + "\\" + sLinkName + "\"";
sRequest = sRequest.Replace("\\", "\\\\");
try
{
    ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\CIMV2", sRequest);

    foreach (ManagementObject queryObj in searcher.Get())
    {
        Console.WriteLine("Target: {0}", queryObj["Target"]);
        // Target: C:\Program Files\Windows Defender\MpCmdRun.exe
    }
}
catch (ManagementException me)
{
    System.Windows.Forms.MessageBox.Show("An error occurred while querying for WMI data: " + me.Message);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-30
    • 2016-08-14
    • 2017-11-02
    • 2017-09-07
    • 2017-06-09
    • 1970-01-01
    相关资源
    最近更新 更多