0
votes

I have a situation with a static const class member which calls a static function to initialize it's value:

//A.h
class A
{
public:
static const int NUM;
static int Function();
};

//A.cpp
const int A::NUM = A::Function();

The problem is that A::Function() has a local static variable which requires the COM library be initialized via a call to CoInitialize():

//A.cpp
int A::Function()
{
static vartype m;
if(SUCCEEDED(CoInitialize(NULL)))
//Now m can be used and initialized.
// m.CreateInstance....
} 

I had previously called CoInitialize() in my WinMain:

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, PSTR cmdLine, int showCmd)
{
if(SUCCEEDED(CoInitialize(NULL)))
    {
    MyApp* app = new MyApp;

    app->Run();

    delete app;

    CoUninitialize();
    }

return 0;
}

But since ConInitialize() is called when the static member variable A::NUM is initialized in the call to A::Function(), and this will happen before the code in WinMain executes, I figured I could remove it from my WinMain:

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, PSTR cmdLine, int showCmd)
{
//if(SUCCEEDED(CoInitialize(NULL)))
    {
    MyApp* app = new MyApp;

    app->Run();

    CoUninitialize();
    }

return 0;
}

Now the program runs fine, but it crashes with an access violation when I exit. Could anyone shed some light on why this is happening?

EDIT: I'm thinking that since static variables are supposed to persist for the duration of the program, when I call CoUninitialize(), the local static variable m (which needs the COM library) runs into a problem. The crash seems to be related to this local variable m. But then the question is, when can I call CoUninitialize() for a static variable which requires the COM library? The problem seems to go away if I uncomment the if statement in WinMain, but I think that's because I end up calling CoInitialize() twice and CoUninitialize() only once.

1

1 Answers

0
votes

First of all, you may use RAII for this case. Just define a simple class like the following one:

class com_scope
{
    com_scope(com_scope const&);
    com_scope& operator= (com_scope const&);
public:
    com_scope() 
    {
        ::CoInitialize(NULL);
    }
    com_scope(DWORD dwCo)
    {
        ::CoInitializeEx(NULL, dwCo);
    }
    virtual ~com_scope() throw()
    {
        ::CoUninitialize();
    }
}

Then define a static const com_scope _AppComScope. Before the statement

const int A::NUM = ...

This code will initialize COM environment before the first call to A::Function, and clean up at the end of the execution.

It is extremly possible that your problem is that you destroy the COM environment before you end up using some com references. This explains the fact that the problem disappears as soon as you remove ::CoUnitialize from WinMain.

P.S.

Although it is a bad idea, but you may not call ::CoUninitialize in your main thread since the OS will make this cleanup when your programs finishes

P.S.S.

Also, I have to admit that one should define _AppComScope in the CPP file in which you assign a value to A::NUM. Otherwise, the standart doesn't guaranties the order of initializations