Whoever already used Drag & Drop in a .NET Application will think this is way to easy to mention somewhere: but you didn't think about MSOffice yet ;)
I found some Code (see Bottom of this Article) in an MSDN-Forum which was not really straight forward so my search continued.
Thanks to a Guy named David Ewen, who has written a very nice Wrapper for this "Mess" and refactored it to a more readable way, it is now broken down to a Level where anybody can use the Stuff.
Read his Article and get the Wrapper HERE.
The most convincing thing about this Wrapper is the possibility to drag more than one attachment: I've found several other attempts to achieve this behavior (i.e. Outlook.Interop), but nothing is worth mentioning here :)
Step over Code and go to Comments
#region using System; using System.Collections; using System.ComponentModel; using System.Drawing; using System.IO; using System.Runtime.InteropServices; using System.Security; using System.Windows.Forms; #endregion namespace DragDropPanel { public delegate void FilenameDroppedHandler(object sender, string filename); public delegate void StreamDroppedHandler(object sender, string filename, NativeMethods.IStream stream); public delegate void StorageDroppedHandler(object sender, string filename, NativeMethods.IStorage storage); public delegate void DroppedByteArrayAvailableHandler(object sender, string filename, byte[] bytes); public interface IDropTargetControl { void Activate(); void DragEnter(string filename); void DragLeave(); void DragOver(); void DragDrop(); } public class FileDropTarget : NativeMethods.IOleDropTarget { private readonly IDropTargetControl owner; private DragDropEffects cachedEffect; public FileDropTarget(IDropTargetControl owner) { this.owner = owner; cachedEffect = DragDropEffects.None; } #region IOleDropTarget Members int NativeMethods.IOleDropTarget.OleDragEnter(object pDataObj, int grfKeyState, long pt, ref int pdwEffect) { // // Default to DROPEFFECT_NONE cachedEffect = DragDropEffects.None; // // Does the data object support CFSTR_FILEDESCRIPTOR if (QueryGetFileDescriptorArray((NativeMethods.IOleDataObject)pDataObj)) { // Retrieve the list of files/folders NativeMethods.IOleDataObject dataObject = (NativeMethods.IOleDataObject)pDataObj; NativeMethods.FILEDESCRIPTOR[] files = GetFileDescriptorArray(dataObject); if (files == null || files.Length == 0) { cachedEffect = DragDropEffects.Copy; string filename = GetFilename(dataObject); owner.DragEnter(filename); } else { NativeMethods.FILEDESCRIPTOR firstFile = files[0]; string firstFilename = firstFile.cFileName; // Indicate that we can copy the item(s) cachedEffect = DragDropEffects.Copy; owner.DragEnter(firstFilename); } } pdwEffect = (int)cachedEffect; return NativeMethods.S_OK; } int NativeMethods.IOleDropTarget.OleDragOver(int grfKeyState, long pt, ref int pdwEffect) { pdwEffect = (int)cachedEffect; owner.DragOver(); return NativeMethods.S_OK; } int NativeMethods.IOleDropTarget.OleDragLeave() { cachedEffect = DragDropEffects.None; owner.DragLeave(); return NativeMethods.S_OK; } int NativeMethods.IOleDropTarget.OleDrop(object pDataObj, int grfKeyState, long pt, ref int pdwEffect) { int result; // // Default to DROPEFFECT_NONE cachedEffect = DragDropEffects.None; // Retrieve the list of files/folders NativeMethods.IOleDataObject dataObject = (NativeMethods.IOleDataObject)pDataObj; NativeMethods.FILEDESCRIPTOR[] files = GetFileDescriptorArray(dataObject); if (files != null && files.Length > 0) { result = CopyFileContents((NativeMethods.IOleDataObject)pDataObj, files); if (NativeMethods.Succeeded(result)) { owner.DragDrop(); cachedEffect = DragDropEffects.Copy; owner.Activate(); } } else { string filename = GetFilename(dataObject); SaveFilename(filename); owner.DragDrop(); owner.Activate(); } pdwEffect = (int)cachedEffect; return NativeMethods.S_OK; } #endregion private string GetFilename(NativeMethods.IOleDataObject dataObject) { NativeMethods.STGMEDIUM medium = new NativeMethods.STGMEDIUM(); NativeMethods.FORMATETC format = new NativeMethods.FORMATETC(); format.cfFormat = (ushort)NativeMethods.ShellClipboardFormats.CFSTR_FILENAMEW.Id; format.dwAspect = NativeMethods.DVASPECT_CONTENT; format.lindex = -1; format.ptd = new IntPtr(0); format.tymed = NativeMethods.TYMED_HGLOBAL | NativeMethods.TYMED_ISTORAGE | NativeMethods.TYMED_ISTREAM | NativeMethods.TYMED_FILE; dataObject.OleGetData(format, medium); string filename; unsafe { IntPtr ptr = NativeMethods.GlobalLock(new HandleRef(null, medium.unionmember)); filename = new string((char*)ptr); NativeMethods.GlobalUnlock(new HandleRef(null, medium.unionmember)); } return filename; } private NativeMethods.FILEDESCRIPTOR[] GetFileDescriptorArray(NativeMethods.IOleDataObject dataObject) { int result; NativeMethods.FILEDESCRIPTOR[] files; NativeMethods.FORMATETC format = new NativeMethods.FORMATETC(); NativeMethods.STGMEDIUM medium = new NativeMethods.STGMEDIUM(); Type formatType; HandleRef hGlobal; IntPtr pdata; // // Query the data object for CFSTR_FILEDESCRIPTORW format.cfFormat = (ushort)NativeMethods.ShellClipboardFormats.CFSTR_FILEDESCRIPTORW.Id; format.dwAspect = NativeMethods.DVASPECT_CONTENT; format.lindex = -1; format.ptd = new IntPtr(0); format.tymed = NativeMethods.TYMED_HGLOBAL; result = dataObject.OleGetData(format, medium); if (NativeMethods.Succeeded(result)) { formatType = typeof(NativeMethods.FILEDESCRIPTORW); } else { // // Query the data object for CFSTR_FILEDESCRIPTORA format = new NativeMethods.FORMATETC(); format.cfFormat = (ushort)NativeMethods.ShellClipboardFormats.CFSTR_FILEDESCRIPTORA.Id; format.dwAspect = NativeMethods.DVASPECT_CONTENT; format.lindex = -1; format.ptd = new IntPtr(0); format.tymed = NativeMethods.TYMED_HGLOBAL; result = dataObject.OleGetData(format, medium); if (NativeMethods.Succeeded(result)) { formatType = typeof(NativeMethods.FILEDESCRIPTORA); } else { // // This data object does not support CFSTR_FILEDESCRIPTOR return new NativeMethods.FILEDESCRIPTOR[0]; } } hGlobal = new HandleRef(null, medium.unionmember); pdata = NativeMethods.GlobalLock(hGlobal); try { // // Determine the number of items in the array NativeMethods.FILEGROUPDESCRIPTORW fgd = (NativeMethods.FILEGROUPDESCRIPTORW) Marshal.PtrToStructure(pdata, typeof(NativeMethods.FILEGROUPDESCRIPTORW)); // // Allocate an array of FILEDESCRIPTOR structures files = new NativeMethods.FILEDESCRIPTOR[fgd.cItems]; // // Set our pointer offset to the beginning of the FILEDESCRIPTOR* array pdata = (IntPtr)((int)pdata + Marshal.SizeOf(pdata)); // // Walk the array, converting each FILEDESCRIPTOR* to a FILEDESCRIPTOR for (int index = 0; index < fgd.cItems; index++) { NativeMethods.FILEDESCRIPTORA fdA = (NativeMethods.FILEDESCRIPTORA) Marshal.PtrToStructure(pdata, typeof(NativeMethods.FILEDESCRIPTORA)); NativeMethods.FILEDESCRIPTORW fdW = (NativeMethods.FILEDESCRIPTORW) Marshal.PtrToStructure(pdata, typeof(NativeMethods.FILEDESCRIPTORW)); files[index] = new NativeMethods.FILEDESCRIPTOR(); if (formatType == typeof(NativeMethods.FILEDESCRIPTORW)) { files[index].dwFlags = fdW.dwFlags; files[index].clsid = fdW.clsid; files[index].sizel = fdW.sizel; files[index].pointl = fdW.pointl; files[index].dwFileAttributes = fdW.dwFileAttributes; files[index].ftCreationTime = fdW.ftCreationTime; files[index].ftLastAccessTime = fdW.ftLastAccessTime; files[index].ftLastWriteTime = fdW.ftLastWriteTime; files[index].nFileSizeHigh = fdW.nFileSizeHigh; files[index].nFileSizeLow = fdW.nFileSizeLow; files[index].cFileName = fdW.cFileName; } else { files[index].dwFlags = fdA.dwFlags; files[index].clsid = fdA.clsid; files[index].sizel = fdA.sizel; files[index].pointl = fdA.pointl; files[index].dwFileAttributes = fdA.dwFileAttributes; files[index].ftCreationTime = fdA.ftCreationTime; files[index].ftLastAccessTime = fdA.ftLastAccessTime; files[index].ftLastWriteTime = fdA.ftLastWriteTime; files[index].nFileSizeHigh = fdA.nFileSizeHigh; files[index].nFileSizeLow = fdA.nFileSizeLow; files[index].cFileName = fdA.cFileName; } // // Advance to the next item in the array pdata = (IntPtr)((int)pdata + Marshal.SizeOf(formatType)); } } catch { // // Bail on any exceptions files = new NativeMethods.FILEDESCRIPTOR[0]; } NativeMethods.GlobalUnlock(hGlobal); NativeMethods.ReleaseStgMedium(medium); return files; } private int CopyFileContents(NativeMethods.IOleDataObject dataObject, NativeMethods.FILEDESCRIPTOR[] files) { int result = NativeMethods.E_FAIL; NativeMethods.STGMEDIUM medium = new NativeMethods.STGMEDIUM(); if (files.Length > 0) { for (int index = 0; index < files.Length; index++) { String filename = files[index].cFileName; // // If the object is a folder, make sure it exists. if ((files[index].dwFileAttributes & NativeMethods.FILE_ATTRIBUTE_DIRECTORY) == NativeMethods.FILE_ATTRIBUTE_DIRECTORY) { // // TODO: Make sure that the specified directory exists } else { // // Otherwise, create the file and save its contents result = SaveToFile(dataObject, NativeMethods.ShellClipboardFormats.CFSTR_FILECONTENTS, index, filename); if (NativeMethods.Failed(result)) { break; } } } NativeMethods.ReleaseStgMedium(medium); } return result; } private int SaveToFile(NativeMethods.IOleDataObject pdata, DataFormats.Format cfFormat, int index, String filename) { int result; NativeMethods.FORMATETC format = new NativeMethods.FORMATETC(); NativeMethods.STGMEDIUM medium = new NativeMethods.STGMEDIUM(); // // Get the data for this file format.cfFormat = (ushort)cfFormat.Id; format.dwAspect = NativeMethods.DVASPECT_CONTENT; format.lindex = index; format.tymed = NativeMethods.TYMED_HGLOBAL | NativeMethods.TYMED_ISTORAGE | NativeMethods.TYMED_ISTREAM; result = pdata.OleGetData(format, medium); if (NativeMethods.Failed(result)) { return result; } // // Save the data to the specified file based on the medium try { switch (medium.tymed) { case NativeMethods.TYMED_HGLOBAL: // TODO: Save HGLOBAL data to a file break; case NativeMethods.TYMED_ISTREAM: SaveStreamToStream(filename, (NativeMethods.IStream) Marshal.GetTypedObjectForIUnknown(medium.unionmember, typeof(NativeMethods.IStream))); break; case NativeMethods.TYMED_ISTORAGE: SaveStorageToStream(filename, (NativeMethods.IStorage) Marshal.GetTypedObjectForIUnknown(medium.unionmember, typeof(NativeMethods.IStorage))); break; } } catch { result = NativeMethods.E_FAIL; } NativeMethods.ReleaseStgMedium(medium); return result; } public event StorageDroppedHandler StorageDropped; public event StreamDroppedHandler StreamDropped; public event FilenameDroppedHandler FilenameDropped; // public event EventHandler HGlobalDropped; public void SaveFilename(string filename) { if (FilenameDropped != null) { FilenameDropped(this, filename); } } public void SaveStreamToStream(string filename, NativeMethods.IStream stream) { if (StreamDropped != null) { StreamDropped(this, filename, stream); } } public void SaveStorageToStream(string filename, NativeMethods.IStorage storage) { if (StorageDropped != null) { StorageDropped(this, filename, storage); } } private bool QueryGetFileDescriptorArray(NativeMethods.IOleDataObject dataObject) { // // Called to determine if the specified data object supports // CFSTR_FILEDESCRIPTORA or CFSTR_FILEDESCRIPTORW int result; NativeMethods.FORMATETC format = new NativeMethods.FORMATETC(); // // Determine if the data object supports CFSTR_FILEDESCRIPTORA format.cfFormat = (ushort)NativeMethods.ShellClipboardFormats.CFSTR_FILEDESCRIPTORA.Id; format.dwAspect = NativeMethods.DVASPECT_CONTENT; format.lindex = -1; format.ptd = new IntPtr(0); format.tymed = NativeMethods.TYMED_HGLOBAL; result = dataObject.OleQueryGetData(format); if (NativeMethods.Succeeded(result)) { return true; } // // Determine if the data object supports CFSTR_FILEDESCRIPTORW format.cfFormat = (ushort)NativeMethods.ShellClipboardFormats.CFSTR_FILEDESCRIPTORW.Id; format.dwAspect = NativeMethods.DVASPECT_CONTENT; format.lindex = -1; format.ptd = new IntPtr(0); format.tymed = NativeMethods.TYMED_HGLOBAL; result = dataObject.OleQueryGetData(format); if (NativeMethods.Succeeded(result)) { return true; } return false; } } public class NativeMethods { public const short CF_BITMAP = 2; public const short CF_DIB = 8; public const short CF_DIF = 5; public const short CF_DSPBITMAP = 0x0082; public const short CF_DSPENHMETAFILE = 0x008E; public const short CF_DSPMETAFILEPICT = 0x0083; public const short CF_DSPTEXT = 0x0081; public const short CF_ENHMETAFILE = 14; public const short CF_GDIOBJFIRST = 0x0300, CF_GDIOBJLAST = 0x03FF; public const short CF_HDROP = 15, CF_LOCALE = 16, CF_MAX = 17; public const short CF_METAFILEPICT = 3; public const short CF_OEMTEXT = 7; public const short CF_OWNERDISPLAY = 0x0080; public const short CF_PALETTE = 9, CF_PENDATA = 10; public const short CF_PRIVATEFIRST = 0x0200, CF_PRIVATELAST = 0x02FF; public const short CF_RIFF = 11; public const short CF_SYLK = 4; public const short CF_TEXT = 1; public const short CF_TIFF = 6; public const short CF_UNICODETEXT = 13; public const short CF_WAVE = 12; public const int DROPEFFECT_COPY = 1; public const int DROPEFFECT_LINK = 4; public const int DROPEFFECT_MOVE = 2; public const int DROPEFFECT_NONE = 0; public const int DROPEFFECT_SCROLL = (unchecked((int)0x80000000)); public const int DVASPECT_CONTENT = 1; public const int DVASPECT_DOCPRINT = 8; public const int DVASPECT_ICON = 4; public const int DVASPECT_THUMBNAIL = 2; public const int E_FAIL = (unchecked((int)0x80004005)); public const uint FILE_ATTRIBUTE_ARCHIVE = 0x00000020; public const uint FILE_ATTRIBUTE_DIRECTORY = 0x00000010; public const uint FILE_ATTRIBUTE_HIDDEN = 0x00000002; public const uint FILE_ATTRIBUTE_NORMAL = 0x00000080; public const uint FILE_ATTRIBUTE_READONLY = 0x00000001; public const uint FILE_ATTRIBUTE_SYSTEM = 0x00000004; public const uint FILE_ATTRIBUTE_TEMPORARY = 0x00000100; public const int S_FALSE = 1; public const int S_OK = 0; public const int STATFLAG_DEFAULT = 0, STATFLAG_NONAME = 1, STATFLAG_NOOPEN = 2; public const int STGC_CONSOLIDATE = 8; public const int STGC_DANGEROUSLYCOMMITMERELYTODISKCACHE = 4; public const int STGC_DEFAULT = 0; public const int STGC_ONLYIFCURRENT = 2; public const int STGC_OVERWRITE = 1; public const uint STGM_CONVERT = 0x00020000; public const uint STGM_CREATE = 0x00001000; public const uint STGM_DELETEONRELEASE = 0x04000000; public const uint STGM_DIRECT = 0x00000000; public const uint STGM_DIRECT_SWMR = 0x00400000; public const uint STGM_FAILIFTHERE = 0x00000000; public const uint STGM_NOSCRATCH = 0x00100000; public const uint STGM_NOSNAPSHOT = 0x00200000; public const uint STGM_PRIORITY = 0x00040000; public const uint STGM_READ = 0x00000000; public const uint STGM_READWRITE = 0x00000002, STGM_SHARE_DENY_NONE = 0x00000040, STGM_SHARE_DENY_READ = 0x00000030, STGM_SHARE_DENY_WRITE = 0x00000020, STGM_SHARE_EXCLUSIVE = 0x00000010; public const uint STGM_SIMPLE = 0x08000000; public const uint STGM_TRANSACTED = 0x00010000; public const uint STGM_WRITE = 0x00000001; public const int TYMED_ENHMF = 64; public const int TYMED_FILE = 2; public const int TYMED_GDI = 16; public const int TYMED_HGLOBAL = 1; public const int TYMED_ISTORAGE = 8; public const int TYMED_ISTREAM = 4; public const int TYMED_MFPICT = 32; public const int TYMED_NULL = 0; public static bool Succeeded(int hr) { return (hr >= 0); } public static bool Failed(int hr) { return (hr < 0); } [DllImport("USER32.DLL", CharSet = CharSet.Auto, SetLastError = true)] public static extern int RegisterClipboardFormat(string format); [DllImport("KERNEL32.DLL", CharSet = CharSet.None, SetLastError = true)] public static extern IntPtr GlobalLock(HandleRef hGlobal); [DllImport("KERNEL32.DLL", CharSet = CharSet.None, SetLastError = true)] public static extern bool GlobalUnlock(HandleRef hGlobal); [DllImport("OLE32.DLL", ExactSpelling = true, CharSet = CharSet.Auto)] public static extern int OleGetClipboard([In, Out] ref IOleDataObject data); [DllImport("OLE32.DLL", ExactSpelling = true, CharSet = CharSet.Auto, PreserveSig = false)] public static extern void RegisterDragDrop(HandleRef hwnd, IOleDropTarget target); [DllImport("OLE32.DLL", CharSet = CharSet.None)] public static extern void ReleaseStgMedium(STGMEDIUM pmedium); [DllImport("OLE32.DLL", ExactSpelling = true, CharSet = CharSet.Auto, PreserveSig = false)] public static extern void RevokeDragDrop(HandleRef hwnd); [DllImport("OLE32.DLL", CharSet = CharSet.Unicode, PreserveSig = false)] public static extern IStorage StgCreateDocfile(String pwcsName, uint grfMode, uint reserved); [DllImport("ole32.dll", PreserveSig = false)] public static extern ILockBytes CreateILockBytesOnHGlobal(IntPtr hGlobal, bool fDeleteOnRelease); [DllImport("OLE32.DLL", CharSet = CharSet.Auto, PreserveSig = false)] public static extern IntPtr GetHGlobalFromILockBytes(ILockBytes pLockBytes); [DllImport("OLE32.DLL", CharSet = CharSet.Unicode, PreserveSig = false)] public static extern IStorage StgCreateDocfileOnILockBytes(ILockBytes plkbyt, uint grfMode, uint reserved); #region IEnumFORMATETC interface [ ComImport, Guid("00000103-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown) ] public interface IEnumFORMATETC { [PreserveSig] int Next( [In, MarshalAs(UnmanagedType.U4)] int celt, [Out] FORMATETC rgelt, [In, Out, MarshalAs(UnmanagedType.LPArray)] int[] pceltFetched); [PreserveSig] int Skip( [In, MarshalAs(UnmanagedType.U4)] int celt); [PreserveSig] int Reset(); [PreserveSig] int Clone( [Out, MarshalAs(UnmanagedType.LPArray)] IEnumFORMATETC[] ppenum); } #endregion #region IDataObject interface [ ComImport, Guid("0000010E-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), SuppressUnmanagedCodeSecurity ] public interface IOleDataObject { [PreserveSig] int OleGetData( FORMATETC pFormatetc, [Out] STGMEDIUM pMedium); [PreserveSig] int OleGetDataHere( FORMATETC pFormatetc, [In, Out] STGMEDIUM pMedium); [PreserveSig] int OleQueryGetData( FORMATETC pFormatetc); [PreserveSig] int OleGetCanonicalFormatEtc( FORMATETC pformatectIn, [Out] FORMATETC pformatetcOut); [PreserveSig] int OleSetData( FORMATETC pFormatectIn, STGMEDIUM pmedium, int fRelease); [return: MarshalAs(UnmanagedType.Interface)] IEnumFORMATETC OleEnumFormatEtc( [In, MarshalAs(UnmanagedType.U4)] int dwDirection); [PreserveSig] int OleDAdvise( FORMATETC pFormatetc, [In, MarshalAs(UnmanagedType.U4)] int advf, [In, MarshalAs(UnmanagedType.Interface)] object pAdvSink, [Out, MarshalAs(UnmanagedType.LPArray)] int[] pdwConnection); [PreserveSig] int OleDUnadvise( [In, MarshalAs(UnmanagedType.U4)] int dwConnection); [PreserveSig] int OleEnumDAdvise( [Out, MarshalAs(UnmanagedType.LPArray)] object[] ppenumAdvise); } #endregion #region IDataObject interface [ ComImport, Guid("00000122-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown) ] public interface IOleDropTarget { [PreserveSig] int OleDragEnter( [In, MarshalAs(UnmanagedType.Interface)] object pDataObj, [In, MarshalAs(UnmanagedType.U4)] int grfKeyState, [In, MarshalAs(UnmanagedType.U8)] long pt, [In, Out] ref int pdwEffect); [PreserveSig] int OleDragOver( [In, MarshalAs(UnmanagedType.U4)] int grfKeyState, [In, MarshalAs(UnmanagedType.U8)] long pt, [In, Out] ref int pdwEffect); [PreserveSig] int OleDragLeave(); [PreserveSig] int OleDrop( [In, MarshalAs(UnmanagedType.Interface)] object pDataObj, [In, MarshalAs(UnmanagedType.U4)] int grfKeyState, [In, MarshalAs(UnmanagedType.U8)] long pt, [In, Out] ref int pdwEffect); } #endregion #region ILockByte interface [ComImport, Guid("0000000A-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface ILockBytes { void ReadAt([In, MarshalAs(UnmanagedType.U8)] long ulOffset, [Out] IntPtr pv, [In, MarshalAs(UnmanagedType.U4)] int cb, [Out, MarshalAs(UnmanagedType.LPArray)] int[] pcbRead); void WriteAt([In, MarshalAs(UnmanagedType.U8)] long ulOffset, IntPtr pv, [In, MarshalAs(UnmanagedType.U4)] int cb, [Out, MarshalAs(UnmanagedType.LPArray)] int[] pcbWritten); void Flush(); void SetSize([In, MarshalAs(UnmanagedType.U8)] long cb); void LockRegion([In, MarshalAs(UnmanagedType.U8)] long libOffset, [In, MarshalAs(UnmanagedType.U8)] long cb, [In, MarshalAs(UnmanagedType.U4)] int dwLockType); void UnlockRegion([In, MarshalAs(UnmanagedType.U8)] long libOffset, [In, MarshalAs(UnmanagedType.U8)] long cb, [In, MarshalAs(UnmanagedType.U4)] int dwLockType); void Stat([Out] STATSTG pstatstg, [In, MarshalAs(UnmanagedType.U4)] int grfStatFlag); } #endregion #region IStream interface [ComImport, Guid("0000000C-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IStream { int Read( IntPtr buf, int len); int Write( IntPtr buf, int len); [return: MarshalAs(UnmanagedType.I8)] long Seek( [In, MarshalAs(UnmanagedType.I8)] long dlibMove, int dwOrigin); void SetSize( [In, MarshalAs(UnmanagedType.I8)] long libNewSize); [return: MarshalAs(UnmanagedType.I8)] long CopyTo( [In, MarshalAs(UnmanagedType.Interface)] IStream pstm, [In, MarshalAs(UnmanagedType.I8)] long cb, [Out, MarshalAs(UnmanagedType.LPArray)] long[] pcbRead); void Commit( int grfCommitFlags); void Revert(); void LockRegion( [In, MarshalAs(UnmanagedType.I8)] long libOffset, [In, MarshalAs(UnmanagedType.I8)] long cb, int dwLockType); void UnlockRegion( [In, MarshalAs(UnmanagedType.I8)] long libOffset, [In, MarshalAs(UnmanagedType.I8)] long cb, int dwLockType); void Stat( [Out] STATSTG pStatstg, int grfStatFlag); [return: MarshalAs(UnmanagedType.Interface)] IStream Clone(); } #endregion #region IStorage interface [Flags] public enum STGM { // Fields STGM_CONVERT = 0x20000, STGM_CREATE = 0x1000, STGM_DELETEONRELEASE = 0x4000000, STGM_DIRECT = 0, STGM_DIRECT_SWMR = 0x400000, STGM_FAILIFTHERE = 0, STGM_NOSCRATCH = 0x100000, STGM_NOSNAPSHOT = 0x200000, STGM_PRIORITY = 0x40000, STGM_READ = 0, STGM_READWRITE = 2, STGM_SHARE_DENY_NONE = 0x40, STGM_SHARE_DENY_READ = 0x30, STGM_SHARE_DENY_WRITE = 0x20, STGM_SHARE_EXCLUSIVE = 0x10, STGM_SIMPLE = 0x8000000, STGM_TRANSACTED = 0x10000, STGM_WRITE = 1 } #region Nested type: IEnumSTATSTG [ComImport] [Guid("0000000d-0000-0000-C000-000000000046")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IEnumSTATSTG { // The user needs to allocate an STATSTG array whose size is celt. [PreserveSig] uint Next( uint celt, [MarshalAs(UnmanagedType.LPArray), Out] STATSTG[] rgelt, out uint pceltFetched ); void Skip(uint celt); void Reset(); [return: MarshalAs(UnmanagedType.Interface)] IEnumSTATSTG Clone(); } #endregion #region Nested type: IStorage [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("0000000B-0000-0000-C000-000000000046")] public interface IStorage { [return: MarshalAs(UnmanagedType.Interface)] IStream CreateStream([In, MarshalAs(UnmanagedType.BStr)] string pwcsName, [In, MarshalAs(UnmanagedType.U4)] int grfMode, [In, MarshalAs(UnmanagedType.U4)] int reserved1, [In, MarshalAs(UnmanagedType.U4)] int reserved2); [return: MarshalAs(UnmanagedType.Interface)] IStream OpenStream([In, MarshalAs(UnmanagedType.BStr)] string pwcsName, IntPtr reserved1, [In, MarshalAs(UnmanagedType.U4)] int grfMode, [In, MarshalAs(UnmanagedType.U4)] int reserved2); [return: MarshalAs(UnmanagedType.Interface)] IStorage CreateStorage([In, MarshalAs(UnmanagedType.BStr)] string pwcsName, [In, MarshalAs(UnmanagedType.U4)] int grfMode, [In, MarshalAs(UnmanagedType.U4)] int reserved1, [In, MarshalAs(UnmanagedType.U4)] int reserved2); [return: MarshalAs(UnmanagedType.Interface)] IStorage OpenStorage([In, MarshalAs(UnmanagedType.BStr)] string pwcsName, IntPtr pstgPriority, [In, MarshalAs(UnmanagedType.U4)] int grfMode, IntPtr snbExclude, [In, MarshalAs(UnmanagedType.U4)] int reserved); void CopyTo(int ciidExclude, [In, MarshalAs(UnmanagedType.LPArray)] Guid[] pIIDExclude, IntPtr snbExclude, [In, MarshalAs(UnmanagedType.Interface)] IStorage stgDest); void MoveElementTo([In, MarshalAs(UnmanagedType.BStr)] string pwcsName, [In, MarshalAs(UnmanagedType.Interface)] IStorage stgDest, [In, MarshalAs(UnmanagedType.BStr)] string pwcsNewName, [In, MarshalAs(UnmanagedType.U4)] int grfFlags); void Commit(int grfCommitFlags); void Revert(); void EnumElements([In, MarshalAs(UnmanagedType.U4)] int reserved1, IntPtr reserved2, [In, MarshalAs(UnmanagedType.U4)] int reserved3, [MarshalAs(UnmanagedType.Interface)] out object ppVal); void DestroyElement([In, MarshalAs(UnmanagedType.BStr)] string pwcsName); void RenameElement([In, MarshalAs(UnmanagedType.BStr)] string pwcsOldName, [In, MarshalAs(UnmanagedType.BStr)] string pwcsNewName); void SetElementTimes([In, MarshalAs(UnmanagedType.BStr)] string pwcsName, [In] FILETIME pctime, [In] FILETIME patime, [In] FILETIME pmtime); void SetClass([In] ref Guid clsid); void SetStateBits(int grfStateBits, int grfMask); void Stat([Out] STATSTG pStatStg, int grfStatFlag); } #endregion #region Nested type: tagRemSNB [StructLayout(LayoutKind.Sequential)] public struct tagRemSNB { public uint ulCntStr; public uint ulCntChar; public IntPtr rgString; } #endregion #endregion #region Shell Clipboard Formats public class ShellClipboardFormats { public static DataFormats.Format CFSTR_SHELLIDLIST { get { return DataFormats.GetFormat("Shell IDList Array"); } } public static DataFormats.Format CFSTR_SHELLIDLISTOFFSET { get { return DataFormats.GetFormat("Shell Objects Offsets"); } } public static DataFormats.Format CFSTR_NETRESOURCES { get { return DataFormats.GetFormat("Net Resource"); } } public static DataFormats.Format CFSTR_FILEDESCRIPTORA { get { return DataFormats.GetFormat("FileGroupDescriptor"); } } public static DataFormats.Format CFSTR_FILEDESCRIPTORW { get { return DataFormats.GetFormat("FileGroupDescriptorW"); } } public static DataFormats.Format CFSTR_FILECONTENTS { get { return DataFormats.GetFormat("FileContents"); } } public static DataFormats.Format CFSTR_FILENAMEA { get { return DataFormats.GetFormat("FileName"); } } public static DataFormats.Format CFSTR_FILENAMEW { get { DataFormats.Format obj = DataFormats.GetFormat("FileNameW"); return obj; } } public static DataFormats.Format CFSTR_PRINTERGROUP { get { return DataFormats.GetFormat("PrinterFriendlyName"); } } public static DataFormats.Format CFSTR_FILENAMEMAPA { get { return DataFormats.GetFormat("FileNameMap"); } } public static DataFormats.Format CFSTR_FILENAMEMAPW { get { return DataFormats.GetFormat("FileNameMapW"); } } public static DataFormats.Format CFSTR_SHELLURL { get { return DataFormats.GetFormat("UniformResourceLocator"); } } public static DataFormats.Format CFSTR_INETURLA { get { return CFSTR_SHELLURL; } } public static DataFormats.Format CFSTR_INETURLW { get { return DataFormats.GetFormat("UniformResourceLocatorW"); } } public static DataFormats.Format CFSTR_PREFERREDDROPEFFECT { get { return DataFormats.GetFormat("Preferred DropEffect"); } } public static DataFormats.Format CFSTR_PERFORMEDDROPEFFECT { get { return DataFormats.GetFormat("Performed DropEffect"); } } public static DataFormats.Format CFSTR_PASTESUCCEEDED { get { return DataFormats.GetFormat("Paste Succeeded"); } } public static DataFormats.Format CFSTR_INDRAGLOOP { get { return DataFormats.GetFormat("InShellDragLoop"); } } public static DataFormats.Format CFSTR_DRAGCONTEXT { get { return DataFormats.GetFormat("DragContext"); } } public static DataFormats.Format CFSTR_MOUNTEDVOLUME { get { return DataFormats.GetFormat("MountedVolume"); } } public static DataFormats.Format CFSTR_PERSISTEDDATAOBJECT { get { return DataFormats.GetFormat("PersistedDataObject"); } } public static DataFormats.Format CFSTR_TARGETCLSID { get { return DataFormats.GetFormat("TargetCLSID"); } } public static DataFormats.Format CFSTR_LOGICALPERFORMEDDROPEFFECT { get { return DataFormats.GetFormat("Logical Performed DropEffect"); } } public static DataFormats.Format CFSTR_AUTOPLAY_SHELLIDLISTS { get { return DataFormats.GetFormat("Autoplay Enumerated IDList Array"); } } } #endregion #region Nested type: FILEDESCRIPTOR [StructLayout(LayoutKind.Sequential)] public sealed class FILEDESCRIPTOR { public uint dwFlags; public Guid clsid; public SIZEL sizel; public POINTL pointl; public uint dwFileAttributes; public FILETIME ftCreationTime; public FILETIME ftLastAccessTime; public FILETIME ftLastWriteTime; public uint nFileSizeHigh; public uint nFileSizeLow; public string cFileName; } #endregion #region Nested type: FILEDESCRIPTORA [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public sealed class FILEDESCRIPTORA { public uint dwFlags; public Guid clsid; public SIZEL sizel; public POINTL pointl; public uint dwFileAttributes; public FILETIME ftCreationTime; public FILETIME ftLastAccessTime; public FILETIME ftLastWriteTime; public uint nFileSizeHigh; public uint nFileSizeLow; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string cFileName; } #endregion #region Nested type: FILEDESCRIPTORW [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public sealed class FILEDESCRIPTORW { public uint dwFlags; public Guid clsid; public SIZEL sizel; public POINTL pointl; public uint dwFileAttributes; public FILETIME ftCreationTime; public FILETIME ftLastAccessTime; public FILETIME ftLastWriteTime; public uint nFileSizeHigh; public uint nFileSizeLow; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string cFileName; } #endregion #region Nested type: FILEGROUPDESCRIPTORA [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public sealed class FILEGROUPDESCRIPTORA { public uint cItems; public FILEDESCRIPTORA[] fgd; } #endregion #region Nested type: FILEGROUPDESCRIPTORW [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public sealed class FILEGROUPDESCRIPTORW { public uint cItems; public FILEDESCRIPTORW[] fgd; } #endregion #region Nested type: FILETIME [StructLayout(LayoutKind.Sequential)] public sealed class FILETIME { public uint nFileTimeHigh; public uint nFileTimeLow; } #endregion #region Nested type: FORMATETC [StructLayout(LayoutKind.Sequential)] public sealed class FORMATETC { public ushort cfFormat; public short dummy; public IntPtr ptd; public int dwAspect; public int lindex; public int tymed; } #endregion #region Nested type: POINTL [StructLayout(LayoutKind.Sequential)] public sealed class POINTL { public int x; public int y; } #endregion #region Nested type: SIZEL [StructLayout(LayoutKind.Sequential)] public sealed class SIZEL { public int cx; public int cy; } #endregion #region Nested type: STATSTG [StructLayout(LayoutKind.Sequential)] public class STATSTG { [MarshalAs(UnmanagedType.LPWStr)] public string pwcsName; public int type; [MarshalAs(UnmanagedType.I8)] public long cbSize; [MarshalAs(UnmanagedType.I8)] public long mtime; [MarshalAs(UnmanagedType.I8)] public long ctime; [MarshalAs(UnmanagedType.I8)] public long atime; [MarshalAs(UnmanagedType.I4)] public int grfMode; [MarshalAs(UnmanagedType.I4)] public int grfLocksSupported; public int clsid_data1; [MarshalAs(UnmanagedType.I2)] public short clsid_data2; [MarshalAs(UnmanagedType.I2)] public short clsid_data3; [MarshalAs(UnmanagedType.U1)] public byte clsid_b0; [MarshalAs(UnmanagedType.U1)] public byte clsid_b1; [MarshalAs(UnmanagedType.U1)] public byte clsid_b2; [MarshalAs(UnmanagedType.U1)] public byte clsid_b3; [MarshalAs(UnmanagedType.U1)] public byte clsid_b4; [MarshalAs(UnmanagedType.U1)] public byte clsid_b5; [MarshalAs(UnmanagedType.U1)] public byte clsid_b6; [MarshalAs(UnmanagedType.U1)] public byte clsid_b7; [MarshalAs(UnmanagedType.I4)] public int grfStateBits; [MarshalAs(UnmanagedType.I4)] public int reserved; } #endregion #region Nested type: STGMEDIUM [StructLayout(LayoutKind.Sequential)] public class STGMEDIUM { public int tymed; public IntPtr unionmember; public IntPtr pUnkForRelease; } #endregion /* [DllImport("ole32.dll")] public static extern int StgCreateDocfileOnILockBytes(ILockBytes plkbyt, uint grfMode, uint reserved, out IStorage ppstgOpen); */ } public class Shell32 { private Shell32() { } #region www.pinvoke.net internal const uint SHGFI_ICON = 0x100; internal const uint SHGFI_LARGEICON = 0x0; // 'Large icon internal const uint SHGFI_SMALLICON = 0x1; // 'Small icon internal const int SHGFI_USEFILEATTRIBUTES = 0x10; [DllImport("shell32.dll", CharSet = CharSet.Auto)] internal static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbFileInfo, uint uFlags); [DllImport("user32.dll", SetLastError = true)] internal static extern int DestroyIcon(IntPtr hIcon); // also from pinvoke.net, with two small tweaks. // 1) the Icon is cloned, so as to allow the native icon to be destroyed (preventing a leak) - tip from CodeProject. // 2) passing the SHGFI_USEFILEATTRIBUTES so as to allow e-mail to be dropped, where the filename doesn't correspond to a real file. public static Icon GetSmallIcon(string fileName) { IntPtr hImgSmall; //the handle to the system image list SHFILEINFO shinfo = new SHFILEINFO(); //Use this to get the small Icon hImgSmall = SHGetFileInfo(fileName, 0, ref shinfo, (uint)Marshal.SizeOf(shinfo), SHGFI_ICON | SHGFI_SMALLICON | SHGFI_USEFILEATTRIBUTES); //The icon is returned in the hIcon member of the shinfo struct Icon icon = (Icon)Icon.FromHandle(shinfo.hIcon).Clone(); DestroyIcon(shinfo.hIcon); return icon; } public static Icon GetLargeIcon(string fileName) { IntPtr hImgLarge; //the handle to the system image list SHFILEINFO shinfo = new SHFILEINFO(); //Use this to get the large Icon hImgLarge = SHGetFileInfo(fileName, 0, ref shinfo, (uint)Marshal.SizeOf(shinfo), SHGFI_ICON | SHGFI_LARGEICON | SHGFI_USEFILEATTRIBUTES); //The icon is returned in the hIcon member of the shinfo struct Icon icon = (Icon)Icon.FromHandle(shinfo.hIcon).Clone(); DestroyIcon(shinfo.hIcon); return icon; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] internal struct SHFILEINFO { public IntPtr hIcon; public int iIcon; public uint dwAttributes; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] public string szDisplayName; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)] public string szTypeName; } ; #endregion } public class DropPanel : UserControl, IDropTargetControl { private static readonly Hashtable lookupImageForExtension = new Hashtable(); private ImageList applicationImageList; private IContainer components; private Panel panel1; private PictureBox pictureBox1; private bool registeredForDragDrop; public DropPanel() { // This call is required by the Windows.Forms Form Designer. InitializeComponent(); // TODO: Add any initialization after the InitializeComponent call Application.OleRequired(); } #region IDropTargetControl Members void IDropTargetControl.Activate() { Form f = FindForm(); if (f != null) { f.Activate(); } } void IDropTargetControl.DragDrop() { pictureBox1.Image = null; } void IDropTargetControl.DragEnter(string filename) { pictureBox1.Image = GetImageForFilename(filename); } void IDropTargetControl.DragLeave() { pictureBox1.Image = null; } void IDropTargetControl.DragOver() { } #endregion public event DroppedByteArrayAvailableHandler DroppedByteArrayAvailable; ////// Clean up any resources being used. /// protected override void Dispose(bool disposing) { if (disposing) { if (components != null) { components.Dispose(); } } base.Dispose(disposing); } private void RegisterForDragDrop() { if (FindForm() != null) { Console.WriteLine("Become visible - registering: {0}", FindForm().Visible); } FileDropTarget dt = new FileDropTarget(this); dt.StreamDropped += dt_StreamDropped; dt.StorageDropped += dt_StorageDropped; dt.FilenameDropped += dt_FilenameDropped; NativeMethods.RegisterDragDrop(new HandleRef(this, Handle), dt); registeredForDragDrop = true; } private void UnregisterForDragDrop() { Console.WriteLine("Become hidden - unregistering"); NativeMethods.RevokeDragDrop(new HandleRef(this, Handle)); registeredForDragDrop = false; } private void panel1_VisibleChanged(object sender, EventArgs e) { if (!DesignMode) { if (Visible && !registeredForDragDrop) { RegisterForDragDrop(); } else { UnregisterForDragDrop(); } } } private void dt_StreamDropped(object sender, string filename, NativeMethods.IStream stream) { try { NativeMethods.STATSTG stg = new NativeMethods.STATSTG(); stream.Stat(stg, 0); IntPtr buf = Marshal.AllocHGlobal((int)stg.cbSize); IntPtr lockedBuf = NativeMethods.GlobalLock(new HandleRef(this, buf)); int x = stream.Read(buf, (int)stg.cbSize); byte[] bytes = new byte[stg.cbSize]; Marshal.Copy(buf, bytes, 0, (int)stg.cbSize); NativeMethods.GlobalUnlock(new HandleRef(this, buf)); Marshal.FreeHGlobal(buf); if (DroppedByteArrayAvailable != null) { DroppedByteArrayAvailable(this, filename, bytes); } } catch (Exception ex) { Console.WriteLine(ex); } } private void dt_StorageDropped(object sender, string filename, NativeMethods.IStorage storage) { try { uint grfFlags = NativeMethods.STGM_CREATE | NativeMethods.STGM_READWRITE | NativeMethods.STGM_SHARE_EXCLUSIVE; NativeMethods.ILockBytes lpBytes = NativeMethods.CreateILockBytesOnHGlobal(IntPtr.Zero, true); NativeMethods.IStorage lpDest = NativeMethods.StgCreateDocfileOnILockBytes(lpBytes, grfFlags, 0); storage.CopyTo(0, null, IntPtr.Zero, lpDest); lpBytes.Flush(); lpDest.Commit(NativeMethods.STGC_DEFAULT); NativeMethods.STATSTG pStatstg = new NativeMethods.STATSTG(); lpBytes.Stat(pStatstg, NativeMethods.STATFLAG_NONAME); IntPtr hGlobal = NativeMethods.GetHGlobalFromILockBytes(lpBytes); HandleRef hRef = new HandleRef(this, hGlobal); IntPtr lpBuf = NativeMethods.GlobalLock(hRef); byte[] bytes = new byte[pStatstg.cbSize]; Marshal.Copy(lpBuf, bytes, 0, (int)pStatstg.cbSize); if (DroppedByteArrayAvailable != null) { DroppedByteArrayAvailable(this, filename, bytes); } NativeMethods.GlobalUnlock(hRef); Marshal.ReleaseComObject(lpDest); Marshal.ReleaseComObject(lpBytes); } catch (Exception ex) { Console.WriteLine(ex); } } private Image GetImageForFilename(string filename) { string ext = Path.GetExtension(filename); if (ext == null || ext.Length == 0) return null; //object idx = lookupImageForExtension[ext.ToLower()]; // caching don't work for shortcuts etc. object idx = null; if (idx == null) { Icon icon = Shell32.GetLargeIcon(filename); applicationImageList.Images.Add(icon); idx = applicationImageList.Images.Count - 1; lookupImageForExtension[ext.ToLower()] = idx; } return applicationImageList.Images[(int)idx]; } private void dt_FilenameDropped(object sender, string filename) { if (DroppedByteArrayAvailable != null) { using (FileStream stream = File.OpenRead(filename)) { long length = stream.Length; byte[] buffer = new byte[length]; stream.Read(buffer, 0, (int)length); string shortFilename = Path.GetFileName(filename); DroppedByteArrayAvailable(this, shortFilename, buffer); } } } #region Component Designer generated code ////// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// private void InitializeComponent() { this.components = new System.ComponentModel.Container(); this.panel1 = new System.Windows.Forms.Panel(); this.pictureBox1 = new System.Windows.Forms.PictureBox(); this.applicationImageList = new System.Windows.Forms.ImageList(this.components); this.panel1.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); this.SuspendLayout(); // // panel1 // this.panel1.BackColor = System.Drawing.Color.NavajoWhite; this.panel1.Controls.Add(this.pictureBox1); this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; this.panel1.Location = new System.Drawing.Point(0, 0); this.panel1.Name = "panel1"; this.panel1.Size = new System.Drawing.Size(64, 64); this.panel1.TabIndex = 0; this.panel1.VisibleChanged += new System.EventHandler(this.panel1_VisibleChanged); // // pictureBox1 // this.pictureBox1.BackColor = System.Drawing.Color.White; this.pictureBox1.BackgroundImage = global::DragDropUI.Properties.Resources.icon_add_document; this.pictureBox1.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Center; this.pictureBox1.Dock = System.Windows.Forms.DockStyle.Fill; this.pictureBox1.Location = new System.Drawing.Point(0, 0); this.pictureBox1.Name = "pictureBox1"; this.pictureBox1.Size = new System.Drawing.Size(64, 64); this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage; this.pictureBox1.TabIndex = 0; this.pictureBox1.TabStop = false; // // applicationImageList // this.applicationImageList.ColorDepth = System.Windows.Forms.ColorDepth.Depth32Bit; this.applicationImageList.ImageSize = new System.Drawing.Size(64, 64); this.applicationImageList.TransparentColor = System.Drawing.Color.Transparent; // // DropControl // this.BackColor = System.Drawing.Color.White; this.Controls.Add(this.panel1); this.Name = "DropControl"; this.Size = new System.Drawing.Size(64, 64); this.panel1.ResumeLayout(false); ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); this.ResumeLayout(false); } #endregion } }
Interesting post i totally agree with the other comments. Keep us posting
ReplyDeleteStandpoint 2016 form presented another email rendering motor to Outlook, named Word. The gigantic thought from Microsoft was to supplant a HTML rendering administration to a word processor rendering administration email.
ReplyDeletehttp://800support.net/sign-in/hotmail-sign-in-hotmail-login/
Are you tired of your quickbooks minor errors or are you fed up of paying technical support and still having issues , Call QuickBooks Support Number +1800-986-6730 is the only QuickBooks support phone number which is carrying its reputation from last 9 years in the market .We provide QuickBooks Pro Support , QuickBooks Premier Support , QuickBooks Enterprise Support , QuickBooks Point of Sale Support , QuickBooks Payroll support and QuickBooks Cloud Hosting Support . Without wasting your time it just takes 5 minutes for our intuit certified proadvisor to take the control of your computer and understand the problem you are going through, after he takes up the responsibility to resolve your problem you just have to sit back and wait for the technician to call you and tell you about the resolution of your problem. All QuickBooks technical support under one roof. QuickBooks Pro Support Number
ReplyDeleteQuickBooks Support Phone Number
QuickBooks Enterprise Support Number
QuickBooks Enterprise Support Phone Number
QuickBooks Desktop Support Number
QuickBooks POS Support Number
QuickBooks customer service 1800-986-6730 QuickBooks support phone number
QuickBooks Support Phone Number
QuickBooks Tech Support Phone Number
QuickBooks Technical Support Number
QuickBooks Tech Support Number
intuit quickbooks support
quickbooks tech support
quickbooks customer support
quickbooks 24/7 support phone number
Nice post! This is a very nice blog that I will definitively come back to more times this year! Thanks for informative post.
ReplyDeletemsn.com hotmail sign in