anupama lite iyer Ответов: 1

Отображение не-windows exe-приложения внутри формы windows


Как я могу встроить неродное приложение (приложение, установленное в windows 7)в форму windows с помощью c#.

Я могу получить то, что у меня есть до сих пор, чтобы работать иногда, когда я начинаю с отладки и приложение открывается в форме. Но когда я начинаю без отладки, приложение всегда открывается вне формы. Я не понимаю, почему это происходит.

Возможно ли то, что я пытаюсь сделать? Судя по другим ответам на форуме, похоже, что это не так

Спасибо

Что я уже пробовал:

public partial class Form1 : Form { Process process = new Process();

    [DllImport("user32.dll", SetLastError = true)]
    static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

    [DllImport("user32.dll", SetLastError = true)]
    internal static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    static extern bool PostMessage(HandleRef hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
    [DllImport("user32.dll")]
    static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);

    [DllImport("User32.dll")]
    private static extern bool SetForegroundWindow(IntPtr hWnd);
    public Form1()
    {
        InitializeComponent();
        // panel1.Container.Add(process);
        process.StartInfo.RedirectStandardOutput = true;
        process.StartInfo.RedirectStandardInput = true;
        process.StartInfo.UseShellExecute = false;
        process.StartInfo.CreateNoWindow = false;
         string path = Path.Combine(Path.GetFullPath(@"C:\Program Files (x86)\Plan-G v3.2.0"), "Plan-G3.exe");
         process = Process.Start(path);

         Debug.WriteLine(process.MainWindowHandle);
         while (process.MainWindowHandle == IntPtr.Zero)
        {
             Thread.Sleep(1000); // Don't hog the CPU
            process.Refresh(); // You need this since `MainWindowHandle` is cached


        }

        Form1.SetForegroundWindow(process.MainWindowHandle);
        SetForegroundWindow(process.MainWindowHandle);

        SetParent(process.MainWindowHandle, panel1.Handle);

        MoveWindow(process.MainWindowHandle, 0, 0, panel1.Width - 90, panel1.Height, true);


    }
}


Я тоже пробовал это:
public partial class Form1 : Form
    {
        [DllImport("user32.dll")]
        static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);

        [DllImport("user32.dll")]
        private static extern IntPtr GetForegroundWindow();

        [DllImport("kernel32.dll")]
        static extern uint GetCurrentThreadId();
        [DllImport("user32.dll")]
        static extern bool AttachThreadInput(uint idAttach, uint idAttachTo,
   bool fAttach);

        [DllImport("user32.dll", SetLastError = true)]
        static extern bool BringWindowToTop(IntPtr hWnd);

        [DllImport("user32.dll", EntryPoint = "ShowWindow", SetLastError = true)]
        static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

        [DllImport("user32.dll", SetLastError = true)]
        static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

        [DllImport("user32.dll", SetLastError = true)]
        internal static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
        Process process = new Process();
        private static void ForceForegroundWindow(IntPtr hWnd)

        {

            uint foreThread = GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero);

            uint appThread = GetCurrentThreadId();

            const int SW_SHOW = 5;

            if (foreThread != appThread)

            {

                AttachThreadInput(foreThread, appThread, true);

                BringWindowToTop(hWnd);

                ShowWindow(hWnd, SW_SHOW);

                AttachThreadInput(foreThread, appThread, false);

            }

            else

            {

                BringWindowToTop(hWnd);

                ShowWindow(hWnd, SW_SHOW);

            }

        }
        public Form1()
        {
            InitializeComponent();

            process.StartInfo.RedirectStandardOutput = true;
            process.StartInfo.RedirectStandardInput = true;
            process.StartInfo.UseShellExecute = false;
            string path = Path.Combine(Path.GetFullPath(@"C:\Program Files (x86)\Plan-G v3.2.0"), "Plan-G3.exe");
            process = Process.Start(path);

            Debug.WriteLine(process.MainWindowHandle);
            while (process.MainWindowHandle == IntPtr.Zero)
            {
                Thread.Sleep(1000); // Don't hog the CPU
                process.Refresh(); // You need this since `MainWindowHandle` is cached


            }

            //Form1.SetForegroundWindow(process.MainWindowHandle);
            ForceForegroundWindow(process.MainWindowHandle);

            SetParent(process.MainWindowHandle, this.Handle);

            MoveWindow(process.MainWindowHandle, 0, 0, this.Width - 90, this.Height, true);
             


        }
    }


Я также рассмотрел все другие решения, предложенные в CodeProject и в других местах, включая:
Выведите процесс на передний план[^]
Размещение EXE-приложений в проекте WinForm[^]
c# - стыковочное окно внутри другого окна - переполнение стека[^]
Как встроить (док-станция) Сторонний EXE-файл в Панель/форму в C# .net[^]

Maciej Los

Почему? В этом нет никакого смысла!

anupama lite iyer

Мне нужно показать его как часть моей формы

1 Ответов

Рейтинг:
1

Dave Kreskowiak

Вам придется объяснить, что вы подразумеваете под "исполняемым файлом приложения, отличного от windows".

С этим есть проблемы. Во-первых, приложение, которое вы запускаете, может не поддерживать это и может отображаться неправильно.

Далее, приложение не будет знать, что оно находится внутри вашего окна приложения. Он будет вести себя так же, как ваше приложение теперь является окном рабочего стола. Пользователи могут перемещать его за пределы экрана, сворачивать, разворачивать, изменять размер и т. д.

Кроме того, при запуске приложения вам нужно дождаться создания дескриптора окна, прежде чем пытаться получить его дескриптор окна. Ваш код, кажется, написан для этого, но он не будет работать во всех случаях. Что еще более важно, дескриптор окна теперь может существовать, но работает ли его насос сообщений? А может, и нет. Когда вы начинаете бросать сообщения в дескриптор окна, насос сообщений для их обработки может еще не быть там, поэтому ваши сообщения игнорируются.

Лучшее решение-отказаться от опроса для MainWindowHandle и просто вызвать процесс.WaitForInputIdle(). Таким образом, вы знаете, что насос сообщений работает.

Кроме того, вы можете избавиться от двух вызовов SetForegroundWindow. Они тебе вообще не понадобятся.