2015-07-16 16 views
12

Tôi đang sử dụng SharpShell để viết một mục trình đơn ngữ cảnh vỏ nhỏ mới sao chép các tệp hiện được chọn vào thư mục con mới, sau đó nhắc người dùng cho tên mới của thư mục.Chọn tệp để đổi tên trong menu ngữ cảnh SharpShell

Tìm kiếm StackOverflow, tôi tìm thấy câu trả lời this. Tuy nhiên, tôi muốn làm điều tương tự trong SharpShell.

Tôi bằng cách nào đó sẽ phải bắn SVSI_EDIT tại đó, tôi có thể tìm thấy chôn sâu trong SharpShell.Interop, nhưng tôi không chắc chắn cách thức hoạt động của tính năng này. Tôi không thể tìm thấy bất kỳ tài liệu hoặc mẫu mã nào.

(Edit: Tôi nghĩ rằng việc tìm hiểu làm thế nào để có được một Pidl từ một tên file sẽ là một khởi đầu tốt, nhưng có lẽ tôi không thực sự cần điều đó ở tất cả?)

+1

Khi bạn tạo thư mục mới bằng cách sử dụng Explorer, thư mục này đặt tên cho thư mục là "Thư mục mới" và sau đó nó sẽ chuyển sang chế độ đổi tên. Khi bạn đang gõ tên thư mục và sau đó nhấn enter, bạn đang thực sự đổi tên thư mục. Điều gì xảy ra nếu người dùng đổi tên thư mục, sau đó nhấn enter trước khi các tệp sao chép xong? Việc đổi tên có thể sẽ thất bại vì các tệp vẫn đang được sao chép vào thư mục. Tôi nghĩ rằng cách tiếp cận này là không tốt và bạn tốt hơn off hiển thị một hình thức với một hộp văn bản cho người dùng. – Ove

Trả lời

4

Bạn có thể bắt đầu tạo một dự án với SharpShell đăng ký một menu ngữ cảnh vỏ mới như trong tutorial này.

Ở đây, chúng tôi phải xác định một lớp thực hiện SharpContextMenu. Để đơn giản chúng ta sẽ tạo menu cho bất kỳ filetype và luôn hiển thị nó:

[ComVisible(true)] 
[COMServerAssociation(AssociationType.AllFiles)] 
public class CopyFilesExtension : SharpContextMenu 
{ 
    protected override bool CanShowMenu() 
    { 
     return true; 
    } 

    protected override ContextMenuStrip CreateMenu() 
    { 
     var menu = new ContextMenuStrip(); 

     var copyFiles = new ToolStripMenuItem { Text = "Copy Files To Folder..." }; 

     copyFiles.Click += (sender, args) => CopyFiles(); 
     menu.Items.Add(copyFiles); 

     return menu; 
    } 

    private void CopyFiles() 
    { 
     ... 
    } 
} 

Nhưng tôi chắc chắn rằng bạn đã làm tất cả điều này, vấn đề ở đây là để thực hiện các phương pháp CopyFiles().

Một cách để làm điều này là hiển thị một hộp thoại yêu cầu tên của thư mục, một cái gì đó như thế này:

CopyFilesDialog

Sau đó, thực hiện CopyFiles() như vậy:

private void CopyFiles() 
{ 
    using (var dialog = new CopyFileDialog()) 
    { 
     if (dialog.ShowDialog() == DialogResult.OK) 
     { 
      var folder = Path.GetDirectoryName(SelectedItemPaths.First()); 
      var newFolder = Path.Combine(folder, dialog.FolderName); 

      Directory.CreateDirectory(newFolder); 

      foreach (var path in SelectedItemPaths) 
      { 
       var newPath = Path.Combine(newFolder, Path.GetFileName(path)); 
       File.Move(path, newPath); 
      } 
     } 
    } 
} 

Trong trên mã, chúng tôi đã yêu cầu tên của thư mục, sau đó tạo thư mục và cuối cùng di chuyển các tệp đã chọn vào thư mục đó.

Tuy nhiên, nếu bạn muốn làm điều đó bằng Đổi tên lệnh trong Windows Explorer chúng ta có thể bắt đầu bằng cách nhập số cần thiết Win32 chức năng:

class Win32 
{ 
    [DllImport("shell32.dll", CharSet = CharSet.Unicode)] 
    public static extern IntPtr ILCreateFromPath([In, MarshalAs(UnmanagedType.LPWStr)] string pszPath); 

    [DllImport("shell32.dll")] 
    public static extern int SHOpenFolderAndSelectItems(IntPtr pidlFolder, uint cidl, IntPtr[] apidl, int dwFlags); 

    [DllImport("shell32.dll")] 
    public static extern void ILFree(IntPtr pidl); 
} 
  • ILCreateFromPath cho phép chúng ta có được PIDL từ tên tệp.
  • SHOpenFolderAndSelectItems cho phép chúng tôi chọn tệp và gửi lệnh đổi tên.
  • ILFree giải phóng không được quản lý PIDL được tạo.

Với những Win32 chức năng chúng ta có thể định nghĩa CopyFiles() như sau:

