从 Windows Forms 将 Internet 快捷方式拖放到桌面






4.65/5 (9投票s)
2005 年 7 月 18 日
4分钟阅读

75776

2153
简短文章,介绍如何将 Windows Forms 应用程序中的 URL 链接拖放到桌面。
引言
这是我写的第一个关于我花了一些时间解决的问题的文章,这个问题涉及到尝试将 URL 从 Windows Forms 项目中拖出,并在桌面上将其显示为快捷方式。这与从 Internet Explorer 将链接拖放到桌面时的功能相同,但事实证明这是一个非常困难的问题,涉及大量的试错和一些“魔术数字”。
背景
总的来说,在同一个 Windows Forms 项目内进行拖放并不难。您需要为拖动源附加一个 ItemDrag
事件处理程序,当它被调用时,您会创建一个 DataObject
并用预定义的格式或您自己的对象填充它。如果您在同一个 Windows Forms 应用程序中捕获拖动,那么一切通常都会顺利进行。然而,当您使用 Object
填充 DataObject
并在两个不同的 Windows Forms 应用程序之间拖放某些格式时,似乎会出现问题。如果您尝试通过使用 DataObject.GetData(Type)
按类型查找对象来获取它,那么剪贴板在跨程序传递时似乎会丢失 .NET 类型信息。假设如果您使用 DataObject.SetData(string nameoftype, object)
来放入数据,然后查找该字符串,这应该可以解决问题,但我尚未测试过。
无论如何,这与我试图做的事情无关,那就是将 Windows Forms ListView
中的 URL 拖放到桌面,并使其创建类似 Internet Explorer 的快捷方式。为了做到这一点,我设计了一个测试应用程序,该应用程序检查 Internet Explorer 传递给它自己创建的 DataObject
的所有不同数据格式,然后尝试模仿它们。这花费了相当多的精力才找出必要的数据格式、魔术数字和内存流的组合,这就是我决定将其写成这篇文章的原因。
使用代码
当我终于把所有东西都弄好时,以下是实现这种效果必须做的事情:
- 您必须创建一个 336 字节的
MemoryStream
,其中包含链接的标题加上 ".url",以 ASCII 格式从索引位置 76 开始。这个索引位置已经从一些 Usenet 帖子中得知,但我还没有看到有人指定 336 字节的长度,因为 Usenet 帖子都关注于从拖入 Windows Forms 的现有DataObject
中检索 URL 标题,而不是创建用于拖出的。您还必须在前面 6 个字节中添加魔术数字 0x1、0x0、0x0、0x0、0x40、0x80,并在字节 72 处添加值 0x78。最后,您必须将此MemoryStream
添加到数据对象中的 "FileGroupDescriptor
" 数据格式中。以下示例显示了创建fileGroupDescriptor
MemoryStream
的代码。private void listView1_ItemDrag(object sender, System.Windows.Forms.ItemDragEventArgs e) { ListViewItem item=e.Item as ListViewItem; if (item!=null) { //create FileGroupDescriptor stream with the title of the link Byte[] title = System.Text.Encoding.ASCII.GetBytes(item.SubItems[0].Text + ".url"); //dont forget the .url! Byte[] fileGroupDescriptor=new Byte[336]; title.CopyTo(fileGroupDescriptor,76); //add the magic numbers! fileGroupDescriptor[0]=0x1; fileGroupDescriptor[4]=0x40; fileGroupDescriptor[5]=0x80; fileGroupDescriptor[72]=0x78;//winXP fix MemoryStream fileGroupDescriptorStream = new MemoryStream(fileGroupDescriptor);
- 接下来您需要创建一个包含链接实际 URL 的
MemoryStream
。这是一个直接的文本到 ASCII 字节MemoryStream
的转换,如下所示://Create the url stream String url=item.SubItems[1].Text; //get the url string Byte[] urlByteArray=System.Text.Encoding.ASCII.GetBytes(url); MemoryStream urlStream=new MemoryStream(urlByteArray);
- 现在您必须做真正困难的部分,至少从我必须弄清楚的角度来看。问题的关键在于,在我的测试应用程序中,从 Internet Explorer 拖放到 Windows Forms 时,
DataObject
中存在一个 "FileContents" 数据格式,但是调用DataObject.GetData("FileContents")
总是会抛出异常,这意味着我无法查看该对象或剪贴板中的内存。所以基本上我只能猜测。我猜想它可能只是一个 .url 文件格式的内存流,该格式在此处 显示。Internet 快捷方式实际上是一种特殊的文件,包含特定的标签和 ".url" 文件扩展名。所以我只是创建了这个文件的内部结构,并将其转储到一个MemoryStream
中,然后祈祷,经过一些试错后,它奏效了。如这里所示,我只实现了 Title 和 Link,但如果您真的想,还可以将其他一些内容放入此文件中。最简单的形式如下:[InternetShortcut] URL=http://thecodeproject.com
到此为止,至少可以让拖动生效。事实证明,桌面上链接的标题是从我们在第 1 步中设置的 "FileDescriptor" 中自动提取的。
创建文件内容的 C# 代码如下:
//create filecontents see //http://www.cyanwerks.com/file-format-url.html //for full format of this file string contents="[InternetShortcut]"+ Environment.NewLine+"URL="+url+Environment.NewLine; Byte[] contentsByteArray=System.Text.Encoding.ASCII.GetBytes(contents); MemoryStream contentsStream=new MemoryStream(contentsByteArray);
- 最后,我们将所有三个对象放入
DataObject
中,并将 URL 添加到 "UniformResourceLocator
" 中,这样我们就可以直接将链接拖入浏览器而不是桌面,然后我们就完成了!//Add everything to the dataobject DataObject data=new DataObject(); data.SetData("FileGroupDescriptor", fileGroupDescriptorStream); //becomes title of link on desktop data.SetData("FileContents", contentsStream); //becomes contents of the .url file data.SetData("UniformResourceLocator", urlStream); //used for dragging to other browsers this.DoDragDrop(data,DragDropEffects.Link);
就是这样。我希望这对大家有帮助,因为这是一个非常有用的功能,但似乎还没有人弄清楚。
示例代码中有一个 ListView
,其中包含一些您可以拖到桌面或浏览器的链接。只需编译并运行,然后随意拖动!
历史
- 版本 1.1 - 2005 年 7 月 21 日 - 修复了 WinXP 问题。