4

In a previous question, there was an explanation how to hide desktop items:

How to hide desktop icons programatically?

For some reason, this code doesn't work for me.

I would have simply commented on the above link, but I don't have enough privileges to comment on other people's questions...

Any ideas what's going wrong? The desktop simply doesn't hide.

UPDATE: Additionally, I tried using the following code (as was suggested here), but still no effect:

struct SHELLSTATE
{
      bool fShowAllObjects;
      bool fShowExtensions;
      bool fNoConfirmRecycle;
      bool fShowSysFiles;
      bool fShowCompColor;
      bool fDoubleClickInWebView;
      bool fDesktopHTML;
      bool fWin95Classic;
      bool fDontPrettyPath;
      bool fShowAttribCol;
      bool fMapNetDrvBtn;
      bool fShowInfoTip1;
      bool fHideIcons1;
      bool fWebView1;
      bool fFilter1;
      bool fShowSuperHidden1;
      bool fNoNetCrawling1;
      UInt32 dwWin95Unused;
      uint uWin95Unused;
      long lParamSort;
      int   iSortDirection;
      uint version;
      uint uNotUsed;
      bool fSepProcess;
      bool fStartPanelOn;
      bool fShowStartPage;
      bool fAutoCheckSelect;
      bool fIconsOnly;
      bool fShowTypeOverlay;
      uint fSpareFlags;
}

class MyClass
{
    const UInt32 SSF_HIDEICONS = 0x00004000;

    [DllImport("Shell32.dll")]
    static extern void SHGetSetSettings(ref SHELLSTATE state, UInt32 dwMask, bool bSet);
    static void Foobar()
    {
        SHELLSTATE stateOfMind = new SHELLSTATE();
        Console.WriteLine("Set to true:");
        SHGetSetSettings(ref stateOfMind, SSF_HIDEICONS, true);
        Console.ReadKey();
        Console.WriteLine("Set to false:");
        SHGetSetSettings(ref stateOfMind, SSF_HIDEICONAS, false);
        Console.ReadKey();
    }
}
Community
  • 1
  • 1
Yehuda Shapira
  • 8,460
  • 5
  • 44
  • 66
  • Did you try restarting *explorer.exe*, like *Tibi* commented? – Otiel Nov 20 '11 at 08:44
  • 2
    That answer is a gross hack. I'm not surprised it doesn't work. Did you look for a shell api based approach use IShellFolder? – David Heffernan Nov 20 '11 at 08:46
  • @Otiel, I tried it. (That is, I ended explorer.exe and started a new task named explorer.) – Yehuda Shapira Nov 20 '11 at 09:00
  • @DavidHeffernan, I'm afraid I didn't quite catch what you're saying... please elaborate. – Yehuda Shapira Nov 20 '11 at 09:01
  • 3
    Another API worth checking out is [SHGetSetSettings](http://msdn.microsoft.com/en-us/library/bb762200%28VS.85%29.aspx) using the [SHELLSTATE.fHideIcons](http://msdn.microsoft.com/en-us/library/bb759788.aspx) bit, which was mentioned in [this post](http://stackoverflow.com/questions/1638471/show-hide-desktop-icons-from-c-application). Haven't tried it myself, though may be worth a shot. (Caveat - two of the other answers there are also gross hacks.) – BrendanMcK Nov 20 '11 at 09:02
  • 1
    The other answer is not a real answer. It's a hack based on undocumented implementation details. The shell has a very rich COM interface. Get an IShellFolder for the desktop and manipulate that. – David Heffernan Nov 20 '11 at 09:02
  • 2
    @Jacob, you might want to provide more background on what you are trying to do here. Are you trying to basically replace the shell outright, like on a dedicated kiosk, or just replace the desktop background, or run full-screen, or something else? And is this a permanent replacement, or just for the duration of some app that is running? – BrendanMcK Nov 20 '11 at 09:11
  • @BrendanMcK, I'm working on a kiosk app, and need to have the icons return once it's over. `SHGetSetSettings` sounds like the right thing. Any idea how to implement it in C#? – Yehuda Shapira Nov 20 '11 at 12:09
  • 2
    @Jacob - should be a fairly simple case of using P/Invoke; see this [tutorial on MSDN](http://msdn.microsoft.com/en-us/library/aa288468.aspx). Keep in mind though that there's any number of ways of side-stepping this type of app; right-clicking desktop may still bring up a menu, Ctrl-ESC will bring up windows menu, Alt-Tab will switch to other apps - and Ctrl-alt-del can be used to bring up the locked desktop and from there task manager. If 'kiosk-lite' is fine, then being a top-most full-screen app (like many games do, or media players and the like) may be a simpler/cleaner approach... – BrendanMcK Nov 20 '11 at 12:19
  • For what it's worth, there are ways of locking down a desktop for use in an actual kisok-style environment; but they are intended as long-term configuration changes to a machine, not something that lasts just for the duration of an app - quick overview [here](http://www.asktheadmin.com/2009/10/group-policy-desktop-lockdown-part-1.html). – BrendanMcK Nov 20 '11 at 12:27
  • @Jacob Please share your code that crashes, as well as a stack trace of the crash. You probably just have a bug. – Raymond Chen Nov 20 '11 at 15:11
  • @RaymondChen, I forgot to use `ref`... my bad! – Yehuda Shapira Nov 20 '11 at 15:13
  • @BrendanMcK Tried SHGetSetSettings and fHideIcons, but still doesn't work! Absolutely no affect! :( (I had to create the SHELLSTATE struct myself; I hope that was the right thing to do...) – Yehuda Shapira Nov 20 '11 at 15:29
  • 1
    @Jacob Please share your code. Until you do that, nobody can help you fix it. My guess is that you declared `SHELLSTATE` wrong. – Raymond Chen Nov 20 '11 at 15:50
  • You declared `SHELLSTATE` incorrectly. The `SHELLSTATE` structure uses bitfields. You are using plain `bool`s. On top of that, you called `SHGetSetSettings` incorrectly. The final parameter is not the state you want to set. It's a flag that says whether you want to read or write the setting. – Raymond Chen Nov 21 '11 at 22:52

1 Answers1

1

Here is sample code in C# that will toggle desktop icons.

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

This sends a message to the SHELLDLL_DefView child window of Progman, which tells it to toggle visibility (by adding or removing the WS_VISIBLE style) of it's only child, "FolderView". "FolderView" is the actual window that contains the icons.

To test to see if icons are visible or not, you can query for the WS_VISIBLE style by using the GetWindowInfo function, shown below:

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

}

Here is a function that calls the above code and returns true if the window is visible, false if not.

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;
}

The windows API code along with more information about the window styles can be found here: http://www.pinvoke.net/default.aspx/user32/GetWindowInfo.html

Michiko
  • 176
  • 1
  • 1
  • 7