再温WIN 32 API------ウィンドウにビットマップファイルを描画


1基本的な考え方
インタフェースシミュレーションを行う場合、ウィンドウにマップする必要があることがよくあります.画像の数が増えるにつれて、リソースファイルにビットマップを追加する方法はますます制御できなくなります.だから「リソースとプログラムの分離」の原則に基づいて、やはり外部ビットマップファイルを使うのがもっとはっきりしています.
では、ビットマップのマップ位置をどのように管理しますか?プログラムコードに書き込むと、結合ローが高すぎるという問題も発生します.解決策は、画像ファイル名とマップ位置の関係を個別のxmlファイルで記録する方法と、ビットマップファイルのファイル名にマップ位置情報を直接含める方法の2つです.本稿では、ビットマップファイル名のフォーマットがdescription_となるより簡単な後者を採用する.xxx-yyy.bmp、xxxがマップされたときのウィンドウに対するx座標、yyyがマップされたときのウィンドウに対するy座標、例えばエンジンボタン_100-200.bmp、マップを表す場合、目的座標点は(100200)です.
マップの実装については,bmpの1つのフォーマットをサポートするだけでよいことを考慮してGDIライブラリで行う.1つのビットマップファイルが複数回マップされる可能性がある(例えばリフレッシュされる場合)ことを考慮して、実装時に直接SetDIBitsToDevice()ではなく、まずDIBをCreateDIBitmap()を介してDDBに変換し、その後このDDBを保存することで、後でマップするたびにBitBlt()というDDBだけで済むようになり、効率が向上します.
 
2コード実装
BitmapHelper.h
#pragma once
/********************************************************************************
                            BitmapHelper     
    :
	       ,              ,           
	       BITMAP,                   。

    :
	           BitmapHelper   。    :

	BitmapHelper *pBmp = new BitmapHelper(L"D:\\  _100-300.bmp");
	pBmp->ShowOnWindow(this->m_hWnd);

	delete pBmp;  //               ,  
********************************************************************************/
class BitmapHelper
{
public:
	BitmapHelper(TCHAR* file);
	~BitmapHelper();

protected:
	TCHAR fileName[256] ; //      
	HBITMAP hBitmap;      //     
	int desX;             //   x  
	int desY;             //   y  
protected:
	void ShowOnWindow(HWND hwnd, int x, int y);   //         
public:
	HBITMAP CreateBitmapObjectFromDibFile(HDC hdc); //      DDB
	void ShowOnWindow(HWND hwnd);
	void ShowOnDevice(HDC dc, int x, int y);

};

 
BitmapHelper.cpp
#include "stdafx.h"
#include "BitmapHelper.h"
#include "string.h"

BitmapHelper::BitmapHelper(TCHAR* file)
{
	this->hBitmap = NULL;
	this->desX = -9999;
	this->desY = -9999;
	::StrCpyNW(this->fileName, file, 256);
	this->fileName[255] = TEXT('\0');
}

