从TrueCrypt卷复制文件到剪贴板?

6
我使用这段代码来将文件复制到剪贴板:
IDataObject data = new DataObject();
data.SetData(DataFormats.FileDrop, new string[] {@"X:\test.doc"});
MemoryStream memo = new MemoryStream(4);
byte[] bytes = new byte[] { (byte)(5), 0, 0, 0 };
memo.Write(bytes, 0, bytes.Length);
data.SetData("Preferred DropEffect", memo);
Clipboard.SetDataObject(data);

不幸的是,如果磁盘是一个TrueCrypt挂载的卷,这种方法是不起作用的。在TrueCrypt卷上如何实现这一点?


恭喜你的百分之百 :) - Javed Akram
2
它到底为什么不工作?剪贴板查看器中是否显示? - fejesjoco
1个回答

5

很遗憾,我认为您无法在Windows 7上使用常规文件系统运行代码而不需要正确的Shell ID列表。正确的代码首先应该提供一个CIDL:

    var data = new DataObject();
    var files = new StringCollection() { @"T:\Test.doc" };
    data.SetFileDropList(files);
    data.SetData("Preferred DropEffect", true, new MemoryStream(new byte[] { 5, 0, 0, 0 }));
    data.SetData("Shell IDList Array", true, CreateShellIDList(files));
    Clipboard.SetDataObject(data, true);

CreateShellIDList函数创建了一个CIDA(CFSTR_SHELLIDLIST)结构的二进制表示,下面是其实现:

[DllImport("shell32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr ILCreateFromPath(string path);
[DllImport("shell32.dll", CharSet = CharSet.None)]
public static extern void ILFree(IntPtr pidl);
[DllImport("shell32.dll", CharSet = CharSet.None)]
public static extern int ILGetSize(IntPtr pidl);

private static MemoryStream CreateShellIDList(StringCollection filenames)
{
    // first convert all files into pidls list
    int pos = 0;
    byte[][] pidls = new byte[filenames.Count][];
    foreach (var filename in filenames)
    {
        // Get pidl based on name
        IntPtr pidl = ILCreateFromPath(filename);
        int pidlSize = ILGetSize(pidl);
        // Copy over to our managed array
        pidls[pos] = new byte[pidlSize];
        Marshal.Copy(pidl, pidls[pos++], 0, pidlSize);
        ILFree(pidl);
    }

    // Determine where in CIDA we will start pumping PIDLs
    int pidlOffset = 4 * (filenames.Count + 2);
    // Start the CIDA stream stream
    var memStream = new MemoryStream();
    var sw = new BinaryWriter(memStream);
    // Initialize CIDA witha count of files
    sw.Write(filenames.Count);
    // Calcualte and write relative offsets of every pidl starting with root
    sw.Write(pidlOffset);
    pidlOffset += 4; // root is 4 bytes
    foreach(var pidl in pidls)
    {
        sw.Write(pidlOffset);
        pidlOffset += pidl.Length;
    }

    // Write the root pidl (0) followed by all pidls
    sw.Write(0);
    foreach(var pidl in pidls) sw.Write(pidl);
    // stream now contains the CIDA
    return memStream;
}

我不能完全自己创造这个,我一段时间以前发现了这个CIDA代码,只是将其移植到C#。我真的记不得原始来源,但到目前为止它运行良好(我也在TrueCrypt上测试过)。


谢谢你的回答,我会检查一下(需要先在这台电脑上安装TrueCrypt)。无论如何,我的代码在Windows 7专业版上运行良好,我只是复制粘贴并测试了一下,但这不太重要。 - Ivan Ičin
好的,它可行了。我知道必须考虑设置Shell位置,但是找不到相关信息。 - Ivan Ičin
CreateShellIDList 的 C++ 实现的原始开发者是 Pascal Hurni。 - pcunite

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接