it-swarm-ko.com

응용 프로그램이 포커스를 훔치는 것을 방지합니다.

활성 창에서 응용 프로그램이 포커스를 훔치지 않도록하는 솔루션이 있습니까?

특히 응용 프로그램을 시작하고 다른 작업을 수행하기 위해 전환하면 새 응용 프로그램이 텍스트 문장을 절반 정도받습니다.

190
svandragt

Windows 내부의extensivemanipulation이 없으면이 작업을 수행 할 수 없으며이를 극복해야합니다.

운영 체제에서 다른 작업을 수행하기 전에 한 가지 작업을 수행하는 것이 중요한 경우 일상적인 컴퓨터 사용의 순간이 있습니다. 그렇게하기 위해서는 특정 창에 집중해야합니다. Windows에서이 동작에 대한 제어는 주로 사용하는 개별 프로그램 개발자에게 맡겨져 있습니다.

이 주제에 관해서 모든 개발자가 올바른 결정을 내리는 것은 아닙니다.

나는 이것이 매우 초조하고 성가신 것을 알고 있지만, 당신은 당신의 케이크를 먹을 수도없고 그것을 먹을 수도 없다. 당신의 일상 생활 전반에 걸쳐 많은 경우가있을 것입니다. 초점이 특정 UI 요소 나 응용 프로그램으로 옮겨지고 초점이 잠긴 상태로 유지되는 것을 요구하는 것은 완벽합니다. 그러나 대부분의 응용 프로그램은 현재 누가 누가 리드인지 결정할 때 다소 평등하며 시스템이 절대로 완벽 할 수는 없습니다.

얼마 전이 문제를 한 번에 모두 해결하기 위해 광범위한 연구를 수행했습니다 (실패했습니다). 내 연구의 결과는 성가심 프로젝트 페이지 에서 찾을 수 있습니다.

프로젝트에는 다음을 호출하여 반복적으로 포커스를 잡으려고하는 응용 프로그램도 포함됩니다.

