启动关联程序或从另一个程序显示“打开方式”对话框

Posted

技术标签:

【中文标题】启动关联程序或从另一个程序显示“打开方式”对话框【英文标题】:Launch associated program or show "Open with" dialog from another program 【发布时间】:2014-06-27 07:33:30 【问题描述】:

在窗口七下,下面的命令显示一个对话框然后没有任何其他操作就终止了,为什么?

预期效果是启动关联程序Notepad++或至少Notepad

RUNDLL32.EXE SHELL32.DLL,OpenAs_RunDLL D:\doc\toto.txt

【问题讨论】:

【参考方案1】:

首先,请注意OpenAs_RunDLL 是undocumented entry point,因此期望它工作的唯一原因是它作为Open With shell 动词的实现出现在HKEY_CLASSES_ROOT 注册表中(至少在某些版本的Windows 中) )。

这仅意味着它可以在被适当的 shell 函数调用时工作。这并不意味着它一定会在任何任意上下文中工作。

在我的家用机器 (Windows Vista) 上,当通过“开始”菜单的“运行”对话框发出命令时,通过 rundll32 调用 OpenAs_RunDLL 可以正常工作(即,使用选定的应用程序打开指定的文件),可以使用键盘快捷键Windows+R

从命令行控制台窗口发出不起作用,症状与您描述的相同:显示对话框,但未启动应用程序。这是完全合法的行为,因为您在不是为它设计的上下文中使用了未记录的入口点。

由于无法保证OpenAs_RunDLL 将在未来的 Windows 版本中完全存在,因此结果很简单:不要使用它。请改用支持的SHOpenWithDialog API 函数,或将ShellExecuteShellExecuteExopenas verb 一起使用;后者可能特别有用,因为它是easy to do from a scripting language such as VBScript。

【讨论】:

根据 Stack Overflow 上其他地方的各种其他答案,如果“open”动词可用,“openas”动词将不起作用。所以SHOpenWithDialog 可能是唯一可靠的解决方案。 你能举一个VBScript的例子来使用SHOpenWithDialog吗? 据我所知,VBScript 无法完成。您必须使用支持调用 Win32 API 的语言(例如 C)。【参考方案2】:

解决方法很简单:cmde.exe start

这是嵌入命令的 Java 代码:

private void open( File file ) 
   try 
      final String cmd =
         String.format( "cmd.exe /C start %s", file.getAbsolutePath());
      Runtime.getRuntime().exec( cmd );
   
   catch( final Throwable t ) 
      t.printStackTrace();
   

选择.project时,显示了以下对话框:

以及选择底部的单选按钮显示以下对话框:

这正是我想要的。

【讨论】:

这对于已经具有关联应用程序的文件(例如原始示例中的文本文件)不起作用(即,不会显示“打开方式”对话框)。 是的,你是对的。我已经更新了从一开始就不清楚的问题的标题......【参考方案3】:

基于对类似问题的其他答案以及来自 CodeProject: Calling the Open With dialog box from your application, using C# 和 PInvoke.net: SHOpenWithDialog (shell32) 的代码,这是适合我的代码

ShellHelper.OpenAs(mainForm.Handle, "path/to/file")

