启动与文件关联的外部进程,并将此应用程序发送到后面

时间:2013-11-07 07:25:01

标签: c# winforms process

我已经看到大量代码通过文件启动外部应用程序,但这不是问题。要明确说明我想要的行为:

  1. 对于给定的文件名,启动正确的过程。
  2. 如果没有关联的进程,正确的shell对话框应提示用户关联。
  3. 启动应用程序时,此应用程序需要转到Z顺序的后面(或者正在启动的应用程序后面)并保持在那里。
  4. 第3步是我没有做对的。我正在通过psd文件启动Photoshop,但是当显示aplash屏幕时,它会随着我的应用程序争夺焦点而闪烁。一旦它正常启动,一切都很好,但我不喜欢闪烁屏幕显示时的闪烁。

    到目前为止,这是我最好的尝试:

    using System;
    using System.Diagnostics;
    using System.Runtime.InteropServices;
    using System.Security;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    
    namespace Romy.Core
    {
        internal static class Example
        {
            public const int SW_RESTORE = 9;
    
            private static readonly IntPtr HWND_BOTTOM = new IntPtr(1);
    
            private const uint SWP_NOACTIVATE = 0x0010;
    
            private const uint SWP_NOMOVE = 0x0002;
    
            private const uint SWP_NOSIZE = 0x0001;
    
            public static void SendWindowBack(IntPtr handle)
            {
                NativeMethods.SetWindowPos(handle, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
            }
    
            public static async void ShellExecuteFile(this IWin32Window window, string filename)
            {
                var p = Process.Start(new ProcessStartInfo()
                {
                    FileName = filename,
                    Verb = "open",
                    UseShellExecute = true,
                    ErrorDialog = true
                });
    
                SendWindowBack(window.Handle);
    
                try
                {
                    await Task.Run(async () =>
                    {
                        try
                        {
                            p.WaitForInputIdle();
                            IntPtr handle = p.MainWindowHandle;
    
                            while (handle == IntPtr.Zero)
                            {
                                await Task.Delay(TimeSpan.FromMilliseconds(250D));
                                handle = p.MainWindowHandle;
                            }
    
                            if (handle != IntPtr.Zero)
                            {
                                if (NativeMethods.IsIconic(handle))
                                    NativeMethods.ShowWindowAsync(handle, SW_RESTORE);
    
                                if (NativeMethods.SetForegroundWindow(handle))
                                    NativeMethods.SetActiveWindow(handle);
                            }
                        }
                        catch (InvalidOperationException) { }
                        catch (PlatformNotSupportedException) { }
                        catch (NotSupportedException) { }
                        catch (Exception ex) { ex.Log(); }
                    }).TimeoutAfter(TimeSpan.FromSeconds(3D));
                }
                catch (TimeoutException) { }
            }
    
            [SuppressUnmanagedCodeSecurity]
            internal static class NativeMethods
            {
                [DllImport("user32.dll")]
                [return: MarshalAs(UnmanagedType.Bool)]
                internal static extern bool IsIconic(System.IntPtr hWnd);
    
                [DllImport("user32.dll")]
                [return: MarshalAs(UnmanagedType.Bool)]
                internal static extern bool SetForegroundWindow(System.IntPtr hWnd);
    
                [DllImport("user32.dll")]
                internal static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter,
                    int X, int Y, int cx, int cy, uint uFlags);
    
                [DllImport("user32.dll")]
                [return: MarshalAs(UnmanagedType.Bool)]
                internal static extern bool ShowWindowAsync(System.IntPtr hWnd, int nCmdShow);
    
                [DllImport("user32.dll")]
                internal static extern System.IntPtr SetActiveWindow(System.IntPtr hWnd);
            }
        }
    }
    

1 个答案:

答案 0 :(得分:0)

尝试删除对 SendWindowBack 的调用,并将 SetForegroundWindow 替换为SetWindowLong。这应该符合您的要求:

  

...(或刚刚启动的应用程序后面)和STAY THERE ..

const int GWL_HWNDPARENT = (-8);

[DllImport("user32.dll", SetLastError = true)]
static extern int SetWindowLong(IntPtr childHandle, int nIndex, IntPtr parentHandle);

if (handle != IntPtr.Zero)
{
    if (NativeMethods.IsIconic(handle))
        NativeMethods.ShowWindowAsync(handle, SW_RESTORE);

    SetWindowLong(handle, GWL_HWNDPARENT, window.Handle)
    NativeMethods.SetActiveWindow(handle);
}     
相关问题