Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Drag and Drop Internet Shortcuts from Windows Forms to the Desktop

0.00/5 (No votes)
21 Jul 2005 1  
Short article on how to drag URL links from a Windows Forms app to the desktop.

screenshot

Introduction

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.

Background

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:

  1. 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 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);
  2. 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:
        //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);
  3. 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:
    [InternetShortcut]
    URL=http://thecodeproject.com

    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:

    //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);
  4. 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!
    //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);

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!

History

  • Version 1.1 - July 21, 2005.-fixed WinXP problem.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here