2013-07-26 4 views
9

У меня есть небольшая проблема, полностью понимающая AttachThreadInput.Понимание AttachThreadInput - отсоединение потерять фокус

Я знаю, что это «соединение» очереди сообщений из 2 потоков, что (что я хочу сделать) позволяет мне, например, заставить мое окно (winforms) на переднем плане.

Что я могу сделать с помощью этого метода:

private void SetForegroundWindowEx(IntPtr hWnd) 
{ 
    uint SW_SHOW = 5; 
    uint appThread = GetCurrentThreadId();  
    uint foregroundThread = GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero);   

    if (foregroundThread != appThread) 
    { 
     AttachThreadInput(foregroundThread, appThread, true); 

     BringWindowToTop(hWnd); 
     ShowWindow(hWnd, SW_SHOW);  
     AttachThreadInput(foregroundThread, appThread, false); 

    } 
    else 
    { 
     BringWindowToTop(hWnd); 
     ShowWindow(hWnd, SW_SHOW); 
    } 
} 

Однако оба окон теряет фокус, как только нить разделиться.

Если я жду, когда очередь сообщений опустятся (Application.DoEvents()) и активирует мое окно (которое теперь находится на переднем плане, но не сфокусировано), оно восстановит фокус и сохранит его.

Если я делаю это до того, как очередь сообщений пуста, она снова потеряет фокус.

Так что я бы предположил, что что-то от отсоединения отвлекает внимание от моих окон, но я понятия не имею, что это такое или как его предотвратить.

Это первое, что я не совсем понимаю.

Второе, что я не получаю, если я не установлю мое окно на передний план:

AttachThreadInput(foregroundThread, appThread, true); 

AttachThreadInput(foregroundThread, appThread, false); 
Application.DoEvents(); 
this.Activate(); 

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

Возможно, кто-то с лучшим пониманием AttachThreadInput может ответить на эти два вопроса.

INFO:
Мне нужно, чтобы украсть фокус в этом случае, потому что мое приложение вызывается с помощью API. Другое приложение, которое вызывает мое, ждет обратной связи от моего приложения и в большинстве случаев зависает, пока не получит информацию.

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

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

+0

Вы могли бы найти [это] (http://blogs.msdn.com/b/oldnewthing/archive/2013/06/19/10426841.aspx) и [это] (HTTP: // блоги. msdn.com/b/oldnewthing/archive/2008/08/01/8795860.aspx) довольно интересно. –

+0

Хорошо, что обе ссылки говорят мне, насколько я плох, потому что хочу присоединить поток ввода, не так ли? Или есть что-то еще, что я пропустил ?. Я знаю, что это не обычное упражнение, и его следует предотвращать практически всеми силами, но в моем случае мне действительно нужно это делать. – Visions

+0

Имейте в виду, я не эксперт здесь, но совсем недавно прочитал эту статью.Сказав это, вы можете сравнить первые строки фрагмента кода с первыми строками в [этом примере] (http://blogs.msdn.com/b/oldnewthing/archive/2013/06/19/10426841. ASPX). С казуальной точки зрения им нравятся совершенно одинаковые (и тем самым заявляя статью «неправильно»). Разумеется, YMMV. –

ответ

8

Вот часть кода C#, которую я использую для этой же цели. Я хотел бы отметить, что есть законные случаи, когда это может потребоваться. В нашей ситуации это была автоматизация MS Word. Всякий раз, когда пользователь нажимает кнопку на панели инструментов внутри нашего приложения, мы должны немедленно принести окно Word к вниманию пользователя.

public static void ForceWindowIntoForeground(IntPtr window) 
{ 
    uint currentThread = Win32.GetCurrentThreadId(); 

    IntPtr activeWindow = Win32.GetForegroundWindow(); 
    uint activeProcess; 
    uint activeThread = Win32.GetWindowThreadProcessId(activeWindow, out activeProcess); 

    uint windowProcess; 
    uint windowThread = Win32.GetWindowThreadProcessId(window, out windowProcess); 

    if (currentThread != activeThread) 
     Win32.AttachThreadInput(currentThread, activeThread, true); 
    if (windowThread != currentThread) 
     Win32.AttachThreadInput(windowThread, currentThread, true); 

    uint oldTimeout = 0, newTimeout = 0; 
    Win32.SystemParametersInfo(Win32.SPI_GETFOREGROUNDLOCKTIMEOUT, 0, ref oldTimeout, 0); 
    Win32.SystemParametersInfo(Win32.SPI_SETFOREGROUNDLOCKTIMEOUT, 0, ref newTimeout, 0); 
    Win32.LockSetForegroundWindow(LSFW_UNLOCK); 
    Win32.AllowSetForegroundWindow(Win32.ASFW_ANY); 

    Win32.SetForegroundWindow(window); 
    Win32.ShowWindow(window, Win32.SW_RESTORE); 

    Win32.SystemParametersInfo(Win32.SPI_SETFOREGROUNDLOCKTIMEOUT, 0, ref oldTimeout, 0); 

    if (currentThread != activeThread) 
     Win32.AttachThreadInput(currentThread, activeThread, false); 
    if (windowThread != currentThread) 
     Win32.AttachThreadInput(windowThread, currentThread, false); 
} 
Смежные вопросы