C++ Direct3D多屏截图

6

大家好,我正在开发一款使用Direct3D技术的应用程序,以便捕获我的两个显示器桌面(当然是作为扩展桌面)。

以下代码可以正常工作,但我只能捕获主显示器,而不能捕获扩展桌面(只捕获了一个屏幕两次)。

我该如何调整这个解决方案以实现双屏捕获?

首先,我初始化Direct3D:

D3DDISPLAYMODE          d3dDisplayMode;
D3DPRESENT_PARAMETERS   d3dPresentationParameters; //Presentation parameters (backbufferwidth, height...)

if( (pSinfo->g_pD3D=Direct3DCreate9(D3D_SDK_VERSION)) == NULL )
    return FALSE;

if( pSinfo->g_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3dDisplayMode) ==  D3DERR_INVALIDCALL )
    return FALSE;

ZeroMemory(&d3dPresentationParameters,sizeof(D3DPRESENT_PARAMETERS));   
d3dPresentationParameters.Windowed = TRUE;
d3dPresentationParameters.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
d3dPresentationParameters.BackBufferFormat = d3dDisplayMode.Format;
d3dPresentationParameters.BackBufferHeight = gScreenRect.bottom = d3dDisplayMode.Height;
d3dPresentationParameters.BackBufferWidth = gScreenRect.right = d3dDisplayMode.Width;
d3dPresentationParameters.MultiSampleType = D3DMULTISAMPLE_NONE;
d3dPresentationParameters.SwapEffect= D3DSWAPEFFECT_DISCARD;
d3dPresentationParameters.hDeviceWindow = hWnd;
d3dPresentationParameters.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
d3dPresentationParameters.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;

pSinfo->uiWidth = d3dDisplayMode.Width;
pSinfo->uiHeight = d3dDisplayMode.Height;

if( pSinfo->g_pD3D->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_REF,hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING ,&d3dPresentationParameters,&pSinfo->g_pd3dDevice) != D3D_OK )
    return FALSE;

然后,循环执行连续截图并将图像数据保存在pData中:

while(1)
{
    pSinfo->g_pd3dDevice->GetRenderTarget(0, &pSinfo->pRenderSurface);
    pSinfo->g_pd3dDevice->CreateOffscreenPlainSurface(pSinfo->uiWidth, pSinfo->uiHeight, pSinfo->d3dFormat, D3DPOOL_SYSTEMMEM, &pSinfo->pRenderSurface, NULL);
    pSinfo->g_pd3dDevice->GetFrontBufferData(0, pSinfo->pRenderSurface);

    //D3DXSaveSurfaceToFile("Desktop.bmp", D3DXIFF_BMP, pSinfo->pRenderSurface,NULL, NULL); //Test

    ZeroMemory(&pSinfo->lockedRect, sizeof(D3DLOCKED_RECT));
    pSinfo->pRenderSurface->LockRect(&pSinfo->lockedRect,NULL, D3DLOCK_READONLY);

    memcpy((BYTE*)pSinfo->pData, (BYTE*)pSinfo->lockedRect.pBits, (pSinfo->uiWidth) * pSinfo->uiHeight * pSinfo->uiBitsPerPixels/8);

    pSinfo->pRenderSurface->UnlockRect();
    //InvalidateRect(((CMainFrame*)(pApp->m_pMainWnd))->m_hWnd,NULL,false);
    pSinfo->pRenderSurface->Release();
}

为了更清楚地了解我的问题和解决方案:
我有两个显示器,使用扩展的窗口桌面。在截屏时,我得到了两个屏幕截图,一个是主屏幕,另一个是扩展屏幕。我想要的是一张主屏幕的截图和一张扩展屏幕的截图。
我猜想我需要在某个地方设置一个参数,指示扩展桌面从Point.x = 1920(对于1080p屏幕)开始,但我不知道如何设置。
非常感谢您的帮助!
Dylan Screen Scheme

如果您有多个显示器,这段代码到底在做什么?你想让它做什么? - Anton Savin
这段代码可以截取我的桌面屏幕,并把截图存储到文件中,之后可以像播放视频一样回看截图。但是在回放截图的时候,我只能看到两个显示器上相同的内容(应用程序显示的是同一个屏幕)。我想要的是完整扩展屏幕的内容。 - Robert Jones
http://msdn.microsoft.com/en-us/library/windows/desktop/bb206364(v=vs.85).aspx - Brandon
@Brandon谢谢你提供的链接,我已经查看过了。不幸的是,我不理解它的工作原理,因为如果我重置一个设备,我必须重新创建它才能再次使用,对吗? - Robert Jones
该行代码:pSinfo->g_pd3dDevice->GetRenderTarget(0, &pSinfo->pRenderSurface); 是不必要的。 - Hinchy
1个回答

3
好的,我现在找到了问题。
需要注意的重要事项是使用以下设备创建:
pSinfo->g_pD3D->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_REF,hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING ,&d3dPresentationParameters,&pSinfo->g_pd3dDevice) != D3D_OK )

在这里,我正在创建一个使用D3DADAPTER_DEFAULT的设备,它不考虑其他显示器。因此,根据可用屏幕的数量,我调整了此代码:

for (i = 0; i < NUMBER_OF_DISPLAYS; i++)
{
    pSinfo->g_pD3D->CreateDevice(i,D3DDEVTYPE_REF,hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING ,&d3dPresentationParameters,&pSinfo->g_pd3dDevice) != D3D_OK )
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接