【问题标题】:Windows splash screen using GDI+使用 GDI+ 的 Windows 启动画面
【发布时间】:2011-07-10 11:11:21
【问题描述】:

这样做的最终目的是在使用透明度的窗口中创建一个启动画面,但这不是我现在所坚持的。

为了创建一个透明窗口,我首先尝试使用 GDI+ 在屏幕外缓冲区上合成启动画面和文本。

目前,我只是尝试合成缓冲区并显示它以响应“WM_PAINT”消息。目前这行不通。我看到的只是一个黑色的窗口。

我想我对在 GDI+ 中设置渲染目标然后渲染它们有误解(我正在尝试使用直接 GDI blit 渲染屏幕)

无论如何,这是目前为止的代码:

//my window initialisation code
void MyWindow::create_hwnd(HINSTANCE instance, const SIZE &dim)
{                       
    DWORD ex_style = WS_EX_LAYERED ; //eventually I'll be making use of this layerd flag 
    m_hwnd = CreateWindowEx(
            ex_style,
            szFloatingWindowClass , 
            L"", 
            WS_POPUP  ,
            0, 
            0,       
            dim.cx, 
            dim.cy,
            null, 
            null, 
            instance, 
            null);      


      m_display_dc = GetDC(NULL);
      //This was sanity check test code - just loading a standard HBITMAP and displaying it in WM_PAINT. It worked fine
      //HANDLE handle= LoadImage(NULL , L"c:\\test_image2.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);       
      m_gdip_offscreen_bm = new Gdiplus::Bitmap(dim.cx, dim.cy);

      m_gdi_dc = Gdiplus::Graphics::FromImage(m_gdip_offscreen_bm);//new Gdiplus::Graphics(m_splash_dc );//window_dc ;m_splash_dc       

        //this draws the conents of my splash screen - this works if I create a GDI+ context for the window, rather than for an offscreen bitmap. 
        //For all I know, it might actually be working but when I try to display the contents on screen, it shows a black image
      draw_all();
        //this is just to show that drawing something simple on the offscreen bit map seems to have no effect
      Gdiplus::Pen pen(Gdiplus::Color(255, 0, 0, 255));
      m_gdi_dc->DrawLine(&pen, 0,0,100,100);

      DWORD last_error = GetLastError(); //returns '0' at this stage                
}

这是处理 WM_PAINT 消息的代码片段:

---8<-----------------------
//Paint message snippit

    case WM_PAINT:
    {
        BITMAP bm;
        PAINTSTRUCT ps;

        HDC hdc = BeginPaint(vg->m_hwnd, &ps); //get the HWNDs DC

        HDC hdcMem = vg->m_gdi_dc->GetHDC();   //get the HDC from our offscreen GDI+ object

        unsigned int width = vg->m_gdip_offscreen_bm->GetWidth();  //width and height seem fine at this point
        unsigned int height = vg->m_gdip_offscreen_bm->GetHeight();
        BitBlt(hdc, 0, 0, width, height, hdcMem, 0, 0, SRCCOPY);   //this blits a black rectangle

        DWORD last_error = GetLastError();              //this was '0'

        vg->m_gdi_dc->ReleaseHDC(hdcMem);  

        EndPaint(vg->m_hwnd, &ps);  //end paint

        return 1;
    }

    ---8<-----------------------

对于这篇长篇文章,我深表歉意。关于如何使用 GDI+(或 GDI)写入屏幕外缓冲区,然后将其显示在屏幕上,有人知道我不太了解吗?

感谢您的阅读。

