Как скрыть иконки на рабочем столе программно?
Как программно отобразить/скрыть значки на рабочем столе, используя С#?
Я пытаюсь создать альтернативный рабочий стол, который использует виджеты, и мне нужно скрыть старые значки.
Ответы
Ответ 1
Вы можете сделать это, используя Windows API. Вот пример кода на С#, который будет переключать значки рабочего стола.
[DllImport("user32.dll", SetLastError = true)] static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)] static extern IntPtr GetWindow(IntPtr hWnd, GetWindow_Cmd uCmd);
enum GetWindow_Cmd : uint
{
GW_HWNDFIRST = 0,
GW_HWNDLAST = 1,
GW_HWNDNEXT = 2,
GW_HWNDPREV = 3,
GW_OWNER = 4,
GW_CHILD = 5,
GW_ENABLEDPOPUP = 6
}
[DllImport("user32.dll", CharSet = CharSet.Auto)] static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
private const int WM_COMMAND = 0x111;
static void ToggleDesktopIcons()
{
var toggleDesktopCommand = new IntPtr(0x7402);
IntPtr hWnd = GetWindow(FindWindow("Progman", "Program Manager"), GetWindow_Cmd.GW_CHILD);
SendMessage(hWnd, WM_COMMAND, toggleDesktopCommand, IntPtr.Zero);
}
Это отправляет сообщение в дочернее окно SHELLDLL_DefView Progman, которое сообщает ему переключать видимость (путем добавления или удаления стиля WS_VISIBLE) только дочернего, "FolderView". "FolderView" - это фактическое окно, содержащее значки.
Чтобы проверить, видны ли значки или нет, вы можете запросить стиль WS_VISIBLE с помощью функции GetWindowInfo, показанной ниже:
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", SetLastError = true)]
private static extern bool GetWindowInfo(IntPtr hwnd, ref WINDOWINFO pwi);
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
private int _Left;
private int _Top;
private int _Right;
private int _Bottom;
}
[StructLayout(LayoutKind.Sequential)]
struct WINDOWINFO
{
public uint cbSize;
public RECT rcWindow;
public RECT rcClient;
public uint dwStyle;
public uint dwExStyle;
public uint dwWindowStatus;
public uint cxWindowBorders;
public uint cyWindowBorders;
public ushort atomWindowType;
public ushort wCreatorVersion;
public WINDOWINFO(Boolean? filler)
: this() // Allows automatic initialization of "cbSize" with "new WINDOWINFO(null/true/false)".
{
cbSize = (UInt32)(Marshal.SizeOf(typeof(WINDOWINFO)));
}
}
Вот функция, вызывающая вышеуказанный код и возвращающая значение true, если окно видимо, false, если нет.
static bool IsVisible()
{
IntPtr hWnd = GetWindow(GetWindow(FindWindow("Progman", "Program Manager"), GetWindow_Cmd.GW_CHILD), GetWindow_Cmd.GW_CHILD);
WINDOWINFO info = new WINDOWINFO();
info.cbSize = (uint)Marshal.SizeOf(info);
GetWindowInfo(hWnd, ref info);
return (info.dwStyle & 0x10000000) == 0x10000000;
}
Код API Windows, а также дополнительную информацию о стилях окна можно найти здесь: http://www.pinvoke.net/default.aspx/user32/GetWindowInfo.html
Ответ 2
Другой подход - создать отдельный рабочий стол и показать его. У него не будет значков.
Запуск приложения на отдельном рабочем столе
Ответ 3
Вы можете создать приложение с полным экраном и сделать его самым большим окном.
Затем заставьте приложение запускаться с окнами.
Ответ 4
Вы можете сделать это в RegEdit
HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced
изменить HideIcons на 1
static void HideIcons()
{
RegistryKey myKey = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced", true);
if (myKey != null)
{
myKey.SetValue("HideIcons", 1);
myKey.Close();
}
}
Используйте класс реестра, как описано здесь.
http://msdn.microsoft.com/en-us/library/microsoft.win32.registry.aspx
Ответ 5
Вы делаете это неправильно. То, что вы действительно пытаетесь сделать, это заменить оболочку. Windows обеспечивает это, поэтому вы должны просто воспользоваться им. Напишите свою собственную оболочку для замены проводника.
Ответ 6
Существует официальный API для подобных действий, он называется API-интерфейсом оболочки. Это должно быть предпочтительнее, чем манипулирование реестром и подход FindWindow
/SendMessage
, как очень хрупкие "решения", которые, как правило, ломаются с будущими версиями Windows (для последних это уже было подтверждено комментаторами).
Шаги:
- Получите интерфейс
IFolderView2
на рабочем столе (поддерживается с Windows Vista). - Вызовите
IFolderView2::SetCurrentFolderFlags()
с FWF_NOICONS
для параметров dwMask
и dwFlags
.
Эффект флага отображается сразу. Нет необходимости перезагружать компьютер или "explorer.exe". Флаг также сохраняется после выхода из системы или перезагрузки.
Трудная вещь - шаг 1). Раймонд Чен показывает код C++ для этого в своей статье "Манипулирование положениями значков рабочего стола", в частности, в его функции FindDesktopFolderView()
.
Вот полный пример C++ в виде консольного приложения. Он основан на коде Raymond Chen. Программа переключает видимость значков рабочего стола при каждом запуске.
Код был протестирован под Windows 10 Build 17134.
#include <ShlObj.h> // Shell API
#include <atlcomcli.h> // CComPtr & Co.
#include <string>
#include <iostream>
#include <system_error>
// Throw a std::system_error if the HRESULT indicates failure.
template< typename T >
void ThrowIfFailed( HRESULT hr, T&& msg )
{
if( FAILED( hr ) )
throw std::system_error{ hr, std::system_category(), std::forward<T>( msg ) };
}
// RAII wrapper to initialize/uninitialize COM
struct CComInit
{
CComInit() { ThrowIfFailed( ::CoInitialize( nullptr ), "CoInitialize failed" ); }
~CComInit() { ::CoUninitialize(); }
};
// Query an interface from the desktop shell view.
void FindDesktopFolderView( REFIID riid, void **ppv, std::string const& interfaceName )
{
CComPtr<IShellWindows> spShellWindows;
ThrowIfFailed(
spShellWindows.CoCreateInstance( CLSID_ShellWindows ),
"Failed to create IShellWindows instance" );
CComVariant vtLoc( CSIDL_DESKTOP );
CComVariant vtEmpty;
long lhwnd;
CComPtr<IDispatch> spdisp;
ThrowIfFailed(
spShellWindows->FindWindowSW(
&vtLoc, &vtEmpty, SWC_DESKTOP, &lhwnd, SWFO_NEEDDISPATCH, &spdisp ),
"Failed to find desktop window" );
CComQIPtr<IServiceProvider> spProv( spdisp );
if( ! spProv )
ThrowIfFailed( E_NOINTERFACE, "Failed to get IServiceProvider interface for desktop" );
CComPtr<IShellBrowser> spBrowser;
ThrowIfFailed(
spProv->QueryService( SID_STopLevelBrowser, IID_PPV_ARGS( &spBrowser ) ),
"Failed to get IShellBrowser for desktop" );
CComPtr<IShellView> spView;
ThrowIfFailed(
spBrowser->QueryActiveShellView( &spView ),
"Failed to query IShellView for desktop" );
ThrowIfFailed(
spView->QueryInterface( riid, ppv ),
"Could not query desktop IShellView for interface " + interfaceName );
}
void ToggleDesktopIcons()
{
CComPtr<IFolderView2> spView;
FindDesktopFolderView( IID_PPV_ARGS(&spView), "IFolderView2" );
DWORD flags = 0;
ThrowIfFailed(
spView->GetCurrentFolderFlags( &flags ),
"GetCurrentFolderFlags failed" );
ThrowIfFailed(
spView->SetCurrentFolderFlags( FWF_NOICONS, flags ^ FWF_NOICONS ),
"SetCurrentFolderFlags failed" );
}
int wmain(int argc, wchar_t **argv)
{
try
{
CComInit init;
ToggleDesktopIcons();
std::cout << "Desktop icons have been toggled.\n";
}
catch( std::system_error const& e )
{
std::cout << "ERROR: " << e.what() << ", error code: " << e.code() << "\n";
return 1;
}
return 0;
}
Ответ 7
Несмотря на то, что он довольно старый, когда я пытался ответить Ondrej Balas, одна проблема, которую я нашел с этим решением, заключается в том, что оно не работает, если команда ToggleDesktop используется для отображения рабочего стола (также, если вращение обоев включено).
В обоих этих случаях окно SHELLDLL_DefView, которое является получателем функции toggleDesktopCommand в функции ToggleDesktopIcons, является не дочерним элементом окна "Диспетчер программ", а окна "WorkerW" (см. WinApi - Как получить SHELLDLL_DefView и Windows Рабочий стол ListView Handle.
Исходя из этого и основываясь на предыдущем ответе Ондрея Баласа, измените функцию ToggleDesktopIcons на:
static void ToggleDesktopIcons()
{
var toggleDesktopCommand = new IntPtr(0x7402);
SendMessage(GetDesktopSHELLDLL_DefView(), WM_COMMAND, toggleDesktopCommand, IntPtr.Zero);
}
И добавьте функцию GetDesktopSHELLDLL_DefView:
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);
[DllImport("user32.dll", SetLastError = false)]
static extern IntPtr GetDesktopWindow();
static IntPtr GetDesktopSHELLDLL_DefView()
{
var hShellViewWin = IntPtr.Zero;
var hWorkerW = IntPtr.Zero;
var hProgman = FindWindow("Progman", "Program Manager");
var hDesktopWnd = GetDesktopWindow();
// If the main Program Manager window is found
if (hProgman != IntPtr.Zero)
{
// Get and load the main List view window containing the icons.
hShellViewWin = FindWindowEx(hProgman, IntPtr.Zero, "SHELLDLL_DefView", null);
if (hShellViewWin == IntPtr.Zero)
{
// When this fails (picture rotation is turned ON, toggledesktop shell cmd used ), then look for the WorkerW windows list to get the
// correct desktop list handle.
// As there can be multiple WorkerW windows, iterate through all to get the correct one
do
{
hWorkerW = FindWindowEx(hDesktopWnd, hWorkerW, "WorkerW", null);
hShellViewWin = FindWindowEx(hWorkerW, IntPtr.Zero, "SHELLDLL_DefView", null);
} while (hShellViewWin == IntPtr.Zero && hWorkerW != IntPtr.Zero);
}
}
return hShellViewWin;
}
Теперь независимо от переключения рабочего стола или поворота обоев ToggleDesktopIcons должен работать всегда.
Для справки: это моя функция рабочего стола, которая вызвала проблему с оригинальной функцией ToggleDesktopIcons
static public void ToggleDesktop(object sender, EventArgs e)
{
var shellObject = new Shell32.Shell();
shellObject.ToggleDesktop();
}