|
Hello Joseph,
Thanks very much for the sample code. I plan to use it in an article that I'm writing for CodeProject that incorporates your cool Window capturing code with my Window Finder utility.
However, Joseph, I found that the sample code contains some possible resoure leakage bug. The following is the code location where the bug is located (at the beginning of the toClipboard() function) :
CDC dc;
if(FullWnd)
{ /* full window */
HDC hdc = ::GetWindowDC(wnd->m_hWnd);
dc.Attach(hdc);
} /* full window */
else
{ /* client area only */
HDC hdc = ::GetDC(wnd->m_hWnd);
dc.Attach(hdc);
} /* client area only */
The problem is that when the CDC object "dc" is destroyed at the end of the function, DeleteDC() will be called instead of ReleaseDC() :
(snippet from the MFC source codes) :
CDC::~CDC()
{
if (m_hDC != NULL)
::DeleteDC(Detach());
}
The Win32 API documentation for DeleteDC() states the following :
"An application must not delete a device context whose handle was obtained by calling the GetDC function. Instead, it must call the ReleaseDC function to free the device context. "
Also, the documentation for GetWindowDC() states :
"After painting is complete, the ReleaseDC function must be called to release the device context."
A good solution is to use CWindowDC and CClientDC classes instead of CDC :
CDC *dc;
if(FullWnd)
{ /* full window */
dc = new CWindowDC(wnd);
//HDC hdc = ::GetWindowDC(wnd->m_hWnd);
//dc -> Attach(hdc);
} /* full window */
else
{ /* client area only */
dc = new CClientDC(wnd);
//HDC hdc = ::GetDC(wnd->m_hWnd);
//dc -> Attach(hdc);
} /* client area only */
And later, at the end of the function, to delete the dc :
delete dc;
I discovered the possible resource leak while debugging with NuMega Bounds Checker.
Best Regards,
Bio.
|
|
|
|
|
Well, I am still new to C.
I have all the code implemented but I dont' know how to format the call of toClipboard?
How do you get the wnd?
toClipboard(wnd,TRUE);
Thanks,
Doug
|
|
|
|
|
Hello Doug,
You need to use C++ in order to use toClipboard(). Here is an example code that uses the toClipboard() function :
BOOL CaptureWindowToClipboard (HWND hwndToCapture)
{
BOOL bRet = FALSE;
if((hwndToCapture) && (::IsWindow (hwndToCapture)))
{
bRet = TRUE;
toClipboard((CWnd *)CWnd::FromHandle (hwndToCapture), TRUE);
}
return bRet;
}
1. We use the CWnd::FromHandle() function to dynamically create a CWnd object.
2. CWnd::FromHandle() will create a CWnd object and return a pointer to us.
The CWnd pointer returned is temporary and will be deleted by the MFC framework automatically (see documentation of CWnd::DeleteTempMap() for details).
Best Regards,
Bio.
|
|
|
|
|
Well, what window do you want to capture? If you know what window you want to capture, you only need a reference to it. For example, if you want to capture the entire app, put your handler in the mainframe class and call it as
toClipboard(this, TRUE);
|
|
|
|
|
Indeed, this appears to be a bug. I should fix it. Thanks for the pointer, and I'll update this the next time I get some time.
|
|
|
|
|
Hello Joseph,
You're most welcome, Joseph. And thanks for the toClipboard() function code. It's very useful nevertheless.
Best Regards,
Bio.
|
|
|
|
|
This text comes straight out of MSVC++ 6.0 ...
An application can simulate a press of the PRINTSCREEN key in order to obtain a screen snapshot and save it to the clipboard. To do this, call keybd_event with the bVk parameter set to VK_SNAPSHOT, and the bScan parameter set to 0 for a snapshot of the full screen or set bScan to 1 for a snapshot of the active window
|
|
|
|
|
I am unable to capture mouse ptr.
|
|
|
|
|
That's right. This is how Windows works. Whenever a DC is created for a window, the mouse pointer is hidden.
I'll think about this...
|
|
|
|
|
That's right. This is how Windows works. Whenever a DC is created for a window, the mouse pointer is hidden.
Of course, there is no good way to capture the mouse cursor anyway, since the cursor you want is somewhere on the screen, and to execute my code, you have to have moved it to someplace else on the screen (a menu item or button item), so there isn't even a meaningful cursor handle or mouse location at the time you activate my code.
One possibility is to use a delay. That is, when executing the code to capture the window, set up a timer event, and when it fires, do the capture then. This gives you time to reposition the mouse and have the cursor be reselected.
|
|
|
|
|
a way is to getcursorpos() and bitblt a mouse pointer icon over the DC.
|
|
|
|
|
How to capture mediaplayer window?
|
|
|
|
|
I want to know how to do that
|
|
|
|
|
|
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case ID_TEST:
ShowOpenedWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam )
{
char str[64];
char fullstr[128];
if (IsWindowVisible(hwnd))
{
GetWindowText(hwnd,str,64);
wsprintf(fullstr,"Windiw [Handle] : %d [Caption] : %s",hwnd,str);
iYPos += 20;
TextOut(GetDC(HWND(lParam)),10,iYPos,fullstr,strlen(fullstr));
}
return TRUE;
}
void ShowOpenedWindow(HWND hWnd)
{
iYPos = 10; //Global Variable
HWND lnDesktop;
lnDesktop = GetDesktopWindow();
EnumWindows(EnumWindowsProc, (long)hWnd);
}
|
|
|
|
|
I have a resource leaking report....from Numega software
MSDN say must call ::ReleaseDC() after calling ::GetDC()
CDC::Attach() doesn't call ::ReleaseDC()
and CDC destructor does:
CDC::~CDC()
{
if (m_hDC != NULL)
::DeleteDC(Detach());
}
|
|
|
|
|
how to capture a menu on the menubar?
benben
|
|
|
|
|
have you ever testet this on a multi monitor system?
It's possible that you capture from the wrong monitor!
But how to make a multi-monitor-save capture routine?
|
|
|
|
|
Anyone know how I could caputure a DOS screen programmatically?
I have found I can intercept the clipboard paste when the users presses PrintScr but this only works for lowres VGA DOS screens. I need to capture proprietry DOS video formats and haven't got a clue!
--
The Obliterator
|
|
|
|
|
As far as I know this technique works on any window you have visible. Note that you can always Alt+Enter and get a window version of the screen, and what I'd do in this case is create a little dialog-based app that had exactly one button (and was consequently very, very small on the screen), labelled "Capture". When "Capture" is clicked, the mouse is captured until its LBUTTONDOWN event is seen. At that point, WindowFromPoint is called to find the window the mouse is over. You then pass the window handle to my function. This should capture the contents of the window.
|
|
|
|
|
Saldy not Unfortunately due to the proprietry video mode the DOS software uses Windows is unable to render the program as a windowed DOS screen using Ctrl-Enter. I guess for the same reason this is why the Prt-Scr button does not work as it does for normal DOS programs.
Unfortuneatly my knowledge of DOS video formats is nil. I presume somehow it would be possible to get a pointer to the screen image buffer and read this directly but I wouldn't even know where to start.
Thanks for your advice anyway though.
--
The Obliterator
|
|
|
|
|
Sounds like one of those programs that deserves to die (it won't run under NT or XP, presumably; if it is doing what you seem to suggest, which is *not* "proprietary" unless it is wedded to a specific non-VESA implementation of a specific card--otherwise it would be stock VGA or SVGA), then the application is doomed anyway. However, in this case you should be able to just go for a pointer to the hardware screen image (I suspect this needs DirectDraw or something like that to make it possible), but that's outside what I know. However, you should still be able to get a window handle to the entire screen and grab it that way. Actually, I was not aware that it was even possible to run stock SVGA apps under Win9x.
If you were running under straight MS-DOS, there were a lot of documented techniques for screen capture which may still be around; they were TSR programs. While these probably can't coexist with Windows, you could always boot in pure MS-DOS mode.
|
|
|
|
|
I agree it is definitely one of those programs that deserves to die! I hate it!
Perhaps I misuse the term "proprietary"... to be honest I'm not really sure what it creates, but I know it is very choosy as to which graphics cards it will and won't work with and none of the screen grabbing software I have tried seems capable of grabbing it
Sadly DirectDraw is out of my knowledge also at this time. I tried getting a window handle to the entire screen but I simply get a scrambled image.
I am in the process of rewriting the entire software program in windows, I just wanted to provide some enhanced functionality for some of our existing customer base.
Thanks for your suggestions anyhow.
--
The Obliterator
|
|
|
|
|
This is some good code, but what I'd like to know is how to grab the contents of a screen that have been covered by other windows / lower in the z-order.
If the window I'm grabbing is burried, the contents of the window on top are captured in the size of the window I want.
Any ideas please?
|
|
|
|
|
i don't think you can do this. the contents of window you are trying to capture don't really exist until they're drawn - and windows aren't drawn in back of other windows - they're only drawn on top of.
if you screen capture a winodw that's been partially overdrawn on by another window, you'll get the overdrawn stuff, too.
-c
------------------------------
Smaller Animals Software, Inc.
http://www.smalleranimals.com
|
|
|
|