Handle COM events

M

Max

I have some code that launches MS Outlook and creates a new email message then
gives control of the Outlook application to the user by displaying it on the screen.
The problem is that when the user closes the Outlook application or sends an email
the Outlook window closes but the process Outlook.exe remains in memory. I have my
code waiting for the close event from the COM and I call Quit() on the Outlook
application but Outlook.exe still hangs in memory. Can anyone tell me what I'm doing
wrong? I just want to get Outlook.exe out of the memory. Sample code is below:

private Outlook.Application m_oApp = null;
private Outlook.MailItem m_oMail = null;

private void button_Click(object sender, System.EventArgs e)
{
try
{
m_oApp = new Outlook.Application();
m_oApp.Inspectors.NewInspector += new Outlook.InspectorsEvents_NewInspectorEventHandler(Inspectors_NewInspector);

m_oMail = (Outlook.MailItem)m_oApp.CreateItem(Outlook.OlItemType.olMailItem);
m_oMail.Display(m_oApp);
}
catch(Exception ex)
{
Debug.WriteLine(ex.ToString());
}
}

private void Inspectors_NewInspector(Outlook.Inspector Inspector)
{
Debug.WriteLine("Inspectors_NewInspector");
((Outlook.InspectorEvents_Event)Inspector).Close +=
new Outlook.InspectorEvents_CloseEventHandler(Outlook_Closed);
}

private void Outlook_Closed()
{
Debug.WriteLine("Outlook_Closed");
try
{
//m_oMail.Close(Outlook.OlInspectorClose.olPromptForSave);
System.Runtime.InteropServices.Marshal.ReleaseComObject(m_oMail);
GC.Collect();
GC.WaitForPendingFinalizers();

m_oApp.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(m_oApp);
GC.Collect();
GC.WaitForPendingFinalizers();
}
catch(Exception ex)
{
Debug.WriteLine(ex.ToString());
}
finally
{
m_oMail = null;
m_oApp = null;
Debug.WriteLine("Cleaned up everything....");
}
}
 
W

Willy Denoyette [MVP]

Max,

When you go that road, you have to release the Inspector event reference
too... (a COM connection point object)

Outlook.InspectorEvents_Event Inspect =
(Outlook.InspectorEvents_Event)Inspector;

...

// when done release all COM references when you need deterministic release
of the COM server.
Marshal.ReleaseComObject(Inspect);
Marshal.ReleaseComObject(..);
..
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers()
Willy.
 
M

Max

I released all the references and removed all the events added as well but Outlook.exe still
won't quit even after being told to go away. I'm confused. The code with changes is below:

private Outlook.Application m_oApp = null;
private Outlook.MailItem m_oMail = null;
private Outlook.Inspectors m_oInsp = null;
private Outlook.InspectorEvents_Event m_oInspector = null;

private void button_Click(object sender, System.EventArgs e)
{
try
{
m_oApp = new Outlook.Application();
oApp.ItemSend += new Outlook.ApplicationEvents_11_ItemSendEventHandler(Outlook_ItemSent);

m_oInsp = m_oApp.Inspectors;
m_oInsp.NewInspector += new Outlook.InspectorsEvents_NewInspectorEventHandler(Inspectors_NewInspector);

m_oMail = (Outlook.MailItem)m_oApp.CreateItem(Outlook.OlItemType.olMailItem);
m_oMail.Display(m_oApp);
}
catch(Exception ex)
{
Debug.WriteLine(ex.ToString());
}
}

private void Outlook_ItemSent(object Item, ref bool Cancel)
{
Debug.WriteLine("Outlook_ItemSent");
m_oMail.Send(); // Force to send email now
}

private void Inspectors_NewInspector(Outlook.Inspector Inspector)
{
Debug.WriteLine("Inspectors_NewInspector");
m_oInspector = (Outlook.InspectorEvents_Event)Inspector;
m_oInspector.Close += new Outlook.InspectorEvents_CloseEventHandler(Outlook_Closed);
}

private void Outlook_Closed()
{
Debug.WriteLine("Outlook_Closed");
try
{
//m_oMail.Close(Outlook.OlInspectorClose.olPromptForSave);
System.Runtime.InteropServices.Marshal.ReleaseComObject(m_oMail);
GC.Collect();
GC.WaitForPendingFinalizers();

m_oInspector.Close -= new Outlook.InspectorEvents_CloseEventHandler(Outlook_Closed);
System.Runtime.InteropServices.Marshal.ReleaseComObject(m_oInspector);
GC.Collect();
GC.WaitForPendingFinalizers();

m_oInsp.NewInspector -= new Outlook.InspectorsEvents_NewInspectorEventHandler(Inspectors_NewInspector);
System.Runtime.InteropServices.Marshal.ReleaseComObject(m_oInsp);
GC.Collect();
GC.WaitForPendingFinalizers();

m_oApp.ItemSend -= new Outlook.ApplicationEvents_11_ItemSendEventHandler(Outlook_ItemSent);
m_oApp.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(m_oApp);
GC.Collect();
GC.WaitForPendingFinalizers();
}
catch(Exception ex)
{
Debug.WriteLine(ex.ToString());
}
finally
{
m_oMail = null;
m_oInspector = null;
m_oInsp = null;
m_oApp = null;
Debug.WriteLine("Cleaned up everything....");
}
}
 
W

Willy Denoyette [MVP]

Max said:
I released all the references and removed all the events added as well but
Outlook.exe still
won't quit even after being told to go away. I'm confused. The code with
changes is below:

Well, I changed your code a bit and transformed it into a console app.
Try this and watch Outlook.exe in taskman.... (this works for me)

