I'm trying to use DeferWindowPos to update the z order of some dialog boxes, but it's not working. Well, the z order does change, but not always in the requested order. Why could that be? It's supposed to work, right?
I am checking all the return values. I observered that if I add the flag SWP_NOSENDCHANGING, DeferWindowPos returns 0 without GetLastError() returning any error code. I didn't add message handlers for WM_WINDOWPOSCHANGING in any of my dialog classes.
For now I use SetWindowPos instead. It always works but it's slower.
I wrote a test, see code below. Any help would be much appreciated.
void test()
{
#ifdef DEFER_WINDOW_POS
class DeferPos
{
public:
DeferPos( const int innWindowCount = 1 )
{
m_hdwp = BeginDeferWindowPos( innWindowCount );
assert( m_hdwp != nullptr );
}
~DeferPos()
{
if( !EndDeferWindowPos(m_hdwp) ) { assert( false ); }
}
void Set( HWND hWnd, HWND hWndAfter, int x, int y, int nWidth, int nHeight, UINT uFlags )
{
assert( m_hdwp != nullptr );
assert( GetLastError() == 0 );
m_hdwp = DeferWindowPos( m_hdwp, hWnd, hWndAfter, x, y, nWidth, nHeight, uFlags );
assert( m_hdwp != nullptr );
assert( GetLastError() == 0 );
}
private:
HDWP m_hdwp = nullptr;
};
auto update_z_order = [](const std::vector<HWND>& vec, UINT flags)
{
DeferPos dp( static_cast<int>(vec.size()) );
HWND hWndAfter = HWND_TOP;
for( HWND hWnd : vec )
{
dp.Set( hWnd, hWndAfter, 0, 0, 0, 0, flags );
hWndAfter = hWnd;
}
};
#else
auto update_z_order = [](const std::vector<HWND>& vec, UINT flags)
{
HWND hWndAfter = HWND_TOP;
for( HWND hWnd : vec )
{
::SetWindowPos(hWnd, hWndAfter, 0, 0, 0, 0, flags );
hWndAfter = hWnd;
}
};
#endif
auto get_dialog_z_order = []()
{
std::vector<HWND> vec;
EnumWindows( [](HWND hWnd, LPARAM lparam)-> BOOL
{
if( dynamic_cast<CDialog*>(CWnd::FromHandle(hWnd)) )
{
reinterpret_cast<std::vector<HWND>*>(lparam)->push_back( hWnd );
}
return TRUE;
}, reinterpret_cast<LPARAM>(&vec) );
return vec;
};
const std::vector<HWND> original_order = get_dialog_z_order();
const std::vector<HWND> reverse_order( original_order.rbegin(), original_order.rend() );
const UINT flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE;
update_z_order( reverse_order, flags );
const std::vector<HWND> new_order = get_dialog_z_order();
assert( new_order == reverse_order ); // this assert sometimes fails when DEFER_WINDOW_POS is defined
}
Related
EDIT : Now this is strange, if I move the call to jItems::populate ( std::string myList ) to the constructor of jDropDown::jDropDown from else where in the jDropDown::jDropDown, the child windows get created.
Originally its been called when the dropdown(jDropDown) window is made visible(shown), and the flow of the program doesn't allow a call to jItems::populate ( std::string myList ) be moved to constructor of jDropDown::jDropDown.
What I an trying to do is create a custom Dropdown box from scratch, the problem I am facing is the final Items(jItem) windows are not created, its an oop design and
every Items(jItem) is derived from jPanel, the other parts of the dropdown box are also drived from jPanel so creating each and every window follows the same process yet the final
Items(jItem) windows are not created, they are not visible and I can't find them with visual studio Spy++
I have checked for instance handle and window handle, and both the checks returns true, yet the jItem windows are not visible and can't find them in spy++ (I can see all the other windows in spy++)
Any help is appreciated.
Here is a reference image and some relevant code.
bool jPanel::registered = false;
jPanel::jPanel( std::string txt, int x, int y, int width, int height, HWND parent, HINSTANCE hInstance, WORD bitmap, DWORD style )
: jControl( parent, hInstance, bitmap )
{
if ( ! registered )
{
WNDCLASSEX wincl;
wincl.hInstance = hInstance;
wincl.lpszClassName = "jPanel";
wincl.lpfnWndProc = WndProc;
wincl.style = CS_BYTEALIGNWINDOW;
wincl.cbSize = sizeof ( WNDCLASSEX );
wincl.hIcon = 0;
wincl.hIconSm = 0;
wincl.hCursor = ::LoadCursor ( NULL, IDC_ARROW );
wincl.lpszMenuName = NULL;
wincl.cbClsExtra = 0;
wincl.cbWndExtra = 4;
wincl.hbrBackground = ::CreateSolidBrush ( backgroundColor );
::RegisterClassEx ( &wincl );
jPanel::registered = true;
}
DWORD flag = WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_CHILD;
if ( style ) flag = flag | style;
hwnd = ::CreateWindowEx ( 0, "jPanel", txt.c_str ( ), flag, x, y, width, height, parent, 0, hInstance, ( LPVOID ) this ) ;
};
jDropDown::jDropDown ( std::string txt, int x, int y, int width, int height, HWND parent, HINSTANCE hInstance, WORD bitmap )
: jPanel ( txt, x, y, width, height, parent, hInstance, bitmap ), capture ( false ), populated ( false )
{
RECT rect;
::GetWindowRect ( hwnd, &rect );
::MapWindowPoints ( HWND_DESKTOP, ::GetParent ( parent ), ( LPPOINT ) &rect, 2 );
items = new jItems ( "My Items List", rect.left, rect.top + height, width, 300, ::GetParent( parent ), hInstance, 0 );
items->setBackgroundColor ( RGB ( 100, 100, 100 ) );
};
jItems::jItems ( std::string txt, int x, int y, int width, int height, HWND parent, HINSTANCE hInstance, WORD bitmap )
: jPanel ( txt, x, y, width, height, parent, hInstance, bitmap ), wWidth ( width ), wHeight ( 30 )
{
::SetWindowPos ( this->hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE );
};
bool jItems::populate ( std::string myList )
{
int y = 0;
Hinstance hInstance = ::GetModuleHandle ( NULL );
std::vector < std::string > list = model::Service::explode ( "^", myList );
for ( std::vector < std::string >::const_iterator it = list.begin ( ); it != list.end ( ); ++it )
{
std::string s = *it;
jItem *i = new jItem ( "Your Item", 0, y, wWidth, wHeight, this->hwnd, hInstance, 0 );
}
::SetWindowPos ( this->hwnd, HWND_TOP, 0, 0, wWidth, list.size ( ) * wHeight, SWP_NOMOVE | SWP_NOZORDER );
return true;
};
jItem::jItem ( std::string txt, int x, int y, int width, int height, HWND parent, HINSTANCE hInstance, WORD bitmap )
: jPanel ( txt, x, y, width, height, parent, hInstance, bitmap ), empty ( false )
{
this->setBackgroundColor ( RGB ( 65, 65, 65 ) );
};
I have gone through all I could find on net but seems like I am missing some very basic thing, having spent so much time on this problem isn't making things easier, so I will go ahead and ask for a help here, see if you can find what I am doing wrong.
Here is the code :
jControl.h
#ifndef _JCONTROL_H
#define _JCONTROL_H
namespace view
{
class jControl
{
public:
HWND hwnd;
HWND hParent;
HBITMAP hbitmap;
std::string text;
HFONT hFont;
COLORREF textColor;
COLORREF backgroundColor;
RECT updateRegion;
bool isUpdateRegion;
public:
jControl ( );
jControl ( HWND parent, HINSTANCE hInstance, WORD bitmap );
~jControl ( );
virtual void show ( );
virtual void hide ( );
virtual void disable ( );
virtual void enable ( );
virtual std::string getText ( );
virtual void setText ( std::string txt );
virtual void setUpdateRegion ( RECT rect );
virtual void setTextColor ( COLORREF crf );
virtual void setBackgroundColor ( COLORREF crf );
virtual void setFont ( HFONT font );
virtual bool setRange ( int range );
virtual bool setStep ( int step );
};
};
#endif
jControl.cpp
#include "jControl.h"
namespace view
{
jControl::jControl( ){};
jControl::jControl ( HWND parent, HINSTANCE hInstance, WORD bitmap )
: hParent ( parent ), hbitmap ( NULL ), isUpdateRegion ( false ), textColor ( RGB ( 255, 255, 255 ) ), backgroundColor ( RGB ( 54, 54, 54 ) )
{
hFont = ::CreateFont ( 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Myriad Pro" );
if ( bitmap != 0 ) hbitmap = LoadBitmap ( hInstance, MAKEINTRESOURCE ( bitmap ) );
};
jControl::~jControl ( )
{
if ( hbitmap ) DeleteObject ( hbitmap );
if ( hFont ) DeleteObject ( hFont );
if ( hwnd ) DestroyWindow ( hwnd );
};
void jControl::show( ) { ::ShowWindow( hwnd, SW_SHOW ); };
void jControl::hide( ) { ::ShowWindow( hwnd, SW_HIDE ); };
void jControl::disable ( ) { EnableWindow ( hwnd, false ); };
void jControl::enable ( ) { EnableWindow ( hwnd, true ); };
std::string jControl::getText ( ) { return text; };
void jControl::setText ( std::string txt ) { text = txt; InvalidateRect ( hwnd, NULL, true ); };
void jControl::setUpdateRegion ( RECT rect ) { updateRegion = rect; isUpdateRegion = true; };
void jControl::setTextColor ( COLORREF crf ) { textColor = crf; };
void jControl::setBackgroundColor ( COLORREF crf ) { backgroundColor = crf; ::InvalidateRect ( hwnd, NULL, true ); };
void jControl::setFont ( HFONT font ) { hFont = font; };
bool jControl::setRange ( int range ) { return true; };
bool jControl::setStep ( int step ) { return true; };
};
jProgressBar.h
#ifndef _JPROGRESSBAR_H
#define _JPROGRESSBAR_H
/** * Parent class include */
#ifndef _JCONTROL_H
#include "../jControl/jControl.h"
#endif
namespace view
{
class jProgressBar : public jControl
{
public:
jProgressBar ( std::string txt, int x, int y, int width, int height, HWND parent, HINSTANCE hInstance, WORD bitmap );
~jProgressBar ( );
std::string getText ( );
void setText ( std::string txt );
bool setRange ( int range );
bool setStep ( int step );
};
};
#endif
jProgressBar.cpp
#include "jProgressBar.h"
namespace view
{
jProgressBar::jProgressBar( std::string txt, int x, int y, int width, int height, HWND parent, HINSTANCE hInstance, WORD bitmap )
: jControl( parent, hInstance, bitmap )
{
hwnd = CreateWindowEx ( WS_EX_TOPMOST, PROGRESS_CLASS, txt.c_str(), WS_CHILD | WS_CLIPSIBLINGS | WS_CHILD, x, y, width, height, parent, 0, hInstance, 0 );
};
jProgressBar::~jProgressBar ( ){};
bool jProgressBar::setRange ( int range )
{
if ( SendMessage ( hwnd, PBM_SETRANGE, 0, MAKELPARAM ( 0, range ) ) != 0 ) return true;
return false;
};
bool jProgressBar::setStep ( int step )
{
if ( SendMessage ( hwnd, PBM_SETSTEP, ( WPARAM ) step, 0 ) != 0 ) return true;
return false;
};
};
And here is the error :
[Linker error] jProgressBar/jProgressBar.cpp:14: undefined reference to `vtable for view::jProgressBar'
I get the error on Constructor and Destructor of JProgressBar.
The problem may be in these lines:
std::string getText( );
and
void setText( std::string txt );
in jProgressBar.h
Please provide a definition for this function in Cpp or remove it from header, I think it should compile. The main reason is: you have overridden a virtual function in a child class with a declaration, but haven't given a definition for the method.
The compiler knows about the function, but the linker is not able to find the definition
For example:
class Base
{
virtual void f() = 0;
}
class Derived : public Base
{
void f();
}
Listboxes do not auto-resize. The best we've got is:
SendMessage(my_listbox, LB_SETHORIZONTALEXTENT, 1000, 0);
MS helpfully notes that "...a list box does not update its horizontal extent dynamically."
(why the heck not...but I digress)
How can the width be set dynamically to avoid truncating the text of a message longer than 1000px?
if I understand the question... :-)
You'll essentially need to measure all of the items in the list box and calculate the maximum width of the list box contents, and then adjust the width of the listbox.
Here's some code from this project (that adds a automatic horizontal scrollbar to listboxes). This snippet is called when the font changes but it demonstrates (roughly) what's needed:
static void OnSetFont( HWND hwnd, HFONT hFont )
//
// Font has changed!
// We need to measure all of our items and reset the horizontal extent of the listbox
{
CData *pData = reinterpret_cast< CData * >( ::GetProp( hwnd, g_pcszDataProperty ) );
pData->m_hFont = hFont;
//
// Set up a HDC...
HDC hdc = GetDC( hwnd );
HGDIOBJ hOld = SelectObject( hdc, pData->m_hFont );
//
// Record the average width for use as our 'fudge factor' later.
TEXTMETRIC tm;
GetTextMetrics( hdc, &tm );
pData->m_nAvergeCharWidth = tm.tmAveCharWidth;
pData->m_nMaxWidth = 0;
//
// This is used as our item buffer. Saves us from having to handle the reallocation
// for different string lengths
CArray< TCHAR, TCHAR > arrBuffer;
//
// Quick reference to make the code below read better
CArray< int, int > &arrWidth = pData->m_arrItemWidth;
//
// The main loop. Iterate over the items, get their text from the listbox and measure
// it using our friendly little helper function.
const UINT uCount = arrWidth.GetSize();
for( UINT u = 0; u < uCount; u++ )
{
const int nLength = ::SendMessage( hwnd, LB_GETTEXTLEN, u, 0 );
arrBuffer.SetSize( nLength + 1 );
::SendMessage( hwnd, LB_GETTEXT, u, (WPARAM)arrBuffer.GetData() );
const int nItemWidth = BaseMeasureItem( pData, hwnd, hdc, arrBuffer.GetData() );
pData->m_arrItemWidth.SetAt( u, nItemWidth );
if( nItemWidth > pData->m_nMaxWidth )
{
pData->m_nMaxWidth = nItemWidth;
}
}
//
// Now, either set the horizontal extent or not, depending on whether we think we need it.
if( pData->m_nMaxWidth > pData->m_nClientWidth )
{
::SendMessage( hwnd, LB_SETHORIZONTALEXTENT, pData->m_nMaxWidth + pData->m_nAvergeCharWidth, 0 );
}
else
{
::SendMessage( hwnd, LB_SETHORIZONTALEXTENT, 0, 0 );
}
//
// The usual release of resources.
SelectObject( hdc, hOld );
ReleaseDC( hwnd, hdc );
}
and...
static int BaseMeasureItem( CData *pData, HWND hwnd, HDC hdc, LPCTSTR pcszText )
//
// Measure and item and adjust the horizontal extent accordingly.
// Because the HDC is already set up we can just do it.
// We return the width of the string so our caller can use it.
{
SIZE size;
::GetTextExtentPoint32( hdc, pcszText, _tcslen( pcszText ), &size );
if( size.cx > pData->m_nMaxWidth )
{
pData->m_nMaxWidth = size.cx;
if( pData->m_nMaxWidth > pData->m_nClientWidth )
{
::SendMessage( hwnd, LB_SETHORIZONTALEXTENT, pData->m_nMaxWidth + pData->m_nAvergeCharWidth, 0 );
}
}
return size.cx;
}
How can I check if an other app is running in full screen mode & topmost in c++ MFC?
I just want to disable all of my auto dialogs (warnings) if media player or other players are running. (Like silent/gamer mode in Avast.)
How could I do that?
Thank you.
using a combination of EnumWindows, GetWindowInfo and GetWindowRect does the trick.
bool IsTopMost( HWND hwnd )
{
WINDOWINFO info;
GetWindowInfo( hwnd, &info );
return ( info.dwExStyle & WS_EX_TOPMOST ) ? true : false;
}
bool IsFullScreenSize( HWND hwnd, const int cx, const int cy )
{
RECT r;
::GetWindowRect( hwnd, &r );
return r.right - r.left == cx && r.bottom - r.top == cy;
}
bool IsFullscreenAndMaximized( HWND hwnd )
{
if( IsTopMost( hwnd ) )
{
const int cx = GetSystemMetrics( SM_CXSCREEN );
const int cy = GetSystemMetrics( SM_CYSCREEN );
if( IsFullScreenSize( hwnd, cx, cy ) )
return true;
}
return false;
}
BOOL CALLBACK CheckMaximized( HWND hwnd, LPARAM lParam )
{
if( IsFullscreenAndMaximized( hwnd ) )
{
* (bool*) lParam = true;
return FALSE; //there can be only one so quit here
}
return TRUE;
}
bool bThereIsAFullscreenWin = false;
EnumWindows( (WNDENUMPROC) CheckMaximized, (LPARAM) &bThereIsAFullscreenWin );
edit2: updated with tested code, which works fine here for MediaPlayer on Windows 7. I tried with GetForeGroundWindow instead of the EnumWindows, but then the IsFullScreenSize() check only works depending on which area of media player the mouse is in exactly.
Note that the problem with multimonitor setups mentioned in the comment below is still here.
in my oppinion a very little improvement
bool AreSameRECT (RECT& lhs, RECT& rhs){
return (lhs.bottom == rhs.bottom && lhs.left == lhs.left && lhs.right == rhs.right && lhs.top == rhs.top) ? true : false;
}
bool IsFullscreenAndMaximized(HWND hWnd)
{
RECT screen_bounds;
GetWindowRect(GetDesktopWindow(), &screen_bounds);
RECT app_bounds;
GetWindowRect(hWnd, &app_bounds);
if(hWnd != GetDesktopWindow() && hWnd != GetShellWindow()) {
return AreSameRECT(app_bounds, screen_bounds);
}
return false;
}
And thanks to priviose answer
BOOL CALLBACK CheckFullScreenMode ( HWND hwnd, LPARAM lParam )
{
if( IsFullscreenAndMaximized(GetForegroundWindow()) )
{
* (bool*) lParam = true;
std::cout << "true";
return FALSE;
}
return TRUE;
}
int main() {
bool bThereIsAFullscreenWin = false;
EnumWindows( (WNDENUMPROC) CheckFullScreenMode, (LPARAM) &bThereIsAFullscreenWin );
}
I made an editor which written in pure WinAPI. Some users want the caption icon become a drag source of the file that opened in editor, like what the explorer window does. I have no idea to implement such feature. Can someone give me example please?
Here is a sample showing how to use the system menu ("caption icon") to detect when to initiate a drag-drop operation:
class SysMenuDragSample
: public CWindowImpl< SysMenuDragSample, CWindow, CFrameWinTraits >
{
private:
static const UINT WM_SHOWSYSTEMMENU = 0x313;
bool mouse_down_in_sys_menu_;
public:
BEGIN_MSG_MAP_EX( SysMenuDragSample )
MSG_WM_NCLBUTTONDOWN( OnNcLButtonDown )
MSG_WM_NCLBUTTONUP( OnNcLButtonUp )
MSG_WM_MOUSEMOVE( OnMouseMove )
MSG_WM_LBUTTONUP( OnLButtonUp )
END_MSG_MAP()
SysMenuDragSample()
: mouse_down_in_sys_menu_( false )
{
}
void BeginDragDropOperation()
{
// TODO: Implement
}
void OnNcLButtonDown( UINT hit_test, CPoint cursor_pos )
{
if( hit_test == HTSYSMENU )
{
mouse_down_in_sys_menu_ = true;
SetCapture();
// NOTE: Future messages will come through WM_MOUSEMOVE, WM_LBUTTONUP, etc.
}
else
SetMsgHandled( FALSE );
}
void OnNcLButtonUp( UINT hit_test, CPoint cursor_pos )
{
if( hit_test == HTSYSMENU )
{
// This message and hit_test combination should never be received because
// SetCapture was called in OnNcLButtonDown.
assert( false );
}
else
SetMsgHandled( FALSE );
}
void OnMouseMove( UINT modifiers, CPoint cursor_pos )
{
if( mouse_down_in_sys_menu_ )
{
ClientToScreen( &cursor_pos );
UINT hit_test = SendMessage( WM_NCHITTEST, 0, MAKELPARAM( cursor_pos.x, cursor_pos.y ) );
if( hit_test != HTSYSMENU )
{
// The cursor has moved outside of the system menu icon so begin the drag-
// drop operation.
mouse_down_in_sys_menu_ = false;
ReleaseCapture();
BeginDragDropOperation();
}
}
else
SetMsgHandled( FALSE );
}
void OnLButtonUp( UINT modifiers, CPoint cursor_pos )
{
if( mouse_down_in_sys_menu_ )
{
// The button was released inside the system menu so simulate a normal click.
mouse_down_in_sys_menu_ = false;
ReleaseCapture();
ClientToScreen( &cursor_pos );
SendMessage( WM_SHOWSYSTEMMENU, 0, MAKELPARAM( cursor_pos.x, cursor_pos.y ) );
}
else
SetMsgHandled( FALSE );
}
};