CoInitialize与CoInitializeEx,AfxOleInit()的不同 控制台程序中AfxOleInit失效原因

CoInitialize()和AfxOleInit()都是初始化COM库,可它们有什么不同呢

    OLE是建立在COM之上的技术,层次比COM要高。AfxOleInit()调用的是OleInitialize(),而 OleInitialize()除了调用CoInitializeEx()来初始化COM库外,还进行一些其它的操作,这些操作对OLE应用来说是必须的,这些OLE应用包括:  
    (1)Clipboard;  
    (2)Drag   and   drop;  
    (3)Object   linking   and   embedding(现在的OLE,已不再仅仅是Object   linking   and   embedding的概念);  
    (4)In-place   activation;  
    与AfxOleInit()对应的是,AfxOleTerm()。  

    AfxOleInit()和AfxOleTerm()其实也是需要成对的,但是,在你的程序中,AfxOleTerm()可以不出现,这是因为,MFC已经帮你做好了(有兴趣的话,你可以仔细研究一下CWinThread::m_lpfnOleTermOrFreeLib,而CWinApp是从CWinThread继承的)。

注:但是当你的函数出现了重复调用AfxOleInit()时间便不能依靠mfc自动调用了,需要显式的调用AfxOleTerm清理com库


CoInitialize与 AfxOleInit

使用MFC的控制台主程序中如果用AfxOleInit()初始化com就会出现DLL中调用wordApp.CreateDispatch("Word.Application",NULL)失败,而改用用CoInitialize()则会成功

在AfxOleInit()函数中设置断点调试之后可以知道: afxContextIsDLL这个标志的值为ture,因而它并不会去调用 OleInitialize ,进而不会调用 CoInitialize.

MSDN(If AfxOleInit is called from an MFC DLL, the call will fail. The failure occurs because the function assumes that, if it is called from a DLL, the OLE system was previously initialized by the calling application.) 看来在这个函数中把当前项目当做DLL来处理了.^_^,不知是不是MFC本身的bug

BOOL AFXAPI AfxOleInit()
{
    _AFX_THREAD_STATE* pState = AfxGetThreadState();
    ASSERT(!pState->m_bNeedTerm);    // calling it twice?

    // Special case DLL context to assume that the calling app initializes OLE.
    // For DLLs where this is not the case, those DLLs will need to initialize
    // OLE for themselves via OleInitialize.  This is done since MFC cannot provide
    // automatic uninitialize for DLLs because it is not valid to shutdown OLE
    // during a DLL_PROCESS_DETACH.
    if (afxContextIsDLL)
    {
        pState->m_bNeedTerm = -1;  // -1 is a special flag
        return TRUE;
    }


    // first, initialize OLE
    SCODE sc = ::OleInitialize(NULL);
    if (FAILED(sc))
    {
        // warn about non-NULL success codes
#ifdef _DEBUG
        TRACE(traceOle, 0, _T("Warning: OleInitialize returned scode = %s.\n"),
            AfxGetFullScodeString(sc));
#endif
        goto InitFailed;
    }
    // termination required when OleInitialize does not fail
    pState->m_bNeedTerm = TRUE;

    // hook idle time and exit time for required OLE cleanup
    CWinThread* pThread; pThread = AfxGetThread();
    ASSERT(pThread);
    pThread->m_lpfnOleTermOrFreeLib = AfxOleTermOrFreeLib;

    // allocate and initialize default message filter
    if (pThread->m_pMessageFilter == NULL)
    {
        pThread->m_pMessageFilter = new COleMessageFilter;
        ASSERT(AfxOleGetMessageFilter() != NULL);
        AfxOleGetMessageFilter()->Register();
    }
    return TRUE;

InitFailed:
    AfxOleTerm();
    return FALSE;
}

转载一下问题