在 Windows XP 和 Windows Vista 及更高版本上。此代码仅使用记录在案的 API(无 rundll32

public class ShellHelper

    #region http://www.pinvoke.net/default.aspx/shell32/SHOpenWithDialog.html

    [DllImport("shell32.dll", EntryPoint = "SHOpenWithDialog", CharSet = CharSet.Unicode)]
    private static extern int SHOpenWithDialog(IntPtr hWndParent, ref tagOPENASINFO oOAI);

    // http://msdn.microsoft.com/en-us/library/windows/desktop/bb773363(v=vs.85).aspx 
    private struct tagOPENASINFO
    
        [MarshalAs(UnmanagedType.LPWStr)]
        public string cszFile;

        [MarshalAs(UnmanagedType.LPWStr)]
        public string cszClass;

        [MarshalAs(UnmanagedType.I4)]
        public tagOPEN_AS_INFO_FLAGS oaifInFlags;
    

    [Flags]
    private enum tagOPEN_AS_INFO_FLAGS
    
        OAIF_ALLOW_REGISTRATION = 0x00000001,   // Show "Always" checkbox
        OAIF_REGISTER_EXT = 0x00000002,   // Perform registration when user hits OK
        OAIF_EXEC = 0x00000004,   // Exec file after registering
        OAIF_FORCE_REGISTRATION = 0x00000008,   // Force the checkbox to be registration
        OAIF_HIDE_REGISTRATION = 0x00000020,   // Vista+: Hide the "always use this file" checkbox
        OAIF_URL_PROTOCOL = 0x00000040,   // Vista+: cszFile is actually a URI scheme; show handlers for that scheme
        OAIF_FILE_IS_URI = 0x00000080    // Win8+: The location pointed to by the pcszFile parameter is given as a URI
    

    private static void DoOpenFileWith(IntPtr hwndParent, string sFilename)
    
        tagOPENASINFO oOAI = new tagOPENASINFO();
        oOAI.cszFile = sFilename;
        oOAI.cszClass = String.Empty;
        oOAI.oaifInFlags = tagOPEN_AS_INFO_FLAGS.OAIF_ALLOW_REGISTRATION | tagOPEN_AS_INFO_FLAGS.OAIF_EXEC;
        SHOpenWithDialog(hwndParent, ref oOAI);
    

    #endregion

    #region http://www.codeproject.com/Articles/13103/Calling-the-Open-With-dialog-box-from-your-applica

    [Serializable]
    private struct ShellExecuteInfo
    
        public int Size;
        public uint Mask;
        public IntPtr hwnd;
        public string Verb;
        public string File;
        public string Parameters;
        public string Directory;
        public uint Show;
        public IntPtr InstApp;
        public IntPtr IDList;
        public string Class;
        public IntPtr hkeyClass;
        public uint HotKey;
        public IntPtr Icon;
        public IntPtr Monitor;
    

    // Code For OpenWithDialog Box

    [DllImport("shell32.dll", SetLastError = true)]
    extern private static bool ShellExecuteEx(ref ShellExecuteInfo lpExecInfo);

    private const uint SW_NORMAL = 1;

    private static void OpenAsOld(IntPtr hwndParent, string file)
    
        ShellExecuteInfo sei = new ShellExecuteInfo();
        sei.Size = Marshal.SizeOf(sei);
        sei.Verb = "openas";
        sei.File = file;
        sei.Show = SW_NORMAL;
        sei.hwnd = hwndParent;
        if (!ShellExecuteEx(ref sei))
            throw new System.ComponentModel.Win32Exception();
    

    #endregion

    public static void OpenAs(IntPtr hWndParent, string file)
    
        if (System.Environment.OSVersion.Version.Major > 5)
        
            DoOpenFileWith(hWndParent, file);
        
        else
        
            OpenAsOld(hWndParent, file);
        
    

【讨论】:

ShellExecute 不适用于我 (win10),除非 sei.fMask = SEE_MASK_INVOKEIDLIST 按照此处的建议设置 ***.com/a/21182262/362515 虽然我发现这很有帮助,但这是对标记为 Java 的问题的 C# 答案。这个答案应该迁移到C#问题How can I show the “Open with” file dialog?。

以上是关于启动关联程序或从另一个程序显示“打开方式”对话框的主要内容,如果未能解决你的问题,请参考以下文章

双击文件夹,他弹出提示说:该文件没有程序与之关联来执行该操作,请在控制面板的文件夹选项中创建关联。

怎样在文件夹选项中创建关联

电脑软件有些图标不正常显示是怎么回事

为啥我的txt文件打不开来了

电脑里的启动脚本是啥意思,在那地方?

打不开IE浏览器显示该文件没有程序与之关联来执行该操作