SetLayeredWindowAttributes not working on Windows 8+ (C++) - c++

I'm writing a library that makes a color in the window client area invisible.
In the application half, first I call window_fix_transparent_color() to make the window layered. Then I use window_set_transparent_color() to make a color in the client area invisible.
Here's my library's code:
#define _WIN32_WINNT 0x0501
#include <windows.h>
extern "C"
{
void window_fix_transparent_color(double window_handle)
{
// sets the window flags to support RGB color transparency.
SetWindowLong((HWND)(DWORD)window_handle,GWL_EXSTYLE,
GetWindowLong((HWND)(DWORD)window_handle,GWL_EXSTYLE)|WS_EX_LAYERED);
}
void window_set_transparent_color(double window_handle,double red,double green,double blue)
{
// sets the RGB color to be transparent for the specified window.
SetLayeredWindowAttributes((HWND)(DWORD)window_handle,RGB(red,green,blue),255,LWA_COLORKEY);
}
}
I'm using the version of MinGW that is packaged with the latest Code::Blocks as my compiler. It works on Windows 7, but not on Windows 8, 8.1, or 10...
Any ideas as to why that is? Also, a weird thing worth noting - it used to work on Windows 8/8.1/10, which leads me to believe a certain Windows update for those platforms may have broken my code. I haven't made any changes to my code since the time it stopped working on platforms past Windows 7.
Thanks!

Why are you using strange types and casts? You should never cast a handle type to DWORD, use INT_PTR or UINT_PTR if you must. A double is actually larger than a HWND in 32-bit applications so you are actually wasting space in addition to making things harder for yourself. A double cannot be used to store a handle in a 64-bit application!
You are also not checking the return value of SetLayeredWindowAttributes so it is impossible to know what the problem really is.
Rewrite the function with correct types and error handling:
void display_error(DWORD error)
{
char buf[100];
wsprintfA(buf, "Error %u!", error);
MessageBoxA(NULL, buf, 0, 0); // Ideally you would pass a window handle here but I don't know if your handle is actually valid
}
void window_fix_transparent_color(HWND window_handle)
{
DWORD error;
// get the window flags to see if RGB color transparency is supported.
SetLastError(0);
LONG_PTR ExStyle = GetWindowLongPtr(window_handle, GWL_EXSTYLE);
if (ExStyle == 0)
{
error = GetLastError();
if (error != 0)
{
display_error(error);
return;
}
}
if ((ExStyle & WS_EX_LAYERED) == 0)
{
// set the window flags to support RGB color transparency.
SetLastError(0);
if (!SetWindowLongPtr(window_handle, GWL_EXSTYLE, ExStyle | WS_EX_LAYERED))
{
error = GetLastError();
if (error != 0)
display_error(error);
}
}
}
void window_set_transparent_color(HWND window_handle, BYTE red, BYTE green, BYTE blue)
{
// sets the RGB color to be transparent for the specified window.
if (!SetLayeredWindowAttributes(window_handle, RGB(red, green, blue), 255, LWA_COLORKEY))
{
display_error(GetLastError());
}
}
...
HWND mywindow = CreateWindowEx(...);
window_fix_transparent_color(mywindow);
window_set_transparent_color(mywindow, ...);

My guess is that you're using "basic" or "classic" theme on Windows 7. Although
undocumented, it activates Windows XP compatibility mode for the Desktop Window
Manager, and changes the way layered windows work. That doesn't happen in later
versions of Windows.

Related

Identify only application windows from EnumDesktopWindows

