Click here to Skip to main content
Click here to Skip to main content
Go to top

Drag-and-Drop Attached File From Outlook (97 and above) to C# Window Form

, 23 May 2004
Rate this:
Please Sign up or sign in to vote.
How to drag-and-drop a file attached to an e-mail message to another program

Introduction

Recently, I decided to write a quick program that would allow me to drag-and-drop an attached zip file from an e-mail message to a C# Windows Form program so that I could extract specific types of files to be printed. Little did I know that I would be stepping into a relatively unknown area of drag-and-drop technology, especially it appears as it relates to e-mail attachments.

The purpose of this article is to provide a simple example of how to drag-and-drop e-mail attachments from Outlook to a C# Windows Form program. This article will not teach the fundamentals of drag-and-drop. There are existing articles at the CodeProject.com site that cover the introduction to this technology. Hopefully, others will find this a good template for approaching such tasks.

Background

I teach computer programming (C++ mainly) at a local college. During this quarter, I offered to let the the students e-mail their completed homework to me. Little did I understand where this would lead me.

The issue became the amount of manual work required to extract the "solution" sets for potentially each homework problem, open a solution, print each of the source files, open the next solution, etc. When at first only two students sent in homework this way, no problem. But when ten students did it during week 3, I was spending more time getting the source to do the grading than I was grading each problem. Being essentially lazy like all good programmers, I decided to program a solution.

Since the students were sending their complete solutions for each problem as a zipped file via e-mail, logically it made sense to create a solution that allowed me to drag-and-drop the attached zip file direct from the email message to the program. I could have extracted the file to a directory and then drag-and-drop to the program, this seemed like wasted effort. Drag-and-drop is supposed to be easy and I had implemented file drap-and-drop at least twice before in programs, so I saw no reason to not start at the e-mail message. Besides, I figured I could find references on the internet if I had problems.

Little did I realize that I was about to step into quicksand.

Having written code for 35 years and C/C++ code for over 25 years, I have over the last two years begun to transition to C# for all but the highest performance needs. I have found C# to be a relatively easy transition from C++ and a great boon for speeding up the development process. I have written Windows code before, during and now after MFC. I also do work with VB and VBA, so I had long missed the easy Windows program development of VB when working with C++, my preferred language (I am a geek!). C# has brought the of VB Windows programming to C++ programmers and increased my efficiency by orders of magnitude when I need to provide an interface to users. While I have not tried to do it, the concepts should work under VB.NET as I have implemented drag-and-drop on a VB.NET program awhile back.

And now we start the trip .....

Using the code

As I mentioned above, I decided to write a program that would allow me to drag a zip file attached to an email and drop it onto my Windows Form program which would extract the sources and print them for me. This example will not go that far. We will walk through creating a Windows Form program in C# which will create a copy of an attached file from an e-mail. Hopefully, this will be enough of a template for other users to implement this feature in their own code.

Whenever I start a new project or task, I first focus on the stuff I don't know. So started with my usual research and did a Google search for drag-and-drop on Outlook email. The Google search returned less than 100 references, unusual for what I figured was well-known technology. Digging into the references, I only found three that actually referred to this type of operation. One reference was for C++ and the second for a Pascal program (which really amazed me). I fully expected to find 100s of references to similar work, so you imagine my surprise. The third valid reference was a response to an e-mail that gave me the clues as how to accomplish what I wanted to do. With the information from the email response, I coded and finished the work in about an hour using a zip file class I had earlier developed to use the WinZip command line program.

My sample program will give you the basic gory details of handling the drag-and-drop of a single file from Outlook. The program simply copies the file to the TEMP directory and makes sure that it was created. Nothing fancy here. First I walk through setting up a Windows Form program and put in the basic event handlers for drag-and-drop. Then I get into the adding the code necessary to deal with dropping an email attachment from Outlook into the program.

Step 1: Create a C# Windows. Start up Visual Studio.Net and create a new project. Select a C# Windows Application. For our test purposes, give it the name TestEmailDragDrop. Let it build the basic structure.

Step 2: Select the properties tab for the form. Find the "Allow Drop" property and change it from False to True. This will allow us to handle the drag-and-drop events.

Step 3: Select the Events option (the lightning strike to right of properties) and find the "DragEnter" event. Click in the blank area to the right of the "DragEnter" portion and double-click. This will create the code below:

Step 4: Again in the Events list, find the "DragDrop" event. Click in the blank area to the right and double-click. This will create the code below:

