第175章 ビットマップリソースの表示


今回は、ちょっと趣を変えてビットマップリソースを ロードしてSetDIBitsToDevice関数で表示します。 この時、ビットマップのカラーデータを読み出してCreatePalette関数で パレットハンドルを取得します。

基本的にはファイルからビットマップを読み出して表示するのと同じです。

1.FindResource関数でリソースのハンドルを取得する 2.LoadResource関数でリソースをグローバルメモリにロードする   第2引数が1.で取得したハンドルとなる 3.LockResource関数でメモリ内のリソースをロックする   戻り値がリソースの最初のバイトのポインタとなる 4.リソースがビットマップの時3.で取得したポインタはBITMAPINFO 構造体へのポインタと考えることができる 5.情報を読み出しカラーパレットのメモリを割り当てる 6.SetDIBitsToDevice関数で表示する

というような感じになります。 では、実際のプログラムを見てみましょう。

メニューの「ファイル」「リソースの読みこみ」を選択すると 左のようなダイアログが出てきます。表示したいビットマップリソースを 選択してOKボタンを押すとクライアント領域に表示されます。 リソースとなるビットマップはあらかじめ、モノクロ、16色、256色 フルカラーのものを用意しておきます。



左の図は16色のビットマップを表示しているところです。 VC++の場合256色まではビットマップエディタで ビットマップを作ることができますがフルカラーのものは 作れません。画像ソフトを利用して作って下さい。 この場合、「挿入」「リソース」で「Bitmap」を選択して 「インポート」でフルカラーのビットマップファイルを選択します。 ビットマップエディタには表示されませんがリソースとして有効です。

// res01.rcの一部 ///////////////////////////////////////////////////////////////////////////// // // Menu // MYMENU MENU DISCARDABLE BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "リソースの読みこみ", IDM_READ MENUITEM SEPARATOR MENUITEM "終了(&X)", IDM_END END END ///////////////////////////////////////////////////////////////////////////// // // Bitmap // MYBMP1 BITMAP DISCARDABLE "my59.BMP" MYBMP2 BITMAP DISCARDABLE "mybmp2.bmp" MYBMP3 BITMAP DISCARDABLE "mybmp3.bmp" MYBMP4 BITMAP DISCARDABLE "bitmap1.bmp" ///////////////////////////////////////////////////////////////////////////// // // Dialog // MYDLG DIALOG DISCARDABLE 0, 0, 130, 53 STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "ビットマップリソースの選択" FONT 9, "MS Pゴシック" BEGIN DEFPUSHBUTTON "OK",IDOK,70,7,50,14 PUSHBUTTON "キャンセル",IDCANCEL,70,24,50,14 COMBOBOX IDC_COMBO1,7,7,60,79,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP END

普通のメニュー、ビットマップ、ダイアログのリソース・スクリプトです。

// res01.cpp #ifndef STRICT #define STRICT #endif #include <windows.h> #include <windowsx.h> #include "resource.h" LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK MyDlgProc(HWND, UINT, WPARAM, LPARAM); ATOM InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); int ReadRes(HWND); char szClassName[] = "res01"; //ウィンドウクラス char szBMPName[64]; //ビットマップリソース名 HINSTANCE hInst; HPALETTE hPalette; int nClr; BOOL bLoad = FALSE; int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow) { MSG msg; hInst = hCurInst; //グローバル変数にコピー if (!InitApp(hCurInst)) return FALSE; if (!InitInstance(hCurInst, nCmdShow)) return FALSE; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } //ウィンドウ・クラスの登録 ATOM InitApp(HINSTANCE hInst) { WNDCLASSEX wc; wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WndProc; //プロシージャ名 wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInst; //インスタンス wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wc.lpszMenuName = "MYMENU"; //メニュー名 wc.lpszClassName = (LPCSTR)szClassName; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); return (RegisterClassEx(&wc)); } //ウィンドウの生成 BOOL InitInstance(HINSTANCE hInst, int nCmdShow) { HWND hWnd; hWnd = CreateWindow(szClassName, "猫でもわかるリソース", //タイトルバーにこの名前が表示されます WS_OVERLAPPEDWINDOW, //ウィンドウの種類 CW_USEDEFAULT, //X座標 CW_USEDEFAULT, //Y座標 CW_USEDEFAULT, //幅 CW_USEDEFAULT, //高さ NULL, //親ウィンドウのハンドル、親を作るときはNULL NULL, //メニューハンドル、クラスメニューを使うときはNULL hInst, //インスタンスハンドル NULL); if (!hWnd) return FALSE; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; }

