SHMultiFileProperties doens't work on XP

2019-08-02 20:38发布

I am using c# to show properties dialog for multiple files using Windows SHMultiFileProperties function.

However, it works perfectly on Windows 7, but no dialog is shown on XP. Actually, function returns zero, so it is not even the error.

I can only think that the problem is in IDataObject that is sent to the function (I found code in the answer):

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


 [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 CIDL we will start pumping PIDLs
int pidlOffset = 4 * (filenames.Count + 2);
// Start the CIDL stream
var memStream = new MemoryStream();
var sw = new BinaryWriter(memStream);
// Initialize CIDL 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 CIDL
return memStream;

}

标签: c# .net shell
0条回答
登录 后发表回答