簡體   English   中英

C# Process.Start 打開外部 exe 的 2 個實例

[英]C# Process.Start opens 2 instance of the external exe

我想打開一個外部 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啟動具有窗口的程序 (.exe),一旦該程序啟動,將其窗口移動到指定監視器上的指定點 (x, y)(例如:1 , 2, 等等...)。 已通過UT512/UT513接口程序(UT512 UT513軟件安裝文件)進行測試。

創建一個類(名稱:Helper.cs)

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

注意:可以使用 Spy++ 找到窗口文本(標題)。

資源

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM