vahid211 Ответов: 1

Как разместить VB6 EXE в C# winform


Я запрограммировал WinForm в .net с помощью C#, чтобы открыть VB6 exe в TabControl,
теперь все окна exe файл как Notpad.exe или ... открывает успех в TabControl, но VB6 не открывается правильно в WinForm,он не подчиняется родительскому / дочернему закону.
Теперь, пожалуйста, помогите мне, это очень важно и несекретно для меня.

В Дополнение:
1-в программе используется класс Procces для запуска программы, а также используется SetParent() для определения Parent/Child legal.
2 - я использовал из Telerik просмотров страницы открывать окна в разных вкладках.


код:

// Global Var ---------------
public string TabName;
public const int GWL_STYLE = -16;
public const uint WS_VISIBLE = 0x10000000;
// ---------------------------

private void radButtonElement3_Click(object sender, EventArgs e)
        {
         //Creeate New Tab in Telerik PageView
            TabName = radButtonElement3.Text;
            Telerik.WinControls.UI.RadPageViewPage Tab = new Telerik.WinControls.UI.RadPageViewPage(TabName);
            radPageView1.Pages.Add(Tab);
            radPageView1.SelectedPage = Tab;


            IntPtr appWin;
            appWin = IntPtr.Zero;

            string exeName = Application.StartupPath + "\\" + "VB6.exe";

            Process p = null;
            try
            {

                // Start the process
                p = System.Diagnostics.Process.Start(exeName);
             

                // Wait for process to be created and enter idle condition
                p.WaitForInputIdle();

                // Get the main handle
                appWin = p.MainWindowHandle;               
                
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.Message, "Error");
            }
                                
           
            //set new Handel 
            IntPtr _newHandler = radPageView1.Pages[(radPageView1.Pages.Count) - 1].Handle;

            SetParent(p.MainWindowHandle, _newHandler);
            SetWindowLong(_newHandler, GWL_STYLE, WS_VISIBLE);
            MoveWindow(_newHandler, 0, 0, radPageView1.Pages[0].Size.Width, radPageView1.Pages[0].Size.Height, true);
        
        }


// define user32.dll ---------------------------------------
[DllImport("user32.dll", EntryPoint = "GetWindowThreadProcessId", SetLastError = true,
             CharSet = CharSet.Unicode, ExactSpelling = true,
             CallingConvention = CallingConvention.StdCall)]
        private static extern long GetWindowThreadProcessId(long hWnd, long lpdwProcessId);

        [DllImport("user32.dll", SetLastError = true)]
        private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

        [DllImport("User32.dll")]
        public static extern int GetClassLong(IntPtr hWnd, int index);

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

        [DllImport("user32.dll", EntryPoint = "GetWindowLongA", SetLastError = true)]
        private static extern long GetWindowLong(IntPtr hwnd, int nIndex);

        [DllImport("user32.dll", EntryPoint = "SetWindowLongA", SetLastError = true)]
        private static extern long SetWindowLong(IntPtr hwnd, int nIndex, long dwNewLong);

        [DllImport("user32.dll", SetLastError = true)]
        private static extern long SetWindowPos(IntPtr hwnd, long hWndInsertAfter, long x, long y, long cx, long cy, long wFlags);

        [DllImport("user32.dll", SetLastError = true)]
        private static extern bool MoveWindow(IntPtr hwnd, int x, int y, int cx, int cy, bool repaint);

        [DllImport("user32.dll", EntryPoint = "PostMessageA", SetLastError = true)]
        private static extern bool PostMessage(IntPtr hwnd, uint Msg, long wParam, long lParam);

Philippe Mori

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

vahid211

танки для вашего внимания

0x01AA

Я несколько раз сталкивался с подобными проблемами. Не спрашивайте меня почему, но поставьте Thread.Sleep(200) _после_ p.WaitForInputIdle() решал ее каждый раз. Я знаю, это не очень хорошее решение... и да, я предполагаю, что вы проверили с помощью отладчика p.MainWindowHandle действителен...

vahid211

привет
Я это сделал, но проблема не разрешилась.
другое решение?

0x01AA

Нет, извините, другой идеи нет. Но я нашел кое-что в вашем коде... вы используете _newHandler....который я думаю, должен быть p. MainWindowHandle:
SetWindowLong(_newHandler, GWL_STYLE, WS_VISIBLE);
MoveWindow(_newHandler, 0, 0, radPageView1.Страницы[0].Размер.Ширина, radPageView1.Страницы[0].Размер.Высота, правда);