using System;
using System.Runtime.InteropServices;
using Outlook; // your PIA namespace
class Tester
{
static Application oApp;
static MailItem myMail;
static Outlook.InspectorEvents_Event Inspect;
[STAThread]
static void Main()
{
oApp = new Application();
oApp.Inspectors.NewInspector += new
Outlook.InspectorsEvents_NewInspectorEventHandler(Inspectors_NewInspector);
myMail = (MailItem)oApp.CreateItem(OlItemType.olMailItem);
myMail.Display(oApp);
myMail.Recipients.Add("nnnnnn@xxxxxx");
myMail.Body = "Test";
// Wait 30 seconds before terminating this client application.
// keep pumping messages (for STA threads only), don't use Sleep in STA
threads!!!) so the finalizer can run.
System.Threading.Thread.CurrentThread.Join(30000);
}
static void Inspectors_NewInspector(Outlook.Inspector Inspector)
{
Console.WriteLine("Inspectors_NewInspector");
Inspect = (Outlook.InspectorEvents_Event)Inspector;
Inspect.Close +=
new Outlook.InspectorEvents_CloseEventHandler(Outlook_Closed);
}

static void Outlook_Closed()
{
Console.WriteLine("Outlook_Closed");
try
{
((Outlook._Application)oApp).Quit();
Marshal.ReleaseComObject(Inspect);
Marshal.ReleaseComObject(myMail);
Marshal.ReleaseComObject(oApp);
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
}
finally
{
Console.WriteLine("Outlook.exe should terminate real soon....");
}
}
}


Willy.
 
M

Max

Willy thanks so much for your help! I copied your code and tried it out but
Outlook.exe still remains in memory :( Is there a way to debug this and see
what is holding it from quitting, ie any references not closed.... ?


Willy Denoyette said:
Max said:
I released all the references and removed all the events added as well but
Outlook.exe still
won't quit even after being told to go away. I'm confused. The code with
changes is below:

Well, I changed your code a bit and transformed it into a console app.
Try this and watch Outlook.exe in taskman.... (this works for me)

using System;
using System.Runtime.InteropServices;
using Outlook; // your PIA namespace
class Tester
{
static Application oApp;
static MailItem myMail;
static Outlook.InspectorEvents_Event Inspect;
[STAThread]
static void Main()
{
oApp = new Application();
oApp.Inspectors.NewInspector += new
Outlook.InspectorsEvents_NewInspectorEventHandler(Inspectors_NewInspector);
myMail = (MailItem)oApp.CreateItem(OlItemType.olMailItem);
myMail.Display(oApp);
myMail.Recipients.Add("nnnnnn@xxxxxx");
myMail.Body = "Test";
// Wait 30 seconds before terminating this client application.
// keep pumping messages (for STA threads only), don't use Sleep in STA
threads!!!) so the finalizer can run.
System.Threading.Thread.CurrentThread.Join(30000);
}
static void Inspectors_NewInspector(Outlook.Inspector Inspector)
{
Console.WriteLine("Inspectors_NewInspector");
Inspect = (Outlook.InspectorEvents_Event)Inspector;
Inspect.Close +=
new Outlook.InspectorEvents_CloseEventHandler(Outlook_Closed);
}

static void Outlook_Closed()
{
Console.WriteLine("Outlook_Closed");
try
{
((Outlook._Application)oApp).Quit();
Marshal.ReleaseComObject(Inspect);
Marshal.ReleaseComObject(myMail);
Marshal.ReleaseComObject(oApp);
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
}
finally
{
Console.WriteLine("Outlook.exe should terminate real soon....");
}
}
}


Willy.
 
M

Max

I just tested your code again on another computer and it seems that Outlook.exe
is terminated correctly there. I'm not sure now why it does not terminate on my
laptop which I use for development. I have dissabled some services and I also have
antivirus and firewal software along with other anti-spyware running in the backgroud.
Is there a particular service responsible for the removal of Outlook.exe which I might
have dissabled and I'm not aware of?

Cheers,
Max


Willy Denoyette said:
Max said:
I released all the references and removed all the events added as well but
Outlook.exe still
won't quit even after being told to go away. I'm confused. The code with
changes is below:

Well, I changed your code a bit and transformed it into a console app.
Try this and watch Outlook.exe in taskman.... (this works for me)

using System;
using System.Runtime.InteropServices;
using Outlook; // your PIA namespace
class Tester
{
static Application oApp;
static MailItem myMail;
static Outlook.InspectorEvents_Event Inspect;
[STAThread]
static void Main()
{
oApp = new Application();
oApp.Inspectors.NewInspector += new
Outlook.InspectorsEvents_NewInspectorEventHandler(Inspectors_NewInspector);
myMail = (MailItem)oApp.CreateItem(OlItemType.olMailItem);
myMail.Display(oApp);
myMail.Recipients.Add("nnnnnn@xxxxxx");
myMail.Body = "Test";
// Wait 30 seconds before terminating this client application.
// keep pumping messages (for STA threads only), don't use Sleep in STA
threads!!!) so the finalizer can run.
System.Threading.Thread.CurrentThread.Join(30000);
}
static void Inspectors_NewInspector(Outlook.Inspector Inspector)
{
Console.WriteLine("Inspectors_NewInspector");
Inspect = (Outlook.InspectorEvents_Event)Inspector;
Inspect.Close +=
new Outlook.InspectorEvents_CloseEventHandler(Outlook_Closed);
}

static void Outlook_Closed()
{
Console.WriteLine("Outlook_Closed");
try
{
((Outlook._Application)oApp).Quit();
Marshal.ReleaseComObject(Inspect);
Marshal.ReleaseComObject(myMail);
Marshal.ReleaseComObject(oApp);
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
}
finally
{
Console.WriteLine("Outlook.exe should terminate real soon....");
}
}
}


Willy.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top