Remembering a Window Position Across Application Invocations

Environment: VC6

I wrote this for a very simple requirement. I wanted the main window of the application to appear at the same position across invocations. Well, what better a place than the Registry to store these positions?

The class for this purpose, called WindowPosition, is a simple class with a handful of public methods.

class WindowPosition
{
public:
  WindowPosition(HKEY hKey,TCHAR* szSubKey);
  virtual ~WindowPosition();

private:
  DWORD m_dwPosArray[5];
  HKEY  m_hKey;
  TCHAR m_szSubKey[MAX_PATH];

  BOOL ValidatePositions(DWORD& dwxPos,DWORD&dwyPos,DWORD&
                                dwWidth,DWORD& dwHeight,DWORD&
                                dwSum);

public:
  BOOL GetWindowPositions(DWORD& dwxPos,DWORD& dwyPos,DWORD&
                                 dwWidth,DWORD& dwHeight);
  void OnWindowPosChanged(WINDOWPOS* lpwndpos);
  BOOL SaveWindowPositions();
};

Here's an explanation of the classes used in the preceding code:

  • GetWindowPositions. Used to get the window positions stored in the Registry.
  • OnWindowPosChanged. Used to set the window positions into the WindowPosition class' member variables.
  • SaveWindowPositions. Used to save the WindowPosition class's data to the Registry.

When constructing the object, one would have to specify the root key and the subkey to store.

Usage

A typical usage of this class can be something like this, and this is how I have implemented it in the sample project that is included with this article.

  1. In the main window class, one would add a member variable of class WindowPosition, say m_wndPos:

    #include "WindowPosition.h"
    
    class CWndPosDlg : public CDialog
    {
    ...............
    // Implementation
    protected:
        HICON m_hIcon;
      WindowPosition  m_wndPos;
        // Generated message map functions
    ...............
    };
    
  2. One would then intercept the WM_WINDOWPOSCHANGED message for the main window and in the handler and simply pass the WINDOWPOS* data to m_wndPos by calling the m_wndPos.OnWindowPosChanged(...) method.

    BEGIN_MESSAGE_MAP(CWndPosDlg, CDialog)
    //{{AFX_MSG_MAP(CWndPosDlg)
    .......
      ON_WM_WINDOWPOSCHANGED()
    .......
    //}}AFX_MSG_MAP
    END_MESSAGE_MAP()
    
    void CWndPosDlg::OnWindowPosChanged( WINDOWPOS* lpwndpos )
    {
      m_wndPos.OnWindowPosChanged(lpwndpos);
      m_wndPos.SaveWindowPositions();
    }
    
  3. One could then save the same to the Registry by calling m_wndPos.SaveWindowPositions() right at that moment (as is done above), or defer it to some other time. For example, one could save the window positions on application exit only.

  4. The next time the application is invoked, we would want the saved window positions to be reflected. You could do this by reading m_wndPos.GetWindowPositions in OnInitDialog (or the equivalent) of the main window and calling SetWindowPos with the retrieved data.

    BOOL CWndPosDlg::OnInitDialog()
    {
      CDialog::OnInitDialog();
    
      // Set the icon for this dialog. The framework does this
      // automatically when the application's main window is not a
      // dialog
      SetIcon(m_hIcon, TRUE);     // Set big icon
      SetIcon(m_hIcon, FALSE);    // Set small icon
    
      // TODO: Add extra initialization here
      DWORD dwXPos,dwYPos,dwWidth,dwHeight;
    
      if(TRUE == m_wndPos.GetWindowPositions(dwXPos,dwYPos,
                                             dwWidth,dwHeight))
      {
        SetWindowPos(NULL,dwXPos,dwYPos,dwWidth,dwHeight,
                     SWP_NOOWNERZORDER | SWP_NOZORDER|SWP_NOSIZE);
      }
      else
        CenterWindow();
          return TRUE;    // return TRUE unless you set the focus
                          // to a control
    }
    

Caveats

Yes, there are a few caveats with this. Nothing so serious, but yes, I would like to fix it and clean it up once I find an elegant way to deal with the issues. If one changes the display resolution, things can get messy!! The main window may even disappear from the visible area of the screen. This is pretty serious and can be annoying.

I would be glad to receive any ideas or suggestions in this matter, or anything for making this a handy class.

Downloads

Download sample - 5 Kb
Download source - 12 Kb


Comments

  • another solution

    Posted by Legacy on 06/23/2003 12:00am

    Originally posted by: Sergey

    class MyDialog: public CDialog { ... };
    
    


    BOOL MyDialog::OnInitDialog()
    {
    ....
    // restore WINDOWPLACAMENT
    WINDOWPLACEMENT wp;
    bool bCenter = true;

    // load structure from some external storage
    // registry, file, etc
    if(LoadFromSomePlace(&wp))
    {
    // center window if SetWindowPlacement fails
    bCenter = !::SetWindowPlacement(GetSafeHwnd(), &wp);
    }

    if(bCenter)
    CenterWindow();
    return TRUE;
    }

    void MyDialog::OnDestroy()
    {
    // save window placement on
    // window destroy

    WINDOWPLACEMENT wp;
    wp.length = sizeof(WINDOWPLACEMENT);
    if(::GetWindowPlacement(&wp))
    {
    // store windowplacemnet
    StoreToSomePlace(&wp);
    }

    // continue destory routines
    ...................
    }

    Reply
  • Recommendation.

    Posted by Legacy on 06/20/2003 12:00am

    Originally posted by: cheepink

    If you want to avoid user changes let save the resolution in the registry also. Or If the resolution is too in the registry is bigger than changed resolution , default it to center.

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Lenovo recommends Windows 8 Pro. "I dropped my laptop getting out of the taxi." This probably sounds familiar to most IT professionals. If your employees are traveling, you know their devices are in for a rough go. Whether it's a trip to the conference room or a convention out of town, any time equipment leaves a user's desk it is at risk of being put into harm's way. Stay connected at all times, whether at the office or on the go, with agile, durable, and flexible devices like the Lenovo® …

  • U.S. companies are desperately trying to recruit and hire skilled software engineers and developers, but there is simply not enough quality talent to go around. Tiempo Development is a nearshore software development company. Our headquarters are in AZ, but we are a pioneer and leader in outsourcing to Mexico, based on our three software development centers there. We have a proven process and we are experts at providing our customers with powerful solutions. We transform ideas into reality.

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date