C++基于D3D截图的实现

Home / C++ MrLee 2015-1-1 5375

在开发D3D截图之前,必须安装DX9.0或以上。不然不能正常编译!
// LScreenDlg.cpp : 实现文件
//
#include "stdafx.h"
#include "LScreen.h"
#include "LScreenDlg.h"
#include "afxdialogex.h"
#include 
#include 
#include 
#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// CLScreenDlg 对话框
#pragma comment(lib,"ddraw.lib")
#pragma comment(lib,"dxguid.lib")
#pragma comment(lib,"d3dx9d.lib")
#pragma comment(lib,"d3d9.lib")
LPDIRECTDRAW lpDD     = NULL;
LPDIRECTDRAWSURFACE lpDDSPrime  = NULL;
LPDIRECTDRAWSURFACE lpDDSBack  = NULL;
LPDIRECTDRAWSURFACE lpDDSGdi  = NULL;
LPDIRECTDRAWSURFACE lpSurf   = NULL;
DDSURFACEDESC DDSdesc;
BOOL m_b24=TRUE;
//rfbServerInitMsg m_scrinfo;
CRect   m_bmrect;
struct _BMInfo {
	BITMAPINFO  bmi;
	BOOL   truecolour;
	RGBQUAD   cmap[256];
} m_bminfo; // 用来保存位图信息的结构

// DirectX初始化。返回当前表面获取一张屏幕位图的存储空间大小
int DX_Init(HWND hWnd)
{
	HRESULT hr;
	// 初始化directX
	hr = DirectDrawCreate(0, &lpDD, 0);
	if (FAILED(hr))
		return FALSE;
	hr = lpDD->SetCooperativeLevel(hWnd, DDSCL_NORMAL);
	if (FAILED(hr))
		return FALSE; 
	ZeroMemory(&DDSdesc, sizeof(DDSdesc));
	DDSdesc.dwSize = sizeof(DDSdesc);
	DDSdesc.dwFlags = DDSD_CAPS;
	DDSdesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
	hr = lpDD->CreateSurface(&DDSdesc, &lpDDSPrime, 0);
	if (FAILED(hr))
		return FALSE; 
	hr = lpDD->GetGDISurface(&lpDDSGdi);
	if (FAILED(hr))
		return FALSE;
	ZeroMemory(&DDSdesc, sizeof(DDSdesc));
	DDSdesc.dwSize = sizeof(DDSdesc);
	DDSdesc.dwFlags = DDSD_ALL;
	hr = lpDDSPrime->GetSurfaceDesc(&DDSdesc);
	if (FAILED(hr))
		return FALSE;
	// 初始化位图信息
	if (!((DDSdesc.dwFlags & DDSD_WIDTH) && (DDSdesc.dwFlags & DDSD_HEIGHT)))
		return FALSE;
	m_bminfo.bmi.bmiHeader.biCompression = BI_RGB;//BI_BITFIELDS;
	m_bminfo.bmi.bmiHeader.biBitCount = (WORD)DDSdesc.ddpfPixelFormat.dwRGBBitCount;
	//m_bminfo.truecolour = DDSdesc.ddpfPixelFormat.dwFlags & DDPF_RGB;
	if(m_bminfo.bmi.bmiHeader.biBitCount > 8)
		m_bminfo.truecolour = TRUE;
	else
		m_bminfo.truecolour = FALSE;
	ZeroMemory(&DDSdesc, sizeof(DDSdesc));
	DDSdesc.dwSize = sizeof(DDSdesc);
	DDSdesc.dwFlags = DDSD_CAPS | DDSD_HEIGHT |DDSD_WIDTH; 
	DDSdesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
	DDSdesc.dwHeight = m_bmrect.Height();
	DDSdesc.dwWidth  = m_bmrect.Width();
	hr = lpDD->CreateSurface(&DDSdesc, &lpDDSBack, 0);
	if (FAILED(hr))
		return FALSE;
	switch (m_bminfo.bmi.bmiHeader.biBitCount)
	{
	case 32:
	case 24:
		// Update the bitmapinfo header
		m_b24 = TRUE;
		break;
	}  
	m_bminfo.bmi.bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
	m_bminfo.bmi.bmiHeader.biWidth = DDSdesc.dwWidth;
	m_bminfo.bmi.bmiHeader.biHeight = DDSdesc.dwHeight;
	m_bminfo.bmi.bmiHeader.biPlanes = 1;
	m_bminfo.bmi.bmiHeader.biCompression = BI_RGB;
	m_bminfo.bmi.bmiHeader.biSizeImage =
		abs((m_bminfo.bmi.bmiHeader.biWidth *
		m_bminfo.bmi.bmiHeader.biHeight *
		m_bminfo.bmi.bmiHeader.biBitCount)/ 8);
	m_bminfo.bmi.bmiHeader.biClrUsed  = 0;
	m_bminfo.bmi.bmiHeader.biClrImportant = 0;
	return m_bminfo.bmi.bmiHeader.biSizeImage;
}
// 捕捉屏幕。rect: 区域。scrBuff: 输出缓冲。scrBuffSize:  缓冲区大小
BOOL CaptureScreen()
{
	UINT buflen = m_bmrect.Width() * m_bmrect.Height() * 4;
	BYTE* buf = new BYTE[buflen];
	HRESULT hr=0;
	CRect rt;
	rt.left = 0;
	rt.top = 0;
	rt.right = m_bmrect.Width();
	rt.bottom = m_bmrect.Height();
	hr = lpDDSBack->BltFast(rt.left,rt.top,lpDDSPrime,rt,DDBLTFAST_NOCOLORKEY | DDBLTFAST_WAIT);
	if (FAILED(hr))
		return FALSE;
	DDSURFACEDESC surfdesc;
	ZeroMemory(&surfdesc, sizeof(surfdesc)); 
	surfdesc.dwSize = sizeof(surfdesc);
	hr   = lpDDSBack->Lock(rt, &surfdesc, DDLOCK_READONLY | DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR, NULL);
	if (FAILED(hr))
		return FALSE;
	memcpy(buf, surfdesc.lpSurface,m_bminfo.bmi.bmiHeader.biSizeImage);
	// unlock the primary surface
	lpDDSBack->Unlock(surfdesc.lpSurface); 

	CBitmap bitmap;
	bitmap.CreateBitmap(rt.Width(),rt.Height(),1,32,buf);
	//复制到粘贴板 
	OpenClipboard(NULL);
	EmptyClipboard();
	SetClipboardData(CF_BITMAP, bitmap);
	CloseClipboard();
	delete buf;
	return TRUE;
} 

