Domanda

I am writing an application that makes some changes to a selected window. I am trying to to figure out how to get the HWND of a window selected after a button press in c#.

The flow would be something like:

The user presses a form button that says select window, the form hides itself as to not allow the selection of itself, the user clicks in another window on the desktop, this can be any application, the form reappears and gathers the HWND of the selected window, the program uses the HWND to do its business.

The part I don't know how to do is get which window was selected.

Any help would be greatly appreciated!

È stato utile?

Soluzione

The 'classic' way to do something like this - as used by Spy++ and various other apps that allow you to select a piece of UI to examine or work with - goes something like: (This is written from a C++/Win32 API point of view, but most steps have .Net equivalents except for WindowFromPoint and GetAncestor)

  • Have some piece of UI that displays a crosshair, and which responds to WM_LBUTTONDOWN/Control.MouseDown
  • When it gets a mouse click,
    • Use SetCapture/Control.Capture to 'capture' the mouse: This is the magic part that causes your HWND to receive all further mouse movement events so long as the left button remains pressed. (This means you don't need a hook or similar.),
    • Use SetCursor to set the cursor to something suitable, such as crosshairs.
    • Set a flag somewhere so you can tell the mouse move events you're about to get during the drag/capture apart from mouse move events you'd get if the user just moved the mouse over your control normally.
  • Now when the user moves the crosshair pointer across the screen, you'll get WM_MOUSEMOVE/Control.MouseMove events - check the flag you set earlier to ensure this is during 'dragging'. Use ClientToScreen/Control.PointToScreen to get screen coordinates from the control-relative coords in the move event, WindowFromPoint to get the child-most window at that position, and GetAncestor(GA_ROOT) to get the top-level window. Perhaps check if the window has WS_CAPTION set to ensure it's a window with a titlebar, if you care about that. (You'll probably also want to filter out the taskbar and desktop windows too.) You can also use APIs like GetWindowThreadProcessID to filter out windows from your own process. If the HWND is a viable candidate, save it away somewhere. If you have some UI still present, you could even use GetWindowText to get the title and/or other details of the window and provide live feedback about which window is potentially selected as the user drags.
  • When the user releases the mouse position, you'll get WM_LBUTTONUP/Control.MouseUp - the user has finished dragging. ReleaseCapture, put the icon and cursor back to the way they were before the user pressed the mouse, and then go on and use the saved HWND - if any.

It's also considered polite to also handle ESC during dragging to cancel the operation.

Also, the above isn't keyboard-friendly; it's also a good idea to use say RegisterHotkey with some hotkey either permanently during the lifetime of your app or just when the selection dialog is present, and respond to the hotkey by using GetForegroundWindow() as mentioned in the other replies.

Altri suggerimenti

One option is to poll the GetForegroundWindow API until the HWND changes to another window.

One approach is

  • Add a global mouse event handler to your application
  • Minimize your application
  • When your global event handler detects a mouse click:
  • Call GetForegroundWindow()
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top