I need to draw something on a window (that isn't mine - it's user-defined, if it matters).
I've already managed to draw on the window by getting the device context using GetDC and drawing normally, the problem is that I don't know when to draw to the window - the window is constantly redrawing itself (for example, a game).
I've got a few ideas but so far they're no good or bad/no implementation.
Using a timer. This was the worst idea, but I'll try anything right now. obviously, since the window is redrawn constantly it would flicker. I thought of forcing the window to redraw before my drawings, but still it's no good. can't really think of a good implementation with a timer...
Hook WM_PAINT message. using SetWindowsHookEx WM_GETMESSAGE hook I can use an event that receive WM_PAINT message whenever the other window receives it, but WM_PAINT is sent before drawing is done. I found on MSDN that instead of WH_GETMESSAGE Windows Hook you can use WndProcRetHook which is called after processing windows messages and recieves a structure containing the message information, but so far no luck - I can't get it to work...
Hooking drawing functions. I've tried hooking the painting function (or functions) such as ReleaseDC and/or EndPaint which invalidate the window, so I can do my last-minute drawings. this time, I got it to work pretty good - but it still flickers a little and on some windows hooking ReleaseDC somehow prevents from the window to render - it doesn't even erase it's background. sometimes even the entire process crashes.
So I'm looking for a good method to be the last to draw on a window before it is displayed on the screen. I prefer avoiding hooks not being done with SetWindowsHookEx (such as: external DLL) but that would be fine too.
Thanks.
An alternative approach might be to avoid painting directly on the window, and instead create a transparent layered window that you keep positioned on top of the main one. That way, the drawing on your window doesn't interfere with the drawing on the main window, and vice-versa.
You may need to take certain steps to that mouse clicks will go through your window to the main window; eg. handle WM_NCHITTEST with HTTRANSPARENT and use the WS_EX_TRANSPARENT style.
Since, under Windows, windows are required to draw on demand, the only way to do this is to use SetWindowsHookEx() to hook the WM_PAINT window for that window.
This is a non-trivial process that requires that your paint code reside in a DLL (so the DLL can be loaded into the target app's address space).
In general, this is not a very good idea unless you have a very good reason to do this.
Related
I am writing an Alt+Tab replacement in C#, and have trouble with fullscreen applications.
Is there a way to detect if a SetForegroundWindow(hWnd) call is going to change the screen resolution? Or equivalently, if hWnd is a fullscreen application? I would like to wait until the resolution change is done, or if there is no change, proceed immediately.
The screen resolution change is done asynchronously, the function call returns well before it happens, so my code runs prematurely, and draws my application onto the surface of the fullscreen application, with wrong dimensions, then after the resolution change, it looks especially ugly.
Source of my application is at https://bitbucket.org/FrigoCoder/frigotab/src if anyone is interested.
To clarify, I would be more interested in knowing beforehand if a resolution change occurs than detecting it later. I already know a half-solution where I call SetForegroundWindow() on GetDesktopWindow() or some other window and watch SystemEvents.DisplaySettingsChanging and DisplaySettingsChanged. This however only gives me a late asynchronous notification if a resolution change occurs, and does not tell me if it does not.
I managed to solve the issue. Instead of trying to detect fullscreen applications, I simply send an inactivation message to the foreground application, which triggers an early resolution change:
SendMessage(GetForegroundWindow(), WM_ACTIVATEAPP, false, GetCurrentThreadId());
This exact same message is also sent during application switches, so I essentially emulate one before it actually happens. I have not encountered any side effects yet.
Mind you however, that this does not solve DWM issues. Windows 7 automatically disables DWM composition for compatibility launches, or when it detects direct access to the primary display surface. It does not allow you to re-enable, and I do not see an easy solution to this problem. Thankfully this issue will eventually go away since DWM composition is always enabled in Windows 8 and newer.
Perhaps the Winforms Event SizeChanged can help you.
You could use this event as a continuation of sorts for the rest of your code. In the case that the event doesn't fire due to no resizing, you could have a secondary continuation that will run after a specified timeout. It's not perfect, but may meet your needs.
I need help handling minimized programs when using a custom/self made explorer.exe file .. because unless properly handled, minimized programs will just shrink to something like 100x50px and stay on screen. I worked out a Timer in C# to check for "iconic" processes, list their mainWindowHandler, and move them outside the screen with "MoveWindow". To bring them back I use the handler and the "ShowWindow" function wich works AWESOME .. but as I said, it involves a constantly running Timer, so there must be a cleaner/easier way of achieving this.
Any ideas? Some way to hook and raise an event when a window is minimized?
*please note: show and movewindow are functions from user32.dll. I'm not trying to catch when MY forms are minimized, but when the OTHERS programs are.
You can create a hook to check when windows are being minimized.
I found a CodeProject article that uses hooks to check when the user opens a system menu (ALT+SPACE) on any window, and then appends an extra item to it. You can use that code to check when the user hits the minimize button, and run whatever code you need there.
The CodeProject article is written in C++, but you can adapt the same method for C# (or use P/Invoke).
I wrote a small autohotkey script that removes the border, titlebar, and resize handles of a window, and centers it on the first monitor. This works for most applications and games, but some (bioshock 2, APB, etc) replace their window style instantly after removing it. Is there a way to block window style changes?
I would prefer to keep this in AHK, but the title has c# in it because I would like to convert my application to that down the road, and if it's only possible in c#/c++ then now would be a good time to start conversion.
I could be missing something, but I doubt this is going to be easy. The behavior you describe is one of an application which is either monitoring for changes in its window style, or just constantly redrawing them nonstop to prevent these changes. Of course you could just Loop through and fight against it where you remove, it replaces, you remove, it replaces, but that won't solve anything.
One way you could try is to create a .dll and inject it into the app's process, and then hook some API calls and simply return before anything gets redrawn. Google for 'detours hooking' for some examples. That might work, but would be out of the scope of AHK. And your simple 15 minute AHK script would turn into a much bigger project. =(
My app has an option to disable aero by calling DwmEnableComposition(0) before capturing a screen image. As you know, disabling aero makes the screen go black then return to normal afterwards. On different PCs this might take 2 to 3 seconds depending on how fast the system is.
Is there a better way of determining if aero has fully disabled before screen capture instead of Thread.Sleep()?
You should be able to do this using the related API function DwmIsCompositionEnabled. The other option might be to listen for the WM_DWMCOMPOSITIONCHANGED event.
Your form's Paint event will run. That doesn't mean all windows will be fully painted, but you can sleep less. Listening for the notification message by overriding WndProc() may work, not sure when it is sent. WM_DWMCOMPOSITIONCHANGED is message 0x31e. I suspect it will be sent too soon, all windows probably have to repaint themselves next. The only way to be sure is to enumerate the windows with EnumWindows and call UpdateWindow. Visit pinvoke.net for the P/Invoke declarations you'll need. Sleep() will work too but there's no way to guess an amount that's guaranteed to work everywhere.
Have you looked into DwmIsCompositionEnabled? This page also says Applications can listen for composition state changes by handling the WM_DWMCOMPOSITIONCHANGED notification.
In an application that I am currently working on, a requirement is to bring a window of an external application to the foreground. Making Win32 API calls such as BringWindowToTop and SetForeground window do not work all the time. This is due to some restrictions within Windows XP. What I would like to do instead is send simulate a mouse click the window's button on the taskbar which I am hoping will bring the window to the front. Does anyone know how this is possible?
Check out the section "How to steal focus on 2K/XP" at http://www.codeproject.com/KB/dialog/dlgboxtricks.aspx, as this is exactly what you need. I wouldn't go the taskbar route as the taskbar could be hidden or simply not there.
It's possible. But it's extremely sketchy. Your application may also break with the next version of Windows, since it's undocumented. What you need to do is find the window handle of the taskbar, then find the window handle of the child window representing the button, then send it a WM_MOUSEDOWN (I think) message.
Here's a bit on finding the window handle of the taskbar:
http://www.codeproject.com/
FWIW, the restrictions on BringWindowToTop/SetForeground are there because it's irritating when a window steals focus. That may not matter if you're working on a corporate environment. Just keep it in mind. :)
I used this in a program where I needed to simulate clicks and mouse movements;
Global Mouse and Keyboard Library
To be honest I've never had an issue bringing a window to the foreground on XP/Vista/2003/2000.
You need to make sure you do the following:
Check if IsIconic (minimized)
If #1 results in true then call
ShowWindow passing SW_RESTORE
Then call SetForegroundWindow
I've never had problems that I can think of doing it with those steps.