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++.

找到

资源: