/*
CIMAGE 안에 있는 JPEG 라이브러리를 이용해서
DC를 캡쳐한것을 JPEG, BMP로 저장하는 소스코드
긁어다 쓰는것도 엄청 복잡하구만 ㅠ.ㅠ
*JPEG 을 컴파일할때 NOT USING MFC 항목을 체크할것
*BMP는 MSDN을 참조
*JPG는 CODEGURU 참조
*ppt 를 전체화면으로 뛰웠을때 파워포인트를 캡쳐해서
저장하는 프로그램이라고 하면 될것임;;
*/
#include <windows.h>
#include <stdio.h>
extern "C" {
#include "jpeglib.h"
}
#include <setjmp.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
struct ima_error_mgr {
struct jpeg_error_mgr pub; /* "public" fields */
jmp_buf setjmp_buffer; /* for return to caller */
};
typedef ima_error_mgr *ima_error_ptr;
void CreateBMPFile(HWND hwnd, LPTSTR pszFile, PBITMAPINFO pbi, HBITMAP hBMP, HDC hDC) ;
void errhandler(LPTSTR pszFile, HWND hwnd);
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
//Header file code
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
HANDLE DDBToDIB(HBITMAP bitmap, DWORD dwCompression);
//In the relevant header file (up near the top):
BOOL DibToSamps(HANDLE hDib,
int nSampsPerRow,
struct jpeg_compress_struct cinfo,
JSAMPARRAY jsmpPixels,
LPTSTR pcsMsg);
BOOL JpegFromDib( HANDLE hDib, //Handle to DIB
int nQuality, //JPEG quality (0-100)
LPTSTR csJpeg, //Pathname to target jpeg file
LPTSTR pcsMsg); //Error msg to return
BOOL BuildSamps(HANDLE hDib,
int nSampsPerRow,
struct jpeg_compress_struct cinfo,
JSAMPARRAY jsmpArray,
LPTSTR pcsMsg);
RGBQUAD QuadFromWord(WORD b16);
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
//Source file code
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
//This function takes the contents of a DIB
//and turns it into a JPEG file.
//
//The DIB may be monochrome, 16-color, 256-color, or 24-bit color.
//
//Any functions or data items beginning with "jpeg_" belong to jpeg.lib,
//and are not included here.
//
//The function assumes 3 color components per pixel.
/////////////////////////////////////////////////////////////////////////////
BOOL JpegFromDib(HANDLE hDib, //Handle to DIB
int nQuality, //JPEG quality (0-100)
LPTSTR csJpeg, //Pathname to jpeg file
LPTSTR pcsMsg) //Error msg to return
{
//Basic sanity checks...
if (nQuality < 0 || nQuality > 100 ||
hDib == NULL ||
pcsMsg == NULL ||
csJpeg == "")
{
if (pcsMsg != NULL)
pcsMsg = "Invalid input data";
return FALSE;
}
pcsMsg = "";
LPBITMAPINFOHEADER lpbi = (LPBITMAPINFOHEADER)hDib;
byte *buf2 = 0;
//Use libjpeg functions to write scanlines to disk in JPEG format
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
FILE* pOutFile; //Target file
int nSampsPerRow; //Physical row width in image buffer
JSAMPARRAY jsmpArray; //Pixel RGB buffer for JPEG file
cinfo.err = jpeg_std_error(&jerr); //Use default error handling (ugly!)
jpeg_create_compress(&cinfo);
if ((pOutFile = fopen(csJpeg, "wb")) == NULL)
{
pcsMsg = "Cannot open ";
// pcsMsg += csJpeg;
jpeg_destroy_compress(&cinfo);
return FALSE;
}
jpeg_stdio_dest(&cinfo, pOutFile);
cinfo.image_width = lpbi->biWidth; //Image width and height, in pixels
cinfo.image_height = lpbi->biHeight;
cinfo.input_components = 3; //Color components per pixel
//(RGB_PIXELSIZE - see jmorecfg.h)
cinfo.in_color_space = JCS_RGB; //Colorspace of input image
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo,
nQuality, //Quality: 0-100 scale
TRUE); //Limit to baseline-JPEG values
jpeg_start_compress(&cinfo, TRUE);
//JSAMPLEs per row in output buffer
nSampsPerRow = cinfo.image_width * cinfo.input_components;
//Allocate array of pixel RGB values
jsmpArray = (*cinfo.mem->alloc_sarray)
((j_common_ptr) &cinfo,
JPOOL_IMAGE,
nSampsPerRow,
cinfo.image_height);
if (DibToSamps(hDib,
nSampsPerRow,
cinfo,
jsmpArray,
pcsMsg))
{
//Write the array of scan lines to the JPEG file
(void)jpeg_write_scanlines(&cinfo,
jsmpArray,
cinfo.image_height);
}
jpeg_finish_compress(&cinfo); //Always finish
fclose(pOutFile);
jpeg_destroy_compress(&cinfo); //Free resources
if (pcsMsg != "")
return FALSE;
else
return TRUE;
}
////////////////////////////////////////////////////////////////
//This function fills a jsmpArray with the RGB values
//for the CBitmap.
//
//It has been improved to handle all legal bitmap formats.
//
//A jsmpArray is a big array of RGB values, 3 bytes per value.
//
//Note that rows of pixels are processed bottom to top:
//The data in the jsamp array must be arranged top to bottom.
////////////////////////////////////////////////////////////////
BOOL DibToSamps(HANDLE hDib,
int nSampsPerRow,
struct jpeg_compress_struct cinfo,
JSAMPARRAY jsmpPixels,
LPTSTR pcsMsg)
{
//Sanity...
if (hDib == NULL ||
nSampsPerRow <= 0 || pcsMsg == NULL)
{
if (pcsMsg !=NULL)
pcsMsg="Invalid input data";
return FALSE;
}
int r=0, p=0, q=0, b=0, n=0,
nUnused=0, nBytesWide=0, nUsed=0, nLastBits=0, nLastNibs=0, nCTEntries=0,
nRow=0, nByte=0, nPixel=0;
BYTE bytCTEnt=0;
LPBITMAPINFOHEADER pbBmHdr= (LPBITMAPINFOHEADER)hDib; //The bit count tells you the format of the bitmap: //Decide how many entries will be in the color table (if any)
switch (pbBmHdr->biBitCount)
{
case 1:
nCTEntries = 2; //Monochrome
break;
case 4:
nCTEntries = 16; //16-color
break;
case 8:
nCTEntries = 256; //256-color
break;
case 16:
case 24:
case 32:
nCTEntries = 0; //No color table needed
break;
default:
pcsMsg = "Invalid bitmap bit count";
return FALSE; //Unsupported format
}
//Point to the color table and pixels
DWORD dwCTab = (DWORD)pbBmHdr + pbBmHdr->biSize;
LPRGBQUAD pCTab = (LPRGBQUAD)(dwCTab);
LPSTR lpBits = (LPSTR)pbBmHdr +
(WORD)pbBmHdr->biSize +
(WORD)(nCTEntries * sizeof(RGBQUAD));
//Different formats for the image bits
LPBYTE lpPixels = (LPBYTE) lpBits;
RGBQUAD* pRgbQs = (RGBQUAD*)lpBits;
WORD* wPixels = (WORD*) lpBits;
//Set up the jsamps according to the bitmap's format.
//Note that rows are processed bottom to top, because
//that's how bitmaps are created.
switch (pbBmHdr->biBitCount)
{
case 1:
nUsed = (pbBmHdr->biWidth + 7) / 8;
nUnused = (((nUsed + 3) / 4) * 4) - nUsed;
nBytesWide = nUsed + nUnused;
nLastBits = 8 - ((nUsed * 8) - pbBmHdr->biWidth);
for (r=0; r < pbBmHdr->biHeight; r++)
{
for (p=0,q=0; p < nUsed; p++)
{
nRow=(pbBmHdr->biHeight-r-1) * nBytesWide;
nByte = nRow + p;
int nBUsed = (p <(nUsed -1)) ? 8 : nLastBits;
for(b=0; b < nBUsed;b++)
{
bytCTEnt = lpPixels[nByte] << b;
bytCTEnt = bytCTEnt >> 7;
jsmpPixels[r][q+0] = pCTab[bytCTEnt].rgbRed;
jsmpPixels[r][q+1] = pCTab[bytCTEnt].rgbGreen;
jsmpPixels[r][q+2] = pCTab[bytCTEnt].rgbBlue;
q += 3;
}
}
}
break;
case 4:
nUsed = (pbBmHdr->biWidth + 1) / 2;
nUnused = (((nUsed + 3) / 4) * 4) - nUsed;
nBytesWide = nUsed + nUnused;
nLastNibs = 2 - ((nUsed * 2) - pbBmHdr->biWidth);
for (r=0; r < pbBmHdr->biHeight;r++)
{
for (p=0,q=0; p < nUsed;p++)
{
nRow=(pbBmHdr->biHeight-r-1) * nBytesWide;
nByte = nRow + p;
int nNibbles = p;
for(n=0; n < nNibbles;n++)
{
bytCTEnt=lpPixels[nByte] << (n*4);
bytCTEnt=bytCTEnt >> (4-(n*4));
jsmpPixels[r][q+0] = pCTab[bytCTEnt].rgbRed;
jsmpPixels[r][q+1] = pCTab[bytCTEnt].rgbGreen;
jsmpPixels[r][q+2] = pCTab[bytCTEnt].rgbBlue;
q += 3;
}
}
}
break;
default:
case 8: //Each byte is a pointer to a pixel color
nUnused = (((pbBmHdr->biWidth + 3) / 4) * 4) -
pbBmHdr->biWidth;
for (r=0;r < pbBmHdr->biHeight; r++)
{
for (p=0,q=0; p < pbBmHdr->biWidth; p++,q+=3)
{
nRow = (pbBmHdr->biHeight-r-1) * (pbBmHdr->biWidth + nUnused);
nPixel = nRow + p;
jsmpPixels[r][q+0] = pCTab[lpPixels[nPixel]].rgbRed;
jsmpPixels[r][q+1] = pCTab[lpPixels[nPixel]].rgbGreen;
jsmpPixels[r][q+2] = pCTab[lpPixels[nPixel]].rgbBlue;
}
}
break;
case 16: //Hi-color (16 bits per pixel)
for (r=0;r < pbBmHdr->biHeight; r++)
{
for (p=0,q=0; p < pbBmHdr->biWidth; p++,q+=3)
{
nRow = (pbBmHdr->biHeight-r-1) * pbBmHdr->biWidth;
nPixel = nRow + p;
RGBQUAD quad = QuadFromWord(wPixels[nPixel]);
jsmpPixels[r][q+0] = quad.rgbRed;
jsmpPixels[r][q+1] = quad.rgbGreen;
jsmpPixels[r][q+2] = quad.rgbBlue;
}
}
break;
case 24:
nBytesWide = (pbBmHdr->biWidth*3);
nUnused = (((nBytesWide + 3) / 4) * 4) -
nBytesWide;
nBytesWide += nUnused;
for (r=0;r < pbBmHdr->biHeight;r++)
{
for (p=0,q=0;p < (nBytesWide-nUnused); p+=3,q+=3)
{
nRow = (pbBmHdr->biHeight-r-1) * nBytesWide;
nPixel = nRow + p;
jsmpPixels[r][q+0] = lpPixels[nPixel+2]; //Red
jsmpPixels[r][q+1] = lpPixels[nPixel+1]; //Green
jsmpPixels[r][q+2] = lpPixels[nPixel+0]; //Blue
}
}
break;
case 32:
for (r=0; r < pbBmHdr->biHeight; r++)
{
for (p=0,q=0; p < pbBmHdr->biWidth; p++,q+=3)
{
nRow = (pbBmHdr->biHeight-r-1) *
pbBmHdr->biWidth;
nPixel = nRow + p;
jsmpPixels[r][q+0] = pRgbQs[nPixel].rgbRed;
jsmpPixels[r][q+1] = pRgbQs[nPixel].rgbGreen;
jsmpPixels[r][q+2] = pRgbQs[nPixel].rgbBlue;
}
}
break;
} //end switch
return TRUE;
}
////////////////////////////////////////
//This function turns a 16-bit pixel
//into an RGBQUAD value.
////////////////////////////////////////
RGBQUAD QuadFromWord(WORD b16)
{
BYTE bytVals[] =
{
0, 16, 24, 32, 40, 48, 56, 64,
72, 80, 88, 96, 104,112,120,128,
136,144,152,160,168,176,184,192,
200,208,216,224,232,240,248,255
};
WORD wR = b16;
WORD wG = b16;
WORD wB = b16;
wR <<= 1; wR >>= 11;
wG <<= 6; wG >>= 11;
wB <<= 11; wB >>= 11;
RGBQUAD rgb;
rgb.rgbReserved = 0;
rgb.rgbBlue = bytVals[wB];
rgb.rgbGreen = bytVals[wG];
rgb.rgbRed = bytVals[wR];
return rgb;
}
void main()
{
PBITMAPINFOHEADER pbih;
BITMAP bmp;
PBITMAPINFO pbmi;
WORD cClrBits;
LPBYTE lpBits;
HWND hPPT;
HDC hdc;
HDC memDC;
HBITMAP m_Bitmap;
int cx, cy;
printf("dll 파일이 불려 집니다. ");
hPPT=FindWindow("screenClass",NULL); //파워포인트 전체화면 차일드 윈도우
if (hPPT == NULL) {
printf("파워포인트가 실행중이지 않습니다 ");
} else {
hdc=GetDC(hPPT);
cx = GetSystemMetrics(SM_CXSCREEN);
cy = GetSystemMetrics(SM_CYSCREEN);
memDC = CreateCompatibleDC(hdc);
m_Bitmap = CreateCompatibleBitmap(hdc, cx, cy);
SelectObject ( memDC, m_Bitmap );
StretchBlt( memDC,
0, 0,
cx, cy, // qt 해상도 width, height
hdc,
0, 0,
cx, cy, // cx -> width, cy -> height
SRCCOPY);
}
// Retrieve the bitmap color format, width, and height.
if (!GetObject(m_Bitmap, sizeof(BITMAP), (LPSTR)&bmp))
// Convert the color format to a count of bits.
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;
// Allocate memory for the BITMAPINFO structure. (This structure
// contains a BITMAPINFOHEADER structure and an array of RGBQUAD
// data structures.)
if (cClrBits != 24)
pbmi = (PBITMAPINFO) GlobalAlloc(LPTR,
sizeof(BITMAPINFOHEADER) +
sizeof(RGBQUAD) * (1<< cClrBits));
// There is no RGBQUAD array for the 24-bit-per-pixel format.
else
pbmi = (PBITMAPINFO) GlobalAlloc(LPTR,
sizeof(BITMAPINFOHEADER));
// Initialize the fields in the BITMAPINFO structure.
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);
// If the bitmap is not compressed, set the BI_RGB flag.
pbmi->bmiHeader.biCompression = BI_RGB;
// Compute the number of bytes in the array of color
// indices and store the result in biSizeImage.
// For Windows NT, the width must be DWORD aligned unless
// the bitmap is RLE compressed. This example shows this.
// For Windows 95/98/Me, the width must be WORD aligned unless the
// bitmap is RLE compressed.
pbmi->bmiHeader.biSizeImage = ((pbmi->bmiHeader.biWidth * cClrBits +31) & ~31) /8
* pbmi->bmiHeader.biHeight;
// Set biClrImportant to 0, indicating that all of the
// device colors are important.
pbmi->bmiHeader.biClrImportant = 0;
HANDLE hDib = DDBToDIB(m_Bitmap, BI_RGB);
JpegFromDib(hDib, 75, "test.jpg", " ");
GlobalFree(hDib);
// CreateBMPFile(hPPT, "test.bmp", pbmi, m_Bitmap, memDC) ;
}
HANDLE DDBToDIB(HBITMAP bitmap, DWORD dwCompression)
{
// 리턴되는 HANDLE에는
// "비트맵 정보 -> 팔레트 정보 -> 비트맵 데이터"의 순서로
// 데이터가 저장된다.
// 256색 이상의 비트맵은 팔레트 정보가 없다.
BITMAP bm;
BITMAPINFOHEADER bi;
LPBITMAPINFOHEADER lpbi;
DWORD dwLen;
HANDLE hDIB;
HANDLE handle;
HDC hDC;
HPALETTE hPal;
// The function has no arg for bitfields
if( dwCompression == BI_BITFIELDS ) return NULL;
// 팔레트가 없는 경우 디폴트 팔레트를 사용
if (hPal == NULL)
hPal = (HPALETTE)GetStockObject(DEFAULT_PALETTE);
// 비트맵 정보를 얻어온다.
GetObject(bitmap, sizeof(BITMAP), (LPSTR)&bm);
// Initialize the bitmapinfoheader
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = bm.bmWidth;
bi.biHeight = bm.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = bm.bmPlanes * bm.bmBitsPixel;
bi.biCompression = dwCompression;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
// 256색 이하일 경우에만 색상의 수가 의미가 있다.
// 즉, 256색 이하일 경우에만 팔레트가 주어진다.
int nColors = 0;
if(bi.biBitCount <= 8) nColors = (1 << bi.biBitCount);
// 헤더의 크기
dwLen = bi.biSize + nColors * sizeof(RGBQUAD);
// We need a device context to get the DIB from
hDC = ::GetDC(NULL); // Screem DC를 얻음
// Screen DC에 팔레트를 설정
hPal = SelectPalette(hDC, hPal, FALSE);
RealizePalette(hDC);
// BITMAPINFOHEADER와 팔레트를 위한 메모리 할당
hDIB = GlobalAlloc(GMEM_FIXED, dwLen);
if (!hDIB){ // 메모리 할당 실패
SelectPalette(hDC, hPal, FALSE); // 팔레트 복귀
::ReleaseDC(NULL, hDC);
return NULL;
}
lpbi = (LPBITMAPINFOHEADER)hDIB;
*lpbi = bi;
// 구조체에 정보를 얻어오기 위해 데이터를 위한 버퍼를 NULL로 준다.
// 특히 이미지 크기를 나타내는 biSizeImage를 얻어온다.
GetDIBits(
hDC, // DC 핸들
bitmap, // 비트맵 핸들
0L, // start scan line
(DWORD)bi.biHeight, // 줄 수
(LPBYTE)NULL, // 비트맵 데이터를 위한 버퍼
(LPBITMAPINFO)lpbi, // 비트맵 정보 구조체에 대한 포인터
(DWORD)DIB_RGB_COLORS // 색상 정보
);
bi = *lpbi;
// If the driver did not fill in the biSizeImage field, then compute it
// Each scan line of the image is aligned on a DWORD (32bit) boundary
if (bi.biSizeImage == 0){
bi.biSizeImage = ((((bi.biWidth * bi.biBitCount) + 31) & ~31) / 8)
* bi.biHeight;
// If a compression scheme is used the result may infact be larger
// Increase the size to account for this.
if (dwCompression != BI_RGB)
bi.biSizeImage = (bi.biSizeImage * 3) / 2;
}
// 비트맵 데이터를 저장하기 위해 메모리를 재할당 한다.
dwLen += bi.biSizeImage;
if (handle = GlobalReAlloc(hDIB, dwLen, GMEM_MOVEABLE))
hDIB = handle;
else{
GlobalFree(hDIB);
// Reselect the original palette
SelectPalette(hDC,hPal,FALSE);
::ReleaseDC(NULL,hDC);
return NULL;
}
// 실제 비트맵의 데이터를 얻어온다.
lpbi = (LPBITMAPINFOHEADER)hDIB;
BOOL bGotBits = GetDIBits(
hDC, // DC 핸들
bitmap, // 비트맵 핸들
0L, // start scan line
(DWORD)bi.biHeight, // 줄 수
(LPBYTE)lpbi + (bi.biSize + nColors * sizeof(RGBQUAD)),
// 비트맵 데이터를 위한 버퍼
(LPBITMAPINFO)lpbi, // 비트맵 정보 구조체에 대한 포인터
(DWORD)DIB_RGB_COLORS // 색상 정보
);
if( !bGotBits )
{
GlobalFree(hDIB);
SelectPalette(hDC,hPal,FALSE);
::ReleaseDC(NULL,hDC);
return NULL;
}
// 팔레트를 복귀
SelectPalette(hDC,hPal,FALSE);
::ReleaseDC(NULL,hDC);
return hDIB;
// hDIB에 대해서는 호출한 쪽에서 메모리를 해제해 주어야 한다.
// GlobalFree(/* HANDLE */ hDIB);
}
void CreateBMPFile(HWND hwnd, LPTSTR pszFile, PBITMAPINFO pbi,
HBITMAP hBMP, HDC hDC)
{
HANDLE hf; // file handle
BITMAPFILEHEADER hdr; // bitmap file-header
PBITMAPINFOHEADER pbih; // bitmap info-header
LPBYTE lpBits; // memory pointer
DWORD dwTotal; // total count of bytes
DWORD cb; // incremental count of bytes
BYTE *hp; // byte pointer
DWORD dwTmp;
HANDLE hDIB;
pbih = (PBITMAPINFOHEADER) pbi;
lpBits = (LPBYTE) GlobalAlloc(GMEM_FIXED, pbih->biSizeImage);
if (!lpBits)
errhandler("GlobalAlloc", hwnd);
// Retrieve the color table (RGBQUAD array) and the bits
// (array of palette indices) from the DIB.
if (!GetDIBits(hDC, hBMP, 0, (WORD) pbih->biHeight, lpBits, pbi,
DIB_RGB_COLORS))
{
errhandler("GetDIBits", hwnd);
}
// Create the .BMP file.
hf = CreateFile(pszFile,
GENERIC_READ | GENERIC_WRITE,
(DWORD) 0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
(HANDLE) NULL);
if (hf == INVALID_HANDLE_VALUE)
errhandler("CreateFile", hwnd);
hdr.bfType = 0x4d42; // 0x42 = "B" 0x4d = "M"
// Compute the size of the entire file.
hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) +
pbih->biSize + pbih->biClrUsed
* sizeof(RGBQUAD) + pbih->biSizeImage);
hdr.bfReserved1 = 0;
hdr.bfReserved2 = 0;
// Compute the offset to the array of color indices.
hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) +
pbih->biSize + pbih->biClrUsed
* sizeof (RGBQUAD);
// Copy the BITMAPFILEHEADER into the .BMP file.
if (!WriteFile(hf, (LPVOID) &hdr, sizeof(BITMAPFILEHEADER),
(LPDWORD) &dwTmp, NULL))
{
errhandler("WriteFile", hwnd);
}
// Copy the BITMAPINFOHEADER and RGBQUAD array into the file.
if (!WriteFile(hf, (LPVOID) pbih, sizeof(BITMAPINFOHEADER)
+ pbih->biClrUsed * sizeof (RGBQUAD),
(LPDWORD) &dwTmp, ( NULL)) )
errhandler("WriteFile", hwnd);
// Copy the array of color indices into the .BMP file.
dwTotal = cb = pbih->biSizeImage;
hp = lpBits;
if (!WriteFile(hf, (LPSTR) hp, (int) cb, (LPDWORD) &dwTmp,NULL))
errhandler("WriteFile", hwnd);
// Close the .BMP file.
if (!CloseHandle(hf))
errhandler("CloseHandle", hwnd);
// Free memory.
GlobalFree((HGLOBAL)lpBits);
}
// 윈도우로 짜면 윈도우 화면에 에러를 보여줄 예정
void errhandler(LPTSTR pszFile, HWND hwnd)
{
printf("pszFile");
}