Interop.Outlook не очищает выбранные письма при перетаскивании

У меня есть элемент управления, на который я могу сбрасывать почтовые элементы, работает нормально, но я не могу заставить его очистить выбор/элементы.

Например: я перетаскиваю почту 1 --> почта 1 находится в моем списке Я удаляю почту 1 из своего списка, возвращаюсь в Outlook и перетаскиваю почту 2
Почта 2 появляется в моем списке, но почта 1 также восстанавливается ! Я нашел много сообщений о Marshal.ReleaseComObject, но я думаю, что делаю это неправильно?

Спецификации: VS2010, фреймворк 4.0. ОС Windows 7, Outlook 2010

Вот часть моего кода:

Вызов моего метода Save:

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

Метод Save:

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

Я также пробовал oExplorer.ClearSelection(), но, как я могу судить по свойству count, он вообще не очищается.


person Mike Dole    schedule 30.12.2012    source источник


Ответы (3)


Потратив часы на чтение различных решений этой проблемы, которая в конечном итоге стала ошибкой в ​​​​способе обработки события ввода в Outlook при перемещении элемента управления, который может обрабатывать перетаскивание в другой программе, я обнаружил, что вы можете это исправить с одной строкой кода, и это то, что нужно распространять!

Microsoft использует буфер обмена для хранения, среди прочего, информации о выделении. Класс, используемый Outlook для этой цели, скрыт за ключом RenPrivateMessages. Его нельзя использовать, потому что интерфейс не освобождают, но, прочитав его, вы снимаете блокировку выбора.

Итак, все, что вам нужно сделать в событии drop в вашем коде, — это добавить эту строку (учитывая, что ваш EventArg называется e):

e.data.GetData("RenPrivateMessages");

person Tjabalooo    schedule 24.08.2015
comment
Мне так нравится этот ответ, я бы потратил на него награду, если бы автор все еще был активен! - person Breeze; 17.06.2016
comment
Если это не очевидно, я хочу отметить, что это также работает при работе с кодом C#/.NET. - person Vlad274; 14.09.2016

Я искал в Интернете решение без обходного пути для переключения панелей. После того, как я нашел решение, которое сработало для меня, я хотел бы поделиться им здесь.

Последней подсказкой было использование метода RemoveFromSelection активного проводника, потому что Marshal.ReleaseComObject не очищает выбор.

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

С уважением,

Кали

person Cali    schedule 28.08.2013

Использование делегата было не такой уж хорошей идеей, оказывается, вы можете найти обходной путь, чтобы повторно активировать свой прогноз.

После сохранения почтового элемента в файл я вызываю 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

Это очищает выбор и предотвращает зависание/зависание Outlook.

С уважением,

Майк

person Mike Dole    schedule 25.01.2013