首页
社区
课程
招聘
[求助]Dx游戏窗口后台截屏问题
发表于: 2013-2-11 19:07 21893

[求助]Dx游戏窗口后台截屏问题

2013-2-11 19:07
21893
游戏用的是DirectDraw, 我的截屏是这样做的:
1.hook了DirectDrawCreate获取了LPDIRECTDRAW
2.hook了CreateSurface, 将主表面地址保存起来
3.创建一个离屏surface,将主表面copy到这个离屏表面上,然后输出到文件

现在问题是这个截屏后,若游戏窗口被遮挡,则被遮挡部分无法获取.
这个是什么原因呢? 是这种截图方式不支持遮挡部分截屏呢?
还是说跟游戏主表面的创建有关,有点诡异,游戏窗口大小是800*600,却创建了一个1400*900(显示器大小)的主表面.
还请高手指点下:)

	//创建后台表面
	if (g_lpDirectDrawCopySurface == NULL)
	{
		LPDIRECTDRAW lpDD = NULL;

		//创建DirectDraw 
		if (FAILED( DirectDrawCreate(NULL,&lpDD,NULL))) 
		{ 
			MyTrace(L_ERROR, "Couldn't create DirectDraw object."); 
			return E_FAIL;
		}

		if (FAILED(lpDD->SetCooperativeLevel(hwnd/*NULL*/, DDSCL_NORMAL))) 
		{ 
			MyTrace(L_ERROR, "SetCooperativeLevel failed.");
			lpDD->Release();
			return E_FAIL;
		}

		//创建后台表面 
		RECT rc;
		GetClientRect(hwnd, &rc);
	
		DDSURFACEDESC desc; 
		ZeroMemory(&desc,sizeof(desc)); 
		desc.dwSize=sizeof(desc); 
		desc.dwFlags= DDSD_WIDTH|DDSD_HEIGHT|DDSD_CAPS; 
		desc.dwWidth=/*::GetSystemMetrics(SM_CXSCREEN); */ /*primedesc.dwWidth*/ /*800*/ rc.right - rc.left;
		desc.dwHeight=/*::GetSystemMetrics(SM_CYSCREEN); */ /*primedesc.dwHeight*/ /*600*/ rc.bottom - rc.top;
		desc.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN; 

		if (FAILED(hr = lpDD->CreateSurface(&desc, &g_lpDirectDrawCopySurface, NULL))) 
		{ 
			MyTrace(L_ERROR, "CreateSurface copysurface failed.err=0x%x", hr);
			lpDD->Release();
			return E_FAIL;
		}
	}
 	

	RECT rc;
	//GetWindowRect(hwnd, &rc);
	GetClientRect(hwnd, &rc);
	MyTrace(L_DEBUG, "GetClientRect: %d,%d,%d,%d", rc.left, rc.right, rc.top, rc.bottom);

	DDSURFACEDESC desc; 
	ZeroMemory(&desc,sizeof(desc)); 
	desc.dwSize = sizeof(desc);
	if (FAILED(hr = g_lpDirectDrawCopySurface->GetSurfaceDesc(&desc))) 
	{ 
		MyTrace(L_ERROR, "copysurface GetSurfaceDesc failed.err=0x%x", hr);
		return E_FAIL;
	}
	else
	{
		MyTrace(L_DEBUG, "copysurface GetSurfaceDesc successfully, nWidth=%d, nHeight=%d", desc.dwWidth, desc.dwHeight);
	}

	if (FAILED(hr = g_lpDirectDrawCopySurface->BltFast(0,0,g_lpDirectDrawPrimeSurface,&rc,DDBLTFAST_NOCOLORKEY| DDBLTFAST_WAIT))) 
	{ 
		MyTrace(L_ERROR, "BltFast failed.err=0x%x", hr);
		return E_FAIL;
	}

	if (FAILED(hr = g_lpDirectDrawCopySurface->Lock(NULL, &desc, DDLOCK_WAIT|DDLOCK_NOSYSLOCK,NULL))) 
	{ 
		MyTrace(L_ERROR, "Lock failed.err=0x%x", hr);
		return E_FAIL;
	}

	//save to bmp
	if(SaveToBitmapFile(&desc, pszFilePath) != S_OK)
	{
		g_lpDirectDrawCopySurface->Unlock(NULL);
		MyTrace(L_ERROR, "SaveToBitmapFile failed.");
		return E_FAIL;
	}
	else
	{
		g_lpDirectDrawCopySurface->Unlock(NULL);
		MyTrace(L_DEBUG, "SaveToBitmapFile successfully.");
	}

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 0
支持
分享
最新回复 (15)
雪    币: 257
活跃值: (67)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
2
现在的DX游戏都是在前台才绘图,当游戏窗口最小化后,就不会再绘制了,因为这时候停止了DX调用,想要截图的话得先把窗口置前台,然后2个调用就搞定,只要没有最小化,窗口被挡住也可以截取,没有LZ那么麻烦
this->GetBackBuffer  //获取图形缓冲区
D3D9SaveSurfaceToFile  //保存到文件
2013-2-11 20:18
0
雪    币: 126
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
恩,最小化肯定不能这么简单就截取.
你的这个不是DirectDraw画图,是D3D9的, 虽然都是属于directx,但不一样啊
2013-2-11 20:35
0
雪    币: 257
活跃值: (67)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
4
D3D9SaveSurfaceToFile

