3

I'm using two batch files for Rainmeter, one to hide all icons and then launch Rainmeter, and another to show all icons and quit Rainmeter to make my desktop look normal again.

My end goal is to make these two batch files into buttons on my task bar that I can click to toggle the look of my desktop.

What I have so far is just the two batch files but all they do is show and hide desktop icons. (I found the code online because I couldn't write it myself)

show.bat

REG ADD "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /V HideIcons /T REG_DWORD /D 0 /F
taskkill /f /im explorer.exe
start explorer.exe

hide.bat

REG ADD "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /V HideIcons /T REG_DWORD /D 1 /F
taskkill /f /im explorer.exe
start explorer.exe

So the code I found works fine but a lot less smooth than just manually hiding desktop icons... The only problem is that when I run show.bat, my icons go back to a position that I don't want them in.

How can I one, get the batch files to show/hide icons more smoothly, and two, not move the icons around?

PS: Just wanted to stress that I seriously have no idea how the code I found works, so you may have to ELI5.

Stephan
  • 53,940
  • 10
  • 58
  • 91
Milquetoast
  • 33
  • 1
  • 3

2 Answers2

10

Firstly, TLDR: I don't think what you want is possible in a batch file, so I have compiled a little program that will toggle your desktop icons on and off each time it is run, and will not affect the positions. https://github.com/smithmart/ToggleIcons/raw/main/ToggleIcons.exe

This was thanks to another answer on stack overflow, but from what you say, I don't think you have the skills to use that answer yourself... so i did it for you.

ELI5:

I believe the reason your icons move about is because you are using taskkill to end explorer.exe. Explorer is the program in windows that runs most of the things you see, like your start bar and desktop, plus when you are browsing through drivers and folders.

So,

taskkill /f /im explorer.exe

stops explorer.exe dead, which is why you see your start bar vanish for a split second when you run your batch. In stopping it like that, it does not get a chance to save your Icon positions so they always revert back to the last known locations.

The reason the script you found does this is because stopping explorer.exe and then starting it back up again refreshes your desktop and this means the first line:

REG ADD "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /V HideIcons /T REG_DWORD /D 1 /F

can take effect. This line changes a setting in windows to say "hide my desktop icons"

Solution(kind of) I do not know a way in a simple batch file of refreshing your desktop settings, but, I did see this answer on stack overflow which is written in c# How to refresh/reload Desktop

I know you probably don't have the knowledge to use this answer so I have made a little exe for you that just toggles your icons

https://github.com/smithmart/ToggleIcons/raw/main/ToggleIcons.exe

It is called ToggleIcons.exe each time you run it, all it does is toggle desktop icons on or off

To use it, just pop it in the same folder as your batch file and add the line:

ToggleIcons.exe

to your script.

you can remove the 3 lines you already have, as this basically does all those 3 things. But, it does not restart explorer.exe which means that your icons will not move anywhere

I have also put the source code for you as taking candy from strangers is often not ideal, so if you don't feel comfortable using it I will not be offended! :D

Just in case the link to other answer is lost, here is the source:

class Program
{
    //Thanks to https://stackoverflow.com/questions/17503289/how-to-refresh-reload-desktop

    [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);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);

    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
    }

    private const int WM_COMMAND = 0x111;

    [DllImport("user32.dll", SetLastError = true)]
    static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

    private delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);

    [DllImport("user32.dll", CharSet = CharSet.Unicode)]
    private static extern int GetWindowText(IntPtr hWnd, StringBuilder strText, int maxCount);

    [DllImport("user32.dll", CharSet = CharSet.Unicode)]
    private static extern int GetWindowTextLength(IntPtr hWnd);

    [DllImport("user32.dll")]
    private static extern bool EnumWindows(EnumWindowsProc enumProc, IntPtr lParam);

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);

    [DllImport("user32.dll", SetLastError = false)]
    static extern IntPtr GetShellWindow();

    public static string GetWindowText(IntPtr hWnd)
    {
        int size = GetWindowTextLength(hWnd);
        if (size++ > 0)
        {
            var builder = new StringBuilder(size);
            GetWindowText(hWnd, builder, builder.Capacity);
            return builder.ToString();
        }

        return String.Empty;
    }

    public static IEnumerable<IntPtr> FindWindowsWithClass(string className)
    {
        IntPtr found = IntPtr.Zero;
        List<IntPtr> windows = new List<IntPtr>();

        EnumWindows(delegate (IntPtr wnd, IntPtr param)
        {
            StringBuilder cl = new StringBuilder(256);
            GetClassName(wnd, cl, cl.Capacity);
            if (cl.ToString() == className && (GetWindowText(wnd) == "" || GetWindowText(wnd) == null))
            {
                windows.Add(wnd);
            }
            return true;
        },
                    IntPtr.Zero);

        return windows;
    }

    static void ToggleDesktopIcons()
    {
        var toggleDesktopCommand = new IntPtr(0x7402);
        IntPtr hWnd = IntPtr.Zero;
        if (Environment.OSVersion.Version.Major < 6 || Environment.OSVersion.Version.Minor < 2) //7 and -
            hWnd = GetWindow(FindWindow("Progman", "Program Manager"), GetWindow_Cmd.GW_CHILD);
        else
        {
            IEnumerable<IntPtr> ptrs = FindWindowsWithClass("WorkerW");
            int i = 0;
            while (hWnd == IntPtr.Zero && i < ptrs.Count())
            {
                hWnd = FindWindowEx(ptrs.ElementAt(i), IntPtr.Zero, "SHELLDLL_DefView", null);
                i++;
            }
        }
        if (hWnd == IntPtr.Zero)
        {
            //"SHELLDLL_DefView" was not found as a child within WorkerW - Lets check the current ShellWindow
            IntPtr desktop = GetShellWindow();
            hWnd = FindWindowEx(desktop, IntPtr.Zero, "SHELLDLL_DefView", null);
        }
        if (hWnd != IntPtr.Zero)
        {
            SendMessage(hWnd, WM_COMMAND, toggleDesktopCommand, IntPtr.Zero);
        }
        
    }

    static void Main(string[] args)
    {
            ToggleDesktopIcons();
    }
}

Update: The process "SHELLDLL_DefView" is where we need to send the command to toggle the icons and this actually starts life as a child of progman. After the user activates some other features (unsure which ones, but Windows + Tab is one) it switches parent to WorkerW Changed this code to check within the currentShellWindow

SmithMart
  • 2,731
  • 18
  • 35
  • Well I downloaded ToggleIcons.exe but it didn't do anything when I ran it. It seems like a good step in the right direction, though! – Milquetoast Jul 25 '16 at 19:43
  • Darn, that is a real shame. Tested on windows 10 here and all desktop icons were popping on and off seamlessly :( you on windows 8? – SmithMart Jul 25 '16 at 20:04
  • Nope, I'm on Windows 10 also – Milquetoast Jul 26 '16 at 00:21
  • Really interesting! Ive changed the code and updated my answer. turns out place you send the command to toggle the icons starts life somewhere else. So changed the code to check again in the Current Windows Shell. This is fun :) (download the new toggleicons.exe) – SmithMart Jul 26 '16 at 06:48
  • Your program works unstable, sometimes it doesn't work when clicking on it. – hyper-cookie Jan 17 '23 at 13:19
1
Dim wsh
Set wsh = CreateObject("Shell.Application")
wsh.ToggleDesktop     'show and hide the desktop
hollopost
  • 569
  • 9
  • 28