2016-10-13 1 views
2

캡션 제목 표시 줄에 아이콘을 그리기 위해 DWM API를 사용하여 DwmExtendFrameIntoClientArea를 호출하여 DWM API를 사용하여 사용자 정의 클라이언트 영역을 만들었습니다.Windows에서 DWM API를 사용하는 Aero caption 제목 표시 줄 문제

내 코드 : 윈도우 7에서

CMainFrame::CMainFrame() 
{ 
    Gdiplus::GdiplusStartupInput gdiplusStartupInput; 
    ULONG_PTR   gdiplusToken; 
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); 

    BOOL fDwmEnabled = FALSE; 
    if (SUCCEEDED(DwmIsCompositionEnabled(&fDwmEnabled))) 
     TRACE0("DWM is enabled\n"); 

    TCHAR szLogoPath[MAX_PATH]; 
    GetModuleFileName (GetModuleHandle(NULL), szLogoPath, _countof(szLogoPath) ); 
    PathRemoveFileSpec (szLogoPath); 
    PathAppend (szLogoPath, _T("lena.bmp")); 
    m_pLogoImage = m_pLogoImage->FromFile (CT2CW(szLogoPath)); 
    if(NULL == m_pLogoImage) 
     TRACE0("load image fail\n"); 
} 

void CMainFrame::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp) 
{ 
    int xFrame = 2; 
    int yFrame = 2; 
    int nTHight = 30; 
    NCCALCSIZE_PARAMS * p; 
    RECT * rc; 
    RECT aRect; 
    RECT bRect; 
    RECT acRect; 
    p = (NCCALCSIZE_PARAMS *)lpncsp; 

    CopyRect(&bRect,&p->rgrc[1]); 
    CopyRect(&aRect,&p->rgrc[0]); 

    acRect.left = aRect.left + xFrame; 
    acRect.top = aRect.top - nTHight; 
    acRect.right = aRect.right - xFrame; 
    acRect.bottom = aRect.bottom - yFrame; 
    CopyRect(&p->rgrc[0],&acRect); 
    CopyRect(&p->rgrc[1],&aRect); 
    CopyRect(&p->rgrc[2],&bRect); 
    CFrameWnd::OnNcCalcSize(TRUE, lpncsp); 
} 

LRESULT CMainFrame::OnNcHitTest(CPoint p) 
{ 
    BOOL dwm_enabled = FALSE; 
    if (SUCCEEDED(DwmIsCompositionEnabled(&dwm_enabled))) 
    { 
     LRESULT result = 0; 
     if (!DwmDefWindowProc(m_hWnd, WM_NCHITTEST, 0, MAKELPARAM(p.x, p.y), &result)) 
      result = HitTestNCA(m_hWnd, p); 

     if (result == HTNOWHERE && GetForegroundWindow() != this) 
     { 
      return HTCAPTION; 
     } 

     return result; 
    } 

    return CWnd::OnNcHitTest(p); 
} 

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) 
{ 
    if(cs.hMenu!=NULL) 
    { 
    ::DestroyMenu(cs.hMenu);  
     cs.hMenu = NULL ;  
    } 
    if(!CFrameWnd::PreCreateWindow(cs)) 
     return FALSE; 
    // TODO: Modify the Window class or styles here by modifying 
    // the CREATESTRUCT cs 
    cs.style = WS_CAPTION | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_OVERLAPPED| WS_SYSMENU | WS_THICKFRAME; 
    cs.dwExStyle &= ~WS_EX_CLIENTEDGE; 
    cs.lpszClass = AfxRegisterWndClass(0); 

    return TRUE; 
} 

void CMainFrame::OnActivate(UINT nState,CWnd* pWndOther,BOOL bMinimized) 
{ 
    CFrameWnd::OnActivate(nState,pWndOther,bMinimized); 
    BOOL fDwmEnabled = FALSE; 
    if (SUCCEEDED(DwmIsCompositionEnabled(&fDwmEnabled))) 
    { 
     if(nState == WA_ACTIVE) 
     { 
      MARGINS margins = {-1}; 
      /*margins.cyTopHeight = 30; 
      margins.cxLeftWidth = 0; 
      margins.cxRightWidth = 0; 
      margins.cyBottomHeight = 0;*/ 
      HRESULT hr = DwmExtendFrameIntoClientArea(m_hWnd, &margins); 
      if (!SUCCEEDED(hr)) 
       TRACE0("Failed in DwmExtendFrameIntoClientArea\n"); 
     } 
    } 
} 

void CMainFrame::OnNcPaint() 
{ 
    CFrameWnd::OnPaint(); 
    CDC* dc = GetWindowDC(); 
    RECT rcClient; 
    GetWindowRect(&rcClient); 
    dc->FillSolidRect(0,0,RECTWIDTH(rcClient),RECTHEIGHT(rcClient),RGB(255,0,0)); 

    CPaintDC gdc(this); // device context for painting 
    Graphics gr(gdc.m_hDC); 
    gr.DrawImage (m_pLogoImage, 0, 0); 
    ReleaseDC(dc); 

} 

결과는 괜찮습니다. enter image description here

그러나, 내 방 창문을 내가 알 수없는 자막이 cs.style에서 WS_THICKFRAME에 의해 발생 발견 윈도우 (10) enter image description here

enter image description here

에서 또 다른 알 수없는 캡션 제목 표시 줄이 나타납니다. WS_THICKFRAME을 제거하면 알 수없는 양이온 막대가 사라지지만 내 창의 테두리 크기를 조정할 수 없습니다. 또한 내 프로그램은 사용자 정의 캡션 표시 줄에서 최소, 최대 및 닫기 버튼 메시지를 더 이상 캡처 할 수 없습니다. 부작용없이 알 수없는 제목 표시 줄을 제거하고 싶습니다. 누구든지 나에게 좋은 해결책이나 제안을 해 줄 수 있습니까?