【问题讨论】:

  • 我发现如果我为屏幕创建另一个 GDI+ 上下文并使用它绘制合成的上下文,它工作正常。但是,我尝试使用 GDI 方法的原因是我可以使用“UpdateLayeredWindow”来实现它。我关于如何使用 GDI- 对 GDI+ 图像进行 blit 的问题仍然存在。
  • 此代码不起作用,因为如果窗口以这种方式添加了 WS_EX_LAYERED 样式,则不会发送 WM_PAINT 消息。这会导致 windows 只对 UpdateLayeredWindow 更新的 windows 屏幕外位图的副本进行 blit。
  • 感谢克里斯的提示。我现在正在关闭分层标志,但我仍然无法绘制 alpha 混合图像。我目前正在尝试使用“AlphaBlend”,它似乎是用于渲染 Alpha 混合图像的替代 fpr BitBlt。到目前为止还没有骰子,它只是将 GetLastError 设置为 'ERROR_INVALID_PARAMETER' 但没有详细说明。我永远不会与 Win32 和 GDI 成为朋友;他们只是玩得不好! Alpha 混合应该是微不足道的。
  • 我是否正确假设'UpdateLayeredWindow'应该,如果它喜欢它给出的源HDC,将该HDC的内容与后台缓冲区混合?尽我所能,我就是做不到。

标签: winapi gdi+ gdi splash-screen


【解决方案1】:

已解决,尽管我确信这不是最佳的。 首先,正如 Chris Becke 所建议的,您不应响应 WM_PAINT 消息,而应仅使用“UpdateLayeredWindow”进行更新。我遇到的问题之一是给 UpdateLayeredWindow 一些错误的坐标,特别是我交换了源和目标(doh!)

这是从 GDI+ 表面调用 UpdateLayeredWindow 的代码。这不是最佳的,但它有效。

void TOPLEVEL_FLOATING_WINDOW::update_layered_window()
{
    BLENDFUNCTION blend_func = { 0 };     //build the blend function object... I guess microsoft doesn't/didn't like constructors
    blend_func.AlphaFormat = AC_SRC_OVER;
    blend_func.BlendFlags = 0;
    blend_func.SourceConstantAlpha = 255;
    blend_func.AlphaFormat = AC_SRC_ALPHA;

    POINT_2i  pt = m_screen_pos;
    VECTOR_2i dim = m_bounds.dimensions();

    POINT_2i  pt_src (0,0) ;            

    Gdiplus::Color bg(0,0,0,0);
    m_gdip_offscreen_bm->GetHBITMAP(bg, &m_offscreen_bm);   //get the Hbitmap from my GDI+ bitmap - I think this is allocating a whole new bitmap off the heap. Yuck, very inefficient!
    HDC  splash_dc = CreateCompatibleDC(m_display_dc);      //create a temporary HDC        
    HGDIOBJ oldobj = SelectObject(splash_dc , m_offscreen_bm);  //'select' the bitmap.      
    UpdateLayeredWindow(m_hwnd,m_display_dc, (POINT*)&pt, (SIZE*)&dim, splash_dc , (POINT*)&pt_src, 0 ,&blend_func,ULW_ALPHA); //this call works and updates our splash screens hidden buffer       
    SelectObject(splash_dc, oldobj);    //some tidy up code
    DeleteObject(m_offscreen_bm);       //free the bitmap. Memory fragmentation HO!
    DeleteDC(splash_dc); //Delete the DC        
}

这是我认为应该起作用但没有起作用的方法。我会分给任何能告诉我为什么不的人!我想这是因为 HDC 不是天生平等的,UpdateLayeredWindow 函数只能接受某个来源以某种方式创建的 HDC。如果这方面的规则更明显,那就太好了。

void TOPLEVEL_FLOATING_WINDOW::update_layered_window_in_an_ideal_world()
    {
        m_refresh_needed = false;
        BLENDFUNCTION blend_func = { 0 };
        blend_func.AlphaFormat = AC_SRC_OVER;
        blend_func.BlendFlags = 0;
        blend_func.SourceConstantAlpha = 255;
        blend_func.AlphaFormat = AC_SRC_ALPHA;

        POINT_2i  pt = m_screen_pos;
        VECTOR_2i dim = m_bounds.dimensions();

        POINT_2i  pt_src (0,0) ;            

        HDC gdi_HDC = m_screen_gdi_dc->GetHDC();    //I have a GDI+ 'Graphics' object whose back buffer is the image I want to composite on to the desktop      
        UpdateLayeredWindow(m_hwnd,m_display_dc, (POINT*)&pt, (SIZE*)&dim, gdi_HDC , (POINT*)&pt_src, 0 ,&blend_func,ULW_ALPHA);
        m_screen_gdi_dc->ReleaseHDC(gdi_HDC);   //be nice and release the gdi_HDC
    }

