This is my first article ever describing a problem I've been working on for some time involving attempting to drag URLs out of a Windows Forms project and have them appear on the desktop as shortcuts. This is the same functionality that you get when you drag links from Internet Explorer to the desktop but it turned out to be a very difficult thing to do involving a lot of trial and error and some magic numbers.
In general, drag and drop within a single Windows Forms project is not that hard. You attach an event handler for
ItemDrag to the drag source and when it gets called you create and fill a
DataObject with one of the predefined formats or your own object. If you are capturing the drag in the same Windows Forms app then everything will usually go smoothly. However there does seem to be problems dragging certain types of formats between two different Windows Forms apps if you populate the
DataObject with an
Object and you try to get it back by looking for that object by Type using
DataObject.GetData(Type) because the clipboard seems to lose the .NET Type information when passing between programs. Presumably if you put the data in using
DataObject.SetData(string nameoftype, object) and then look for the string, this should get around this problem but I haven't tested this.
Anyway that's incidental to what I was attempting to do which was to drag a URL from a Windows Forms
ListView to the desktop and have it create a shortcut similar to the behavior of Internet Explorer. To do this I basically designed a test application which looked at all the different data formats that Internet Explorer was passing to the
DataObject that it creates itself and then tried to mimic them. This took quite a bit of effort to come up with the combination of data formats and magic numbers and memory streams necessary, and that's why I decided to put it into this article.
Using the code
When I finally got everything working, here is what it turns out must be done in order to achieve this effect:
- You must create a
MemoryStream of 336 bytes with the title of the link plus ".url" contained in ASCII starting at index position 76. This index position is already known from a few Usenet posts but I haven't seen anybody specifying the 336 byte length as the Usenet posts were all concerned with retrieving a URL title from an existing
DataObject dragged into Windows Forms, not creating one to drag out. You must also add the magic numbers 0x1, 0x0, 0x0, 0x0, 0x40, 0x80 to the first 6 bytes and a value of 0x78 at byte 72. Finally you must add this
MemoryStream to the "
FileGroupDescriptor" data format in the data object. The following sample shows the code to create the
private void listView1_ItemDrag(object sender,
ListViewItem item=e.Item as ListViewItem;
Byte title =
+ ".url"); Byte fileGroupDescriptor=new Byte;
fileGroupDescriptor=0x78; MemoryStream fileGroupDescriptorStream =
- The next thing you have to create is a
MemoryStream containing the actual URL of the link. This is a straightforward conversion from text to a
MemoryStream of ASCII bytes as shown:
String url=item.SubItems.Text; Byte urlByteArray=System.Text.Encoding.ASCII.GetBytes(url);
MemoryStream urlStream=new MemoryStream(urlByteArray);
- Now you have to do the really hard part, at least from the point of view of what I had to figure out. Basically the problem with this was on my test application, dragging from Internet Explorer to Windows Forms showed a "FileContents" data format as being present in the
DataObject, but the call to
DataObject.GetData("FileContents") always threw an exception meaning I couldn't get a look at the object or the memory that was in the clipboard for this. So basically I guessed. I figured it was probably just a memory stream of the .url file format which is shown here. The internet shortcut is actually a special type of file containing certain tags and a ".url" file extension. So I just created the internals of this file and dumped it into a
MemoryStream and prayed, and after a bit of trial and error it worked. As shown here, I've only implemented the Title, and the Link, but there are a few other things you can put in this file if you really feel like it. The simplest form looks likes this:
That's all you need to at least get the drag to work. It turns out the title of the link on the desktop is pulled from the "FileDescriptor" that we set in step 1 automatically.
The code for creating the file contents is as shown:
MemoryStream contentsStream=new MemoryStream(contentsByteArray);
- Finally we just put all three objects into the
DataObject, as well as add the URL into "
UniformResourceLocator" which gives us the ability to drag the link straight into the browser instead of the desktop and then we are done!
DataObject data=new DataObject();
That's it. I hope this helps people because it's a very useful feature that nobody seems to have figured out yet.
The sample code has a
ListView with some links that you can drag to your desktop or to a browser. Just compile and run and drag away!
- Version 1.1 - July 21, 2005.-fixed WinXP problem.