(Print this page)

Dropping a Outlook message on your application
Published date: Sunday, May 4, 2008
On: Moer and Éric Moreau's web site

Long time readers remember that I have already written an article titled “Drag and Drop in VB.Net” back in February 2004.

Lately, I was requested to enable an application to receive a drop event of an Outlook message. Of course the base of the operation is exactly the same but the message from Outlook is in a special proprietary format.

First look at my toolset

When I first had the request, I queried Google for it to discover that one of the tools I often use (Aspose.Network) offered something to help me. A first quick test showed me that I was able to handle the drop operation of an Outlook message correctly but when we were ready to implement it into the real solution which is using an Infragistics UltraTree we discovered that both products are not really compatible with each other. Infragistics has its own set of events that are not supported by Aspose. So I went to Google again...

Another false-positive result

My Google session quickly brought me to a Code Project article titled “Drag-and-Drop Attached File From Outlook (97 and above) to C# Window Form” from Tom Gueth that was very promising. So I downloaded it and give it a try to discover that it wasn’t working for what I needed. It allows you to drag an attachment from an email to your form but not the whole email as I needed. One of the comments at the bottom of this article led me to the solution I am showing here.

So what is working for me?

I was looking for a solution that doesn’t require me to instantiate Outlook as we all know that it can lead us into problems when deploying to a large set of users. But didn’t find anything working well with the constraints I had.

So I have added a reference to “Microsoft.Office.Interop.Outlook” component like shown in figure 1.

Figure 1: Adding a reference to Outlook

Then I built my very complex demo GUI like shown in figure 2. The GUI only contains 3 labels (named Label1, lblFormat, and lblFile in top-to-bottom order). The BorderStyle of the 3 controls has been set to FixedSingle, and the AutoSize property set to False. The AllowDrop property of the top-most label control has been set to True because this one will be used as the drop target.

Figure 2: the GUI of the demo application

Then I was ready to start writing code. I started by declaring a class level instance of Outlook like this:

Dim objOL As New Microsoft.Office.Interop.Outlook.Application

Then I have added code to the DragOver event of the Label1 control (the top-most one) to provide feedback when users are dragging a file (from Windows Explorer) or a mail message (from Outlook) over it:

If e.Data.GetDataPresent(DataFormats.FileDrop) Then
    'handle a file dragged from Windows explorer
    e.Effect = DragDropEffects.Copy
    lblFormat.Text = "DragOver ... File drop"
ElseIf e.Data.GetDataPresent("FileGroupDescriptor") Then
    'handle a message dragged from Outlook
    e.Effect = DragDropEffects.Copy
    lblFormat.Text = "DragOver ... Outlook"
Else
    'otherwise, do not handle
    e.Effect = DragDropEffects.None
    lblFormat.Text = ""
End If
This code is doing 2 things:
  • It changes the cursor when dragging over the label and a valid format (tested with the GetDataPresent method) is detected.
  • It displays the recognized format into the lblFormat label.

Then I have added this code to the DragLeave event of the Label1 control to empty the format label control:

lblFormat.Text = String.Empty
The only that is left now is to add code the DragDrop event, this is where the real juice is. Have I said that I wanted to support multiple files and/or email messages? This code does. This is the required code which I have commented for you to be able to follow what is happening:
If e.Data.GetDataPresent(DataFormats.FileDrop) Then
    'supports a drop of a file from Windows Explorer

    ' copy the name of the dragged files into a string array
    Dim draggedFiles As String() = CType(e.Data.GetData(DataFormats.FileDrop), String())

    'handle each file passed as needed
    For Each fileName As String In draggedFiles
        'hardcode a destination path for testing
        Dim strDestinationFile As String = _
                    IO.Path.Combine("c:\temp", _
                                    IO.Path.GetFileName(fileName))
        'test if source and destination are the same
        If strDestinationFile.Trim.ToUpper = fileName.Trim.ToUpper Then
            lblFile.Text += strDestinationFile + _
                            " - Source and Destination are the same!!!" + _
                            Environment.NewLine
        Else
            lblFile.Text += "Copying - " + _
                            strDestinationFile + Environment.NewLine
            IO.File.Copy(fileName, strDestinationFile)
        End If
    Next

ElseIf e.Data.GetDataPresent("FileGroupDescriptor") Then
    'supports a drop of a Outlook message

    'Dim objMI As Object - if you want to do late-binding
    Dim objMI As Microsoft.Office.Interop.Outlook.MailItem

    For Each objMI In objOL.ActiveExplorer.Selection()
        'hardcode a destination path for testing
        Dim strFile As String = _
                    IO.Path.Combine("c:\temp", _
                                    (objMI.Subject + ".msg").Replace(":", ""))
        lblFile.Text += strFile + Environment.NewLine
        objMI.SaveAs(strFile)
    Next
End If
lblFormat.Text = String.Empty
This code copies the files or emails into the “c:\temp” folder (that needs to exist). The reason why Outlook needs to be instantiated is because of this line of code which takes the currently selected items in Outlook to handle them (instead of really using what is in the ClipBoard):
For Each objMI In objOL.ActiveExplorer.Selection()

Going late-bound

If you don’t like the idea of referencing Outlook (because you are not sure what version of Outlook people are using), it is possible to use late-binding and still have the same result at runtime. Many programmers are using early-binding while developing to have access to the Intelli-Sense but go late-bound before building a release version.

To achieve it, you need to:

  • Remove the reference to Outlook
  • Switch to “Option Strict Off”
  • Change your objOL declaration to something like: Dim objOL As Object = GetObject(, "Outlook.Application")
  • Change your objMi declaration to something like: Dim objMI As Object

Conclusion

This article shows how to support file drop from Windows Explorer as well as an email message drop from Outlook. I would have preferred a solution without relying on Outlook but it seems to be much more complex. After all, if people are dropping a message from Outlook that means that it should be installed!


(Print this page)