Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pasting in autosave mode sometimes opens duplicate file explorer instance #9

Closed
eltos opened this issue Apr 5, 2022 · 2 comments
Closed
Labels
enhancement New feature or request

Comments

@eltos
Copy link
Owner

eltos commented Apr 5, 2022

To Reproduce

  1. Open a special folder like "Downloads" in Windows file explorer (make sure it's ::{374DE290-123F-4565-9164-39C4925E467B} and not C:\Users\User\Downloads)
  2. With autosave enabled, right click > paste into file
  3. A new file explorer window (C:\Users\User\Downloads) will open with the new file selected for rename.

Expected behaviour
The file is selected for rename in the existing file explorer. Furthermore, when multiple windows with the same location are open, the one where the right-click action was performed is used.

Cause
This is caused by the use of SHOpenFolderAndSelectItems which does not re-use an existing file explorer instance where the path is a GUID (like ::{374DE290-123F-4565-9164-39C4925E467B} instead of C:\Users\User\Downloads) and also does not know which instance to re-use if there are multiple.


Related:

@eltos eltos added the enhancement New feature or request label Apr 5, 2022
@eltos
Copy link
Owner Author

eltos commented Apr 5, 2022

An alternative approach would be to manually iterate the open instances and find a matching one.

This works very well, except that it takes a moment until the newly created file appears in the Folder.Items() list.
Therefore, if calling ExplorerUtil.RequestFilenameEdit(file) too early, it can not select the newly created file and the method falls back to SHOpenFolderAndSelectItems.
One could overcome this by introducing an artificial delay. Since SHOpenFolderAndSelectItems also takes a moment to select the file, this is no general disadvantage. However, the question remains how long the delay has to be, and if there is a way to use a callback or something in order not to introduce a hardcoded Thread.Sleep(1000);.

In ExplorerUtils.cs:

        /// <summary>
        /// Searches the file with given path in the given shell window and selects it if found
        /// </summary>
        /// <param name="window">The shell window</param>
        /// <param name="path">The path of the file to select</param>
        /// <param name="edit">Select in edit mode if true, otherwise just select</param>
        /// <returns>True if the file was found and selected, false otherwise</returns>
        private static bool SelectPathInWindow(SHDocVw.InternetExplorer window, string path, bool edit=true) {
            IShellFolderViewDual view = window?.Document as IShellFolderViewDual;
            if (view != null) {
                // TODO: some time needed for the file to appears in view.Folder.Items()
                foreach (FolderItem folderItem in view.Folder.Items()) {
                    if (folderItem.Path == path){
                        SetForegroundWindow((IntPtr)window.HWND);
                        // https://docs.microsoft.com/en-us/windows/win32/shell/shellfolderview-selectitem
                        view.SelectItem(folderItem, 16 /* focus it, */ + 8 /* ensure it's visible, */ 
                                                                   + 4 /* deselect all other and */ 
                                                                   + (edit ? 3 : 1) /* select or edit */);
                        return true;
                    }
                }
            }
            return false;
        }
        
        /// <summary>
        /// Request file name edit by user in active explorer path
        /// </summary>
        /// <param name="filePath">Path of file to select/edit</param>
        /// <param name="edit">can be set to false to select only (without entering edit mode)</param>
        public static void RequestFilenameEdit(string filePath, bool edit = true) {
            
            filePath = Path.GetFullPath(filePath);
            var dirPath = Path.GetDirectoryName(filePath);
            
            // check current shell window first
            var focussedWindow = GetActiveExplorer();
            if (GetExplorerPath(focussedWindow) == dirPath) {
                if (SelectPathInWindow(focussedWindow, filePath, edit))
                    return;
            }
            
            // then check other open shell windows
            var shellWindows = new SHDocVw.ShellWindows();
            foreach (SHDocVw.InternetExplorer window in shellWindows) {
                if (GetExplorerPath(window) == dirPath) {
                    if (SelectPathInWindow(window, filePath, edit))
                        return;
                }
            }
            
            // or open a new shell window
            IntPtr file;
            SHParseDisplayName(filePath, IntPtr.Zero, out file, 0, out _);
            try {
                SHOpenFolderAndSelectItems(file, 0, null, edit ? 1 : 0);
            } finally {
                ILFree(file);
            }
        }

        [DllImport("user32.dll")]
        static extern bool SetForegroundWindow(IntPtr hWnd);
        
        [DllImport("shell32.dll", SetLastError = true)]
        public static extern void SHParseDisplayName([MarshalAs(UnmanagedType.LPWStr)] string name,
            IntPtr bindingContext, [Out] out IntPtr pidl, uint sfgaoIn, [Out] out uint psfgaoOut);      

@eltos eltos closed this as completed in ddfb8a4 Apr 5, 2022
@eltos
Copy link
Owner Author

eltos commented Jul 17, 2023

However, the question remains how long the delay has to be, and if there is a way to use a callback or something in order not to introduce a hardcoded Thread.Sleep(1000);.

This was solved with window.Refresh() and window.DocumentComplete. See ddfb8a4.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant