lexxpavlov
@lexxpavlov
Программист, преподаватель

Как правильно открыть окно в другом приложении?

У меня есть два WPF-приложения. Я через WCF передаю сообщение из первого приложения во второе открыть новое окно, причём, новое окно должно появиться поверх всех других окон (в том числе, и поверх окна первого приложения).

Если новое окно открыть с помощью метода Show(), то оно открывается позади текущего окна (окна первого приложения). Лучшим способом открытия нового окна я делаю так:
window.Topmost = true;
window.Show();
window.Topmost = false;

Окно появляется поверх первого окна и активируется. (Интересно, что winapi-функции SetForegroundWindow, BringWindowToTop, SwitchToThisWindow не помогают, уверенно помогло только Topmost = true.)

Остаётся только проблема, что первое окно по прежнему считает себя активированным и фокус остаётся на первом окне - клавиши работают на первом окне. window.Focus(); не помогает. Щелчок мыши по новому окну фокус в него передаётся, и только тогда первое окно понимает, что потеряло фокус и деактивировалось.

Как передать фокус в новое окно?
  • Вопрос задан
  • 638 просмотров
Решения вопроса 1
lexxpavlov
@lexxpavlov Автор вопроса
Программист, преподаватель
В описании функции SetForegroundWindow написаны условия, когда эта функция работает. В некоторых случаях почему-то в другое окно не передаётся клавиатурный фокус. Точнее, второй процесс, который открывает окно, не имеет фокуса. Почему-то в некоторых случаях это не мешает ему открывать активное окно (видимо, одно из других условий срабатывает), но в некоторых - не может сделать окно активным.

Решение - симулировать нажатие клавиши в процессе, который будет открывать окно:
private const byte VK_LMENU = 0xA4;
private const byte KEYEVENTF_EXTENDEDKEY = 0x01;
private const byte KEYEVENTF_KEYUP = 0x02;
private const byte KEYSCAN_LALT = 0xB8;

[DllImport("user32.dll")]
internal static extern bool SetForegroundWindow(IntPtr hwnd);
[DllImport("user32.dll")]
private static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo);

public static void BringWindowToFront(IntPtr hwnd)
{
    // симуляция нажатия клавиши ALT https://stackoverflow.com/a/13881647/1343405
    keybd_event(VK_LMENU, KEYSCAN_LALT, 0, 0);
    keybd_event(VK_LMENU, KEYSCAN_LALT, KEYEVENTF_KEYUP, 0);

    SetForegroundWindow(hwnd);
}


Полезные ссылки: вопрос, статья.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 2
@John_Nash
coder
Специально создал проект и проверил: SetForegroundWindow прекрасно работает. У меня семерка x64
Ответ написан
AlexanderYudakov
@AlexanderYudakov
C#, 1С, Android, TypeScript
Насколько я помню, SetForegroundWindow работает только если его вызывать из UI-потока активного приложения. Т.е. если одно активное приложение хочет сделать активным другое приложение - это пожалуйста. А вот если фоновое приложение захочет сделать активным само себя - это ни-ни, операционка не позволит всяким спамерам отвлекать пользователя от работы.

В нашем случае SetForegroundWindow(handle окна приложения 2) должно вызваться из UI-потока приложения 1.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы