33074


WinAPIの初心者です。  
今作っているプログラムで、グラデーションがかかったウィンドウを作り、  
端に行くにつれて透明になっていく効果を付けたいと思っています。  
そこで、調べた情報をもとに、以下のようなプログラムを作成したのですが、  
UpdateLayeredWindowがエラー(0)を返してしまい、透過ができません。  
この関数の仕様など調べましたが、誤っている箇所がどうしてもわかりません。  
拙い質問とは思いますが、どうか助けていただきたいです。

追記：コメントありがとうございます。  
GetLastError()の返り値は87なのでERROR_INVALID_PARAMETERです。  
渡す値が間違っているのでしょうか？

[code]

    #define _WIN32_WINNT 0x0500
    
    #include <windows.h>
    
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    ATOM InitApp(HINSTANCE);
    BOOL InitInstance(HINSTANCE, int);
    
    LPCWSTR szClassName = L"layer01";    //ウィンドウクラス
    HINSTANCE hInst;
    
    HBITMAP hBmpGra;    //グラデーションを格納
    
    int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst,
        LPSTR lpsCmdLine, int nCmdShow) {
        MSG msg;
        BOOL bRet;
    
        hInst = hCurInst;
        if (!InitApp(hCurInst))
            return FALSE;
        if (!InitInstance(hCurInst, nCmdShow))
            return FALSE;
        while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) {
            if (bRet == -1) {
                break;
            } else {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }
        return (int)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 = (HICON)LoadImage(NULL,
            MAKEINTRESOURCE(IDI_APPLICATION),
            IMAGE_ICON,
            0,
            0,
            LR_DEFAULTSIZE | LR_SHARED);
        wc.hCursor = (HCURSOR)LoadImage(NULL,
            MAKEINTRESOURCE(IDC_ARROW),
            IMAGE_CURSOR,
            0,
            0,
            LR_DEFAULTSIZE | LR_SHARED);
        wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
        wc.lpszMenuName = NULL;    //メニュー名
        wc.lpszClassName = szClassName;
        wc.hIconSm = (HICON)LoadImage(NULL,
            MAKEINTRESOURCE(IDI_APPLICATION),
            IMAGE_ICON,
            0,
            0,
            LR_DEFAULTSIZE | LR_SHARED);
    
        return (RegisterClassEx(&wc));
    }
    
    //ウィンドウの生成
    BOOL InitInstance(HINSTANCE hInst, int nCmdShow) {
        HWND hWnd;
    
        hWnd = CreateWindowEx(WS_EX_LAYERED | WS_EX_TOPMOST | WS_EX_TOOLWINDOW,
            szClassName,
            L"Test Layer Window",   //Title
            WS_POPUP,
            0,  //X
            0,  //Y
            400,    //width
            300,    //height
            NULL,   //hWnd
            NULL,   //Menu
            hInst,
            NULL);
        if (!hWnd)
            return FALSE;
        ShowWindow(hWnd, nCmdShow);
        UpdateWindow(hWnd);
        return TRUE;
    }
    
    //グラデーションのBitmapの作成
    HBITMAP make_gradation(HWND hWnd, unsigned height, unsigned width, BYTE _r, BYTE _g, BYTE _b){
        BITMAPV5HEADER bi;
        void *lpBits;
        ZeroMemory(&bi, sizeof(BITMAPV5HEADER));
        bi.bV5Size = sizeof(BITMAPV5HEADER);
        bi.bV5Width = width;
        bi.bV5Height = height;
        bi.bV5Planes = 1;
        bi.bV5BitCount = 32;
        bi.bV5Compression = BI_BITFIELDS;
        bi.bV5RedMask = 0x00FF0000;
        bi.bV5GreenMask = 0x0000FF00;
        bi.bV5BlueMask = 0x000000FF;
        bi.bV5AlphaMask = 0xFF000000;
        HDC hdc = GetDC(hWnd);
        HBITMAP hbmp = CreateDIBSection(hdc, (BITMAPINFO *)&bi, DIB_RGB_COLORS,
            (void **)&lpBits, NULL, (DWORD)0);
        ReleaseDC(hWnd, hdc);
        DWORD *lpdwPixel = (DWORD *)lpBits;
        BYTE r, g, b, a;
        for (DWORD y = 0; y < height; ++y) {
            a = 255 * y / height;
            r = int(_r) * y * a / height / 255;
            g = int(_g) * y * a / height / 255;
            b = int(_b) * y * a / height / 255;
            for (DWORD x = 0; x < width; ++x) {
                lpdwPixel[(height - y - 1)*width + x] = (r << 16) | (g << 8) | b | (a << 24);
            }
        }
        return hbmp;
    };
    
    
    //ウィンドウプロシージャ
    LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) {
        int id;
        HDC hdc, hdc_mem, hsdc;
        HBRUSH hBrush;
        PAINTSTRUCT ps;
        LPCWSTR szBuf = L"Test Layer Window";
        BITMAP bmp_info;
        HBITMAP hBmp;
        int wx, wy;
        const COLORREF col = RGB(0, 255, 0);
        HGDIOBJ hOldObj;
        BLENDFUNCTION blend;
        POINT wndPos;
        SIZE  wndSize;
        RECT  rc;
        POINT po;
    
        switch (msg) {
        case WM_CREATE:
            SetLayeredWindowAttributes(hWnd, RGB(255, 0, 0), 0, LWA_COLORKEY);
            hBmpGra = make_gradation(hWnd, 300, 400, 0, 255, 60);
    
        case WM_PAINT:
            hsdc = GetDC(0);
            hdc = BeginPaint(hWnd, &ps);
            hdc_mem = CreateCompatibleDC(hdc);
            //hBmp = make_gradation(hWnd, 300, 400, 0, 255, 63);
            SelectObject(hdc_mem, hBmpGra);
            BitBlt(hdc, 0, 0, 400, 300, hdc_mem, 0, 0, SRCCOPY | CAPTUREBLT);
    
            po.x = po.y = 0;
            blend.BlendOp = AC_SRC_OVER;
            blend.BlendFlags = 0;
            blend.SourceConstantAlpha = 255;
            blend.AlphaFormat = AC_SRC_ALPHA;
            UpdateLayeredWindow(hWnd, hsdc, nullptr, nullptr, hdc_mem, &po, 0, &blend, ULW_ALPHA);
    
        //  DeleteObject(hBmp);
            DeleteDC(hdc_mem);
            SetBkMode(hdc, TRANSPARENT);
            EndPaint(hWnd, &ps);
            ReleaseDC(0, hsdc);
            break;
        case WM_CLOSE:
            id = MessageBox(hWnd,
                L"終了してもよろしいですか",
                L"確認",
                MB_YESNO | MB_ICONQUESTION);
            if (id == IDYES)
                DestroyWindow(hWnd);
            break;
        case WM_RBUTTONDOWN:
            SendMessage(hWnd, WM_CLOSE, 0, 0);
            break;
        case WM_LBUTTONDOWN:
            PostMessage(hWnd, WM_NCLBUTTONDOWN, (WPARAM)HTCAPTION, lp);
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return (DefWindowProc(hWnd, msg, wp, lp));
        }
        return 0;
    }
    
