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);
效果截圖: