using System; using System.Runtime.InteropServices; namespace Common.Native { public class WinEvent { public enum Event { Min = 0x00000001, Max = 0x7FFFFFFF, /* * EVENT_SYSTEM_SOUND * Sent when a sound is played. Currently nothing is generating this, we * this event when a system sound (for menus, etc) is played. Apps * generate this, if accessible, when a private sound is played. For * example, if Mail plays a "New Mail" sound. * * System Sounds: * (Generated by PlaySoundEvent in USER itself) * hwnd is NULL * idObject is OBJID_SOUND * idChild is sound child ID if one * App Sounds: * (PlaySoundEvent won't generate notification; up to app) * hwnd + idObject gets interface pointer to Sound object * idChild identifies the sound in question * are going to be cleaning up the SOUNDSENTRY feature in the control panel * and will use this at that time. Applications implementing WinEvents * are perfectly welcome to use it. Clients of IAccessible* will simply * turn around and get back a non-visual object that describes the sound. */ SystemSound = 0x0001, /* * EVENT_SYSTEM_ALERT * System Alerts: * (Generated by MessageBox() calls for example) * hwnd is hwndMessageBox * idObject is OBJID_ALERT * App Alerts: * (Generated whenever) * hwnd+idObject gets interface pointer to Alert */ SystemAlert = 0x0002, /* * EVENT_SYSTEM_FOREGROUND * Sent when the foreground (active) window changes, even if it is changing * to another window in the same thread as the previous one. * hwnd is hwndNewForeground * idObject is OBJID_WINDOW * idChild is INDEXID_OBJECT */ SystemForeground = 0x0003, /* * Menu * hwnd is window (top level window or popup menu window) * idObject is ID of control (OBJID_MENU, OBJID_SYSMENU, OBJID_SELF for popup) * idChild is CHILDID_SELF * * EVENT_SYSTEM_MENUSTART * EVENT_SYSTEM_MENUEND * For MENUSTART, hwnd+idObject+idChild refers to the control with the menu bar, * or the control bringing up the context menu. * * Sent when entering into and leaving from menu mode (system, app bar, and * track popups). */ SystemMenuStart = 0x0004, SystemMenuEnd = 0x0005, /* * EVENT_SYSTEM_MENUPOPUPSTART * EVENT_SYSTEM_MENUPOPUPEND * Sent when a menu popup comes up and just before it is taken down. Note * that for a call to TrackPopupMenu(), a client will see EVENT_SYSTEM_MENUSTART * followed almost immediately by EVENT_SYSTEM_MENUPOPUPSTART for the popup * being shown. * * For MENUPOPUP, hwnd+idObject+idChild refers to the NEW popup coming up, not the * parent item which is hierarchical. You can get the parent menu/popup by * asking for the accParent object. */ SystemMenuPopupStart = 0x0006, SystemMenuPopupEnd = 0x0007, /* * EVENT_SYSTEM_CAPTURESTART * EVENT_SYSTEM_CAPTUREEND * Sent when a window takes the capture and releases the capture. */ SystemCaptureStart = 0x0008, SystemCaptureEnd = 0x0009, /* * Move Size * EVENT_SYSTEM_MOVESIZESTART * EVENT_SYSTEM_MOVESIZEEND * Sent when a window enters and leaves move-size dragging mode. */ SystemMoveSizeStart = 0x000A, SystemMoveSizeEnd = 0x000B, /* * Context Help * EVENT_SYSTEM_CONTEXTHELPSTART * EVENT_SYSTEM_CONTEXTHELPEND * Sent when a window enters and leaves context sensitive help mode. */ SystemContextHelpStart = 0x000C, EventSystemContextHelpEnd = 0x000D, /* * Drag & Drop * EVENT_SYSTEM_DRAGDROPSTART * EVENT_SYSTEM_DRAGDROPEND * Send the START notification just before going into drag&drop loop. Send * the END notification just after canceling out. * Note that it is up to apps and OLE to generate this, since the system * doesn't know. Like EVENT_SYSTEM_SOUND, it will be a while before this * is prevalent. */ SystemDragDropStart = 0x000E, SystemDragdropEnd = 0x000F, /* * Dialog * Send the START notification right after the dialog is completely * initialized and visible. Send the END right before the dialog * is hidden and goes away. * EVENT_SYSTEM_DIALOGSTART * EVENT_SYSTEM_DIALOGEND */ SystemDialogStart = 0x0010, SystemDialogEnd = 0x0011, /* * EVENT_SYSTEM_SCROLLING * EVENT_SYSTEM_SCROLLINGSTART * EVENT_SYSTEM_SCROLLINGEND * Sent when beginning and ending the tracking of a scrollbar in a window, * and also for scrollbar controls. */ SystemScrollingStart = 0x0012, SystemScrollingEnd = 0x0013, /* * Alt-Tab Window * Send the START notification right after the switch window is initialized * and visible. Send the END right before it is hidden and goes away. * EVENT_SYSTEM_SWITCHSTART * EVENT_SYSTEM_SWITCHEND */ SystemSwitchStart = 0x0014, SystemSwitchEnd = 0x0015, /* * EVENT_SYSTEM_MINIMIZESTART * EVENT_SYSTEM_MINIMIZEEND * Sent when a window minimizes and just before it restores. */ SystemMinimizeStart = 0x0016, SystemMinimizeEnd = 0x0017, SystemDesktopSwitch = 0x0020, EventSystemEnd = 0x00FF, OemDefinedStart = 0x0101, OemDefinedEnd = 0x01FF, UiaEventIdStart = 0x4E00, UiaEventIdEnd = 0x4EFF, UiaPropIdStart = 0x7500, UiaPropIdEnd = 0x75FF, ConsoleCaret = 0x4001, ConsoleUpdateRegion = 0x4002, ConsoleUpdateSimple = 0x4003, ConsoleUpdateScroll = 0x4004, ConsoleLayout = 0x4005, ConsoleStartApplication = 0x4006, ConsoleEndApplication = 0x4007, ConsoleEnd = 0x40FF, /* * Object events * * The system AND apps generate these. The system generates these for * real windows. Apps generate these for objects within their window which * act like a separate control, e.g. an item in a list view. * * When the system generate them, dwParam2 is always WMOBJID_SELF. When * apps generate them, apps put the has-meaning-to-the-app-only ID value * in dwParam2. * For all events, if you want detailed accessibility information, callers * should * * Call AccessibleObjectFromWindow() with the hwnd, idObject parameters * of the event, and IID_IAccessible as the REFIID, to get back an * IAccessible* to talk to * * Initialize and fill in a VARIANT as VT_I4 with lVal the idChild * parameter of the event. * * If idChild isn't zero, call get_accChild() in the container to see * if the child is an object in its own right. If so, you will get * back an IDispatch* object for the child. You should release the * parent, and call QueryInterface() on the child object to get its * IAccessible*. Then you talk directly to the child. Otherwise, * if get_accChild() returns you nothing, you should continue to * use the child VARIANT. You will ask the container for the properties * of the child identified by the VARIANT. In other words, the * child in this case is accessible but not a full-blown object. * Like a button on a titlebar which is 'small' and has no children. */ /* * For all EVENT_OBJECT events, * hwnd is the dude to Send the WM_GETOBJECT message to (unless NULL, * see above for system things) * idObject is the ID of the object that can resolve any queries a * client might have. It's a way to deal with windowless controls, * controls that are just drawn on the screen in some larger parent * window (like SDM), or standard frame elements of a window. * idChild is the piece inside of the object that is affected. This * allows clients to access things that are too small to have full * blown objects in their own right. Like the thumb of a scrollbar. * The hwnd/idObject pair gets you to the container, the dude you * probably want to talk to most of the time anyway. The idChild * can then be passed into the acc properties to get the name/value * of it as needed. * * Example #1: * System propagating a listbox selection change * EVENT_OBJECT_SELECTION * hwnd == listbox hwnd * idObject == OBJID_WINDOW * idChild == new selected item, or CHILDID_SELF if * nothing now selected within container. * Word '97 propagating a listbox selection change * hwnd == SDM window * idObject == SDM ID to get at listbox 'control' * idChild == new selected item, or CHILDID_SELF if * nothing * * Example #2: * System propagating a menu item selection on the menu bar * EVENT_OBJECT_SELECTION * hwnd == top level window * idObject == OBJID_MENU * idChild == ID of child menu bar item selected * * Example #3: * System propagating a dropdown coming off of said menu bar item * EVENT_OBJECT_CREATE * hwnd == popup item * idObject == OBJID_WINDOW * idChild == CHILDID_SELF * * Example #4: * * For EVENT_OBJECT_REORDER, the object referred to by hwnd/idObject is the * PARENT container in which the zorder is occurring. This is because if * one child is zordering, all of them are changing their relative zorder. */ ObjectCreate = 0x8000, // hwnd + ID + idChild is created item ObjectDestroy = 0x8001, // hwnd + ID + idChild is destroyed item ObjectShow = 0x8002, // hwnd + ID + idChild is shown item ObjectHide = 0x8003, // hwnd + ID + idChild is hidden item ObjectReorder = 0x8004, // hwnd + ID + idChild is parent of zordering children /* * NOTE: * Minimize the number of notifications! * * When you are hiding a parent object, obviously all child objects are no * longer visible on screen. They still have the same "visible" status, * but are not truly visible. Hence do not send HIDE notifications for the * children also. One implies all. The same goes for SHOW. */ ObjectFocus = 0x8005, // hwnd + ID + idChild is focused item ObjectSelection = 0x8006, // hwnd + ID + idChild is selected item (if only one), or idChild is OBJID_WINDOW if complex ObjectSelectionAdd = 0x8007, // hwnd + ID + idChild is item added ObjectSelectionRemove = 0x8008, // hwnd + ID + idChild is item removed ObjectSelectionWithin = 0x8009, // hwnd + ID + idChild is parent of changed selected items /* * NOTES: * There is only one "focused" child item in a parent. This is the place * keystrokes are going at a given moment. Hence only send a notification * about where the NEW focus is going. A NEW item getting the focus already * implies that the OLD item is losing it. * * SELECTION however can be multiple. Hence the different SELECTION * notifications. Here's when to use each: * * (1) Send a SELECTION notification in the simple single selection * case (like the focus) when the item with the selection is * merely moving to a different item within a container. hwnd + ID * is the container control, idChildItem is the new child with the * selection. * * (2) Send a SELECTIONADD notification when a new item has simply been added * to the selection within a container. This is appropriate when the * number of newly selected items is very small. hwnd + ID is the * container control, idChildItem is the new child added to the selection. * * (3) Send a SELECTIONREMOVE notification when a new item has simply been * removed from the selection within a container. This is appropriate * when the number of newly selected items is very small, just like * SELECTIONADD. hwnd + ID is the container control, idChildItem is the * new child removed from the selection. * * (4) Send a SELECTIONWITHIN notification when the selected items within a * control have changed substantially. Rather than propagate a large * number of changes to reflect removal for some items, addition of * others, just tell somebody who cares that a lot happened. It will * be faster an easier for somebody watching to just turn around and * query the container control what the new bunch of selected items * are. */ ObjectStateChange = 0x800A, // hwnd + ID + idChild is item w/ state change /* * Examples of when to send an EVENT_OBJECT_STATECHANGE include * * It is being enabled/disabled (USER does for windows) * * It is being pressed/released (USER does for buttons) * * It is being checked/unchecked (USER does for radio/check buttons) */ ObjectLocationChange = 0x800B, // hwnd + ID + idChild is moved/sized item /* * Note: * A LOCATIONCHANGE is not sent for every child object when the parent * changes shape/moves. Send one notification for the topmost object * that is changing. For example, if the user resizes a top level window, * USER will generate a LOCATIONCHANGE for it, but not for the menu bar, * title bar, scrollbars, etc. that are also changing shape/moving. * * In other words, it only generates LOCATIONCHANGE notifications for * real windows that are moving/sizing. It will not generate a LOCATIONCHANGE * for every non-floating child window when the parent moves (the children are * logically moving also on screen, but not relative to the parent). * * Now, if the app itself resizes child windows as a result of being * sized, USER will generate LOCATIONCHANGEs for those dudes also because * it doesn't know better. * * Note also that USER will generate LOCATIONCHANGE notifications for two * non-window sys objects: * (1) System caret * (2) Cursor */ ObjectNameChange = 0x800C, // hwnd + ID + idChild is item w/ name change ObjectDescriptionChange = 0x800D, // hwnd + ID + idChild is item w/ desc change ObjectValueChange = 0x800E, // hwnd + ID + idChild is item w/ value change ObjectParentChange = 0x800F, // hwnd + ID + idChild is item w/ new parent ObjectHelpChange = 0x8010, // hwnd + ID + idChild is item w/ help change ObjectDefaultActionChange = 0x8011, // hwnd + ID + idChild is item w/ def action change ObjectAcceleratorChange = 0x8012, // hwnd + ID + idChild is item w/ keybd accel change ObjectInvoked = 0x8013, // hwnd + ID + idChild is item invoked ObjectTextSelectionChanged = 0x8014, // hwnd + ID + idChild is item w? test selection change /* * EVENT_OBJECT_CONTENTSCROLLED * Sent when ending the scrolling of a window object. * * Unlike the similar event (EVENT_SYSTEM_SCROLLEND), this event will be * associated with the scrolling window itself. There is no difference * between horizontal or vertical scrolling. * * This event should be posted whenever scroll action is completed, including * when it is scrolled by scroll bars, mouse wheel, or keyboard navigations. * * example: * hwnd == window that is scrolling * idObject == OBJID_CLIENT * idChild == CHILDID_SELF */ ObjectContentScrolled = 0x8015, SystemArrangmentPreview = 0x8016, ObjectEnd = 0x80FF, AiaStart = 0xA000, AiaEnd = 0xAFFF } public enum ObjectIdentifier : uint { Window = 0x00000000, SystemMenu = 0xFFFFFFFF, TitleBar = 0xFFFFFFFE, Menu = 0xFFFFFFFD, Client = 0xFFFFFFFC, VerticalScroll = 0xFFFFFFFB, HorizontalScroll = 0xFFFFFFFA, SizeGrip = 0xFFFFFFF9, Caret = 0xFFFFFFF8, Cursor = 0xFFFFFFF7, Alert = 0xFFFFFFF6, Sound = 0xFFFFFFF5 } public enum ChildIdentifier { Self = 0 } [Flags] public enum SetWinEventHookFlags : uint { OutOfContext = 0x0000, // Events are ASYNC SkipOwnThread = 0x0001, // Don't call back for events on installer's thread SkipOwnProcess = 0x0002, // Don't call back for events on installer's process InContext = 0x0004, // Events are SYNC, this causes your dll to be injected into every process } public delegate void WinEventDelegate(IntPtr hWinEventHook, Event eventType, IntPtr hwnd, ObjectIdentifier idObject, int idChild, uint dwEventThread, uint dwmsEventTime); [DllImport("user32.dll")] public static extern IntPtr SetWinEventHook(Event eventMin, Event eventMax, IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, SetWinEventHookFlags dwFlags); [DllImport("user32.dll")] public static extern bool UnhookWinEvent(IntPtr hWinEventHook); } }