/* デスクトップ・マスコット のサンプル・プログラム その4 Win32 SDK/C&MFC Programming Tips(http://www3.freeweb.ne.jp/misc/kmiwaki/developer/tips/index.shtml)の ・非四角形のウィンドウを作るには?(デスクトップにマスコットを表示させるには?) ・ビットマップの形をしたリージョンを作成するには?(CreateRgnFromBmp) を元にしている。 これは、サンプル3-5の変更物。 実行すると、bmp絵の形のウィンドウが 画面の真中に出現し、ちょっとゆれながらアニメして表示される。 つかむこと可能。右クリックでメニューだして Exit を選んで終了。 bmp素材提供は, pukaku. 2000/05/20 by tenk* 2000/06/04 ちらつき対策. WM_PAINT中の処理が重たいとちらつきやすい? リージョンの更新をWM_TIMER側に戻したらマシになったかも。 (WM_PAINT中にWM_TIMERが実行される、ということはなさそだった。  WM_PAINTの再入でもないし。疑念で、WM_TIMERとWM_PAINTのやりとりは  mas_anmNoでなくmas_bmpNoに絵の番号経由にし、 各処理頭でmas_anmNo/mas_bmpNoの値は一時変数に移した)。 あと背景描画色を NULL_BRUSH でなく BLACK_BRUSH に変更。ちらついた とき多少マシに見えるかも。 2000/06/04 画面の真中に出現し、ちょっとゆれてみせる */ #include #include "resource.h" /*--------------------------------------------------------------------------*/ /* 現在のインスタンス */ static HINSTANCE app_hInst; /* 1コマ、何マイクロ秒か */ #define MICRO_SEC_PER_FRM (8 * (1000/60)) /* 8 フレーム(1/60秒). ちなみに 1000/60≒17ms */ /* マスコットキャラデータの管理用 */ #define MAS_BMP_W (80) // 起動時の窓サイズ. #define MAS_BMP_H (80) // 実際は BMPから取得するので、そのサイズが収まる範囲で適当に設定。 #define MAS_BMP_NUM (sizeof(mas_bmp_res)/sizeof(mas_bmp_res[0])) //絵の枚数(配列より計算) static int mas_bmp_res[] = { IDB_IMAGE_00, /* 0 */ IDB_IMAGE_01, /* 1 */ IDB_IMAGE_02, /* 2 */ }; static HBITMAP mas_hBmp[MAS_BMP_NUM]; static HRGN mas_hRgns[MAS_BMP_NUM]; static volatile HRGN mas_hRgn; static volatile int mas_bmpNo; #define MAS_ANM_NUM (sizeof(mas_anm)/sizeof(mas_anm[0])) //絵を表示する順番(配列より計算) static volatile int mas_anmNo; static int mas_anm[] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 1, 2, 2, 1}; /*--------------------------------------------------------------------------*/ LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); HRGN CreateRgnFromBmp(HBITMAP hBitmap, COLORREF cTransparentColor/* = 0xffffffff*/); /*--------------------------------------------------------------------------*/ int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE dummy_hPrevInstance, LPSTR dummy_lpCmdLine, int nCmdShow) { TCHAR *szWindowClass = "mascot test program"; WNDCLASSEX wcex; HWND hWnd; RECT rct; MSG msg; int x0,y0; /* BLOCK : ウィンドウ クラスの登録 */ wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = 0; wcex.lpfnWndProc = (WNDPROC) WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInst; wcex.hIcon = 0; wcex.hCursor = LoadCursor(NULL, IDC_ARROW); //wcex.hbrBackground = (HBRUSH)(NULL_BRUSH); wcex.hbrBackground = (HBRUSH)(BLACK_BRUSH); wcex.lpszMenuName = NULL; wcex.lpszClassName = szWindowClass; wcex.hIconSm = NULL; RegisterClassEx(&wcex); // とりあえず表示座標を画面の中心にする SystemParametersInfo(SPI_GETWORKAREA, 0, &rct, 0); x0 = (rct.right - MAS_BMP_W) / 2; y0 = (rct.bottom - MAS_BMP_H) / 2; /* メインウィンドウの作成 */ app_hInst = hInst; /* グローバル変数にインスタンス ハンドルの保存 */ hWnd = CreateWindowEx( WS_EX_TOPMOST | WS_EX_TOOLWINDOW , szWindowClass , NULL , WS_POPUP , x0 , y0 , MAS_BMP_W , MAS_BMP_H , NULL , NULL , hInst , NULL ); if (hWnd == 0) return FALSE; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); /* メイン メッセージ ループ */ while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_CREATE: { HRGN hRgn_tmp; RECT rect; int i,n; GetClientRect(hWnd, &rect); for (i = 0; i < MAS_BMP_NUM; i++) { mas_hBmp[i] = LoadBitmap(app_hInst, MAKEINTRESOURCE(mas_bmp_res[i])); mas_hRgns[i] = CreateRgnFromBmp(mas_hBmp[i], (UINT)-1); } hRgn_tmp = CreateRectRgn(0, 0, 0, 0); mas_anmNo = 0; mas_bmpNo = mas_anm[mas_anmNo]; CombineRgn(hRgn_tmp, mas_hRgns[mas_bmpNo], NULL, RGN_COPY); SetWindowRgn(hWnd, hRgn_tmp, 0); mas_hRgn = hRgn_tmp; SetProp(hWnd, "region", mas_hRgn); } /* タイマー割り込み設定. */ SetTimer(hWnd,1, MICRO_SEC_PER_FRM, NULL); break; case WM_TIMER: /* 単位時間ごとの処理. */ { // ウィンドウを揺らす static int tmr = 0; int n = (tmr++) % 12, d; RECT r; GetWindowRect(hWnd, &r); d = (n < 6) ? 1 : -1; MoveWindow(hWnd, r.left+d, r.top, r.right-r.left, r.bottom-r.top, TRUE); //SetWindowPos(hWnd, HWND_NOTOPMOST, r.left+d, r.top, r.right-r.left, r.bottom-r.top, SWP_NOACTIVATE|SWP_SHOWWINDOW); } { // CG変更の準備 int cgNoOld, cgNoNew; HRGN hRgn_tmp; cgNoOld = mas_anm[mas_anmNo]; mas_anmNo = (mas_anmNo + 1) % MAS_ANM_NUM; // アニメ番号を更新 cgNoNew = mas_anm[mas_anmNo]; if (cgNoNew != cgNoOld) { // 前回と絵が違えば更新 // リージョンの設定 hRgn_tmp = CreateRectRgn(0, 0, 0, 0); CombineRgn(hRgn_tmp, mas_hRgns[cgNoNew], NULL, RGN_COPY); //CombineRgn(hRgn_tmp, hRgn_tmp, mas_hRgns[cgNoNew], RGN_OR); SetWindowRgn(hWnd, hRgn_tmp, TRUE); if (mas_hRgn) DeleteObject(mas_hRgn); mas_hRgn = hRgn_tmp; SetProp(hWnd, "region", mas_hRgn); InvalidateRect(hWnd, NULL, 0); // 画面更新要求。WM_PAINTが実行される。 } mas_bmpNo = cgNoNew; // 次回描画する絵の番号を設定 } break; case WM_PAINT: { PAINTSTRUCT ps; HRGN hRgn_tmp; BITMAP bm; // 画像のヘッダ情報取得用 HDC dst_hdc; HDC src_hdc; int n; n = mas_bmpNo; // n = mas_anm[mas_anmNo]; GetObject(mas_hBmp[n], sizeof(BITMAP), &bm); dst_hdc = BeginPaint(hWnd, &ps); // 描画開始 { // bmp を描画 src_hdc = CreateCompatibleDC(dst_hdc); SelectObject(src_hdc, mas_hBmp[n]); BitBlt(dst_hdc, 0,0, bm.bmWidth, bm.bmHeight, src_hdc, 0,0, SRCCOPY); } EndPaint(hWnd, &ps); // 描画終了 DeleteDC(src_hdc); } break; case WM_DESTROY: //終了 { int i; for (i = 0; i < MAS_BMP_NUM; i++) { if (mas_hBmp[i]) DeleteObject(mas_hBmp[i]); if (mas_hRgns[i]) DeleteObject(mas_hRgns[i]); } // リージョンの解放 if (GetProp(hWnd, "region")) { if (mas_hRgn) DeleteObject(mas_hRgn); DeleteObject(GetProp(hWnd, "region")); RemoveProp(hWnd, "region"); } } KillTimer(hWnd,1); /* タイマー割り込み終了 */ PostQuitMessage(0); /* 終了リクエスト */ break; case WM_NCRBUTTONDOWN: { // 右ボタンが押されたときの処理。ユーザ終了ができるようメニューを出す。 int xPos, yPos; HMENU hMenu, hSubMenu; xPos = LOWORD(lParam); yPos = HIWORD(lParam); hMenu = LoadMenu(app_hInst, MAKEINTRESOURCE(IDC_MAINMENU)); hSubMenu = GetSubMenu(hMenu, 0); TrackPopupMenu(hSubMenu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RIGHTBUTTON, xPos, yPos, 0, hWnd, NULL); } break; case WM_COMMAND: { /* メニュー選択処理 */ //int wmEvent = HIWORD(wParam); int wmId = LOWORD(wParam); switch (wmId) { case IDM_EXIT: DestroyWindow(hWnd); break; default: return DefWindowProc(hWnd, uMsg, wParam, lParam); } } break; case WM_NCHITTEST: /* 窓をつかんだとき、あたかもタイトルバーにマウスがあるようにWindowsを騙す */ wParam = DefWindowProc(hWnd, uMsg, wParam, lParam); if (wParam == HTCLIENT) return HTCAPTION; return wParam; default: return DefWindowProc(hWnd, uMsg, wParam, lParam); } return 0; } /*--------------------------------------------------------------------------*/ /* 関数 : CreateRgnFromBmp ( HBITMAP, COLORREF ) */ /* 用途 : ビットマップからリージョンを作成する */ /* 引数 : */ /* hBitmap - リージョンを作成するビットマップ */ /* cTransparentColor - 透明色(RGB(255,255,255)のように指定する) */ /* デフォルトでは左下隅のドットの色が透明色となる */ HRGN CreateRgnFromBmp(HBITMAP hBitmap, COLORREF cTransparentColor/* = 0xffffffff*/) { BITMAP bm; /* BITMAP structure */ HBITMAP hDIBSection = NULL; /* Handle to DIB */ COLORREF *pBits = NULL; /* Pointer to the DIB's bit values */ HRGN hRgn; /* Handle to Region */ /* hBitmap のチェック */ if (hBitmap == 0) return NULL; /* ビットマップのサイズを取得 */ if (GetObject(hBitmap, sizeof(bm), &bm) == 0) return NULL; /* BLOCK : DIBの作成 */ /* 成功すると hDIBSection にビットマップハンドル、pBits にビットへの */ /* ポインタが設定される。(DeleteObject(hDIBSection); を忘れてはいけない) */ /* 失敗すると hDIBSection 及び pBits は NULL のまま。 */ { HDC hMemDC; /* Handle to a device context : DIB */ HDC hCopyDC = NULL; /* Handle to a device context : DDB -> DIB */ HBITMAP hOldDIBsBmp = NULL; /* Handle of the object being replaced : DIB */ HBITMAP hOldDDBsBmp = NULL; /* Handle of the object being replaced : DDB */ BITMAPINFOHEADER bmih; /* DIB's BITMAPINFOHEADER structure */ BOOL bResultBitBlt = TRUE; /* Result of BitBlt function */ /* メモリデバイスコンテキストを作成 */ hMemDC = CreateCompatibleDC(NULL); if (hMemDC == NULL) goto CLEANUP_DIB; /* DIB(Device Independent Bitmaps : デバイスに依存しないビットマップ) */ /* のヘッダ情報を書きこむ */ bmih.biSize = sizeof(BITMAPINFOHEADER), /* size of the structure */ bmih.biWidth = bm.bmWidth; /* width of the bitmap */ bmih.biHeight = bm.bmHeight; /* height of the bitmap */ bmih.biPlanes = 1; /* must be set to 1 */ bmih.biBitCount = 32; /* maximum of 2^32 colors */ bmih.biCompression = BI_RGB; /* an uncompressed format */ bmih.biSizeImage = 0; /* must be set to zero for BI_RGB bitmaps */ bmih.biXPelsPerMeter = 0; /* set to zero */ bmih.biYPelsPerMeter = 0; /* set to zero */ bmih.biClrUsed = 0; /* must be set to zero */ bmih.biClrImportant = 0; /* set to zero, all colors are required */ /* DIBの作成 */ hDIBSection = CreateDIBSection( hMemDC, /* HDC hdc : handle to device context */ (CONST BITMAPINFO *)&bmih, /* CONST BITMAPINFO *pbmi : pointer to BITMAPINFO structure */ DIB_RGB_COLORS, /* UINT iUsage : color data type(RGB values) */ (void **) &pBits, /* VOID *ppvBits : pointer to receive the bitmap's bit values */ NULL, /* HANDLE hSection : handle to a file mapping object. */ /* This parameter can be NULL. */ 0 /* DWORD dwOffset : ignored by hSection */ ); if (hDIBSection == NULL) goto CLEANUP_DIB; /* 作成したDIBをDCに選択 */ hOldDIBsBmp = (HBITMAP) SelectObject(hMemDC, hDIBSection); /* 画像の転送元となるメモリデバイスコンテキストを作成 */ hCopyDC = CreateCompatibleDC(hMemDC); if (hCopyDC == NULL) goto CLEANUP_DIB; /* hBitmap で指定されたビットマップをデバイスコンテキストに選択 */ hOldDDBsBmp = (HBITMAP) SelectObject(hCopyDC, hBitmap); /* ビットマップをhMemDCに転送 */ bResultBitBlt = BitBlt(hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, hCopyDC, 0, 0, SRCCOPY); /* クリーンアップ */ CLEANUP_DIB: if (hOldDDBsBmp) SelectObject(hCopyDC, hOldDDBsBmp); if (hCopyDC) DeleteDC(hCopyDC); if (hOldDIBsBmp) SelectObject(hMemDC, hOldDIBsBmp); if (hMemDC) DeleteDC(hMemDC); /* BitBlt 関数が失敗していたらDIBを削除しNULLに設定 */ if (bResultBitBlt == 0) { DeleteObject(hDIBSection); hDIBSection = NULL; pBits = NULL; } } /* End of BLOCK : DIBの作成 */ /* DIBの作成に失敗していたらリージョンは作れない */ if (hDIBSection == NULL) return NULL; /* BLOCK : リージョンの作成 */ { HRGN hDotRgn; /* 一時的なドットのリージョン */ int x,y,xx; /* 透明色が指定されていなければ、左下隅のドットの色が透明色となる */ if (cTransparentColor == 0xffffffff) cTransparentColor = *pBits; /* 空のリージョンの作成 */ hRgn = CreateRectRgn(0, 0, 0, 0); /* 縦横にビットが透明色かを調べ、透明色で無い部分をリージョンに追加 */ for (y = 0; y < bm.bmHeight; y++) { /* 縦方向 */ for (x = 0; x < bm.bmWidth; x++) { /* 横方向 */ if (*pBits != cTransparentColor) { /* 透明色ではない? *//* Yes! */ xx = x; /* x を保存(透明色ではない点の始まりを保存) */ /* 連続した透明色ではない領域を求める */ for (x = x + 1; x < bm.bmWidth; x++) { /* ポインタをインクリメント */ pBits++; /* 透明色になったら break */ if (*pBits == cTransparentColor) break; } /* 一時的な透明色でない領域のリージョンを作成 */ hDotRgn = CreateRectRgn(xx, bm.bmHeight - y, x, bm.bmHeight - y - 1); /* hRgn と合成(ビットマップ全体のリージョンを作成) */ CombineRgn(hRgn, hRgn, hDotRgn, RGN_OR); /* 一時的なリージョンを削除 */ DeleteObject(hDotRgn); } /* ポインタをインクリメント */ pBits++; } } } /* End of BLOCK : リージョンの作成 */ /* HBITMAP(DIB)を削除 */ DeleteObject(hDIBSection); /* return the handle of the region */ return hRgn; }