このへんはいつもと同じです。WinMain関数の中でインスタンスハンドルを グローバル変数にコピーしている点に注意して下さい。

//ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { int id; HDC hdc; PAINTSTRUCT ps; HRSRC hRsrc; HANDLE hRes; LPBITMAPINFO lpBinfo; char *szBuf; switch (msg) { case WM_COMMAND: switch (LOWORD(wp)) { case IDM_END: SendMessage(hWnd, WM_CLOSE, 0, 0); break; case IDM_READ: ReadRes(hWnd); break; } break; case WM_PAINT: if (!bLoad) return (DefWindowProc(hWnd, msg, wp, lp)); hdc = BeginPaint(hWnd, &ps); if (nclr) { SelectPalette(hdc, hPalette, FALSE); RealizePalette(hdc); } hRsrc = FindResource(hInst, szBMPName, RT_BITMAP); hRes = LoadResource(hInst, hRsrc); lpBinfo = (LPBITMAPINFO)LockResource(hRes); szBuf = (char *)lpBinfo + sizeof(BITMAPINFOHEADER) + nClr * sizeof(RGBQUAD); SetDIBitsToDevice(hdc, 0, 0, lpBinfo->bmiHeader.biWidth, lpBinfo->bmiHeader.biHeight, 0, 0, 0, lpBinfo->bmiHeader.biHeight, szBuf, lpBinfo, DIB_RGB_COLORS); EndPaint(hWnd, &ps); break; case WM_CLOSE: id = MessageBox(hWnd, "終了してもよいですか", "終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { if (hPalette) DeleteObject(hPalette); DestroyWindow(hWnd); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0; }

メニューからIDM_READが選択されたら自作のReadRes関数を 読んでリソース名を取得しカラーパレットのハンドルを取得します。

WM_PAINTメッセージが来たらパレットを選択して実体化します。 そして、ビットマップをロードして表示します。 この一連の操作はビットマップをファイルから読み出して表示する時と 同じです。

