12

SharpShell を使用して、現在選択されているファイルを新しいサブフォルダーにコピーし、ユーザーにディレクトリの新しい名前を求める小さな新しいシェル コンテキスト メニュー項目を作成しています。

StackOverflow を検索すると、この回答が見つかりました。ただし、SharpShell でも同じことをしたいと思います。

どうにかして発砲SVSI_EDITする必要があり、奥深くに埋もれていることがわかりますが、これSharpShell.Interopがどのように機能するかはわかりません。ドキュメントやコード サンプルがまったく見つかりません。

(編集:Pidlファイル名から を取得する方法を見つけることは良い出発点になると思いますが、実際にはまったく必要ないのではないでしょうか?)

4

2 に答える 2

4

このチュートリアルのように、 SharpShellでプロジェクトの作成を開始して、新しいシェル コンテキスト メニューを登録できます。

ここでは、 を実装するクラスを定義する必要がありますSharpContextMenu。簡単にするために、任意のファイルタイプのメニューを作成し、常に表示します。

[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()
    {
        ...
    }
} 

しかし、私はあなたがこれをすべてやったと確信しています.ここでの問題はCopyFiles()メソッドを実装することです.

これを行う 1 つの方法は、次のようなフォルダーの名前を尋ねるダイアログを表示することです。

ファイルのコピー ダイアログ

次に、CopyFiles()次のように実装します。

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

上記のコードでは、フォルダーの名前を尋ね、フォルダーを作成し、最後に選択したファイルをそのフォルダーに移動しました。

ただし、 Windows エクスプローラーでRenameコマンドを使用して実行したい場合は、必要なWin32関数をインポートすることから始めることができます。

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ファイル名からPIDLを取得できます。
  • SHOpenFolderAndSelectItemsファイルを選択して名前変更コマンドを送信できるようにします。
  • ILFreePIDL管理されていない作成済みを解放します。

これらのWin32CopyFiles()関数を使用して、次のように定義できます。

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

SharpShell.Interop.Shell32このクラスで使用できる唯一のメソッドは、ShellExecuteEx()新しいプロセスを起動するために使用されるため、使用できません。

于 2016-03-25T16:57:24.410 に答える
3

質問で引用された例SelectItemInExplorerの機能を使用すると、非常に基本的な実装は次のようになります。可能な限り、SharpShell の既存の宣言をできるだけ多く使用するように、P/Invoke 機能が書き直されました。

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);
        }
    }
}
于 2016-03-21T04:00:39.453 に答える