唯一的另一种选择是忽略 GDI+ 并使用我自己的光栅库渲染所有内容,这很高兴渲染到任何屏幕外缓冲区。但是,这对这个项目来说有点过头了。

【讨论】:

    【解决方案2】:

    这是一种将 GDI+ 位图放入分层窗口的方法。这允许多个位图叠加、定位和调整大小。

    void SetSplashImage()
    {
      // Default to upper left of screen
      POINT ptOrigin = { 0, 0 };
      SIZE sizeSplash = { 128, 128 };
    
      // Get the actual screen location
      GetPointOfOrigin(ptOrigin, sizeSplash);
    
      // Our in memory database of GDI+ Bitmaps
      data::image::BoxOfBits *box = 
        dynamic_cast<data::image::BoxOfBits *>(&Images.get_package("skin_layout_008"));
    
      // Create a display context as a canvas to draw the images
      HDC hdcScreen = GetDC(NULL);
      HDC hdcMem = CreateCompatibleDC(hdcScreen);
      HBITMAP bmMem = CreateCompatibleBitmap(hdcScreen, sizeSplash.cx, sizeSplash.cy);
    
      // Prep canvas for rendering graphic
      HBITMAP hbmpOld = (HBITMAP)SelectObject(hdcMem, bmMem);
      Gdiplus::Graphics graphics(hdcMem);
    
      // Base image is a pic of a folder
      Gdiplus::RectF canvasDest(0,0,128,128);
      graphics.DrawImage(box->grab("black_folder").pBitmap_, 
        canvasDest,  0,0,128,128,  Gdiplus::UnitPixel);
    
      // Overlay a pic of some tools in center of folder 
      Gdiplus::RectF canvasDest2(30,50,64,64); // resize half actual size
      graphics.DrawImage(box->grab("work_tools").pBitmap_,
        canvasDest2,  0,0,128,128,  Gdiplus::UnitPixel);
    
      // Overlay a pic of a cog in upper left corner of folder
      Gdiplus::RectF canvasDest1(16,16,32,32); // resize half actual size
      graphics.DrawImage(box->grab("cog_edit").pBitmap_,
        canvasDest1,  0,0,32,32,  Gdiplus::UnitPixel);
    
      // Prepare to alpha blend the canvas with the screen
      BLENDFUNCTION blend = { 0 };
      blend.BlendOp = AC_SRC_OVER;
      blend.SourceConstantAlpha = 255;
      blend.AlphaFormat = AC_SRC_ALPHA;
    
      // Composite the canvas with the screen into the layered window
      POINT ptZero = { 0 };
      UpdateLayeredWindow(hwnd_, hdcScreen, &ptOrigin, &sizeSplash,
          hdcMem, &ptZero, RGB(0, 0, 0), &blend, ULW_ALPHA);
    
      // Delete temporary objects used for canvas
      SelectObject(hdcMem, hbmpOld);
      DeleteObject(bmMem);
      DeleteDC(hdcMem);
      ReleaseDC(NULL, hdcScreen);
    
      // Update mouse hit-test coordinates
      GetWindowRect(hwnd_, &rcMousedown_);
    }
    

    由三个位图组成的分层窗口在屏幕上如下所示: - 猜我没有足够的声誉来发布图片:(

    这是链接 - http://i.stack.imgur.com/HmU7H.png

    【讨论】:

      猜你喜欢
      • 2011-01-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-26
      • 1970-01-01
      • 1970-01-01
      • 2011-07-12
      • 1970-01-01
      相关资源
      最近更新 更多