VB.Net Drag and Drop from Outlook

One thing I have been working on for years now is a database program that among other things has a part that lets you attach files into it. The drag and drop functionality was easy for regular files on the hard drive but a feature request came in to drag and drop files from a outlook attachment. Luckily someone had already figured this out in C# which I converted into VB here: http://www.codeproject.com/Articles/7140/Drag-and-Drop-Attached-File-From-Outlook-and-ab. This was all fine and dandy until I got a request last week to attach the actual email itself, not a attachment. After more searching I found someone that did this using the Outlook interop libraries here: http://www.emoreau.com/Entries/Articles/2008/05/Dropping-a-Outlook-message-on-your-application.aspx. So after a little more playing I updated my drag and drop code to decipher between a normal file, a Outlook attachment, or a Outlook email and act accordingly.

Couple notes: DisplayMessageBox is a custom message box used by my program (replace with MsgBox if needed) and AddTempFileToArray does exactly that, adds any temp files I create or use to a array which I then delete when my program closes (don’t want a bunch of temp files created and left), and SaveButton is enabled only during a edit operation.

In my control where I will accept the drop:

Private Sub MyControlToAcceptTheDrop_DragEnter(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles MyControlToAcceptTheDrop.DragEnter
' Make sure that the format is a file drop.
If (e.Data.GetDataPresent(DataFormats.FileDrop)) And (SaveButton.Visible = True) Then
e.Effect = DragDropEffects.Copy
ElseIf (e.Data.GetDataPresent("FileGroupDescriptor")) And (SaveButton.Visible = True) Then
e.Effect = DragDropEffects.Copy
Else
' Do not allow drop.
e.Effect = DragDropEffects.None
End If
End Sub

And my code to handle the drop:

'''

''' Handle File Drops
'''

''' DragEventArgs ''' Path to the actual file or temp file
''' Returns the full path to the file being dropped or to a temp file that contains the file in memory (for use with Outlook or other program drag drops)
Friend Function HandleFileDrops(ByVal e As System.Windows.Forms.DragEventArgs) As String
Try
If e.Data.GetDataPresent(DataFormats.FileDrop) Then
' We have a file so lets pass it to the calling form
Dim Filename As String() = CType(e.Data.GetData(DataFormats.FileDrop), String())
HandleFileDrops = Filename(0)
ElseIf e.Data.GetDataPresent("FileGroupDescriptor") Then
' We have a embedded file. First lets try to get the file name out of memory
Dim theStream As Stream = CType(e.Data.GetData("FileGroupDescriptor"), Stream)
Dim fileGroupDescriptor(512) As Byte
theStream.Read(fileGroupDescriptor, 0, 512)
Dim fileName As System.Text.StringBuilder = New System.Text.StringBuilder("")
Dim i As Integer = 76
While Not (fileGroupDescriptor(i) = 0)
fileName.Append(Convert.ToChar(fileGroupDescriptor(i)))
System.Math.Min(System.Threading.Interlocked.Increment(i), i - 1)
End While
theStream.Close()
' We should have the file name or if its a email the subject line. Create our temp file based on the temp path and this info
Dim myTempFile As String = Path.GetTempPath & fileName.ToString
' Look to see if this is a email message. If so save that temporarily and get the temp file.
If InStr(myTempFile, ".msg") > 0 Then
Dim objOL As New Microsoft.Office.Interop.Outlook.Application
Dim objMI As Microsoft.Office.Interop.Outlook.MailItem
If objOL.ActiveExplorer.Selection.Count > 1 Then
DisplayMessageBox("You can only drag and drop one item at a time into this screen. The first item you selected will be used.", "One Item At A Time", , FormStartPosition.CenterParent)
End If
For Each objMI In objOL.ActiveExplorer.Selection()
objMI.SaveAs(myTempFile)
Exit For
Next
objOL = Nothing
objMI = Nothing
Else
' If its a attachment we need to pull the file itself out of memory
Dim ms As MemoryStream = CType(e.Data.GetData("FileContents", True), MemoryStream)
Dim FileBytes(CInt(ms.Length)) As Byte
' read the raw data into our variable
ms.Position = 0
ms.Read(FileBytes, 0, CInt(ms.Length))
ms.Close()
' save the raw data into our temp file
Dim fs As FileStream = New FileStream(myTempFile, FileMode.OpenOrCreate, FileAccess.Write)
fs.Write(FileBytes, 0, FileBytes.Length)
fs.Close()
End If
' Make sure we have a actual file and also if we do make sure we erase it when done
If File.Exists(myTempFile) Then
' Assign the file name to the add dialog
HandleFileDrops = myTempFile
Call AddTempFileToArray(myTempFile)
Else
HandleFileDrops = String.Empty
End If
Else
Throw New System.Exception("An exception has occurred.")
End If
Catch ex As Exception
DisplayMessageBox("Could not copy file from memory. Please save the file to your hard drive first and then retry your drag and drop.", "Drag and Drop Failed")
HandleFileDrops = String.Empty
End Try

End Function

As you might be able to guess I only look at the first email message if multiple are selected and let the user know that also. I’m sure there is a way to loop through multiple files, Outlook attachments, or Outlook emails but I don’t need that functionality so I didn’t code it (but I did warn in case it happens).

9 thoughts on “VB.Net Drag and Drop from Outlook

  1. Allan, This code has helped me significantly and I know it’s from a long time ago, so I apologize for even asking the question. This code is functioning for me 99% of the time.

    I have a similar need to save files, Outlook attachments, or Outlook emails to my database. I can’t get the code to recognize when I am dragging an email attachment from an email. I have an email that has another email attached and I need to save only the attached email that is being dragged into my application window. The “If InStr(myTempFile, “.msg”) > 0″ is evaluating true and it is saving the full email, not just the attachment.

    I wonder if you have any thoughts that might help.

    Thanks,
    Brian

    1. So that’s a tricky one where there is no good answer. The Outlook drag and drop grabs the information about what your dropping. Since it sees the .msg it assumes you want the email even though you want the attachment that also happens to be a email. The best you could do is add a prompt that asks the user, something like:

      If (InStr(myTempFile, ".msg") > 0) AND (MsgBox("Do you want to add the email message itself? Answer No to add any attachment instead.", MsgBoxStyle.YesNo, "Message itself?") = MsgBoxResult.Yes)

      This way if they say no it will skip to the next else statement and do the attachment. If they click Yes it will add the email itself. Can’t think of a better way to do it.
      (Note: I didn’t test this but the logic should be correct)

  2. Thanks so much for the prompt response! Your solution is good. I’ll review your input with my colleague.

    Best regards and thanks again,
    Brian

  3. Looking around how to handle email attachments for my application and found your code very nice. Just a question the attachments from the mails saved are corrupted. So maybe there is something wrong with the length.

    1. Not sure, we’ve been using this code for years now for both email attachments and emails themselves without any issues.

  4. Hello Allan,
    I don’t know whether you would even see this message but I thought I could give it a try. I was searching for a solution to drag and drop emails from outlook into my software. And then I came across your code and I tried it but without succes.
    On the line If objOL.ActiveExplorer.Selection.Count > 1 Then I get the folowing error: De conversie van tekenreeks Drag and Drop Failed naar type Integer is ongeldig. The conversion of string Drag and Drop failed to type integer is invalid.

    1. It’s almost like objOL.ActiveExplorer is null. So in the first couple lines:

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

      Should be successful and objOL should not be nothing. If it is then yeah the next lines will fail. You can try to force it to a value just to make sure, something like:

      If val(objOL.ActiveExplorer.Selection.Count) > 1

      But otherwise I’m not sure why it would throw that error. This is a little old so maybe the interop libraries are outdated but were still using it daily in a program so it definitely does work. Make sure you have referenced that interop library in your program? Is there a inner message on the error?

  5. Hello Allan,

    Thanks for the response :-). I am not a trained programmer so maybe that could be part of the issue but I want to learn.
    When I put a watch on the objOL.ActiveExplorer I get the following error message (unfortunately it is in Dutch) but basically it seems to be that he cannot convert tot het Outlook_application. Interface is not registered he says.

    Kan COM-object van het type Microsoft.Office.Interop.Outlook.ApplicationClass niet converteren naar interfacetype Microsoft.Office.Interop.Outlook._Application. Deze bewerking is mislukt doordat de QueryInterface-aanroep voor het COM-onderdeel voor de interface met IID {00063001-0000-0000-C000-000000000046} is mislukt door de volgende fout: Interface is niet geregistreerd (Uitzondering van HRESULT: 0x80040155).

    1. So somewhere in your project you need to make a reference to the outlook library. Should be “Microsoft Outlook 16.0 Object Library”. If you are in VS 2019 or 2022 and making a .Net app it would be under “My Project” -> “References” -> “Add” then look through the COM list. Otherwise it doesn’t know what to do with that line.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.