윈도우 프로그래밍을 하다보면 가끔 다른 윈도우의 화면을 갈무리 해야 하는 경우가 생깁니다. (Capture 처럼) 이럴때 아래의 코드 중 HWND GetHandleFromPID(DWORD pid); 함수를 사용하면 간단히 해당 프로그램의 HWND 를 얻을 수 있습니다.
#include <windows.h>
#include "winproc.h"
typedef struct _ProcessCallbackData
{
DWORD m_pid;
HWND m_hwnd;
} ProcessCallbackData;
BOOL CALLBACK EnumProc(HWND hwnd, LPARAM lParam)
{
DWORD pid = 0;
ProcessCallbackData *pcbd = (ProcessCallbackData *)lParam;
if ( IsWindowVisible(hwnd) == FALSE )
return TRUE;
GetWindowThreadProcessId(hwnd, &pid);
if ( pcbd->m_pid != pid )
return TRUE;
pcbd->m_hwnd = hwnd;
return FALSE;
}
HWND GetHandleFromPID(DWORD pid)
{
ProcessCallbackData cbd = {0};
if (pid == 0)
return NULL;
cbd.m_pid = pid;
cbd.m_hwnd = NULL;
EnumWindows( EnumProc, (LPARAM)&cbd );
return cbd.m_hwnd;
}
HWND GetHandleFromPID(DWORD pid) 를 통해 HWND 를 얻었으면 이제 HDC 를 얻고 해당 윈도우를 다른 Memory DC 에 복사 하여 이를 저장할 수 있습니다.
먼저 아래 코드를 먼저 보면
#include <windows.h>
HBITMAP HDC2HBITMAP( HDC hSrcDC, int nWidth, int nHeight)
{
BOOL bSuccess = FALSE;
HDC hMemDC = CreateCompatibleDC( hSrcDC );
HBITMAP hBitmap = CreateCompatibleBitmap( hSrcDC, nWidth, nHeight );
if ( hBitmap == NULL )
{
return NULL;
}
HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap);
if(!BitBlt(hMemDC, 0, 0, nWidth, nHeight, hSrcDC, 0, 0, SRCCOPY))
bSuccess = FALSE;
else
bSuccess = TRUE;
SelectObject(hMemDC, hOldBitmap);
DeleteDC(hMemDC);
return hBitmap;
}
PBITMAPINFO CreateBitmapInfoStruct(HBITMAP hBmp)
{
BITMAP bmp;
WORD cClrBits;
static
PBITMAPINFO pbmi = {0};
if (!GetObject(hBmp, sizeof(BITMAP), (LPSTR)&bmp))
return NULL;
cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel);
if (cClrBits == 1)
cClrBits = 1;
else
if (cClrBits <= 4)
cClrBits = 4;
else
if (cClrBits <= 8)
cClrBits = 8;
else
if (cClrBits <= 16)
cClrBits = 16;
else
if (cClrBits <= 24)
cClrBits = 24;
else
cClrBits = 32;
if (cClrBits != 24)
{
pbmi = (PBITMAPINFO) LocalAlloc(LPTR, sizeof(BITMAPINFOHEADER) +
sizeof(RGBQUAD) * (1<< cClrBits));
}
else
{
pbmi = (PBITMAPINFO) LocalAlloc(LPTR, sizeof(BITMAPINFOHEADER));
}
pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pbmi->bmiHeader.biWidth = bmp.bmWidth;
pbmi->bmiHeader.biHeight = bmp.bmHeight;
pbmi->bmiHeader.biPlanes = bmp.bmPlanes;
pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel;
if (cClrBits < 24)
pbmi->bmiHeader.biClrUsed = (1<<cClrBits);
pbmi->bmiHeader.biCompression = BI_RGB;
pbmi->bmiHeader.biSizeImage = ((pbmi->bmiHeader.biWidth * cClrBits +31) & ~31) ⁄8 * pbmi->bmiHeader.biHeight;
pbmi->bmiHeader.biClrImportant = 0;
return pbmi;
}
BOOL CreateBMPFile(LPTSTR pszFile, PBITMAPINFO pbi, HBITMAP hBMP, HDC hDC)
{
HANDLE hf;
BITMAPFILEHEADER hdr;
PBITMAPINFOHEADER pbih;
LPBYTE lpBits;
DWORD dwTotal;
DWORD cb;
BYTE *hp;
DWORD dwTmp;
pbih = (PBITMAPINFOHEADER) pbi;
if ( pbih->biSizeImage == 0 )
return FALSE;
lpBits = (LPBYTE) GlobalAlloc(GMEM_FIXED, pbih->biSizeImage);
if (!lpBits)
return FALSE;
if (!GetDIBits(hDC, hBMP, 0, (WORD) pbih->biHeight, lpBits, pbi, DIB_RGB_COLORS))
{
return FALSE;
}
hf = CreateFile( pszFile,
GENERIC_READ | GENERIC_WRITE,
(DWORD) 0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
(HANDLE) NULL );
if (hf == INVALID_HANDLE_VALUE)
return FALSE;
hdr.bfType = 0x4d42;
hdr.bfSize = (DWORD)(sizeof(BITMAPFILEHEADER) + pbih->biSize + pbih->biClrUsed
* sizeof(RGBQUAD) + pbih->biSizeImage);
hdr.bfReserved1 = 0;
hdr.bfReserved2 = 0;
hdr.bfOffBits = (DWORD)(sizeof(BITMAPFILEHEADER) + pbih->biSize + pbih->biClrUsed
* sizeof (RGBQUAD) );
if (!WriteFile(hf, (LPVOID) &hdr, sizeof(BITMAPFILEHEADER), (LPDWORD) &dwTmp, NULL))
return FALSE;
if ( !WriteFile(hf, (LPVOID) pbih, sizeof(BITMAPINFOHEADER) + pbih->biClrUsed * sizeof (RGBQUAD), (LPDWORD) &dwTmp, ( NULL)))
return FALSE;
dwTotal = cb = pbih->biSizeImage;
hp = lpBits;
if (!WriteFile(hf, (LPSTR) hp, (int) cb, (LPDWORD) &dwTmp,NULL))
return FALSE;
if (!CloseHandle(hf))
return FALSE;
GlobalFree((HGLOBAL)lpBits);
return TRUE;
}
HDC2BITMAP() 이 있고, 이를 이전에 얻은 HWND hWnd 를 통해 HDC hDC = GetWindowDC(hWnd); 를 수행 한 다음 얻은 HDC 로 HBITMAP 을 만들어 낼 수 있게 됩니다.
실제 예제를 들면 다음과 같이 사용될 수 있습니다.
HDC hDC = GetWindowDC( hWnd );
RECT winR = {0};
GetWindowRect( hWnd, &winR );
int nW = winR.right - winR.left;
int nH = winR.bottom - winR.top;
HBITMAP hBmp = HDC2HBITMAP( hDC, nW, nH );
if ( hBmp != NULL )
{
PBITMAPINFO bitmapInfo = CreateBitmapInfoStruct( hBmp );
CreateBMPFile( "test.bmp", bitmapInfo, hBmp, hDC );
}
이때 CreateBMPFile() 대신 GetDIBits() 를 이용하면 해당 Bitmap 의 DIB array 를 얻을 수 있으며, 이는 다른 형태의 데이터나 jpeglib 을 통해 JPEG 파일을 만들수도 있게 됩니다.