Как активировать Окно, запущенное другим процессом - PullRequest
0 голосов
/ 10 декабря 2018

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

Следующая настройка:

  • Мое приложение .NET C # с графическим интерфейсом (позволяет называть его gui) открывает другое приложение (позволяет назвать его server) с помощьюсоздание new Process()
  • * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  • * * * * * *1013* * * * * * * * * * * * * * *1013* 1013 * *1013* * * * * * * * * * * * * * * *1013* *1013* *1013* * * * * * * * * * * * * * *1013* * * * * * * * *1013* * * * * * * * * *1013* * * * * * * *} * * * **
  • Затем gui дает команду server на выполнение некоторых задач
  • Эти задачи определены в сборке / DLL, которую я предоставляю server
  • Один из нихЗадача состоит в том, чтобы открыть форму / диалог и задать пользователю еще несколько вопросов

Теперь, поскольку весь пользовательский опыт должен быть оптимизирован для повторной работы, элементы GUI (окна / формы / диалоги), которые открываются, нуждаются вбыть предварительно выбранным / сфокусированным / активным.

Первая проблема возникает, поскольку я не нашел четкого объяснения того, в чем разница между этими свойствами (Focus, Active, Selected, TopMost)Это.

Теперь реальный вопросКак я могу гарантировать, что все элементы графического интерфейса активны и выбраны, независимо от того, запущены ли они моим gui процессом или server процессом?

Использование WINAPI может быть более мощным, я читал такя определил следующее

// required to use WINAPI for RegainFocus();
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern int SetForegroundWindow(IntPtr hwnd);
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern IntPtr SetActiveWindow(IntPtr hwnd);
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

static private void RegainFocus()
{
    // set focus back to and show application for faster input
    // SW_RESTORE = 9
    ShowWindow(Process.GetCurrentProcess().MainWindowHandle, 9);
    SetForegroundWindow(Process.GetCurrentProcess().MainWindowHandle);
    SetActiveWindow(Process.GetCurrentProcess().MainWindowHandle);
}

Тогда я до сих пор пробовал:

  • Установите StartInfo процесса server следующим образом (так новый процесс делаетне крадите фокус gui)
    myProcess.StartInfo.UseShellExecute = false;
    myProcess.StartInfo.CreateNoWindow = true;
    myProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
    
  • Запустите процесс server и WaitForInputIdle (как описано здесь ), чтобы гарантировать, что server действительно готов
  • Также используйте RegainFocus() в gui приложении
  • В DLL для server я создаю новый Form() и пытаюсь (вывести окновперед и выберите его)
    myForm = new Form();
    myForm.Activated += dialog_Activated;
    myForm.PerformLayout();
    myForm.TopMost = true;
    myForm.Activate();
    myForm.BringToFront();
    myForm.Focus();
    myForm.Select();
    DialogResult result = myForm.ShowDialog();
    
  • TopMost=true работает с диалоговым окном перед gui
  • Метод dialog_Activated() устанавливаетСфокусируйтесь на первом элементе управления вводом, используя FocusControl().Это работает.

Результатом этого является окно поверх моего gui, в котором курсор мигает в первом элементе управления вводом, но не выбран / неактивен.Когда я нажимаю <TAB>, я вижу, что в gui, который находится в фоновом режиме, выбирается другой элемент управления.

Я также пытался распылять RegainFocus() вызовов в форме, но это не сработало.

Другие идеи, которые у меня есть, но я не могу их реализовать:

Target Framework - это .NET 4.5, целевая операционная системасистемы Windows 7 и Windows 10.

Спасибо за любую помощь и входы / советы!

1 Ответ

0 голосов
/ 12 декабря 2018

У меня есть решение, которое работает на Windows 10 и Windows 7.

После потери фокуса я использую функцию RegainFocus(), чтобы восстановить фокус (и активировать окно), см. Вопрос.Внимание: не смешивайте процесс HANDLE и MainWindowHandle.Когда объект скрыт, его MainWindowHandle вполне может быть 0.

. Я удалил

    myProcess.StartInfo.UseShellExecute = false;
    myProcess.StartInfo.CreateNoWindow = true;
    myProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;

при запуске процесса server, чтобы не мешать видимостигосударство.Я сохранил [WaitForInputIdle][1], хотя.

В Windows 7 этого было все еще недостаточно, и AllowSetForegroundWindow в созданном процессе не работал (хотя спасибо за комментарии), вместо того, чтобы принестиокно впереди, панель задач мигала .Решение здесь состояло в том, чтобы установить значение реестра из

\HKEY_CURRENT_USER\Control Panel\Desktop\ForegroundLockTimeout 

равным 0 и перезагрузить компьютер.Тогда код вел себя одинаково для Windows 7 и 10. С правильными разрешениями это могло бы быть даже сделано программно .

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...