지금까지 설명한 핵심 코드에 주석과 예외 사항 체크를 추가한 완전한 OnLButtonDown 함수를 소스 3-1에 나타내었다.
#define DIB_HEADER_MARKER ((WORD) ('M' << 8) | 'B') void CBmpShowView::OnLButtonDown(UINT nFlags, CPoint point) { FILE* fp = NULL; fopen_s(&fp, "lenna.bmp", "rb"); if (!fp) return; BITMAPFILEHEADER bmfh; BITMAPINFOHEADER bmih; // BITMAPFILEHEADER 읽기 if (fread(&bmfh, sizeof(BITMAPFILEHEADER), 1, fp) != 1) { fclose(fp); return; } // BMP 파일임을 나타내는 'BM' 마커가 있는지 확인 if (bmfh.bfType != DIB_HEADER_MARKER) { fclose(fp); return; } // BITMAPINFOHEADER 읽기 if (fread(&bmih, sizeof(BITMAPINFOHEADER), 1, fp) != 1) { fclose(fp); return; } LONG nWidth = bmih.biWidth; LONG nHeight = bmih.biHeight; WORD nBitCount = bmih.biBitCount; DWORD dwWidthStep = (DWORD)((nWidth * nBitCount / 8 + 3) & ~3); DWORD dwSizeImage = nHeight * dwWidthStep; // DIB 구조 전체 크기 계산 (BITMAPINFOHEADER + 색상 테이블 + 픽셀 데이터) DWORD dwDibSize; if (nBitCount = = 24) dwDibSize = sizeof(BITMAPINFOHEADER) + dwSizeImage; else dwDibSize = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << nBitCount) + dwSizeImage; // 파일로부터 DIB 구조를 읽어서 저장할 메모리 공간 할당 BYTE* pDib = new BYTE[dwDibSize]; if (pDib = = NULL) { fclose(fp); return; } // 파일로부터 Packed-DIB 크기만큼을 읽기 fseek(fp, sizeof(BITMAPFILEHEADER), SEEK_SET); if (fread(pDib, sizeof(BYTE), dwDibSize, fp) != dwDibSize) { delete[] pDib; pDib = NULL; fclose(fp); return; } // 픽셀 데이터 시작 위치 계산 LPVOID lpvBits; if (nBitCount = = 24) lpvBits = pDib + sizeof(BITMAPINFOHEADER); else lpvBits = pDib + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << nBitCount); // DIB 화면 출력 CClientDC dc(this); ::SetDIBitsToDevice(dc.m_hDC, point.x, point.y, nWidth, nHeight, 0, 0, 0, nHeight, lpvBits, (BITMAPINFO*)pDib, DIB_RGB_COLORS); // 메모리 해제 및 파일 닫기 delete[] pDib; fclose(fp); CView::OnLButtonDown(nFlags, point); }