C# Process.Start 打开外部EXE文件的两个实例
C# Process.Start opens two instances of the external EXE file
我想打开一个外部EXE文件(写在Delphi),把它放在屏幕的顶部和特定位置。
这段代码用到:
ProcessStartInfo psi = new ProcessStartInfo("UT512_UT513.exe");
psi.WindowStyle = ProcessWindowStyle.Normal;
p = Process.Start(psi);
Thread.Sleep(5000);
SetWindowPos(p.MainWindowHandle, HWND_TOPMOST, panel1.Location.X, panel1.Location.Y, 500, 500, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
MoveWindow(p.MainWindowHandle, panel1.Location.X, panel1.Location.Y, 500, 500, true);
SetParent(p.MainWindowHandle, this.Handle);
但问题是它打开了应用程序的两个实例。一个在顶部运行良好,但不在所需位置。第二个运行在第一个之后并且没有控件和 UI 并且具有黑色背景。
关闭应用程序会关闭第二个并保留第一个 运行。
您可以看到下图:
下面显示了如何使用 System.Diagnostics.Process
启动具有 window 的程序 (.exe),一旦该程序启动,将其 window 移动到指定点(x, y) 在指定的监视器上(例如:1、2 等...)。
已通过UT512/UT513 Interface Program(UT512 UT513软件安装文件)测试
创建一个class(名称:Helper)
文件Helper.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Drawing;
using System.Windows.Forms;
namespace MoveWindowTest
{
public class Helper
{
[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
public enum SpecialWindowHandles : int
{
/// <summary>
/// Places the window at the top of the Z order.
/// </summary>
HWND_TOP = 0,
/// <summary>
/// Places the window at the bottom of the Z order. If
/// the hWnd parameter identifies a topmost window, the
/// window loses its topmost status and is placed at
/// the bottom of all other windows.
/// </summary>
HWND_BOTTOM = 1,
/// <summary>
/// Places the window above all non-topmost windows. The
/// window maintains its topmost position even when
/// it is deactivated.
/// </summary>
HWND_TOPMOST = -1,
/// <summary>
/// Places the window above all non-topmost windows (that
/// is, behind all topmost windows). This flag has no
/// effect if the window is already a non-topmost window.
/// </summary>
HWND_NOTOPMOST = -2
}
[Flags]
public enum SetWindowPosFlags : uint
{
/// <summary>
/// If the calling thread and the thread that owns the
/// window are attached to different input queues, the
/// system posts the request to the thread that owns
/// the window. This prevents the calling thread
/// from blocking its execution while other
/// threads process the request.
/// </summary>
SWP_ASYNCWINDOWPOS = 0x4000,
/// <summary>
/// Prevents generation of the WM_SYNCPAINT message.
/// </summary>
SWP_DEFERERASE = 0x2000,
/// <summary>
/// Draws a frame (defined in the window's class
/// description) around the window.
/// </summary>
SWP_DRAWFRAME = 0x0020,
/// <summary>
/// Applies new frame styles set using the SetWindowLong
/// function. Sends a WM_NCCALCSIZE message to the
/// window, even if the window's size is not being
/// changed. If this flag is not specified,
/// WM_NCCALCSIZE is sent only when the window's
/// size is being changed.
/// </summary>
SWP_FRAMECHANGED = 0x0020,
/// <summary>
/// Hides the window.
/// </summary>
SWP_HIDEWINDOW = 0x0080,
/// <summary>
/// Does not activate the window. If this flag is not
/// set, the window is activated and moved to the top
/// of either the topmost or non-topmost group
/// (depending on the setting of the hWndInsertAfter parameter).
/// </summary>
SWP_NOACTIVATE = 0x0010,
/// <summary>
/// Discards the entire contents of the client area. If
/// this flag is not specified, the valid contents of
/// the client area are saved and copied back into the
/// client area after the window is sized or repositioned.
/// </summary>
SWP_NOCOPYBITS = 0x0100,
/// <summary>
/// Retains the current position (ignores X and Y parameters).
/// </summary>
SWP_NOMOVE = 0x0002,
/// <summary>
/// Does not change the owner window's position in the Z order.
/// </summary>
SWP_NOOWNERZORDER = 0x0200,
/// <summary>
/// Does not redraw changes. If this flag is set, no
/// repainting of any kind occurs. This applies to
/// the client area, the nonclient area (including
/// the title bar and scroll bars), and any part
/// of the parent window uncovered as a result of
/// the window being moved. When this flag is set,
/// the application must explicitly invalidate or
/// redraw any parts of the window and parent
/// window that need redrawing.
/// </summary>
SWP_NOREDRAW = 0x0008,
/// <summary>
/// Same as the SWP_NOOWNERZORDER flag.
/// </summary>
SWP_NOREPOSITION = 0x0200,
/// <summary>
/// Prevents the window from receiving the WM_WINDOWPOSCHANGING message.
/// </summary>
SWP_NOSENDCHANGING = 0x0400,
/// <summary>
/// Retains the current size (ignores the cx and cy parameters).
/// </summary>
SWP_NOSIZE = 0x0001,
/// <summary>
/// Retains the current Z order (ignores
/// the hWndInsertAfter parameter).
/// </summary>
SWP_NOZORDER = 0x0004,
/// <summary>
/// Displays the window.
/// </summary>
SWP_SHOWWINDOW = 0x0040,
}
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect);
[DllImport("User32.dll")]
public static extern Int32 SetWindowPos(IntPtr hwnd,
SpecialWindowHandles hwndInsertAfter,
int x,
int y,
int cx,
int cy,
SetWindowPosFlags flags);
public static System.Drawing.Point GetCurrentWindowPosition(IntPtr hwnd)
{
Point p = new Point(-1, -1);
RECT rect = new RECT();
if (GetWindowRect(hwnd, ref rect))
{
p = new Point(rect.Left, rect.Top);
}
return p;
}
public static void MoveWindowToMonitor(IntPtr hwnd, int monitorNumber, int x, int y)
{
RECT rect = new RECT();
if (GetWindowRect(hwnd, ref rect))
{
SetWindowPos(hwnd,
SpecialWindowHandles.HWND_TOP,
System.Windows.Forms.Screen.AllScreens[monitorNumber].WorkingArea.Left + x,
System.Windows.Forms.Screen.AllScreens[monitorNumber].WorkingArea.Top + y,
rect.Right,
rect.Bottom,
SetWindowPosFlags.SWP_SHOWWINDOW | SetWindowPosFlags.SWP_NOSIZE);
}
}
public static void StartProcess(string fullyQualifiedExeFilename,
string windowTitle,
int monitorNumber,
int x,
int y)
{
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = fullyQualifiedExeFilename;
startInfo.CreateNoWindow = true; // Don't create a window
//startInfo.UseShellExecute = true; // If true, uses 'ShellExecute'; if false, uses 'CreateProcess'
startInfo.UseShellExecute = false; // If true, uses 'ShellExecute'; if false, uses 'CreateProcess'
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
using (Process p = new Process { StartInfo = startInfo, EnableRaisingEvents = true })
{
p.Start(); //start
// Don't wait for exit
}
// Give the window time to be created.
// Periodically check if the window has been created yet.
// The sleep time can be adjusted as desired,
// as well as maxCount.
int count = 0;
int maxCount = 50;
IntPtr hwnd = IntPtr.Zero;
do
{
System.Threading.Thread.Sleep(75);
//System.Threading.Thread.Sleep(125);
// Find window
hwnd = FindWindow(null, windowTitle);
//Debug.WriteLine("hwnd: " + hwnd.ToString("X8") + " count: " + count.ToString());
if (hwnd != IntPtr.Zero)
{
break;
}
count++; // Increment
} while (count < maxCount);
// Move window
MoveWindowToMonitor(hwnd, monitorNumber, x, y);
}
}
}
用法:
string filename = System.IO.Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86),
@"DMM\UT512_UT513\UT512_UT513.exe");
if (!System.IO.File.Exists(filename))
{
filename = System.IO.Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles),
@"DMM\UT512_UT513\UT512_UT513.exe");
}
if (!System.IO.File.Exists(filename))
{
throw new Exception("Filename '" + filename + "' not found.");
}
// Start 'UT512_UT513 V2.00.exe' and move it to monitor 1; x = 100, y = 200
Helper.StartProcess(filename, "UT512/UT513 Interface Program V2.00", 1, 100, 200);
注意: window文本(标题)可以通过Spy++.
找到
资源:
- How do I find the position / location of a window given a hWnd without NativeMethods?
- findwindow (user32)
- setwindowpos (user32)
- enumwindows (user32)
- Get the current window position under Windows
- FindWindow in C# (via P/Invoke) finds desired window handle, but not in the desired conditions. How do I fix it?
- How to use EnumWindows to get only actual application windows?
- Enumerating Windows Using P/Invoke
我想打开一个外部EXE文件(写在Delphi),把它放在屏幕的顶部和特定位置。
这段代码用到:
ProcessStartInfo psi = new ProcessStartInfo("UT512_UT513.exe");
psi.WindowStyle = ProcessWindowStyle.Normal;
p = Process.Start(psi);
Thread.Sleep(5000);
SetWindowPos(p.MainWindowHandle, HWND_TOPMOST, panel1.Location.X, panel1.Location.Y, 500, 500, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
MoveWindow(p.MainWindowHandle, panel1.Location.X, panel1.Location.Y, 500, 500, true);
SetParent(p.MainWindowHandle, this.Handle);
但问题是它打开了应用程序的两个实例。一个在顶部运行良好,但不在所需位置。第二个运行在第一个之后并且没有控件和 UI 并且具有黑色背景。
关闭应用程序会关闭第二个并保留第一个 运行。
您可以看到下图:
下面显示了如何使用 System.Diagnostics.Process
启动具有 window 的程序 (.exe),一旦该程序启动,将其 window 移动到指定点(x, y) 在指定的监视器上(例如:1、2 等...)。
已通过UT512/UT513 Interface Program(UT512 UT513软件安装文件)测试
创建一个class(名称:Helper)
文件Helper.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Drawing;
using System.Windows.Forms;
namespace MoveWindowTest
{
public class Helper
{
[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
public enum SpecialWindowHandles : int
{
/// <summary>
/// Places the window at the top of the Z order.
/// </summary>
HWND_TOP = 0,
/// <summary>
/// Places the window at the bottom of the Z order. If
/// the hWnd parameter identifies a topmost window, the
/// window loses its topmost status and is placed at
/// the bottom of all other windows.
/// </summary>
HWND_BOTTOM = 1,
/// <summary>
/// Places the window above all non-topmost windows. The
/// window maintains its topmost position even when
/// it is deactivated.
/// </summary>
HWND_TOPMOST = -1,
/// <summary>
/// Places the window above all non-topmost windows (that
/// is, behind all topmost windows). This flag has no
/// effect if the window is already a non-topmost window.
/// </summary>
HWND_NOTOPMOST = -2
}
[Flags]
public enum SetWindowPosFlags : uint
{
/// <summary>
/// If the calling thread and the thread that owns the
/// window are attached to different input queues, the
/// system posts the request to the thread that owns
/// the window. This prevents the calling thread
/// from blocking its execution while other
/// threads process the request.
/// </summary>
SWP_ASYNCWINDOWPOS = 0x4000,
/// <summary>
/// Prevents generation of the WM_SYNCPAINT message.
/// </summary>
SWP_DEFERERASE = 0x2000,
/// <summary>
/// Draws a frame (defined in the window's class
/// description) around the window.
/// </summary>
SWP_DRAWFRAME = 0x0020,
/// <summary>
/// Applies new frame styles set using the SetWindowLong
/// function. Sends a WM_NCCALCSIZE message to the
/// window, even if the window's size is not being
/// changed. If this flag is not specified,
/// WM_NCCALCSIZE is sent only when the window's
/// size is being changed.
/// </summary>
SWP_FRAMECHANGED = 0x0020,
/// <summary>
/// Hides the window.
/// </summary>
SWP_HIDEWINDOW = 0x0080,
/// <summary>
/// Does not activate the window. If this flag is not
/// set, the window is activated and moved to the top
/// of either the topmost or non-topmost group
/// (depending on the setting of the hWndInsertAfter parameter).
/// </summary>
SWP_NOACTIVATE = 0x0010,
/// <summary>
/// Discards the entire contents of the client area. If
/// this flag is not specified, the valid contents of
/// the client area are saved and copied back into the
/// client area after the window is sized or repositioned.
/// </summary>
SWP_NOCOPYBITS = 0x0100,
/// <summary>
/// Retains the current position (ignores X and Y parameters).
/// </summary>
SWP_NOMOVE = 0x0002,
/// <summary>
/// Does not change the owner window's position in the Z order.
/// </summary>
SWP_NOOWNERZORDER = 0x0200,
/// <summary>
/// Does not redraw changes. If this flag is set, no
/// repainting of any kind occurs. This applies to
/// the client area, the nonclient area (including
/// the title bar and scroll bars), and any part
/// of the parent window uncovered as a result of
/// the window being moved. When this flag is set,
/// the application must explicitly invalidate or
/// redraw any parts of the window and parent
/// window that need redrawing.
/// </summary>
SWP_NOREDRAW = 0x0008,
/// <summary>
/// Same as the SWP_NOOWNERZORDER flag.
/// </summary>
SWP_NOREPOSITION = 0x0200,
/// <summary>
/// Prevents the window from receiving the WM_WINDOWPOSCHANGING message.
/// </summary>
SWP_NOSENDCHANGING = 0x0400,
/// <summary>
/// Retains the current size (ignores the cx and cy parameters).
/// </summary>
SWP_NOSIZE = 0x0001,
/// <summary>
/// Retains the current Z order (ignores
/// the hWndInsertAfter parameter).
/// </summary>
SWP_NOZORDER = 0x0004,
/// <summary>
/// Displays the window.
/// </summary>
SWP_SHOWWINDOW = 0x0040,
}
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect);
[DllImport("User32.dll")]
public static extern Int32 SetWindowPos(IntPtr hwnd,
SpecialWindowHandles hwndInsertAfter,
int x,
int y,
int cx,
int cy,
SetWindowPosFlags flags);
public static System.Drawing.Point GetCurrentWindowPosition(IntPtr hwnd)
{
Point p = new Point(-1, -1);
RECT rect = new RECT();
if (GetWindowRect(hwnd, ref rect))
{
p = new Point(rect.Left, rect.Top);
}
return p;
}
public static void MoveWindowToMonitor(IntPtr hwnd, int monitorNumber, int x, int y)
{
RECT rect = new RECT();
if (GetWindowRect(hwnd, ref rect))
{
SetWindowPos(hwnd,
SpecialWindowHandles.HWND_TOP,
System.Windows.Forms.Screen.AllScreens[monitorNumber].WorkingArea.Left + x,
System.Windows.Forms.Screen.AllScreens[monitorNumber].WorkingArea.Top + y,
rect.Right,
rect.Bottom,
SetWindowPosFlags.SWP_SHOWWINDOW | SetWindowPosFlags.SWP_NOSIZE);
}
}
public static void StartProcess(string fullyQualifiedExeFilename,
string windowTitle,
int monitorNumber,
int x,
int y)
{
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = fullyQualifiedExeFilename;
startInfo.CreateNoWindow = true; // Don't create a window
//startInfo.UseShellExecute = true; // If true, uses 'ShellExecute'; if false, uses 'CreateProcess'
startInfo.UseShellExecute = false; // If true, uses 'ShellExecute'; if false, uses 'CreateProcess'
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
using (Process p = new Process { StartInfo = startInfo, EnableRaisingEvents = true })
{
p.Start(); //start
// Don't wait for exit
}
// Give the window time to be created.
// Periodically check if the window has been created yet.
// The sleep time can be adjusted as desired,
// as well as maxCount.
int count = 0;
int maxCount = 50;
IntPtr hwnd = IntPtr.Zero;
do
{
System.Threading.Thread.Sleep(75);
//System.Threading.Thread.Sleep(125);
// Find window
hwnd = FindWindow(null, windowTitle);
//Debug.WriteLine("hwnd: " + hwnd.ToString("X8") + " count: " + count.ToString());
if (hwnd != IntPtr.Zero)
{
break;
}
count++; // Increment
} while (count < maxCount);
// Move window
MoveWindowToMonitor(hwnd, monitorNumber, x, y);
}
}
}
用法:
string filename = System.IO.Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86),
@"DMM\UT512_UT513\UT512_UT513.exe");
if (!System.IO.File.Exists(filename))
{
filename = System.IO.Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles),
@"DMM\UT512_UT513\UT512_UT513.exe");
}
if (!System.IO.File.Exists(filename))
{
throw new Exception("Filename '" + filename + "' not found.");
}
// Start 'UT512_UT513 V2.00.exe' and move it to monitor 1; x = 100, y = 200
Helper.StartProcess(filename, "UT512/UT513 Interface Program V2.00", 1, 100, 200);
注意: window文本(标题)可以通过Spy++.
找到资源:
- How do I find the position / location of a window given a hWnd without NativeMethods?
- findwindow (user32)
- setwindowpos (user32)
- enumwindows (user32)
- Get the current window position under Windows
- FindWindow in C# (via P/Invoke) finds desired window handle, but not in the desired conditions. How do I fix it?
- How to use EnumWindows to get only actual application windows?
- Enumerating Windows Using P/Invoke