Closed Oliviaophia closed 5 years ago
It seems that methods 2 and 3 do not support windows below win10.
It seems that window10 changed some methods of the taskbar to message control. So I found the reason why the taskbar refused to hide sometimes. It can be hidden correctly by sending a WM_USER + 459
message.
Buggy experimental version (C++):
#include <iostream>
#include <Windows.h>
#include <dwmapi.h>
APPBARDATA msg_data = { sizeof(APPBARDATA) };
WINDOWPLACEMENT placement = { sizeof(WINDOWPLACEMENT) };
POINT cursor;
HWND window;
DWORD pid;
BOOL cloaked_val = TRUE;
inline bool is_cursor_over_taskbar()
{
GetCursorPos(&cursor);
switch (msg_data.uEdge)
{
case ABE_BOTTOM:
if (cursor.y >= msg_data.rc.top)
return true;
return false;
case ABE_LEFT:
if (cursor.x <= msg_data.rc.right)
return true;
return false;
case ABE_TOP:
if (cursor.y <= msg_data.rc.bottom)
return true;
return false;
default:
if (cursor.x >= msg_data.rc.left)
return true;
return false;
}
}
int main()
{
auto try_show_bar = true;
msg_data.lParam = ABS_AUTOHIDE;
SHAppBarMessage(ABM_SETSTATE, &msg_data);
while (true)
{
while (is_cursor_over_taskbar())
Sleep(250);
window = GetForegroundWindow();
if (window == nullptr)
{
Sleep(375);
continue;
}
RECT window_rect;
GetWindowRect(window, &window_rect);
SHAppBarMessage(ABM_GETTASKBARPOS, &msg_data);
if (msg_data.rc.top > window_rect.bottom || window_rect.left > msg_data.rc.right || msg_data.rc.left > window_rect.right || window_rect.top > msg_data.rc.bottom)
{
if (try_show_bar)
{
try_show_bar = false;
PostMessage(FindWindow(TEXT("Shell_TrayWnd"), nullptr), WM_USER + 459, TRUE, 0x10001);
Sleep(375);
continue;
}
Sleep(375);
continue;
}
PostMessage(FindWindow(TEXT("Shell_TrayWnd"), nullptr), WM_USER + 459, FALSE, 0);
try_show_bar = true;
}
}
Buggy experimental version (C#): With some improvements.
switch (MsgData.uEdge)
{
case 3:
if (Control.MousePosition.Y >= MsgData.rc.top)
{
return;
}
break;
case 0:
if (Control.MousePosition.X <= MsgData.rc.right)
{
return;
}
break;
case 1:
if (Control.MousePosition.Y <= MsgData.rc.bottom)
{
return;
}
break;
default:
if (Control.MousePosition.X >= MsgData.rc.left)
{
return;
}
break;
}
Forewindow = GetForegroundWindow();
if (IsWindowVisible(Forewindow) == false)
{
return;
}
DwmGetWindowAttribute(Forewindow, 14, out Cloakedval, sizeof(int));
if (Cloakedval)
{
return;
}
StringBuilder sb = new StringBuilder(255);
GetClassNameW(Forewindow, sb, 255);
string name = sb.ToString();
if (name == "WorkerW" || name == "Progman")
{
PostMessageW(FindWindow("Shell_TrayWnd", null), 0x05CB, (IntPtr)1, (IntPtr)0x10001);
return;
}
GetWindowRect(Forewindow, out TagRect lpRect);
SHAppBarMessage(5, ref MsgData);
if (MsgData.rc.top > lpRect.bottom || lpRect.left > MsgData.rc.right || MsgData.rc.left > lpRect.right || lpRect.top > MsgData.rc.bottom)
{
PostMessageW(FindWindow("Shell_TrayWnd", null), 0x05CB, (IntPtr)1, (IntPtr)0x10001);
return;
}
PostMessageW(FindWindow("Shell_TrayWnd", null), 0x05CB, (IntPtr)0, (IntPtr)0);
done~
I have been looking for new ways to implement Auto Mode in the past few months.
The basic idea is to set the taskbar to Auto-Hide and then activate it. In this way, many of the SmartTaskbar bugs will not longer exist (#8 , #13 , #19 , #24 , #25 ).
Currently I have found three successful but flawed ways:
Use the
WM_ACTIVATE
message to activate the taskbar:PostMessage(FindWindow(TEXT("Shell_TrayWnd"), nullptr), WM_ACTIVATE, WA_ACTIVE, NULL);
Using this method, we can bring out the taskbar in a very short time. It will quickly return to the hidden state and then display again when it receives the next
WM_ACTIVATE
message. This way is a bit stupid, but it looks very funny ~Use the
WM_USER + 459
message to activate the taskbar:PostMessage(FindWindow(TEXT("Shell_TrayWnd"), nullptr), WM_USER + 459, TRUE, 0x10001);
Deactivate:
PostMessage(FindWindow(TEXT("Shell_TrayWnd"), nullptr), WM_USER + 459, FALSE, 0);
This method can successfully activate the taskbar for a long time, and the effect is perfect. But its last parameter doesn't always have to be
0x10001
, and its changing pattern looks like random. This makes it difficult for me to locate really valid values. Moreover, this method can only activate one taskbar at a time, not the desired multi-monitor solution.Use the
WM_USER + 443
message to activate the taskbar by activate start button?PostMessage(FindWindow(TEXT("Shell_TrayWnd"), nullptr), WM_USER + 443, TRUE, 0);
Deactivate:
PostMessage(FindWindow(TEXT("Shell_TrayWnd"), nullptr), WM_USER + 443, FALSE, 0);
This method requires a click on the start button to make it selected, and then the taskbar with the button can be activated. Similarly, only one taskbar can be activated at a time.
The above methods can be executed correctly on Windows10 1809. But these methods are not perfect, if you happen to know how to activate the taskbar when it is auto-hide, please help me!