1
votes

I have written a sub to send an e-mail through Outlook when I click a send button located in a WinForm. If Outlook is closed, my code works fine. When Outlook is already opened, I keep getting an error with OutMail = oApp.CreateItem(0)

An unhandled exception of type 'System.InvalidCastException' occurred in OfficeAutomation.exe

Additional information: Unable to cast COM object of type 'Microsoft.Office.Interop.Outlook.ApplicationClass' to interface type 'Microsoft.Office.Interop.Outlook._Application'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{00063001-0000-0000-C000-000000000046}' failed due to the following error: The RPC server is unavailable. (Exception from HRESULT: 0x800706BA).

Private Sub EmailOut_Click(sender As Object, e As EventArgs) Handles EmailOut.Click
    Dim oApp As Outlook.Application = Nothing

    ' Check whether there is an Outlook process running.
    Dim outlookRunning As Integer = Process.GetProcessesByName("OUTLOOK").Length
    If outlookRunning > 0 Then
        ' If Outlook is running, use the GetActiveObject method to obtain the 
        ' process and cast it to an Application object.
        Try
            oApp = TryCast(System.Runtime.InteropServices.Marshal.GetActiveObject("Outlook.Application"),  _
                Outlook.Application)
        Catch generatedExceptionName As System.Exception
            oApp = TryCast(Activator.CreateInstance(Type.GetTypeFromProgID("Outlook.Application")),  _
                Outlook.Application)
        Finally
            ' Kill Outlook and then restart it as a last resort.
            Dim workers As Process() = Process.GetProcessesByName("OUTLOOK")
            For Each worker As Process In workers
                worker.Kill()
                worker.WaitForExit()
                worker.Dispose()
            Next
        End Try
    Else
        ' If Outlook is not running, create a new instance of Outlook.
        oApp = New Outlook.Application()
        Dim ns As Outlook.NameSpace = oApp.GetNamespace("MAPI")
        Try
            ' try to use default profile and do not open a window
            ' if login fails, then we must pop up a window and let the 
            ' user choose a profile to allow access
            ns.Logon("", "", False, System.Reflection.Missing.Value)
        Catch generatedExceptionName As System.Exception
            ' use default profile and pop up a window
            ns.Logon("", "", True, True)
        End Try
        ns = Nothing
    End If
    Dim OutMail As Outlook.MailItem

    OutMail = oApp.CreateItem(0)

    With OutMail
        If Not String.IsNullOrEmpty(EmailAdr.Text) Then
            .To = EmailAdr.Text
        Else
            MessageBox.Show("Please enter an e-mail address", "Missing Recipient", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
            Exit Sub
        End If
        If Not String.IsNullOrEmpty(CcAdr.Text) Then
            .CC = CcAdr.Text
        End If
        .Subject = OutSubject.Text
        .Body = OutTextBox.Text
        System.Threading.Thread.Sleep(5000)
        .Send()
    End With
    System.Threading.Thread.Sleep(5000)
    oApp = Nothing
    Microsoft.VisualBasic.Shell("taskkill /F /IM outlook.exe", Microsoft.VisualBasic.vbHide)
End Sub
2

2 Answers

2
votes

Do not use GetActiveObject - Outlook is a singleton, CreateInstance will return a pointer to the already running instance.

1
votes

You should try creating a new instance of outlook regardless of whether it's running or not. I don't think there's any need to try to grab onto the running instance (if that's even possible, which it seems like is not).

EDIT: I would definitely take Dmitry's word over mine, however.