HRSRC FindResource( HMODULE hModule, LPCTSTR lpName, // リソース名 LPCTSTR lpType // リソースのタイプ );

hModuleは、リソースの入っているモジュールのインスタンスハンドルを指定します。

lpNameは、リソース名を指定します。

lpTypeは、リソースのタイプを指定します。RT_BITMAP, RT_DIALOG, というように 「RT_何とか」というものが10数個用意されています。

戻り値はリソースハンドルです。失敗した時はNULLが返されます。

HGLOBAL LoadResource( HMODULE hModule, HRSRC hResInfo // リソースハンドル );

この関数でリソースをメモリにロードします。 hModuleには、インスタンスハンドルを指定します。

hResInfoには、FindResource関数で取得したリソースハンドルを指定します。

戻り値はロードされたリソースのグローバルメモリブロックのハンドルです。 失敗した時はNULLが返されます。

LPVOID LockResource( HGLOBAL hResData );

グローバルメモリブロックにロードされたリソースをロックして そのアドレスを取得します。失敗したらNULLが返されます。

プログラム終了時にはDeleteObject関数でパレットハンドルを破棄します。

int ReadRes(HWND hWnd) { HANDLE hResource, hPalMem; HRSRC hRsrc; LPBITMAPINFO lpbi; LPLOGPALETTE lplp; int i, id, index; char str[256]; char szCl[5][64] = { "フルカラー", "モノクロ", "16色", "256色", "その他"}; id = DialogBox(hInst, "MYDLG", hWnd, (DLGPROC)MyDlgProc); if (id == IDCANCEL) return -1; hRsrc = FindResource(hInst, szBMPName, RT_BITMAP); if (hRsrc == NULL) { MessageBox(hWnd, "FindResource Error", "Error", MB_OK); return -1; } hResource = LoadResource(hInst, hRsrc); if (hResource == NULL) { MessageBox(hWnd, "LoadResource Error", "Error", MB_OK); return -1; } lpbi = (LPBITMAPINFO)LockResource(hResource); if (lpbi->bmiHeader.biClrUsed != 0) nClr = lpbi->bmiHeader.biClrUsed; else { if (lpbi->bmiHeader.biBitCount == 24) nClr = 0; else nClr = 1 << (lpbi->bmiHeader.biBitCount); } if (nClr) { hPalMem = GlobalAlloc(GHND, sizeof(LOGPALETTE) + nClr * sizeof(PALETTEENTRY)); lplp = (LPLOGPALETTE)GlobalLock(hPalMem); lplp->palNumEntries = nClr; lplp->palVersion = 0x300; for (i = 0; i < nClr; i++) { lplp->palPalEntry[i].peRed = lpbi->bmiColors[i].rgbRed; lplp->palPalEntry[i].peGreen = lpbi->bmiColors[i].rgbGreen; lplp->palPalEntry[i].peBlue = lpbi->bmiColors[i].rgbBlue; lplp->palPalEntry[i].peFlags = NULL; } hPalette = CreatePalette(lplp); if (hPalette == NULL) MessageBox(hWnd, "CreatePalette Error", "Error", MB_OK); GlobalUnlock(hPalMem); GlobalFree(hPalMem); } bLoad = TRUE; switch (nClr) { case 0: index = 0; break; case 2: index = 1; break; case 16: index = 2; break; case 256: index = 3; break; default: index = 4; break; } wsprintf(str, "%sのリソースを読みこみます", szCl[index]); MessageBox(hWnd, str, "ビットマップ情報", MB_OK); InvalidateRect(hWnd, NULL, TRUE); return 0; }

メニューの「リソースの読みこみ」が選択されると この関数が呼ばれます。 まず、ダイアログボックスを表示してリソースの 名前を取得します。取得したリソース名はグローバル変数の szBMPNameに格納されます。

FindResource, LoadResource, LockResource関数で ロードされたリソースのアドレスを取得してlpbiにコピーします。 lpbiはこのビットマップの情報を含んだBITMAPINFO構造体 のアドレスと考えることもできます。これから、biClrUsed を調べます。これが0でない時は実際に使用されるカラーテーブルの インデックス数となります。0の時はbiBitCountに対応した カラー数が使用されます。

biBitCountが0ならフルカラーでカラーテープルは使用しません。 1の時は2色、4の時は16色、8の時は256色です。 これは、1に対してbiBitCountだけビット演算子で左にシフトすれば よいことがわかります。

必要なカラー数がわかったらカラーパレットのメモリを GlobalAllocで確保します。そして各カラーをパレットにロードして CreatePalette関数でパレットを作成します。

bLoadをTRUEにします。

ユーザーに色数を知らせます。

最後にInvalidateRect関数でWM_PAINTメッセージを出させます。

LRESULT CALLBACK MyDlgProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp) { static HWND hCtrl; switch (msg) { case WM_INITDIALOG: hCtrl = GetDlgItem(hDlg, IDC_COMBO1); ComboBox_AddString(hCtrl, "MYBMP1"); ComboBox_AddString(hCtrl, "MYBMP2"); ComboBox_AddString(hCtrl, "MYBMP3"); ComboBox_AddString(hCtrl, "MYBMP4"); if (bLoad) ComboBox_SetText(hCtrl, szBMPName); else ComboBox_SetText(hCtrl, "MYBMP1"); return TRUE; case WM_COMMAND: switch (LOWORD(wp)) { case IDOK: ComboBox_GetText(hCtrl, szBMPName, sizeof(szBMPName) - 1); EndDialog(hDlg, IDOK); return TRUE; case IDCANCEL: EndDialog(hDlg, IDCANCEL); return TRUE; } return FALSE; } return FALSE; }

ダイアログボックスのプロシージャです。

初期化処理としてコンボボックスに「MYBMP1」... 「MYBMP4」をComboBox_AddStringマクロで 追加しておきます。もし前回ロードされている ビットマップがあるなら(bLoad==TRUE)その名前を ComboBox_SetTextマクロで表示しておきます。 初めてロードされる時は「BITMAP1」を表示させておきます。

OKボタンが押されたらComboBox_GetTextマクロで 選択されたリソース名をszBMPNameに取得します。

さて、今回のプログラムは単にビットマップリソースを 表示するだけのものです。 第26章のプログラムと 比較してみて下さい。


[SDK第2部 Index] [総合Index] [Previous Chapter] [Next Chapter]

Update 09/Feb/1999 By Y.Kumei
当ホーム・ページの一部または全部を無断で複写、複製、 転載あるいはコンピュータ等のファイルに保存することを禁じます。