您的位置:首页 > 编程语言 > C#

C# 如何用DragDrop拖放特殊文件到程序窗口 (如:我的电脑 回收站 网上邻居)

2014-10-22 17:00 501 查看
    最常见的情况是把一个文件拖放到Form窗体中,窗体显示文件的路径和文件名。这个功能容易实现,具体思路是借助Form的事件响应函数DragEnter和DragDrop来完成。

    DragEnter函数主要作用是在拖拽文件进入窗体时修改鼠标图标样式,指定拖拽的可能效果(是拷贝文件数据,还是显示文件路径)。
    DragDrop函数主要作用是在鼠标拖放结束时进行某些操作。

    可以使用下面代码实现常规文件的拖放:

<pre name="code" class="csharp">        private void Form1_DragEnter(object sender, DragEventArgs e)
        {
        <span style="white-space:pre">	</span>e.Effect = DragDropEffects.Link; //重要代码:把拖拽的文件当成一个文件链接
        }
<span style="white-space:pre">	</span>private void Form1_DragDrop(object sender, DragEventArgs e)
        {
                //string[] formatList = e.Data.GetFormats();
                string  filename = ((Array)e.Data.GetData(DataFormats.FileDrop)).GetValue(0).ToString ();
                //或者 string  filename = ((Array)e.Data.GetData(“FileDrop”)).GetValue(0).ToString ();
        }



    函数e.Data.GetData(string)里可填的数据类型可以是DataFormats.FileDrop,也可以是字符串形式如"FileDrop","FileName"等,根据拖放文件的类型而不同。我们可以通过e.Data.GetFormats()来获得具体的格式类型列表。

    常规文件Formats类型信息如下:



    例如:FileDrop包含了文件的全路径字符串,FileName则包含文件名。

    特殊文件的拖放(如:我的电脑,网上邻居,回收站等)也可以用e.Data.GetFormats()来获得具体的格式类型列表。

    具体信息如下:



显然里面并没有FileDrop和FileName。因此要想获取特殊文件的文件名用FileDrop和FileName不行。那么这个办法就不奏效了。

然而我们却注意到一个细节,不论什么类型的文件都有"Shell IDList Array","DragImageBits",“DragContext”等其它信息。

经过查找相关资料了解到"Shell IDList Array"实际上它指向一个CIDA结构。通过它可以得到对应的PIDL。而PIDL里有文件的相关信息。

特殊文件拖放的实现代码:

private void Form1_DragEnter(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Link; //重要代码:把拖拽的文件当成一个文件链接
}
private void Form1_DragDrop(object sender, DragEventArgs e)
{
string[] str = e.Data.GetFormats();
MemoryStream data = (MemoryStream)e.Data.GetData("Shell IDList Array");
byte[] b = data.ToArray();
IntPtr p = Marshal.AllocHGlobal(b.Length);
Marshal.Copy(b, 0, p, b.Length);

UInt32 cidl = (UInt32)Marshal.ReadInt32(p);

int offset = sizeof(UInt32);
IntPtr parentpidl = (IntPtr)((int)p + (UInt32)Marshal.ReadInt32(p, offset));

for (int i = 1; i <= cidl; ++i)
{
offset += sizeof(UInt32);
IntPtr relpidl = (IntPtr)((int)p + (UInt32)Marshal.ReadInt32(p, offset));
IntPtr abspidl = ILCombine(parentpidl, relpidl);
SHFILEINFO sf = new SHFILEINFO();
if (SHGetFileInfo(abspidl, 0, ref sf, Marshal.SizeOf(sf), SHGFI.PIDL | SHGFI.DISPLAYNAME | SHGFI.TYPENAME).ToInt32() > 0)
{
MessageBox.Show(sf.szDisplayName);
}

ILFree(abspidl);
}
}
"Shell IDList Array"的构建与解析用到了下面的代码:(参考帖子:http://www.cnblogs.com/feiyun0112/archive/2009/02/09/1386802.html)
[DllImport("shell32.dll")]
public static extern IntPtr ILCombine(IntPtr pidl1, IntPtr pidl2);
[DllImport("shell32.dll")]
public static extern void ILFree(IntPtr pidl);

public enum SFGAO : uint
{
BROWSABLE = 0x8000000,
CANCOPY = 1,
CANDELETE = 0x20,
CANLINK = 4,
CANMONIKER = 0x400000,
CANMOVE = 2,
CANRENAME = 0x10,
CAPABILITYMASK = 0x177,
COMPRESSED = 0x4000000,
CONTENTSMASK = 0x80000000,
DISPLAYATTRMASK = 0xfc000,
DROPTARGET = 0x100,
ENCRYPTED = 0x2000,
FILESYSANCESTOR = 0x10000000,
FILESYSTEM = 0x40000000,
FOLDER = 0x20000000,
GHOSTED = 0x8000,
HASPROPSHEET = 0x40,
HASSTORAGE = 0x400000,
HASSUBFOLDER = 0x80000000,
HIDDEN = 0x80000,
ISSLOW = 0x4000,
LINK = 0x10000,
NEWCONTENT = 0x200000,
NONENUMERATED = 0x100000,
READONLY = 0x40000,
REMOVABLE = 0x2000000,
SHARE = 0x20000,
STORAGE = 8,
STORAGEANCESTOR = 0x800000,
STORAGECAPMASK = 0x70c50008,
STREAM = 0x400000,
VALIDATE = 0x1000000
}
public const int MAX_PATH = 260;

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct SHFILEINFO
{
public IntPtr hIcon;
public int iIcon;
public SFGAO dwAttributes;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
public string szDisplayName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
public string szTypeName;
}

public enum SHGFI : uint
{
ADDOVERLAYS = 0x20,
ATTR_SPECIFIED = 0x20000,
ATTRIBUTES = 0x800,
DISPLAYNAME = 0x200,
EXETYPE = 0x2000,
ICON = 0x100,
ICONLOCATION = 0x1000,
LARGEICON = 0,
LINKOVERLAY = 0x8000,
OPENICON = 2,
OVERLAYINDEX = 0x40,
PIDL = 8,
SELECTED = 0x10000,
SHELLICONSIZE = 4,
SMALLICON = 1,
SYSICONINDEX = 0x4000,
TYPENAME = 0x400,
USEFILEATTRIBUTES = 0x10
}

public enum FILE_ATTRIBUTE
{
READONLY = 0x00000001,
HIDDEN = 0x00000002,
SYSTEM = 0x00000004,
DIRECTORY = 0x00000010,
ARCHIVE = 0x00000020,
DEVICE = 0x00000040,
NORMAL = 0x00000080,
TEMPORARY = 0x00000100,
SPARSE_FILE = 0x00000200,
REPARSE_POINT = 0x00000400,
COMPRESSED = 0x00000800,
OFFLINE = 0x00001000,
NOT_CONTENT_INDEXED = 0x00002000,
ENCRYPTED = 0x00004000
}

[DllImport("shell32", EntryPoint = "SHGetFileInfo", ExactSpelling = false, CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr SHGetFileInfo(IntPtr ppidl, FILE_ATTRIBUTE dwFileAttributes, ref SHFILEINFO sfi, int cbFileInfo, SHGFI uFlags);

效果截图:



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息