Strange behaviour when using Marshal.GetActiveObject("Outlook.Application")

0

In order to start outlook and wait until it's available via Interop I wrote the following Console app:

static Outlook.Application outlook;
static void Main(string[] args)
{
    Console.WriteLine("Enter Profile:");
    var profile = Console.ReadLine();

    var process = Process.GetProcessesByName("Outlook").FirstOrDefault();
    if (process == null)
    {
        ProcessStartInfo startInfo = new ProcessStartInfo("outlook.exe", $"/profile \"{profile}\""); // MK_E_UNAVAILABLE appears until I click in the console window
        // ProcessStartInfo startInfo = new ProcessStartInfo("outlook.exe"); // Works as expected
        process = Process.Start(startInfo);
    }

    while (outlook == null && !process.HasExited)
    {
        try
        {
            outlook = (Outlook.Application)Marshal.GetActiveObject("Outlook.Application");
            break;
        }
        catch (System.Exception ex)
        {
            Console.WriteLine(ex.Message);
            outlook = null;
        }
        process.Refresh();
        Thread.Sleep(500);
    }

    if (outlook != null)
        Console.WriteLine($"Outlook is running.");

    Console.ReadKey();
}

I verified in task manager that console app is running under the same user as Outlook does (see here).

The output of the console app is:

Vorgang nicht verfügbar. (Ausnahme von HRESULT: 0x800401E3 (MK_E_UNAVAILABLE))
Vorgang nicht verfügbar. (Ausnahme von HRESULT: 0x800401E3 (MK_E_UNAVAILABLE))
Vorgang nicht verfügbar. (Ausnahme von HRESULT: 0x800401E3 (MK_E_UNAVAILABLE))

This message gets repeated until I click into the console window or resize it. Then output changes to

Outlook is running.

This does only happen when starting outlook with the profile parameter. Without profile parameter the message Outlook is running. appears straight after I selected the profile in the Outlook profile dialog.

Can anybody explain what's the reason for this behaviour?

c#
outlook
office-interop
asked on Stack Overflow May 22, 2020 by Abid

1 Answer

1

Try to use WaitForInputIdle() to force the processing of your application to wait until the message loop has returned to the idle state. When a process with a user interface is executing, its message loop executes every time a Windows message is sent to the process by the operating system. The process then returns to the message loop. A process is said to be in an idle state when it is waiting for messages inside of a message loop. This state is useful, for example, when your application needs to wait for a starting process to finish creating its main window before the application communicates with that window. If a process does not have a message loop, WaitForInputIdle() throws an InvalidOperationException.

Also I'd suggest adding any delay before checking whether it is running or not.

Process.Start(startInfo);
Thread.Sleep(5000);

Another possible solution is to use COM Automation with the Logon method which allows specifying the profile name:

myNameSpace = Application.GetNamespace("MAPI"); 
myNameSpace.Logon("LatestProfile", Type.Missing , true, true); 
answered on Stack Overflow May 22, 2020 by Eugene Astafiev

User contributions licensed under CC BY-SA 3.0