5

I want to write a Windows C++ application where the contents of the window is whatever is behind the window (as if the window is transparent). That is, I want to retrieve the bounding box of my window; capture those coordinates below, and draw them on my window. Therefore it is crucial that I can exclude the window itself during the capture.

"Why not just make the window transparent?" you ask. Because the next step for me is to make modifications to that image. I want to apply some arbitrary filters on it. For example, let's just say that I want to blur that image, so that my window looks like a frosted glass.

I tried to use the magnification API sample at https://code.msdn.microsoft.com/windowsdesktop/Magnification-API-Sample-14269fd2 which actually provides me the screen contents excluding my window. However, re-rendering the image is done in a timer, which causes a very jittery image; and I couldn't figure out how to retrieve and apply arbitrary transformations to that image.

I don't know where to start and really could use some pointers at this point. Sorry if I'm approaching this from a stupid perspective.

Edit: I am adding a mock-up of what I mean:

example

Edit 2: Just like in the magnification API example, view would be constantly refreshed (as frequently as possible, say every 16 ms just for argument's sake). See Visolve Deflector for an example; although it does not apply any effects on the captured region.

Again, I will be modifying the image data afterwards; therefore I cannot use the Magnification API's kernel matrix support.

kubuzetto
  • 1,046
  • 1
  • 12
  • 31
  • 2
    There's already an API for [blur effect](https://msdn.microsoft.com/en-us/library/windows/desktop/aa969537(v=vs.85).aspx). – rustyx Oct 01 '17 at 19:40
  • Blur effect was an example, I want to apply arbitrary transformations on the image. – kubuzetto Oct 01 '17 at 19:43
  • 2
    This does not seem very realistic as it would require intrusion into composition manager work (that is what mentioned magnification API seem to perform). Maybe hiding your window and making screenshot of whatever is behind to display as window content would be sufficient or you need to update it dynamically? – user7860670 Oct 01 '17 at 19:52
  • In that case would it be possible to retrieve the image using the magnification API, then reading the image data from the component? – kubuzetto Oct 01 '17 at 19:55
  • 1
    You don't need magnification API for screen shot. Just create a bitmap then `BitBlt` from desktop to that bitmap. See [example](https://stackoverflow.com/q/30092754/4603670) – Barmak Shemirani Oct 01 '17 at 23:56
  • Does this exclude the window from which I take the screenshot? Otherwise I cannot use this. – kubuzetto Oct 02 '17 at 04:40

3 Answers3

1

You can start by modifying MAGCOLOREFFECT . In MagnifierSample.cpp we have:

if (ret) 
{ 
    MAGCOLOREFFECT magEffectInvert =  
    {{ // MagEffectInvert 
        { -1.0f,  0.0f,  0.0f,  0.0f,  0.0f }, 
        {  0.0f, -1.0f,  0.0f,  0.0f,  0.0f }, 
        {  0.0f,  0.0f, -1.0f,  0.0f,  0.0f }, 
        {  0.0f,  0.0f,  0.0f,  1.0f,  0.0f }, 
        {  1.0f,  1.0f,  1.0f,  0.0f,  1.0f }  
    }}; 

    ret = MagSetColorEffect(hwndMag,&magEffectInvert); 
} 

Using a Color Matrix to Transform a Single Color.

For more advanced effects, you can blit contents to memory device context.

Daniel Sęk
  • 2,504
  • 1
  • 8
  • 17
  • I have seen that sample code, but I want to apply arbitrary transformations on the image. – kubuzetto Oct 02 '17 at 06:27
  • 1
    I would try to get control contents with WM_PRINTCLIENT. If you want to put modified image in magnifying control, subclass it and handle WM_PAINT. It could be a lot harder when it doesn't implement WM_PRINTCLIENT or paints outside WM_PAINT. – Daniel Sęk Oct 02 '17 at 08:20
  • Just to clarify, your suggestion is to use the magnification API anyway; then read the contents of `hwndMag` at every WM_PAINT event, then use the data to render on a second control; right? In that case, can I keep the first control be hidden from view (would it still get updated I mean)? – kubuzetto Oct 02 '17 at 10:41
  • 1
    Checked with Spy++, and WC_MAGNIFIER control contains child control "Hardware Magnifier" which contains Static Control so subclassing is problematic. To make it work you would have practically hack it with no guarantee that it would work on all systems. I assume that it is a wrong way. Somehow you have to recreate Magnification Api way, but I don't know how. Sometimes it flickers and windows bellow could be seen through it, so it probably removes itself from desktop for a short time. – Daniel Sęk Oct 02 '17 at 12:57
1

You did not specify if this is a one time activity or you need a continuous stream of whats behind your window (like Magnifier/etc). And if continuous, whats the frequency of updates you may need.

Anyway in either case I see two primary use cases:

  1. The contents behind your app are constant: You may not believe, but most of the time the contents behind your window will not change.
  2. The contents behind your window are changing/animating: this is a trickier case.

Thus if you can let go the non-constant/animated background usecase, the solution is pretty simple in both one shot and continuous stream cases:

  1. Hide your application window
  2. Take a screenshot, and cache it!
  3. Show your app back (crop everything apart from your application main window's bounding box), and now user can apply the filter
  4. Even if user changes the filter, reapply that to to cached image.
  5. Track your window's WM_MOVE/WM_SIZE and repeat above process for new dimensions.

Additionally if you need to be precise, use SetWindowsHookEx for CBT/etc.

Corner cases from top of my head:

  1. Notify icon/Balloon tool tips
  2. Desktop background scheduling (windows third party app)
  3. Application specific message boxes etc!

Hope this helps!

subdeveloper
  • 1,381
  • 8
  • 21
  • 1
    Continuous, therefore any hide / capture / show loop would cause a tremendous amount of flicker. – kubuzetto Oct 02 '17 at 06:29
  • 1
    @kubuzetto Thanks for the details, can you also help if most of your background will be static or Animated? (since putting transformations like you mentioned on an Animated background continuously may really bring the system down, so is that a valid usecase?) My reason for asking is, if you are only looking at continuous capture of less-frequently changing screen, you can get away with my suggestions above (i.e. tracking `WM_MOVE`, `WM_SIZE` thing and only doing the show/hide feat when your window's position has changed. This will prevent the flicker (and result in performance enhancement). – subdeveloper Oct 02 '17 at 08:06
  • The Desktop Composition Manager *does* continuously refresh the screen (if needed), and I don't see, how that *"really brings the system down"*. That's just guessing, and probably wrong at that, too. At any rate, this does not address the question that was asked, any more than claiming, that the solution were non-trivial. This isn't helpful. – IInspectable Oct 02 '17 at 09:31
  • 1
    I don't know the background's behavior in advance. Animated content is very possible. – kubuzetto Oct 02 '17 at 10:35
  • @IInspectable I am not pointing towards the window refresh, I am concerned about the transformations kukuzetto will use on that refreshed image continuously (as low as 16 ms in his words) which may require some processing if his capture window size is relatively big. – subdeveloper Oct 02 '17 at 12:46
  • Transformations is what dedicated graphics processing units do all the time. Are you suggesting to not use the system for what the system does best? – IInspectable Oct 02 '17 at 12:58
0

I've achieved something akin to this using the "GetForeGroundWindow" and "PrintWindow".

It's kind of involved, but here is a picture. The Image updates with it's source, but it's slow, so there is a significant lag (i.e .2 seconds=.5seconds) Rather than a blur effect I opted for a SinWave effect. Also, using GetForeGroundWindow basically means it can only copy the contents of one window. If you want to hear more just respond and I'll put together some steps and an example repo. enter image description here