Solved

COM CoInitializeEx(COINIT_MULTITHREADED) and AfxDAOInit

Posted on 1999-01-25
8
1,571 Views
Last Modified: 2013-11-25
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.

0
Comment
Question by:rmichels
  • 4
  • 4
8 Comments
 
LVL 15

Expert Comment

by:Tommy Hui
ID: 1185116
You are probably better off served creating a separate thread that calls CoInitialize() and do all of the DAO stuff in there.
0
 
LVL 3

Author Comment

by:rmichels
ID: 1185117
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
 
LVL 15

Accepted Solution

by:
Tommy Hui earned 100 total points
ID: 1185118
"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
 
LVL 3

Author Comment

by:rmichels
ID: 1185119
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
Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

 
LVL 15

Expert Comment

by:Tommy Hui
ID: 1185120
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
 
LVL 3

Author Comment

by:rmichels
ID: 1185121
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
 
LVL 15

Expert Comment

by:Tommy Hui
ID: 1185122
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
 
LVL 3

Author Comment

by:rmichels
ID: 1185123
I'll give your latest comment a try.  Thanks for all your comments!


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

When writing generic code, using template meta-programming techniques, it is sometimes useful to know if a type is convertible to another type. A good example of when this might be is if you are writing diagnostic instrumentation for code to generat…
Article by: SunnyDark
This article's goal is to present you with an easy to use XML wrapper for C++ and also present some interesting techniques that you might use with MS C++. The reason I built this class is to ease the pain of using XML files with C++, since there is…
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 user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.

708 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

15 Experts available now in Live!

Get 1:1 Help Now