17

My program sets "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" value "Hidden". Hovewer I'm not able to refresh the explorer to take into account this change. I've tried:

1)

    SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, IntPtr.Zero, IntPtr.Zero);` 

2)

    SHELLSTATE state = new SHELLSTATE(); 
    state.fShowAllObjects = (uint)1; 
    SHGetSetSettings(ref state, SSF.SSF_SHOWALLOBJECTS, true); 

3)

    SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, SPI_SETNONCLIENTMETRICS, 0, SMTO_ABORTIFHUNG, 5000, ref dwResult); 

4)

    SendMessage(HWND_BROADCAST, WM_COMMAND, 28931 /* Refresh */, 0); 

Nothing works. So what should I do? If I refresh Explorer myself with F5, then it works. Hovewer I would like some elegant solution, so it would refresh the display everywhere, even in OpenFile/SaveFile dialogs, which are currently open.

I'm using C# .NET, Win7.

Status Update #1

As Anders pointed out, there is a simple way to refresh explorer windows using COM:

Guid CLSID_ShellApplication = new Guid("13709620-C279-11CE-A49E-444553540000");
Type shellApplicationType = Type.GetTypeFromCLSID(CLSID_ShellApplication, true);
dynamic shellApplication = Activator.CreateInstance(shellApplicationType);
dynamic windows = shellApplication.Windows();
for (int i = 0; i < windows.Count; i++)
    windows.Item(i).Refresh();

So this part is done. Hovewer I still need to refresh the OpenFile/SaveFile dialogs, and the code above doesn't do that. Does anybody know how to refresh those dialogs?

An important point is that if I change the "Show Hidden Files" in Folder Options in Control panel, those OpenFile/SaveFile dialogs are not refreshed by the system, I must refresh them manually using F5. I'm just looking for a method how to refresh all those dialogs using C#, so I don't need to press F5 anymore...

Status Update #2

Ok, so new problem with the code above - it refresh not only windows explorers, but also internet explorers... Any idea how to refresh windows explorers ONLY?

Paya
  • 5,124
  • 4
  • 45
  • 71
  • @SLaks: Maybe it's a tweaking utility? – Max Shawabkeh Mar 21 '10 at 21:19
  • @Max: It isn't. http://stackoverflow.com/questions/2488632/win-c-run-app-as-administrator-without-uac-prompt/2488645#2488645 – SLaks Mar 21 '10 at 21:21
  • @SLaks: Right, didn't think to check previous questions since the poster has 1 rep. – Max Shawabkeh Mar 21 '10 at 21:26
  • @SLaks: The application in the link is different than this one, I'm developing more app at a time. The app in this question is simply a program, which registers a hotkey (Ctrl+H for example) and it will toggle the explorer "Hidden" settings and refresh the explorer... – Paya Mar 21 '10 at 21:27
  • I see; it sounds useful. I apologize. I don't have an answer, though – SLaks Mar 21 '10 at 21:37
  • I also tried using SendKeys to send F5, and that does not work either. When pressing F5 by hand, it seems that file *pane* on the right needs to be in focus for refresh to work -- if the window frame or folders pane is in focus, F5 does not do the refresh. – dbkk Apr 02 '10 at 17:28

5 Answers5

18

I figured out a way to check if the windows was a Windows Explorer window, and don't have enough of a rep to add a comment so thought I'd submit it as an answer to help you out because this question helped me out.

        // based on http://stackoverflow.com/questions/2488727/refresh-windows-explorer-in-win7
        Guid CLSID_ShellApplication = new Guid("13709620-C279-11CE-A49E-444553540000");
        Type shellApplicationType = Type.GetTypeFromCLSID(CLSID_ShellApplication, true);

        object shellApplication = Activator.CreateInstance(shellApplicationType);
        object windows = shellApplicationType.InvokeMember("Windows", System.Reflection.BindingFlags.InvokeMethod, null, shellApplication, new object[] { });

        Type windowsType = windows.GetType();
        object count = windowsType.InvokeMember("Count", System.Reflection.BindingFlags.GetProperty, null, windows, null);
        for (int i = 0; i < (int)count; i++)
        {
            object item = windowsType.InvokeMember("Item", System.Reflection.BindingFlags.InvokeMethod, null, windows, new object[] { i });
            Type itemType = item.GetType();

            // only refresh windows explorers
            string itemName = (string)itemType.InvokeMember("Name", System.Reflection.BindingFlags.GetProperty, null, item, null);
            if (itemName == "Windows Explorer")
            {
                itemType.InvokeMember("Refresh", System.Reflection.BindingFlags.InvokeMethod, null, item, null);
            }
        }
Adam
  • 619
  • 1
  • 4
  • 19
  • However the Windows Explorer in Win7 is somewhat strange. If I set the "Hidden" value in registry, while no Windows Explorer is running, and then start the Windows Explorer, then he will not take the registry change into account, and I need to refresh it after it starts. Do you, by any luck, know how to force the Win Explorer to take the change into account? Periodically refreshing all Explorers to make sure that all new-started Explorers get refreshed is not very nice solution. :-( – Paya May 19 '10 at 11:34
  • 2
    At first, the code did not work for me on Windows 8. I added additional check for itemName == "File Explorer". `if (itemName == "Windows Explorer" || itemName == "File Explorer")` After that it worked. This [post](http://winsupersite.com/article/windows8/windows-8-feature-focus-file-explorer-144727) says it is renamed to File Explorer in Windows 8. Thank you. – bhavik shah Nov 17 '14 at 11:04
  • I occasionally would get a null item. Fixed it by simply checking for null before trying to get item type ie. if (item != null ) Type itemType = item.GetType(); – Lee Jan 21 '16 at 02:53
  • "Windows Explorer" and "File Explorer" won't work on non-English Windows versions, we need to get the localized name of the Explorer window. Check my answer: https://stackoverflow.com/a/75970123/5514131 – Ahmed Osama Apr 09 '23 at 11:12
2

I don't know about Open/Save dialogs, but you can get a list of open explorer windows with COM automation, the Shell.Application object has a collection of windows, or CoCreate IID_IShellWindows directly, each window in the list has a refresh method.

WSH/JScript:

for(var sw=new ActiveXObject("Shell.Application").Windows(),i=0;i<sw.Count; ++i)
   sw.Item(i).Refresh();

I don't know about C#, but here are examples dealing with shell windows in WSH/JScript and c++

Anders
  • 97,548
  • 12
  • 110
  • 164
  • Well I've found only this way: http://web.archive.org/web/20080205152949/http://www.experts-exchange.com/Programming/Programming_Languages/C_Sharp/Q_20907891.html to execute above code in C#. I hope I'm missing something, because that way isn't really convenient... – Paya Apr 12 '10 at 16:18
  • You can call COM code in C# (Or put my code in a .js file and execute it with wscript.exe) – Anders Apr 12 '10 at 16:21
  • And to what should I cast object returned from System.Runtime.InteropServices.Marshal.GetActiveObject("Shell.Application");? I just wasn't able to find any suitable interface (I really don't know much about COM). – Paya Apr 12 '10 at 16:32
  • I just can't get it running. I've tried this code: http://pastebin.com/GFhPCWwX but it just thrown an exception on GetActiveObject (MK_E_UNAVAILABLE). I've tried running the program with admin rights, same exception... What am I missing? – Paya Apr 15 '10 at 13:15
1

With Windows 10 having changed the name of the Explorer window:

if ((itemName == "Windows Explorer") || (itemName == "File Explorer")) {
    itemType.InvokeMember("Refresh", System.Reflection.BindingFlags.InvokeMethod, null, item, null);
}
Anton Vlasov
  • 1,372
  • 1
  • 10
  • 18
Edgar5
  • 41
  • 2
0

When you install an application that registers a file type, Explorer windows often refresh to indicate the new association - could you spy on the API calls that an installer is making to see how it refreshes the window?

ultrafez
  • 543
  • 6
  • 19
  • I guess it probably calls SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, IntPtr.Zero, IntPtr.Zero);, but that doesn't refresh Hidden files, I guess (haven't tried). – Paya Apr 02 '10 at 23:37
  • Now I think about it, you could just hook the window when you switch hidden files on. Then you'd get the exact API call... – ultrafez Apr 03 '10 at 01:01
  • I've tried hooking windows messages, and it looks like the system is sending WM_WININICHANGE message. But for some weird reason, if I send that message to explorer windows, they just ignore it. – Paya Apr 25 '10 at 19:35
  • Could it be an integrity level issue? If you're running as a low-integrity process, then the system will prevent your window messages from reaching high-integrity processes, I think... – Jonathan Gilbert Feb 18 '16 at 03:00
  • @JonathanGilbert I can't imagine that Paya is still struggling with this problem, given that they asked the question 6 years ago... – ultrafez Feb 18 '16 at 13:35
  • Haha, good point -- I hadn't noticed the dates :-) But maybe someone else will stumble across the thread, having similar issues, and just maybe my comment will point them in the right direction. – Jonathan Gilbert Feb 18 '16 at 16:16
0

Adding to @Adam answer https://stackoverflow.com/a/2863647/5514131, "Windows Explorer" and "File Explorer" won't work on non-English Windows versions, we need to get the localized name of the Explorer window by reading the explorer.exe MUI resource file.

We will use SHLoadIndirectString API to read the text resource from explorer.exe.mui file.

[DllImport("shlwapi.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
public static extern int SHLoadIndirectString(string pszSource, StringBuilder pszOutBuf, int cchOutBuf, IntPtr ppvReserved);


    static void Main(string[] args)
    {

        var resourcePath = @"@%SystemRoot%\en-US\explorer.exe.mui,-6020"; //en-US should be replaced with the current Windows language code
        resourcePath = Environment.ExpandEnvironmentVariables(resourcePath);

        StringBuilder outBuff = new StringBuilder(1024);

        var result = SHLoadIndirectString(resourcePath, outBuff, outBuff.Capacity, IntPtr.Zero);

        if (result == 0)
        {
            Console.WriteLine(outBuff.ToString());
        }
        else
        {
            Console.WriteLine("SHLoadIndirectString method failed, error code: {0}", result);
        }

        Console.ReadLine();

    }

On Windows 10, this will output: File Explorer

Ahmed Osama
  • 348
  • 1
  • 9