I have been debugging an MFC application that calls AfxOleInit() to initialize COM. The call has returned true, but I am catching COM exceptions when trying to instantiate and use any COM objects - the error says that COM has not been initialized. After stepping into the AfxOleInit method, I can see why this is happening - There is a macro named 'afxContextIsDLL' that is returning true, and this is causing AfxOleInit to immediatly return without calling OleInitialize. According to the documentation located here (http://msdn2.microsoft.com/en-us/library/e91aseaz(VS.80).aspx), this is expected behavior "If AfxOleInit is called from an MFC DLL". However, my application is an exe.

From there, I created a new Win32 Console Application with MFC header files as a Windows application project to see if it was a project setting. Upon calling AfxOleInit in InitInstance, I see the same behavior. I then created an new Win32 Console Application with MFC header files as a Console application project. The call to AfxWinInit trips up on the same macro (afxContexIsDLL) and never calls AfxInitThread. I have also added a call to AfxOleInit to this project and I am seeing the same behavior - OleInitialize never gets called.

The strange thing is that there are other projects in the application that are executables, and call AfxOleInit successfully (ie, stepping into this method, the macro afxContextIsDLL is false, and OleInitialize gets called). The only difference is that these projects were created with an earlier version of Visual Studio... This project was made with VS2K5. Suspecting that it had to do with some project setting, I made a copy of one of these executables' project file, 'gutted' it by adding the new application's files and include libraries, but still am seeing


COM中CoInitializeEx 与CoInitialize的区别

    CoInitialize、CoInitializeEx都是windows的API,主要是告诉windows以什么方式为程序创建COM对象,原因是程序调用com库函数(除CoGetMalloc和内存分配函数)之前必须初始化com库。
    CoInitialize指明以单线程方式创建。
    CoInitializeEx可以指定COINIT_MULTITHREADED以多线程方式创建。

    创建单线程方式的COM服务器时不用考虑串行化问题,多线程COM服务器就要考虑。

    CoInitialize并不装载com库,这个函数只是用来初始化当前线程使用什么样的套间。当使用这个函数以后,线程就和一个套间建立了对应关系。
    线程的套间模式决定了该线程如何调用com对象,是否需要列集等

    套间是com中用来解决并发调用冲突的很有效的办法
    Before calling any COM functions, a thread needs to call CoInitialize to load the COM infrastructure (and to enter an apartment). Once a thread calls CoInitialize, the thread is free to call COM APIs.

    CoInitializeEx provides the same functionality as CoInitialize and also provides a parameter to explicitly specify the thread's concurrency model. The current implementation of CoInitialize calls CoInitializeEx and specifies the concurrency model as single-thread apartment. Applications developed today should call CoInitializeEx rather than CoInitialize.

    注:新的应用程序应该调用CoInitializeEx而不是CoInitialize,否则就会有必要在之后每个调用Com的线程中调用CoInitialize来初始化出每个线程自己的套间

引用MSDN,有兴趣的看下吧

   A thread must call CoInitializeEx or CoInitialize before calling any other COM library function except the CoGetMalloc function and other memory allocation calls (CoTaskMemAlloc, CoTaskMemFree, CoTaskMemReAlloc, and the IMalloc methods on the task allocation supplied by CoGetMalloc). Otherwise, the COM library function will return CO_E_NOTINITIALIZED.

Once the concurrency model for a thread is set, it cannot be changed. A call to CoInitializeEx on a thread that was previously initialized with a different concurrency model will fail and return RPC_E_CHANGED_MODE.

If neither concurrency model is specified by the dwCoInit parameter, the default is COINIT_MULTITHREADED.

Objects created in a single-threaded apartment (STA) receive method calls only from their apartment's thread, so calls are serialized and arrive only at message-queue boundaries (when the Win32 function PeekMessage or SendMessage is called).

Objects created on a COM thread in a multithread apartment (MTA) must be able to receive method calls from other threads at any time. You would typically implement some form of concurrency control in a multithreaded object's code using Win32 synchronization primitives such as critical sections, semaphores, or mutexes to help protect the object's data.

When an object that is configured to run in the neutral threaded apartment (NTA) is called by a thread that is in either an STA or the MTA, that thread transfers to the NTA. If this thread subsequently calls CoInitializeEx, the call fails and returns RPC_E_CHANGED_MODE.

CoInitializeEx provides the same functionality as CoInitialize and also provides a parameter to explicitly specify the thread's concurrency model. The current implementation of CoInitialize calls CoInitializeEx and specifies the concurrency model as single-thread apartment. Applications developed today should call CoInitializeEx rather than CoInitialize.

Because OLE technologies are not thread-safe, the OleInitialize function calls CoInitializeEx with the COINIT_APARTMENTTHREADED flag. As a result, an apartment that is initialized for multithreaded object concurrency cannot use the features enabled by OleInitialize.

Because there is no way to control the order in which in-process servers are loaded or unloaded, do not call CoInitialize, CoInitializeEx, or CoUninitialize from the DllMain function.

posted @ 2009-07-01 10:56  dzqabc  阅读(4167)  评论(0编辑  收藏  举报