Christian de Bellefeuille
asked on
Title bar not drawn on Windows 7
We are developing an application which takes a snapshot of a screen. We use a function from Windows API named "GetWindowDC" to get the handle of the application and we use a BitBlt to copy it.
We use GetWindowRect to get get the size of the window and ClientToScreen to get it's position.
We need to render the image from snapshots of the applications currently running, so the some application could be hide in the process.
The problem that we have is that the titlebar and borders of the application are not drawn properly. Instead of having them, it put some crap in arround our snapshot where the titlebar should appear.
P.S: We are using Windows 7.
We tried it on Windows XP and while we are getting the title bar and the borders, we are also getting a part that shoudn't be there. The region taken is too large.
Anyone got an idea, a solution? You can see the result bellow.
Thanks
We use GetWindowRect to get get the size of the window and ClientToScreen to get it's position.
We need to render the image from snapshots of the applications currently running, so the some application could be hide in the process.
The problem that we have is that the titlebar and borders of the application are not drawn properly. Instead of having them, it put some crap in arround our snapshot where the titlebar should appear.
P.S: We are using Windows 7.
We tried it on Windows XP and while we are getting the title bar and the borders, we are also getting a part that shoudn't be there. The region taken is too large.
Anyone got an idea, a solution? You can see the result bellow.
Thanks
ASKER
I don't use Graphics.CopyFromScreen because it's actually slower than calling Windows' API (more than twice slower) and it's not what I'm actually performing. The code you see on the snapshot only retrieve the whole screen. I'm trying to get only the application snapshot and this is the second reason I'm using Bitblt. Here's the code I'm using to get the application snapshot so far...
Although you didn't provide the solution, thanks for showing me how to use the rect the right way... I was always wandering why my rect.{x,y} were always 0,0.
static public Bitmap FormSnapShot()
{
Size c = SystemInformation.PrimaryMonitorSize;
Bitmap bmp;
IntPtr dc1;
IntPtr dc2;
Graphics g;
bmp = new Bitmap(c.Width, c.Height);
g = Graphics.FromImage(bmp);
//Retrieve all the processes that have a MainWindowHandle
IntPtr[] tabHandle = Procslst.listProcHandle();
//So I can see the blank...
g.FillRectangle(Brushes.Aqua,0,0,c.Width,c.Height);
dc1 = g.GetHdc();
Rectangle irect;
//dc2 = GetDC(GetDesktopWindow());
//BitBlt(dc1, 0, 0, c.Width, c.Height, dc2, 0, 0, SRCCOPY);
//ReleaseDC(GetDesktopWindow(), dc2);
//Draws all the windows on my image
foreach (IntPtr ihandle in tabHandle)
{
dc2 = GetWindowDC(ihandle);
irect = getWindowBound(ihandle);
BitBlt(dc1, irect.Left, irect.Top, irect.Width, irect.Height, dc2, 0, 0, SRCCOPY);
ReleaseDC(ihandle, dc2);
}
g.ReleaseHdc(dc1);
g.Dispose();
return bmp;
}
Although you didn't provide the solution, thanks for showing me how to use the rect the right way... I was always wandering why my rect.{x,y} were always 0,0.
Have you got it working correctly now then?...or do you still need help?
ASKER
Well the title bar and the borders are still not drawn. I need to know how can I get them to be drawn other than by taking a snapshot of the whole screen (application by application).
I think line #29 is wrong:
BitBlt(dc1, irect.Left, irect.Top, irect.Width, irect.Height, dc2, 0, 0, SRCCOPY);
The coords passed in should be CLIENT coords because you are getting a DC to a specific window.
Try this instead:
BitBlt(dc1, 0, 0, irect.Width, irect.Height, dc2, 0, 0, SRCCOPY);
*If you were using the DC of the desktop itself then you'd need the screen coords of the window.
BitBlt(dc1, irect.Left, irect.Top, irect.Width, irect.Height, dc2, 0, 0, SRCCOPY);
The coords passed in should be CLIENT coords because you are getting a DC to a specific window.
Try this instead:
BitBlt(dc1, 0, 0, irect.Width, irect.Height, dc2, 0, 0, SRCCOPY);
*If you were using the DC of the desktop itself then you'd need the screen coords of the window.
ASKER
The images are draw at the right place. I tested your code and all the applications are draw on the upper left corner. I forgot to comment my code a bit but line 29 copies the DC into the DC of an image the size of the screen. I hope it helps you helping me. The only problem we have is that the title bar and the borders are not draw with the form when we do our Bitblt, probably because it is draw in another context (this is with Aero we're getting different results with Aero disabled).
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Don't worry for VB.NET.
I've tried your sample, as-is in VB.NET, but i get the same result...
As you can see on this sample, Notepad titlebar & borders are complete crap.
On this other sample, you can see that Internet Explorer titlebar & borders are not correct too.
I've tried this code on 2 computers with Windows 7 Home Edition x64, and both get the same result.
My target framework was 4.0, but i've tried with 2.0 and i have the same problem.
I've tried your sample, as-is in VB.NET, but i get the same result...
As you can see on this sample, Notepad titlebar & borders are complete crap.
On this other sample, you can see that Internet Explorer titlebar & borders are not correct too.
I've tried this code on 2 computers with Windows 7 Home Edition x64, and both get the same result.
My target framework was 4.0, but i've tried with 2.0 and i have the same problem.
Wish I knew what the difference is... =\
Can you give a good "big picture" of your overall app again...maybe there is a different approach that is acceptable.
Can you give a good "big picture" of your overall app again...maybe there is a different approach that is acceptable.
ASKER
We are trying to develop a VNC-Like application to display our screen to someone else.
We want to add a functionality where the user can uncheck an application from a list of loaded applications, to hide this application to the remote viewer. (It would still be displayed locally, but it wouldn't be seen by the remote).
If it wouldn't be about that application choice, we would have taken the whole screen and check for differences only... but we can't do that as you can see
We want to add a functionality where the user can uncheck an application from a list of loaded applications, to hide this application to the remote viewer. (It would still be displayed locally, but it wouldn't be seen by the remote).
If it wouldn't be about that application choice, we would have taken the whole screen and check for differences only... but we can't do that as you can see
Oh wow...you might need to go "lower" and utilize something like C++ where you have better access to windows messages and do things like DLL injection. (not my cup of tea though!) You might want to get some folks from the C++ zone in on the question as they might have insight from a lower level windows messages perspective.
ASKER
(Sorry for the delay)
We are looking for another possible solution using MaskBlt. We are crawling inside the API to find something useful. I think that we can create a Mask and use it with a screenshot of the full screen to achieve what we want to do.
I'll accept your solution as the solution since it should be working on "most" systems.
Thanks a lot for your lights Idle_Mind
We are looking for another possible solution using MaskBlt. We are crawling inside the API to find something useful. I think that we can create a Mask and use it with a screenshot of the full screen to achieve what we want to do.
I'll accept your solution as the solution since it should be working on "most" systems.
Thanks a lot for your lights Idle_Mind
You're using:
dc2 = GetDC(GetDesktopWindow());
Which indicates you want to copy directly from the screen.
Instead of GetDC(), GetDesktopWindow(), and BitBlt(), why not simply use Graphics.CopyFromScreen()?
http://msdn.microsoft.com/en-us/library/6yfzc507.aspx
Simplified, it might look like:
Open in new window
Obviously that snippet will capture the entire screen.
If you want to capture just a specific window based on its Handle, then you are correct to start with GetWindowRect(). Remember, though, that the values returned by this API are ALREADY in screen coordinates so ClientToScreen() isn't needed.
Here's an example of capturing just the area covered by a Notepad instance:
Open in new window