Ddraw后台截图网上找了很久,也没有完整的,这里分享一下自己的代码。不过在实测的时候,发现,被遮挡部分虽然可以截取到画面,但画面是固定的,不会更新。只有没被遮挡的部分才会更新。在这里求助高手!
void *g_pBlt=NULL;
LPDIRECTDRAW g_lpDD = NULL;
LPDIRECTDRAWSURFACE g_pDrawSurface = NULL; // Our rendering device
BYTE Blt_Begin[5];//用于保存入口的5字节
//*/
//窗口截屏在这里进行。
HRESULT __stdcall New_Blt( LPDIRECTDRAWSURFACE p0, LPRECT p1,LPDIRECTDRAWSURFACE p2, LPRECT p3,DWORD p4, LPDDBLTFX p5)
{
HRESULT hr;
__asm pushad
//恢复hook
memcpy(g_pBlt,Blt_Begin,5);//先还原入口的5字节
hr = IDirectDrawSurface_Blt(p0,p1,p2,p3,p4,p5);
if(g_NeedGetBmp)
{
//复制整个表面到我们自己的表面
IDirectDrawSurface_Blt(g_pDrawSurface,NULL,p2,NULL,DDBLT_WAIT,NULL);
g_NeedGetBmp=0;//只调用一次
}
if(g_ReHook)//需要再次hook
{
//再次hook
*(BYTE*)g_pBlt=0xe9;
*(DWORD*)((BYTE*)g_pBlt+1)=(DWORD)New_Blt-(DWORD)g_pBlt-5;
}
__asm popad
return hr;
}
HBITMAP GameDDraw_GetWindowBmp(HWND hWnd,RECT *rc);
BOOL InitDraw(HWND hWnd)
{
DDSURFACEDESC desc;
HRESULT (WINAPI *pDirectDrawCreate)( GUID FAR *lpGUID, LPDIRECTDRAW FAR *lplpDD, IUnknown FAR *pUnkOuter );
pDirectDrawCreate=GetProcAddress(GetModuleHandle(TEXT("ddraw.dll")), "DirectDrawCreate");
if(pDirectDrawCreate==NULL)
{
MessageBox(NULL,"error0","",MB_OK);
return FALSE;
}
//创建DirectDraw
if (FAILED( pDirectDrawCreate(NULL,&g_lpDD,NULL)))
{
MessageBox(NULL,"error1","",MB_OK);
return FALSE;
}
if(FAILED(IDirectDraw_SetCooperativeLevel(g_lpDD,hWnd, DDSCL_NORMAL)))
{
MessageBox(NULL,"error2","",MB_OK);
return FALSE;
}
//创建后台表面
ZeroMemory(&desc,sizeof(desc));
desc.dwSize=sizeof(desc);
desc.dwFlags= DDSD_WIDTH|DDSD_HEIGHT|DDSD_CAPS;
desc.dwWidth=640;
desc.dwHeight=480;
desc.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN;
if (FAILED(IDirectDraw_CreateSurface(g_lpDD,&desc, &g_pDrawSurface, NULL)))
{
MessageBox(NULL,"error3","",MB_OK);
IDirectDraw_Release(g_lpDD);
return FALSE;
}
return TRUE;
}
void GamdDDraw_HookBlt(HWND hWnd)
{
if(g_pDrawSurface==NULL)
{
if(InitDraw(hWnd))
{
DWORD oldpro=0;
DWORD d3d9_adr=(DWORD)GetModuleHandleA("ddraw.dll");
g_pBlt=(LPVOID)((DWORD)GetClassVirtualFnAddress(g_pDrawSurface,5));
g_ReHook=1;//设置自动挂接
memcpy(Blt_Begin,g_pBlt,5);//保存IDirect3DDevice9::Present入口的5个字节
VirtualProtect(g_pBlt,5,PAGE_EXECUTE_READWRITE,&oldpro);
*(BYTE*)g_pBlt=0xe9;
*(DWORD*)((BYTE*)g_pBlt+1)=(DWORD)New_Blt-(DWORD)g_pBlt-5;
//MessageBox(NULL,"成功","",MB_OK);
}
}
}
void GameDDraw_UnHookBlt()
{
if(g_pDrawSurface)
{
//释放离开屏幕的表面
g_ReHook=0;
Sleep(500);//等待释放
IDirectDrawSurface_Release(g_pDrawSurface);
IDirectDraw_Release(g_lpDD);
g_pDrawSurface=NULL;
g_lpDD=NULL;
//g_pBlt=NULL;
}
}
HBITMAP GameDDraw_GetWindowBmp(HWND hWnd,const RECT *rc)
{
int Width,Height;
static volatile int only_one=0;
HBITMAP hBmp;
HDC hDC;
DDSURFACEDESC desc;
int CUT,num;
if(NULL==g_pDrawSurface)
GamdDDraw_HookBlt(hWnd);
if(NULL==g_pDrawSurface)
return NULL;
if(rc==NULL)
{
Width=640;
Height=480;
CUT=FALSE;
}
else
{
Width=rc->right-rc->left;
Height=rc->bottom-rc->top;
CUT=TRUE;
}
while(only_one)Sleep(g_Delay);
only_one=1;//多线程防止冲突
//强制更新窗口//试了好几个方法,不知道怎么更新窗口才有效
hDC=GetDC(hWnd);
g_SendMessage(hWnd,WM_PRINT,hDC,PRF_CLIENT);
ReleaseDC(hWnd,hDC);
//InvalidateRect(hWnd,NULL,TRUE);
g_NeedGetBmp=1;//开始截图
num=30;
while(--num)
{
if(g_NeedGetBmp==0)
break;
Sleep(g_Delay);
}
if(num==0)
return NULL;
//开始处理表面
ZeroMemory(&desc,sizeof(desc));
desc.dwSize = sizeof(desc);
if (SUCCEEDED(IDirectDrawSurface_Lock(g_pDrawSurface,NULL, &desc, DDLOCK_READONLY | DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR , NULL)))
//截图出来了,转换表面到bmp
//if (SUCCEEDED(IDirectDrawSurface_GetSurfaceDesc(g_pDrawSurface,&desc))) //g_sc.CaptureSurface(p0, p2 );
{
if(CUT)
{
char *p1,*p2,*s=malloc(Width*Height*4);
int y;
p1=((char *)desc.lpSurface);
p1+=(4*((rc->top)*640+rc->left));
p2=s;
for(y=0;y<Height;y++)
{
memcpy(p2,p1,Width*4);
p2+=Width*4;
p1+=640*4;
}
hBmp=CreateBitmap(Width,Height,1,32,s);
free(s);
}
else
{
//怎么转换为bmp呢
hBmp=CreateBitmap(Width,Height,1,32,desc.lpSurface);
}
IDirectDrawSurface_Unlock(g_pDrawSurface,desc.lpSurface);
#ifdef _DEBUG
SaveBmpToFile(hBmp,NULL);
#endif
only_one=0;
return hBmp;
}
only_one=0;
return NULL;
}
//*/
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!