How to hide the windows 10 taskbar close button using WINAPI? - winapi

I need to find a way to remove this button:
I already tried to put the CS_NOCLOSE flag into the WNDCLASS, but this is not working.
WNDCLASS wc;
wc.style = CS_OWNDC | CS_NOCLOSE;
wc.lpfnWndProc = (WNDPROC)staticWindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
I also have this code inside the callback:
case WM_INITMENU:
EnableMenuItem((HMENU)wParam, SC_CLOSE, MF_BYCOMMAND | MF_DISABLED);
break

I didn't find a way to disable the close button but I have hidden my window from the taskbar as explained here https://msdn.microsoft.com/en-us/library/windows/desktop/cc144179(v=vs.85).aspx#tbnotify_Taskbar_Display_Options (section Managing Taskbar Buttons)) using the WS_EX_TOOLWINDOW flag.
Thx for help

Related

Rich Edit Control paints whole application black after unminimize

SOLVED: I've posted my solution as an answer.
Here's my problem: (gif) (Sort of solved if I reload the bitmaps for painting the background image when unminimizing before any WM_PAINT message.)
It happens whenever I unminimize the application, time when the app first displays OK (for a brief split second unless you are stepping with the debugger), and suddenly turns black (or whatever color has been set as hbrBackground in the app window classes). I can prevent this behaviour by reloading the HBITMAPs used in WM_PAINT, which are global variables and initialised with their corresponding values at app startup.
The gif starts showing the app reopened after a minimize, with the debugger stepping through the parent window of the Rich Edit Control message loop, the moments just before and after the background of all windows turns black, and then stepping into the Rich Edit Control subclass message loop, into WM_PAINT.
This never happens if I'm switching between apps without the app in question never having been minimized before.
This never happens if the Rich Edit Control (RICHEDIT50W) hasn't displayed any text before, ie. the app works OK if no text is ever displayed.
This is the window tree:
Main Window
Some Child Windows
Child Window 1
Rich Edit Control
The stepping goes out of the Child Window 1 WndProc; into the WM_PAINT of the Rich Edit Control inside the WndSubclassProcWhatever callback.
Some of the things I've done before realizing that a call to LoadImage() just after unminimize could fix the background issue:
Intercept the message loop of the Rich Edit Control with a subclass, and handle (as well as in every other window) messages as: WM_COMMAND, WM_IME_NOTIFY, WM_NCPAINT, WM_WINDOWPOSCHANGED, WM_WINDOWPOSCHANGING, WM_ERASEBKGND... Mainly returning something different than the DefSubclassProc/DefWindowProcW.
Calling ValidateRect() as soon as the app is reopened...
It has happened before that instead of the whole app turning black, only the text "highlighting" or the Rich Edit Control parent turned black, with the whole app turning black after another minimize unminimize cycle.
I'm using Visual Studio Community 2019 with default settings in an updated Windows 10, and seeing this problem both in release and debug builds.
I'm now looking forward to prevent the bitmaps from "unloading", thus saving many seemingly unnecessary LoadImage() calls. SOLVED
I tried uploading a minimal version of the code, yet the behaviour turned out not to be exactly the same, so thanks for the answer given before!
This has nothing to do with Rich Edit Control , even if you delete all of the controls, this will happen.
All you have to do is add a default color to the window background when you register the window.
Here:
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_DBLCLKS;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = NULL; // Procesás WM_GETICON
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = NULL;
wcex.lpszMenuName = NULL;
wcex.lpszClassName = L"mainWindowClass";
wcex.hIconSm = NULL; // Procesás WM_GETICON
return RegisterClassExW(&wcex);
}
Click again after minimize the window will cause it to redraw with the default background color, But you set the background color to NULL here. So try to change wcex.hbrBackground = NULL to wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1)
Updated:
It sounds like you have the same problem as I have encountered before.
Here is my previous code:
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code that uses hdc here...
hdcMem = CreateCompatibleDC(hdc);
HGDIOBJ previousbit = SelectObject(hdcMem, hBmp);
AlphaBlend(hdc, 0, 0, width_1, height_1, hdcMem, 0, 0, width_1, height_1, bf);
DeleteDC(hdcMem);
EndPaint(hWnd, &ps);
}
break;
case WM_MOUSEWHEEL:
{
if (GET_WHEEL_DELTA_WPARAM(wParam) > 0 && bTrans <= 234)
{
bTrans += 20;
bf.SourceConstantAlpha = bTrans;
InvalidateRect(hWnd, NULL, TRUE);
}
if (GET_WHEEL_DELTA_WPARAM(wParam) < 0 && bTrans >= 20)
{
bTrans -= 20;
bf.SourceConstantAlpha = bTrans;
InvalidateRect(hWnd, NULL, TRUE);
}
return 0;
}
I slide the mouse wheel, it will trigger the InvalidateRect(hWnd, NULL, TRUE);
But if I delete DeleteDC(hdcMem), it will return a main window without a picture.
The debug snapshot is :
Yes, you can find previousbit == NULL.
As #Remy Lebeau said that, you are leaking the HBITMAP that SelectObject() returns, and giving the HDC permission to potentially destroy your bitmapBackgroundMainWindow behind your back.
This is the main cause.
A call to DeleteObject() fixed the issue.
This is the code from one of the bitmap-background window WM_PAINT messages fixed with the corresponding DeleteObject() call:
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
HDC temporaryDC = CreateCompatibleDC(hdc);
BITMAP bitmapToBitBlt;
HGDIOBJ hgdiobjToBitBlt = SelectObject(temporaryDC, bitmapBackgroundMainWindow);
GetObjectW(bitmapBackgroundMainWindow, sizeof(BITMAP), &bitmapToBitBlt);
BitBlt(hdc, 0, 0, bitmapToBitBlt.bmWidth, bitmapToBitBlt.bmHeight, temporaryDC, 0, 0, SRCCOPY);
DeleteObject(temporaryDC); // This fixes the app.
EndPaint(hWnd, &ps);
return 0;
As Windows Docs state, after calling CreateCompatibleDC():
When you no longer need the memory DC, call the DeleteDC function. We recommend that you call DeleteDC to delete the DC. However, you can also call DeleteObject with the HDC to delete the DC.
How does this translate to my app unexpected behaviour, I don't know, feel free to clarify in the comments!

