5,691,626 members and growing! (13,425 online)
Email Password   helpLost your password?
Platforms, Frameworks & Libraries » COM / COM+ » COM Interop     Intermediate

Using COM Objects in Multithreaded .NET Applications

By Xiangyang Liu 刘向阳

Sample VB.NET and C# code that uses existing com objects in ASP.NET pages
C#, Windows, .NET 1.0, .NETVisual Studio, VS.NET2002, Dev

Posted: 12 Jun 2003
Updated: 12 Aug 2003
Views: 72,036
Bookmarked: 28 times
Announcements
Loading...



Search    
Advanced Search
Sitemap
28 votes for this Article.
Popularity: 6.38 Rating: 4.41 out of 5
2 votes, 7.1%
1
1 vote, 3.6%
2
4 votes, 14.3%
3
1 vote, 3.6%
4
20 votes, 71.4%
5

Overview

Suppose you have an existing COM component implemented in VC++ or VB. You have been using it in your desktop applications without any problem. Now you need the same functionality in your .NET projects. You could spend time to reimplement the component using C# or VB.NET but sometimes this approach is not always an ideal one. For example, there could be a lot of Win32 API calls or calls to some other third-party C library in the old version, it might not be easily implemented using C#. Even worse, the component could be written by someone else who already left the company (and took the expertise with him), or it could be a third-party component with no source code.

Fortunately, it is not hard to use COM components directly in .NET projects. There have been some good articles talking about this, I just want to briefly summarize what you have to do in order to use a COM component from .NET projects: First you need to install and register the COM component, then you need to add a reference to the COM component in your .NET projects. .NET will automatically generate a "wrapper" dll for you.  

Let's see a simple example. I have included with this article a DummyCom.dll written with VC++/ATL which implements a simple COM object called DummyObj. This COM object has only one method called Test. The method takes an input string and returns an output string.  The output string indicates the date/time the object was created and the date/time the method was called as well as the input string passed into the method.  Here is C# sample code that calls the Test method of DummyObj.

using DUMMYCOMLIB;

    ...
    DummyObj obj = new DummyObj();
    String sOutput = obj.Test("this is a test");

    ...

Here is what the output string looks like:

Object created at '2003-06-13, 11:06:18'
'Test' method called at '2003-06-13, 11:06:18' with input 'this is a test'

If it was always this easy then I wouldn't need to write this article. There are some potential problems which I will try to address below.

The Problems

Suppose the above sample code is cut from the code behind file of a web (aspx) page. As we can see the COM object reference is assigned to a local variable. After the code is executed, the reference is gone and there is no way to get back to the same instance of the COM object again. For each web request, the above code will create a new COM object. This may not be an issue for many COM objects; however, some COM objects may have to do heavy one-time initialization work before they can be used.  For example, when the object in question is created, it may need to access a remote database to fetch data for later use. So it may be preferable to keep the reference to the COM object and reuse it in multiple web requests.

Ok, that's easy. All we have to do is use a static member variable of the current class to hold the COM object and use it in all web requests. In case you don't know, the static (or Shared for VB.NET) keyword means that this member variable is global and you don't need to create an instance of the class in order to access it. There are still problems with this approach, however. First of all, the COM object in question may not be thread-safe at the instance level. If multiple web requests are using the same instance, it may crash the server machine. Secondly, even if the COM obj is thread-safe, the performance may be bad if there is only one instance to serve all web requests. For example, the threading model for the COM object may be "apartment", which implies that only one thread can use it at any given time, all the other threads will have to wait for their turn.

Apparently, we need a different approach to solve these problems

The ASP.NET Thread Pool and the ObjMan Class

ASP.NET applications and ASP.NET web services use a thread pool to serve client requests. The threads in the pool will be reused for multiple requests. The number of threads in the pool will increase only when the number of simultaneous client requests increases. 

