c# - 启动与文件关联的外部进程并将此应用程序发送到后台

标签 c# winforms process

我见过大量通过文件启动外部应用程序的代码,但这不是问题所在。准确阐明我想要的行为:

  1. 对于给定的文件名,启动正确的进程。
  2. 如果没有关联进程,正确的 shell 对话框应提示用户关联一个进程。
  3. 当应用程序启动时,此应用程序需要转到 Z 顺序的后面(或刚好在正在启动的应用程序后面)并保持在那里。

第 3 步是我没做对的地方。我正在通过 psd 文件启动 Photoshop,但在显示闪屏时,它会随着我的应用程序争夺焦点而闪烁。一旦正常启动,一切都很好,但我不喜欢显示闪屏时的闪烁。

这是我迄今为止最好的尝试:

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

最佳答案

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

...(or just behind the app that is launching) and 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);
}     

关于c# - 启动与文件关联的外部进程并将此应用程序发送到后台,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19830156/

相关文章:

c# - 面板不会停靠在我希望它们在 winforms 中的位置

c# - MySQL SecureString作为连接字符串

unix - 杀死 UNIX 系统上已失效的进程

c# - SMTP 服务器需要安全连接或客户端未通过身份验证。服务器响应为 : 5. 5.1 需要身份验证

c# - 在 winform 中打开 PDF 或 Doc

c# - 使用 Azure Functions 上传 Parquet 文件流

c# - 使用 sql 数据库部署 wpf 应用程序

c# - 获取无法确定调用者错误的应用程序身份

c# - 如何在任务管理器中拥有不同的进程名称(当前进程)名称?

c - 使用 Apache/FastCGI 生成多个 C 可执行进程