2012-10-27 2 views
1

외부 응용 프로그램이 종료되었을 때 경고를 받으려고합니다. 내 테스트를 위해 메모장의 hwnd를 검색하여 모니터에 설정했습니다. 이상하게도 메모장이 닫히지 않았는데도 메모장에서 다른 응용 프로그램을 클릭 할 때마다 시스템 이벤트가 발생합니다. 왜 아무 생각 없어?EVENT_OBJECT_DESTROY 메모장에서 초점을 잃었습니까?

몇 가지 빠른 예를 호출하는 코드 :

uint EVENT_OBJECT_DESTROY = 0x8001; 
IntPtr notepadHwnd = <your pointer> 
var mon = new WindowMonitor(notepadHwnd, EVENT_OBJECT_DESTROY); 
mon.EventOccurred += (sender, args) => Console.WriteLine("closed"); 

모니터 :

public class WindowMonitor : IDisposable 
    { 
    //store delegate to prevent GC 
    private User32.WinEventDelegate dEvent; 

    private IntPtr _hook; 
    private readonly IntPtr _window; 
    private readonly List<uint> _watchedEvents = new List<uint>(); 

    public event EventHandler<AccessibleEventTypeEventArgs> EventOccurred; 

    public WindowMonitor(IntPtr windowToMonitor, params User32.AccessibleEventType[] eventsToMonitor) 
    { 
     //prevent junk 
     if (eventsToMonitor == null || eventsToMonitor.Length == 0) 
     throw new ArgumentNullException("eventsToMonitor", "Must specify events to monitor"); 
     if (windowToMonitor == IntPtr.Zero) 
     throw new ArgumentNullException("windowToMonitor", "Must specify a valid window handle to monitor"); 

     _window = windowToMonitor; 

     //cast them now so we dont have to cast each one when evaluting events 
     uint lowest = (uint) User32.AccessibleEventType.EVENT_MAX; 
     uint highest = (uint) User32.AccessibleEventType.EVENT_MIN; 
     foreach (User32.AccessibleEventType eventType in eventsToMonitor) 
     { 
     var castType = (uint) eventType; 
     _watchedEvents.Add(castType); 

     //need the range of events to subscribe to 
     if (castType > highest) 
      highest = castType; 
     if (castType < lowest) 
      lowest = castType; 
     } 

     //sign up for the event 
     dEvent = this.winEvent; 
     _hook = User32.SetWinEventHook(lowest, highest, IntPtr.Zero, dEvent, 0, 0, User32.WINEVENT_OUTOFCONTEXT); 

     //ensure it worked 
     if (IntPtr.Zero.Equals(_hook)) throw new Win32Exception(); 

     //no kill callback 
     GC.KeepAlive(dEvent); 
    } 

    private void winEvent(IntPtr hWinEventHook, uint eventType, IntPtr hWnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime) 
    { 
     //only care about the events for the specified window 
     if (hWnd != _window) 
     return; 

     if (_watchedEvents.Contains(eventType)) 
     { 
     if (EventOccurred != null) 
      EventOccurred(this, new AccessibleEventTypeEventArgs((User32.AccessibleEventType) eventType)); 
     } 
    } 

    public void Dispose() 
    { 
     //unhook the listener 
     if (!IntPtr.Zero.Equals(_hook)) 
     User32.UnhookWinEvent(_hook); 

     //clear variables 
     _hook = IntPtr.Zero; 
     dEvent = null; 

     //kill any event listeners 
     EventOccurred = null; 

     GC.SuppressFinalize(this); 
    } 
    } 

일부 WINAPI (내가 이벤트 consts의 목록을 생략) : 당신은

public delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, 
    int idObject, int idChild, uint dwEventThread, uint dwmsEventTime); 

[DllImport("user32.dll")] 
public static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, 
    WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags); 

[DllImport("user32.dll")] 
public static extern bool UnhookWinEvent(IntPtr hWinEventHook); 

답변

1

을 아마 캐럿에 대한 이벤트를 볼 수 있습니다. winevent가 생기면 일반적으로 HWND idObject를 확인하여 실제로 관심있는 창의 일부분에 대한 이벤트인지 확인해야합니다. 창 자체 (OBJID_WINDOW) 또는 스크롤 바, 캐럿 또는 다른 것과 같은 일부 다른 측면.

포도주를 디버깅하려면 Accessible Event Watcher tool을 확인하십시오 - 모드 메뉴 및 모드/설정에서 WinEvents를 수신하도록 구성하십시오. 예를 들어 원하는 이벤트를 선택하십시오. EVENT_OBJECT_DESTROY 및 표시 할 이벤트 정보 (일반적으로 hwnd, idObject 및 idChild).

- 그런데

, 당신의 코드에 한 의견은 : 당신은 단지 특정 창에서 이벤트를 찾고 있다면, 그 윈도우의 스레드 (GetWindowThreadProcessId)를 얻고, 그와 함께 SetWinEventHook를 사용하는 것이 더 효율적입니다 idThread는 0을 전달하여 모든 스레드를 수신하는 대신 해당 특정 스레드에서만 이벤트를 가져옵니다. 이렇게하면 Win32가 이벤트 원본에서 필터링을 수행하므로 전체 데스크톱의 모든 스레드에서 해당 유형의 이벤트를 가져 오는 것보다 효율적이며 필요하지 않은 이벤트는 무시합니다.

+0

당신은 캐럿에 대해 정확히 맞았습니다. 또한 idThread에 대한 팁을 주셔서 감사합니다. 확실히 도움이되었습니다. –

관련 문제