My solution to the above problems is create only one instance of the COM object for each thread. With my solution, the object instance for the current thread is created the first time it is needed. It is assigned a name at the time of creation and later the name string can be used to retrieve the instance for reuse. ObjMan is a VB.NET class contained in ObjectManager.dll. Here is a static method of ObjMan that is used to create and retrieve a COM object.

Public Shared Function GetComObject(ByVal sObjName As String, _
    ByVal sProgID As String, ByVal sServerName As String) As Object

The sObjName parameter is a user assigned name string to identify the COM object. The sProgID parameter is the prog id of the COM object. The sServerName parameter (optional) is used for creating the COM object on a remote server. The return value is a reference to the COM object for the current thread. Here is sample C# code that calls this method.

using DUMMYCOMLib;

    ...
    DummyObj obj = (DummyObj)ObjectManager.ObjMan.GetComObject("MyObjName",
        "DummyObj.1");
    OutputBox.Text = obj.Test(InputBox.Text);
    // ObjectManager.ObjMan.RemoveComObject("MyObjName");

    ...
When the above code is executed by threads in a thread pool, COM object DummyObj will be created only once for each thread. The GetComObject method will retrieve an existing instance if one is already created by a previous attempt within the same thread.

The method RemoveComObject is used to get rid of the COM object created by GetComObject. If you uncomment the last line of code in the above sample, then DummyObj will be created every time the code is executed. Please note that RemoveComObject only removes the COM object with given name for the current thread. You cannot create the COM object by calling GetComObject in one thread and remove it from a different thread using RemoveComObject . It is possible to create and use multiple instances of a COM object in the same thread as long as you give them different names.

The implementation of the ObjMan class is simple and straightforward. Internally, the ObjMan class uses a hashtable to store data (Hashtable is my favorite .NET class, by the way). The key string for an object in the hashtable is the name of the thread. Each object in the hashtable is itself a hashtable for the corresponding thread.  So all COM objects created in a thread are stored in a single child hashtable. The key string for an object in the child hashtable is the sObjName parameter in the GetComObject method.

The Source Code and Sample Projects

The download file includes the ObjectManager project (the ObjMan class) and the ObjectManagerTest project (an ASP.NET test program). Here is how to install and run everything:
  1. Unzip the downloaded file onto your local machine (you need to preserve the directory structure in the zip file).
  2. Double click the ObjManInstall.vbs script file to create a virtual web directory ObjManTest for the test project.
  3. Access the URL http://localhost/ObjManTest.aspx from your browser to display a web form.
The Run button on the web form will call the Test method of the DummyObj object.

Please note that some COM objects (including all GUI controls) cannot be used this way. I hope this article is helpful to some of you. Thanks for reading my articles and using my tools .

Latest Update

  1. July 10, 2003:  Modified article text (again). Simplified source code.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Xiangyang Liu 刘向阳



Location: United States United States

Other popular COM / COM+ articles:

Article Top
Sign Up to vote for this article
You must Sign In to use this message board.
FAQ FAQ Noise ToleranceSearch Search Messages 
 Layout  Per page   
 Msgs 1 to 6 of 6 (Total in Forum: 6) (Refresh)FirstPrevNext
GeneralThread Data SlotseditorHeath Stewart7:09 13 Aug '03  
GeneralRe: Thread Data SlotsmemberXiangyang Liu8:16 13 Aug '03  
GeneralRe: Thread Data SlotseditorHeath Stewart9:08 13 Aug '03  
GeneralRe: Thread Data SlotsmemberXiangyang Liu10:09 13 Aug '03  
GeneralWhy use this approachsussAnonymous5:10 11 Jul '03  
GeneralRe: Why use this approachmemberXiangyang Liu9:44 11 Jul '03  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 12 Aug 2003
Editor: Heath Stewart
Copyright 2003 by Xiangyang Liu 刘向阳
Everything else Copyright © CodeProject, 1999-2008
Web09 | Advertise on the Code Project