/// <summary>
        /// Utility function to extract an array of file contents file descriptors from
        /// an IDataObject instnace
        /// </summary>
        /// <param name="dataObject">data object to extract descriptors from</param>
        /// <returns>array of file descriptors</returns>
        public static FileDescriptor[] GetFileDescriptors(IDataObject dataObject)
        {
            // Use an OleDataObject
            OleDataObject oleDataObject = OleDataObject.CreateFrom(dataObject);

            if (oleDataObject == null)
            {
                const string message = "DataObject not valid for FileContents!";
                Debug.Fail(message);
                throw
                    new InvalidOperationException(message);
            }

            // Try to get the data as FileGroupDescriptorW then try to get it
            // as FileGroupDescriptor
            bool bFileNameIsWide;
            OleStgMediumHGLOBAL stgMedium = (OleStgMediumHGLOBAL)oleDataObject.GetData(
                DataFormatsEx.FileGroupDescriptorWFormat, TYMED.HGLOBAL);

            if (stgMedium != null)
            {
                bFileNameIsWide = true;
            }
            else
            {
                stgMedium = (OleStgMediumHGLOBAL)oleDataObject.GetData(
                    DataFormatsEx.FileGroupDescriptorFormat, TYMED.HGLOBAL);

                if (stgMedium != null)
                {
                    bFileNameIsWide = false;
                }
                else
                {
                    const string message = "File group descriptor not available!";
                    Debug.Fail(message);
                    throw
                        new InvalidOperationException(message);
                }
            }


            // Copy the descriptors
            using ( stgMedium )
            {
                using (HGlobalLock globalMem = new HGlobalLock(stgMedium.Handle))
                {
                    // get a pointer to the count
                    IntPtr pCount = globalMem.Memory;

                    // determine the number of file descriptors
                    Int32 count = Marshal.ReadInt32(pCount);

                    // get a pointer to the descriptors
                    IntPtr pDescriptors =
                        new IntPtr(globalMem.Memory.ToInt32() + Marshal.SizeOf(count));

                    // allocate the array of structures that will be returned
                    FileDescriptor[] descriptors = new FileDescriptor[count];

                    // determine the sizes of the various data elements
                    const int FILENAME_BUFFER_SIZE = 260;
                    int       headerSize           = Marshal.SizeOf(typeof(FILEDESCRIPTOR_HEADER));
                    int       fileNameSize         = bFileNameIsWide ? FILENAME_BUFFER_SIZE * 2 : FILENAME_BUFFER_SIZE;
                    int       totalSize            = headerSize + fileNameSize;

                    // iterate through the memory block copying the FILEDESCRIPTOR structures
                    for (int i = 0; i < count; i++)
                    {
                        // determine the addresses of the various data elements
                        IntPtr pAddr         = new IntPtr(pDescriptors.ToInt32() + (i * totalSize));
                        IntPtr pFileNameAddr = new IntPtr(pAddr.ToInt32() + headerSize);

                        // copy the header
                        descriptors[i].header = (FILEDESCRIPTOR_HEADER)
                                                Marshal.PtrToStructure(pAddr, typeof(FILEDESCRIPTOR_HEADER));

                        // copy the file name (use Unicode or Ansi depending upon descriptor type)
                        if (bFileNameIsWide)
                        {
                            descriptors[i].fileName = Marshal.PtrToStringUni(pFileNameAddr);
                        }
                        else
                        {
                            descriptors[i].fileName = Marshal.PtrToStringAnsi(pFileNameAddr);
                        }
                    }

                    // return the descriptors
                    return(descriptors);
                }
            }
        }
        /// <summary>
        /// Utility function to extract an array of file contents file descriptors from
        /// an IDataObject instnace
        /// </summary>
        /// <param name="dataObject">data object to extract descriptors from</param>
        /// <returns>array of file descriptors</returns>
        public static FileDescriptor[] GetFileDescriptors(IDataObject dataObject)
        {
            // Use an OleDataObject
            OleDataObject oleDataObject = OleDataObject.CreateFrom(dataObject);
            if (oleDataObject == null)
            {
                const string message = "DataObject not valid for FileContents!";
                Debug.Fail(message);
                throw
                    new InvalidOperationException(message);
            }

            // Try to get the data as FileGroupDescriptorW then try to get it
            // as FileGroupDescriptor
            bool bFileNameIsWide;
            OleStgMediumHGLOBAL stgMedium = (OleStgMediumHGLOBAL)oleDataObject.GetData(
                                                                      DataFormatsEx.FileGroupDescriptorWFormat, TYMED.HGLOBAL);
            if (stgMedium != null)
            {
                bFileNameIsWide = true;
            }
            else
            {
                stgMedium = (OleStgMediumHGLOBAL)oleDataObject.GetData(
                                                      DataFormatsEx.FileGroupDescriptorFormat, TYMED.HGLOBAL);

                if (stgMedium != null)
                {
                    bFileNameIsWide = false;
                }
                else
                {
                    const string message = "File group descriptor not available!";
                    Debug.Fail(message);
                    throw
                        new InvalidOperationException(message);
                }
            }

            // Copy the descriptors
            using (stgMedium)
            {
                using (HGlobalLock globalMem = new HGlobalLock(stgMedium.Handle))
                {
                    // get a pointer to the count
                    IntPtr pCount = globalMem.Memory;

                    // determine the number of file descriptors
                    Int32 count = Marshal.ReadInt32(pCount);

                    // get a pointer to the descriptors
                    IntPtr pDescriptors =
                        new IntPtr(globalMem.Memory.ToInt32() + Marshal.SizeOf(count));

                    // allocate the array of structures that will be returned
                    FileDescriptor[] descriptors = new FileDescriptor[count];

                    // determine the sizes of the various data elements
                    const int FILENAME_BUFFER_SIZE = 260;
                    int headerSize = Marshal.SizeOf(typeof(FILEDESCRIPTOR_HEADER));
                    int fileNameSize = bFileNameIsWide ? FILENAME_BUFFER_SIZE * 2 : FILENAME_BUFFER_SIZE;
                    int totalSize = headerSize + fileNameSize;

                    // iterate through the memory block copying the FILEDESCRIPTOR structures
                    for (int i = 0; i < count; i++)
                    {
                        // determine the addresses of the various data elements
                        IntPtr pAddr = new IntPtr(pDescriptors.ToInt32() + (i * totalSize));
                        IntPtr pFileNameAddr = new IntPtr(pAddr.ToInt32() + headerSize);

                        // copy the header
                        descriptors[i].header = (FILEDESCRIPTOR_HEADER)
                                                Marshal.PtrToStructure(pAddr, typeof(FILEDESCRIPTOR_HEADER));

                        // copy the file name (use Unicode or Ansi depending upon descriptor type)
                        if (bFileNameIsWide)
                            descriptors[i].fileName = Marshal.PtrToStringUni(pFileNameAddr);
                        else
                            descriptors[i].fileName = Marshal.PtrToStringAnsi(pFileNameAddr);
                    }

                    // return the descriptors
                    return descriptors;
                }
            }
        }
 /// <summary>
 /// Initialize using file meta-info and the OleDataObject from which
 /// to fetch the file contents when it is time to write them
 /// </summary>
 /// <param name="fileDescriptor"></param>
 /// <param name="dataObject"></param>
 /// <param name="fileIndex"></param>
 private FileItemFromFileContents(
     FileDescriptor fileDescriptor, OleDataObject oleDataObject, int fileIndex)
     : base(fileDescriptor.fileName)
 {
     this.fileDescriptor = fileDescriptor;
     this.oleDataObject = oleDataObject;
     this.fileIndex = fileIndex;
 }