Link to home
Start Free TrialLog in
Avatar of onyxmedia
onyxmedia

asked on

MFC Programming question

Is it possible to disable the move of the window without
hiding the titlebar (like patching GetMinMaxInfo for
disabling the resize of the window) ?
Thanx.
Avatar of jaba
jaba

Yeah. you should dispatch WM_WINDOWPOSCHANGING message. Lparam of this message is pointer to WINDOWPOS structure. You have to set flags member to SWP_NOMOVE.
Or you can change x, y, cx , cy ... members to initial values :-)
For more information look for you SDK documentation. Using flags member method usable for WIN32 but i am not sure about WIN16. But setting x,y,  cx, cy members to i nitial values is usable in WIN16 ( i am sure).
This message also usable for resizing window on  fixed dimentions.
Write a handle for WM_NCHITTEST, call the base class implementation, and change any return of HTCAPTION into HTBORDER (or maybe HTCLIENT).  If the hit test is HTCAPTION, the you can move etc with the mouse - changing the return value to something else changes the behaviour of the mouse.

Please reject previous and so I can submit this one if you prefer it.

Well, well. I am sure, you never seen Windows. Caption usable NOT ONLY for moving window (it usable for maximizingwindow TOO). Its posssible to move window WITHOUT dragging it by caption. (see system menu). Go, Ronslow, lets try to disable THIS method of window moving.

Hey - don't get nasty !!  I HAVE seen windows, thank you very much (you wanna compare expert ratings here? or years of programming experience?).

I simply provided an alternative method of preventing window movement by dragging.

And I DO know there are other ways to move a window than by the title bar, and there are other uses for the titlbe bar.

Your answer seemed a bit confusing, talking about dispatching a WM_WINDOWPOSCHANGING.  Did you really mean providing a handler or reponding to the message?  And don't forget to NOT call the base class.

BTW: You can easily disable the system menu options for moving (and other system menu options).

Here's how...

void CMainFrame::OnInitMenuPopup(CMenu* pMenu, UINT nIndex, BOOL bSysMenu)
{
      if (bSysMenu && !m_bSysMenuInitialized) {
            pMenu->RemoveMenu (SC_MOVE,    MF_BYCOMMAND);
            pMenu->RemoveMenu (SC_SIZE, MF_BYCOMMAND);
            pMenu->RemoveMenu (SC_RESTORE, MF_BYCOMMAND);
            pMenu->RemoveMenu (SC_MINIMIZE,MF_BYCOMMAND);
            pMenu->RemoveMenu (SC_MAXIMIZE,MF_BYCOMMAND);
            pMenu->RemoveMenu (SC_TASKLIST,MF_BYCOMMAND);
            for (UINT i=0; i<pMenu->GetMenuItemCount(); i++) {
                  if (pMenu->GetMenuItemID(i) == 0) { // (if separator)
                        pMenu->RemoveMenu (i, MF_BYPOSITION);
                        continue;
                  }
            }
            m_bSysMenuInitialized = TRUE;
      }
      CFrameWnd::OnInitMenuPopup(pMenu, nIndex, bSysMenu);
}

void CMainFrame::OnNcLButtonDblClk(UINT nHitTest, CPoint point)
{
      if (nHitTest==HTCAPTION) return;
      CFrameWnd::OnNcLButtonDblClk(nHitTest, point);
}

void CMainFrame::OnSysCommand(UINT nID, LPARAM lParam)
{
      switch (nID & 0x0fff0) {
      case SC_MINIMIZE:
      case SC_RESTORE:
      case SC_NEXTWINDOW:
      case SC_PREVWINDOW:
      case SC_TASKLIST:
      case SC_SIZE:
      case SC_MOVE:
            return;             // (don't do anything)
      }
      CFrameWnd::OnSysCommand(nID, lParam);
}

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
      if (! CFrameWnd::PreCreateWindow(cs)) return FALSE;
      cs.style &= ~WS_MINIMIZEBOX;
      cs.style &= ~WS_MAXIMIZEBOX;
      return TRUE;
}

This is MY solution.

void CMainFrame::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos)
{
      CMDIFrameWnd::OnWindowPosChanging(lpwndpos);
    lpwndpos->flags |= SWP_NOMOVE;
   
}

Well there you go.

How will that affect (if at all) initial creation of the main window?  It seems a little harsh rejecting ALL window movements.

Of course, there is also the fact that the user can still try to move the window, and system menu options are still there for doing so, but nothing will happen.  It is better to get rid of the commands (or at least disable them) so it doesn't appear to the user that his system just isn't working any more.  I don't think your solution on its own is the best way to go UI-wise.

Maybe a combination of the two solutions here would be best.

