Windows API: UpdateLayeredWindow return values

2.6k views Asked by At

I have a layered window in my program and it seems(visually) to work fine, but the return code from UpdateLayeredWindow is supposed to be a non-zero value on success. In my case, it is 0, and GetLastError returns 87, that is for an incorrect parameter. Can someone please tell me if there is anything wrong with my setup? Here is the complete function, window styles are WS_EX_LAYERED|WS_EX_TOPMOST and WS_POPUP.

bool SplashScreen(HWND hwnd, HINSTANCE m_hinstance)
{
    HBITMAP hBitmap = (HBITMAP)LoadImage(m_hinstance, "splash.bmp", IMAGE_BITMAP, 640, 640, LR_LOADFROMFILE);
    PAINTSTRUCT     ps;
    HDC             hdc;
    BITMAP          bitmap;
    HDC             hdcMem;
    HGDIOBJ         oldBitmap;
    int result=0;

    if(!SetLayeredWindowAttributes(hwnd, 0, (255 * 100) / 100, LWA_ALPHA))
    {
        char msg[255];
        sprintf(msg,"Error SetLayeredWindowAttributes: %d",GetLastError());
        MessageBox(hwnd,msg,"System",MB_OK);
        return false;
    }

    hdc = BeginPaint(hwnd, &ps);
    if(!hdc)
    {
        char msg[255];
        sprintf(msg,"Error BeginPaint: %d",GetLastError());
        MessageBox(hwnd,msg,"System",MB_OK);
        return false;
    }

    hdcMem = CreateCompatibleDC(hdc);
    if(!hdcMem)
    {
        char msg[255];
        sprintf(msg,"Error CreateCompatibleDC: %d",GetLastError());
        MessageBox(hwnd,msg,"System",MB_OK);
        return false;
    }

    oldBitmap = SelectObject(hdcMem, hBitmap);

    GetObject(hBitmap, sizeof(bitmap), &bitmap);
    result=BitBlt(hdc, 0, 0, 640, 640, hdcMem, 0, 0, SRCCOPY);
    if(result==0)
    {
        char msg[255];
        sprintf(msg,"Error BitBlt: %d",GetLastError());
        MessageBox(hwnd,msg,"System",MB_OK);
        return false;
    }

    BLENDFUNCTION blend = { 0 };
    blend.BlendOp = AC_SRC_OVER;
    blend.SourceConstantAlpha = 255;
    blend.AlphaFormat = AC_SRC_ALPHA;

    result=UpdateLayeredWindow(hwnd,GetDC(NULL),NULL,NULL,hdcMem,NULL, RGB(0,0,0),&blend, ULW_ALPHA);// Returns non-zero on success(!), in reality works when 0 is returned.
    if(result==0)
    {
        char msg[255];
        sprintf(msg,"Error UpdateLayeredWindow: %d",GetLastError());// Error UpdateLayeredWindow: 87
        MessageBox(hwnd,msg,"System",MB_OK);
        return false;
    }

    result=SetLayeredWindowAttributes(hwnd, RGB(255,255,255), 0, ULW_COLORKEY);
    if(result==0)
    {
        char msg[255];
        sprintf(msg,"Error SetLayeredWindowAttributes: %d",GetLastError());
        MessageBox(hwnd,msg,"System",MB_OK);
        return false;
    }

    result=EndPaint(hwnd, &ps);
    if(result==0)
    {
        char msg[255];
        sprintf(msg,"Error EndPaint: %d",GetLastError());
        MessageBox(hwnd,msg,"System",MB_OK);
        return false;
    }

    SelectObject(hdcMem, oldBitmap);
    DeleteDC(hdc);
    DeleteObject(hdcMem);
    return true;
}
1

There are 1 answers

0
Remy Lebeau On BEST ANSWER

You are calling SetLayeredWindowAttributes() and UpdateLayeredWindow() on the same HWND. That will not work, and the documentation is very clear on that:

http://msdn.microsoft.com/en-us/library/windows/desktop/ms633540(v=vs.85).aspx

Note that once SetLayeredWindowAttributes has been called for a layered window, subsequent UpdateLayeredWindow calls will fail until the layering style bit is cleared and set again.

Do not use SetLayeredWindowAttributes() and UpdateLayeredWindow() together. They are very different methodologies. Either use SetLayeredWindowAttributes() with traditional WM_PAINT drawing, or use UpdateLayeredWindow() with an in-memory bitmap. Do not use both. Based on what you have shown, you should be using UpdateLayeredWindow() by itself. It will set a bitmap as the window contents and set the window's transparency/alpha at the same time.

And do not use Begin/EndPaint() outside of a WM_PAINT handler.