2013-07-06 211 views
7

我有一个WPF C#项目,我正在实现Windows文件夹选项的设置。其中之一是“单击打开一个项目”(而不是双击)。当我为这个问题更改注册表项时,我需要刷新我找到解决方案的Windows资源管理器。但是桌面不会刷新,甚至手动刷新也不会应用更改。 我已经使用IActiveDesktop :: ApplyChanges方法,但没有工作(或者我犯了一个错误)。我也用这个代码片断,但它仍然不适,我所做的更改:如何刷新/重新加载桌面

SHChangeNotify(0x8000000, 0x1000, IntPtr.Zero, IntPtr.Zero); 

这里是我用来刷新赢资源管理器(巫完整的代码片段是从本网站):

[System.Runtime.InteropServices.DllImport("Shell32.dll")] 
    private static extern int SHChangeNotify(int eventId, int flags, IntPtr item1, IntPtr item2); 

    public static void RefreshWindowsExplorer() 
    { 
     // Refresh the desktop 
     SHChangeNotify(0x8000000, 0x1000, IntPtr.Zero, IntPtr.Zero); 

     // Refresh any open explorer windows 
     // 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 Explorer, without checking for the name this could refresh open IE windows 
      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); 
      } 
     } 
    } 

,对于Windows资源管理器的工作原理,但不是桌面(这是奇怪,因为桌面取决于探险太)。 那么我应该如何重新加载桌面,以便我的更改生效?

+0

如果您尝试终止所有资源管理器实例并创建一个新实例,该怎么办? – master131

+0

@ master131,这是行得通的,但这不是一个选项,因为用户将失去所有的资源管理器窗口。 – SepehrM

+0

可能的重复[如何使“显示/隐藏桌面图标”设置生效?](http://stackoverflow.com/questions/3326062/how-do-i-make-the-show-hide-desktop -icons-setting-take-effect) –

回答

2

感谢您的回复和评论。我终于想出了解决这个问题的方法。我们可以隐藏所有桌面图标,然后再显示它们。这将强制桌面重新加载。

更新:在窗口8,SHELLDLL_DefViewWorkerW窗口中的一个的孩子。 (而不是Progman)因此,这里是更新的代码在Windows 8和8.1也工作:

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


    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 
     { 
      var ptrs = FindWindowsWithClass("WorkerW"); 
      int i = 0; 
      while (hWnd == IntPtr.Zero && i < ptrs.Count()) 
      { 
       hWnd = FindWindowEx(ptrs.ElementAt(i), IntPtr.Zero, "SHELLDLL_DefView", null); 
       i++; 
      } 
     } 
     SendMessage(hWnd, WM_COMMAND, toggleDesktopCommand, IntPtr.Zero); 
    } 

现在我们只需拨动桌面图标两次:

 ToggleDesktopIcons(); 
     ToggleDesktopIcons(); 

希望这有助于别人..

2

如果您发布了更改该设置的代码,我会在回复之前根据以下建议对其进行测试。

你试过:

1)从上面的代码删除声明if (itemName == "Windows Explorer"),所以它刷新每个窗口(包括桌面)?

2)通过SendMessage WIN32 API广播WM_SETTINGCHANGE?

private const int HWND_BROADCAST = 0xffff; 
private const int WM_WININICHANGE = 0x001a, WM_SETTINGCHANGE = 0x001a, INI_INTL = 1; 
[DllImport("user32.dll")] 
private static extern int SendMessage(int hWnd, uint wMsg, uint wParam, uint lParam); 

SendMessage(HWND_BROADCAST, WM_SETTINGCHANGE, 0, INI_INTL); 

[Credit]

3)IActiveDesktop.ApplyChanges

[ComImport] 
[Guid("F490EB00-1240-11D1-9888-006097DEACF9")] 
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
public interface IActiveDesktop 
{ 
    [PreserveSig] 
    int ApplyChanges(AD_Apply dwFlags); 
    // [...] 
    // Note: There is a lot more to this interface, 
    //  please see PInvoke.net link below. 
} 
private const int AD_APPLY_REFRESH = 4; 

IActiveDesktop.ApplyChanges(AD_APPLY_REFRESH); 

[PInvoke.net - IActiveDesktop]

如果这些都不管用,让我知道。如果涉及到它,可以保存所有打开的资源管理器窗口,终止资源管理器,等待资源管理器重新启动,重新打开每个资源管理器窗口并重新定位它们......如果可以接受的话。

希望这会有所帮助。

+0

非常感谢,但不幸的是他们都没有为我工作。所以我想通了,我可以隐藏桌面图标,然后显示它们。这只是做我想要的并重新加载桌面。 – SepehrM

+1

@feedwall如果是这种情况,您可以获取桌面的句柄并手动发送{F5}键... – SepehrM