// ------------------------------------------------------ // // Internal Methods // // ------------------------------------------------------ // Update the Array of hwnd requesting notifications // Param name="hwnd" // Param name="raiseEvents" - function to call to create a raw element // Param name="aEvtIdProp" // Param name="cProps" - Number of valid props in the array static internal void AddToNotificationList (IntPtr hwnd, ProxyRaiseEvents raiseEvents, EvtIdProperty[] aEvtIdProp, int cProps) { GetCallbackQueue(); // Build the list of Event to Window List BuildEventsList (EventFlag.Add, hwnd, raiseEvents, aEvtIdProp, cProps); }
// Update the Array of hwnd requesting notifications // eFlag - Add or Remove // hwnd // raiseEvents - function to call to create a raw element // aEvtIdProp - Array of Tupples WinEvent and Automation properties // cProps - Number of valid props in the array private static void BuildEventsList(EventFlag eFlag, IntPtr hwnd, ProxyRaiseEvents raiseEvents, EvtIdProperty[] aEvtIdProp, int cProps) { // All operations in the list of events and windows handle must be atomic lock (_ahp) { for (int i = 0; i < cProps; i++) { EvtIdProperty evtIdProp = aEvtIdProp[i]; // Map a property into a WinEventHookProperty int evt = Array.BinarySearch(_eventIdToIndex, evtIdProp._evtId); // add the window to the list if (evt >= 0) { EventHookParams hookParams = null; uint processId; if (hwnd == IntPtr.Zero) { // if its a global event use this well known key to the hash processId = _globalEventKey; } else { if (Misc.GetWindowThreadProcessId(hwnd, out processId) == 0) { processId = _globalEventKey; } } // If never seens this EventId before. Create the notification object if (_ahp[evt] == null) { // create the hash table the key is the process id _ahp[evt] = new Hashtable(10); } // Find the EventHookParams. // _ahp is an array of Hashtables where each Hashtable corrasponds to one event. // Get the correct Hashtable using the index evt. Then lookup the EventHookParams // in the hash table, using the process id. hookParams = (EventHookParams)_ahp[evt][processId]; // If there is not an entry for the event for the specified process then create one. if (hookParams == null) { hookParams = new EventHookParams(); hookParams._process = processId; _ahp[evt].Add(processId, hookParams); } ArrayList eventCreateParams = hookParams._alHwnd; if (eFlag == EventFlag.Add) { if (eventCreateParams == null) { // empty array, create the hwnd arraylist hookParams._evtId = evtIdProp._evtId; eventCreateParams = hookParams._alHwnd = new ArrayList(16); } // Check if the event for that window already exist. // Discard it as no dups are allowed for (int index = eventCreateParams.Count - 1; index >= 0; index--) { EventCreateParams ecp = (EventCreateParams)eventCreateParams[index]; // Code below will discard duplicates: // Proxy cannot subscribe same hwnd to the same event more than once // However proxy can be globaly registered to be always notified of some event, in order to // do this proxy will send IntPtr.Zero as hwnd. Please notice that a given Proxy can be globaly registered // to some EVENT_XXX only once. This will be ensured via delegate comparison. if ((hwnd == IntPtr.Zero || ecp._hwnd == hwnd) && ecp._idProp == evtIdProp._idProp && ecp._raiseEventFromRawElement == raiseEvents) { return; } } // Set the WinEventHook if first time around if (eventCreateParams.Count == 0) { _callbackQueue.PostSyncWorkItem(new QueueItem.WinEventItem(ref hookParams, _startDelegate)); } // add the event into the list // Called after the Post does not matter because of the lock eventCreateParams.Add(new EventCreateParams(hwnd, evtIdProp._idProp, raiseEvents)); } else { if (eventCreateParams == null) { return; } // Remove a notification // Go through the list of window to find the one for (int index = eventCreateParams.Count - 1; index >= 0; index--) { EventCreateParams ecp = (EventCreateParams)eventCreateParams[index]; // Detect if caller should be removed from notification list bool remove = false; if (raiseEvents == null) { // Not a global wide events remove = (ecp._hwnd == hwnd && ecp._idProp == evtIdProp._idProp); } else { // Global events Debug.Assert(hwnd == IntPtr.Zero, @"BuildEventsList: event is global but hwnd is not null"); remove = (ecp._hwnd == hwnd && ecp._raiseEventFromRawElement == raiseEvents); } if (remove) { eventCreateParams.RemoveAt(index); // if empty then stop listening for this event arg if (eventCreateParams.Count == 0) { _callbackQueue.PostSyncWorkItem(new QueueItem.WinEventItem(ref hookParams, _stopDelegate)); _ahp[evt].Remove(processId); } break; } } } } } } }
// Update the Array of hwnd requesting notifications calling the main routine // Param name="hwnd" // Param name="raiseEvents" - Callback, should be null for non system-wide events // Param name="aEvtIdProp" // Param name="cProps" - Number of valid props in the array static internal void RemoveToNotificationList (IntPtr hwnd, EvtIdProperty[] aEvtIdProp, ProxyRaiseEvents raiseEvents, int cProps) { // Remove the list of Event to Window List // NOTE: raiseEvents must be null in the case when event is not a system-wide event BuildEventsList (EventFlag.Remove, hwnd, raiseEvents, aEvtIdProp, cProps); }
// Update the Array of hwnd requesting notifications // eFlag - Add or Remove // hwnd // raiseEvents - function to call to create a raw element // aEvtIdProp - Array of Tupples WinEvent and Automation properties // cProps - Number of valid props in the array private static void BuildEventsList (EventFlag eFlag, IntPtr hwnd, ProxyRaiseEvents raiseEvents, EvtIdProperty[] aEvtIdProp, int cProps) { // All operations in the list of events and windows handle must be atomic lock (_ahp) { for (int i = 0; i < cProps; i++) { EvtIdProperty evtIdProp = aEvtIdProp[i]; // Map a property into a WinEventHookProperty int evt = Array.BinarySearch (_eventIdToIndex, evtIdProp._evtId); // add the window to the list if (evt >= 0) { EventHookParams hookParams = null; uint processId; if (hwnd == IntPtr.Zero) { // if its a global event use this well known key to the hash processId = _globalEventKey; } else { if (Misc.GetWindowThreadProcessId(hwnd, out processId) == 0) { processId = _globalEventKey; } } // If never seens this EventId before. Create the notification object if (_ahp[evt] == null) { // create the hash table the key is the process id _ahp[evt] = new Hashtable(10); } // Find the EventHookParams. // _ahp is an array of Hashtables where each Hashtable corrasponds to one event. // Get the correct Hashtable using the index evt. Then lookup the EventHookParams // in the hash table, using the process id. hookParams = (EventHookParams)_ahp[evt][processId]; // If there is not an entry for the event for the specified process then create one. if (hookParams == null) { hookParams = new EventHookParams(); hookParams._process = processId; _ahp[evt].Add(processId, hookParams); } ArrayList eventCreateParams = hookParams._alHwnd; if (eFlag == EventFlag.Add) { if (eventCreateParams == null) { // empty array, create the hwnd arraylist hookParams._evtId = evtIdProp._evtId; eventCreateParams = hookParams._alHwnd = new ArrayList (16); } // Check if the event for that window already exist. // Discard it as no dups are allowed for (int index = eventCreateParams.Count - 1; index >= 0; index--) { EventCreateParams ecp = (EventCreateParams)eventCreateParams[index]; // Code below will discard duplicates: // Proxy cannot subscribe same hwnd to the same event more than once // However proxy can be globaly registered to be always notified of some event, in order to // do this proxy will send IntPtr.Zero as hwnd. Please notice that a given Proxy can be globaly registered // to some EVENT_XXX only once. This will be ensured via delegate comparison. if ( (hwnd == IntPtr.Zero || ecp._hwnd == hwnd) && ecp._idProp == evtIdProp._idProp && ecp._raiseEventFromRawElement == raiseEvents) { return; } } // Set the WinEventHook if first time around if (eventCreateParams.Count == 0) { _callbackQueue.PostSyncWorkItem (new QueueItem.WinEventItem (ref hookParams, _startDelegate)); } // add the event into the list // Called after the Post does not matter because of the lock eventCreateParams.Add (new EventCreateParams (hwnd, evtIdProp._idProp, raiseEvents)); } else { if ( eventCreateParams == null ) return; // Remove a notification // Go through the list of window to find the one for (int index = eventCreateParams.Count - 1; index >= 0; index--) { EventCreateParams ecp = (EventCreateParams)eventCreateParams[index]; // Detect if caller should be removed from notification list bool remove = false; if (raiseEvents == null) { // Not a global wide events remove = (ecp._hwnd == hwnd && ecp._idProp == evtIdProp._idProp); } else { // Global events Debug.Assert (hwnd == IntPtr.Zero, @"BuildEventsList: event is global but hwnd is not null"); remove = (ecp._hwnd == hwnd && ecp._raiseEventFromRawElement == raiseEvents); } if (remove) { eventCreateParams.RemoveAt (index); // if empty then stop listening for this event arg if (eventCreateParams.Count == 0) { _callbackQueue.PostSyncWorkItem (new QueueItem.WinEventItem (ref hookParams, _stopDelegate)); _ahp[evt].Remove(processId); } break; } } } } } } }