/*
    :       DDB
    : hdc   DC
     : DDB  ,    NULL
*/
HBITMAP BitmapHelper::CreateBitmapObjectFromDibFile(HDC hdc)
{
	BITMAPFILEHEADER* pbmfh = NULL;
	HANDLE hFile = NULL;
	DWORD dwFileSize = 0;
	
	hFile = CreateFile(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
	if (hFile == INVALID_HANDLE_VALUE)
	{
		return NULL;
	}
	dwFileSize = GetFileSize(hFile, NULL);
	pbmfh = (BITMAPFILEHEADER*)malloc(dwFileSize);
	if (pbmfh == NULL)
	{
		CloseHandle(hFile);
		return NULL;
	}
	DWORD dwBytesRead = 0;
	BOOL bSuccess = ::ReadFile(hFile, pbmfh, dwFileSize, &dwBytesRead, NULL);
	::CloseHandle(hFile);
	//            
	if (!bSuccess || dwBytesRead != dwFileSize || pbmfh->bfType != *(WORD*) "BM" || pbmfh->bfSize != dwFileSize)
	{
		free(pbmfh);
		return NULL;
	}

	HBITMAP hBitmap = ::CreateDIBitmap(hdc,
		(BITMAPINFOHEADER*)(pbmfh + 1),
		CBM_INIT,
		(BYTE*)pbmfh + pbmfh->bfOffBits,
		(BITMAPINFO*)(pbmfh + 1),
		DIB_RGB_COLORS);

	free(pbmfh);

	return hBitmap;
}
/*
  :           
  :hdc   DC, (x,y)        
*/
void BitmapHelper::ShowOnDevice(HDC hdc, int x, int y)
{
	if (this->hBitmap == NULL)
	{
		this->hBitmap = this->CreateBitmapObjectFromDibFile(hdc);
	}
	if (this->hBitmap != NULL)
	{
		BITMAP bitmap;
		::GetObject(this->hBitmap, sizeof(BITMAP), &bitmap);

		HDC hdcMem = ::CreateCompatibleDC(hdc);
		::SelectObject(hdcMem, this->hBitmap);
		::BitBlt(hdc, x, y, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, SRCCOPY);
		::DeleteDC(hdcMem);
	}
}
/*
  :          
  :hwnd     , (x,y)        
*/
void BitmapHelper::ShowOnWindow(HWND hwnd, int x, int y)
{
	if (this->hBitmap == NULL)
	{
		HDC hdc = ::GetDC(hwnd);
		this->hBitmap = this->CreateBitmapObjectFromDibFile(hdc);
		::ReleaseDC(hwnd, hdc);
	}
	if (this->hBitmap != NULL)
	{
		BITMAP bitmap;
		::GetObject(this->hBitmap, sizeof(BITMAP), &bitmap);

		HDC hdc = ::GetDC(hwnd);

		HDC hdcMem = ::CreateCompatibleDC(hdc);
		::SelectObject(hdcMem, this->hBitmap);
		::BitBlt(hdc, x, y, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, SRCCOPY);
		::DeleteDC(hdcMem);

		::ReleaseDC(hwnd, hdc);
	}
}
/*
  :                    
  : hwnd     
  :          name_xxx-yyy.bmp
*/
void BitmapHelper::ShowOnWindow(HWND hwnd)
{
	//      
	if (this->desX == -9999)
	{
		int i = 0;
		int indexLast_ = 0; //    _,       
		int indexLastDot = 0;   //    .,        
		int indexSep = 0;       //       -
		int n = wcslen(this->fileName);
		for (i = n-1; i >=0; i--)
		{
			if (this->fileName[i] == L'_')
			{
				break;
			}
		}
		indexLast_ = (i == 0 ? -1 : i); // -1         
		for (i = n - 1; i >= 0; i--)
		{
			if (this->fileName[i] == L'.')
			{
				break;
			}
		}
		indexLastDot = (i == 0 ? n : i); // n         

		int xyStart = indexLast_ + 1; //       
		int xyEnd = indexLastDot - 1;     //       

		for (i = xyStart; i <= xyEnd; i++)
		{
			if (this->fileName[i] == L'-')
			{
				break;
			}
		}
		indexSep = i == xyEnd ? -1 : i; // -1       -
		
		if (n==0 || indexSep==-1) {
			this->desX = 0;
			this->desY = 0;
		}
		else
		{
			TCHAR s_x[10];
			int count = indexSep - xyStart;
			wcsncpy_s(s_x, 10, this->fileName+xyStart, count);
			s_x[count] = L'\0';
			this->desX = _wtoi(s_x);

			WCHAR s_y[10];
			count = xyEnd - indexSep;
			wcsncpy_s(s_y, 10, this->fileName+indexSep+1, count);
			s_y[count] = L'\0';
			this->desY = _wtoi(s_y);
		}
	}
	this->ShowOnWindow(hwnd, this->desX, this->desY);
}
BitmapHelper::~BitmapHelper()
{
	if (this->hBitmap != NULL)         //       
	{
		::DeleteObject(this->hBitmap);
	}
}