COM CoInitializeEx(COINIT_MULTITHREADED) and AfxDAOInit

I've following Microsoft's documentation, for dealing with DAO when you have a secured database.  You basically have to initialize Dao yourself with AfxDaoInit(), and then setup to system MDW for access security.

I'm trying to do this in a Out of Process Com server (EXE), that has called CoInitializeEx(COINIT_MULTITHREADED) to provided a multi-threading COM interface.  This server is a singleton.

The problem is that AfxDaoInit() calls CoInitialize() which calls CoInitialize().  Microsoft documents that CoInitialize() simply calls CoInitializeEx(COINIT_APARTMENTTHREADED).

By calling this, it attempts to change the threading model after initialization and returns an error.  This is a documented error condition.

This problem did not show up until I installed NT Service Pack 4, which I guess properly detects the threading model change.

My question is, how does one use Dao within a multi-threaded out of process com server?  The design of the object is thread safe, DOA is only called and used during an initialization process that is run only once.

LVL 3
rmichelsAsked:
Who is Participating?

Improve company productivity with a Business Account.Sign Up

x
 
Tommy HuiConnect With a Mentor EngineerCommented:
"Once on thread has called CoInitializeEx(), that thread or any other thread cannot call CoInitializeEx() with a different threading model."

This is not true. A thread can enter and leave any COM apartment as long as it properly exits an apartment before entering a different one. In a thread, you can call CoInit as many times as possible. Here is a program (designed for VC for simplicity):

#define _WIN32_WINNT 0x400
#include <windows.h>
#include <ole2.h>
#include <tchar.h>
#include <stdio.h>

#pragma comment(lib, "ole32.lib")

int main(int argc, char* argv[])
{
      HRESULT hr;

      hr = CoInitializeEx(0, COINIT_APARTMENTTHREADED);
      if (FAILED(hr))
      {
            _tprintf(_T("CoInit apartment failed 1. \n"));
      }

      // success
      hr = CoInitializeEx(0, COINIT_APARTMENTTHREADED);
      if (FAILED(hr))
      {
            _tprintf(_T("CoInit apartment failed 2. \n"));
      }

      CoUninitialize();

      // Final call to leave apartment
      //
      CoUninitialize();

      // Switch apartments
      //
      hr = CoInitializeEx(0, COINIT_MULTITHREADED);
      if (FAILED(hr))
      {
            _tprintf(_T("CoInit multi failed 1. \n"));
      }

      hr = CoInitializeEx(0, COINIT_APARTMENTTHREADED);
      if (FAILED(hr))
      {
            _tprintf(_T("CoInit apartment failed 3. \n"));
      }

      // Since only CoInit succeeded
      //
      CoUninitialize();

      return 0;
}

If you run this program, you should see the output: CoInit apartment failed 3. The reason is the main thread is trying to switch COM apartments without properly exiting the apartment first.

In your application, you can have the main thread be in one COM apartment and in your second thread be in another COM apartment. While COM does allow this, it takes more effort to get it right. So you can have your main thread do all of its regular stuff and have a secondary thread and initializes DAO with its own apartment.

0
 
Tommy HuiEngineerCommented:
You are probably better off served creating a separate thread that calls CoInitialize() and do all of the DAO stuff in there.
0
 
rmichelsAuthor Commented:
Sorry, but your answer is the crux of the problem.  Once on thread has called CoInitializeEx(), that thread or any other thread cannot call CoInitializeEx() with a different threading model.

In my program, one thread has started the Server and called CoInitializeEx(), another thread has issued a second CoInitialize()..which errors out.
0
Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

 
rmichelsAuthor Commented:
While techinically correct, I don't think your answer helps me, but I'll ask for more information.  The COM Server is an Out of Process EXE server.  On it's main startup, it initializes itself to a Multi Threaded server.  Also this com object is a singleton.  One server for many clients.  So the main thread of the EXE has initialized to Multi Threaded.  When a Client comes in and wants to do some processing, it calls AfxDaoInit, which calls CoInitialize().  This client is on a separate thread.  The CoInitializeFails.  

I don't see how I can uninitialize the first Thread, without breaking the COM interface?  The only uninitialize I do, is when the server is exiting.
0
 
Tommy HuiEngineerCommented:
When the client comes into your server, you can create another thread and wait for the thread to finish. The other thread initializes COM to be single apartment and initializes DAO. It can then do your queries and deinitializes DAO and COM and returns. The client thread can then continue executing with the returned data.

0
 
rmichelsAuthor Commented:
True, your response is correct and I realize design changes can help the problem, but does not answer the more basic question:

My question is, how does one use Dao within a multi-threaded out of process com server?  Any help there?





0
 
Tommy HuiEngineerCommented:
The trouble with DAO is that in MFC, you are stuck to their model. If you install the DAOSDK, you'll find the dbDao classes which are infinitely more flexible. They will let you initialize to different apartments. The DAOSDK is included on your VC++ CDROM.

If you are familiar with the MFC classes, the dbDao classes are really easy to pick up.
0
 
rmichelsAuthor Commented:
I'll give your latest comment a try.  Thanks for all your comments!


0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.