OleInitialize CoInitialize CoInitializeEx

Posted on 2003-11-07
Medium Priority
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?

Question by:Sandra-24
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 3
  • 3
LVL 48

Accepted Solution

AlexFM earned 1200 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:

LVL 86

Expert Comment

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")
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

LVL 86

Expert Comment

ID: 9707768
Sorry, my fault :o)

Author Comment

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?

LVL 48

Assisted Solution

AlexFM earned 1200 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).
LVL 86

Assisted Solution

jkr earned 800 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")

Author Comment

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

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.

LVL 48

Assisted Solution

AlexFM earned 1200 total points
ID: 9709350

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.

Author Comment

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.


Featured Post

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

What is C++ STL?: STL stands for Standard Template Library and is a part of standard C++ libraries. It contains many useful data structures (containers) and algorithms, which can spare you a lot of the time. Today we will look at the STL Vector. …
Introduction This article is a continuation of the C/C++ Visual Studio Express debugger series. Part 1 provided a quick start guide in using the debugger. Part 2 focused on additional topics in breakpoints. As your assignments become a little more …
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.

765 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