Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / Languages / VB.NET / October 2007

Tip: Looking for answers? Try searching our database.

Wrapping Word.Application object with an IDisposable class?

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
surturz - 10 Oct 2007 06:00 GMT
Hi,

I'm using VB2005 + Office XP Enterprise.

If you create a Word.Application object, you risk a memory leak if your
application crashes because Word.Application is an unmanaged COM Interop
object.

I want to encapsulate the Word.Application in a Class that implements
IDisposable to avoid this potential memory leak. Here is the code I have:

   Imports Microsoft.Office.Interop
   ''' <summary>
   ''' Encapsulates MS Word using IDisposable to prevent memory leaks. Use
WordFactory.GetWordApp to obtain a memory-safe Word.Application object
   ''' </summary>
   ''' <remarks></remarks>
   Public Class WordFactory
       Implements IDisposable
       Public Sub New()
           mobjWordApp = New Word.Application
       End Sub
       Private mobjWordApp As Word.Application
       Public ReadOnly Property WordApp() As Word.Application
           Get
               Return mobjWordApp
           End Get
       End Property
       Public Shared Function GetWordApp() As Word.Application
           Dim wf As New WordFactory
           Return wf.WordApp
       End Function
   #Region " IDisposable Support "
       Private disposedValue As Boolean = False        ' To detect
redundant calls    
       ' IDisposable
       Protected Overridable Sub Dispose(ByVal disposing As Boolean)
           If Not Me.disposedValue Then
               If disposing Then
                   'free managed resources when explicitly called
               End If

               'free unmanaged resources
               On Error Resume Next
               mobjWordApp.Quit()
               On Error GoTo 0
           End If
           Me.disposedValue = True
       End Sub
       ' This code added by Visual Basic to correctly implement the
disposable pattern.
       Public Sub Dispose() Implements IDisposable.Dispose
           ' Do not change this code.  Put cleanup code in Dispose(ByVal
disposing As Boolean) above.
           Dispose(True)
           GC.SuppressFinalize(Me)
       End Sub
       Protected Overrides Sub Finalize()
           Call Dispose(False)
           MyBase.Finalize()
       End Sub
   #End Region
   End Class