private void CopyFiles() 
{ 
    var folder = Path.GetDirectoryName(SelectedItemPaths.First()); 
    var newFolder = Path.Combine(folder, "New Folder"); 
    Directory.CreateDirectory(newFolder); 

    foreach (var path in SelectedItemPaths) 
    { 
     var newPath = Path.Combine(newFolder, Path.GetFileName(path)); 
     File.Move(path, newPath); 
    } 

    RenameInExplorer(newFolder); 
} 


private static void RenameInExplorer(string itemPath) 
{ 
    IntPtr folder = Win32.ILCreateFromPath(Path.GetDirectoryName(itemPath)); 
    IntPtr file = Win32.ILCreateFromPath(itemPath); 

    try 
    { 
     Win32.SHOpenFolderAndSelectItems(folder, 1, new[] { file }, 1); 
    } 
    finally 
    { 
     Win32.ILFree(folder); 
     Win32.ILFree(file); 
    } 
} 

Chúng tôi không thể sử dụng SharpShell.Interop.Shell32 kể từ khi phương pháp duy nhất có sẵn trong lớp này là ShellExecuteEx() được sử dụng để khởi động quy trình mới.

3

Sử dụng chức năng SelectItemInExplorer từ cited example trong câu hỏi, rất triển khai cơ bản sẽ giống như sau. Khi có thể, bất kỳ chức năng P/Invoke nào cũng được viết lại để sử dụng càng nhiều các khai báo hiện có của SharpShell càng tốt.

using SharpShell.Attributes; 
using SharpShell.Interop; 
using SharpShell.SharpContextMenu; 
using System; 
using System.IO; 
using System.Linq; 
using System.Runtime.InteropServices; 
using System.Windows.Forms; 

namespace SendToFolderRename 
{ 
    [ComVisible(true)] 
    [COMServerAssociation(AssociationType.AllFiles)] 
    public class SendToFolderRename : SharpContextMenu 
    { 
     [DllImport("ole32.dll")] 
     private static extern int CreateBindCtx(int reserved, out IntPtr ppbc); 

     [DllImport("shell32.dll")] 
     private static extern int SHOpenFolderAndSelectItems(IntPtr pidlFolder, uint cidl, IntPtr[] apidl, int dwFlags); 

     protected override bool CanShowMenu() 
     { 
      return true; 
     } 

     protected override ContextMenuStrip CreateMenu() 
     { 
      var menu = new ContextMenuStrip(); 
      var itemCountLines = new ToolStripMenuItem 
      { 
       Text = "Copy files to subfolder" 
      }; 

      itemCountLines.Click += CopyFilesToSubfolder; 
      menu.Items.Add(itemCountLines); 
      return menu; 
     } 

     private void CopyFilesToSubfolder(object sender, EventArgs e) 
     { 
      //System.Diagnostics.Debugger.Break(); 
      string firstSelectedFile = SelectedItemPaths.FirstOrDefault(); 

      if (string.IsNullOrEmpty(firstSelectedFile)) 
       return; 

      string currentDirPath = (new FileInfo(firstSelectedFile)).DirectoryName; 
      string newDirName = Path.GetRandomFileName(); 
      string newDirPath = Path.Combine(currentDirPath, newDirName); 
      DirectoryInfo newDir = Directory.CreateDirectory(newDirPath); 
      foreach (string filePath in SelectedItemPaths) 
      { 
       FileInfo fileInfo = new FileInfo(filePath); 
       string newFilePath = Path.Combine(fileInfo.DirectoryName, newDirName, fileInfo.Name); 
       File.Copy(filePath, newFilePath); 
      } 

      SelectItemInExplorer(IntPtr.Zero, newDirPath, true); 
     } 

     public static void SelectItemInExplorer(IntPtr hwnd, string itemPath, bool edit) 
     { 
      if (itemPath == null) 
       throw new ArgumentNullException("itemPath"); 

      IntPtr folder = PathToAbsolutePIDL(hwnd, Path.GetDirectoryName(itemPath)); 
      IntPtr file = PathToAbsolutePIDL(hwnd, itemPath); 
      try 
      { 
       SHOpenFolderAndSelectItems(folder, 1, new[] { file }, edit ? 1 : 0); 
      } 
      finally 
      { 
       Shell32.ILFree(folder); 
       Shell32.ILFree(file); 
      } 
     } 

     private static IntPtr GetShellFolderChildrenRelativePIDL(IntPtr hwnd, IShellFolder parentFolder, string displayName) 
     { 
      IntPtr bindCtx; 
      CreateBindCtx(0, out bindCtx); 

      uint pchEaten = 0; 
      SFGAO pdwAttributes = 0; 
      IntPtr ppidl; 
      parentFolder.ParseDisplayName(hwnd, bindCtx, displayName, ref pchEaten, out ppidl, ref pdwAttributes); 
      return ppidl; 
     } 

     private static IntPtr PathToAbsolutePIDL(IntPtr hwnd, string path) 
     { 
      IShellFolder desktopFolder; 
      Shell32.SHGetDesktopFolder(out desktopFolder); 
      return GetShellFolderChildrenRelativePIDL(hwnd, desktopFolder, path); 
     } 
    } 
} 
+0

Xin chào, cảm ơn rất nhiều câu trả lời của bạn. Tôi sẽ thử nó vào ngày mai (tôi đã bận) và báo cáo lại nếu nó hoạt động. Sẽ hơi buồn nếu không có cách nào khác để làm điều đó, nhưng nó tốt hơn là không có gì :) – Lynn

Các vấn đề liên quan