VC-如何抓取DirectX的窗口?
对于使用GDI进行处理的窗口,用GDI的函数就可以获得窗口内容。但是使用了DirectX的窗口,这种方式就不行了,应该怎么去获取呢?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
对于使用GDI进行处理的窗口,用GDI的函数就可以获得窗口内容。但是使用了DirectX的窗口,这种方式就不行了,应该怎么去获取呢?
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
接受
或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
发布评论
评论(3)
原理很简单,其实就是把游戏当前屏幕的数据存成一个图片文件;
下面一段代码,它实现了DirectDraw下的的游戏截屏。
// 功能:将一个DirectDraw表面,存为一张24位BMP位图 (传入主表面即截屏)
// 输入:表面指针,输出的文件名
// 输出:是否成功
bool SaveToBitmapFile(LPDIRECTDRAWSURFACE lpSurface, char* filename)
{
WORD* lpBuffer; // 表面指针
int nPitch; // 表面跨距
int nWidth, nHeight; // 表面宽高
// 打开文件s
FILE* fp;
if( (fp=fopen(filename, "wb ")) != NULL )
{
// 锁定表面
DDSURFACEDESC ddsd;
ddsd.dwSize = sizeof(ddsd);
HRESULT ddrval = lpSurface-> Lock( NULL, &ddsd, DDLOCK_WAIT, NULL );
if( ddrval == DD_OK )
{
lpBuffer = (WORD *)ddsd.lpSurface;
nWidth = ddsd.dwWidth;
nHeight = ddsd.dwHeight;
nPitch = ddsd.lPitch > > 1; //lPitch以Byte为单位,GraphPitch以WORD为单位。所以GraphPitch = lPitch / 2;
}
// 保存文件头
BITMAPFILEHEADER FileHeader;
FileHeader.bfType = 'BM ';
FileHeader.bfSize = nWidth * nHeight * 3 + 0x36;
FileHeader.bfReserved1 = 0;
FileHeader.bfReserved2 = 0;
FileHeader.bfOffBits = 0x36;
fwrite(&FileHeader, sizeof(BITMAPFILEHEADER), 1, fp);
// 保存文件信息
BITMAPINFOHEADER Header;
Header.biSize = sizeof(BITMAPINFOHEADER); // 结构的大小
Header.biWidth = nWidth; // 宽
Header.biHeight = nHeight; // 高
Header.biPlanes = 1; // 固定
Header.biBitCount = 24; // 颜色数
Header.biCompression = BI_RGB; // 是否压缩
Header.biSizeImage = nWidth * nHeight * 3; // 图片的大小
Header.biXPelsPerMeter = 0;
Header.biYPelsPerMeter = 0;
Header.biClrUsed = 0;
Header.biClrImportant = 0;
fwrite(&Header, Header.biSize, 1, fp);
// 写入具体内容(从下向上存放)
fseek(fp, 0x36, SEEK_SET);
WORD word;
lpBuffer += nWidth * (nHeight - 1);
for(int i=0; i <nHeight; i++)
{
for(int j=0; j <nWidth; j++)
{
word = *lpBuffer;
fputc( GetBlue( word ), fp); // 蓝
fputc( GetGreen( word ), fp); // 绿
fputc( GetRed( word ), fp); // 红
lpBuffer++;
}
lpBuffer -= nPitch*2; // 指针转到上一行的开始
}
fclose(fp);
// 解锁表面
ddrval = lpSurface-> Unlock( NULL );
return true;
}
return false;
}
inline unsigned char GetRed(WORD color)
{
if( Is555 )
return (color> > 7) & 0xff;
else
return (color> > 8) & 0xff;
}
inline unsigned char GetGreen(WORD color)
{
if( Is555 )
return (color> > 2) & 0xff;
else
return (color> > 3) & 0xff;
}
inline unsigned char GetBlue(WORD color)
{
return (color & 0x1f) < < 3;
}
微软在Direct3D的接口中提供了函数D3DXSaveSurfaceToFileInMemory可以用来抓取:
HBITMAP MyClass::ScreenGrab()
{
//RenderTargetSurface.
IDirect3DSurface9* pRenderTargetSurface = NULL;
//DestinationTargetSurface
IDirect3DSurface9* pDestinationTargetSurface = NULL;
//DisplayMode
D3DDISPLAYMODE d3dDipMode;
//HBITMAP that will be the return of the method
HBITMAP hbm;
if (m_pd3dDevice == NULL)
return NULL;
//Get the client rectangle
RECT rc;
GetClientRect(myhWnd, &rc);
ClientToScreen(myhWnd, LPPOINT(&rc.left));
ClientToScreen(myhWnd, LPPOINT(&rc.right));
//GetRenderTargetSurface.
if(FAILED(m_pd3dDevice->GetRenderTarget(0, &pRenderTargetSurface)))
return NULL;
//Display Mode (d3dDipMode)
if(FAILED(m_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&d3dDipMode)))
return NULL;
//GetDestinationTargetSurface
if(FAILED(m_pd3dDevice->CreateOffscreenPlainSurface((rc.right - rc.left),
(rc.bottom - rc.top),
d3dDipMode.Format,
D3DPOOL_SYSTEMMEM,
&pDestinationTargetSurface,
NULL)))
return NULL;
//copy RenderTargetSurface -> DestTarget
if(FAILED(m_pd3dDevice->GetRenderTargetData(pRenderTargetSurface, pDestinationTargetSurface)))
return NULL;
LPD3DXBUFFER bufferedImage = NULL;
//Save the DestinationTargetSurface into memory (as a bitmap)
if(FAILED(D3DXSaveSurfaceToFileInMemory(&bufferedImage,
D3DXIFF_BMP,
pDestinationTargetSurface,
NULL,
NULL)))
{
return NULL;
}
//TRANSFORMATION REQUIRED HERE!!!!
//I WANT TO TRANSFORM bufferedImage INTO A HBITMAP SO THAT THE METHOD RETURNS
//THAT HBITMAP TO FULFIL MY CONTRACT.
//Release Resources
pRenderTargetSurface->Release();
pDestinationTargetSurface->Release();
//Return HBITMAT
return hbm;
}
截图的方法在文档里面已经很明确地说明了:只有一种最可靠的方法,就是GetFrontBufferData
CreateOffscreenSurface(..., &surface);
//窗口模式下应该是Desktop的大小;全屏下是屏幕分辨率的大小
pD3DDevice->GetFrontBufferData(0, surface);