Solved

Need "always-maximized" app window that does not cover taskbar or move or change size ever but can be minimized.

Posted on 2000-04-07
9
484 Views
Last Modified: 2013-11-20
I am having trouble forcing my application window to be "always maximized".

Before firing off a reference to a typical article on this, please consider the exact problems I am having. Many such articles have let me down in one way or another.

My goal is simple. I just want the app window to appear in the "standard" maximized position (NOT COVERING UP THE TASKBAR!!!) and stay that way forever except when someone minimizes the window, which should be possible. Resizing and moving, however, should be impossible.

So far I have read many detailed explanations for doing this and they all let me down in one way or another.

FYI, Here is my list of ways these well-written articles still managed to fail my simple requirements...
1) Window is always maximized, but it covers the taskbar.
2) Window is always maximized and does not cover taskbar until you move the taskbar to an odd location (e.g. top of the screen).
3) Window is always maximized, but it can be moved around.
4) Window is always maximized, but double-clicking the caption area spntaneously reduces its size and there is no way back to the maximume size.
5) Window appears non-maximized for a brief moment during application startup.

I have tried overloading
void CMainFrame::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
BOOL CMainFrame::ActivateWindow()
but I can never get it all working together.

The hardest part seems to be retaining the "standard" size for maximized state while removing/disabling the maximize-button, which should be removed to emphasize that resizing is not possible. It seems like this necesatates an overload for OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI). However, the examples for doing this never seem to account for the possibility that the maximize-button is disabled, which (don't ask me why?) alters the default behavior for sizing the maximized window.

Thanks for your interest in this,
-Chris Ternoey
0
Comment
Question by:cternoey
  • 4
  • 2
  • 2
  • +1
9 Comments
 
LVL 23

Expert Comment

by:chensu
ID: 2695140
Override OnWindowPosChanging. While this message is being processed, modifying any of the values in WINDOWPOS affects the window's new size, position, or place in the Z order. An application can prevent changes to the window by setting or clearing the appropriate bits in the flags member of WINDOWPOS. But you should allow its changes at the first time, which ocurrs when the application starts up.
0
 

Author Comment

by:cternoey
ID: 2695728
Adjusted points from 120 to 150
0
 

Author Comment

by:cternoey
ID: 2695729
Chensu,
Many thanks for the great lead you gave here. After incorporating your suggestion and many other odds and ends into my CMainFrame class, I solved many of my problems. And the result is pretty cool.

But there is one defect. )-:

When the application is minimized, it creates a very odd artifact. The minimized window does not dissappear as usual. Instead, it collapses into a very small rectangle in the top left corner of the screen. This collapsed window looks like a minimized document window inside an application like Microsoft Word or Visual Studio. I am not sure I have ever seen this behavior in an app window, and it is kind of trippy.

I assume this is related to the fact that the position of the window is locked (the SWP_NOMOVE flag gets added to the window style settings). But I don't know how to address the problem.

I have tried overloading OnSize(), checking for the SIZE_MINIMIZED message and switching the _isLocked variable back to false. But this does not work. I am very surprised by this odd behavior and stumped for ways to address it.

Any suggestions will be much appreciated.

Regards,
-Chris Ternoey


My code base is an SDI generated by AppWizard.

Code modifications are include here for reference...

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
      /* Usual stuff omitted for clarity! */

      CRect rectDesktop;
      if (!::SystemParametersInfo(SPI_GETWORKAREA, 0, &rectDesktop, 0))
             ::GetWindowRect(::GetDesktopWindow(), &rectDesktop);
      _isLocked = false;
      SetWindowPos(&wndTop, rectDesktop.left,      rectDesktop.top,
            rectDesktop.right - rectDesktop.left,
            rectDesktop.bottom - rectDesktop.top,
            SWP_SHOWWINDOW);      
      return 0;
}

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
      cs.style = WS_OVERLAPPED | WS_CAPTION  | FWS_ADDTOTITLE
            | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZE;

      return CFrameWnd::PreCreateWindow(cs);
}