D3D8也可以啊
D3D8SaveSurfaceToFile
2013-2-11 20:42
0
雪    币: 126
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
D3D9可以向下兼容8 但不能兼容DirectDraw吧? 我不是很熟悉这一块,但两者的API完全不一样,应该是不一样的
2013-2-11 21:20
0
雪    币: 257
活跃值: (67)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
6
游戏没有调用D3D8.DLL or D3D9.DLL?模块列表中没有?
2013-2-11 21:54
0
雪    币: 126
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
恩,没调用你说的DLL,调用的是ddraw.dll 属于DirectX,但不是D3D9/8之类
2013-2-11 22:17
0
雪    币: 257
活跃值: (67)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
8
那就把主表面缓冲区直接dump出来试试看行不行,ddraw并未提供类似SaveSurfaceToFile这样的接口
2013-2-11 22:31
0
雪    币: 126
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
我最上面那个代码就是dump主表面,能截屏,但遮挡部分无法截取,截下来的还是被遮挡.
实在不行就只能把遮挡的所有窗口透明,再截取....
其实我那个游戏用普通的BitBlt在未遮挡下就能截取,采用DirectDraw就是为了希望截取遮挡部分.
2013-2-11 23:13
0
雪    币: 257
活跃值: (67)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
10
DirectDraw都是游戏内部绘制的,不存在遮挡的问题
2013-2-11 23:18
0
雪    币: 126
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
你看我的代码,结果确实被遮挡了...
2013-2-12 00:02
0
雪    币: 8835
活跃值: (2404)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
12
据说游戏引擎在最小化或者窗体XX的时候,直接停止重绘节约gpu和cpu成本了~~
2013-2-12 17:06
0
雪    币: 257
活跃值: (67)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
13
传说游戏都是这样啊
2013-2-12 17:34
0
雪    币: 126
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
找到原因了,直接取主表面,copy一份到离屏表面,然后打印,那个结果就是遮挡的还是遮挡.
解决方法就是对主表面的blt函数hook,当主表面更新数据时,即调用blt时,此时传入的src表面是未遮挡的,就是麻烦点,那个src表面就是离屏表面,而且是多个拼凑的...
顺便还做了个小测试,在主表面的blt函数中加了个sleep(50),这个cpu占用率就降低了 哈哈哈
2013-2-12 17:59
0
雪    币: 28
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
说了这么多,代码呢
2017-9-19 22:39
0
雪    币: 5
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
最小化窗口怎么找图
2018-1-8 03:37
0
游客
登录 | 注册 方可回帖
返回
//