Witam. Od jakiegoś czasu piszę aplikację, która sprawdza procesy użytkownika, wypluwa okienko z jego wyborem. Następnie użytkownik powinien otrzymać screenshota tego wybranego okienka. Kod jest połączeniem WINAPI oraz wxWidget'sów.
Poniżej zamieszczam poszczególne pliki źródłowe i nagłówkowe, zaraz wyjaśnię w czym problem.
//clippingwindow.h
// clippingwindow.h
#ifndef CLIPPINGWINDOW_H
#define CLIPPINGWINDOW_H
#include "wx/wx.h"
#include <vector>
class MyApp: public wxApp {
virtual bool OnInit();
};
class MyFrame: public wxFrame {
wxButton* sh_button;
wxPanel* myPanel;
//wxFlexGridSizer * ssizer;
wxBitmap* screenshot;
void CaptureWindow( HWND hwnd );
const int showWindowChoiceDlg(const std::vector<wxString>& pTitles, const std::vector<wxString>& pClassNames);
public:
MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size);
void OnQuit( wxCommandEvent& event );
void OnPaint(wxPaintEvent& event);
void ToDoScreenshot( wxCommandEvent& event );
DECLARE_EVENT_TABLE()
enum
{
ID_Quit = 11000,
ID_Screenshot
};
};
#endif //CLIPPINGWINDOW_H
// clippingwindow.cpp : Defines the entry point for the console application.
#include "clippingwindow.h"
#include <wx/image.h>
BEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_MENU(ID_Quit, MyFrame::OnQuit)
EVT_BUTTON(ID_Screenshot, MyFrame::ToDoScreenshot)
EVT_PAINT(MyFrame::OnPaint)
END_EVENT_TABLE()
IMPLEMENT_APP(MyApp)
#include "stdafx.h"
#include "EnumProc.h"
#define tpf _tprintf
inline bool isswitch(TCHAR c) { return c==L'/' || c==L'-'; }
bool MyApp::OnInit()
{
MyFrame *frame = new MyFrame( wxT("clippingwindow"), wxPoint(50,50), wxSize(450,340) );
frame->Show(TRUE);
SetTopWindow(frame);
return TRUE;
}
MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
: wxFrame((wxFrame *)NULL, -1, title, pos, size), screenshot(NULL)
{
wxMenu *menuFile = new wxMenu;
menuFile->Append( ID_Quit, "E&xit" );
wxMenuBar *menuBar = new wxMenuBar;
menuBar->Append( menuFile, "&File" );
SetMenuBar( menuBar );
CreateStatusBar();
SetStatusText( wxT("Welcome to clippingwindow!") );
myPanel = new wxPanel(this);
//ssizer = new wxFlexGridSizer(2);
sh_button = new wxButton(myPanel, ID_Screenshot, _("Screenshot") );
//ssizer->Add(sh_button);
}
void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
{
Close(TRUE);
}
void MyFrame::ToDoScreenshot( wxCommandEvent& event ) {
std::vector<HWND> hvec;
std::vector<wxString> tvec;
std::vector<wxString> cvec;
int count=0;
BOOL bFirstModule = TRUE;
CProcessIterator itp;
for (DWORD pid=itp.First(); pid; pid=itp.Next()) {
// Note: first module in CProcessModuleIterator is EXE for this process
//
TCHAR modname[_MAX_PATH];
CProcessModuleIterator itm(pid);
HMODULE hModule = itm.First(); // .EXE
if (hModule) {
GetModuleBaseName(itm.GetProcessHandle(),
hModule, modname, _MAX_PATH);
// Iterate over all top-level windows in process
//
BOOL bFirstWindow = TRUE;
CMainWindowIterator itw(pid);
for (HWND hwnd = itw.First(); hwnd; hwnd=itw.Next()) {
if (bFirstModule) {
bFirstModule = FALSE;
}
if (bFirstWindow) {
bFirstWindow = FALSE;
}
char classname[256],title[256];
GetClassName(hwnd,classname,sizeof(classname));
GetWindowText(hwnd,title,sizeof(title));
hvec.push_back( hwnd );
tvec.push_back( wxString( title ) );
cvec.push_back( wxString( classname ) );
}
bFirstWindow || count++;
}
}
//tu okno wyboru
wxASSERT( hvec.size() == tvec.size() );
wxASSERT( tvec.size() == cvec.size() );
const int index = showWindowChoiceDlg(tvec, cvec);
if( index == -1 ) {
// select cancel in dialog window
return;
}
if( hvec[index] == NULL ) {
wxMessageBox(_("Handle to aplication is empty"), _("Warning"), wxICON_WARNING, this);
}
CaptureWindow( hvec[index] );
//--------------------
// Show new modal dialog window with tree or list proces, select one of.., and MyFrame::CaptureWindow( HWND hwnd );
/wxMessageBox( wxT("MyFrame::ToDoScreenshot"),
wxT("Make screenshot"), wxOK | wxICON_INFORMATION, this);/
}
const int
MyFrame::showWindowChoiceDlg(const std::vector<wxString>& pTitles, const std::vector<wxString>& pClassNames) {
wxASSERT(pTitles.size() == pClassNames.size());
// [PL] Tworzymy liste wyboru
wxArrayString lst;
int i=0;
for (std::vector<wxString>::const_iterator it = pTitles.begin(); it != pTitles.end(); it++) {
const wxString tLabel = *it + wxT(" [") + pClassNames[i] + wxT("]");
++i;
lst.Add(tLabel);
}
if (i==0) {
wxMessageBox(_("List is empty"), _("Warning"), wxICON_WARNING, this);
return -1;
}
wxSingleChoiceDialog tDlg(this, _("Select capture window"), _("Select capture window2"), lst);
if (tDlg.ShowModal() == wxID_OK) {
return tDlg.GetSelection();
}
return -1;
}; // showWindowChoiceDlg
void MyFrame::OnPaint(wxPaintEvent& event) {
if (screenshot != NULL) {
wxPaintDC dc( myPanel );
//dc.DrawBitmap( *screenshot, 0, 0, true /* use mask */ );
}
event.Skip();
}
void MyFrame::CaptureWindow( HWND hwnd ) {/* wskaniki nie sa puste - ale program poprawnie grabuje tylko siebie*/
//------------------
//test
/* SetCapture( hwnd );*/
- ShowWindow(hwnd, SW_HIDE); * hide and show == activate window
// ShowWindow(hwnd, SW_SHOW); - *SetActiveWindow( hwnd );
//
////Create a DC for the whole screen area
// wxImage::AddHandler(new wxBMPHandler);
//
// -
/*wxWindowDC*/ wxScreenDC dcWindow;*(/* wxWindow* aktywny*/ );
-
*wxWindowDC dcWindow( );
-
*Get the size of the screen/DC
// wxCoord screenWidth, screenHeight;
// dcWindow.GetSize(&screenWidth, &screenHeight);
//
// wxBitmap screenshot(screenWidth, screenHeight,-1);
//
// wxMemoryDC memDC;
//
// memDC.SelectObject(screenshot);
//
// memDC.Blit( 0, 0,
// screenWidth, screenHeight,&dcWindow,
// 0, 0 );
//
// memDC.SelectObject(wxNullBitmap);
//
// screenshot.SaveFile("screenshot.bmp",wxBITMAP_TYPE_BMP);
//
//-----------------
ShowWindow(hwnd, SW_HIDE); // hide and show == activate window
ShowWindow(hwnd, SW_SHOW);
*!hwnd = SetActiveWindow( hwnd );*it's safe - always window from this instance ?
!hwnd = GetActiveWindow();- always window from this instance ?
*!hwnd = GetTopWindow( hwnd ); * handle of parent window,
// Ten kod działa dla bierzącej applikacji, inaczej kopiuje czarną bitmapę
//Jak będzie działać ok to przeniosę btmapę do okna w wxwidgetsach
HDC hDCMem = CreateCompatibleDC(NULL); * handle to memory device context *! hDC - no effect!
RECT rect;
GetWindowRect(hwnd, & rect);
HBITMAP hBmp = NULL;
{
HDC hDC = GetDC(hwnd);
//HDC hDC =GetWindowDC(hwnd);
hBmp = CreateCompatibleBitmap(hDC, rect.right - rect.left, rect.bottom - rect.top);
ReleaseDC(hwnd, hDC);
}
// sprobuj zapisac bez schowka
HGDIOBJ hOld = SelectObject(hDCMem, hBmp);
SendMessage(hwnd, WM_PRINT, (WPARAM) hDCMem, PRF_CHILDREN | PRF_CLIENT | PRF_ERASEBKGND | PRF_NONCLIENT | PRF_OWNED);
SelectObject(hDCMem, hOld);
DeleteObject(hDCMem);
OpenClipboard(hwnd);
EmptyClipboard();
SetClipboardData(CF_BITMAP, hBmp);
CloseClipboard();
//---------------
// Paste from clipboard to wxBitmap and show
//wxImage::AddHandler(new wxBMPHandler);
/* wxStaticBitmap aa(myPanel, wxID_ANY, screenshot);
ssizer->Add(&aa, wxEXPAND );*/
/*
//
// screenshot = new wxBitmap(screenWidth, screenHeight,-1);
//
// BITMAP bm;
//GetObject ( hBmp, sizeof(bm), &bm );
// wxBitmap screenshot;
// if(screenshot.Create( (void*) &bm, wxBITMAP_TYPE_BMP, rect.right - rect.left, rect.bottom - rect.top) ) {
// screenshot.SaveFile("screenshot.bmp",wxBITMAP_TYPE_BMP);
// wxMessageBox(_("Save picture"), _("Warning"), wxICON_WARNING, this);
// }
*/
}
////////////////////////////////////////////////////////////////
// MSDN Magazine -- July 2002
// If this code works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
// Compiles with Visual Studio 6.0 and Visual Studio .NET
// Runs in Windows XP and probably Windows 2000 too.
//
#pragma once
//////////////////
// Iterate the top-level windows. Encapsulates ::EnumWindows.
//
class CWindowIterator {
protected:
HWND* m_hwnds; // array of hwnds for this PID
DWORD m_nAlloc; // size of array
DWORD m_count; // number of HWNDs found
DWORD m_current; // current HWND
static BOOL CALLBACK EnumProc(HWND hwnd, LPARAM lp);
// virtual enumerator
virtual BOOL OnEnumProc(HWND hwnd);
// override to filter different kinds of windows
virtual BOOL OnWindow(HWND hwnd) {
return TRUE;
}
public:
CWindowIterator(DWORD nAlloc=1024);
~CWindowIterator();
DWORD GetCount() { return m_count; }
HWND First();
HWND Next() {
return m_hwnds && m_current < m_count ? m_hwnds[m_current++] : NULL;
}
};
//////////////////
// Iterate the top-level windows in a process.
//
class CMainWindowIterator : public CWindowIterator {
protected:
DWORD m_pid; // process id
virtual BOOL OnWindow(HWND hwnd);
public:
CMainWindowIterator(DWORD pid, DWORD nAlloc=1024);
~CMainWindowIterator();
};
//////////////////
// Process iterator -- iterator over all system processes
// Always skips the first (IDLE) process with PID=0.
//
class CProcessIterator {
protected:
DWORD* m_pids; // array of procssor IDs
DWORD m_count; // size of array
DWORD m_current; // next array item
public:
CProcessIterator();
~CProcessIterator();
DWORD GetCount() { return m_count; }
DWORD First();
DWORD Next() {
return m_pids && m_current < m_count ? m_pids[m_current++] : 0;
}
};
//////////////////
// Iterate the modules in a process. Note that the first module is the
// main EXE that started the process.
//
class CProcessModuleIterator {
protected:
HANDLE m_hProcess; // process handle
HMODULE* m_hModules; // array of module handles
DWORD m_count; // size of array
DWORD m_current; // next module handle
public:
CProcessModuleIterator(DWORD pid);
~CProcessModuleIterator();
HANDLE GetProcessHandle() { return m_hProcess; }
DWORD GetCount() { return m_count; }
HMODULE First();
HMODULE Next() {
return m_hProcess && m_current < m_count ? m_hModules[m_current++] : 0;
}
};
////////////////////////////////////////////////////////////////
// MSDN Magazine -- July 2002
// If this code works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
// Compiles with Visual Studio 6.0 and Visual Studio .NET
// Runs in Windows XP and probably Windows 2000 too.
//
#include "stdafx.h"
#include "EnumProc.h"
CWindowIterator::CWindowIterator(DWORD nAlloc)
{
assert(nAlloc>0);
m_current = m_count = 0;
m_hwnds = new HWND [nAlloc];
m_nAlloc = nAlloc;
}
CWindowIterator::~CWindowIterator()
{
delete [] m_hwnds;
}
//////////////////
// Move to first top-level window.
// Stuff entire array and return the first HWND.
//
HWND CWindowIterator::First()
{
::EnumWindows(EnumProc, (LPARAM)this);
m_current = 0;
return Next();
}
//////////////////
// Static enumerator passes to virtual fn.
//
BOOL CALLBACK CWindowIterator::EnumProc(HWND hwnd, LPARAM lp)
{
return ((CWindowIterator*)lp)->OnEnumProc(hwnd);
}
//////////////////
// Virtual enumerator proc: add HWND to array if OnWindow is TRUE.
//
BOOL CWindowIterator::OnEnumProc(HWND hwnd)
{
if (OnWindow(hwnd)) {
if (m_count < m_nAlloc)
m_hwnds[m_count++] = hwnd;
}
return TRUE; // keep looking
}
//////////////////
// Main window iterator: special case to iterate main windows of a process.
//
CMainWindowIterator::CMainWindowIterator(DWORD pid, DWORD nAlloc)
: CWindowIterator(nAlloc)
{
m_pid = pid;
}
CMainWindowIterator::~CMainWindowIterator()
{
}
//////////////////
// virtual override: is this window a main window of my process?
//
BOOL CMainWindowIterator::OnWindow(HWND hwnd)
{
if (GetWindowLong(hwnd,GWL_STYLE) & WS_VISIBLE) {
DWORD pidwin;
GetWindowThreadProcessId(hwnd, &pidwin);
if (pidwin==m_pid)
return TRUE;
}
return FALSE;
}
CProcessIterator::CProcessIterator()
{
m_pids = NULL;
}
CProcessIterator::~CProcessIterator()
{
delete [] m_pids;
}
//////////////////
// Get first process.
// Call EnumProcesses to initialize entire array, then return first one.
//
DWORD CProcessIterator::First()
{
m_current = (DWORD)-1;
m_count = 0;
DWORD nalloc = 1024;
do {
delete [] m_pids;
m_pids = new DWORD [nalloc];
if (EnumProcesses(m_pids, nalloc*sizeof(DWORD), &m_count)) {
m_count /= sizeof(DWORD);
m_current = 1; // important: skip IDLE process with pid=0.
}
} while (nalloc <= m_count);
return Next();
}
CProcessModuleIterator::CProcessModuleIterator(DWORD pid)
{
// open the process
m_hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
FALSE, pid);
}
CProcessModuleIterator::~CProcessModuleIterator()
{
CloseHandle(m_hProcess);
delete [] m_hModules;
}
//////////////////
// Get first module in process. Call EnumProcesseModules to
// initialize entire array, then return first module.
//
HMODULE CProcessModuleIterator::First()
{
m_count = 0;
m_current = (DWORD)-1;
m_hModules = NULL;
if (m_hProcess) {
DWORD nalloc = 1024;
do {
delete [] m_hModules;
m_hModules = new HMODULE [nalloc];
if (EnumProcessModules(m_hProcess, m_hModules,
nalloc*sizeof(DWORD), &m_count)) {
m_count /= sizeof(HMODULE);
m_current = 0;
}
} while (nalloc <= m_count);
}
return Next();
}
A tak wygląda sampel dla przeglądania procesóww winapi:
////////////////////////////////////////////////////////////////
// MSDN Magazine -- July 2002
// If this code works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
// Compiles with Visual Studio 6.0 and Visual Studio .NET
// Runs in Windows XP and probably Windows 2000 too.
//
// lp -- list processes from command line.
// Illustrates how to use the various iterator classes in EnunmProc.h/cpp
//
#include "stdafx.h"
#include "EnumProc.h"
#define tpf _tprintf // to hide ugly underbars
// pre-declare functions
void help();
// global switches
BOOL bClassName=FALSE; // show window classname
BOOL bTitle=FALSE; // show window title
BOOL bBare=FALSE; // no header
// check for switch: / or -
inline BOOL isswitch(TCHAR c) { return c==L'/' || c==L'-'; }
//////////////////
// Main entry point
//
int main(int argc, TCHAR* argv[], TCHAR* envp[])
{
// Parse command line. Switches can come in any order.
//
for (int i=1; i<argc; i++) {
if (isswitch(argv[i][0])) {
for (UINT j=1; j<_tcslen(argv[i]); j++) {
switch(tolower(argv[i][j])) {
case 'c':
bClassName=TRUE;
break;
case 't':
bTitle=TRUE;
break;
case 'b':
bBare=TRUE;
break;
case '?':
default:
help();
return 0;
}
}
} else {
help();
return 0;
}
}
// Iterate over all processes
//
int count=0;
BOOL bFirstModule = TRUE;
CProcessIterator itp;
for (DWORD pid=itp.First(); pid; pid=itp.Next()) {
// Note: first module in CProcessModuleIterator is EXE for this process
//
TCHAR modname[_MAX_PATH];
CProcessModuleIterator itm(pid);
HMODULE hModule = itm.First(); // .EXE
if (hModule) {
GetModuleBaseName(itm.GetProcessHandle(),
hModule, modname, _MAX_PATH);
// Iterate over all top-level windows in process
//
BOOL bFirstWindow = TRUE;
CMainWindowIterator itw(pid);
for (HWND hwnd = itw.First(); hwnd; hwnd=itw.Next()) {
if (bFirstModule) {
if (!bBare) {
tpf(_T("PID %-13s%-8s %s%s%s\n"),_T("Module"),_T("HWND"),
bClassName ? _T("class name") : _T(""),
bClassName && bTitle ? _T("/") : _T(""),
bTitle ? _T("title") : _T(""));
tpf(_T("---- ------------ -------- ----------------\n"));
}
bFirstModule = FALSE;
}
if (bFirstWindow) {
tpf(_T("%04x %-13s"), pid, modname);
bFirstWindow = FALSE;
} else {
tpf(_T("%18s"),_T(" "));
}
char classname[256],title[256];
GetClassName(hwnd,classname,sizeof(classname));
GetWindowText(hwnd,title,sizeof(title));
tpf(_T("%08x %s %s\n"), hwnd,
bClassName ? classname : _T(""),
bTitle ? title : _T(""));
}
bFirstWindow || count++;
}
}
if (!bBare) {
tpf(_T("----\n"));
tpf(_T("%d processes found.\n"),count);
}
return 0;
}
void help()
{
tpf(_T("lp: List top-level proceses.\n"));
tpf(_T(" Copyright 2002 Paul DiLascia.\n\n"));
tpf(_T("Format: lp [/bct?]\n\n"));
tpf(_T("Options:\n"));
tpf(_T(" /b(are) no header\n"));
tpf(_T(" /c(lass) show window class names\n"));
tpf(_T(" /t(itle) show window titles\n"));
tpf(_T("\n"));
}
// Jeszcze standardoweplikidodawane do projektów windy:
#define VC_EXTRALEAN // Exclude rarely-used stuff from headers
#include <windows.h>
#include <stdio.h>
#include <conio.h> // getche
#include <tchar.h>
#include <psapi.h> // PSAPI for EnumProcesses
#include <string.h>
#include <assert.h>
#pragma warning(disable:4786) // disable annoying C4786
#include <string> // STL string class
#include <list> // STL list class
using namespace std; // use STL
//oraz
#include "stdafx.h"
//---
Każda metoda która pozwala na zgrabowanie okienka z innego programu jest dla mnie dobra.Walczę ztym odkilkudnia jest to priorytetowe zadanie. Biblioteki mam raczej narzucone, ewentualnie mogę uzywać jakiechś bezpłatnych.
Będę wdzięczny za wszelkie rzeczowe uwagi.