Solved

OleInitialize CoInitialize CoInitializeEx

Posted on 2003-11-07
10
2,413 Views
Last Modified: 2008-02-01
When you intitialize a COM object do you need to call one of these functions? (otherwise I'm way off the mark)

Which function do you use? What's the difference? MSDN doesn't seem particularily clear on that.

Where do you call it? At the beginning of your code? Inside a function that uses the COM object?

Thanks,
-Sandra
0
Comment
Question by:Sandra-24
  • 4
  • 3
  • 3
10 Comments
 
LVL 48

Accepted Solution

by:
AlexFM earned 300 total points
ID: 9706258
These functions should be called in each thread which works with COM, for example, creates and uses some COM components.

CoInitialize - initializes COM in the current thread using STA model. Remains for backward compatibility; use CoInitializeEx instead of it.

CoInitializeEx - initializes COM in the current thread. Allows to select STA amd MTA models.

OleInitialize - initializes COM in the current thread using STA model and activates additional functionality.

When to call: in the start of each thread. If application is single-threaded, in the main thread initialization code. In MFC application this may be, for example, InitInstance.

What function should be called:
CoInitialize - should not be used.
OleInitialize - if you need Clipboard, drag-and-drop, OLE or in-place-activation support.
CoInitializeEx - in other cases.

See details in this article:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnesscom/html/c5interfaceimplementationrevisited.asp


0
 
LVL 86

Expert Comment

by:jkr
ID: 9707728
>>These functions should be called in each thread which works with COM

Multithreading and COM requires special care, as passing IF pointers between threads is inherently dangerous.

>>MSDN doesn't seem particularily clear on that


The article at http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnesscom/html/c5interfaceimplementationrevisited.asp ("Interface and Implementation Revisited") is pretty on point about the differences :o)

You also might want to read an article by *the* COM guru at http://www.microsoft.com/msj/0798/com0798.aspx ("House of COM")
0
 
LVL 48

Expert Comment

by:AlexFM
ID: 9707749
0
 
LVL 86

Expert Comment

by:jkr
ID: 9707768
Sorry, my fault :o)
0
 
LVL 3

Author Comment

by:Sandra-24
ID: 9707812
lol @ Alex & jkr

So if I have several threads that will use this COM object (possibly concurrently) do I use CoInitializeEx(NULL,COINIT_MULTITHREADED) before I started the threads or do I use CoInitializeEx(NULL,COINIT_APARTMENTTHREADED) in the beginning of each thread?

Thanks!
0
Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

 
LVL 48

Assisted Solution

by:AlexFM
AlexFM earned 300 total points
ID: 9707829
You should use CoInitializeEx in the beginning of each thread. But which one of them - I am not sure. I would try CoInitializeEx(NULL,COINIT_MULTITHREADED).
0
 
LVL 86

Assisted Solution

by:jkr
jkr earned 200 total points
ID: 9707862
And, you will need to marshal the interface pointers between the threads:

See 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);"

If you want to avoid all the marshalling hassle, take a look at http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com/htm/cmi_d2l_5omd.asp ("IGlobalInterfaceTable"), which provides aninterface is an efficient way for a process to store an interface pointer in a memory location that can be accessed from multiple apartments within the process, such as processwide variables and agile (free-threaded marshaled) objects containing interface pointers to other objects (last half of the sentence shamelessly stolen from that page :o)

On the last issue, see also

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com/htm/aptnthrd_4ew5.asp ("Creating the Global Interface Table")

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com/htm/aptnthrd_6uat.asp ("When to Use the Global Interface Table")

http://www.microsoft.com/msj/0997/activex0997.aspx ("ActiveX Q&A, MSJ September, 1997 - Apartment Neutrality: The Free Threaded Marshaler and the Global Interface Table")
0
 
LVL 3

Author Comment

by:Sandra-24
ID: 9709316
This is odd. I'm compiling on a Win XP machine but it seems CoInitializeEx is not availiable to me.

I looked in objbase header and it's defined like so:

#if (_WIN32_WINNT >= 0x0400 ) || defined(_WIN32_DCOM) // DCOM
WINOLEAPI  CoInitializeEx(IN LPVOID pvReserved, IN DWORD dwCoInit);

the constant COINIT_MULTITHREADED is also defined like that. It is also unavailible.

So i changed my code to this:

#if (_WIN32_WINNT >= 0x0400 ) || defined(_WIN32_DCOM) // DCOM
      CoInitializeEx(NULL,COINIT_MULTITHREADED);
#else
      CoInitialize(NULL);
#endif

It will now compile, which means it'll use CoInitialize.

I'll look into this behaviour in the morning but it strikes me that XP is > NT 4 and is defined (as far as I can tell) on my machine to be 0x0501.

Odd.
0
 
LVL 48

Assisted Solution

by:AlexFM
AlexFM earned 300 total points
ID: 9709350
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sdkintro/sdkintro/using_the_sdk_headers.asp

Requirements for CoInitializeEx:

Windows NT/2000: Requires Windows NT 4.0 or later.
Windows 95/98: Requires Windows 98 (or Windows 95 with DCOM).


You need to add line
#define _WIN32_WINNT 0x0400

to compile CoInitializeEx. To compile it in Win98 add line
#define _WIN32_WINDOWS 0x0410    // or more

Add this definition in stdafx.h, before all #include lines.
0
 
LVL 3

Author Comment

by:Sandra-24
ID: 9711052
I added _WIN32_WINNT 0x0501 to the preprocessor definitions in the project properties. It worked, thanks.

Always so much more to learn it seems! Thanks again guys.

-Sandra
0

Featured Post

Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

Join & Write a Comment

  Included as part of the C++ Standard Template Library (STL) is a collection of generic containers. Each of these containers serves a different purpose and has different pros and cons. It is often difficult to decide which container to use and …
This article will show you some of the more useful Standard Template Library (STL) algorithms through the use of working examples.  You will learn about how these algorithms fit into the STL architecture, how they work with STL containers, and why t…
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.
The viewer will be introduced to the member functions push_back and pop_back of the vector class. The video will teach the difference between the two as well as how to use each one along with its functionality.

758 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

16 Experts available now in Live!

Get 1:1 Help Now