Office application does not quit

M

Max

I have the following code on a form that launches Microsoft Outlook and creates a new email message for the user:

Code:
Outlook.Application oApp = new Outlook.Application();
Outlook.MailItem oMail = (Outlook.MailItem)oApp.CreateItem(Outlook.OlItemType.olMailItem);
oMail.HTMLBody = "SOME HTML TEXT HERE";
oMail.Display(oApp);

oMail.Close(Outlook.OlInspectorClose.olDiscard);
NAR(oMail);
oApp.Quit();
NAR(oApp);
GC.Collect();
GC.WaitForPendingFinalizers();

where NAR(....) is defined as follows:

Code:
private void NAR(object o)
{
try{ System.Runtime.InteropServices.Marshal.ReleaseComObject(o); }
catch{}
finally{ o = null; }
}

Problem is that when the Outlook application created is closed, it still resides
in memory. A quick check in the task list shows OUTLOOK.EXE wasting memory
space. If I run this code 10 times it will waste 180-250MB of memory. The only
way to kill it is by going to the system tray and manually removing it. How can
I force OUTLOOK.EXE to die? The Garbage collector does not seem to be doing a
good job. In fact the above code works and kills OUTLOOK.EXE when
Code:
 oMail.Display(oApp);
is not presend and the Outlook application is not
shown, but when it is shown to the user then it just lies in memory even after it was closed.
 
W

Willy Denoyette [MVP]

This ...
oMail.Display(oApp);
instructs Outlook to switch to interactive mode, so...
the outlook server EXE is waiting for a "Send" command, that means you need
to press the Send button or you have to execute a oMail.Send(); instruction
in the client.

All this GC stuff and ReleaseComObject stuff is not required here, the GC
has nothing to do with all this.

Willy.
 
M

Max

Thanks for your reply Willy!

What if the user decides not to send this email and just presses the close button in Outlook.
Is there a way to know when the user does this so I can kill the Outlook process programatically
to remove it from memory?

Cheers,
Max



Willy Denoyette said:
This ...
oMail.Display(oApp);
instructs Outlook to switch to interactive mode, so...
the outlook server EXE is waiting for a "Send" command, that means you need
to press the Send button or you have to execute a oMail.Send(); instruction
in the client.

All this GC stuff and ReleaseComObject stuff is not required here, the GC
has nothing to do with all this.

Willy.


Max said:
I have the following code on a form that launches Microsoft Outlook and
creates a new email message for the user:

Code:
Outlook.Application oApp = new Outlook.Application();
Outlook.MailItem oMail =
(Outlook.MailItem)oApp.CreateItem(Outlook.OlItemType.olMailItem);
oMail.HTMLBody = "SOME HTML TEXT HERE";
oMail.Display(oApp);

oMail.Close(Outlook.OlInspectorClose.olDiscard);
NAR(oMail);
oApp.Quit();
NAR(oApp);
GC.Collect();
GC.WaitForPendingFinalizers();

where NAR(....) is defined as follows:

Code:
private void NAR(object o)
{
try{ System.Runtime.InteropServices.Marshal.ReleaseComObject(o); }
catch{}
finally{ o = null; }
}

Problem is that when the Outlook application created is closed, it still
resides in memory. A quick check in the task list shows OUTLOOK.EXE
wasting memory space. If I run this code 10 times it will waste 180-250MB
of memory. The only way to kill it is by going to the system tray and
manually removing it. How can I force OUTLOOK.EXE to die? The Garbage
collector does not seem to be doing a good job. In fact the above code
works and kills OUTLOOK.EXE when
Code:
 oMail.Display(oApp);
is
not presend and the Outlook application is not shown, but when it is shown
to the user then it just lies in memory even after it was closed.
 
W

Willy Denoyette [MVP]

Max said:
Thanks for your reply Willy!

What if the user decides not to send this email and just presses the close
button in Outlook. Is there a way to know when the user does this so I can
kill the Outlook process programatically
to remove it from memory?

Cheers,
Max