1 Ответов

Рейтинг:
1

Philippe Mori

На самом деле нет смысла иметь отношения родитель/ребенок между различными приложениями. И очевидно, что Windows не предназначена для обработки таких сценариев. И это может быть еще хуже с VB или .NET в сочетании, поскольку каждая технология имеет свой способ обработки и диспетчеризации событий...

Возможно, вы захотите преобразовать свой VB-код для создания активных/X (COM) элементов управления, которые затем могут быть встроены в форму или пользовательский элемент управления.

Или еще лучше было бы преобразовать код VB6 в любой VB.NET или код C#, или замените эти элементы управления более современными элементами управления, предназначенными для .NET.

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

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

Лучшей альтернативой может быть повторное использование кода из VB6 EXE, но повторное использование пользовательского интерфейса с помощью .NET.


0x01AA

Всего несколько мыслей:
Имеет ли это смысл или нет, я не могу судить.
Но "и очевидно, что Windows не предназначена для обработки таких сценариев", я думаю, это очень смелое утверждение. Что, кроме окна, является рабочим столом windows (HWND WINAPI GetDesktopWindow (void))?

Philippe Mori

Общее правило состоит в том, что каждое приложение (или окна верхнего уровня) имеет свой собственный поток пользовательского интерфейса... Рабочий стол Windows - это "особенное" окно, поскольку оно в некотором смысле принадлежит всем приложениям и в то же время не принадлежит ни одному приложению (например, ваше приложение не получит событие paint, если рабочий стол будет перерисован).
Некоторые ссылки, которые могут быть полезны:
Потоки объектов пользовательского интерфейса, часть 1: оконные ручки
Запуск приложения WPF с несколькими потоками пользовательского интерфейса
Кто когда-нибудь напишет многопоточную графическую программу?

vahid211

Дорогой Филипп Мори
Спасибо за ваш ответ, но я уверен, что это возможно,
на самом деле мы имеем около 300 форма в VB6 EXE-файл, который мы хотим управлять thire одной строки меню ленты из Telerik в .чистая позвонить в VB6 EXE-файл с и открываем каждую ссылку в новом новые на вкладке Управления, только это.

Philippe Mori

Что ж, даже если это каким-то образом сработает, это злоупотребление системой.

Тот факт, что он работает не так, как вы ожидаете, означает, что Windows или .NET не были разработаны с учетом этих случаев, поэтому вы, по сути, используете недокументированные функции, которые могут затруднить команде Windows (или команде .NET) улучшение своего кода, поскольку изменения могут привести к неожиданным нарушениям некоторых приложений.

Кстати, зачем вам помещать элементы управления в EXE-файл? Я думаю, что было бы гораздо разумнее поместить эти элементы управления внутри библиотеки DLL и использовать их в качестве активных элементов управления/X. Таким образом, пользовательский интерфейс из элементов управления VB будет находиться в том же потоке, что и основной поток пользовательского интерфейса приложения, и вам не придется бороться с системой.

vahid211

Дорогой Филипп Мори
как мы можем сделать DLL и использовать активные элементы управления/X ?
пожалуйста, предложите какую-нибудь статью, которая четко изучает эту тему.

BR,

Philippe Mori

Подробностей я не знаю. Я никогда не создавал таких элементов управления, и уже более 10 лет я, по сути, делаю только код на C#...

У вас действительно 300 EXE-файлов, каждый из которых содержит одну форму?

Если это так, то может быть проще пересмотреть пользовательский интерфейс так, чтобы часть экрана была зарезервирована для EXE-файла, а другая-для навигационного пользовательского интерфейса. Например, навигатор будет находиться слева, а EXE-файл-справа. За исключением начальной позиции (и закрытия) EXE-формы, у вас не будет большого взаимодействия между навигатором и отображаемым EXE-файлом. На панели задач они будут отображаться как 2 приложения.

Philippe Mori

Кстати, вы пробовали использовать стандартные элементы управления .NET, чтобы увидеть, работает ли это?

vahid211

дорогой Филипп Мори
да, я пробовал. вчера я познакомился с инструментом под названием Interop Toolkit, я думаю, что он может помочь мне реализовать этот сценарий,
если вы знаете это, пожалуйста, дайте мне некоторую информацию, чтобы понять это.
BR,