[C++] Screeny na Win Vista i 7

0

Witam,

mam problem z robieniem screenów na Windowsie Vista i 7. Na starszych wersjach bez problemowo programowo mogę robić screeny grom uruchamianym w OpenGL, natomiast na nowych systemach albo robi mi czarnego screena, albo na zrzucie ekranu widzę pulpit w rozdzielczości z jaką uruchomiłem grę.

Próbowałem między innymi takich funkcji, jak widać poniżej, ale żadna nie działa :( Screeny z pulpitu wychodzą dobre, ale z gier nie działają.

void Screeny::Get24BitBmp ( const int &nWidth, const int &nHeight,const HBITMAP &hBitmap , BYTE *lpDesBits)
{
	HDC hDC = ::GetDC( 0 );

	HDC memDC1 = ::CreateCompatibleDC ( hDC );
	HDC memDC2 = ::CreateCompatibleDC ( hDC );

	BYTE *lpBits = NULL;

	BITMAPINFO bmi;
	::ZeroMemory( &bmi, sizeof(BITMAPINFO) );
	bmi.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
	bmi.bmiHeader.biWidth       = nWidth;
	bmi.bmiHeader.biHeight      = nHeight;
	bmi.bmiHeader.biPlanes      = 1;
	bmi.bmiHeader.biBitCount    = 32;
	bmi.bmiHeader.biCompression = BI_RGB;

	HBITMAP hDIBMemBM  = ::CreateDIBSection( 0, &bmi, DIB_RGB_COLORS, (void**)&lpBits, NULL, NULL );
	
	HBITMAP hOldBmp1  = (HBITMAP)::SelectObject(memDC1, hDIBMemBM );

	HBITMAP hOldBmp2  = (HBITMAP) ::SelectObject ( memDC2,hBitmap);

	::BitBlt( memDC1, 0, 0, nWidth, nHeight, memDC2, 0, 0, SRCCOPY );

	for ( int i = 0 ; i < nHeight ; i++)
		::CopyMemory(&lpDesBits[i*3*nWidth],&lpBits[nWidth*3*(nHeight-1-i)],nWidth*3);

	// clean up
	::SelectObject	( memDC1, hOldBmp1  );
	::SelectObject	( memDC2,hOldBmp2  );
	::ReleaseDC		( 0, hDC      );
	::DeleteObject	( hDIBMemBM  );
	::DeleteObject	( hOldBmp1  );
	::DeleteObject	( hOldBmp2  );
	::DeleteDC		( memDC1  );
	::DeleteDC		( memDC2  );
}
//-------------------------------------------------------------------------------
BOOL Screeny::CaptureWindow( HWND hWndSrc,double fPreviewRatio,char *lpszFileName,BOOL bSaveToFile)
{
	RECT rc={0};
	::GetWindowRect(hWndSrc,&rc);
	int Width	= rc.right-rc.left;
	int Height	= rc.bottom-rc.top;
	Width		= (Width/4)*4;

	HDC		hdc		= ::GetDC(0);
	HDC		memDC	= ::CreateCompatibleDC ( hdc );
	HBITMAP memBM	= ::CreateCompatibleBitmap ( hdc, Width, Height );
	HBITMAP hOld	= (HBITMAP)::SelectObject ( memDC, memBM );

	int Bpp = ::GetDeviceCaps(hdc,BITSPIXEL);
	int size = (Bpp/8) * ( Width * Height );
    BYTE *lpBits1 = new BYTE[size];    
    BYTE *lpBits2 = new BYTE[Width * Height*3];    
    BYTE *lpBits3 = new BYTE[Width * Height*3];    

	BOOL Ret=TRUE;
	HBITMAP hBmp=0;
	int MinBlackPixels=Width * Height*10;
	int Count =0;
	int Size24 = Width * Height*3;
	while ( Count < 5 )
	{

		Ret = Capture(hWndSrc,memDC);
		::GetBitmapBits( memBM, size, lpBits1 );    
		 hBmp = ::CreateBitmap(Width,Height,1,Bpp,lpBits1);
		Get24BitBmp	(Width,Height,hBmp,lpBits2);
		int BlackPixels=0;
		for (int i=0;i<Size24;i+=3)
		{
			if ( lpBits2[i+2]==0 && lpBits2[i+1]==0 && lpBits2[i+0] == 0)
				BlackPixels++;
		}

		if ( BlackPixels < MinBlackPixels )
		{
			MinBlackPixels = BlackPixels;
			::memcpy(lpBits3,lpBits2,Size24);
			Count=0;
		}
		Count++;
		::DeleteObject(hBmp);
	}
	::memcpy(lpBits2,lpBits3,Size24);

	if (bSaveToFile)
		SaveBmpToFile(lpszFileName, Width, Height,24, (int*)lpBits2);

	delete [] lpBits1;    
	delete [] lpBits2;    
	delete [] lpBits3;    
	::SelectObject(memDC,hOld);
	::DeleteObject(memBM);
	::DeleteObject(hBmp);
	::DeleteDC(memDC);
	::ReleaseDC( 0, hdc );   

	return Ret;
}

BOOL Screeny::Capture( HWND hwnd,HDC memDC)
{
	typedef BOOL (WINAPI *tPrintWindow)( HWND, HDC,UINT);

    tPrintWindow pPrintWindow = 0;
    HINSTANCE handle = ::LoadLibraryA("gdi32.dll");
    if ( handle == 0 ) 
		return FALSE;

	pPrintWindow = (tPrintWindow)::GetProcAddress(handle, "PrintWindow");     
    int Ret = TRUE;
	if ( pPrintWindow ) 
		Ret = pPrintWindow(hwnd, memDC,0 );
	else
	{
		Ret = FALSE;
	}
	::FreeLibrary(handle);
	return (Ret? TRUE: FALSE);
}
0

bo HDC hDC = ::GetDC( 0 ); daje uchwyt pulpitu
pewnie w vista i 7 zmienili cos w managerze okienek i stad problem
poszukaj w google sugestii jak to zrobic pod vista/7

0

To wiem, że daje uchwyt do pulpitu. Ustawiałem również na uchwyty okien gier, ale wtedy właśnie dostawałem efekt czarnego screena. Na necie szukałem już pod wieloma hasłami i znajdywałem tylko jakieś wskazówki, że trzeba przechwytywać dane z bufora karty graficznej i korzystać z jakiejś dll obsługującej opengl, ale nie wiem do końca jak to zaimplementować. Gdy w Qt pisałem programik, który właśnie robił screena na podstawie bufora przekazywanego do karty graficznej, wychodziły mi dziwne rzeczy :D

http://taksi.sourceforge.net/ - tu jest open sourcowy programik, w którym to robienie screenów działa, ale nie byłem w stanie wyłuskać kodu, który jest mi potrzebny.

0

Poszukaj screen overlay, czy jakoś tak.

0

A jak się ma nakładanie obrazka na obraz z gry do screenowania? :P

0

Nikt z Was się z czymś takim nie spotkał?

0

Chciałbym odświeżyć temat. Oto moje funkcje do robienia screenów:

BOOL Screeny::CaptureWindow( HWND hWndSrc,double fPreviewRatio,char *lpszFileName,BOOL bSaveToFile)
{
	RECT rc={0};
	::GetWindowRect(hWndSrc,&rc);
	int Width	= rc.right-rc.left;
	int Height	= rc.bottom-rc.top;
	Width		= (Width/4)*4;

	HDC		hdc		= ::GetDC(hWndSrc);
	HDC		memDC	= ::CreateCompatibleDC ( hdc );
	HBITMAP memBM	= ::CreateCompatibleBitmap ( hdc, Width, Height );
	HBITMAP hOld	= (HBITMAP)::SelectObject ( memDC, memBM );

	int Bpp = ::GetDeviceCaps(hdc,BITSPIXEL);
	int size = (Bpp/8) * ( Width * Height );
    BYTE *lpBits1 = new BYTE[size];    
    BYTE *lpBits2 = new BYTE[Width * Height*3];    
    BYTE *lpBits3 = new BYTE[Width * Height*3];    

	BOOL Ret=TRUE;
	HBITMAP hBmp=0;
	int MinBlackPixels=Width * Height*10;
	int Count =0;
	int Size24 = Width * Height*3;
	while ( Count < 5 )
	{

		Ret = Capture(hWndSrc,memDC);
		::GetBitmapBits( memBM, size, lpBits1 );    
		 hBmp = ::CreateBitmap(Width,Height,1,Bpp,lpBits1);
		Get24BitBmp	(Width,Height,hBmp,lpBits2);
		int BlackPixels=0;
		for (int i=0;i<Size24;i+=3)
		{
			if ( lpBits2[i+2]==0 && lpBits2[i+1]==0 && lpBits2[i+0] == 0)
				BlackPixels++;
		}

		if ( BlackPixels < MinBlackPixels )
		{
			MinBlackPixels = BlackPixels;
			::memcpy(lpBits3,lpBits2,Size24);
			Count=0;
		}
		Count++;
		::DeleteObject(hBmp);
	}
	::memcpy(lpBits2,lpBits3,Size24);

	if (bSaveToFile)
		SaveBmpToFile(lpszFileName, Width, Height,24, (int*)lpBits2);

	delete [] lpBits1;    
	delete [] lpBits2;    
	delete [] lpBits3;    
	::SelectObject(memDC,hOld);
	::DeleteObject(memBM);
	::DeleteObject(hBmp);
	::DeleteDC(memDC);
	::ReleaseDC( 0, hdc );   

	return Ret;
}

BOOL Screeny::Capture( HWND hwnd,HDC memDC)
{
	typedef BOOL (WINAPI *tPrintWindow)( HWND, HDC,UINT);

    tPrintWindow pPrintWindow = 0;
    HINSTANCE handle = ::LoadLibraryA("gdi32.dll");
    if ( handle == 0 ) 
		return FALSE;

	pPrintWindow = (tPrintWindow)::GetProcAddress(handle, "PrintWindow");     
    int Ret = TRUE;
	if ( pPrintWindow ) 
		Ret = pPrintWindow(hwnd, memDC,0 );
	else
	{
		Ret = FALSE;
	}
	::FreeLibrary(handle);
	return (Ret? TRUE: FALSE);
}

Najgorsze jest to, że ona działa gdy okienko gry ( w tym wypadku Counter-Strike (opengl)) nie jest zmaksymalizowane. Proszę pomóżcie, bo naprawdę skończyły mi się pomysły :(

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