This is my very first C++ application. I have absolutely no experience in C++ or Windows application programming so any feedback/help is appreciated. Please let me know if I am making any mistakes or not following best practices in my code.
I am trying to write a C++ program that replicates the behaviour of the WIN + D
keyboard shortcut, but only affects the windows on the monitor with the mouse.
Inspite of checking IsWindowVisible() and IsIconic() there are some system windows that get minimized and maximized, resulting in weird glitches like:
All icons from the desktop get minimized, and a gray bar appears
A blank instance of Microsoft Edge opens
The Windows Settings app appears out of nowhere
The code to minimize the windows:
static std::stack<HWND> minimizedWindowPointers;
Monitors monitors;
RECT activeMonitorRect;
static BOOL CALLBACK windowEnumerator(HWND w, LPARAM l){
if(!IsWindowVisible(w) || IsIconic(w) || getWindowTitle(w).size() == 0) return true;
RECT r;
GetWindowRect(w, &r);
if(doRectsIntersect(r, activeMonitorRect)){
SendMessage(w, WM_SYSCOMMAND, SC_MINIMIZE, 0);
minimizedWindowPointers.push(w);
}
return true;
}
void minimizeWindowsOnActiveMoniter(){
if(monitors.getRectOfMonitorWithPointer(&activeMonitorRect)) return;
EnumDesktopWindows(NULL, windowEnumerator, NULL);
areWindowsMinimized = true;
}
void maximizeWindowsOnActiveMoniter(){
HWND w;
for(int i = minimizedWindowPointers.size(); i > 0; i--){
w = minimizedWindowPointers.top();
minimizedWindowPointers.pop();
if(IsIconic(w)){
SendMessage(w, WM_SYSCOMMAND, SC_RESTORE, 0);
std::wcout << "MAXIMIZING: " << getWindowTitle(w) << std::endl;
}
}
areWindowsMinimized = false;
}
I am running Windows 10 Pro, with Visual Studio 19 Preview.
GetWindowLong can get the window flags with GWL_STYLE. Check for WS_CAPTION and WS_MINIMIZEBOX. I would also check for WS_VISIBLE again for good measure.

Get details about all running applications C++ [duplicate]

