というような感じになります。 では、実際のプログラムを見てみましょう。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
このへんはいつもと同じです。WinMain関数の中でインスタンスハンドルを グローバル変数にコピーしている点に注意して下さい。// 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; }
メニューからIDM_READが選択されたら自作のReadRes関数を 読んでリソース名を取得しカラーパレットのハンドルを取得します。//ウィンドウプロシージャ 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; }
WM_PAINTメッセージが来たらパレットを選択して実体化します。 そして、ビットマップをロードして表示します。 この一連の操作はビットマップをファイルから読み出して表示する時と 同じです。
hModuleは、リソースの入っているモジュールのインスタンスハンドルを指定します。HRSRC FindResource( HMODULE hModule, LPCTSTR lpName, // リソース名 LPCTSTR lpType // リソースのタイプ );
lpNameは、リソース名を指定します。
lpTypeは、リソースのタイプを指定します。RT_BITMAP, RT_DIALOG, というように 「RT_何とか」というものが10数個用意されています。
戻り値はリソースハンドルです。失敗した時はNULLが返されます。
この関数でリソースをメモリにロードします。 hModuleには、インスタンスハンドルを指定します。HGLOBAL LoadResource( HMODULE hModule, HRSRC hResInfo // リソースハンドル );
hResInfoには、FindResource関数で取得したリソースハンドルを指定します。
戻り値はロードされたリソースのグローバルメモリブロックのハンドルです。 失敗した時はNULLが返されます。
グローバルメモリブロックにロードされたリソースをロックして そのアドレスを取得します。失敗したらNULLが返されます。LPVOID LockResource( HGLOBAL hResData );
プログラム終了時にはDeleteObject関数でパレットハンドルを破棄します。
メニューの「リソースの読みこみ」が選択されると この関数が呼ばれます。 まず、ダイアログボックスを表示してリソースの 名前を取得します。取得したリソース名はグローバル変数の szBMPNameに格納されます。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; }
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章のプログラムと 比較してみて下さい。
Update 09/Feb/1999 By Y.Kumei