|
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using JGLibrary;
namespace JGFSControls
{
internal class JDropFiles
{
private JDropFiles()
{
//
// No instances, all static - this is standalone as it is a bit specialised
//
}
/// <summary>
/// Copies array of file names to Clipboard in FileDrop format, returns true on success, false on failure
/// </summary>
/// <param name="strFiles">String array of fully qualified file names to be copied to Clipboard. </param>
public static DataObject CopyFilesToClipboardForDragDrop(List<string> listFilePaths, POINT pt)
{
// Create and Copy File List to Clipboard in several formats
if (listFilePaths == null || listFilePaths.Count < 1)
return null;
// Obtain a DROPFILES for the give list of files
MemoryStream msDrop = FileListToDropFiles(listFilePaths, pt);
// Get a DataObject for Shortcuts
MemoryStream msLinks = FileListToShellIDListArray(listFilePaths);
// Get a File List
string szFileList = CreateFileList(listFilePaths);
// Now wrap them all in one DataObject
DataObject doTemp = new DataObject();
doTemp.SetData(DataFormats.FileDrop, true, msDrop);
doTemp.SetData("Shell IDList Array", true, msLinks);
doTemp.SetData(DataFormats.StringFormat, true, szFileList);
// Copy the data object to the clipboard
Clipboard.SetDataObject(doTemp, false);
return doTemp;
}
private static string CreateFileList(List<string> listSourceObjects)
{
string szResult = "";
for (int count = 0; count < listSourceObjects.Count; count++)
szResult += listSourceObjects[count] + '\0';
szResult += '\0';
return szResult;
}
private static object[] FileListToIDListArray(List<string> listObjects)
{
IntPtr pidl;
int cbPidl;
// Allocate an array of objects (byte arrays) to store the
// pidl of each item in the file list
object[] apidl = new object[listObjects.Count];
for (int count = 0; count < listObjects.Count; count++)
{
// Obtain a pidl for the file
pidl = ILCreateFromPath(listObjects[count]);
cbPidl = (int)ILGetSize(pidl);
// Convert the pidl to a byte array
apidl[count] = (object)new byte[cbPidl];
Marshal.Copy(pidl, (byte[])apidl[count], 0, cbPidl);
// Free the pidl
ILFree(pidl);
}
return apidl;
}
private static MemoryStream FileListToShellIDListArray(List<string> listObjects)
{
int cb = 0;
int offset = 0;
int count;
uint pidlDesktop = 0;
object[] apidl = null;
MemoryStream stream = null;
BinaryWriter streamWriter = null;
// Convert the array of paths to an array of pidls
apidl = FileListToIDListArray(listObjects);
// Determine the amount of memory required for the CIDA
// The 2 in the statement below is for the offset to the
// folder pidl and the count field in the CIDA structure
cb = offset = Marshal.SizeOf(typeof(uint)) * (apidl.Length + 2);
for (count = 0; count < apidl.Length; count++)
{
cb += ((byte[])apidl[count]).Length; ;
}
// Create a memory stream that we will write the CIDA into
stream = new MemoryStream();
// Wrap the memory stream with a BinaryWriter object
streamWriter = new BinaryWriter(stream);
// Write the cidl member of the CIDA structure
streamWriter.Write(apidl.Length);
// Write the array of offsets for each pidl. Calculate each offset as we go
streamWriter.Write(offset);
offset += Marshal.SizeOf(pidlDesktop);
for (count = 0; count < apidl.Length; count++)
{
streamWriter.Write(offset);
offset += ((byte[])apidl[count]).Length;
}
// Write the parent folder pidl
streamWriter.Write(pidlDesktop);
// Write the item pidls
for (count = 0; count < apidl.Length; count++)
{
streamWriter.Write((byte[])apidl[count]);
}
// Return the memory stream that contains the CIDA
return stream;
}
private static MemoryStream FileListToDropFiles(List<string> listFilePaths, POINT pt)
{
DataObject doTemp = new DataObject();
int numFiles = listFilePaths.Count + 1;
int count;
// Create DROPFILES structure
DROPFILES df = new DROPFILES();
df.pFiles = Marshal.SizeOf(df);
df.pt = pt;
df.fNC = false;
df.fWide = 0;
// Calculate memory required
int intMemRequired = Marshal.SizeOf(typeof(DROPFILES));
IntPtr ipGlobal = Marshal.AllocHGlobal(intMemRequired);
// Copy the DROPFILES structure in to memory
Marshal.StructureToPtr(df, ipGlobal, true);
// For Debugging - Read it back
//DROPFILES dfTemp = new DROPFILES();
//dfTemp = (DROPFILES)Marshal.PtrToStructure(ipGlobal, typeof(DROPFILES));
// Create a MemoryStream that we will write the data into
MemoryStream msTemp = new MemoryStream();
BinaryWriter streamWriter = new BinaryWriter(msTemp);
// Write the DROPFILES structure to the MemoryStream - convert to a byte[]
byte[] bTemp = new byte[Marshal.SizeOf(typeof(DROPFILES))];
Marshal.Copy(ipGlobal, bTemp, 0, 20);
streamWriter.Write(bTemp, 0, 20);
// Now Write the FileList - don't copy over listFilePaths, it copies the preceeding '@' and breaks it!
string strFileList = CreateFileList(listFilePaths);
for (count = 0; count < strFileList.Length; count++)
streamWriter.Write(strFileList[count]);
// Terminating double zero
streamWriter.Write((byte)0);
streamWriter.Write((byte)0);
// //Debugging - write it to a file to test
// string strTest = @"D:\Temp\TestData.bin";
// FileStream fs = new FileStream(strTest, FileMode.Create);
// // Create the writer for data.
// BinaryReader r = new BinaryReader(msTemp);
// msTemp.Position = 0;
//
// BinaryWriter w = new BinaryWriter(fs);
// // Write data to Test.data.
// try
// {
// for(int i = 0; i < msTemp.Length; i++)
// {
// w.Write(r.ReadByte());
// }
// }
// finally
// {
// w.Close();
// }
// Free Global Memory
Marshal.FreeHGlobal(ipGlobal);
return msTemp;
}
// ILCreateFromPath
[DllImport("shell32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr ILCreateFromPath(string pwszPath);
// ILFree
[DllImport("shell32.dll", CharSet = CharSet.None)]
public static extern void ILFree(IntPtr pidl);
// ILGetSize
[DllImport("shell32.dll", CharSet = CharSet.None)]
public static extern uint ILGetSize(IntPtr pidl);
[StructLayout(LayoutKind.Sequential)]
public struct DROPFILES
{
public int pFiles;
public POINT pt;
public bool fNC;
public int fWide;
}
} // End cDropFiles
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
I have been a keen hobbyist programmer since getting my first computer - a Vic 20 (you had to be able to write programs then since few programs were available and all were expensive).
Retired and now living in Pewsey, Wiltshire, where I spend (far too much of) my time writing computer programs to keep my mind active.