In VC++, I use EnumWindows(...), GetWindow(...), and GetWindowLong(), to get the list of windows and check whether the window is top window (no other window as owner), and whether the window is visible (WS_VISIBLE). However, although my desktop is showing only 5 windows, this EnumWindows is giving me 50 windows, how funny! Any Windows geek here please help me clarify...
The way to list out only windows in taskbar (or similarly in Alt-Tab box) is described by Raymond in this article on MSDN blog:
Which windows appear in the Alt+Tab list?
And this is the super function to check whether a window is shown in alt-tab:
BOOL IsAltTabWindow(HWND hwnd)
{
TITLEBARINFO ti;
HWND hwndTry, hwndWalk = NULL;
if(!IsWindowVisible(hwnd))
return FALSE;
hwndTry = GetAncestor(hwnd, GA_ROOTOWNER);
while(hwndTry != hwndWalk)
{
hwndWalk = hwndTry;
hwndTry = GetLastActivePopup(hwndWalk);
if(IsWindowVisible(hwndTry))
break;
}
if(hwndWalk != hwnd)
return FALSE;
// the following removes some task tray programs and "Program Manager"
ti.cbSize = sizeof(ti);
GetTitleBarInfo(hwnd, &ti);
if(ti.rgstate[0] & STATE_SYSTEM_INVISIBLE)
return FALSE;
// Tool windows should not be displayed either, these do not appear in the
// task bar.
if(GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_TOOLWINDOW)
return FALSE;
return TRUE;
}
Credited to the source code here:
http://www.dfcd.net/projects/switcher/switcher.c
The windows that you are talking about, with an X button and a title bar, etc. are not the only kind of windows. Buttons, dropdown menus, labels, icons, text boxes, the task bar, and just about everything else is a window too1. So EnumWindows is doing exactly what it's supposed to do: enumerate all the top level windows.
1 Even though this is true, EnumWindows only enumerates the top level windows. That means it won't enumerate any child windows:
The EnumWindows function does not enumerate child windows, with the exception of a few top-level windows owned by the system that have the WS_CHILD style.
However, many things on your desktop are windows as well, not just the "windows" you're thinking about.
The answer provided by #jondinham does work perfectly for me. So I work out my own solution.
1.Problems I met with previous solution
Running on Windows 10 home edition 1909., I get two extra unexpected Windows "Calculator" and "Setting".
In addition, windows of Tencent QQ can not be detected, because the following fails:
// the following removes some task tray programs and "Program Manager"
ti.cbSize = sizeof(ti);
GetTitleBarInfo(hwnd, &ti);
if(ti.rgstate[0] & STATE_SYSTEM_INVISIBLE)
return FALSE;
However, I think the bug may be resulted by the particularity of Tencent QQ, I can not even make its' window TOPMOST with DeferWindowPos.
Perhaps someone can help me figure out why this happened and help improving the previous solution by #jondinham.
2.My Solution
I tried to examing the icons of the windows, and filter out windows that does not have its own icon or uses the icon same as the system default. I use code snippets from answer and answer and do some modification. This solution works very well for me.
HICON get_windows_HICON_critical(HWND hwnd)
{
// Get the window icon
HICON icon = reinterpret_cast<HICON>(::SendMessageW(hwnd, WM_GETICON, ICON_SMALL, 0));
if (icon == 0) {
// Alternative method. Get from the window class
icon = reinterpret_cast<HICON>(::GetClassLongPtrW(hwnd, GCLP_HICONSM));
}
// Alternative method: get the first icon from the main module (executable image of the process)
if (icon == 0) {
icon = ::LoadIcon(GetModuleHandleW(0), MAKEINTRESOURCE(0));
}
// // Alternative method. Use OS default icon
// if (icon == 0) {
// icon = ::LoadIcon(0, IDI_APPLICATION);
// }
if(icon == ::LoadIcon(0, IDI_APPLICATION)){
// Filter out those with default icons
icon = 0;
}
return icon;
}
static BOOL CALLBACK enumWindowCallback(HWND hWnd, LPARAM lparam) {
int length = GetWindowTextLength(hWnd);
char* buffer = new char[length + 1];
GetWindowText(hWnd, buffer, length + 1);
std::string windowTitle(buffer);
// List visible windows with a non-empty title
if (IsWindowVisible(hWnd) && length != 0) {
HICON icon = get_windows_HICON_critical(hWnd);
if(icon!=0){
std::cout << hWnd << ": " << windowTitle << std::endl;
}
}
return TRUE;
}
3.Problems with my solution
My solution can not deal with Windows Store APP, according to this question.
For all people looking to find a way to remove Invisible windows like Settings or Microsoft Store from the list:
These windows are cloaked, meaning they still have the dwStyle WS_VISIBLE, but the user can't see them.
You can detect this using the function DwmGetWindowAttribute. The dwAttribute you want to get is DWMWA_CLOAKED (enum constant 14). Only if the value in pvAttribute after the method call is 0, the window is not cloacked.

SDL2 toggle SDL_WINDOW_RESIZABLE state for fake fullscreen

To do a "fake" fullscreen window in SDL2 without a modeset you can create a borderless, maximized window using something like this.
int idx = SDL_GetWindowDisplayIndex(g_displayWindow);
SDL_Rect bounds;
SDL_GetDisplayBounds(idx, &bounds);
//SDL_SetWindowResizable(g_displayWindow, SDL_FALSE);
SDL_SetWindowBordered(g_displayWindow, SDL_FALSE);
SDL_SetWindowPosition(g_displayWindow, bounds.x, bounds.y);
SDL_SetWindowSize(g_displayWindow, bounds.w, bounds.h);
For non-resizable windows, this works perfectly. On windows created with SDL_WINDOW_RESIZABLE there is an annoying grey border on the bottom and right edges of the screen (on windows). Unfortunately there isn't a SDL_SetWindowResizable function (as of SDL 2.0.4). How can we get rid of the resizing border without recreating the window?
SDL_WINDOW_FULLSCREEN_DESKTOP and SDL_WINDOW_FULLSCREEN both do a modeset which I want to avoid - it takes longer, it's harder to alt-tab out of, and if the game hits a breakpoint in the debugger it can lock up the whole system.
This is what I came up with - tested and works on windows.
void SDL_SetWindowResizable(SDL_Window *win, SDL_bool resizable)
{
SDL_SysWMinfo info;
SDL_VERSION(&info.version);
SDL_GetWindowWMInfo(g_displayWindow, &info);
#if WIN32
HWND hwnd = info.info.win.window;
DWORD style = GetWindowLong(hwnd, GWL_STYLE);
if (resizable)
style |= WS_THICKFRAME;
else
style &= ~WS_THICKFRAME;
SetWindowLong(hwnd, GWL_STYLE, style);
#endif
}
The SDL_SetWindowResizable() function was added in SDL 2.0.5 which was released in Oct 2016. Announcing SDL 2.0.5
Assuming your SDL_Window pointer (that you got from SDL_CreateWindow()) is named window, use:
/* To disable resizing: */
SDL_SetWindowResizable(window, SDL_FALSE);
/* To enable resizing: */
SDL_SetWindowResizable(window, SDL_TRUE);