void CMainFrame::OnWindowPosChanging( WINDOWPOS* lpwndpos )
{
      if (_isLocked) {
            lpwndpos->flags = lpwndpos->flags | SWP_NOMOVE;
      } else {
            _isLocked = true;
      }
      CFrameWnd::OnWindowPosChanging(lpwndpos);
}

void CMainFrame::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)
{
      CFrameWnd::OnGetMinMaxInfo(lpMMI);
      CRect r;
      SystemParametersInfo(SPI_GETWORKAREA, 0, &r, SPIF_UPDATEINIFILE);
      lpMMI->ptMaxSize.x = r.Width();
      lpMMI->ptMaxSize.y = r.Height();
      lpMMI->ptMaxPosition.x = r.left;
      lpMMI->ptMaxPosition.y = r.top;
}

void CMainFrame::OnSettingChange(UINT uFlags, LPCTSTR lpszSection)
{
      CFrameWnd::OnSettingChange(uFlags, lpszSection);      
      // TODO: Add your message handler code here
      CRect rectDesktop;
      if (!::SystemParametersInfo(SPI_GETWORKAREA, 0, &rectDesktop, 0))
             ::GetWindowRect(::GetDesktopWindow(), &rectDesktop);
      _isLocked = false;
      SetWindowPos(&wndTop, rectDesktop.left,      rectDesktop.top,
            rectDesktop.right - rectDesktop.left,
            rectDesktop.bottom - rectDesktop.top,
            SWP_SHOWWINDOW);
}

0
 
LVL 9

Expert Comment

by:ShaunWilde
ID: 2695780
how about telling it to hide ?
0
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 

Author Comment

by:cternoey
ID: 2696313
I can not find any way to hide the app-window that does not also remove the app from the taskbar. )-:
0
 
LVL 9

Expert Comment

by:ShaunWilde
ID: 2696322
how about moving the app so it is off-screen then? or you may want to use ITaskbarList interface to put your app back on the task bar - not tried it for hidden windows though so I can't be sure of the outcome
0
 
LVL 1

Expert Comment

by:nv3prasad
ID: 2696824
Try these small steps ( i.e add handlers and copy the code for each one of them ), which will lead you to all  your solutions.

STEP 1:
---------

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
   //Change the Style
    cs.style = WS_OVERLAPPED | WS_CAPTION | FWS_ADDTOTITLE
                | WS_THICKFRAME | WS_SYSMENU | WS_MINIMIZEBOX |
                WS_MAXIMIZEBOX | WS_MAXIMIZE ;

    return (CFrameWnd::PreCreateWindow(cs));
}// End of Precreate

STEP 2:
---------

void CMainFrame::OnNcLButtonDblClk( UINT nHitTest, CPoint point )
{
    // Check if the double click is on the caption bar
    if(nHitTest == HTCAPTION)
    {
     //If yes do nothing ( eat away the message )
    }
    else
    {
        //else route the message
        CWnd::OnNcLButtonDblClk(nHitTest,point);
    }
}

STEP 3:
----------

void CMainFrame::OnNcLButtonDown( UINT nHitTest, CPoint point )
{
    //If message is from the Minimize or Maximize Button
    //Then eat it
    if(nHitTest == HTMAXBUTTON)
    {
     //Do nothing
    }
    else
    {
        //Route the message
        CWnd::OnNcLButtonDown(nHitTest,point);
    }
}// End of OnNcLButtonDown


Step 4:
---------

void CMainFrame::OnSysCommand( UINT nID, LPARAM lParam )
{
    //if Restore Command and the application is full screen then eat away
    //the message else re route the message
    if(nID == SC_RESTORE)
    {
        if(!IsIconic())
            return;
    }
    CWnd::OnSysCommand(nID, lParam);
}// End of OnsysCommand
0
 
LVL 23

Accepted Solution

by:
chensu earned 150 total points
ID: 2696839
UINT CMainFrame::OnNcHitTest(CPoint point)
{
    UINT nHitTest = CFrameWnd::OnNcHitTest(point);

    if (nHitTest == HTCAPTION || nHitTest == HTMAXBUTTON)
        nHitTest = HTNOWHERE;

    return nHitTest;
}
0
 

