How to create borderless CFrameWnd for SDI application

52 Views Asked by At

I have an SDI application with CFrameWnd-inherited frame and a view. I want my application to look like MSVS installer window:

enter image description here

I.e., it's borderless, has straight angels, has shadow, has menu buttons - minimize, close, etc.

I found a post for making such a look for CDialog-derived class in the post Borderless Window with Drop Shadow. However, I'm unable to adapt the code. My attempt is to initialize Gdiplus in application class:

BOOL Application::InitInstance()
{
    INITCOMMONCONTROLSEX InitCtrls;
    InitCtrls.dwSize = sizeof(InitCtrls);
    InitCtrls.dwICC = ICC_WIN95_CLASSES;
    InitCommonControlsEx(&InitCtrls);
    CWinApp::InitInstance();

    Gdiplus::GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR                    gdipToken = 0;
    Gdiplus::GdiplusStartup(&gdipToken, &gdiplusStartupInput, nullptr);
    // ...

And the code for the frame:

MainFrame.h

#pragma once

class MainFrame : public CFrameWnd
{
public:
    BOOL PreCreateWindow(CREATESTRUCT& cs) override
    {
        if (!CFrameWnd::PreCreateWindow(cs))
            return FALSE;

        cs.style     = WS_POPUP | WS_CAPTION | DS_CENTER;
        cs.dwExStyle = 0;

        return TRUE;
    }

    void DoDataExchange(CDataExchange* pDX) override
    {
        CFrameWnd::DoDataExchange(pDX);

        if (!m_initialized) {
            MARGINS m { 0, 0, 0, 1 };
            DwmExtendFrameIntoClientArea(m_hWnd, &m);

            SetWindowPos(
                nullptr, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
            SetWindowLong(m_hWnd, DWLP_MSGRESULT, 0);
            m_initialized = true;
        }
    }

protected:
    DECLARE_DYNCREATE(MainFrame)
    DECLARE_MESSAGE_MAP()

    void OnPaint()
    {
        PAINTSTRUCT ps { 0 };
        HDC         hdc = ::BeginPaint(m_hWnd, &ps);
        // Draw with GDI+ to make sure the alpha channel is opaque.
        Gdiplus::Graphics   gfx { hdc };
        Gdiplus::SolidBrush brush { Gdiplus::Color { 255, 255, 255 } };
        gfx.FillRectangle(&brush,
                          static_cast<INT>(ps.rcPaint.left),
                          static_cast<INT>(ps.rcPaint.top),
                          static_cast<INT>(ps.rcPaint.right - ps.rcPaint.left),
                          static_cast<INT>(ps.rcPaint.bottom - ps.rcPaint.top));

        ::EndPaint(m_hWnd, &ps);
    }

private:
    bool m_initialized = false;
};

MainFrame.cpp:

#include "pch.h"
#include "framework.h"
#include "Application.h"
#include "MainFrame.h"

IMPLEMENT_DYNCREATE(MainFrame, CFrameWnd)

BEGIN_MESSAGE_MAP(MainFrame, CFrameWnd)
ON_WM_PAINT()
END_MESSAGE_MAP()

I do initialization in the DoDataExcange because I didn't found the better place yet. The application window either doesn't appear, or looks like ordinar window, it depends on whether the WS_POPUP style is included or not. (Also I didn't change some WinAPI calls with the MFC analogs just to be sure I'm not missing somewhat).

How to create a window that looks like the one on screenshot?

Update: When I set the following styles: cs.style = DS_CENTER; , it doesn't change a lot:

enter image description here

Also I would like to remove inner view's borders, but I suppose it should be asked in separate question.

0

There are 0 best solutions below