Well, there is something wrong with your scenario. You are using COM interop
to automate Outlook, but at the same time you are using Outlook in an
interactive fashion, these two don't go well together, whenever you switch
to interactive mode as by calling Display(), you put the responsabilty to
interact and exit the application in the hands of the interactive user, else
you don't show the UI and it's up to the .NET (well, COM) client to clean up
after it has done. In you scenario there is no way for the client
application to know whether the interactiv user doesn't want to send a mail
message.
Really, I wonder why you are doing this.


Willy.
 
M

Max

Good question.

I'm working on an application which manages information about units in the field
which could have problems. This requires that we have some kind of "generate a service call" option.
Basically when the user clicks the "Generate service call" button, the email client of choice, whether
it be MS Office 2000/2002/XP/2003 or Outlook Expressed is launched and information about the
deffective unit is dumped into the body of the email. The user then selects the recipient - ie some service
person who needs to go out in the field and fix the unit, and sends the email OR could technically just close
the Outlook window created.

I'm actually using late binding in my code, not the example I posted earlier. As it turns out when an instance
of Outlook is launched, even if the user clicks on the "Send" button in Outlook to send the message and
the window closes, if you check in the task manager OUTLOOK.EXE still hangs in memory. This also
happens even if the user just closes the Outlook window without sending any message.

I could just grab the address book from either program and create my own email window with the contacts
on one side and I won't have to worry about launching any Outlook or Outlook Express instance, but.... I
kind of wanted to just launch the email application of choice.

I suppose it's not possible to do all this in .NET?
 
W

Willy Denoyette [MVP]

Inline ***

Willy.

Max said:
Good question.

I'm working on an application which manages information about units in the
field
which could have problems. This requires that we have some kind of
"generate a service call" option.
Basically when the user clicks the "Generate service call" button, the
email client of choice, whether
it be MS Office 2000/2002/XP/2003 or Outlook Expressed is launched and
information about the
deffective unit is dumped into the body of the email. The user then
selects the recipient - ie some service
person who needs to go out in the field and fix the unit, and sends the
email OR could technically just close
the Outlook window created.

I'm actually using late binding in my code, not the example I posted
earlier. As it turns out when an instance
of Outlook is launched, even if the user clicks on the "Send" button in
Outlook to send the message and the window closes, if you check in the
task manager OUTLOOK.EXE still hangs in memory. This also
happens even if the user just closes the Outlook window without sending
any message.

*** I understand, but you can't send a Quit command from the client as this
will interfere with the UI user do you?
This is what Outlook is waiting for to go away. What you should do is
communicate back to the client to signal that the UI user has done with it,
the COM client waits to receive an event after which he calls Quit to get
rid of the server (Outlook.exe). Another thing you could do is connect to a
running instance instead of creating a new instance of the Outlook app.
(Check the Marshall class for the GetActiveObject()). If Outlook is allready
running it connects to the running instance, otherwise it starts a new
instance.
 
M

Max

Thanks for your reply Willy.
*** I understand, but you can't send a Quit command from the client as this
will interfere with the UI user do you?
No no, I am not using Quit() in my code, I'm just creating the instance and
giving it to the user. What I posted earlier was just me "experimenting" with early
binding to see how to kill the running instance with Quit() and it wasn't working :))
What you should do is communicate back to the client to signal that the UI user has
done with it, the COM client waits to receive an event after which he calls Quit to get
rid of the server (Outlook.exe).
This is the part I don't get. I don't know how to communicate from the Outlook UI user
to the client. I don't have control of Outlook, the user does. I assume there is some way
I could wait for an event but I don't know what to wait for and how to wait for it.
After I use Display(....) the client application keeps running and does something else,
while the user looks at the message in Outlook and sends it (or closes it) whenever s/he
decides. What event(s) is(are) there to let the client know what Outlook did? Like
how do I know in the client when the user sends the message or closes Outlook so I can
call Quit() in the client? What event does the COM client wait for before calling Quit()?
 

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