Запустите связанную программу или покажите диалог "Открыть с помощью" из другой программы

В седьмом окне следующая команда отображает диалоговое окно, а затем завершается без каких-либо других действий. Почему?

Ожидаемый эффект запуска соответствующей программы Notepad++ или по крайней мере Notepad

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

3 ответа

Решение

Решение очень простое: 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 выбран следующий диалог:

введите описание изображения здесь

и когда выбран переключатель внизу, отображается следующее диалоговое окно:

введите описание изображения здесь

Это именно то, что я хочу.

Во-первых, обратите внимание, что OpenAs_RunDLL является недокументированной точкой входа, поэтому единственная причина, по которой он должен работать, состоит в том, что он появляется в реестре HKEY_CLASSES_ROOT как реализация для Open With глагол оболочки (по крайней мере, в некоторых версиях Windows).

Это только означает, что он может работать при вызове соответствующими функциями оболочки. Это не значит, что он обязательно будет работать в любом произвольном контексте.

На моей домашней машине (Windows Vista) звонит OpenAs_RunDLL с помощью rundll32 работает (т. е. указанный файл открывается с использованием выбранного приложения), когда команда запускается через диалоговое окно "Пуск" в меню "Пуск", которое можно открыть с помощью сочетания клавиш Windows+R,

Он не работает, когда выдается из окна консоли командной строки, и симптомы такие же, как вы описали: диалоговое окно отображается, но приложение не запускается. Это совершенно законное поведение, потому что вы используете недокументированную точку входа в контексте, для которого она не предназначена.

Поскольку нет гарантии, что OpenAs_RunDLL будет существовать вообще в будущих версиях Windows, результат прост: не используйте его. Используйте поддерживаемые SHOpenWithDialog Функция API вместо этого, или использовать ShellExecute или же ShellExecuteEx с openas глагол; последнее может быть особенно полезным, потому что это легко сделать из скриптового языка, такого как VBScript.

Основываясь на других ответах на аналогичные вопросы и на код из CodeProject: вызов диалогового окна Open With из вашего приложения с использованием 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);
        }
    }
}
Другие вопросы по тегам