2013-07-06 284 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