Is there a way to get an handle to Windows's wallpaper (behind icons) in C++ in order to draw on it?
That would allow to make an active desktop (discontinued after Windows XP) equivalent, a Wallpaper Engine equivalent, or any other similar tool. (Temperature and resources usage monitoring on the wallpaper in my case).
Note: the handle returned by GetDesktopWindow() returns the window at desktop icons level, not behind it.
Solutions from similar questions aren't working for me.
Specifically i tried VLC media player's wallpaper mode code.
Key code is:
hwnd = FindWindow( _T("Progman"), NULL );
if( hwnd ) hwnd = FindWindowEx( hwnd, NULL, _T("SHELLDLL_DefView"), NULL );
if( hwnd ) hwnd = FindWindowEx( hwnd, NULL, _T("SysListView32"), NULL );
if( !hwnd )
{
msg_Warn( p_vout, "couldn't find \"SysListView32\" window, "
"wallpaper mode not supported" );
return;
}
But it will not draw on the wallpaper.
Credits to this draw behind desktop icons C# page as reference. The article explains the theory behind the solution, which applies regardless of the programming language being used.
Long story short, the smooth fading animation you see on Windows 10 when changing wallpaper is achieved by creating a new window that does exactly what you're asking for, drawing under the icons. That window achieves the fade-in effect for the new wallpaper, and is created by the Program Manager.
In the mentioned article you can see together with C# implementation an explanation of every step. Here i'll write a C++ equivalent keeping comments from the source.
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
HWND p = FindWindowEx(hwnd, NULL, L"SHELLDLL_DefView", NULL);
HWND* ret = (HWND*)lParam;
if (p)
{
// Gets the WorkerW Window after the current one.
*ret = FindWindowEx(NULL, hwnd, L"WorkerW", NULL);
}
return true;
}
HWND get_wallpaper_window()
{
// Fetch the Progman window
HWND progman = FindWindow(L"ProgMan", NULL);
// Send 0x052C to Progman. This message directs Progman to spawn a
// WorkerW behind the desktop icons. If it is already there, nothing
// happens.
SendMessageTimeout(progman, 0x052C, 0, 0, SMTO_NORMAL, 1000, nullptr);
// We enumerate all Windows, until we find one, that has the SHELLDLL_DefView
// as a child.
// If we found that window, we take its next sibling and assign it to workerw.
HWND wallpaper_hwnd = nullptr;
EnumWindows(EnumWindowsProc, (LPARAM)&wallpaper_hwnd);
// Return the handle you're looking for.
return wallpaper_hwnd;
}
The C-like casts can be replaced with reinterpret_casts, according to your coding preferences.
One note that isn't mentioned in the article:
Since when changing wallpaper a new WorkerW window is generated to achieve the fading effect, if the user tries to change wallpaper while your program is actively drawing and refreshing your instance of WorkerW, the user set background will be placed on top of your drawing, start fading in until it reaches 100% opacity, and lastly be destroyed, leaving your WorkerW still running.
Related
Sorry is this is a basic question but I can't wrap my head around this. I am trying to maximize a new chrome window, but I cant seem to find the handle to it. Here is the code I wrote so far to try to debug it but...
LPCWSTR window = L"chrome.exe";
HWND hWND = FindWindow(NULL, window);
SetWindowPos(
hWND,
HWND_TOPMOST,
10,
10,
10,
10,
SWP_SHOWWINDOW
);
The values were set to 10 just to see if it would move.
a) how do i get the handle of a specific window (in this case a new window of chrome)
b) is there a faster way to maximize a window than SetWindowPos()
Hi so the title describes it pretty well, I'm currently working on a software that will be installed on a POS system now when an event occurs this program needs to create a popup for the cashier to confirm what my concern is that since this is a separate program from the POS if the POS is fullscreen (not windowed) It will steal focus from the POS thus having to wait 2 seconds while window flashes to black fullscreen pos goes down then popup comes up and then having to restore the POS.
I need to be able to get around this problem of POS minimizing and having the cashier's input as well.
Here is what I'm currently attempting.
// Create the window object
hWnd = CreateWindowEx(WS_EX_TOOLWINDOW,
ClsName, WndName,
WS_POPUPWINDOW | WS_CAPTION,
200, 120, 200, 320,
NULL, NULL, hInstance, NULL);
// Find out if the window was created
if( !hWnd ) // If the window was not created,
return 0; // stop the application
// Display the window to the user
Sleep(10000); //Used so I can open a fullscreen window to test
ShowWindow(hWnd, SW_SHOWNOACTIVATE);
UpdateWindow(hWnd);
Thank you for your help :)
My program - among other things - changes the console window appearance (mainly the window size and border).
Now on my computer, everything is working perfectly at the moment, but when I run the application in VirtualBox, or on a different computer, I get the following:
The window on the top-left corner of the image is not actually a window. It's an image of a window, that you can't click. (mouse clicks go through it)
You can get rid of it by stretching the selection rectangle on the desktop over it, or if you highlight (for example) a button that is under it. Also, you can move a window over it, which makes it disappear completely.
The black rectangle on the bottom-right corner of the image is my console window, which is displayed correctly.
My question is, how to get rid of the 'ghost' window with C++?
I tried Googling a bit, but all I could find was ChangeDisplaySettings(0, 0);, which on my computer doesn't do anything (probably because I don't even have this problem on my computer), and in VirtualBox, it first appears to momentarily make the console window fullscreen and then back to the way it was. (the screen flickers the first time you run the application)
Although it does remove the ghost window, I don't want the screen to flicker like that, so this is not what I'm looking for.
EDIT:
As I can't really figure out what would be relevant code for this problem, I'll just dump pretty much all the code that has anything to do with changing the window itself in my program.
CSBIEx.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX);
GetConsoleScreenBufferInfoEx(hCon, &CSBIEx);
CSBIEx.dwSize.X = 49;
CSBIEx.dwSize.Y = 21;
SetConsoleScreenBufferInfoEx(hCon, &CSBIEx);
srWnd.Bottom = 20;
srWnd.Left = 0;
srWnd.Right = 48;
srWnd.Top = 0;
SetConsoleWindowInfo(hCon, TRUE, &srWnd);
GetClientRect(hWnd, &rClnt);
rClnt.top += 1;
rClnt.bottom -= 2;
rClnt.right -= 1;
SetWindowLongPtr(hWnd, GWL_STYLE, WS_POPUP);
exStyle = GetWindowLongPtr(hWnd, GWL_EXSTYLE);
exStyle &= ~WS_EX_CLIENTEDGE;
SetWindowLongPtr(hWnd, GWL_EXSTYLE, exStyle);
BringWindowToTop(hWnd);
SetWindowPos(hWnd, HWND_TOPMOST, ((rScr.right / 2) - rClnt.right / 2) - 1, (rScr.bottom / 2) - rClnt.bottom / 2, 0, 0, SWP_FRAMECHANGED | SWP_DRAWFRAME | SWP_NOSIZE);
SetWindowRgn(hWnd, CreateRectRgnIndirect(&rClnt), 1);
ShowWindow(hWnd, SW_SHOWNORMAL);
//ChangeDisplaySettings(0, 0);
2ND EDIT:
I don't know if it's of any help, but I noticed that if I use ChangeDisplaySettings(NULL, 0); instead of ChangeDisplaySettings(0, 0); it doesn't do anything. That's pretty weird considering that NULL is #defined 0..
If no one can figure anything out, I'll probably just end up using ChangeDisplaySettings(0, 0);.
InvalidateRect(NULL, NULL, TRUE);
Was the thing that I was looking for.
Are you running an "Aero" theme on your computer? If so, switch to the classic theme. Betcha you will see the problem manifest itself. I think your app is not handling the WM_PAINT message properly. The Aero themes send far fewer WM_PAINT messages. The OS does the painting with bitmaps that it saves.
EDIT: Try calling these with the new dimensions:
BOOL WINAPI SetConsoleDisplayMode(
_In_ HANDLE hConsoleOutput,
_In_ DWORD dwFlags,
_Out_opt_ PCOORD lpNewScreenBufferDimensions
);
http://msdn.microsoft.com/en-us/library/windows/desktop/ms686033%28v=vs.85%29.aspx
BOOL WINAPI SetConsoleWindowInfo(
_In_ HANDLE hConsoleOutput,
_In_ BOOL bAbsolute,
_In_ const SMALL_RECT *lpConsoleWindow
);
http://msdn.microsoft.com/en-us/library/windows/desktop/ms686125%28v=vs.85%29.aspx
You can also try sending yourself a WM_PAINT message with DispatchMessage.
I am creating a basic GUI with the Windows API and I have run into an issue. It starts with a main window that opens with a custom background color I set (RGB(230,230,230)). It then displays text in the upper left corner with the static control.
settingstext = CreateWindow("STATIC",
"SETTINGS",
SS_LEFT | WS_CHILD,
12,
20,
100,
20,
hwnd,
NULL,
proginstance,
NULL);
ShowWindow(settingstext, 1);
This works, but when the text is displayed I need a way to change the background of it to match the main window or else it just looks like it doesn't blend in.
My question is, how do I do this? I currently use the method below and it works, but I wanted to know, is there a way to permanently set the background color somehow, right after the CreateWindow function for the static control without changing system colors, and just have it apply to that one control and not anything that sends the WM_CTLCOLORSTATIC message. I have experimented around with using the GetDC function and SetBkColor function outside of the message loop but nothing works.
case WM_CTLCOLORSTATIC:
{
HDC hdcStatic = (HDC) wParam;
SetTextColor(hdcStatic, RGB(0,0,0));
SetBkColor(hdcStatic, RGB(230,230,230));
return (INT_PTR)CreateSolidBrush(RGB(230,230,230));
}
I want to do this because...
I don't want to fill up my message loop with functions that need to be called every time the window repaints.
Have the changes apply to only this static control.
I would be very thankful for any help that could be provided, at least pointing me in the right direction, thanks.
For static text controls there's no permanent way to set the text color or their background. Even if you want to apply the changes to a single static control; you would still have to handle WM_CTLCOLORSTATIC notification message in parent dlgproc just when the control is about to be drawn.
This is due to the DefWindowProc overwriting your changes to the device context each time it handles WM_CTLCOLORSTATIC as stated in the MSDN:
By default, the DefWindowProc function selects the default system colors for the static control.
static HBRUSH hBrush = CreateSolidBrush(RGB(230,230,230));
case WM_CTLCOLORSTATIC:
{
if (settingstext == (HWND)lParam)
//OR if the handle is unavailable to you, get ctrl ID
DWORD CtrlID = GetDlgCtrlID((HWND)lParam); //Window Control ID
if (CtrlID == IDC_STATIC1) //If desired control
{
HDC hdcStatic = (HDC) wParam;
SetTextColor(hdcStatic, RGB(0,0,0));
SetBkColor(hdcStatic, RGB(230,230,230));
return (INT_PTR)hBrush;
}
}
If you're looking to make the control's background transparent over a parent dialog you could use SetBkMode(hdcStatic, TRANSPARENT).
I think there is a permanent way to do it.
Just after you create the label,use GetDC() function to get the Device Context.
Then use:
SetTextColor(hdcStatic, RGB(0,0,0));
SetBkColor(hdcStatic, RGB(230,230,230)); // Code Copied from the above answer by cpx.
And it should do .
Have you considered subclassing the static window and doing owner draw?
I'm trying to get thumbnail pictures of windows that are not visible.
Here's the code I have so far
BOOL CALLBACK WindowProc(HWND hWnd, LPARAM lParam)
{
RECT WindRect;
GetWindowRect(hWnd, &WindRect)
CurrentScreenShot->Next = new ScreenShotList();
CurrentScreenShot = CurrentScreenShot->Next;
HDC SourceDC = GetDC(hWnd);
HDC TargetDC = CreateCompatibleDC(SourceDC);
CurrentScreenShot->ScreenShot = CreateCompatibleBitmap(SourceDC, WindRect.right - WindRect.left, WindRect.bottom - WindRect.top);
BitBlt(TargetDC, 0, 0, WindRect.right - WindRect.left, WindRect.bottom - WindRect.top, SourceDC, 0, 0, SRCCOPY);
ReleaseDC(hWnd, SourceDC);
g_iWindows++;
return TRUE;
}
For now, WindowProc is being called directly using FindWindow to get a handle, though, I eventually want to use EnumWindows to loop through all of the windows to get their thumbnails and store them in a linked list.
WindowProc(FindWindow(NULL, L"File Explorer"), 0);
This code is in a DLL, which is called from a C# Forms application. For now the C# application just takes the bitmap and saves it to a file.
The problem is that unless I use FindWindow to get the visible window (which also happens to be the C# application), the picture ends up being a black box.
Is it possible to get an picture of a background window?
EDIT: This is a Windows Mobile application
There is no redrawing going on for invisible Windows, thats why you cannot get their content from the DC. Try sending a WM_PRINT message to the target window to request that it draws its content to your DC.
Edit:
Sorry, i did not notice this was for Windows Mobile. Other than WM_PRINT, i don't know a way to get the content of an invisible window. Of course you can still show the window (and make sure it is on top / not covered by other windows) and then run the code you have, but thats probably a bit messy.