Grabowanie okna innej aplikacji

0

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.

0

No chyba przesadziłeś w BCB :


void __fastcall TForm1::Button1Click(TObject *Sender)
{
   HWND BCBHandle = FindWindow("NazwaOkna", NULL);

   if (BCBHandle)
   {
      HDC dc = GetWindowDC(BCBHandle);
      Graphics::TCanvas *ScreenCanvas = new Graphics::TCanvas;
      Graphics::TBitmap *BMP = new Graphics::TBitmap;
      ScreenCanvas->Handle = dc;

      TRect rect = ScreenCanvas->ClipRect;
      rect.Right = rect.Right - rect.Left;
      rect.Bottom = rect.Bottom - rect.Top;
      rect.Top = rect.Left = 0;

      BMP->Width = rect.Right;
      BMP->Height= rect.Bottom;
      BMP->Canvas->CopyRect(rect, ScreenCanvas, ScreenCanvas->ClipRect);

      BMP->SaveToFile("c:\\zrzut.bmp");

      delete ScreenCanvas;
      delete BMP;
      ReleaseDC(BCBHandle, dc);
   }
}
 

A jak nie pasuje BCB to zrób przekład na API WIN .
Zapewniam że nie jest to wielki problem .

0

Na WINAPI będzie to tak: znaleźć kontekst okna (FindWindow, GetWindowDC tak jak dzejo pokazał) i za pomocą BitBlt przenieść jego zawartość na inny kontekst, np kontekst utworzonej przez ciebie bitmapy, którą chcesz zapisać do pliku, albo kontekst okna twojego programu w którym screen ma być pokazany.

1 użytkowników online, w tym zalogowanych: 0, gości: 1