Step 5: Now we have the basic code in place to handle the drag-and-drop operation. Go to the DragEnter event handler and add the following code:

    
    private void Form1_DragEnter(object sender, 
        System.Windows.Forms.DragEventArgs e)
    {
      // for this program, we allow a file to be dropped from Explorer
      if (e.Data.GetDataPresent(DataFormats.FileDrop)) 
      {  e.Effect = DragDropEffects.Copy;}
      //    or this tells us if it is an Outlook attachment drop
      else if (e.Data.GetDataPresent("FileGroupDescriptor"))
      {  e.Effect = DragDropEffects.Copy;}
      //    or none of the above
      else
      {  e.Effect = DragDropEffects.None;}
    }
    
    

We are setting up here to either receive a file from Explorer (DataFormats.FileDrop) and from Outlook ("FileGroupDescriptor"). I won't claim to understand all the details of this data format, but I was lucky enough to find a couple of examples of how to handle (one in Pascal of all languages) this format. At this point, we don't care about the format. We just want to have the effects property for our event set to the DragDropEffects.Copy value. If other than these two, simply set the effects to DragDropEffects.None.

Now that we have the DragEnter event handled, we turn our focus to the DataDrop event. This is where we get cute. Below is the code to handle the DragDrop event for both the FileDrop and the FileGroupDescriptor types of objects:

    private void Form1_DragDrop(object sender, 
         System.Windows.Forms.DragEventArgs e)
    {
      string [] fileNames = null;

      try
      {
        if ( e.Data.GetDataPresent(DataFormats.FileDrop,false) == true)
        {          
          fileNames = (string []) e.Data.GetData(DataFormats.FileDrop);
          // handle each file passed as needed
          foreach( string fileName in fileNames)
          {
            // do what you are going to do with each filename
          }
        }
        else if (e.Data.GetDataPresent("FileGroupDescriptor"))
        {
          //
          // the first step here is to get the filename
          // of the attachment and
          // build a full-path name so we can store it 
          // in the temporary folder
          //

          // set up to obtain the FileGroupDescriptor 
          // and extract the file name
          Stream theStream = (Stream) e.Data.GetData("FileGroupDescriptor");
          byte [] fileGroupDescriptor = new byte[512];
          theStream.Read(fileGroupDescriptor,0,512);
          // used to build the filename from the FileGroupDescriptor block
          StringBuilder fileName = new StringBuilder("");
          // this trick gets the filename of the passed attached file
          for(int i=76; fileGroupDescriptor[i]!=0; i++)
          {  fileName.Append(Convert.ToChar(fileGroupDescriptor[i]));}
          theStream.Close();
          string path = Path.GetTempPath();  
              // put the zip file into the temp directory
          string theFile = path+fileName.ToString();  
              // create the full-path name

          //
          // Second step:  we have the file name.  
          // Now we need to get the actual raw
          // data for the attached file and copy it to disk so we work on it.
          //

          // get the actual raw file into memory
          MemoryStream ms = (MemoryStream) e.Data.GetData(
              "FileContents",true);
          // allocate enough bytes to hold the raw data
          byte [] fileBytes = new byte[ms.Length];
          // set starting position at first byte and read in the raw data
          ms.Position = 0;
          ms.Read(fileBytes,0,(int)ms.Length);
          // create a file and save the raw zip file to it
          FileStream fs = new FileStream(theFile,FileMode.Create);
          fs.Write(fileBytes,0,(int)fileBytes.Length);

          fs.Close();  // close the file

          FileInfo tempFile = new FileInfo(theFile);

          // always good to make sure we actually created the file
          if ( tempFile.Exists == true)
          {  
            // for now, just delete what we created
            tempFile.Delete();
          }
          else
          {  Trace.WriteLine("File was not created!");}
        }

      }
      catch (Exception ex)
      {
        Trace.WriteLine("Error in DragDrop function: " + ex.Message);

        // don't use MessageBox here - Outlook or Explorer is waiting !
      }
    
    }

    

I won't attempt to explain the FileDrop type. This is better explained in other CodeProject examples. I will focus on the FileGroupDescriptor type.

