/// <summary> /// Copy a global memory block into a file /// </summary> /// <param name="hGlobal">global memory block</param> /// <param name="destFileName">file to copy global memory into</param> private void CopyHGLOBALToFile(IntPtr hGlobal, string destFileName) { HGlobalLock globalMem = new HGlobalLock(hGlobal); using (globalMem) { FileStream destination = new FileStream(destFileName, FileMode.Create, FileAccess.ReadWrite); using (destination) { // use Win32 WriteFile so we can blast the entire unamanged memory // block in a single call (if we wanted to use managed file io // methods we would have to copy the entire memory block into // unmanaged memory first) uint bytesWritten; bool success = Kernel32.WriteFile( destination.SafeFileHandle, globalMem.Memory, globalMem.Size.ToUInt32(), out bytesWritten, IntPtr.Zero); if (!success) { throw new Win32Exception(Marshal.GetLastWin32Error(), "Error occured attempting to write file: " + destination.Name); } } } }
/// <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> /// Create a cloned copy of the the passed storage medium. This method works via /// a combination of actually copying underling data and incrementing reference /// counts on embedded objects. /// </summary> /// <param name="stgmIn">storage medium in</param> /// <param name="stgmOut">storage medium out</param> /// <returns>HRESULT.S_OK if the medium was successfully cloned, various /// OLE error codes if an error occurs during the clone </returns> private int CloneStgMedium(STGMEDIUM stgmIn, ref STGMEDIUM stgmOut) { // copy storage type stgmOut.tymed = stgmIn.tymed; // copy or add ref count to the actual data switch (stgmIn.tymed) { // global memory blocks get copied case TYMED.HGLOBAL: using (HGlobalLock input = new HGlobalLock(stgmIn.contents)) stgmOut.contents = input.Clone(); break; // COM interfaces get copied w/ their ref-count incremented case TYMED.ISTREAM: case TYMED.ISTORAGE: stgmOut.contents = stgmIn.contents; Marshal.AddRef(stgmOut.contents); break; // don't know how to clone other storage medium types (return error) case TYMED.ENHMF: case TYMED.FILE: case TYMED.GDI: case TYMED.MFPICT: default: return DV_E.TYMED; } // copy pUnkForRelease and add a reference count on it if there is one stgmOut.pUnkForRelease = stgmIn.pUnkForRelease; if (stgmOut.pUnkForRelease != IntPtr.Zero) Marshal.AddRef(stgmOut.pUnkForRelease); // return success return HRESULT.S_OK; }