Tech Off Thread

18 posts

Way to detect DWM open/close window animations?

Back to Forum: Tech Off
  • User profile image
    LeoDavidson

    On Windows 7, I'm trying to write something which overlays a top-level layered window above my app's main window to create some visual effects. The intention is to make it look like everything is part of the main window even though there's really another window above it rendering some of the effects.

     

    It goes wrong if the main window is opening / closing / minimizing / etc. because of the DWM's animations. The top-level effects window is positioned so that it's on top of where GetWindowRect reports the main window to be, but the on-screen representation of the main window isn't really there. The main window is being transformed & animated in 3D space away from or towards the reported window location. So my top-level effects window is sitting in space looking really weird and drawing its effects over other windows. Smiley

     

    I'd be happy to simply disable my effect while the DWM animations are playing. Problem is I can't see a way to detect them. I'd like to do it properly in case future OS versions make the animations longer or shorter. i.e. I'd prefer not to use a kludge that says "don't apply my effects if the window was only opened/restored/maximized 1 second ago."

     

    (I don't want to turn off the DWM animations for the main window.)

     

    There are a bunch of stats returned by DwmGetCompositionTimingInfo but I'm not sure if any of them are useful for detecting the animations. It's not very clear to me what the stats are for but I'm guessing it's to do with syncing multimedia or measuring performance rather than seeing what's going on with a particular window.

     

    There's also some DWM APIs like DwmFlush, DwmAttachMilContent, DwmGetGraphicsStreamTransformHint, DwmGetGraphicsStreamClient which (despite dating back to Vista) still seem to be undocumented (beyond their argument/return types). Is there some fuller documentation for the DWM API somewhere that I'm missing?

     

  • User profile image
    figuerres

    are you using WPF or GDI+ ?

     

    with wpf you can't do it in one window?

  • User profile image
    LeoDavidson

    figuerres said:

    are you using WPF or GDI+ ?

     

    with wpf you can't do it in one window?

    Plain GDI. GDI+ is an option but I don't think it would help here. I can't use WPF as it's a C++ app.

     

    The effects window I'm overlaying has a static copy of what the main window used to look like. On to that I'm using DWM to render a live copy of the main window. The live copy scrolls/fades/zooms to give a smooth transition from the old UI state to the new one.

     

    Doing it this way means the existing UI elements don't need to be modified for the effect to work; they just paint themselves as normal. During the transition the UI remains "live", painting updates and responding to the mouse and keyboard (since the effects window is "click-through"). With just two lines of code I can add a transition effect to almost any UI change.

     

    It all seems to work great, except if the effect is triggered while DWM is applying its own transition animations to the window. So if I could just detect when/whether those are happening I could disable my effect.

     

    (Obviously I also have to worry about the main window being moved or resized while the effects window is over the top of it. That is easy enough. The problem with the DWM animations is that they visually move the window and yet it doesn't move as far as things like GetWindowRect or WM_SIZE are concerned.)

     

    Maybe a picture shows it better. Say notepad is opening:

     

    (It's actually a screenshot of notepad closing, as that was easier to capture, but just pretend it's opening instead. Smiley)

     

    Generic Forum Image

     

    If you were to overlay a copy of its client area on top of where the OS reports it to be, you'd end up with this:

     

    Generic Forum Image

     

  • User profile image
    figuerres

    LeoDavidson said:
    figuerres said:
    *snip*

    Plain GDI. GDI+ is an option but I don't think it would help here. I can't use WPF as it's a C++ app.

     

    The effects window I'm overlaying has a static copy of what the main window used to look like. On to that I'm using DWM to render a live copy of the main window. The live copy scrolls/fades/zooms to give a smooth transition from the old UI state to the new one.

     

    Doing it this way means the existing UI elements don't need to be modified for the effect to work; they just paint themselves as normal. During the transition the UI remains "live", painting updates and responding to the mouse and keyboard (since the effects window is "click-through"). With just two lines of code I can add a transition effect to almost any UI change.

     

    It all seems to work great, except if the effect is triggered while DWM is applying its own transition animations to the window. So if I could just detect when/whether those are happening I could disable my effect.

     

    (Obviously I also have to worry about the main window being moved or resized while the effects window is over the top of it. That is easy enough. The problem with the DWM animations is that they visually move the window and yet it doesn't move as far as things like GetWindowRect or WM_SIZE are concerned.)

     

    Maybe a picture shows it better. Say notepad is opening:

     

    (It's actually a screenshot of notepad closing, as that was easier to capture, but just pretend it's opening instead. Smiley)

     

    Generic Forum Image

     

    If you were to overlay a copy of its client area on top of where the OS reports it to be, you'd end up with this:

     

    Generic Forum Image

     

    http://msdn.microsoft.com/en-us/library/ms742522.aspx

     

    you can host wpf from win32 according to this page in msdn.

  • User profile image
    LeoDavidson

    figuerres said:
    LeoDavidson said:
    *snip*

    http://msdn.microsoft.com/en-us/library/ms742522.aspx

     

    you can host wpf from win32 according to this page in msdn.

    I think that's using C++/CLI so it'd turn my app into a managed one which I want to avoid. (On the grounds of avoiding complexity, if nothing else.)

     

    Not sure WPF would solve the problem anyway, unless the whole UI was re-written as WPF? When WPF and Win32 are used in the same window they have to be segregated (no overlapping controls/regions). They can share a window but they can't interact, at least as I understand it.

     

    My aim is to make something that can be slotted into existing code without much plumbing and without having to change the way existing controls paint themselves or the way they are hosted in the window.

     

    DWM's live-thumbnail API is perfect for that as it lets me render a live copy of the window, faded/enlarged/reduced. From just messing around with it for a day I've got something that's almost perfect, except when DWM is messing with my window's shape in a way I don't know how to detect.

     

    (Hope that makes sense. Probably not explaining myself very well at 4am. Smiley)

     

  • User profile image
    figuerres

    LeoDavidson said:
    figuerres said:
    *snip*

    I think that's using C++/CLI so it'd turn my app into a managed one which I want to avoid. (On the grounds of avoiding complexity, if nothing else.)

     

    Not sure WPF would solve the problem anyway, unless the whole UI was re-written as WPF? When WPF and Win32 are used in the same window they have to be segregated (no overlapping controls/regions). They can share a window but they can't interact, at least as I understand it.

     

    My aim is to make something that can be slotted into existing code without much plumbing and without having to change the way existing controls paint themselves or the way they are hosted in the window.

     

    DWM's live-thumbnail API is perfect for that as it lets me render a live copy of the window, faded/enlarged/reduced. From just messing around with it for a day I've got something that's almost perfect, except when DWM is messing with my window's shape in a way I don't know how to detect.

     

    (Hope that makes sense. Probably not explaining myself very well at 4am. Smiley)

     

    well one thing i was thinking of was to make a dll that was C++/CLI with just the UI bits only.

    so 90% of the app logic would stay in raw C++ and would just have calls to an interface / with the impliemtation in C++/CLI

    minimal impack to the perf of the app and to the non-ui code.

     

    honestly there comes a point when IMHO it becomes time to embrace a chnage, WPF was made for making better visuals that in apps and to be able to do things that were difficult or impossible with GDI and WInforms.

    sounds like you are getting into that area or right on the edge of it.

     

    just as a bit of input - Over the last few months I have been getting more into SIlverlight as our clients use a lot of web stuff and they have been asking for more complex things that really needed silverlight or flash to do them.

     

    so with silverlight what i have found is that on the code side i can't really see any huge change from winforms to xaml in event handlers and other mundane coding.

    yes xaml is very different from the classic forms code but even then most of the code that interacts with the markup is not that far different.

     

    now things like building a dependancy property - a bit funky but not hard to follow.

     

    just so you know that it's some work but not all that hard if you take a bit of time and study some examples.

  • User profile image
    LeoDavidson

    figuerres said:
    LeoDavidson said:
    *snip*

    well one thing i was thinking of was to make a dll that was C++/CLI with just the UI bits only.

    so 90% of the app logic would stay in raw C++ and would just have calls to an interface / with the impliemtation in C++/CLI

    minimal impack to the perf of the app and to the non-ui code.

     

    honestly there comes a point when IMHO it becomes time to embrace a chnage, WPF was made for making better visuals that in apps and to be able to do things that were difficult or impossible with GDI and WInforms.

    sounds like you are getting into that area or right on the edge of it.

     

    just as a bit of input - Over the last few months I have been getting more into SIlverlight as our clients use a lot of web stuff and they have been asking for more complex things that really needed silverlight or flash to do them.

     

    so with silverlight what i have found is that on the code side i can't really see any huge change from winforms to xaml in event handlers and other mundane coding.

    yes xaml is very different from the classic forms code but even then most of the code that interacts with the markup is not that far different.

     

    now things like building a dependancy property - a bit funky but not hard to follow.

     

    just so you know that it's some work but not all that hard if you take a bit of time and study some examples.

    There's too much existing UI code in the project to make porting to WPF a realistic option. It also hosts several native 3rd party UI components that don't have WPF equivalents. An all-WPF UI would definitely make this kind of thing easier if it was a new or small project but it'd take man-years to change the existing project.

     

    Using WPF for individual controls in the UI would be fine, but I want something which can apply effects on top of existing controls/window regions.

     

    Hmm, I wonder if there's a way to make DWM treat two top-level windows as part of the same thing, applying the same animations & transforms to both at once? That would solve things as well.

     

  • User profile image
    figuerres

    LeoDavidson said:
    figuerres said:
    *snip*

    There's too much existing UI code in the project to make porting to WPF a realistic option. It also hosts several native 3rd party UI components that don't have WPF equivalents. An all-WPF UI would definitely make this kind of thing easier if it was a new or small project but it'd take man-years to change the existing project.

     

    Using WPF for individual controls in the UI would be fine, but I want something which can apply effects on top of existing controls/window regions.

     

    Hmm, I wonder if there's a way to make DWM treat two top-level windows as part of the same thing, applying the same animations & transforms to both at once? That would solve things as well.

     

    well a control is an hwnd .....

    and that is in an hwnd.....

     

    it would seem like you could create a window that is a child of the "main" window and make it act like a docking panel

    that might do it for you?

     

    just don't try this with anti-matter Smiley  BOOM!

  • User profile image
    Cannot​Resolve​Symbol

    figuerres said:
    LeoDavidson said:
    *snip*

    well a control is an hwnd .....

    and that is in an hwnd.....

     

    it would seem like you could create a window that is a child of the "main" window and make it act like a docking panel

    that might do it for you?

     

    just don't try this with anti-matter Smiley  BOOM!

    You don't need to "make it act like a docking panel" (or provide any behavior at all, really), just setting the parent of your effects window to your main window should be sufficient to make it behave as though its part of the main window from the DWM's perspective (along with the obvious change to use coordinates relative to the window).

     

    Downside:  if your child window has a title bar, it will most likely no longer be drawn by the DWM.  Also, you can get some weirdness WRT keyboard focus when doing this; if your effects window is just a transient thing, this shouldn't be an issue (and it won't be any more of an issue than when you were using a separate window).

  • User profile image
    LeoDavidson

    figuerres said:
    LeoDavidson said:
    *snip*

    well a control is an hwnd .....

    and that is in an hwnd.....

     

    it would seem like you could create a window that is a child of the "main" window and make it act like a docking panel

    that might do it for you?

     

    just don't try this with anti-matter Smiley  BOOM!

    They're all HWNDs but that doesn't mean WPF can draw a window that displays a modified copy of my native windows on top of those windows (which is what I'm doing at the moment), due to the "airspace restrictions".

     

    As far as I can tell, mixing WPF and native controls just means they can sit next to each other in the same window. I don't think they can visually interact/overlap.

     

  • User profile image
    LeoDavidson

    CannotResolveSymbol said:
    figuerres said:
    *snip*

    You don't need to "make it act like a docking panel" (or provide any behavior at all, really), just setting the parent of your effects window to your main window should be sufficient to make it behave as though its part of the main window from the DWM's perspective (along with the obvious change to use coordinates relative to the window).

     

    Downside:  if your child window has a title bar, it will most likely no longer be drawn by the DWM.  Also, you can get some weirdness WRT keyboard focus when doing this; if your effects window is just a transient thing, this shouldn't be an issue (and it won't be any more of an issue than when you were using a separate window).

    The effects window can't be a proper child (WS_CHILD) of the main window since DWM thumbnails can only be drawn into top-level windows.

     

    (Drawing the thumbnail directly into the main window won't work as the thumbnail is of the main window and DWM checks for such loops.)

     

    When I create the effects window as a popup (WS_POPUP) I am specifying the main window as the parent in the CreateWindowEx call, but that doesn't seem to help. It opens in-place instantly instead of being animated like the main window is.

     

    If I call SetParent on the effects window right after creating it, specifying the main window as its parent, then that breaks the DWM thumbnail.

     

  • User profile image
    figuerres

    LeoDavidson said:
    figuerres said:
    *snip*

    They're all HWNDs but that doesn't mean WPF can draw a window that displays a modified copy of my native windows on top of those windows (which is what I'm doing at the moment), due to the "airspace restrictions".

     

    As far as I can tell, mixing WPF and native controls just means they can sit next to each other in the same window. I don't think they can visually interact/overlap.

     

    Leo i was replying to your "use a window" as you wrote it...  IE a classic GDI window.

     

    perhaps not a child window but ... like a child.  hey it's a hack .... who knows....

     

    thats why i was thinking get out of gdi .... or make a custom window class that takes over the layering and drawing.

  • User profile image
    Cannot​Resolve​Symbol

    LeoDavidson said:
    CannotResolveSymbol said:
    *snip*

    The effects window can't be a proper child (WS_CHILD) of the main window since DWM thumbnails can only be drawn into top-level windows.

     

    (Drawing the thumbnail directly into the main window won't work as the thumbnail is of the main window and DWM checks for such loops.)

     

    When I create the effects window as a popup (WS_POPUP) I am specifying the main window as the parent in the CreateWindowEx call, but that doesn't seem to help. It opens in-place instantly instead of being animated like the main window is.

     

    If I call SetParent on the effects window right after creating it, specifying the main window as its parent, then that breaks the DWM thumbnail.

     

    Wait, what?  I'm not sure I follow you here...  are you using this window as an overlay to add visual effects to your application or are you using this window to draw a custom preview thumbnail?

     

    At any rate, anything you do on this is a hack.  You're only going to get so far before you need to move to a proper animation framework (through WPF, through the Windows 7-specific Animation Manager, or through a third-party framework).  Might as well do it right from the start than have to come back in a year and rewrite everything when you need to do something that's beyond what your hack-around can do.

  • User profile image
    figuerres

    CannotResolveSymbol said:
    LeoDavidson said:
    *snip*

    Wait, what?  I'm not sure I follow you here...  are you using this window as an overlay to add visual effects to your application or are you using this window to draw a custom preview thumbnail?

     

    At any rate, anything you do on this is a hack.  You're only going to get so far before you need to move to a proper animation framework (through WPF, through the Windows 7-specific Animation Manager, or through a third-party framework).  Might as well do it right from the start than have to come back in a year and rewrite everything when you need to do something that's beyond what your hack-around can do.

    it's an overlay on the main app window. he is creating visual effects to make the app window have some look.

    when the win7 dwm starts animating the close / open or other effects his second window gets out of sync with what dwm is doing.

     

     

  • User profile image
    LeoDavidson

    CannotResolveSymbol said:
    LeoDavidson said:
    *snip*

    Wait, what?  I'm not sure I follow you here...  are you using this window as an overlay to add visual effects to your application or are you using this window to draw a custom preview thumbnail?

     

    At any rate, anything you do on this is a hack.  You're only going to get so far before you need to move to a proper animation framework (through WPF, through the Windows 7-specific Animation Manager, or through a third-party framework).  Might as well do it right from the start than have to come back in a year and rewrite everything when you need to do something that's beyond what your hack-around can do.

    It is a bit of a hack, but one which works well (so far, at least) apart from this one issue.

     

    Spending the next few years re-writing the entire app to get a bit of eye candy isn't an option, as nice as that idea may sound in an ideal world with infinite time & resources and access to the source code of all OS and 3rd party components. (This effect has to work, for example, on hosted ActiveX controls.) If re-writing the whole app is the only option then I'll simply do without the effect.

     

    However, if there is some way to detect when DWM has finished animating my window then I believe I can make everything work perfectly.

  • User profile image
    AndyC

    LeoDavidson said:
    CannotResolveSymbol said:
    *snip*

    It is a bit of a hack, but one which works well (so far, at least) apart from this one issue.

     

    Spending the next few years re-writing the entire app to get a bit of eye candy isn't an option, as nice as that idea may sound in an ideal world with infinite time & resources and access to the source code of all OS and 3rd party components. (This effect has to work, for example, on hosted ActiveX controls.) If re-writing the whole app is the only option then I'll simply do without the effect.

     

    However, if there is some way to detect when DWM has finished animating my window then I believe I can make everything work perfectly.

    As you say, it's a bit of a hack and you aren't really using DWM thumbnails in a way anyone ever intended them to work, which is probably why it doesn't. I suspect the best you'll get is to disable DWM animations for your window, although I have a suspicion that something like Flip3D may make your UI break also.

  • User profile image
    LeoDavidson

    AndyC said:
    LeoDavidson said:
    *snip*

    As you say, it's a bit of a hack and you aren't really using DWM thumbnails in a way anyone ever intended them to work, which is probably why it doesn't. I suspect the best you'll get is to disable DWM animations for your window, although I have a suspicion that something like Flip3D may make your UI break also.

    Flip3D is fine, FWIW. You can opt windows out of it so the overlay window would be hidden whenever it's active (including when it's animating things into position).

     

    Think I'll explore an alternative way to do the effect now. Have an idea that might give a good result but won't be hardware accelerated and will only work with windows that allow painting to a specific device-context. If that works well enough then it'll save a lot of hassle.

     

  • User profile image
    LeoDavidson

    I gave up on the alternative method in the end. Ran into too many problems with controls drawing directly into the window, or directly manipulating the window (e.g. shifting parts of it around in when scrolling), over the top of what I was doing. That's what makes the DWM thumbnail method so great: It takes the rendering output or the windows and does things to it without affecting it at all. (It also lets me easily create effects on areas of the top-level window which can cross over child windows.)

     

    So I went back to plan A. Almost ditched the idea completely but it looked so nice (to me Smiley) that I kept at it a bit more, and I think I now have it working really well, albeit with some kludges. Long term testing will determine whether the feature sticks or is canned.

     

    While playing with this stuff I discovered that Windows 7's DWM process will crash (and sometimes reset the desktop back to classic rendering) if the user invokes Aero Peek while a DWM thumbnail is being moved around in another window as Peek fades things out to sheets of glass. Sad

     

    Workaround is to set the new DWM window flag on the window the thumbnail is rendered into, telling DWM to ignore that window for Aero Peek. (Drawback is that it then stays visible while the other windows are faded to glass, but in my case that's fine as it's only visible for half a second anyway.)

     

    I also noticed that my overlay window is considered part of the main window when minimising/restoring the window, and within Flip 3D. So it's only considered a separate window during the window-open animation, which seems weird. It's like the pop-up is only "attached" to its parent after that window-open animation has completed. (I checked that I'm not opening my pop-up before the parent window has been made visible, and I'm not.)

     

Comments closed

Comments have been closed since this content was published more than 30 days ago, but if you'd like to continue the conversation, please create a new thread in our Forums, or Contact Us and let us know.