CLScreenDlg::CLScreenDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(CLScreenDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CLScreenDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CLScreenDlg, CDialogEx)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BUTTON1, &CLScreenDlg::OnBnClickedButton1)
	ON_BN_CLICKED(IDC_BUTTON2, &CLScreenDlg::OnBnClickedButton2)
	ON_WM_HOTKEY()
	ON_WM_DESTROY()
END_MESSAGE_MAP()

// CLScreenDlg 消息处理程序
BOOL CLScreenDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();
	// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标
	// TODO: 在此添加额外的初始化代码
	RegisterHotKey(m_hWnd,1000,NULL,VK_F8);
	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}
// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。
void CLScreenDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文
		SendMessage(WM_ICONERASEBKGND, reinterpret_cast(dc.GetSafeHdc()), 0);
		// 使图标在工作区矩形中居中
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;
		// 绘制图标
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}
//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CLScreenDlg::OnQueryDragIcon()
{
	return static_cast(m_hIcon);
}
BOOL ScreenShot(LPDIRECT3DDEVICE9 lpDevice, HWND hWnd, TCHAR* fileName) 
{ 
	HRESULT hr; 
	// Get adapter display mode 
	D3DDISPLAYMODE mode; 
	if (FAILED(hr = lpDevice->GetDisplayMode(0, &mode))) 
		return hr; 
	// Create the surface to hold the screen image data 
	LPDIRECT3DSURFACE9 surf; 
	if (FAILED(hr = lpDevice->CreateOffscreenPlainSurface(mode.Width, 
		mode.Height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &surf, NULL))) //注意第四个参数不能是D3DPOOL_DEFAULT 
	{ 
		return hr; 
	} 
	// Get the screen data 
	if (FAILED(hr = lpDevice->GetFrontBufferData(0, surf))) 
	{ 
		surf->Release() ; 
		return hr ; 
	}
	// area to capture 
	RECT *rect = NULL ; 
	WINDOWINFO windowInfo ; 
	windowInfo.cbSize = sizeof(WINDOWINFO) ; 
	if(hWnd) // capture window 
	{ 
		GetWindowInfo(hWnd, &windowInfo) ; 
		rect = &windowInfo.rcWindow ; 
	} 
	// Save the screen date to file 
	hr = D3DXSaveSurfaceToFile(fileName, D3DXIFF_BMP, surf, NULL, NULL); 
	surf->Release() ; 
	return hr ; 
} 