[/code]


CC BY-SA 3.0
2017-03-03T03:28:21.090
33056
2017-03-03T12:42:22.553
2017-03-03T10:01:30.377
19110
20910
question
c++ c winapi
WinAPIのUpdateLayeredWindowの使い方


まず第一に、UpdateLayeredWindow を使うなら SetLayeredWindowAttributes
を呼び出してはいけません。MSDNライブラリでは[「レイヤードウィンドウ」](https://msdn.microsoft.com/ja-
jp/library/ms997507.aspx#layerwin_topic2a)の項目に次の記述があります。

> また、 SetLayeredWindowAttributes がレイヤード ウィンドウに対して呼び出された後、レイヤリング スタイル
> ビットがクリアされて、再び設定されるまでは、後続の UpdateLayeredWindow コールは失敗するということを忘れないでください。

これに加えて色々試した結果、第四引数 `psize`
を指定することで動作しました。[MSDNライブラリ](https://msdn.microsoft.com/ja-
jp/library/cc364847.aspx)では「ウィンドウのサイズを変更しないときは、NULL
を指定します。」とあるので、省略してもよさそうなのですが…。

上記二か所を修正したものを抜粋して次に示します。

[code]

    case WM_CREATE:
        // SetLayeredWindowAttributes(hWnd, RGB(255, 0, 0), 0, LWA_COLORKEY);
        hBmpGra = make_gradation(hWnd, 300, 400, 0, 255, 60);
    
    case WM_PAINT:
        hsdc = GetDC(0);
        hdc = BeginPaint(hWnd, &ps);
        hdc_mem = CreateCompatibleDC(hdc);
        //hBmp = make_gradation(hWnd, 300, 400, 0, 255, 63);
        SelectObject(hdc_mem, hBmpGra);
        BitBlt(hdc, 0, 0, 400, 300, hdc_mem, 0, 0, SRCCOPY | CAPTUREBLT);
    
        wndSize.cx = 400; wndSize.cy = 300;
        po.x = po.y = 0;
        blend.BlendOp = AC_SRC_OVER;
        blend.BlendFlags = 0;
        blend.SourceConstantAlpha = 255;
        blend.AlphaFormat = AC_SRC_ALPHA;
        UpdateLayeredWindow(hWnd, hsdc, nullptr, &wndSize, hdc_mem, &po, 0, &blend, ULW_ALPHA);
    
    //  DeleteObject(hBmp);
        DeleteDC(hdc_mem);
        SetBkMode(hdc, TRANSPARENT);
        EndPaint(hWnd, &ps);
        ReleaseDC(0, hsdc);
        break;
    
[/code]

ところで、UpdateLayeredWindow を使うと WM_PAINT メッセージは飛んでこなくなります。描画処理を WM_PAINT
に書いている現在のコードでも最初一回は呼ばれるので一応動作しますが、今後の再描画も WM_PAINT
とは独立して行うわけですから、別の場所に書いた方が分かりやすいかと思います。例えば WM_CREATE とか。

このあたりのことも先ほどの[「レイヤードウィンドウ」](https://msdn.microsoft.com/ja-
jp/library/ms997507.aspx#layerwin_topic2a)の項目に書かれています。


CC BY-SA 3.0
2017-03-03T12:42:22.553
33074
2017-03-03T12:42:22.553
8000
33056
answer