Dialog using runtime-created template doesn't work on XP 32 bit

I have written a runtime-created dialog class that doesn't use any resource files based on this example: http://blogs.msdn.com/b/oldnewthing/archive/2005/04/29/412577.aspx
It is compiled on a Windows 7 x64 machine, but as an x86 application. The dialog is part of a larger program that at other places use normal dialogs with resource files (MFC).
The dialog is launched by DialogBoxIndirectParam like this:
DialogBoxIndirectParam(NULL, m_template.GetTemplate(), NULL, DlgProc, reinterpret_cast<LPARAM>(this));
The dialog shows fine on all Windows 7 x64 machines I have tried, but it doesn't work on Windows XP x86 machines. I don't know if it's the Windows version or the CPU bit part that is the culprit.
Some interesting but strange things:
Dialogs in the same program using normal resources work fine in both Win 7 and Win XP.
When comparing the runtime-created dialog template byte by byte I can see no difference from the resource-constructed dialogs.
As long as I don't add any controls what so ever to the dialog, it WILL display in XP, but if I add as much as a single static it won't.
I have monitored the callback function and when it starts it sends WM_SETFONT, WM_DESTROY, WM_NCDESTROY and then dies. It's like it gives up somewhere between WM_SETFONT and WM_CREATE.
I have found others with similar problems but none exactly like mine: http://social.msdn.microsoft.com/Forums/zh/vcgeneral/thread/45989a10-2785-486d-94ae-4f1f3e1ca651, http://cboard.cprogramming.com/windows-programming/39218-createdialog-failure.html
I must say that I'm at my wits end about this, I'm just not good enough at win32 programming to figure out exactly what could be wrong here.
Here is what the template code looks like:
DialogTemplate::DialogTemplate(const std::wstring& title, WORD width, WORD height) :
m_numControls(0)
{
AddHeader(title, width, height);
AddFont();
}
DialogTemplate::~DialogTemplate(void)
{
}
void DialogTemplate::AddHeader(const std::wstring& title, WORD width, WORD height)
{
// Write out the extended dialog template header
m_data.Write<WORD>(1); // dialog version
m_data.Write<WORD>(0xFFFF); // extended dialog template
m_data.Write<DWORD>(0); // help ID
m_data.Write<DWORD>(0); // extended style
m_data.Write<DWORD>(WS_CAPTION | WS_SYSMENU | DS_SETFONT | DS_MODALFRAME);
m_data.Write<WORD>(0); // number of controls (placeholder)
m_data.Write<WORD>(32); // X
m_data.Write<WORD>(32); // Y
m_data.Write<WORD>(width); // width
m_data.Write<WORD>(height); // height
m_data.WriteString(L""); // no menu
m_data.WriteString(L""); // default dialog class
m_data.WriteString(title.c_str()); // title
}
bool DialogTemplate::AddFont()
{
// Write out font
HDC hdc = GetDC(NULL);
if (!hdc)
return false;
NONCLIENTMETRICSW ncm = { sizeof(ncm) };
if (!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0))
return false;
if (ncm.lfMessageFont.lfHeight < 0)
ncm.lfMessageFont.lfHeight = -MulDiv(ncm.lfMessageFont.lfHeight, 72, GetDeviceCaps(hdc, LOGPIXELSY));
m_data.Write<WORD>((WORD)ncm.lfMessageFont.lfHeight); // point
m_data.Write<WORD>((WORD)ncm.lfMessageFont.lfWeight); // weight
m_data.Write<BYTE>(ncm.lfMessageFont.lfItalic); // Italic
m_data.Write<BYTE>(ncm.lfMessageFont.lfCharSet); // CharSet
m_data.WriteString(ncm.lfMessageFont.lfFaceName);
return true;
}
void DialogTemplate::AddControl(LPCWSTR pszType, WORD x, WORD y, WORD width, WORD height, const std::wstring& text, DWORD controlId, DWORD style)
{
m_data.AlignToDword();
m_data.Write<DWORD>(0); // help id
m_data.Write<DWORD>(0); // window extended style
m_data.Write<DWORD>(WS_CHILD | style); // style
m_data.Write<WORD>(x); // x
m_data.Write<WORD>(y); // y
m_data.Write<WORD>(width); // width
m_data.Write<WORD>(height); // height
m_data.Write<DWORD>(controlId); // control ID
m_data.WriteString(pszType); // control type (as string)
m_data.WriteString(text.c_str()); // text
m_data.Write<WORD>(0); // no extra data
++m_numControls;
m_data.Overwrite<WORD>(m_numControls, NUM_CTRL_OFFS);
}
void DialogTemplate::AddControl(DWORD dwType, WORD x, WORD y, WORD width, WORD height, const std::wstring& text, DWORD controlId, DWORD style)
{
m_data.AlignToDword();
m_data.Write<DWORD>(0); // help id
m_data.Write<DWORD>(0); // window extended style
m_data.Write<DWORD>(WS_CHILD | style); // style
m_data.Write<WORD>(x); // x
m_data.Write<WORD>(y); // y
m_data.Write<WORD>(width); // width
m_data.Write<WORD>(height); // height
m_data.Write<DWORD>(controlId); // control ID
m_data.Write<DWORD>(dwType); // control type (as DWORD)
m_data.WriteString(text.c_str()); // text
m_data.Write<WORD>(0); // no extra data
++m_numControls;
m_data.Overwrite<WORD>(m_numControls, NUM_CTRL_OFFS);
}
Wow, it's super annoying to paste code here if it's indented by tabs :-/
The code looks about right, but it does not show the produced template, which fails to instantiate.
One thing I noticed weird is:
m_data.Write<DWORD>(dwType); // control type (as DWORD)
This does not sound about right, you need 0xFFFF in front if it:
If the first element is 0xFFFF, the array has one additional element
that specifies the ordinal value of a predefined system class. The
ordinal can be one of the following atom values.
Under Win32 I believe the dialog template strcture needs to be byte aligned.