How to prevent moving of a window without titlebar but with WS_SYSMENU style?

I want to prevent moving of a window which I created before using CreateWindowEx.
HWND hWnd = CreateWindowEx(0, wc.lpszClassName, "Title", WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_OVERLAPPEDWINDOW, 0, 0, rect.right - rect.left, rect.bottom - rect.top, nullptr, nullptr, nullptr, nullptr);
The most common solution suggested for this is changing the windows style to have no titlebar i.e.
SetWindowLongPtr(hWnd, GWL_STYLE, GetWindowLongPtr(hWnd, GWL_STYLE) & ~(WS_CAPTION | WS_THICKFRAME));
While this solves the problem for drag- & drop at the titlebar, the window is still movable from the control menu (if the window is active press ALT, LEFT, DOWN and select "Move"). I tried using EnableMenuItem(GetSystemMenu(hWnd, FALSE), SC_MOVE, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); because this is how the disabling for the Close entry works (using SC_CLOSE instead of SC_MOVE), but it did not disable the Move option.
Is there any way using win32 api to disable only the "Move" option from the context menu without removing the WS_SYSMENU style completly?
The clue to disabling the SC_MOVE item is in the description of the GetSystemMenu function:
The system automatically grays items on the standard window menu, depending on the situation. The application can perform its own checking or graying by responding to the WM_INITMENU message that is sent before any menu is displayed.
So even though you're disabling the menu item initially, the system is re-enabling it when the menu is displayed. To fix it, you need to handle WM_INITMENU or WM_INITMENUPOPUP yourself and override the system's behaviour. For example,
in your window procedure:
case WM_INITMENUPOPUP:
if (wParam == reinterpret_cast<WPARAM>(GetSystemMenu(hWnd, FALSE)))
{
// override handling of the system menu
EnableMenuItem(reinterpret_cast<HMENU>(wParam), SC_MOVE, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
return 0;
}
// if WM_INITMENUPOPUP isn't for the system menu, fall through to
// default processing
return DefWindowProc(hWnd, uMsg, wParam, lParam);

Why is my capture window code not working?

I am newbie to winapi. I have seen an example to capture desktop excluding some windows at codeproject
There a child window is created and it is captured.
hwndMag = CreateWindow(WC_MAGNIFIER, TEXT("MagnifierWindow"),
WS_CHILD | MS_SHOWMAGNIFIEDCURSOR | WS_VISIBLE,
0, 0, m_ScreenX, m_ScreenY,
hostDlg->GetSafeHwnd(), NULL, hInstance, NULL );
Instead of creating a child window, I want to create a parent window.
I have tried with this code.
hwndMag = CreateWindow(WC_MAGNIFIER, TEXT("MagnifierWindow"),
MS_SHOWMAGNIFIEDCURSOR | WS_VISIBLE,
0, 0, m_ScreenX, m_ScreenY,
NULL , NULL, hInstance, NULL );
A new window is visible with black screen. And even when I click the capture button the window is stucked.
Why is this happening and How can I make that work with a new parent window?
Thanks
The magnifier window should be a child window. It therefore needs a host parent window. The example code on MSDN shows how to do it:
BOOL CreateMagnifier(HINSTANCE hInstance)
{
// Register the host window class.
WNDCLASSEX wcex = {};
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = 0;
wcex.lpfnWndProc = HostWndProc;
wcex.hInstance = hInstance;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(1 + COLOR_BTNFACE);
wcex.lpszClassName = WindowClassName;
if (RegisterClassEx(&wcex) == 0)
return FALSE;
// Create the host window.
hwndHost = CreateWindowEx(WS_EX_TOPMOST | WS_EX_LAYERED | WS_EX_TRANSPARENT,
WindowClassName, WindowTitle,
WS_CLIPCHILDREN,
0, 0, 0, 0,
NULL, NULL, hInstance, NULL);
if (!hwndHost)
{
return FALSE;
}
// Make the window opaque.
SetLayeredWindowAttributes(hwndHost, 0, 255, LWA_ALPHA);
// Create a magnifier control that fills the client area.
hwndMag = CreateWindow(WC_MAGNIFIER, TEXT("MagnifierWindow"),
WS_CHILD | MS_SHOWMAGNIFIEDCURSOR | WS_VISIBLE,
0, 0,
LENS_WIDTH,
LENS_HEIGHT,
hwndHost, NULL, hInstance, NULL );
if (!hwndMag)
{
return FALSE;
}
return TRUE;
}
This same documentation also says:
The magnifier control must be hosted in a window created with the WS_EX_LAYERED extended style. After creating the host window, call SetLayeredWindowAttributes to set the opacity of the host window. The host window is typically set to full opacity to prevent the underlying screen content from showing though. The following example shows how to set the host window to full opacity:
SetLayeredWindowAttributes(hwndHost, NULL, 255, LWA_ALPHA);
If you apply the WS_EX_TRANSPARENT style to the host window, mouse clicks are passed to whatever object is behind the host window at the location of the mouse cursor. Be aware that, because the host window does not process mouse clicks, the user will not be able to move or resize the magnification window by using the mouse.
The MSDN example above illustrates this. And the CodeProject article that you link to also adheres to these rules. You must do likewise.
in case it's of interest, I created a sample app which uses the magnification API a while back called "Windows 7 UI Automation Client API C# sample (focus tracking)", available at https://code.msdn.microsoft.com/Windows-7-UI-Automation-6390614a. The app tracks where keyboard focus is, and then shows the element with focus in a magnification window, (and inverts the colors using the magnification API). This is a C# app, so it uses interop to access the magnification API.
A screenshot of the results is shown below.
Thanks,
Guy

How to display bitmap image in background Win32

I am having a hard time finding out how to load my .bmp image into the background.
Here is my code:
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = CreatePatternBrush(LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP1)));
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
Though the problem is not entirely code related. I simply have a file x.bmp, and I have the IDB_BITMAP1 defined in my resource.rc file and included with an identifier in resource.h -- but when I run it I just get a white screen. The question here is, how can I upload my .bmp image to the .rc file? I am using MSVS20124. When I right click the .rc file add>bitmap>import...>x.bmp I get an error "could not load file". Why is this? I just want to set that x.bmp as the background in my window.
thanks
You are not performing any error checking in the call to LoadBitmap and the call to CreatePatternBrush. Very likely one of these calls fails and so hbrBackground is set to NULL, which results in a white background.
Your next step is to do some debugging to work out which call fails. Quite likely is that the bitmap file that you are linking as a resource uses a format that is not supported by LoadBitmap. Or perhaps the bitmap file is somehow not being linked. But so long as you actually manage to create a bitmap and then a brush, the system will use that brush to paint the background.

