当完整路径解析为 64 位目录时,无法从 32 位 C# 应用程序启动快捷方式 (lnk) 文件 [英] Unable to launch shortcut (lnk) files from 32-bit C# application when the full path resolves to a 64-bit directory

查看:28
本文介绍了当完整路径解析为 64 位目录时,无法从 32 位 C# 应用程序启动快捷方式 (lnk) 文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试从 C# 应用程序启动开始"菜单中的程序,并且开始"菜单中的几乎所有项目都是快捷方式 (lnk) 文件.当使用 Process.Start 启动这些文件时,我发现如果 lnk 文件的完整路径指向 C:\Program Files 目录,我会收到系统找不到指定的路径"错误.我对文件系统重定向做了一些研究在 Windows 中,所以我尝试禁用它,但我仍然遇到相同的错误:

I'm trying to launch programs in the Start Menu from a C# application, and nearly all of the items in the Start Menu are shortcut (lnk) files. When using Process.Start to launch these files, I found that I was getting "The system cannot find the path specified" error if the full path of the lnk file pointed to the C:\Program Files directory. I did some research with File System Redirection in Windows, so I tried disabling it, but I'm still getting the same error:

// 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 位应用程序创建快捷方式、将其放置在 C 驱动器上并尝试使用上面的代码运行它来在任何 64 位计算机上重现此问题.

This returns "The system cannot find the path specified." However, if I launch c:\splitter.lnk from the Start > Run dialog box, the program runs just fine. You can reproduce this issue on any 64-bit machine by creating a shortcut for any 64-bit app, placing it on the C drive, and attempting to run it using the code above.

有没有更好的方法来启动 .lnk 文件来避免这个问题?还是我没有正确禁用文件重定向?

Is there a better way to launch .lnk files to avoid this problem? Or am I not disabling file redirection properly?

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

I also tried setting UseShellExecute to true to have the operating system run the file, but that still fails, which is interesting because running the same path from the Start > Run dialog box works just fine:

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#如何以编程方式跟踪 .lnk 文件,但两种方法都返回完整路径为 C:\Program Files (x86)\Splitter.exe 而不是 C:\Program Files\Splitter.exe 的实际路径.

EDIT 2: I figured that instead of trying to launch the LNK file directly, I would get the target for it, and then run the target. I tried using How to resolve a .lnk in c# and How to follow a .lnk file programmatically, but both methods return the full path as C:\Program Files (x86)\Splitter.exe instead of the actual path of C:\Program Files\Splitter.exe.

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

Perhaps I can use one of the above methods to get the target of the LNK file. Then I can see if the target contains Program Files (x86). If it does, replace it with Program Files and check if the file exists. If it exists in Program Files, run that. If not, run the file from the Program Files (x86) location. This would be a messy workaround, but I don't know what else to try at this point. Any suggestions would be appreciated.

推荐答案

我能够通过使用位于 如何在 c# 中解析 .lnk.我将 ResolveShortcut 函数修改为以下内容:

I was able to provide a workaround for this issue by using Sam Saffron's example script at How to resolve a .lnk in c#. I modified the ResolveShortcut function to the following:

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;
}

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

If anyone is aware of a better way to do this, I am open to ideas. Otherwise I will use this method and accept this workaround as the answer.

这篇关于当完整路径解析为 64 位目录时,无法从 32 位 C# 应用程序启动快捷方式 (lnk) 文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