Why does EnumWindows return more windows than I expected?

In VC++, I use EnumWindows(...), GetWindow(...), and GetWindowLong(), to get the list of windows and check whether the window is top window (no other window as owner), and whether the window is visible (WS_VISIBLE). However, although my desktop is showing only 5 windows, this EnumWindows is giving me 50 windows, how funny! Any Windows geek here please help me clarify...
The way to list out only windows in taskbar (or similarly in Alt-Tab box) is described by Raymond in this article on MSDN blog:
Which windows appear in the Alt+Tab list?
And this is the super function to check whether a window is shown in alt-tab:
BOOL IsAltTabWindow(HWND hwnd)
{
TITLEBARINFO ti;
HWND hwndTry, hwndWalk = NULL;
if(!IsWindowVisible(hwnd))
return FALSE;
hwndTry = GetAncestor(hwnd, GA_ROOTOWNER);
while(hwndTry != hwndWalk)
{
hwndWalk = hwndTry;
hwndTry = GetLastActivePopup(hwndWalk);
if(IsWindowVisible(hwndTry))
break;
}
if(hwndWalk != hwnd)
return FALSE;
// the following removes some task tray programs and "Program Manager"
ti.cbSize = sizeof(ti);
GetTitleBarInfo(hwnd, &ti);
if(ti.rgstate[0] & STATE_SYSTEM_INVISIBLE)
return FALSE;
// Tool windows should not be displayed either, these do not appear in the
// task bar.
if(GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_TOOLWINDOW)
return FALSE;
return TRUE;
}
Credited to the source code here:
http://www.dfcd.net/projects/switcher/switcher.c
The windows that you are talking about, with an X button and a title bar, etc. are not the only kind of windows. Buttons, dropdown menus, labels, icons, text boxes, the task bar, and just about everything else is a window too1. So EnumWindows is doing exactly what it's supposed to do: enumerate all the top level windows.
1 Even though this is true, EnumWindows only enumerates the top level windows. That means it won't enumerate any child windows:
The EnumWindows function does not enumerate child windows, with the exception of a few top-level windows owned by the system that have the WS_CHILD style.
However, many things on your desktop are windows as well, not just the "windows" you're thinking about.
The answer provided by #jondinham does work perfectly for me. So I work out my own solution.
1.Problems I met with previous solution
Running on Windows 10 home edition 1909., I get two extra unexpected Windows "Calculator" and "Setting".
In addition, windows of Tencent QQ can not be detected, because the following fails:
// the following removes some task tray programs and "Program Manager"
ti.cbSize = sizeof(ti);
GetTitleBarInfo(hwnd, &ti);
if(ti.rgstate[0] & STATE_SYSTEM_INVISIBLE)
return FALSE;
However, I think the bug may be resulted by the particularity of Tencent QQ, I can not even make its' window TOPMOST with DeferWindowPos.
Perhaps someone can help me figure out why this happened and help improving the previous solution by #jondinham.
2.My Solution
I tried to examing the icons of the windows, and filter out windows that does not have its own icon or uses the icon same as the system default. I use code snippets from answer and answer and do some modification. This solution works very well for me.
HICON get_windows_HICON_critical(HWND hwnd)
{
// Get the window icon
HICON icon = reinterpret_cast<HICON>(::SendMessageW(hwnd, WM_GETICON, ICON_SMALL, 0));
if (icon == 0) {
// Alternative method. Get from the window class
icon = reinterpret_cast<HICON>(::GetClassLongPtrW(hwnd, GCLP_HICONSM));
}
// Alternative method: get the first icon from the main module (executable image of the process)
if (icon == 0) {
icon = ::LoadIcon(GetModuleHandleW(0), MAKEINTRESOURCE(0));
}
// // Alternative method. Use OS default icon
// if (icon == 0) {
// icon = ::LoadIcon(0, IDI_APPLICATION);
// }
if(icon == ::LoadIcon(0, IDI_APPLICATION)){
// Filter out those with default icons
icon = 0;
}
return icon;
}
static BOOL CALLBACK enumWindowCallback(HWND hWnd, LPARAM lparam) {
int length = GetWindowTextLength(hWnd);
char* buffer = new char[length + 1];
GetWindowText(hWnd, buffer, length + 1);
std::string windowTitle(buffer);
// List visible windows with a non-empty title
if (IsWindowVisible(hWnd) && length != 0) {
HICON icon = get_windows_HICON_critical(hWnd);
if(icon!=0){
std::cout << hWnd << ": " << windowTitle << std::endl;
}
}
return TRUE;
}
3.Problems with my solution
My solution can not deal with Windows Store APP, according to this question.
For all people looking to find a way to remove Invisible windows like Settings or Microsoft Store from the list:
These windows are cloaked, meaning they still have the dwStyle WS_VISIBLE, but the user can't see them.
You can detect this using the function DwmGetWindowAttribute. The dwAttribute you want to get is DWMWA_CLOAKED (enum constant 14). Only if the value in pvAttribute after the method call is 0, the window is not cloacked.