본문 바로가기

Developement/C/C++

Porcess ID 로 해당 윈도우의 HWND 를 얻고 BMP 로 저장.

 윈도우 프로그래밍을 하다보면 가끔 다른 윈도우의 화면을 갈무리 해야 하는 경우가 생깁니다. (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 파일을 만들수도 있게 됩니다.