

C#でのドラッグ&ドロップによる他のアプリからのデータ取得は、以下に公開されているソースを流用しました。  
[Outlook Drag and Drop in
C#](http://www.codeproject.com/Articles/28209/Outlook-Drag-and-Drop-in-C)

しかし、FileContentsの取得結果がAll 0になってしまいます。サイズは取得すべきサイズになっていて正しいです。  
FORMATETC構造体に設定する.lindexメンバー変数の値が正しく設定されていないせいだとおもい、FILEGROUPDESCRIPTOR構造体の.cItemsの値を設定してやってるんですが、やはりAll
0のままです。  
何が悪いのかわかりません・・・

[code]

        case "FileContents":
        //override the default handling of FileContents which returns the
        //contents of the first file as a memory stream and instead return
        //a array of MemoryStreams containing the data to each file dropped
    
        //get the array of filenames which lets us know how many file contents exist
    
        // modified begin
        //string[] fileContentNames = (string[])this.GetData("FileGroupDescriptor");
        string[] fileContentNames = (string[])this.GetData("FileGroupDescriptorW");     // Unicode UTF-16LE
        if (fileContentNames.Length <= 0)
            fileContentNames = (string[])this.GetData("FileGroupDescriptor");
    
        //create a MemoryStream array to store the file contents
        MemoryStream[] fileContents = new MemoryStream[fileContentNames.Length];
    
        //loop for the number of files acording to the file names
        for(int fileIndex = 0;fileIndex < fileContentNames.Length;fileIndex++)
        {
            //get the data at the file index and store in array
            // modified begin
            //fileContents[fileIndex] = this.GetData(format, fileIndex);
            if (gFileGrpDescW != null)
            {
                fileContents[fileIndex] = this.GetData(format, (int)gFileGrpDescW.cItems);
            }
            else if (gFileGrpDescA != null)
            {
                fileContents[fileIndex] = this.GetData(format, (int)gFileGrpDescA.cItems);
            }
            // modified end
        }
    
        // added
        gFileGrpDescW = null;
        gFileGrpDescA = null;
    
        //return array of MemoryStreams containing file contents
        return fileContents;
    
[/code]

なお、具体的なアプリというのはEvernoteなのですが、Evernoteのノートを開発アプリにドラッグ&ドロップされたら直接受け取りたいのです。  
一応元のコードをほぼそのまま使用しています。なお、ドラッグ&ドロップ時に複数のノートをまとめてドラッグすると、一つのデータとして受け取りますのでコード中のループは1度しか行われません。  
Evernoteからエクスプローラ上に複数のノートをドラッグ&ドロップしても、一つのファイルとして出力されます。

FileContentsの情報取得については、以下の情報を参考にしています。  
[Shows how Email attachments can be dropped onto your own
controls](http://www.codeguru.com/cpp/i-n/internet/email/article.php/c3381/Handling-
Drag-and-Drop-of-Email-Attachments.htm)

しかし、前述の通りFileContentsがAll 0となってしまい、困っています。  
宜しくお願いいたします。


CC BY-SA 3.0
2015-01-31T19:39:27.673
5670
2015-02-01T11:24:01.113
7966
question
c#
C#にてアプリからドラッグ&ドロップを受け入れたいのですが、FileContentsの結果がAll 0になってしまいます。


EvernoteとOutlook Drag and Drop in C#の両方をダウンロードして試してみました。  
Evernote側は複数のノートをドラッグしても１つ目しか送ってこないようで、受け側にはどうしようもなく感じました。  
OutlookDataObjectクラスの方はアドレス計算を32bitで行っているために64bitで動作しなかったり、マネージ／アンマネージの扱いが何重にも回りくどく遠回りしている感を醸し出していたりはしますが、FileContents自体は取れていました。

試していて気づいたのは、１回のDrag &
Dropで複数回読み出すと１回目の読み出しでIStreamが終端までseekされているため、２回目はまず先頭に戻す必要があります。  
もし、オリジナルコードを残し、その後ろに書き足したりしているとそれが理由で読み出せないように見えるかもしれません。

* * *

ついでなのでドロップされたデータからファイル名とコンテンツを読み込むクラスを書いてみました。  
`File.Get(e.Data)`で取り出せます。エラー処理はしてません。

[code]

    using System;
    using System.Diagnostics;
    using System.IO;
    using System.Linq;
    using System.Runtime.InteropServices;
    using System.Runtime.InteropServices.ComTypes;
    using System.Windows.Forms;
    using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME;
    using IComDataObject = System.Runtime.InteropServices.ComTypes.IDataObject;
    using IFormsDataObject = System.Windows.Forms.IDataObject;
    using STATSTG = System.Runtime.InteropServices.ComTypes.STATSTG;
    
    namespace Sayuri.IO {
        public class File {
            private File(string name, byte[] bytes) {
                Name = name;
                Bytes = bytes;
            }
            public string Name { get; private set; }
            public byte[] Bytes { get; private set; }
    
            static readonly DataFormats.Format CFSTR_FILEDESCRIPTORW = DataFormats.GetFormat("FileGroupDescriptorW");
            static readonly DataFormats.Format CFSTR_FILECONTENTS = DataFormats.GetFormat("FileContents");
    
            [DllImport("Kernel32.dll", SetLastError = true)]
            static extern IntPtr GlobalAlloc(int uFlags, int dwBytes);
            [DllImport("Kernel32.dll")]
            static extern IntPtr GlobalFree(IntPtr hMem);
            [DllImport("Kernel32.dll", SetLastError = true)]
            static extern IntPtr GlobalLock(IntPtr hMem);
            [DllImport("Kernel32.dll", SetLastError = true)]
            static extern IntPtr GlobalSize(IntPtr hMem);
            [DllImport("Kernel32.dll")]
            static extern bool GlobalUnlock(IntPtr hMem);
    
            [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)]
            struct FILEDESCRIPTORW {
                public int dwFlags;
                public Guid clsid;
                public long sizel;
                public long pointl;
                public int dwFileAttributes;
                public FILETIME ftCreationTime;
                public FILETIME ftLastAccessTime;
                public FILETIME ftLastWriteTime;
                public int nFileSizeHigh;
                public uint nFileSizeLow;
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
                public string cFileName;
            }
    
            [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)]
            struct FILEGROUPDESCRIPTORW {
                public int cItems;
                [MarshalAs(UnmanagedType.ByValArray)]
                public FILEDESCRIPTORW[] fgd;
            }
    
            public static File[] Get(IFormsDataObject dataObject) {
                return Get((IComDataObject)dataObject);
            }
    
            public static File[] Get(IComDataObject dataObject) {
                var fileDescriptor = GetFileDescriptor(dataObject);
                return fileDescriptor.fgd.Select((fgd, i) => new File(fgd.cFileName, GetFileContent(dataObject, i))).ToArray();
            }
    
            static FILEGROUPDESCRIPTORW GetFileDescriptor(IComDataObject dataObject) {
                var format = new FORMATETC {
                    cfFormat = unchecked((short)CFSTR_FILEDESCRIPTORW.Id),
                    dwAspect = DVASPECT.DVASPECT_CONTENT,
                    ptd = IntPtr.Zero,
                    lindex = 0,
                    tymed = TYMED.TYMED_HGLOBAL
                };
                STGMEDIUM medium;
                dataObject.GetData(ref format, out medium);
                Debug.Assert(medium.tymed == TYMED.TYMED_HGLOBAL && medium.unionmember != IntPtr.Zero && medium.pUnkForRelease == null);
                try {
                    return Marshal.PtrToStructure<FILEGROUPDESCRIPTORW>(GlobalLock(medium.unionmember));
                }
                finally {
                    GlobalFree(medium.unionmember);
                }
            }
    
            static byte[] GetFileContent(IComDataObject dataObject, int i) {
                var format = new FORMATETC {
                    cfFormat = unchecked((short)CFSTR_FILECONTENTS.Id),
                    dwAspect = DVASPECT.DVASPECT_CONTENT,
                    ptd = IntPtr.Zero,
                    lindex = i,
                    tymed = TYMED.TYMED_HGLOBAL | TYMED.TYMED_ISTREAM
                };
                STGMEDIUM medium;
                dataObject.GetData(ref format, out medium);
                Debug.Assert(medium.unionmember != IntPtr.Zero && medium.pUnkForRelease == null);
                switch (medium.tymed) {
                    case TYMED.TYMED_HGLOBAL: {
                            var size = (long)GlobalSize(medium.unionmember);
                            Debug.Assert(size <= Int32.MaxValue);
                            var buffer = new byte[size];
                            Marshal.Copy(GlobalLock(medium.unionmember), buffer, 0, buffer.Length);
                            GlobalUnlock(medium.unionmember);
                            GlobalFree(medium.unionmember);
                            return buffer;
                        }
                    case TYMED.TYMED_ISTREAM: {
                            var stream = (IStream)Marshal.GetObjectForIUnknown(medium.unionmember);
                            Marshal.Release(medium.unionmember);
                            STATSTG statstg;
                            stream.Stat(out statstg, 0);
                            Debug.Assert(statstg.cbSize <= Int32.MaxValue);
                            var buffer = new byte[statstg.cbSize];
                            stream.Read(buffer, buffer.Length, IntPtr.Zero);
                            return buffer;
                        }
                }
                throw new Exception();
            }
        }
    }
    
[/code]


CC BY-SA 3.0
2015-02-01T00:49:14.180
5678
2015-02-01T11:24:01.113
2015-02-01T11:24:01.113
4236
4236
5670
answer