안부,

+1

* "누구든지 나에게 좋은 해결책이 나 제안을 제공 할 수 있습니까?"* - 당신이 필요로하는 무엇을 알려하지 않는, 즉 아마하지 않을 일어날 것입니다. 당신은 당신이 정말로 원하지 않는 것에 대해 많이 이야기했지만, 당신이 정말로 필요로하는 것을 간결하게 묘사하지 않았습니다. – IInspectable

+0

부작용없이 알 수없는 제목 표시 줄을 제거하고 싶습니다. 감사합니다 – user2365346

답변

1

DwmExtendFrameIntoClientArea를 사용하면, 프레임은 클라이언트 영역으로 연장되는 것을 의미한다. 비 클라이언트 영역에 더 이상 없습니다. 그래서 OnNcPaint를 오버라이드 (override) 할 필요가 없습니다, 당신은 경계선의 두께를 추적 할 수 OnPaint

void CMainFrame::OnPaint() 
{ 
    CPaintDC dc(this); 

    //paint titlebar area (this used to be the non-client area) 
    CRect rc; 
    GetClientRect(&rc); 
    rc.bottom = titlebar_height; 

    CDC memdc; 
    memdc.CreateCompatibleDC(&dc); 
    BITMAPINFOHEADER bmpInfoHeader = { 
     sizeof(BITMAPINFOHEADER), rc.Width(), -rc.Height(), 1, 32 }; 
    HBITMAP hbitmap = CreateDIBSection(
     dc, (BITMAPINFO*)(&bmpInfoHeader), DIB_RGB_COLORS, NULL, NULL, 0); 
    auto oldbitmap = memdc.SelectObject(hbitmap); 

    dc.BitBlt(0, 0, rc.Width(), rc.Height(), &memdc, 0, 0, SRCCOPY); 
    memdc.SelectObject(oldbitmap); 
    DeleteObject(hbitmap); 

    //begin normal paint 
    //The new client area begins below titlebar_height which we define earlier 
    GetClientRect(&rc); 
    rc.top = titlebar_height; 
    dc.FillSolidRect(&rc, RGB(0, 0, 255)); 

    Gdiplus::Image *image = Gdiplus::Image::FromFile(L"file.jpg"); 
    Gdiplus::Graphics gr(dc); 
    gr.DrawImage(image, 0, 0); 
    delete image; 
} 

를 사용하여 멤버 변수 CRect m_border에 그림의 모든 작업을 수행 할 수 있습니다. AdjustWindowRectEx을 사용하여 테두리 두께를 찾을 수 있습니다.

void CMainFrame::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized) 
{ 
    CFrameWnd::OnActivate(nState, pWndOther, bMinimized); 

    titlebar_height = 100; 
    //find border thickness 
    if (GetWindowLongPtr(m_hWnd, GWL_STYLE) & WS_THICKFRAME) 
    { 
     m_border = { 0,0,0,0 }; 
     AdjustWindowRectEx(&m_border, GetWindowLongPtr(m_hWnd, 
       GWL_STYLE) & ~WS_CAPTION, FALSE, NULL); 
     m_border.left = abs(m_border.left); 
     m_border.top = abs(m_border.top); 
    } 
    else if (GetWindowLongPtr(m_hWnd, GWL_STYLE) & WS_BORDER) 
    { 
     m_border = { 1,1,1,1 }; 
    } 
    else 
    { 
     m_border = { 0,0,0,0 }; 
    } 

    //Extend frame in to client area 
    MARGINS margins = { 0 }; 
    margins.cyTopHeight = titlebar_height; //<<=== *** edited 
    DwmExtendFrameIntoClientArea(m_hWnd, &margins); 
    SetWindowPos(NULL, 0, 0, 0, 0, 
      SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED); 
} 

m_border{7,7,7,7}위한 것;

Windows에서 왼쪽, 오른쪽, 아래쪽 테두리에 페인팅을 수행 할 수 있습니다. 상단 테두리가 하나가

void CMainFrame::OnNcCalcSize(BOOL validate, NCCALCSIZE_PARAMS FAR* lpncsp) 
{ 
    if (validate) 
    { 
     lpncsp->rgrc[0].left += m_border.left; 
     lpncsp->rgrc[0].right -= m_border.right; 
     lpncsp->rgrc[0].bottom -= m_border.bottom; 
    } 
    else 
    { 
     CFrameWnd::OnNcCalcSize(validate, lpncsp); 
    } 
} 

도 볼 변경 How to glow the minimum. maximum and close button?

+0

나는 그것을 시도했지만 내 프로그램은 최소, 최대 및 닫기 버튼 메시지를 캡처 할 수 없습니다. – user2365346

+0

이전에 비슷한 질문을 던졌을 것입니다. 전체 예제를 추가했습니다. 링크를 참조하십시오. 유일한 다른 점은 제목 표시 줄의 높이가 고정되어있는 예를 추가 한 것입니다 (예 : 60 픽셀). 그러나 당신의 버전에서는 전체 윈도우가 titlebar처럼 행동하기를 원합니다.이 경우'titlebar_height'를 최대 화면 높이로 변경하십시오.'SystemParametersInfo (SPI_GETWORKAREA ....)'OnNcPaint에 대한 오버라이드를 추가하지 마십시오 –

+0

있습니다. 그것을 해결했다. 팁 주셔서 감사합니다. – user2365346