Forum
Please
Log In
to post a new message or reply to an existing one. If you are not registered, please
register.
NOTE: Some forums may be read-only if you are not currently subscribed to
our technical support services.
Subject |
Author |
Date |
|
Dylan da Silva
|
Apr 20, 2010 - 2:54 PM
|
My menus keep closing whenever a thread tries to send a COMMAND message to the frame. I used ZoomScrollBar to confirm the issue.
I added a resource to resource.h #define ID_JUNK_COMMAND 7000
Here are the modified source files:
// MainFrm.h : interface of the CMainFrame class
//
/////////////////////////////////////////////////////////////////////////////
#if !defined(AFX_MAINFRM_H__8AD8EDA0_FE43_4657_B159_597A63DD8A98__INCLUDED_)
#define AFX_MAINFRM_H__8AD8EDA0_FE43_4657_B159_597A63DD8A98__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "ChildView.h"
#if !defined(__EXT_TEMPL_H)
#include <ExtTempl.h>
#endif
// my stuff ///// begin
class CMyThread : public CWinThread
{
public:
CMyThread(CFrameWnd* wnd) : m_wnd(wnd), m_working(TRUE) {}
~CMyThread(void) {}
CFrameWnd* GetWnd(void) { return m_wnd; }
BOOL IsNotDone(void) { return m_working; }
void StopThread(void) { m_working = FALSE; }
private:
CFrameWnd* m_wnd;
BOOL m_working;
};
// my stuff ///// end
class CMainFrame : public CExtNCW < CFrameWnd >
{
public:
CMainFrame();
protected:
DECLARE_DYNAMIC(CMainFrame)
// Attributes
public:
private:
// window placement persistence
WINDOWPLACEMENT m_dataFrameWP;
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CMainFrame)
public:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
virtual BOOL OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo);
virtual BOOL PreTranslateMessage(MSG* pMsg);
virtual BOOL DestroyWindow();
virtual void ActivateFrame(int nCmdShow = -1);
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CMainFrame();
virtual void RecalcLayout(BOOL bNotify = TRUE);
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
public: // control bar embedded members
class CMyStatusBar : public CExtStatusControlBar
{
protected:
virtual LRESULT WindowProc( UINT message, WPARAM wParam, LPARAM lParam )
{
if( message == WM_HSCROLL || message == WM_VSCROLL )
return GetParent()->GetDlgItem(AFX_IDW_PANE_FIRST)->SendMessage( message, wParam, lParam );
return CExtStatusControlBar::WindowProc( message, wParam, lParam );
}
}; // class CMyStatusBar
CMyStatusBar m_wndStatusBar;
CExtMenuControlBar m_wndMenuBar;
CExtThemeSwitcherToolControlBar m_wndToolBarUiLook;
CChildView m_wndView;
// Generated message map functions
protected:
//{{AFX_MSG(CMainFrame)
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnSetFocus(CWnd *pOldWnd);
afx_msg void OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI);
//}}AFX_MSG
afx_msg void OnUpdateControlBarMenu(CCmdUI* pCmdUI);
afx_msg BOOL OnBarCheck(UINT nID);
// my stuff ///// begin
afx_msg void OnJunkCommand(void);
// my stuff ///// end
DECLARE_MESSAGE_MAP()
// my stuff ///// begin
private:
CMyThread* m_thread;
// my stuff ///// end
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_MAINFRM_H__8AD8EDA0_FE43_4657_B159_597A63DD8A98__INCLUDED_) // MainFrm.cpp : implementation of the CMainFrame class
//
#include "stdafx.h"
#include "ZoomScrollBar.h"
#include "MainFrm.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
// my stuff ///// begin
UINT MyThreadProc( LPVOID pParam );
// my stuff ///// end
/////////////////////////////////////////////////////////////////////////////
// CMainFrame
IMPLEMENT_DYNAMIC( CMainFrame, CFrameWnd )
BEGIN_MESSAGE_MAP( CMainFrame, CFrameWnd )
//{{AFX_MSG_MAP(CMainFrame)
ON_WM_CREATE()
ON_WM_SETFOCUS()
ON_WM_GETMINMAXINFO()
//}}AFX_MSG_MAP
ON_COMMAND_EX(ID_VIEW_MENUBAR, OnBarCheck )
ON_UPDATE_COMMAND_UI(ID_VIEW_MENUBAR, OnUpdateControlBarMenu)
// my stuff ///// begin
ON_COMMAND(ID_JUNK_COMMAND, OnJunkCommand )
// my stuff ///// end
ON_COMMAND_EX(ID_VIEW_UI_LOOK_BAR, OnBarCheck )
ON_UPDATE_COMMAND_UI(ID_VIEW_UI_LOOK_BAR, OnUpdateControlBarMenu)
END_MESSAGE_MAP()
static UINT indicators[] =
{
ID_SEPARATOR, // status line indicator
ID_INDICATOR_LOCATION,
ID_ZOOM_VALUE_PANE,
ID_ZOOM_SCROLL_BAR_PANE,
// ID_INDICATOR_CAPS,
// ID_INDICATOR_NUM,
// ID_INDICATOR_SCRL,
};
void CMainFrame::OnUpdateControlBarMenu(CCmdUI* pCmdUI)
{
CExtControlBar::DoFrameBarCheckUpdate( this, pCmdUI, true );
}
BOOL CMainFrame::OnBarCheck(UINT nID)
{
return CExtControlBar::DoFrameBarCheckCmd( this, nID, true );
}
// my stuff ///// begin
void CMainFrame::OnJunkCommand(void)
{
// do Fibanacci
unsigned long long garbage = 24;
for(int i=0;i<1000;++i)
garbage *= (unsigned long long)i;
}
// my stuff ///// end
/////////////////////////////////////////////////////////////////////////////
// CMainFrame construction/destruction
CMainFrame::CMainFrame()
{
CWinApp * pApp = ::AfxGetApp();
ASSERT( pApp != NULL );
ASSERT( pApp->m_pszRegistryKey != NULL );
ASSERT( pApp->m_pszRegistryKey[0] != _T(’\0’) );
ASSERT( pApp->m_pszProfileName != NULL );
ASSERT( pApp->m_pszProfileName[0] != _T(’\0’) );
if( ! g_PaintManager.PaintManagerStateLoad(
pApp->m_pszRegistryKey,
pApp->m_pszProfileName,
pApp->m_pszProfileName
)
)
g_PaintManager.InstallPaintManager(
RUNTIME_CLASS(CExtPaintManagerOffice2007_R2_LunaBlue)
);
// if( ! g_PaintManager.PaintManagerStateLoad(
// pApp->m_pszRegistryKey,
// pApp->m_pszProfileName,
// pApp->m_pszProfileName
// )
// )
// {
// CExtPaintManagerSkin * pPM = new CExtPaintManagerSkin;
// bool bLoaded = true;
// if( ! pPM->m_Skin.SearchAndLoadSkinFile( _T("Aqua.Skin"), false ) )
// {
// if( ! pPM->m_Skin.SearchAndLoadSkinFile( _T("..\\..\\Skins\\Binary\\Aqua.Skin"), false ) )
// {
// bLoaded = false;
// ::AfxMessageBox( _T("Failed to load initial skin.") );
// delete pPM;
// }
// }
// if( bLoaded )
// g_PaintManager.InstallPaintManager( pPM );
// }
CExtPopupMenuWnd::g_bMenuExpanding = false;
CExtPopupMenuWnd::g_bMenuHighlightRarely = false;
// window placement persistence
::memset( &m_dataFrameWP, 0, sizeof(WINDOWPLACEMENT) );
m_dataFrameWP.length = sizeof(WINDOWPLACEMENT);
m_dataFrameWP.showCmd = SW_HIDE;
}
CMainFrame::~CMainFrame()
{
}
void CMainFrame::RecalcLayout(BOOL bNotify)
{
CExtNCW < CFrameWnd > :: RecalcLayout( bNotify );
}
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if( CExtNCW < CFrameWnd > :: OnCreate( lpCreateStruct ) == -1 )
return -1;
m_wndStatusBar.m_bDrawPaneSeparatorsInsteadOfBorders = true;
if( (! m_wndStatusBar.Create( this ) )
|| (! m_wndStatusBar.SetIndicators(
indicators,
sizeof(indicators)/sizeof(UINT)
) )
)
{
TRACE0("Failed to create status bar\n");
return -1; // fail to create
}
m_wndStatusBar.SetPaneWidth( 0, 10 );
m_wndStatusBar.GetStatusBarCtrl().SetMinHeight( 25 );
// create a view to occupy the client area of the frame
if( ! m_wndView.Create(
NULL,
NULL,
AFX_WS_DEFAULT_VIEW|WS_CLIPCHILDREN|WS_CLIPSIBLINGS,
CRect( 0, 0, 0, 0 ),
this,
AFX_IDW_PANE_FIRST,
NULL
)
)
{
TRACE0("Failed to create view window\n");
return -1;
}
CString strTitleOld = GetTitle(), strTitleNew;
strTitleNew.Format(
_T("%s - [%d objects loaded]"),
LPCTSTR( strTitleOld ),
m_wndView.GetObjectCount()
);
SetTitle( LPCTSTR( strTitleNew ) );
OnUpdateFrameTitle( FALSE );
CWinApp * pApp = ::AfxGetApp();
ASSERT( pApp != NULL );
ASSERT( pApp->m_pszRegistryKey != NULL );
ASSERT( pApp->m_pszRegistryKey[0] != _T(’\0’) );
ASSERT( pApp->m_pszProfileName != NULL );
ASSERT( pApp->m_pszProfileName[0] != _T(’\0’) );
ASSERT( pApp->m_pszProfileName != NULL );
HICON hIcon = pApp->LoadIcon( IDR_MAINFRAME );
ASSERT( hIcon != NULL );
SetIcon( hIcon, TRUE );
SetIcon( hIcon, FALSE );
g_CmdManager->ProfileSetup(
pApp->m_pszProfileName,
GetSafeHwnd()
);
VERIFY(
g_CmdManager->UpdateFromMenu(
pApp->m_pszProfileName,
IDR_MAINFRAME
)
);
if( ! m_wndMenuBar.Create(
NULL,
this,
ID_VIEW_MENUBAR
)
)
{
TRACE0("Failed to create menubar\n");
return -1;
}
if( (! m_wndToolBarUiLook.Create( NULL, this, ID_VIEW_UI_LOOK_BAR ) )
|| (! m_wndToolBarUiLook.ThemeSwitcherInit() )
)
{
TRACE0("Failed to create the m_wndToolBarUiLook toolbar\n");
return -1; // fail to create
}
m_wndToolBarUiLook.EnableDocking( CBRS_ALIGN_ANY );
if( ! CExtControlBar::FrameEnableDocking( this ) )
{
ASSERT( FALSE );
return -1;
}
if( ! CExtControlBar::ProfileBarStateLoad(
this,
pApp->m_pszRegistryKey,
pApp->m_pszProfileName,
pApp->m_pszProfileName,
&m_dataFrameWP
)
)
{
DockControlBar( &m_wndToolBarUiLook, AFX_IDW_DOCKBAR_LEFT );
RecalcLayout();
}
// my stuff ///// begin
m_thread = new CMyThread((CFrameWnd*)this);
AfxBeginThread(MyThreadProc, m_thread);
// my stuff ///// end
return 0;
}
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if( ! CExtNCW < CFrameWnd > :: PreCreateWindow( cs ) )
return FALSE;
cs.dwExStyle &= ~(WS_EX_CLIENTEDGE|WS_EX_LAYOUTRTL);
cs.style |= WS_CLIPCHILDREN|WS_CLIPSIBLINGS;
cs.lpszClass = AfxRegisterWndClass( CS_HREDRAW|CS_HREDRAW|CS_DBLCLKS );
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CMainFrame diagnostics
#ifdef _DEBUG
void CMainFrame::AssertValid() const
{
CExtNCW < CFrameWnd > :: AssertValid();
}
void CMainFrame::Dump(CDumpContext& dc) const
{
CExtNCW < CFrameWnd > :: Dump( dc );
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CMainFrame message handlers
void CMainFrame::OnSetFocus(CWnd* pOldWnd)
{
pOldWnd;
// forward focus to the view window
if( m_wndView.GetSafeHwnd() != NULL )
m_wndView.SetFocus();
}
BOOL CMainFrame::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
{
// let the view have first crack at the command
if( m_wndView.GetSafeHwnd() != NULL )
{
if( m_wndView.OnCmdMsg( nID, nCode, pExtra, pHandlerInfo ) )
return TRUE;
}
// otherwise, do default handling
return CExtNCW < CFrameWnd > :: OnCmdMsg( nID, nCode, pExtra, pHandlerInfo );
}
BOOL CMainFrame::PreTranslateMessage(MSG* pMsg)
{
if( m_wndToolBarUiLook.PreTranslateMessage( pMsg ) )
return TRUE;
if( m_wndMenuBar.TranslateMainFrameMessage(pMsg) )
return TRUE;
return CExtNCW < CFrameWnd > :: PreTranslateMessage(pMsg);
}
BOOL CMainFrame::DestroyWindow()
{
CWinApp * pApp = ::AfxGetApp();
ASSERT( pApp != NULL );
ASSERT( pApp->m_pszRegistryKey != NULL );
ASSERT( pApp->m_pszRegistryKey[0] != _T(’\0’) );
ASSERT( pApp->m_pszProfileName != NULL );
ASSERT( pApp->m_pszProfileName[0] != _T(’\0’) );
VERIFY(
CExtControlBar::ProfileBarStateSave(
this,
pApp->m_pszRegistryKey,
pApp->m_pszProfileName,
pApp->m_pszProfileName
)
);
VERIFY(
g_PaintManager.PaintManagerStateSave(
pApp->m_pszRegistryKey,
pApp->m_pszProfileName,
pApp->m_pszProfileName
)
);
g_CmdManager->ProfileWndRemove( GetSafeHwnd() );
// my stuff ///// begin
m_thread->StopThread();
m_thread->Delete();
// my stuff ///// end
return CExtNCW < CFrameWnd > :: DestroyWindow();
}
void CMainFrame::ActivateFrame(int nCmdShow)
{
// window placement persistence
if( m_dataFrameWP.showCmd != SW_HIDE )
{
SetWindowPlacement( &m_dataFrameWP );
CExtNCW < CFrameWnd > :: ActivateFrame( m_dataFrameWP.showCmd );
m_dataFrameWP.showCmd = SW_HIDE;
return;
}
CExtNCW < CFrameWnd > :: ActivateFrame( nCmdShow );
}
void CMainFrame::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)
{
CFrameWnd::OnGetMinMaxInfo( lpMMI );
lpMMI->ptMinTrackSize.x = g_PaintManager->UiScalingDo( 700, CExtPaintManager::__EUIST_X );
lpMMI->ptMinTrackSize.y = g_PaintManager->UiScalingDo( 300, CExtPaintManager::__EUIST_Y );
}
// my stuff ///// begin
UINT MyThreadProc( LPVOID pParam )
{
CMyThread* pThread = (CMyThread*)pParam;
if (pThread == NULL)
return 1;
while (pThread->IsNotDone())
{
pThread->GetWnd()->PostMessage(WM_COMMAND,MAKEWPARAM(ID_JUNK_COMMAND,0));
Sleep(1000);
}
return 0; // thread completed successfully
}
// my stuff ///// end
Looks like a bug but if it’s not then how would I modify the ZoomScrollBar project to fix the issue I’m having?
|
|
Dylan da Silva
|
Apr 21, 2010 - 4:30 AM
|
And the pasted header and source file were taken directly from the Prof-UIS Sample "ZoomScrollBar" so you can paste them right in.
|
|
Technical Support
|
Apr 22, 2010 - 5:25 AM
|
The problem is not with the WM_COMMAND message. The WM_CANCELMODE message is somehow becomes posted to the main UI thread and that’s why the popup menus become closed. We just verified this message is not sent by MFC and Prof-UIS source code. The following version of the WM_COMMAND method allows you to avoid menu closing: void CMainFrame::OnJunkCommand(void)
{
// do Fibonacci
unsigned long garbage = 24;
for(int i=0;i<1000;++i)
garbage *= (unsigned long)i;
MSG msg;
while( ::PeekMessage( &msg, NULL, WM_CANCELMODE, WM_CANCELMODE, PM_NOREMOVE ) )
{
if( ! ::PeekMessage( &msg, NULL, WM_CANCELMODE, WM_CANCELMODE, PM_REMOVE ) )
break;
}
}
|
|
Dylan da Silva
|
Jul 26, 2010 - 1:14 PM
|
Any movement on this issue? We still have a problem with the menus closing.
|
|
Technical Support
|
Jul 28, 2010 - 2:27 AM
|
Unfortunately, no. The WM_CANCELMODE message is extremely important both for Prof-UIS and Win32 menus. This is the classic approach to close the Win32 menus. If your app needs to ensure there are no menus displayed on the screen, then it should send the WM_CANCELMODE message to the main window. The same is supported by Prof-UIS and we cannot ignore the WM_CANCELMODE messages.
|
|
Dylan da Silva
|
Jul 28, 2010 - 5:57 AM
|
I know there is a lot of text in this message and that you are not likely to be the original tech support representative with whom I originally dealt with, so please take the time to read the issue before answering. I’m aware of what WM_CANCELMODE does and how it should be used. However, our application did not have problems with menus being unusable before we started using Prof-UIS 2.88. Just to save you some time, I’ll recap. Our application periodically sends messages to the active frame resulting in the frame title text changing (one line of code that does this: wnd->SetWindowText() ). It’s a very simple operation and occurs at a 1 second interval. Since switching to Prof-UIS we now cannot keep a menu drop down menu open for longer than 1 second. The previous conversation (see above) resulted in a "fix" that was in fact a hack and changed the behavior of the menus such that they would open and stay open but moving the mouse across the menubar did not sequentially open the drop down menus and often introduced a redraw issue where the menu item tab would be drawn solid white and illegible. This behavior is also not normal and undesirable. We would really like this issue resolved properly. Others who wish to show the time ticking away in title bar or do some other frequent SetWindowText operation via a threaded process will no doubt encounter the same issue. We have been unable to reproduce the issue in a normal VS2003 MFC application such as this application was before we started using Prof-UIS. We were also unable to reproduce the issue in the VS2008 built-in skinning library (which incidentally matches the Prof_UIS look-and-feel very closely).
|
|
Dylan da Silva
|
Apr 22, 2010 - 7:19 AM
|
I’ve implemented the work around and the menu stays open but it is no longer behaving like every other menu I’ve ever seen. For example, open Visual Studio, click the File button and then drag your mouse back and forth along the menu bar. You’ll see that each menu option drops down when you hover over it. Our application no longer does this. Once you click file and the menu drops down, the file menu dropdown persists but none of the other menu items drop down when you hover over them. If you click on another menu item it drops down but then it persists and no others drop down. Also there are frequent redraw issues where the text and the button itself on the menu bar are not drawn, leaving a white square where the button used to be, but the menu dropdown is drawn correctly.
|
|
Dylan da Silva
|
Apr 22, 2010 - 6:38 AM
|
In fact, I’m thinking if you take a closer look at that message structure you might be able to determine the origin of the WM_CANCELMODE message and fix the issue.
|
|
Technical Support
|
Apr 27, 2010 - 10:29 AM
|
We are still trying to catch the source of this WM_CANCELMODE message. But let us take another look at this very interesting task. The WM_COMMAND messages are classically sent by menu items and any kind of buttons. These command messages are typically the main user actions in the most of applications. The user actions can cause displaying dialog boxes and other windows. What is the reason for sending WM_COMMAND messages between threads? Why not to use some other messages?
|
|
Dylan da Silva
|
Apr 27, 2010 - 10:43 AM
|
We need to communicate with a child frame (MDI application) but all we give to the thread is the mainframe. Any Registered Message sent to the mainframe is never received by the Childframe. So we opted to use commands to the document which can get access the child frame. This worked fine before we started using Prof-UIS. Something introduced by Prof-UIS is rerouting or handling commands differently resulting in the menu misbehaving. As a work around we put a Relay() message handler into the mainframe that sends a received message to all descendants. It’s looks like this:
frame->PostMessage(UM_MAINFRAME_RELAY_MESSAGE,static_cast<WPARAM>(UM_CHILDFRAME_MESSAGE));
And all the handler does is this:
this->SendMessageToAllDescendants(static_cast<UINT>(wparam)); So we made it work without breaking the application. But this seems to be an issue we shouldn’t have had to work around.
|
|
Dylan da Silva
|
Apr 22, 2010 - 6:28 AM
|
Just so you can understand why I believe this is a Prof-UIS issue. We have not changed this application and it was working before. All we’ve done is replace controls and dialogs with the Prof-UIS library equivalents and wrapped CFrameWnd or CWnd objects in the Prof-UIS templates (eg. CExtNCW <T>) The only obvious changes that could lead to this issue is the addition of the CExtMenuControlBar, changing our class CChildFrameWnd : public CExtNCW <CMDIFrameWnd>, and overriding the CChildFrameWnd::PreTranslateMessage(MSG*) function so it passes messages to the m_menuControlBar object. The work around that you have provided should get us through in the meantime (provided that it actually works) but we suspect this will impact other things indirectly. We’d like to see a real fix and not have to resort to hacking.
|
|
Dylan da Silva
|
Apr 22, 2010 - 5:58 AM
|
Thank you for your reply. However, I think there is more to this that simply adding this to 25 or 30 command handlers. I realize that using Prof-UIS requires overriding 1 or 2 MFC window message functions namely PreTranslateMessage() and OnCmdMsg(). These functions intercept a command or message and pass it to the Prof-UIS objects you specify so they can handle the message BEFORE anything else does. In this case I have reason to believe that any command sent to the frame is passed to the menu bar on the MainFrame before it reaches it’s target in the MainFrame. Could this be related to the CommandManager somehow? I have not registered the message with the command manager. Could this be causing the problem?
|
|
Dylan da Silva
|
Apr 20, 2010 - 8:07 PM
|
BTW, I’m using Visual Studio 2008 and Prof-UIS v2.88.
|
|