e-fs.info

PeekMessage


命令されてからでは遅い

Win01〜Win04で作ってたのはイベントドリブンという方式で、(イベント駆動型とも言う)
システムから命令されてから実行していた。
遅いので、イベントが発生していない時に処理をしてしまおう。
というのが、PeekMessage関数である。

実行サンプル

プログラム

#include <windows.h>
#include <windowsx.h>

HWND g_hwnd;
const int    WINX    = 320;
const int    WINY    = 240;
const char    TITLE[] = "Win05";

LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
void Mainloop(HDC hdc);

HDC Back_Init_Surface(HWND hwnd)
{
    HDC hdc,BackDC;
    HBITMAP hBackBMP;

    hdc=GetDC(hwnd);
    BackDC=CreateCompatibleDC(hdc);
    hBackBMP=CreateCompatibleBitmap(hdc,WINX,WINY);
    SelectObject(BackDC,hBackBMP);
    PatBlt(BackDC,0,0,WINX,WINY,WHITENESS);
    DeleteObject(hBackBMP);
    ReleaseDC(hwnd,hdc);

    return BackDC;
}

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE,LPSTR lpCmdLine,int nCmdShow)
{
    MSG msg;
    WNDCLASSEX wc;
    HWND hwnd;

    ZeroMemory(&wc,sizeof(WNDCLASSEX));

    wc.cbSize        = sizeof(WNDCLASSEX);
    wc.style        = CS_HREDRAW|CS_VREDRAW;
    wc.lpfnWndProc    = WndProc;
    wc.lpszMenuName = NULL;
    wc.hInstance    = hInstance;
    wc.hIcon        = (HICON)LoadImage(hInstance,MAKEINTRESOURCE(IDI_APPLICATION),IMAGE_ICON,0,0,LR_SHARED);
    wc.hIconSm        = (HICON)LoadImage(hInstance,MAKEINTRESOURCE(IDI_APPLICATION),IMAGE_ICON,0,0,LR_SHARED);
    wc.hCursor        = (HCURSOR)LoadImage(NULL,MAKEINTRESOURCE(IDC_ARROW),IMAGE_CURSOR,0,0,LR_DEFAULTCOLOR | LR_SHARED);
    wc.hbrBackground= (HBRUSH)GetStockObject(BLACK_BRUSH);
    wc.lpszClassName= TITLE;

    if(!RegisterClassEx(&wc))return FALSE;

    // ウィンドウのスタイル
    // WS_OVERLAPPEDWINDOW = 大抵のやつを有効にしろ
    // & ~WS_THICKFRAME = WS_OVERLAPPEDWINDOWからサイズ変更を無効に
    // & ~WS_MAXIMIZEBOX = WS_OVERLAPPEDWINDOWから最大化を無効に
    const DWORD dwStyle = WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX;

    // ウィンドウを作る!
    hwnd = CreateWindowEx(0,TITLE,TITLE,dwStyle,
        GetSystemMetrics(SM_CXSCREEN)/2 - WINX/2,    // 真ん中に表示
        GetSystemMetrics(SM_CYSCREEN)/2 - WINY/2,    // 真ん中に表示
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        NULL,NULL,hInstance,NULL);

    if(!hwnd)return FALSE;

    g_hwnd = hwnd;

    //----- ウィンドウサイズをWINX WINY の大きさに。------
    RECT window_rect;
    SetRect(&window_rect,0,0,WINX,WINY);
    AdjustWindowRectEx(&window_rect,GetWindowLong(hwnd,GWL_STYLE),GetMenu(hwnd) != NULL,GetWindowLong(hwnd,GWL_EXSTYLE));
    const int nWidth  = window_rect.right  - window_rect.left;
    const int nHeight = window_rect.bottom - window_rect.top;
    SetWindowPos(hwnd,NULL,0,0,nWidth,nHeight,SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
    //----- WINX WINY の大きさに。E -----

    // ちらつきが起こるのでダブルバッファ
    HDC BackDC = Back_Init_Surface(hwnd);
    ShowWindow(hwnd,nCmdShow);
    UpdateWindow(hwnd);
    
    HDC hdc=GetDC(hwnd);

    int frame = 0;    // 開始時からの合計フレーム数
    bool active;    // ウィンドウはアクティブ?
    
    for(;;){
        active = (hwnd == GetActiveWindow()) ? (IsIconic(hwnd)? true : false) : true;
        // PeekMessage
        if(active || PeekMessage(&msg,NULL,0,0,PM_NOREMOVE)){
            if(!GetMessage(&msg,(HWND)NULL,0,0))break;
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }else{
            // ウィンドウを白で塗りつぶし
            PatBlt(BackDC,0,0,WINX,WINY,WHITENESS);
            if(!active){
                Mainloop(BackDC);
            }
            // メインの画面に描画
            BitBlt(hdc,0,0,WINX,WINY,BackDC,0,0,SRCCOPY);
        }
        Sleep(1);//    これを入れないと単なる無限ループ
    }
    ReleaseDC(hwnd,hdc);

    return (int)msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam){
    switch(msg){
        // Escを押された時だけDestroy処理が発生
        case WM_KEYDOWN:
            if(wParam != VK_ESCAPE){return 0;}
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
        default:
            break;
    }
    return (DefWindowProc(hwnd,msg,wParam,lParam));
}

static int x=0,y=0;
static const int speed = 1;

// メインループ
void Mainloop(HDC hdc){
    if(GetKeyState(VK_UP   ) & 0x80)y -= speed;
    if(GetKeyState(VK_DOWN ) & 0x80)y += speed;
    if(GetKeyState(VK_RIGHT) & 0x80)x += speed;
    if(GetKeyState(VK_LEFT ) & 0x80)x -= speed;

    TextOut(hdc,x,y,"Win05",5);
}