void CLScreenDlg::OnBnClickedButton1()//GDI
{
	// TODO: 在此添加控件通知处理程序代码
	HWND hWnd = (HWND)0x00090D64;
	CDC *pDC;//屏幕DC
	pDC = CDC::FromHandle(::GetDC(hWnd));//获取目标句柄DC
	CRect rt;
	::GetWindowRect(hWnd,rt);
	int Width = rt.Width();
	int Height = rt.Height();
	CDC memDC;//内存DC
	memDC.CreateCompatibleDC(pDC);
	CBitmap memBitmap, *oldmemBitmap;//建立和屏幕兼容的bitmap
	memBitmap.CreateCompatibleBitmap(pDC, Width, Height);
	oldmemBitmap = memDC.SelectObject(&memBitmap);//将memBitmap选入内存DC
	memDC.BitBlt(0, 0, Width, Height, pDC, 0, 0, SRCCOPY);//复制屏幕图像到内存DC
	//复制到粘贴板 
	OpenClipboard();
	EmptyClipboard();
	SetClipboardData(CF_BITMAP, memBitmap);
	CloseClipboard();
	MessageBox("操作完成");
}
void testDX(HWND hWnd)
{
	LPDIRECT3D9 lpD3D = Direct3DCreate9(D3D_SDK_VERSION);
	LPDIRECT3DDEVICE9 lpDevice = NULL;
	D3DPRESENT_PARAMETERS d3dpp = {0};
	d3dpp.Windowed = TRUE;
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
	d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
	HRESULT Return_CreateDevice = lpD3D->CreateDevice (D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,
		hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &lpDevice);
	D3DDISPLAYMODE mode;
	HRESULT hr = lpDevice->GetDisplayMode(NULL, &mode);
	LPDIRECT3DSURFACE9 surf;
	hr = lpDevice->CreateOffscreenPlainSurface(mode.Width, mode.Height,D3DFMT_A8R8G8B8,D3DPOOL_SYSTEMMEM,&surf,NULL);
	hr = lpDevice->GetFrontBufferData(0,surf);
	ScreenShot(lpDevice,hWnd,"C:\\1.bmp");
}
void testDX2(HWND hWnd)
{
	LPDIRECT3DDEVICE9 lpDevice = NULL;
	LPDIRECT3D9 lpD3D = Direct3DCreate9(D3D_SDK_VERSION);
	D3DPRESENT_PARAMETERS d3dpp = {0};
	d3dpp.Windowed = TRUE;
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
	HRESULT result = lpD3D->CreateDevice( 
		D3DADAPTER_DEFAULT, 
		D3DDEVTYPE_HAL, 
		hWnd, 
		D3DCREATE_MIXED_VERTEXPROCESSING, 
		&d3dpp, 
		&lpDevice); 
	D3DDISPLAYMODE displayMode; 
	LPDIRECT3DSURFACE9 pd3dsFront = NULL; 
	lpDevice->GetDisplayMode(0, &displayMode); 
	lpDevice->CreateOffscreenPlainSurface(
		displayMode.Width,
		displayMode.Height,
		D3DFMT_A8R8G8B8,
		D3DPOOL_SYSTEMMEM,
		&pd3dsFront,
		NULL);
	lpDevice->GetFrontBufferData(0, pd3dsFront); 
	D3DXSaveSurfaceToFile("C:\\2.bmp", D3DXIFF_BMP, pd3dsFront, NULL, NULL); 
	if(pd3dsFront)
		pd3dsFront->Release(); 
}
void CLScreenDlg::OnBnClickedButton2()//DX
{
	// TODO: 在此添加控件通知处理程序代码
	// DirectX截屏
	testDX2(t_hWnd);
	MessageBox("操作完成");
}

void CLScreenDlg::OnHotKey(UINT nHotKeyId, UINT nKey1, UINT nKey2)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	CDialogEx::OnHotKey(nHotKeyId, nKey1, nKey2);
	if (nHotKeyId == 1000)
	{
		CPoint p;
		::GetCursorPos(&p);
		t_hWnd = ::WindowFromPoint(p);
		if(t_hWnd != NULL)
			MessageBox("成功");
	}
}

void CLScreenDlg::OnDestroy()
{
	CDialogEx::OnDestroy();
	// TODO: 在此处添加消息处理程序代码
	UnregisterHotKey(m_hWnd,1000);
}

本文链接:https://www.it72.com/600.htm

推荐阅读
最新回复 (0)
返回