Well. I made small test programm (by MSVC appwizard) and  wrote its  code. All working nice. While initial window creation window never recive WM_MOVE message, only WM_SIZE. What why its  dont  affect  initial creation.
Really, this work correct, but look ugly (because while dragging   window user can see dragging  rectangle but window dont move after  you release mouse button). To avoid it need add few more code:

CMainFrame::OnSize(int cx, int cy)
{
    GetWindowRect(&m_rectWindowRect);
}

void CMainFrame::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos)
{
CMDIFrameWnd::OnWindowPosChanging(lpwndpos);
lpwndpos->flags |= SWP_NOMOVE;
// Setting tracker rectangle to initial  window size and position
lpwndpos->x = m_rectWindowRect.left;
lpwndpos->y = m_rectWindowRect.top;
lpwndpos->cx = m_rectWindowRect.right-m_rectWindowRect.left;
lpwndpos->cy = m_rectWindowRect.top-m_rectWindowRect.bottom;
}

Where m_rectWindowRect.top is CRect member of CMainFrame.
In this case user dont  see tracker rectangle dragging.
Really, if onyxmedia wont window be moved,  he must disable or remove "Move" item  from sysmenu. It correct interface solution. BUT  ! Question  is :
============================
Is it possible to disable the move of the window without
hiding the titlebar (like patching GetMinMaxInfo for
disabling the resize of the window) ?
============================
And my answer is right in this context. I  really dont know anything about onyxmedia`s UI form, he  didnt ask anything about pretty UI view of his main window. May be his main window dont have sysmenu at all.
We have BOTH answered the question correctly (you got in first though) - but in different ways.

"Is it possible to disable the move of the window without
hiding the titlebar"

I've disabled the user from being able to move the window.

You have disabled the window from moving if the user tries

The different is that I am stopping the cause, and you are stopping the effect.

As I said, for a nice user interface onyxmedia should probably combine the two solutions (as you have also now suggested because with your initial solution, the user can still try to move the window and gets an unexpected UI feedback and result).

Anyway - there is little point in us arguing over this.  We have presented our solutions and it is up to onyxmedia to award points for answers.

Perhaps (seeing we have both put some effort into this) he could put up a duplicate question (that I can answer with my solution) so we can BOTH get some points.

BTW: It is quite likely that he DOES have a system menu, because you can get it from right clicking in the title bar of an app.
Avatar of onyxmedia

ASKER

Sorry ...
First, the program NEVER gone in the OnWindowPosChanging,
after your comment (This is MY solution ...), this function was
called, BUT the pointer lpwndpos is always NULL !!!
I had first a debug assertion failed, but after modifications:
if (lpwndpos != NULL) ...
the pointer NEVER get different than NULL !!!
I've tested the proposition from RONSLOW, and it works !!
Sorry jaba ... but thanx for your answer !
What operation system you using ? Vertion of compiler /MFC ? What kind of window ? Any more details ? I cant belive pointer alwas NULL, this part of code tested on reall window.
Seems odd - - can you please post your OnWindowPosChanging code and also the message map entries.

PS: Can I put my solution up as an answer please if you are happy with it?

I'm running Windows NT Workstation 4.0, Visual C++ 5.0,
using MFC, my program is an SDI application and I have
implemented the OnWindowPosChanging in the CMainFrame
class ... Comment : The main view is a CFormView !

Here's the code :

MainFrm.h ---------------------------------------------------
protected:
      afx_msg void OnWindowPosChanging( WINDOWPOS FAR* lpwndpos );

MainFrm.cpp -----------------------------------------------
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
      //{{AFX_MSG_MAP(CMainFrame)
      ON_MESSAGE(WM_WINDOWPOSCHANGING, OnWindowPosChanging)
      //}}AFX_MSG_MAP
END_MESSAGE_MAP()

void CMainFrame::OnWindowPosChanging( WINDOWPOS FAR* lpwndpos )
{
      CFrameWnd::OnWindowPosChanging(lpwndpos);
      WINDOWPOS *lpwp = lpwndpos;
//      lpwndpos->flags |= SWP_NOMOVE;
}

Note : I have made a VERY simple SDI application with
only THIS function in the MainFrame, and I have lauched
it in debug mode -> the pointer lpwp is ALWAYS NULL !

Comment to RONSLOW : Yes, you can put your solution as an
answer, I would be happy to grade it !
Dear Onixmedia,
It is quite clear why you get the lpwndpos always NULL. The ON_MESSAGE macro should be associated with following prototype funciton:
LONG OnMyWindowPosChanging( UINT wParam, LONG lParam )
{WINDOWPOS FAR* lpwndpos = (WINDOWPOS FAR*)lParam;
  ...
}
If you wont to use CWnd::OnWindowPosChanging, then add
Add the ON_WM_WINDOWPOSCHANGING( ) macro to you messag map and DO  NOT you ON_MESSAGE.
yours, IGor

ASKER CERTIFIED SOLUTION
Avatar of RONSLOW
RONSLOW

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thanx !