Object Life Cycle Implications

Team-Fly    

 
.NET and COM Interoperability Handbook, The
By Alan Gordon
Table of Contents
Chapter Seven.  Advanced .NET to COM Interop

Object Life Cycle Implications

There is a variety of ways to instantiate an object with COM, the typical way being to call CoCreateInstance. With COM, any function that activates an object will also initialize the reference count to one. When you are done with the object, you must remember to call Release on the object. When you decide to call Release is entirely up to you. In some cases, you will instantiate an object, call methods on one or more of its interfaces, and then immediately release the interface pointer. In other cases, you may instantiate your COM object when the application starts and hold the interface pointer until the application shuts down. In this latter model, you will likely use the same object again and again. Which approach you choose is entirely up to you, but it will likely be strongly driven by (a) the cost (in terms of time) to instantiate an object and (b) the cost in terms of memory and or other resources, like database connections or locks to maintain an extant object. In other words, if it does not take much time to instantiate an object, but the object consumes a lot of resources while it exists, you are better off instantiating the object only when you need it and then releasing it immediately. If the reverse is true, that is, it takes a long time to instantiate the object, but, after it is created, it does not consume a great deal of resources, you are better off keeping the object around until the application shuts down. Of course, many COM objects do not fall strongly into either camp; they neither take an excessively long time to instantiate nor consume a great deal of resources while they are extant. In those cases, you are better off taking the approach of instantiating the object when your application starts and then holding until your application shuts down. With this approach, you save the overhead associated with instantiating and destroying your objects.

If the resource consumption or initialization time of a COM object does favor one or the other life cycle approaches, be aware that using a COM object from a managed code client dramatically changes its life cycle semantics. All managed code objects are garbage collected. A managed code object only becomes eligible for garbage collection when it is no longer reachable through a reference. When you are using a COM object through COM Interop, the RCW, which is a managed code object, holds all the Interface pointers on the underlying COM object. The Finalize method in the RCW will release all of these interface pointers when the RCW is garbage collected. Unfortunately, because it's a managed object, the RCW won't be garbage collected until the garbage collector runs, which, if memory is not in short supply on your system, will likely not be until the application shuts down.

Fortunately, you can immediately release a COM object using the ReleaseCOMObject method on the System.Runtime.InteropServices.Marshal class. Calling this method will immediately call the Release method on the underlying COM object.

Let's look at an example that illustrates this point using the COM financial component that I introduced in Chapter 6. To make the example more useful for the subject matter of this section, I will override the FinalRelease method in the ATL CComObjectRootEx class and have it display a message box when the financial object's reference count goes to 0.

Note

A COM object built with ATL will call the FinalRelease method when its reference count goes to 0, but before it is destroyed .


Add the following code to the TimeValue.h file in the Visual C++ project:

 class ATL_NO_VTABLE CTimeValue : ... { public:       CTimeValue()       {       } // ... code omitted for clarity       void FinalRelease(); private       double mInterestRate; }; 

I omitted the code before the FinalRelease method to show only those parts that are relevant to this discussion. I then added the following code to the .cpp file for the TimeValue class.

 void CTimeValue::FinalRelease() {       ::MessageBox(0,"Object is Released",           "Object Released",0); } 

I first built an unmanaged VB 6 client for this object with the following code in a click handler:

 Private Sub Command1_Click()     Dim objFinancial As TimeValue     Set objFinancial = New TimeValue     Label1.Caption = objFinancial.MonthlyPayment(         360, 6.75, 350000)     Set objFinancial = Nothing End Sub 

Notice that I set the reference to the object to "Nothing" before I leave the method. With VB6, setting an object reference to nothing will cause the VB runtime to generate a call to the Release method on the object that the reference was previously pointing to. Since there is only one reference pointing to the object, this will cause the object's reference count to go to zero. Therefore, each time that the objFinancial object reference goes out of scope, it will call Release on the underlying COM object, so you will see a message box like the one shown in Figure 7-1 each time you pushed the button.

Figure 7-1. The message box showing that the object is released.

graphics/07fig01.jpg

This is the expected life cycle behavior for an unmanaged client. Let's take a quick look at the code that you wrote for the managed client in Chapter 6 so that you can understand the expected life cycle for the object when it is called from a managed client.

 1.  private void cmdGetLoanAmt_Click(object sender, 2.      System.EventArgs e) 3.  { 4.    short shtNumMonths; 5.    double dblInterestRate, dblMonthlyPmt, dblResult; 6.    try 7.    { 8.      TimeValue objFinancial=new TimeValue(); 9.             shtNumMonths=short.Parse(txtMonths.Text); 10.             dblInterestRate= 11.     Double.Parse(txtInterestRate.Text); 12.     dblMonthlyPmt= 13.       Double.Parse(txtMonthlyPmt.Text); 14.     dblResult= 15.       objFinancial.loanAmount(shtNumMonths, 16.       dblInterestRate,dblMonthlyPmt); 17.     lblLoanAmt.Text= 18.         String.Format("{0:C}",dblResult); 19.   } 20.   catch(System.Exception ex) 21.   { 22.     MessageBox.Show(ex.Message); 23.   } 24. } 

The code that you are looking at is the Click handler for the Get Loan Amount button; this is the logic that gets executed each time you click the Get Loan Amount button. Notice that I instantiate the object as a local variable on line 8. The objFinancial object reference will go out of scope on line 19. Therefore, the object that I instantiated on line 8 is actually eligible for collection after I pass line 19. If you run the client, though, you will notice that the Object is Released message box never shows up. In fact, you'll notice that, even if you click the button several times, you'll never see the message box. If you shut down the managed client (by clicking the X button in the upper right-hand corner, for instance), the message box pops up as many times as you clicked the Get Loan Amount button. This indicates that all of the objects were deleted when you shut down the application.

The life cycle behavior of this COM object is very different when it is used from a managed client as compared to an unmanaged client. To make the COM object behave the same when it is called from a managed code client as it would when it is called from an unmanaged code clientthat is, the object is created and released each time you click the buttonadd the following line of code at the end of the try block, that is, after line 18 in the previous listing.

 System.Runtime.InteropServices. Marshal.ReleaseComObject(objFinancial); 

The ReleaseComObject method immediately decrements the reference count of the COM object that you pass to it. Now you will see the Object is Released message box each time you click the button indicating that the object is being released immediately. If you attempt to use an object after you have called the ReleaseComObject method, the RCW will throw an error of type System.Runtime.InteropServices.InvalidComObjectException that contains the following message:

 COM object that has been separated from its underlying RCW can not be used. 

Team-Fly    
Top
 


. Net and COM Interoperability Handbook
The .NET and COM Interoperability Handbook (Integrated .Net)
ISBN: 013046130X
EAN: 2147483647
Year: 2002
Pages: 119
Authors: Alan Gordon

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net