I've been working on a custom GUI framework since I just can't deal with managed crap or native code which requires development of UIs through markup (XAML). I am trying to create a prototype of an application which uses that GUI framework, but I am having a platform-specific issue with the nature of windows within WinAPI.
The DWM doesn't really allow customization of the non-client area which breaks immersion, the only thing it allows is extension into the client area in order to give an illusion of customization.
So, the best course of action is to reconstruct the "non-client area" within the client area (relative to WINAPI) and that required me to strip the caption, maximize, minimize buttons etc. So, I basically enumerated all the things I want out and OR-ed them together and flipped all the bits in order to deactivate them.
~(WS_CAPTION | WS_SYSMENU | WS_HSCROLL | WS_VSCROLL | WS_MINIMIZE | WS_MAXIMIZE | WS_THICKFRAME)
Once these style go away, I cannot use normal shutdown procedures (Alt+F4, or right clicking in the taskbar and going "Close") because they don't work. I had to intercept VK_ESCAPE and PostQuitMessage(0) manually just so I could exit without being forced to kill the process.
Why is this so? And how can I fix this?
The short answer
Replace:
~(WS_CAPTION | WS_SYSMENU | WS_HSCROLL | WS_VSCROLL | WS_MINIMIZE | WS_MAXIMIZE | WS_THICKFRAME)
With:
WS_POPUP
And no more funky behavior. The application responds correctly. Enjoy the cake.
The long answer
Ah, as with everything on MSDN lately, the cake is a lie. Window styles are not really just visual. They also specify what inherent window functionalities are available to the application's window(s). Now, there is a fair amount of trickery here to be observed.
First of all, the MSDN isn't really forthcoming and useful with its window style definition table. The default behavior for windows is the classic caption, close, border package which is identified as the WS_OVERLAPPEDWINDOW which occupies the simplest expression, 0 (a 32-bit value, all bits down, 0x00000000), so someone wishing to rush through things could just set 0 for styles in the CreateWindow* function and it would yield a classic window.
What you want is a bare-bone, dirty and empty window. And Microsoft's got exactly the thing you're looking for - WS_POPUP which sets the highest bit to 1 and everything else is 0. This will drop all the fancy resizing automata, window captioning and the cute minimize, maximize and close buttons.
Which means you're going to have to reimplement everything. But that's what you're going for, right?
Just flipping all the bits isn't enough, you will drop the wanted options, but also activate the rest of the options resulting in the application acting funny, what you're experiencing right now. Therefore, you either AND it with something else or use something readily defined by Microsoft - WS_POPUP.
And again. Enjoy the cake and happy coding.
Related
I use a CEdit text field to input a search term in an MFC application. When using it on FullHD resolution it works fine, I can input as long as big of a string as i need, but when using on 4k resolution the text is limited to 10 characters. The return of GetLimitText is 3000, and if I SetLimitText to a value smaller than 10 it works, limiting to more (such as 20) doesn't do anything, only 10 characters can be input still. Has anyone had this problem before or it might be from my implementation?
I "fixed" it in a way. I was calling CWnd::ModifyStyleEx(0, WS_EX_CLIENTEDGE). I replaced with CWnd::ModifyStyle(0, WS_BORDER). This is not a true fix as it changes the way it looks a bit, but I guess this is a bug.
I ran into a similar problem when creating the equivalent of resources for a CDialogBar on-the-fly (instead of using the resource editor). One of the controls was a CEdit control, and as user3808318 pointed out, MFC or Windows mysteriously ignores any value you assign using SetLimitText, and seems to ignore any characters you type that would extend beyond the edit control on the screen.
This is the original way that I created the edit control that resulted in this problem.
Create (WS_CHILD | WS_VISIBLE | WS_BORDER, rectDummy, this, IDC_FIND_TEXT)
Here is the correct way, now including the ES_AUTOHSCROLL option.
Create(WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL, rectDummy, this, IDC_FIND_TEXT)
I was investigating an issue related to losing focus and changing activation of windows. What I found was that if I create an invisible property sheet, the active/foreground window changes and so does the focus window. Here is some sample MFC code:
// ignore CAutoDeleter, just a template that calls "delete this " in PostNcDestroy()
CPropertySheet* pSheet = new CAutoDeleter<CPropertySheet>(_T("Test Sheet"));
CTestPage* pPage = new CAutoDeleter<CTestPage>();
pSheet->AddPage(pPage);
DWORD style = WS_SYSMENU | WS_POPUP | WS_CAPTION | DS_MODALFRAME | DS_CONTEXTHELP;
// style |= WS_DISABLED; //does nothing to help
DWORD exStyle = 0;
//exStyle = WS_EX_NOPARENTNOTIFY|WS_EX_NOACTIVATE; // does nothing to help
pSheet->Create(AfxGetMainWnd(), style, exStyle); // adding
After the call to pSheet->Create(), the active/foreground/focus window has changed and the application window is on top. If I use Spy++ and look at the window that is created, it turns out that a property sheet is a DIALOG window class. I am assuming it has a different WNDPROC, of course. What is interesting, is if I create an invisible modeless dialog using, it does not exhibit the problem. If I create the invisible modeless dialog, the active/foreground/focus window remains the same.
I tried setting various flags as in the code snippet, but alas they did not have any discernible effect--I still had the flashing and activation non-sense.
I could get some improvement by setting and clearing a hook (WH_CBT) before and after pSheet->Create()--and then eating the activation messages. When I do that, I don't have the horrible flashing and my application window does not come to the top. However, the focus (and caret for windows that have carets) does go away from whichever window had it before the Create().
Does anyone know a way to keep the focus and activation unchanged when creating an invisible property sheet? (At some point, the property sheet may or may not be set visible. And, if the property sheet is invisible when being destroyed, it also causes the blinking and activation changes.)
I tried using the values returned in GetUIThreadInfo() to try and restore things after the call to Create(), but it causes some flashing as well.
I just want to know how to create an invisible Property Sheet which won't cause the active, foreground, and focus window to change.
Unfortunately the underlying API function PropertySheet calls SetForegroundWindow on the main property sheet dialog after creation. There's no easy way around this - your kludge with the WH_CBT hook is probably your best option.
Edit: As suggested by #stephen in the comments on this duplicate question, you may be able to prevent the activation/focus change using LockSetForegroundWindow.
I have been struggling with this same issue for weeks, with a similar project, where my main application launches a secondary EXE process to act as a server in an audio application (which needs to be a separate process to shield the application from plugin faults, and so it can be high priority for real-time audio processing).
My secondary EXE is a modeless CPropertySheet, for status and diagnostic display, but is intended to be launched hidden and in the background. However it was always stealing the activation from the main application on launch, regardless of what workarounds I tried (such as overriding OnWindowPosChanging).
I thought I was going to go mad, so I was very happy to find this question. The WH_CBT trick is useful, but I found while it prevented activation of the secondary EXE, it did not prevent deactivation of the main application.
But then I discovered an excellent solution, in the LockSetForegroundWindow API (available since Win2K) which I had never heard of before. Looks like it is intended for exactly this purpose, to disable the change of foreground activation and prevent peer processes from stealing it.
https://msdn.microsoft.com/en-us/library/windows/desktop/ms633532(v=vs.85).aspx
It works very well to nullify the internal call to SetForegroundWindow that happens deep within the property sheet common control, and works equally well whether used in the main application before CreateProcess or in the secondary EXE. I chose the latter case, to wrap the property sheet creation:
LockSetForegroundWindow(LSFW_LOCK);
pSheet->Create(NULL, dwStyle, dwExStyle);
LockSetForegroundWindow(LSFW_UNLOCK);
This minimises the scope of the intervention and keeps the fix localised to the process that is the source of the problem. I hope this will save others from wasting as much time on this tedious issue as I did.
I was investigating an issue related to losing focus and changing activation of windows. What I found was that if I create an invisible property sheet, the active/foreground window changes and so does the focus window. Here is some sample MFC code:
// ignore CAutoDeleter, just a template that calls "delete this " in PostNcDestroy()
CPropertySheet* pSheet = new CAutoDeleter<CPropertySheet>(_T("Test Sheet"));
CTestPage* pPage = new CAutoDeleter<CTestPage>();
pSheet->AddPage(pPage);
DWORD style = WS_SYSMENU | WS_POPUP | WS_CAPTION | DS_MODALFRAME | DS_CONTEXTHELP;
// style |= WS_DISABLED; //does nothing to help
DWORD exStyle = 0;
//exStyle = WS_EX_NOPARENTNOTIFY|WS_EX_NOACTIVATE; // does nothing to help
pSheet->Create(AfxGetMainWnd(), style, exStyle); // adding
After the call to pSheet->Create(), the active/foreground/focus window has changed and the application window is on top. If I use Spy++ and look at the window that is created, it turns out that a property sheet is a DIALOG window class. I am assuming it has a different WNDPROC, of course. What is interesting, is if I create an invisible modeless dialog using, it does not exhibit the problem. If I create the invisible modeless dialog, the active/foreground/focus window remains the same.
I tried setting various flags as in the code snippet, but alas they did not have any discernible effect--I still had the flashing and activation non-sense.
I could get some improvement by setting and clearing a hook (WH_CBT) before and after pSheet->Create()--and then eating the activation messages. When I do that, I don't have the horrible flashing and my application window does not come to the top. However, the focus (and caret for windows that have carets) does go away from whichever window had it before the Create().
Does anyone know a way to keep the focus and activation unchanged when creating an invisible property sheet? (At some point, the property sheet may or may not be set visible. And, if the property sheet is invisible when being destroyed, it also causes the blinking and activation changes.)
I tried using the values returned in GetUIThreadInfo() to try and restore things after the call to Create(), but it causes some flashing as well.
I just want to know how to create an invisible Property Sheet which won't cause the active, foreground, and focus window to change.
Unfortunately the underlying API function PropertySheet calls SetForegroundWindow on the main property sheet dialog after creation. There's no easy way around this - your kludge with the WH_CBT hook is probably your best option.
Edit: As suggested by #stephen in the comments on this duplicate question, you may be able to prevent the activation/focus change using LockSetForegroundWindow.
I have been struggling with this same issue for weeks, with a similar project, where my main application launches a secondary EXE process to act as a server in an audio application (which needs to be a separate process to shield the application from plugin faults, and so it can be high priority for real-time audio processing).
My secondary EXE is a modeless CPropertySheet, for status and diagnostic display, but is intended to be launched hidden and in the background. However it was always stealing the activation from the main application on launch, regardless of what workarounds I tried (such as overriding OnWindowPosChanging).
I thought I was going to go mad, so I was very happy to find this question. The WH_CBT trick is useful, but I found while it prevented activation of the secondary EXE, it did not prevent deactivation of the main application.
But then I discovered an excellent solution, in the LockSetForegroundWindow API (available since Win2K) which I had never heard of before. Looks like it is intended for exactly this purpose, to disable the change of foreground activation and prevent peer processes from stealing it.
https://msdn.microsoft.com/en-us/library/windows/desktop/ms633532(v=vs.85).aspx
It works very well to nullify the internal call to SetForegroundWindow that happens deep within the property sheet common control, and works equally well whether used in the main application before CreateProcess or in the secondary EXE. I chose the latter case, to wrap the property sheet creation:
LockSetForegroundWindow(LSFW_LOCK);
pSheet->Create(NULL, dwStyle, dwExStyle);
LockSetForegroundWindow(LSFW_UNLOCK);
This minimises the scope of the intervention and keeps the fix localised to the process that is the source of the problem. I hope this will save others from wasting as much time on this tedious issue as I did.
I have an owner drawn listbox (CListBox in MFC) with 100,001 items in it. The listbox is single column with a vertical scrollbar. There is nothing else special about it as far as I can see. The styles are:
LBS_OWNERDRAWFIXED | LBS_NOINTEGRALHEIGHT | LBS_EXTENDEDSEL | LBS_NODATA | WS_VSCROLL | WS_TABSTOP
I have my own data structure behind it and instead of inserting the items one by one, I just perform a pBlistBox->SendMessage(LB_SETCOUNT, 100000, 0) to set the count of items in the listbox.
My issue is that when I scroll down the listbox by grabbing the thumb on the scrollbar, when it gets near 65000+ (can't see if it's exactly 65535, but I expect it is), it then sort of wraps around back to 0. The items that are drawn from WM_DRAWITEM are wrong. When I should be near 70,000, then items are near 4,500 or so. If I drag all the way to the bottom and let go, the thumb bounces back to 34,454 or so. It looks to be some kind of limit. However, if I hit HOME or END keys it does the right thing. If I use the scroll arrows, it also does the right thing. If I click in the page down areas it also does the right thing. The only time it does not do the right thing is when it scrolls via the thumb (SB_THUMBTRACK).
Anyone have any ideas how I can get it to scroll correctly? Obviously it seems to be some kind of 16-bit limit, but GetScrollInfo() shows that it knows to scroll the full amount.
To get full control of the scrol bar you. Need to call GetScrollInfo or GetScrollPos
The behaviour is fully documented in the MSDN here
I would like to use a transparent read-only text box as a replacement for a label; to allow users to select+copy the text. Exactly what Windows Explorer uses on the file properties window:
I've found similar question: Making a TextBox Transparent
Comments there suggest that proposed solutions do not work with ClearType. But my testing of suggested "AlphaBlendTextBox - A transparent/translucent textbox for .NET" component shows otherwise.
Anyway, the code looks quite complex for such a "simple task". They do save parent control image to a bitmap, drawing that bitmap over and over again with the text on top of it. I would expect there there has to be a solution delegating drawing of the background to parent control.
Possibly their solution is that complex because it allows alpha-blending too. I do not need that. I just want to see a parent background behind the text. Is there a simpler/smarter way?
Note that I'm happy with any winapi solution (pure winapi, MFC, WinForms, Delphi, whatever).
According to Spy++, it's a typical Edit control with WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR | WS_EX_NOPARENTNOTIFY as extended style and WS_CHILDWINDOW | WS_VISIBLE | ES_LEFT | ES_AUTOHSCROLL | ES_READONLY as original window style.
I've tested it in Win32 and I can confirm that it does what you want it to do.
Also, next time you want to mimic the appearances of other controls, simply fire up Spy++ to get the detailed information about them.