4

我正在尝试从 C# 应用程序启动“开始”菜单中的程序,“开始”菜单中的几乎所有项目都是快捷方式 (lnk) 文件。当使用 Process.Start 启动这些文件时,我发现如果 lnk 文件的完整路径指向 C:\Program Files 目录,则会出现“系统找不到指定的路径”错误。我对 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 文件,不如为其获取目标,然后运行目标。我尝试使用How to resolve a .lnk in c#How to follow a .lnk file programmatically,但两种方法都将完整路径返回为 C:\Program Files (x86)\Splitter.exe 而不是 C:\ 的实际路径程序文件\Splitter.exe。

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

4

1 回答 1

5

通过使用 Sam Saffron 在How to resolve a .lnk in c# 中的示例脚本,我能够提供解决此问题的方法。我将 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;
}

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

于 2013-10-22T22:31:34.057 回答