Mike Dole
Mike Dole

Reputation: 687

Interop.Outlook doesn't clear selected mails at drag and drop

I have a control which I can drop mail items on, works fine but I can't get it to clear the selection / items.

For example: I drag and drop mail 1 --> mail 1 is in my list I delete mail 1 from my list go back to Outlook and drag and drop mail 2
Mail 2 appears in my list but mail 1 is also revived! I've found a lot of postings about Marshal.ReleaseComObject but I guess I'm not doing it in the right way?

Specs: VS2010, 4.0 framework. Windows 7 OS, Outlook 2010

Here's part of my code:

The call to my Save method:

ElseIf e.Data.GetDataPresent("FileGroupDescriptor") Then
    Try
        Dim SafeSaveMethod As New dlgCallSaveMails(AddressOf SaveMailsFromSelection)
        Me.BeginInvoke(SafeSaveMethod, Me.FileData.Pad)

The Save method:

Private Sub SaveMailsFromSelection(_path As String)
    ' File uit Outlook
    Dim x As Integer
    Dim xitmndx As Integer = 0
    Dim DestFile As String
    Dim oOutLook As New Outlook.Application
    Dim oExplorer As Outlook.Explorer
    Dim oSelection As Outlook.Selection
    Dim strFile As String

    oExplorer = oOutLook.ActiveExplorer
    oSelection = oExplorer.Selection
    Dim currentFolder As MAPIFolder = oExplorer.CurrentFolder
    Dim folders As Folders = currentFolder.Folders


    Try
        For Each mitem As Object In oSelection
            xitmndx += 1

            Dim mi As Microsoft.Office.Interop.Outlook.MailItem = TryCast(mitem, Microsoft.Office.Interop.Outlook.MailItem)

                        mi.SaveAs(_path & "\" & String.Format("{0:yyyy-MM-dd_hh-mm-ss-tt}", mi.CreationTime) & "-" & CleanInput(mi.Subject) & ".msg", Outlook.OlSaveAsType.olMSG)

                Marshal.ReleaseComObject(mi)
                mi = Nothing
        Next

    Catch ex As System.Exception
        WriteError2EventLog("Error picDropZone_DragDrop 4: " & ex.ToString)
        MsgBox(Err.Description, MsgBoxStyle.Exclamation, "mycontrol")
    Finally
        Marshal.ReleaseComObject(oExplorer)
        Marshal.ReleaseComObject(oSelection)
        Marshal.ReleaseComObject(currentFolder)
        Marshal.ReleaseComObject(folders)
        Marshal.FinalReleaseComObject(oExplorer)
    End Try
End Sub

I also tried oExplorer.ClearSelection() but as I can tell from the count property it doesn't clear at all

Upvotes: 4

Views: 1750

Answers (3)

Tjabalooo
Tjabalooo

Reputation: 76

After spending hours reading up on different solutions to this problem, which ends up beeing a bug in Outlooks way of handling the enter-event when moving over a control that can handle drag & drop in another program, I found out that you can fix it with one single line of code and that is something that should be spread!

Microsoft uses the clipboard to store, among other things, information about the selection. The class that is used by Outlook for this purpose is hidden behind the key named RenPrivateMessages. It can't be used because they won't release the interface, but by reading it you clear the lock on the selection.

So, all you have to do in the drop-event in your code is to add this row (given that your EventArg is named e):

e.data.GetData("RenPrivateMessages");

Upvotes: 6

Cali
Cali

Reputation: 11

I was searching the web for a solution without the workaround to switch the panes. After I had found a solution that worked for me, I would like to share it here.

The final clue, was to use the RemoveFromSelection method of the active explorer, cos the Marshal.ReleaseComObject only don't clear the selection.

Public Sub outlook_drop()
    Try
        get_outlook_application_explorer()
        If IsNothing(oExplorer) = True Then
            MessageBox.Show("Cannot open Outlook.")
            Exit Sub
        End If

        Dim selection As Selection = oExplorer.Selection
        If selection.Count = 0 Then
            Marshal.ReleaseComObject(selection)
            MessageBox.Show("Nothing selected.")
            Exit Sub
        End If

        Dim filename As String
        Dim ext As String = ".msg"

        Dim mail As MailItem                                ' Important, no 'Shadow'-objects, such as "For Each mail as MailItem in selection", cos you need to free it with Marshal.ReleaseComObject()...
        For Each mail In selection
            Dim subtxt As String = mail.Subject
            If Not String.IsNullOrEmpty(subtxt) Then
                If subtxt.Length > 120 Then
                    subtxt = Left(subtxt, 120)
                End If
            End If

            filename = fill_filename(mail.Attachments.Count.ToString, subtxt, mail.SenderName, mail.ReceivedTime.ToShortDateString)

            Dim newFile As String = IO.Path.Combine(fuldir, filename + ext)
            Dim count As Integer = 0
            While IO.File.Exists(newFile)
                count += 1
                If count > 25 Then
                    newFile = Nothing
                    Exit While
                End If

                newFile = IO.Path.Combine(fuldir, filename + "(" + count.ToString + ")" + ext)
            End While

            If String.IsNullOrEmpty(newFile) = False Then
                mail.SaveAs(newFile)
            End If
            oExplorer.RemoveFromSelection(mail) ' Important, to remove the object from Selection, ReleaseComObject() only don't do.
            Marshal.ReleaseComObject(mail)  
        Next

        Marshal.ReleaseComObject(selection)
    Catch ex As System.Exception
        MessageBox.Show(ex.Message)
    End Try
End Sub

Regards,

Cali

Upvotes: 1

Mike Dole
Mike Dole

Reputation: 687

Using a delegate wasn't such a good idea, turns out you can do a workaround to reactivate your outlook.

After saving the mailitem to file I make a call to SwitchOutlookPanes()

 Public Sub SwitchOutlookPanes()
    Dim Outlook As Microsoft.Office.Interop.Outlook.Application
    Dim explorer As Microsoft.Office.Interop.Outlook.Explorer = Nothing
    Try
        If Outlook Is Nothing Then
            If Outlook Is Nothing Then Outlook = CType(Microsoft.VisualBasic.Interaction.GetObject("", "Outlook.Application"), Microsoft.Office.Interop.Outlook.Application)
            explorer = Outlook.ActiveExplorer
        End If

        If Outlook IsNot Nothing And explorer IsNot Nothing Then
            Dim nMAPIFOlder As Interop.Outlook.MAPIFolder = explorer.CurrentFolder
            explorer.CurrentFolder = Outlook.OlDefaultFolders.olFolderContacts
            System.Threading.Thread.Sleep(1500)
            explorer.CurrentFolder = nMAPIFOlder
        End If
    Catch ex As System.Exception
    Finally
        Marshal.ReleaseComObject(explorer)
        Marshal.ReleaseComObject(Outlook)
    End Try

End Sub

This clears the selection and prevents Outlook from freezing / hanging..

Regards,

Mike

Upvotes: 0

Related Questions