/// <summary> /// Create an array of FileItem objects based on a data object that contains /// FileContents /// </summary> /// <param name="dataObject">data object containing FileContents</param> /// <returns>Array of FileItem objects. Returns null if the FileContents /// could not be extracted from the passed dataObject</returns> public static FileItem[] CreateArrayFromDataObject(IDataObject dataObject) { try { // get the ole data object OleDataObject oleDataObject = OleDataObject.CreateFrom(dataObject); if (oleDataObject == null) { Debug.Fail("Unable to access OleDataObject!"); return(null); } // get an array of file descriptors specifying the file contents FileDescriptor[] fileDescriptors = FileContentsHelper.GetFileDescriptors(dataObject); // allocate a FileItem object for each descriptor FileItem[] fileItems = new FileItem[fileDescriptors.Length]; // initialize the file items for (int i = 0; i < fileDescriptors.Length; i++) { fileItems[i] = new FileItemFromFileContents( fileDescriptors[i], oleDataObject, i); } // return the file items return(fileItems); } // this is a sketchy operation involving all kinds of interop voodoo, // if we fail in release mode it is likely due to a drop source giving // us invalid or unexpected data -- handle this gracefully while // logging the error catch (Exception e) { Debug.Fail("Unexpected error accessing FileContents", e.Message); return(null); } }
/// <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); } } }