I am currently trying to retrieve the list of icons from my desktop to change their locations and / or hide them as well as display others.
I tried to get the FolderView in the code below but it doesn't even show the number of icons I have on the desktop because count return 0.
HWND hDesktop = GetDesktopWindow();
HWND hDefView = FindWindowEx(hDesktop, NULL, L"SHELLDLL_DefView", NULL);
HWND folderView = FindWindowEx(hShellWnd, NULL, L"SysListView32", NULL);
int count = (int) SendMessage(folderView, LVM_GETITEMCOUNT, 0, 0);
cout << count << endl;
I did tests on the variables and is noticed that hDefView is NULL.
Probably the reason why count return 0.
EDIT : After replace GetDesktopWindow by GetShellWindow the result is always the same, 0
The shell window hierarchy is not documented nor stable. "ProgMan" is usually the parent of "SHELLDLL_DefView" but if you change to slideshow wallpaper it can also be "WorkerW".
It is much better to inspect/manipulate the desktop with the documented shell COM interfaces: IShellWindows, IShellBrowser, IFolderView and IShellFolder.
Related
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.
Can anyone tell me why the child window cannot be created?
I'm using the forgers win32api guide but I cannot figure out what is the problem.
When the program starts running I have all of the controls, but when I click on the 'new' menuitem I get the error message. This is right after the winmain.
Other things like menuitems, the tool and status bars, opening or saving files works.
**HWND CreateNewMDIChild(HWND hMDIClient)
{
MDICREATESTRUCT mcs;
HWND hChild;
mcs.szTitle = "[Untitled]";
mcs.szClass = g_szChildClassName;
mcs.hOwner = GetModuleHandle(NULL);
mcs.x = mcs.cx = CW_USEDEFAULT;
mcs.y = mcs.cy = CW_USEDEFAULT;
mcs.style = MDIS_ALLCHILDSTYLES;
hChild = (HWND)SendMessage(hMDIClient, WM_MDICREATE, 0, (LONG)&mcs);
if(!hChild)
{
MessageBox(hMDIClient, "MDI Child creation failed.", "Oh Oh...",
MB_ICONEXCLAMATION | MB_OK);
}
return hChild;
}**
That's an unfortunate bug in the sample code, that prevents it from running on 64-bit Windows. The final parameter to SendMessage is of type LPARAM (an alias for LONG_PTR). Casting it to LONG truncates it to 4 bytes, not quite sufficient for a 64-bit pointer (see Data Type Ranges).
Change the following line
hChild = (HWND)SendMessage(hMDIClient, WM_MDICREATE, 0, (LONG)&mcs);
to
hChild = (HWND)SendMessage(hMDIClient, WM_MDICREATE, 0, (LPARAM)&mcs);
and the code should run as expected.
so am trying to make my window class full screen, but it's not working , it just flickers black then it does not become full screen here is the source code :-
void InitEngine::Init(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd, DesktopScreenInfo * ScreenInfo, LPSTR WindowName)
{
mWindoClass = new WNDCLASSEX();
ZeroMemory(mWindoClass,sizeof(WNDCLASSEX));
if(ScreenInfo) mScreenInfo = ScreenInfo;
else mScreenInfo = &DesktopScreen::GetScreenInfo();
mWindoClass->cbSize = sizeof(WNDCLASSEX);// window size
mWindoClass->style = CS_HREDRAW | CS_VREDRAW; // so it draw when Horizontal or Vertical change
mWindoClass->lpfnWndProc = WindowProc;
mWindoClass->hInstance = hInstance;
mWindoClass->hCursor = LoadCursor(NULL, IDC_ARROW); //load normal cursor
mWindoClass->hbrBackground = (HBRUSH)COLOR_WINDOW;
mWindoClass->lpszClassName = "PoPEngineClass";
DEVMODE screen;
memset(&screen,0,sizeof(screen));
screen.dmSize = sizeof(screen);
screen.dmPelsWidth = mScreenInfo->Width;
screen.dmPelsHeight = mScreenInfo->Height;
screen.dmBitsPerPel = mScreenInfo->ScreenDepth;
screen.dmDisplayFrequency = mScreenInfo->FrameRate;
screen.dmFields = DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
ChangeDisplaySettings(&screen, CDS_FULLSCREEN);
RegisterClassEx(mWindoClass);
WindowHandel = CreateWindowEx(NULL , mWindoClass->lpszClassName , WindowName , WS_POPUP, 0 , 0, mScreenInfo->Width, mScreenInfo->Height, NULL, NULL, hInstance, NULL);
ShowWindow(WindowHandel, nShowCmd);
UpdateWindow(WindowHandel);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
ChangeDisplaySettings does not actually make a window full-screen - despite the perhaps misleading name of the flag. To make a window go full screen, you basically have to do a bunch of work yourself:
remember the old position
change the window style to remove the borders and titlebar
get the screen size, set the window's new position to cover the screen
and put it on top of other windows (the latter two you can do with the SetWindowPos call.)
There's a couple of answers to this same question elsewhere on SO -- but there's problems with them. Instead recommend reading Raymond Chen's blog entry on this: How do I cover the taskbar with a fullscreen window? - the difference between what he's doing any my list above is that he's creating a new window without vs modifying an existing one; which is actually a neater approach as it means you don't need to deal with remembering/restoring the old position.
ChangedisplaySetting's CDS_FULLSCREEN flag has a different meaning: the call is for changing display mode settings, not making a window fullscreen; but the flag is telling windows that the mode change is temporary, so should't be saved. For example, if an app that plays back video at a specific resolution is going full screen, it might want to change the actual screen resolution to match the video, but just so long as it is full screen. Or a OpenGL game or similar might use this to ensure it is running full-screen with a specific resolution. So it really means "change the display settings to these, but I'm doing this just because I'm going fullscreen, so don't make the change permanent'. Raymond Chan writes a bit more about this flag on his blog here. If you don't care about the screen resolution settings, and you just want your window taking up all of the screen area, then you don't need this call.
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.
I am registering my Class in the following method:
BOOL CNDSClientDlg::InitInstance()
{
//Register Window Updated on 16th Nov 2010, #Subhen
// Register our unique class name that we wish to use
WNDCLASS wndcls;
memset(&wndcls, 0, sizeof(WNDCLASS));
wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
wndcls.lpfnWndProc = ::DefWindowProc;
wndcls.hInstance = AfxGetInstanceHandle();
wndcls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wndcls.lpszMenuName = NULL;
//Class name for using FindWindow later
wndcls.lpszClassName = _T("CNDSClientDlg");
// Register new class and exit if it fails
if(!AfxRegisterClass(&wndcls)) // [C]
{
return FALSE;
}
}
and then calling the InitInstance method and creating the window in constructor of the Class:
CNDSClientDlg::CNDSClientDlg(CWnd* pParent /*=NULL*/)
: CDialog(CNDSClientDlg::IDD, pParent)
{
InitInstance();
HWND hWnd;
hInst = AfxGetInstanceHandle(); // Store instance handle in our global variable
hWnd = CreateWindow(_T("CNDSClientDlg"), "NDS", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInst, NULL);
}
Now in my other application I am finding the window and trying to bring to top:
Edit
Able to bring newlyCreated Windows with below code
CWnd *pWndPrev = NULL;
CWnd *FirstChildhWnd = NULL;
pWndPrev = CWnd::FindWindow(_T("CNDSClientDlg"),NULL);
if(pWndPrev != NULL)
{
//pWndPrev->BringWindowToTop();
WINDOWPLACEMENT wndplacement;
pWndPrev->GetWindowPlacement(&wndplacement);
wndplacement.showCmd = SW_RESTORE;
pWndPrev->SetWindowPlacement(&wndplacement);
pWndPrev->SetForegroundWindow();
FirstChildhWnd = pWndPrev->GetLastActivePopup();
if (pWndPrev != FirstChildhWnd)
{
// a pop-up window is active, bring it to the top too
FirstChildhWnd->GetWindowPlacement(&wndplacement);
wndplacement.showCmd = SW_RESTORE;
FirstChildhWnd->SetWindowPlacement(&wndplacement);
FirstChildhWnd->SetForegroundWindow();
}
I am able to find the window as pWndPrev is not NULL , but It is not bringing up my application to front. Do I need to register any other class Instead of CNDSClientDlg. I want to bring my MFC application to top.
A few things to look at...
1) Try SetForegroundWindow() instead of BringWindowToTop(). It's been awhile since I've done Win32 programming, but I seem to recall that BringWindowToTop() has some limitations (especially when working with windows in different processes).
2) There are some rules that Microsoft put in place regarding SetForegroundWindow() starting with Windows 2000. The short version is that only the front-most application can change the foreground window. The idea is that an application that is not front-most cannot "jump in front of" the active application. If a background application calls SetForegroundWindow(), Windows will flash the taskbar button for the app, but will not actually bring the app to the front. The user must do that. I'm oversimplifying the rules, but this may be something to look at depending on your specific scenario.
BringWindowToTop() only works if the calling process is the foreground process or if it received the last input event.
Call CWnd::SetForegroundWindow() instead.
You may need to call AllowSetForegroundWindow in your "other" application before calling SetForegroundWindow.
That is assuming your other application is the foreground app and is trying to pass on its foreground status to the application with the window.
If neither app is the foreground app then you're not supposed to be able to bring a window to the front, although there are ways to do it (both accidentally and on purpose).
SetWindowPos(&wndTopMost, -1, -1, -1, -1, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
SetForegroundWindow();