![]() |
Web Development »
Applications & Tools »
Tools with source code
Intermediate
Screen capture, window resizing utility with source codeBy peterboultonThis utility uses Lim Bio Liong's excellent Spy++ style Window Finder code to build a screen capture utility (featuring text capture as well as bitmaps) and window resizer/mover. It also demonstrates stay on top and expanding/contracting (i.e. more detail / less detail) dialog boxes. |
VC6, VC7, VC7.1Win2K, WinXP, Win2003, MFC, VS.NET2003, Dev
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||


Lim Bio Liong's excellent CodeProject article (MS Spy++ style Window Finder) does all the hard work relating to picking a window to work with for this utility. I claim no credit whatever for this.
However, Lim Bio Liong's sample project launches the window finder dialog from an SDI application and is provided principally to assist in demonstrating the window finder code.
As a developer, I wanted a simple, free tool that would do all of the following:
That's what the tool presented in this article sets out to do. As a full time developer I expect to make a lot of use of it from now on!
Along the way, the source code also demonstrates 'stay on top' functionality, and the dialog box expands and contracts to show more or less detail.
The first thing I wanted to do was to turn the original SDI app + dialog box into a dialog box application, as the SDI bit was inappropriate to my design.
As an MFC developer, the easiest way was:
InitInstance() and replace it with the code needed to launch the Win32 dialog, i.e.: InitialiseResources(); long lRet = (long)DialogBox ( (HINSTANCE)m_hInstance, // handle to application instance (LPCTSTR)MAKEINTRESOURCE (IDD_DIALOG_SEARCH_WINDOW), // identifies dialog box template (HWND)NULL, // handle to owner window (DLGPROC)SearchWindowDialogProc // pointer to dialog box procedure );
It was also necessary to move some of the global declarations out of the SDI app file and into the windowfinder.cpp file. The result is that the application's InitApp() initializes the resources required for the dialog and then launches the dialog.
The code in DisplayInfoOnFoundWindow() in windowfinder.cpp receives a handle to the selected window. With this handle, it is simple to get the window's text:
char winTxt[5000]; memset(winTxt, 0, 5000); SendMessage(hwndFoundWindow, WM_GETTEXT, 5000, (LPARAM)winTxt);
(The MSDN documentation states that this method is preferable to GetWindowText() when getting text from a window outside your application.)
However, some controls do not yield their contents in this way. So, for example, to get the text from a listbox control, we use the following:
if(strcmp(szClassName, "ListBox") == 0) { CListBox lb; // Instantiate a MFC listbox object lb.Attach(hwndFoundWindow); // Attach the listbox's HWND to our MFC object nItems=lb.GetCount(); for(count=0; count < nItems; count++) { lb.GetText(count, strItem); strItem+="\r\n"; strcat(winTxt, strItem); } lb.Detach(); // Must remember to detach, // otherwise when lb goes out of scope // it will destroy the listbox prematurely! }
(It would be nice to capture the text from more complex controls, such as tree controls, using a similar approach but to date such an approach eludes me. Even myTreeCtrl.GetItemText(myTreeCtrl.GetRootItem() returns an empty string, for some reason.)
This is processed in SearchWindowDialogProc() - (search windowfinder.cpp for "if(wID == IDC_CAPTURE_BUTTON)").
A global is already set to the handle of the target window before SearchWindowDialogProc() is called, so we already have a handle to the window to capture.
We need to temporarily hide our application in case it overlaps the capture target, then we capture the screen area to a compatible bitmap and insert it into the clipboard, finally restoring our application's window.
The biggest challenge here was that I initially thought you should use the device context of the window you want to capture to create the compatible bitmap - however this led to the 'wrong' area being captured. Using "hdc=GetDC(HWND_DESKTOP)" gets things capturing correctly.
The code in DisplayInfoOnFoundWindow() in windowfinder.cpp receives a handle to the selected window. With this handle, it is simple to resize the target window (where h and w are the desired height and width of the target window):
WINDOWPLACEMENT wp; GetWindowPlacement(g_hwndFoundWindow, &wp); // Adjust width and height to required wp.rcNormalPosition.right=wp.rcNormalPosition.left+w; wp.rcNormalPosition.bottom=wp.rcNormalPosition.top+h; // Set window placement SetWindowPlacement(g_hwndFoundWindow, &wp);
Similarly, moving the window to a screen location is easily accomplished via the Get/SetWindowPlacement() Win32 functions.
Making the dialog stay on top of all other windows is easy, but not documented in a sufficiently clear enough way for my simple mind to understand in the MS docs:
To set the stay on top property:
SetWindowPos( hwndDlg, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW );
To remove it:
SetWindowPos( hwndDlg, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW );
We can make the dialog show more or less detail by resizing it using the position of a visible (or hidden) control on the dialog as a marker.
The following code block handles expanding / contracting the dialog:
WINDOWPLACEMENT dlgwp; GetWindowPlacement(hwndDlg, &dlgwp); CRect rect; UINT nBtnState=IsDlgButtonChecked(hwndDlg, IDC_EXPANDVIEW_CHECK); if(nBtnState == BST_CHECKED) // Expanded view { // Get window placement of bottom groupbox, // which is the marker for the expanded view GetWindowRect(GetDlgItem(hwndDlg, IDC_DETAILS_STATIC), &rect); dlgwp.rcNormalPosition.bottom=rect.bottom+8; SetWindowPlacement(hwndDlg, &dlgwp); } else // Shrunk view { // Get window placement of window text static, which // is the marker for the expanded view GetWindowRect(GetDlgItem(hwndDlg, IDC_WINTXT_STATIC), &rect); dlgwp.rcNormalPosition.bottom=rect.top+2; SetWindowPlacement(hwndDlg, &dlgwp); }
The IDC_DETAILS_STATIC ID refers to the static groupbox labeled "Details:" at the bottom of the expanded application window.
The IDC_WINTXT_STATIC ID refers to the static groupbox labeled "Window Text" on the dialog.
As you can see, we get the initial dimensions of the dialog and marker statics using GetWindowPlacement() and GetWindowRect() and adjust the WINDOWPLACEMENT's rcNormalPosition members. Finally we use the adjusted WINDOWPLACEMENT structure to set the new size of the dialog.
Hopefully what we have here is a reasonably useful little tool for software / web site developers. Along the way, I learned a little more about Win32 (but think I will stick with MFC given the choice!). I hope you find the tool useful, even if the source code is a mixture of Lim Bio Liong's original work and my quick and dirty (but hell, they seem to work!) hacks.
Finally, if you do find the tool useful, I'd really appreciate it if you could kindly take the time to click on the link to http://www.powerprogrammer.co.uk/ at the top right of the tool's dialog. Oh, and also, how about giving this article a nice rating so that others can be alerted to the benefits too! Thanks!
General
News
Question
Answer
Joke
Rant
Admin
Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads.
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 1 Jul 2005 Editor: Smitha Vijayan |
Copyright 2003 by peterboulton Everything else Copyright © CodeProject, 1999-2010 Web10 | Advertise on the Code Project |