8

I have seen several tools adding a custom button and/or drawing on the title bar of all windows of all applications in Windows. How is that done? Extra points for an example in Delphi.

EDIT: I found something for dotNET that does this: http://www.thecodeking.co.uk/2007/09/adding-caption-buttons-to-non-client.html#.VdmioEDenqQ

dummzeuch
  • 10,975
  • 4
  • 51
  • 158
  • Can you expand on "extra points"? You will award a bounty for someone who writes the code for you? As for these tools, why don't you find the source for one and work from that. And which versions of the OS do you hope to support. – David Heffernan Aug 17 '15 at 19:30
  • 2
    @DavidHeffernan It's a common phrase - "bonus points for..." just means, in this context, it would be ideal and the OP would be happy about it. And do you know any OS programs that do this? I don't. I've seen Skype, Chrome etc do - but I don't know of many others. If you know any maybe you can post what they are? – David Aug 17 '15 at 19:34
  • 1
    You're taking it too literally. It's just a figure of speech. I'd like to support Windows 8.x and Windows 10. – dummzeuch Aug 17 '15 at 19:35
  • So far as I know, you need to set up a custom title bar - ie you don't draw just a custom button, but custom everything, handing over to the OS to draw the elements where possible. See the fifth dot point in this answer: http://stackoverflow.com/questions/3822609/documentation-and-api-samples-for-drawing-on-windows-aero-glass-dwm-gdi-gdi/3826784#3826784 - a very useful blog post by Chris Rolliston – David Aug 17 '15 at 19:36
  • 1
    @DavidM The asker here wants to splat a button on all top level windows, even those in other processes. – David Heffernan Aug 17 '15 at 19:37
  • I know how to do that for the windows of my own programs, but I'd like to draw to the title of all programs. – dummzeuch Aug 17 '15 at 19:41
  • @DavidHeffernan I missed that, thanks. Some of those techniques might still be useful, but I don't know if that's how it's done. If I was writing something like this, I might try making the extra button really be a separate window that doesn't accept focus, and using Windows hooks to find all the messages moving the top-level windows to keep the "button" in the right place. – David Aug 17 '15 at 19:42
  • 2
    In general this won't work out well. What about windows that don't have a caption bar. Or draw their own. Or draw a button where you want yours. – David Heffernan Aug 17 '15 at 19:54
  • @DavidHeffernan AnVir Task Manager, for example, doing it well: [Additional controls on the window](http://picpaste.com/anvir1-GpJRPnls.png) and [additional buttons on the title and items in the window menu](http://picpaste.com/anvir2-07UD5Yha.png). So, theoretically, mission possible. – Abelisto Aug 17 '15 at 20:06
  • 1
    @Abelisto Windows that don't have a caption bar? Or two programs that both do the same as AnVir? Not going to work out. – David Heffernan Aug 17 '15 at 20:07
  • 2
    Give up. It fails the [What if two programs did this?](http://blogs.msdn.com/b/oldnewthing/archive/2005/06/07/426294.aspx) test. The caption bar is private to the application implementing it. It doesn't provide an extensibility interface. It's the moral equivalent of the old-style control subclassing. – IInspectable Aug 17 '15 at 20:21
  • TeamViewer have this button on every window and have elegant setting to avoid conflicts with other software: custom offset of the button. Need this code too – Alex Egorov Aug 17 '15 at 20:32
  • @IInspectable As I understand AnVir does not creates true caption bar button but creates small floating window which moved together with main window. Such trick allows to work with any window even without caption. How it works internally - it is another big question. However OP can start [here](https://msdn.microsoft.com/en-us/library/windows/desktop/ms632589(v=vs.85).aspx) and [here](https://msdn.microsoft.com/en-us/library/windows/desktop/ms644990(v=vs.85).aspx) (WH_SHELL and WH_CALLWNDPROC flags in our case) – Abelisto Aug 17 '15 at 20:36
  • @Abelisto: That doesn't help one bit. If two programs did this, both lose. And this still doesn't answer the question: **Where** should the floating window be located? The caption bar does not provide an extensibility interface. You have no means of knowing, which screen real estate your window can use, without obscuring anything important. – IInspectable Aug 17 '15 at 22:15
  • Which is where Microsoft needs to build-in such a feature for this to be truly feasible. Have Windows automatically arrange these buttons in a certain order. I doubt they'll make such a feature though, but who knows. I mean, look at the main menu in OS-X... – Jerry Dodge Aug 18 '15 at 03:08
  • You can setup the `WH_CALLWNDPROCRET` hook for `WM_NCPAINT` message (where you will draw your button) for every top-level visible window (whose creations you can trace by another hook). The similar you can do for mouse events. – TLama Sep 02 '15 at 11:16
  • Looks like the .Net article does it much as in my answer from earlier today, except it's process-local. My comment explains how to achieve the same thing for all processes. – David Sep 02 '15 at 17:01

2 Answers2

5

How I see this job:

  1. First of all we should be able to paint this button on the our own window caption. This procedure will be used later
  2. This part of the program enumerates the active and visible windows
  3. This part of the program using injection attach our dll to enumerated windows
  4. From injected dll we can draw the button on the window caption
  5. Inside this dll we should process the click on the button
  6. We should have mechanism to send result to our main program
Filip Roséen - refp
  • 62,493
  • 20
  • 150
  • 196
Alex Egorov
  • 907
  • 7
  • 26
3

I haven't done this, so the following is what I would investigate if I were to try:

  • For each application / each top-level window:
  • Create a floating window and position it over the title bar wherever you want it to sit. Set up the parent / child relationship, but this window is part of your own process. (There are occasionally problems parenting a window from one process to one from another process, but try. I'd avoid injecting into other processes if possible.)
  • You can investigate the window flags to see if the window has a title bar (ie if you should add a button) via GetWindowLong with GWL_STYLE looking for WS_CAPTION. The same call will also let you see the type of caption / frame, which you can combine with GetSystemMetrics with, eg, SM_CYDLGFRAME to figure out the right size for your button on this specific window's title bar.
  • This window is now your button: paint, handle clicks etc as appropriate.
  • Make it a non-focusable window so that clicks to it don't take focus away from the window is is on the title bar of. You don't want clicking it to make the title bar change colour, for example. Do this by setting the WS_EX_NOACTIVATE window flag, something like: SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) orWS_EX_NOACTIVATE).
  • The main problem is to keep it positioned correctly when the window moves, is resized, etc. To do this, install a hook for the system move events. You can also hook minimize and restore via EVENT_SYSTEM_MINIMIZESTART and EVENT_SYSTEM_MINIMIZEEND. This will allow you to keep track of all windows moving around onscreen, such that you can adjust the button-window position if necessary.

That gives you a window which you can paint as a button (and respond to clicks etc), that visually is "attached" to other windows so it stays in the same place as the user drags the title bar, minimizes or maximises the app, etc, and that is in your own process without cross-process problems.

Community
  • 1
  • 1
David
  • 13,360
  • 7
  • 66
  • 130