我已经看到了大量通过文件启动外部应用程序的代码,但这不是问题。为了准确澄清我想要的行为:
- 对于给定的文件名,启动正确的进程。
- 如果没有关联的进程,正确的 shell 对话框应该提示用户关联一个。
- 启动应用程序时,此应用程序需要转到 Z 顺序的后面(或就在正在启动的应用程序后面)并留在那里。
第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);
}
}
}