Win32: full-screen and hiding taskbar

I have a window, which I SetWindowPos(window, HWND_TOP, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), SWP_FRAMECHANGED);
It covers the whole screen, ok, but it takes a while (0.5 sec) to cover the taskbar as well.
Is there a way to come over the taskbar immediately? I found that setting HWND_TOPMOST does it immediately, but it stays above all the other windows, even if I switch the app - this is something I don't want. Also, if I first hide the window and then show it, it somehow forces the window to redraw and covers the taskbar immediately, but it flickers (because of the hiding). Is there another way?
Edit 2. There is even a better way for doing fullscreen, the chromium way, source taken from here:
http://src.chromium.org/viewvc/chrome/trunk/src/ui/views/win/fullscreen_handler.cc?revision=HEAD&view=markup
void FullscreenHandler::SetFullscreenImpl(bool fullscreen, bool for_metro) {
ScopedFullscreenVisibility visibility(hwnd_);
// Save current window state if not already fullscreen.
if (!fullscreen_) {
// Save current window information. We force the window into restored mode
// before going fullscreen because Windows doesn't seem to hide the
// taskbar if the window is in the maximized state.
saved_window_info_.maximized = !!::IsZoomed(hwnd_);
if (saved_window_info_.maximized)
::SendMessage(hwnd_, WM_SYSCOMMAND, SC_RESTORE, 0);
saved_window_info_.style = GetWindowLong(hwnd_, GWL_STYLE);
saved_window_info_.ex_style = GetWindowLong(hwnd_, GWL_EXSTYLE);
GetWindowRect(hwnd_, &saved_window_info_.window_rect);
}
fullscreen_ = fullscreen;
if (fullscreen_) {
// Set new window style and size.
SetWindowLong(hwnd_, GWL_STYLE,
saved_window_info_.style & ~(WS_CAPTION | WS_THICKFRAME));
SetWindowLong(hwnd_, GWL_EXSTYLE,
saved_window_info_.ex_style & ~(WS_EX_DLGMODALFRAME |
WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE));
// On expand, if we're given a window_rect, grow to it, otherwise do
// not resize.
if (!for_metro) {
MONITORINFO monitor_info;
monitor_info.cbSize = sizeof(monitor_info);
GetMonitorInfo(MonitorFromWindow(hwnd_, MONITOR_DEFAULTTONEAREST),
&monitor_info);
gfx::Rect window_rect(monitor_info.rcMonitor);
SetWindowPos(hwnd_, NULL, window_rect.x(), window_rect.y(),
window_rect.width(), window_rect.height(),
SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
}
} else {
// Reset original window style and size. The multiple window size/moves
// here are ugly, but if SetWindowPos() doesn't redraw, the taskbar won't be
// repainted. Better-looking methods welcome.
SetWindowLong(hwnd_, GWL_STYLE, saved_window_info_.style);
SetWindowLong(hwnd_, GWL_EXSTYLE, saved_window_info_.ex_style);
if (!for_metro) {
// On restore, resize to the previous saved rect size.
gfx::Rect new_rect(saved_window_info_.window_rect);
SetWindowPos(hwnd_, NULL, new_rect.x(), new_rect.y(),
new_rect.width(), new_rect.height(),
SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
}
if (saved_window_info_.maximized)
::SendMessage(hwnd_, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
}
}
Edit.
It is probably better to create a fullscreen window as BrendanMcK pointed it out in a comment to this answer, see this link: http://blogs.msdn.com/b/oldnewthing/archive/2005/05/05/414910.aspx ("How do I cover the taskbar with a fullscreen window?")
The new code using the link above would be:
HWND CreateFullscreenWindow(HWND hwnd)
{
HMONITOR hmon = MonitorFromWindow(hwnd,
MONITOR_DEFAULTTONEAREST);
MONITORINFO mi = { sizeof(mi) };
if (!GetMonitorInfo(hmon, &mi)) return NULL;
return CreateWindow(TEXT("static"),
TEXT("something interesting might go here"),
WS_POPUP | WS_VISIBLE,
mi.rcMonitor.left,
mi.rcMonitor.top,
mi.rcMonitor.right - mi.rcMonitor.left,
mi.rcMonitor.bottom - mi.rcMonitor.top,
hwnd, NULL, g_hinst, 0);
}
Old answer below - do not use it, stays only for the record on how NOT to do this.
You have to hide taskbar and menubar to see fullscreen immediately.
Here is the code (uses WTL), call SetFullScreen(true) to go into full screen mode:
template <class T, bool t_bHasSip = true>
class CFullScreenFrame
{
public:
bool m_fullscreen;
LONG m_windowstyles;
WINDOWPLACEMENT m_windowplacement;
CFullScreenFrame()
:
m_fullscreen(false),
m_windowstyles(0)
{ }
void SetFullScreen(bool fullscreen)
{
ShowTaskBar(!fullscreen);
T* pT = static_cast<T*>(this);
if (fullscreen) {
if (!m_fullscreen) {
m_windowstyles = pT->GetWindowLongW(GWL_STYLE);
pT->GetWindowPlacement(&m_windowplacement);
}
}
// SM_CXSCREEN gives primary monitor, for multiple monitors use SM_CXVIRTUALSCREEN.
RECT fullrect = { 0 };
SetRect(&fullrect, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
WINDOWPLACEMENT newplacement = m_windowplacement;
newplacement.showCmd = SW_SHOWNORMAL;
newplacement.rcNormalPosition = fullrect;
if (fullscreen) {
pT->SetWindowPlacement(&newplacement);
pT->SetWindowLongW(GWL_STYLE, WS_VISIBLE);
pT->UpdateWindow();
} else {
if (m_fullscreen) {
pT->SetWindowPlacement(&m_windowplacement);
pT->SetWindowLongW(GWL_STYLE, m_windowstyles);
pT->UpdateWindow();
}
}
m_fullscreen = fullscreen;
}
void ShowTaskBar(bool show)
{
HWND taskbar = FindWindow(_T("Shell_TrayWnd"), NULL);
HWND start = FindWindow(_T("Button"), NULL);
if (taskbar != NULL) {
ShowWindow(taskbar, show ? SW_SHOW : SW_HIDE);
UpdateWindow(taskbar);
}
if (start != NULL) {
// Vista
ShowWindow(start, show ? SW_SHOW : SW_HIDE);
UpdateWindow(start);
}
}
};
You also have to add some code to WM_CLOSE message:
case WM_CLOSE:
ShowTaskBar(true);
There is one caveat with this solution, if your application crashes or is killed through task manager, then user losses taskbar on his system permanently! (unless he runs your application again, goes into fullscreen and exits, then he will see the taskbar again).
Earlier in my answer I pointed to "atlwince.h" but that function worked only on Windows CE, the one I pasted above works fine with XP, Vista and 7.
Yup, HWND_TOPMOST does it for me.
Here is a section of code that makes full-screen work well (and quick) for me:
bool enterFullscreen(HWND hwnd, int fullscreenWidth, int fullscreenHeight, int colourBits, int refreshRate) {
DEVMODE fullscreenSettings;
bool isChangeSuccessful;
RECT windowBoundary;
EnumDisplaySettings(NULL, 0, &fullscreenSettings);
fullscreenSettings.dmPelsWidth = fullscreenWidth;
fullscreenSettings.dmPelsHeight = fullscreenHeight;
fullscreenSettings.dmBitsPerPel = colourBits;
fullscreenSettings.dmDisplayFrequency = refreshRate;
fullscreenSettings.dmFields = DM_PELSWIDTH |
DM_PELSHEIGHT |
DM_BITSPERPEL |
DM_DISPLAYFREQUENCY;
SetWindowLongPtr(hwnd, GWL_EXSTYLE, WS_EX_APPWINDOW | WS_EX_TOPMOST);
SetWindowLongPtr(hwnd, GWL_STYLE, WS_POPUP | WS_VISIBLE);
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, fullscreenWidth, fullscreenHeight, SWP_SHOWWINDOW);
isChangeSuccessful = ChangeDisplaySettings(&fullscreenSettings, CDS_FULLSCREEN) == DISP_CHANGE_SUCCESSFUL;
ShowWindow(hwnd, SW_MAXIMIZE);
return isChangeSuccessful;
}
Note that this will change the resolution if you tell it the wrong settings. This is what I usually want, but if you don't like that, you can find out your resolution by using (where mainWindow is returned from something like CreateWindow() or CreateWindowEx()):
windowHDC = GetDC(mainWindow);
fullscreenWidth = GetDeviceCaps(windowHDC, DESKTOPHORZRES);
fullscreenHeight = GetDeviceCaps(windowHDC, DESKTOPVERTRES);
colourBits = GetDeviceCaps(windowHDC, BITSPIXEL);
refreshRate = GetDeviceCaps(windowHDC, VREFRESH);
When you want to get out of full-screen you do something like this:
bool exitFullscreen(HWND hwnd, int windowX, int windowY, int windowedWidth, int windowedHeight, int windowedPaddingX, int windowedPaddingY) {
bool isChangeSuccessful;
SetWindowLongPtr(hwnd, GWL_EXSTYLE, WS_EX_LEFT);
SetWindowLongPtr(hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_VISIBLE);
isChangeSuccessful = ChangeDisplaySettings(NULL, CDS_RESET) == DISP_CHANGE_SUCCESSFUL;
SetWindowPos(hwnd, HWND_NOTOPMOST, windowX, windowY, windowedWidth + windowedPaddingX, windowedHeight + windowedPaddingY, SWP_SHOWWINDOW);
ShowWindow(hwnd, SW_RESTORE);
return isChangeSuccessful;
}
I set my code to change between full-screen and windowed mode using a hotkey, and I keep the windowed mode variables as global, so that when changing to windowed mode, it stays put.
This code also has the advantage of running in the equivalent of "exclusive mode" (I'm using XP, and haven't tried it on the newer versions of windows), which means it'll be much, much faster. Let me know if I've made any mistakes from condensing the code (from my much bigger code).
Raymond Chen describes the "correct" way to do this at his blog:
https://devblogs.microsoft.com/oldnewthing/20100412-00/?p=14353
Fiddling with the task bar window explicitly is not recommended behaviour.
Here's the latest unbroken link to Raymond Chen answer.
Since MSDN/Microsoft keeps breaking links I'll paste below for posterity:
For some reason, people think too hard. If you want to create a fullscreen window that covers the taskbar, just create a fullscreen window and the taskbar will automatically get out of the way. Don't go around hunting for the taskbar and poking it; let it do its thing.
As always, start with the scratch program and add the following:
HWND CreateFullscreenWindow(HWND hwnd)
{
HMONITOR hmon = MonitorFromWindow(hwnd,
MONITOR_DEFAULTTONEAREST);
MONITORINFO mi = { sizeof(mi) };
if (!GetMonitorInfo(hmon, &mi)) return NULL;
return CreateWindow(TEXT("static"),
TEXT("something interesting might go here"),
WS_POPUP | WS_VISIBLE,
mi.rcMonitor.left,
mi.rcMonitor.top,
mi.rcMonitor.right - mi.rcMonitor.left,
mi.rcMonitor.bottom - mi.rcMonitor.top,
hwnd, NULL, g_hinst, 0);
}
void OnChar(HWND hwnd, TCHAR ch, int cRepeat)
{
if (ch == TEXT(' ')) {
CreateFullscreenWindow(hwnd);
}
}
HANDLE_MSG(hwnd, WM_CHAR, OnChar);
Note that this sample program doesn't worry about destroying that fullscreen window or preventing the user from creating more than one. It's just a sample. The point is seeing how the CreateFullScreenWindow function is written.
We use the MonitorFromWindow function to figure out which monitor we should go fullscreen to. Note that in a multiple monitor system, this might not be the same monitor that the taskbar is on. Fortunately, we don't have to worry about that; the taskbar figures it out.
I've seen people hunt for the taskbar window and then do a ShowWindow(hwndTaskbar, SW_HIDE) on it. This is nuts for many reasons.
First is a mental exercise you should always use when evaluating tricks like this: "What if two programs tried this trick?" Now you have two programs both of which think they are in charge of hiding and showing the taskbar, neither of which is coordinating with the other. The result is a mess. One program hides the taskbar, then the other does, then the first decides it's finished so it unhides the taskbar, but the second program wasn't finished yet and gets a visible taskbar when it thought it should be hidden. Things only go downhill from there.
Second, what if your program crashes before it gets a chance to unhide the taskbar? The taskbar is now permanently hidden and the user has to log off and back on to get their taskbar back. That's not very nice.
Third, what if there is no taskbar at all? It is common in Terminal Server scenarios to run programs by themselves without Explorer (archived). In this configuration, there is no Explorer, no taskbar. Or maybe you're running on a future version of Windows that doesn't have a taskbar, it having been replaced by some other mechanism. What will your program do now?
Don't do any of this messing with the taskbar. Just create your fullscreen window and let the taskbar do its thing automatically.
I believe the taskbar will get out of the way when its shell hook tells it about a "rude app", this might take a little while.
What if you start out with the window HWND_TOPMOST and make it not top most after 1 second?
Right click on the taskbar
choose Properties
uncheck the checkbox that says "Keep the taskbar on top of other windows".
The taskbar belongs to the user, It's up to them to care about having it take 1/2 second to auto-hide when you app goes full screen. If they want to change that behavior then they can change it.
If you are working in an embedded system, then you may have a legitimate reason to hide the taskbar. But in that case, there's no reason not to simply configure the taskbar to not always be on top. You could also have a look at SystemParametersInfo if you want to change some of these settings in your code.

Resources