Author Comment

by:cternoey
ID: 2698245
Chensu,
Your suggestion was very helpful.
Some difficulty with your solution was:
1) It does not discourage the user from selecting 'move' on the taskbar popup menu.
2) It makes it impossible to activate the window by clicking the caption bar.
However, I did use a variation of your code in my final solution.
Thanks you.

nv3prasad,
Your suggestions were also helpful.
Some difficulty with your solution was:
1) If the user selects 'tile horizontally' or 'tile vertically' from the taskbar popup menu, the window changes to the non-maximized window despite attempts to eat the RESTORE message.
I think it would be a great solution if I knew how to handle the tiling event.

Points:
I only used chensu's code in my final solution, so he gets the 150 points.
I am awarding an 'A' mostly because that will encourage future generations to read this long discussion.

PLEASE NOTE: I am posting a dummy question for nv3prasad worth 50 points because nv3prasad's were very helpful to me in thinking thru my options.

The final solution that I chose works as follows:

Step1:
Define StretchWindow()
void CMainFrame::StretchWindow()
{
      CRect rectDesktop;
      if (!::SystemParametersInfo(SPI_GETWORKAREA, 0, &rectDesktop, 0))
            ::GetWindowRect(::GetDesktopWindow(), &rectDesktop);
      SetWindowPos(&wndTop, rectDesktop.left, rectDesktop.top,
            rectDesktop.right - rectDesktop.left,
            rectDesktop.bottom - rectDesktop.top,
            SWP_SHOWWINDOW);
}

Step2:
Place calls to StretchWindow in OnMove and OnSize.
For example:
void CMainFrame::OnSize(UINT nType, int cx, int cy)
{
      CFrameWnd::OnSize(nType, cx, cy);
      StretchWindow();
}
To my surprise this does not create infinite loops.

Step3:
Adjust window style in PreCreate to remove MaximizeBox:
      cs.style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZE;

Step4:
For a nice touch, adjust chensu's code to be:
UINT CMainFrame::OnNcHitTest(CPoint point)
{
    UINT nHitTest = CFrameWnd::OnNcHitTest(point);
      if (nHitTest == HTCAPTION) {
            nHitTest = HTMAXBUTTON;
      }
    return nHitTest;
}
This fixes a problem that the window could not be activated by clicking the caption bar, but still discourages window moving (it is already prevented by OnMove overload)

Additionally, I think it might help to add a call to StretchWindow inside OnCreate() and also to add these overloads (which might be unnecessary, but seem like a good idea)

void CMainFrame::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)
{
      CFrameWnd::OnGetMinMaxInfo(lpMMI);
      CRect r;
      SystemParametersInfo(SPI_GETWORKAREA, 0, &r, SPIF_UPDATEINIFILE);
      lpMMI->ptMaxSize.x = r.Width();
      lpMMI->ptMaxSize.y = r.Height();
      lpMMI->ptMaxPosition.x = r.left;
      lpMMI->ptMaxPosition.y = r.top;
}

void CMainFrame::OnSettingChange(UINT uFlags, LPCTSTR lpszSection)
{
      CFrameWnd::OnSettingChange(uFlags, lpszSection);
      StretchWindow();
}

Thanks again for all contributions. If ever someone need to solve this problem, I hope they find this page.
0

Featured Post

Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
configuration management 2 99
GIF file bit manipulation for color change 5 104
lucky13 challenge 11 111
tripleUp challenge 7 65
Introduction: Dynamic window placements and drawing on a form, simple usage of windows registry as a storage place for information. Continuing from the first article about sudoku.  There we have designed the application and put a lot of user int…
Exception Handling is in the core of any application that is able to dignify its name. In this article, I'll guide you through the process of writing a DRY (Don't Repeat Yourself) Exception Handling mechanism, using Aspect Oriented Programming.
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
You have products, that come in variants and want to set different prices for them? Watch this micro tutorial that describes how to configure prices for Magento super attributes. Assigning simple products to configurable: We assigned simple products…

708 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

14 Experts available now in Live!

Get 1:1 Help Now