Solved

COM DLL deployed on COM+ behaves errtic

Posted on 2003-12-03
5
352 Views
Last Modified: 2013-12-04
We have developed a COM based Client-Server application. The UI makes request to the Server which is a COM (MyServer.dll) DLL. This DLL in turn calls another generic COM component (DBWrapper.dll) for Database access. MyServer.dll is to be deployed on COM+ on a different machine than that of UI and DBWrapper will be deployed on the same machine as MyServer.dll and is to be instantiated as In-Proc (NO COM+).

If we instantiate MyServer as a In-Proc server the application works fine. But if I deploy MyServer on COM+ the DBWrapper behaves erratic. Some times it gives proper response and sometimes it returns error. We have no clue as to what is wrong. The behaviour is random and it can't be predicted which specific call causes failure.

Can anybody tell me what might be going wrong in this scenario? I am using ATL with C++ for sever and the component threading model is both.

Thanks in advance
Prasanna
0
Comment
Question by:mprasanna
  • 2
5 Comments
 
LVL 86

Accepted Solution

by:
jkr earned 125 total points
ID: 9866954
>>the component threading model is both.

See http://support.microsoft.com/default.aspx?scid=kb;en-us;150777 ("INFO: Descriptions and Workings of OLE Threading Models")

See also http://support.microsoft.com/default.aspx?scid=kb;en-us;206076 ("206076 - MARSHAL.EXE: How To Marshal Interfaces Across Apartments")

To elaborate (http://msdn.microsoft.com/msdnmag/issues/1100/wicked/default.aspx):

"Always Call CoInitialize(Ex)
A few months ago, I received an e-mail message from a friend at a prominent hardware company. His company had written a fairly sophisticated COM-based application that employed a number of in-proc and local (out-of-process) COM components. At startup, the application created COM objects to serve various client threads running in multithreaded apartments (MTAs). The objects were also consigned to MTAs, which meant that interface pointers could be freely exchanged among client threads. In testing, my friend discovered that everything worked fine until the application was ready to shut down. Then, for no apparent reason, calls to Release (calls that had to be made in order to properly free the interface pointers that the clients were holding) were locking up. His question: "What on earth is going wrong?"

The answer, as it turned out, was quite simple. The application's developers had done everything right with one very important exception: they weren't calling CoInitialize or CoInitializeEx in all of their client threads. One of the fundamental rules of modern-day COM is that every thread that uses COM should first initialize COM by calling either CoInitialize or CoInitializeEx. There are no exemptions to this rule. Among other things, CoInitialize(Ex) places a thread inside an apartment and initializes important per-thread state information that is required for COM to operate properly. Failure to call CoInitialize(Ex) typically manifests itself early in the application's lifetime in the form of failed COM API functions, most commonly activation requests. But sometimes the problems are more insidious and don't manifest themselves until it's too late, as in the case of calls to Release that disappear and never return. Once the dev team added CoInitialize(Ex) calls to all the threads that touched COM, their problems went away.

Ironically, Microsoft is one of the reasons that COM programmers sometimes don't call CoInitialize(Ex). The Microsoft® Knowledge Base contains documents stating that calls to CoInitialize(Ex) aren't strictly necessary for MTA-based threads (see article Q150777 for an example). Yes, there are cases in which you can get away with skipping CoInitialize(Ex). No, you shouldn't do it unless you know what you're doing and can be absolutely sure that you'll suffer no debilitating effects. It's never harmful to call CoInitialize(Ex), so my advice to COM programmers is to always call it from any thread that does anything whatsoever with COM.

Don't Pass Raw Interface Pointers Between Threads
One of the first COM projects I ever consulted on involved a distributed application comprising about 100,000 lines of code, written by a large software company on the West Coast. The application created dozens of COM objects on various machines and called into those objects from background threads launched by client processes. The development team was stymied by calls that would disappear into never-never land or simply fail for no obvious reason. One of the most egregious symptoms that they demonstrated for me was that following a call that failed to return, starting other COM-enabled applications (including Microsoft Paint, of all things) on the same machine would frequently induce those applications to lock up too.

An examination of their code revealed that they had broken one of the fundamental laws of COM concurrency, which says that if one thread wants to share an interface pointer with another thread, it should first marshal the interface pointer. Marshaling an interface pointer enables COM to create a new proxy if necessary (and a new channel object, pairing the proxy with a stub) to permit callouts from another apartment. Passing a raw interface pointer (a 32-bit address in memory) to another thread without marshaling it bypasses COM's concurrency mechanism, and can produce all sorts of undesirable behavior if the sending and receiving threads reside in different apartments. (In Windows® 2000, because two objects can share an apartment but reside in different contexts, it can even get you in trouble if the threads are in the same apartment.) A typical symptom involves calls that fail and return RPC_E_WRONG_THREAD_ERROR.

Windows NT® 4.0 and higher make it easy to marshal interface pointers between threads with a pair of API functions named CoMarshalInterThreadInterfaceInStream and CoGetInterfaceAndReleaseStream. Let's say one thread in your application (thread A) has created a COM object and received an IFoo interface pointer in return, and that another thread in the same process (thread B) wants to place calls to that object. In preparation for passing the interface pointer to thread B, thread A should marshal the interface pointer like this:

CoMarshalInterThreadInterfaceInStream (IID_IFoo, pFoo, &pStream);

Once CoMarshalInterThreadInterfaceInStream has returned, thread B can safely unmarshal the interface pointer:

IFoo* pFoo;
CoGetInterfaceAndReleaseStream (pStream, IID_IFoo, (void**) &pFoo);"
0
 
LVL 86

Expert Comment

by:jkr
ID: 10801445
The Q is answered :o)
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

zlib is a free compression library (a DLL) on which the popular gzip utility is built.  In this article, we'll see how to use the zlib functions to compress and decompress data in memory; that is, without needing to use a temporary file.  We'll be c…
For most people, the WrapPanel seems like a magic when they switch from WinForms to WPF. Most of us will think that the code that is used to write a control like that would be difficult. However, most of the work is done by the WPF engine, and the W…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
This video gives you a great overview about bandwidth monitoring with SNMP and WMI with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're looking for how to monitor bandwidth using netflow or packet s…

760 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now