For the real geeks, the FileGroupDescriptor structure is explained at the MSDN web page MSDN FileGroupDescriptor (assuming Microsoft doesn't change the link address). Basically, it is a variable length structure with a 4-byte count at the lead followed by a FILEDESCRIPTOR Structure that holds the information on the file being passed. The problem is that the file does not exist other than in memory (the Clipboard) (Outlook 97 actually creates the file in a TEMP area) so we can't reference it directly. My simple approach here is to copy to a memory-based file before actually creating it in the TEMP directory. The user is welcome to modify the code to do something more to their liking.

In this case, we are assuming only one file is being passed. I didn't need to handle multiple files so I haven't coded that capability yet.

The first step in the code above is to get the FileGroupDescriptor structure by putting it into a byte array. This is simpler than trying to marshall the structure and works for this simple example. We obtain the byte array by casting the object that was dropped (the FileGroupDescriptor block) to a Stream object. We then read the FileGroupDescriptor into a byte array (fileGroupDescriptor). Once we have the FileGroupDescriptor, we simply point to the 76th byte in the array which is the starting point for the filename of the attached file and build up the file name by converting the byte to a Unicode char and appending it to a StringBuilder object. When we finish building the filename, we close the Stream object, get the path to the TEMP file area and append the filename after converting the StringBuilder object to a string (ToString()).

We now know the name of the file that we are being passed. If you don't care what the name is, you could skip this first step and go direct to Step 2.

We start the second step by getting the FileContents data and casting it to a MemoryStream object. We calculate the number of bytes needed, allocate a byte array of the correct size and copy (Read) the information into our byte array. We then create a FileStream object (fs) giving it the name that was passed in the FileGroupDescriptor block above. We copy (Write) the data to the file and close it. We now have a copy of the attached file.

The last thing the code does is check to make sure the file exists, just to be safe.

Voila! Drag-and-drop of an attached file in a Outlook email

History

  • March 5, 2004: (Library Version 1.0.0.0)
    • This is the initial release of the article. No changes.

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

Share

About the Author

tgueth
President Binary Star Technology, Inc
United States United States
have programmed since 1969, back in the good old days. Remember when C was first announced to the world and the how so much better it was over existing computer languages.
 
Know most languages but enjoy low-level and database programming most. Doing most of my work in C#, an absolutely great language.

Comments and Discussions

 
GeneralMy vote of 5 PinmemberMember 1055849329-Jan-14 6:50 
GeneralGreat example PinmemberTony D Great1-Jul-13 7:03 
GeneralCannot find this file. Verify the path and file name are correct. PinmemberOlivierNice15-Jun-11 22:21 
Generalconverting application in vb.net Pinmembermarco.facchetti@globalinfo.it30-Jun-10 4:20 
GeneralMultiple Files Pinmemberkazg7-Aug-08 19:03 
GeneralRe: Multiple Files PinmemberMember 6192944-Mar-10 1:42 
Using o2 As IO.Stream = e.Data.GetData("FileGroupDescriptorW")
Using sr As New IO.StreamReader(CType(o2, IO.Stream), System.Text.Encoding.Unicode)
Dim str As String() = sr.ReadToEnd.Split(New String() {Chr(0)}, StringSplitOptions.RemoveEmptyEntries) '.Replace(Chr(0), ""))
 
For i = 1 To str.GetUpperBound(0)
MsgBox(str(i))
Next
End Using
End Using
GeneralRe: Multiple Files Pinmemberkrashcontrol5-Apr-10 8:40 
GeneralRe: Multiple Files Pinmembertomxx823-Nov-10 21:34 
GeneralRe: Multiple Files Pinmemberrudro20-Jun-11 4:58 
GeneralRe: Multiple Files Pinmembersosololo19-Mar-12 21:42 
GeneralWorks in Windows Forms but NOT in WPF Form (.NET 3.5) PinmemberBurning Shadow15-Jul-08 1:26 
GeneralRe: Works in Windows Forms but NOT in WPF Form (.NET 3.5) Pinmembertgueth15-Jul-08 1:29 
GeneralRe: Works in Windows Forms but NOT in WPF Form (.NET 3.5) PinmemberBurning Shadow16-Jul-08 3:25 
GeneralRe: Works in Windows Forms but NOT in WPF Form (.NET 3.5) Pinmemberjohnwayne1526-Aug-11 6:12 
GeneralDragging the whole email into windows explorer Pinmemberbravovj30-Jan-08 10:00 
GeneralAlmost working Pinmemberfreemem11-Dec-07 7:55 
GeneralRe: Almost working PinmemberMember 78929272-Jul-12 12:23 
GeneralRe: Almost working Pinmembertgueth2-Jul-12 14:52 
GeneralAlmost working Pinmemberfreemem11-Dec-07 7:54 
QuestionDrag n Drop from Outlook to Windows Form PinmemberWalaza6-Jun-07 3:31 
GeneralFileContents returns null Pinmemberaedes27-May-07 22:08 
AnswerRe: FileContents returns null PinmemberMarek.T2-Apr-09 2:41 
GeneralRe: FileContents returns null Pinmembershah.mihir@ymail.com28-Jun-12 16:55 
QuestionDrag and Drop from Outlook to ASP.Net Pinmembersumibell8-Mar-07 23:23 
AnswerRe: Drag and Drop from Outlook to ASP.Net Pinmembertgueth9-Mar-07 1:23 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140916.1 | Last Updated 24 May 2004
Article Copyright 2004 by tgueth
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid