当完整路径解析为 64 位目录时,无法从 32 位 C# 应用程序启动快捷方式 (lnk) 文件

2024-03-16

我正在尝试从 C# 应用程序启动“开始”菜单中的程序,并且“开始”菜单中的几乎所有项目都是快捷方式 (lnk) 文件。当使用 Process.Start 启动这些文件时,我发现如果 lnk 文件的完整路径指向 C:\Program Files 目录,则会出现“系统找不到指定的路径”错误。我做了一些研究文件系统重定向 http://msdn.microsoft.com/en-us/library/aa365743%28VS.85%29.aspx在 Windows 中,所以我尝试禁用它,但仍然收到相同的错误:

// disable file system redirection:
IntPtr ptr = new IntPtr();
bool isWow64FsRedirectionDisabled = Wow64DisableWow64FsRedirection(ref ptr);
// run the file:
System.Diagnostics.Process.Start("c:\\splitter.lnk");

这将返回“系统找不到指定的路径。”但是,如果我从“开始”>“运行”对话框启动 c:\splitter.lnk,则程序运行得很好。您可以在任何 64 位计算机上重现此问题,方法是为任何 64 位应用程序创建快捷方式,将其放置在 C 驱动器上,然后尝试使用上面的代码运行它。

有没有更好的方法来启动 .lnk 文件来避免此问题?或者我没有正确禁用文件重定向?

编辑:我还尝试将 UseShellExecute 设置为 true 以使操作系统运行该文件,但这仍然失败,这很有趣,因为从“开始”>“运行”对话框运行相同的路径效果很好:

Process process = new Process();
process.StartInfo.UseShellExecute = true;
process.StartInfo.FileName = "c:\\splitter.lnk";
process.Start();

编辑2:我认为我不会尝试直接启动LNK文件,而是获取它的目标,然后运行该目标。我尝试使用如何在 C# 中解析 .lnk https://stackoverflow.com/questions/139010/how-to-resolve-a-lnk-in-c-sharp and 如何以编程方式跟踪 .lnk 文件 https://stackoverflow.com/questions/8660705/how-to-follow-a-lnk-file-programmatically,但这两种方法都会返回 C:\Program Files (x86)\Splitter.exe 的完整路径,而不是 C:\Program Files\Splitter.exe 的实际路径。

也许我可以使用上述方法之一来获取LNK文件的目标。然后我可以查看目标是否包含程序文件(x86)。如果存在,请将其替换为 Program Files 并检查该文件是否存在。如果它存在于程序文件中,请运行它。如果没有,请从 Program Files (x86) 位置运行该文件。这将是一个混乱的解决方法,但我现在不知道还能尝试什么。任何建议,将不胜感激。


我能够通过使用 Sam Saffron 的示例脚本来解决此问题如何在 C# 中解析 .lnk https://stackoverflow.com/questions/139010/how-to-resolve-a-lnk-in-c-sharp。我将 ResolveShortcut 函数修改为以下内容:

public static string ResolveShortcut(string filename)
{
    // this gets the full path from a shortcut (.lnk file).
    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);
    string final_string = sb.ToString();
    if (final_string.Length == 0)
        final_string = filename;
    // If the the shortcut's target resolves to the Program Files or System32 directory, and the user is on a
    // 64-bit machine, the final string may actually point to C:\Program Files (x86) or C:\Windows\SYSWOW64.
    // This is due to File System Redirection in Windows -- http://msdn.microsoft.com/en-us/library/aa365743%28VS.85%29.aspx.
    // Unfortunately the solution there doesn't appear to work for 32-bit apps on 64-bit machines.
    // We will provide a workaround here:
    string new_path = Validate_Shortcut_Path(final_string, "SysWOW64", "System32");
    if (File.Exists(new_path) == true && File.Exists(final_string) == false)
    {
        // the file is actually stored in System32 instead of SysWOW64. Let's update it.
        final_string = new_path;
    }
    new_path = Validate_Shortcut_Path(final_string, "Program Files (x86)", "Program Files");
    if (File.Exists(new_path) == true && File.Exists(final_string) == false)
    {
        // the file is actually stored in Program Files instead of Program Files (x86). Let's update it.
        final_string = new_path;
    }
    // the lnk may incorrectly resolve to the C:\Windows\Installer directory. Check for this.
    if (final_string.ToLower().IndexOf("windows\\installer") > -1)
        final_string = filename;
    if (File.Exists(final_string))
        return final_string;
    else
        return filename;
    }

public static string Validate_Shortcut_Path(string final_string, string find_what, string replace_with)
{
    string final_string_lower = final_string.ToLower();
    string find_what_lower = find_what.ToLower();
    int find_value = final_string_lower.IndexOf(find_what_lower);
    if (find_value > -1)
    {
        // the shortcut resolved to the find_what directory, which can be SysWOW64 or Program Files (x86), 
        // but this may not be correct. Let's check by replacing it with another value.
        string new_string = final_string.Substring(0, find_value) + replace_with + final_string.Substring(find_value + find_what.Length);
        if (File.Exists(new_string) == true && File.Exists(final_string) == false)
        {
            // the file is actually stored at a different location. Let's update it.
            final_string = new_string;
        }
    }
    return final_string;
}

如果有人知道更好的方法来做到这一点,我愿意接受想法。否则我将使用此方法并接受此解决方法作为答案。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

当完整路径解析为 64 位目录时,无法从 32 位 C# 应用程序启动快捷方式 (lnk) 文件 的相关文章

随机推荐