Now the odd thing is that it seems to work fine when compiled. Code such as

       Dim w As Word.Application = WordFactory.GetWordApp
       Throw New Exception("An unhandled exception was intentionally thrown
for testing purposes")

Finalizes the Word.Application object correctly (i.e. it disappears from
Task Manager), but if the program is run from the VB IDE, WINWORD.EXE stays
in Task Manager.

Is this some artefact of the debugger? Or am I doing something wrong?
Jialiang Ge [MSFT] - 10 Oct 2007 09:00 GMT
Hello,

From your post, my understanding on this issue is: you want to know why the
Word process is not closed in Dispose method when the application is tested
in Visual Studio debug mode. If I'm off base, please feel free to let me
know.

I did a test with your WordFactory class. In order to see why the Word
process is not closed in Dispose, I removed the "On Error Resume Next" and
"On Error GoTo 0" around "mobjWordApp.Quit()", then I got the exception
thrown by Visual Studio debugger at the sentence:
*COM object that has been separated from its underlying RCW cannot be
used.*
This problem is most likely caused that your COM objects are called on
different threads. The creation of the COM object is on one thread (the
main thread in this issue), and the clean on another thread (the .NET
Garbage Collection thread in this context). By default we use STA apartment
model so if you are using COM objects in different threads, this may cause
issues like interop exceptions "object disconnected from its RCW". It means
that we need to keep track of the thread which created those COM objects.
If that thread ends, the COM object will also go away even if the RCW that
.NET is using is still alive because the GC has not cleaned it yet (Dispose
has not been called). In your question, you said that the problem only
occurs in VS IDE, but based on my test, sometimes the exception also occurs
when I run the application directly. In order to resolve the problem, I
still suggest that you call mobjWordApp.Quit in the thread where
wobjWordApp is created because Office COM object is designed as STA. Please
also call System.Runtime.InteropServices.Marshal.ReleaseComObject to ensure
all the reference count to the COM object is decreased. (See the kb article
Office application does not quit after automation from Visual Studio .NET
client http://support.microsoft.com/kb/317109).

Please let me know if you have any other concerns, or need anything else.

Sincerely,
Jialiang Ge (jialge@online.microsoft.com, remove 'online.')
Microsoft Online Community Support

==================================================
For MSDN subscribers whose posts are left unanswered, please check this
document: http://blogs.msdn.com/msdnts/pages/postingAlias.aspx

Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications. If you are using Outlook Express/Windows Mail, please make sure
you clear the check box "Tools/Options/Read: Get 300 headers at a time" to
see your reply promptly.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
surturz - 11 Oct 2007 06:21 GMT
Thanks for your very informative post.

Unfortunately, the whole point is to ensure the COM object is disposed if
there is an unhandled exception in my program, so I can't guarantee calling
.Quit from the creating thread.

Multi-threading isn't my strong suit - I usually write fairly high-level apps.

That KB article looks very useful, perhaps there is a better way using
ReleaseComObject().

-DCS

> Hello,
>
[quoted text clipped - 57 lines]
> ==================================================
> This posting is provided "AS IS" with no warranties, and confers no rights.
Jialiang Ge [MSFT] - 11 Oct 2007 12:31 GMT
Hello,

Although we could not call the Quit method on the Office application object
in Dispose because Dispose runs in the GC thread, in order to quit the Word
process when we encounter unhandled exceptions, I think we could register
the Application.ThreadException event
(http://msdn2.microsoft.com/en-us/library/system.windows.forms.application.t
hreadexception.aspx) if your project is a Windows Form application. In
WinForm applications, exceptions occurring in the main thread are caught
and handled by CLR(a default exception dialog will  be shown). We could
hook up and handle the Application.ThreadException event to provide a
custom exception handler. That is to say, Application_ThreadException event
handler runs on the main Windows Form thread, and if our Word.Application
object is also constructed on the main thread, we could call Quit on the
object to stop the process of Word. Here is my test code:

In application's main method, we register the events:
<SecurityPermission(SecurityAction.Demand,
Flags:=SecurityPermissionFlag.ControlAppDomain)> _
Public Shared Sub Main()
   ' Add the event handler for handling UI thread exceptions to the event.
   AddHandler Application.ThreadException, AddressOf
ErrorHandlerForm.Form1_ThreadException

   ' Set the unhandled exception mode to force all Windows Forms errors to
go through
   ' our handler.
   
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException)

   ' Runs the application.
   Application.Run(New Form1())
End Sub

To raise an unhandled exeption:
' Programs the button to throw an exception when clicked.
Private Sub button1_Click(ByVal sender As Object, ByVal e As
System.EventArgs) Handles button1.Click
   Throw New ArgumentException("The parameter was invalid")
End Sub

In Private Shared Sub Form1_ThreadException(ByVal sender As Object, ByVal t
As ThreadExceptionEventArgs), we try to access the Word.Application object
and call Quit on it.

I am still doing researches to see whether there are better ways to ensure
that the Word process is stopped. I will get back to you as soon as
possible. Thank you for your patience.

Sincerely,
Jialiang Ge  (jialge@online.microsoft.com, remove 'online.')
Microsoft Online Community Support

=================================================
When responding to posts, please "Reply to Group" via your newsreader
so that others may learn and benefit from your issue.
=================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
Jialiang Ge [MSFT] - 16 Oct 2007 03:28 GMT
Hello,

Would you mind letting me know the result of the suggestions? How is the
issue in your side? Is it a Windows form project or a console one? If you
need further assistance, feel free to let me know. I will be more than
happy to be of assistance.

Have a great day!

Sincerely,
Jialiang Ge  (jialge@online.microsoft.com, remove 'online.')
Microsoft Online Community Support

=================================================
When responding to posts, please "Reply to Group" via your newsreader
so that others may learn and benefit from your issue.
=================================================
This posting is provided "AS IS" with no warranties, and confers no rights.

Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.