switch( message ) {
  case WM_TIMER:
    if( hWnd != NULL ) {
      // Start off easy
      // SetForegroundWindow will not move the window to the foreground,
      // but it will invoke FlashWindow internally and, thus, show the
      // taskbar.
      SetForegroundWindow( hWnd );

      // Our application is awesome! It must have your focus!
      SetActiveWindow( hWnd );

      // Flash that button!
      FlashWindow( hWnd, TRUE );
    }
    break;

이 스 니펫에서 볼 수 있듯이, 필자의 연구는 내가 좋아하지 않는 사용자 인터페이스 동작의 다른 측면에도 중점을 두었다.

이 문제를 해결하기 위해 노력한 방법은 모든 새 프로세스에 DLL을로드하고 다른 창이 활성화되도록하는 API 호출을 연결하는 것입니다.
마지막 부분은 멋진 API 후킹 라이브러리 덕분입니다. 나는 아주 훌륭한 mhook 라이브러리 를 사용했다 :

#include "stdafx.h"
#include "mhook-2.2/mhook-lib/mhook.h"

typedef NTSTATUS( WINAPI* PNT_QUERY_SYSTEM_INFORMATION ) ( 
  __in       SYSTEM_INFORMATION_CLASS SystemInformationClass,     
  __inout    PVOID SystemInformation, 
  __in       ULONG SystemInformationLength, 
  __out_opt  PULONG ReturnLength    
);

// Originals
PNT_QUERY_SYSTEM_INFORMATION OriginalFlashWindow   = 
  (PNT_QUERY_SYSTEM_INFORMATION)::GetProcAddress( 
  ::GetModuleHandle( L"user32" ), "FlashWindow" );

PNT_QUERY_SYSTEM_INFORMATION OriginalFlashWindowEx = 
  (PNT_QUERY_SYSTEM_INFORMATION)::GetProcAddress( 
  ::GetModuleHandle( L"user32" ), "FlashWindowEx" );

PNT_QUERY_SYSTEM_INFORMATION OriginalSetForegroundWindow = 
  (PNT_QUERY_SYSTEM_INFORMATION)::GetProcAddress( 
  ::GetModuleHandle( L"user32" ), "SetForegroundWindow" );

// Hooks
BOOL WINAPI
HookedFlashWindow(
  __in  HWND hWnd,
  __in  BOOL bInvert
  ) {
  return 0;
}

BOOL WINAPI 
HookedFlashWindowEx(
  __in  PFLASHWINFO pfwi
  ) {
  return 0;
}

BOOL WINAPI 
HookedSetForegroundWindow(
  __in  HWND hWnd
  ) {
  // Pretend window was brought to foreground
  return 1;
}


BOOL APIENTRY 
DllMain( 
  HMODULE hModule,
  DWORD   ul_reason_for_call,
  LPVOID  lpReserved
  ) {
  switch( ul_reason_for_call ) {
    case DLL_PROCESS_ATTACH:
      Mhook_SetHook( (PVOID*)&OriginalFlashWindow,         HookedFlashWindow );
      Mhook_SetHook( (PVOID*)&OriginalFlashWindowEx,       HookedFlashWindowEx );
      Mhook_SetHook( (PVOID*)&OriginalSetForegroundWindow, HookedSetForegroundWindow );
      break;

    case DLL_PROCESS_DETACH:
      Mhook_Unhook( (PVOID*)&OriginalFlashWindow );
      Mhook_Unhook( (PVOID*)&OriginalFlashWindowEx );
      Mhook_Unhook( (PVOID*)&OriginalSetForegroundWindow );
      break;
  }
  return TRUE;
}

그 당시의 테스트에서이 기능은 훌륭하게 작동했습니다. 모든 새로운 프로세스에 DLL을로드하는 부분을 제외하고. 상상할 수 있듯이, 그것은 너무 가볍게 받아 들일 수있는 것이 아닙니다. 나는 AppInit_DLLs 접근법을 사용했다.

기본적으로 이것은 위대한 작품입니다. 그러나 나는적절하게새로운 DLL을 새로운 프로세스에 삽입하는 것을 발견하지 못했습니다. 그리고 이것에 투자 한 시간은 포커스 훔치기가 나를 괴롭히는 성가심을 크게 과소 평가합니다.

DLL 주입 문제 외에도 Google 코드 구현시 다루지 않은 집중 도용 방법이 있습니다. 동료는 실제로 몇 가지 추가 연구를 수행하고 그 방법을 다루었습니다. 문제는 SO : https://stackoverflow.com/questions/7430864/windows-7-prevent-application-from-losing-focus 에서 논의되었습니다.

51
Der Hochstapler

Windows 7에서 ForegroundLockTimeout 레지스트리 항목을 더 이상 확인하지 않으면 Process Monitor로이를 확인할 수 있습니다. 실제로 Windows 7에서는 전경 창을 변경할 수 없습니다. 가서 자세한 내용에 대해 를 읽어보십시오. 심지어 Windows 2000부터 존재했습니다.

그러나 문서는 짜증나고 서로 쫓아 가서 그 주위의 길을 찾습니다 .

따라서 SetForegroundWindow 또는 유사한 API 함수로 버그가 발생합니다 ...

실제로 올바르게 수행하는 유일한 방법은 정기적으로 LockSetForegroundWindow 을 호출하는 작은 응용 프로그램을 만들어 버기 API 함수에 대한 호출을 사실상 비활성화하는 것입니다.

충분하지 않은 경우 (또 다른 버그가있는 API 호출?) 더 나아가서 진행 상황을 확인하기 위해 API monitoring 을 수행 한 다음 간단히 모든 프로세스에서 API 호출을 후크하십시오 그 후 포 그라운드를 엉망으로 만드는 any 호출을 제거 할 수 있습니다. 그러나 아이러니하게도 이것은 Microsoft에 의해 권장되지 않습니다 ...

23
Tamara Wijsman

TweakUI 에 옵션이 있습니다. 그것은 모호한 소프트웨어 개발자가 자신의 앱에 집중하도록하는 일반적인 트릭의 대부분을 막습니다.

그것은 계속되는 무기 전쟁이기 때문에 그것이 모든 것을 위해 작동하는지 모르겠습니다.

업데이트 : EndangeredMassa 에 따르면 TweakUI는 Windows 7에서 작동하지 않습니다.

18
Simon P Stevens

나는 "초점을 훔치는"두 가지 방법, 즉 (1) 창문이 전경으로오고, (2) 창에 키 입력이 오는 등의 혼란이있을 수 있다고 생각합니다.

여기에 언급 된 문제는 아마도 두 번째로, 사용자의 요청이나 허가없이 Windows가 전경에 초점을 맞춤으로써 포커스를 주장하는 것입니다.

여기서 토론은 XP와 7 사이에서 분리되어야합니다.

윈도우 XP

XP에는 응용 프로그램이 포커스를 훔치지 못하도록 방지하기 위해 XP이 (가) Windows 7과 동일하게 작동하도록하는 레지스트리 해킹이 있습니다.

  1. Regedit를 사용하여 HKEY_CURRENT_USER\Control Panel\Desktop로 이동하십시오.
  2. ForegroundLockTimeout을 두 번 클릭하고 그 값을 16 진수로 30d40로 설정하십시오.
  3. 확인을 누르고 regedit를 종료하십시오.
  4. 변경 사항을 적용하려면 PC를 재부팅하십시오.

윈도우 7

(아래의 설명은 대부분 XP에도 적용됩니다.)

Windows에서 응용 프로그램이 포커스를 훔치지 않고 기능을 유지할 수 없도록 차단할 수있는 방법이 없음을 이해하십시오. 예를 들어, 파일 복사 중에 바이러스 백신이 잠재적 인 위협을 감지하여 수행 할 작업을 묻는 창을 팝업하려는 경우이 창을 차단하면 복제가 종료되지 않는 이유를 결코 알 수 없습니다.

Windows 7에서는 MS-Windows focus-follows-mouse 레지스트리 해킹 _을 사용하는 Windows 자체의 동작에 한 가지 수정 만 가능합니다. _, 포커스 및/또는 활성화가 항상 창으로 이동합니다. 커서 아래에. 응용 프로그램이 데스크탑 전체에 나타나지 않도록 지연을 추가 할 수 있습니다.
이 문서를 참조하십시오 : Windows 7 - 마우스를 올리면 창을 활성화 - 활성화 .

그렇지 않으면 죄책감 프로그램을 감지하고 중화해야합니다. 항상 포커스가있는 동일한 응용 프로그램 인 경우이 응용 프로그램은 포커스를 가져 오도록 프로그래밍되어 있으며 컴퓨터에서 시작하지 못하게하거나 포커스를 사용하지 못하게 할 수 있습니다. 이 동작을 피하려면 해당 응용 프로그램에서 제공하는 일부 설정을 사용하십시오.

VB Code에 포함 된 VBS 스크립트를 사용하여 누가 훔치고 있는지 식별 할 수 있음 저자는 범인을 프린터 소프트웨어의 "콜 홈"업데이터로 식별하는 데 사용했습니다.

다른 모든 것이 실패 할 때 필사적 인 방법이며,이 잘못 구성된 응용 프로그램을 식별 한 경우 최소화하고 그 자체가 앞으로 나아지지 않을 것이라는 희망을 갖습니다. 가장 강력한 형태의 최소화는 Best Free Application Minimizer 에 나열된 무료 제품 중 하나를 사용하여 트레이에 있습니다.

절망적 인 순서로 생각하는 마지막 아이디어는 Desktops 또는 Dexpot 과 같은 제품을 사용하여 가상으로 데스크탑을 분쇄하고 기본값이 아닌 다른 데스크탑에서 작업하는 것입니다.

[편집하다]

Microsoft가 보관 갤러리를 폐기 한 결과 위의 VB code가 재현되었습니다.

Declare Auto Function GetForegroundWindow Lib "user32.dll" () As Integer
Declare Auto Function GetWindowThreadProcessId Lib "user32.dll" (ByVal hwnd As Integer, ByRef procid As Integer) As UInteger

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Me.RichTextBox1.AppendText("Starting up at " & Now & vbCrLf)
    End Sub

    Private Sub GoingAway(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Deactivate, Me.LostFocus

        Dim hwnd As Integer = GetForegroundWindow()
        ' Note that process_id will be used as a ByRef argument
        ' and will be changed by GetWindowThreadProcessId
        Dim process_id As Integer = 1
        GetWindowThreadProcessId(hwnd, process_id)

        If (process_id <> 1) Then
            Dim appExePath As String = Process.GetProcessById(process_id).MainModule.FileName() 
            Me.RichTextBox1.AppendText("Lost focus at " & Now & " due to " & appExePath & vbCrLf)
        Else
            Me.RichTextBox1.AppendText("Lost focus due to unknown cause.")
        End If

    End Sub
14
harrymc

Der Hochstapler의 답변 에 영감을 얻어 필자는 64 비트 및 32 비트 프로세스와 함께 작동하며 Windows 7 또는 Windows 7에서 포커스 도용을 방지하는 DLL injector를 작성하기로 결정했습니다. 최신 : https://blade.sk/stay-focused/

작동 방식은 새로 생성 된 윈도우 (SetWinEventHook 사용)를 감시하고 Der Hochstapler의 것과 매우 비슷한 DLL을 이미 존재하지 않는 경우 윈도우 프로세스에 삽입하는 것입니다. DLL을 언로드하고 종료 할 때 원래 기능을 복원합니다.

내 테스트에서, 그것은 지금까지 아주 잘 작동합니다. 그러나이 문제는 SetForegroundWindow을 호출하는 앱보다 심층적 인 것으로 보입니다. 예를 들어 새 창을 만들면 자동으로 포 그라운드로 가져와 사용자가 다른 창에 입력하는 것을 방해합니다.

초점을 도용하는 다른 방법을 다루려면 더 많은 테스트가 필요하며 시나리오가 발생하는 경우 이에 대한 피드백을 보내 주시면 감사하겠습니다.

2
blade

Ghacks는 가능한 해결책을 가지고 있습니다 :

하루에 여러 번 발생하여 일부 응용 프로그램이 활성 창의 초점을 훔쳐서 훔치는 경우가 있습니다. 이것은 파일을 추출하거나 예를 들어 전송이 완료되는 여러 가지 이유로 발생할 수 있습니다. 이 일이 일어날 때가 대부분의 경우 중요하지 않지만 때로는 기사를 쓰는 중이며 일부 단어를 다시 입력해야한다는 것뿐만 아니라 집중력을 잃어서 다시 초점을 맞추기 위해 클릭해야한다는 것을 의미하지는 않습니다.

Pro Reviewer 웹 사이트에는 이런 일이 발생하지 않도록하는 방법에 대한 팁이 있습니다. 초점 도용을 방지하는 가장 쉬운 방법은 "응용 프로그램이 포커스를 도용하지 못하게 방지"라는 설정이있는 Tweak UI를 사용하는 것입니다. 이 옵션을 선택하면 다른 응용 프로그램이 갑자기 팝업되어 현재 작업하고있는 창의 초점을 훔칠 수 없습니다.

이것은 응용 프로그램이 이전에 최소화 된 경우에만 작동합니다 . 초점을 도용하는 대신 여러 번 깜박입니다 Tweak UI에서 동일한 메뉴에 정의 할 수 있습니다 . Tweak UI를 사용하지 않으려는 경우 Windows 레지스트리에서 설정을 변경할 수 있습니다.

레지스트리 키 HKEY_CURRENT_USER> 제어판> 데스크톱으로 이동하여 ForegroundLockTimeout 값을 30d40 (16 진수) 또는 200000 (10 진수)으로 변경합니다. ForeGroundFlashCount 키는 0을 무제한으로 의미하는 사용자에게 알리는 창 깜박임 양을 정의합니다.

2
Ivo Flipse

프로그래밍 방식으로 활성화, 최대화 및 다른 프로세스에서 해당 프로세스의 주 창에 포커스를 후 TaskBar 새로 활성화 된 대상 창이 깜박임 중지하는 방법을 알아 냈습니다. 우선이 작업이 허용 될지 여부에 많은 제한이 있습니다.

"시스템은 전경 윈도우를 설정할 수있는 프로세스를 제한합니다. 프로세스는 다음 조건 중 하나에 해당하는 경우에만 전경 윈도우를 설정할 수 있습니다.

  • 프로세스는 포 그라운드 프로세스입니다.
  • 프로세스는 포 그라운드 프로세스에 의해 시작되었습니다.
  • 프로세스가 마지막 입력 이벤트를 수신했습니다.
  • 전경 과정이 없습니다.
  • 포 그라운드 프로세스가 디버깅 중입니다.
  • 전경이 잠겨 있지 않습니다 (LockSetForegroundWindow 참조).
  • 전경 잠금 시간 제한이 만료되었습니다 (SystemParametersInfo의 SPI_GETFOREGROUNDLOCKTIMEOUT 참조).
  • 활성화 된 메뉴가 없습니다.

https://docs.Microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-allowsetforegroundwindow

따라서 제어 프로세스가 포어 그라운드에 있으면 일시적으로 다른 프로세스를 활성화 할 수 있습니다 AllowSetForegroundWindow 를 대상 프로세스의 프로세스 ID 와 호출하여 전경을 완전히 훔칠 수 있습니다. 그런 다음 대상 프로세스는 자체 창 핸들을 사용하여 SetForegroundWindow 자체를 호출 할 수 있으며 작동합니다.

분명히 이것은 두 프로세스 간의 조정이 필요하지만 작동하며 모든 Explorer 클릭을 리디렉션하는 단일 인스턴스 응용 프로그램 을 구현하기 위해이 작업을 수행하는 경우 기존 앱 인스턴스로 시작하면 어쨌든 명명 된 파이프가 이미있을 것입니다.

0
Glenn Slayden