Visual c++ 并行模式库(PPL)中的COM STA模型?

Visual c++ 并行模式库(PPL)中的COM STA模型?,visual-c++,visual-studio-2012,mfc,windows-8.1,ppl,Visual C++,Visual Studio 2012,Mfc,Windows 8.1,Ppl,我有一个MFC应用程序,它使用并行模式库来执行一些异步任务。其中一些使用COM对象,因此我需要在此类任务中初始化COM库。在所有这些情况下,我都使用COM STA模型初始化,因为主线程是MFC app(MFC app线程只能是STA),我不知道在哪个上下文中调用我的任务 例如: BOOL CMyApp::InitInstance() { // base initialization CWinAppEx::InitInstance(); AfxOleInit(

我有一个MFC应用程序,它使用并行模式库来执行一些异步任务。其中一些使用COM对象,因此我需要在此类任务中初始化COM库。在所有这些情况下,我都使用COM STA模型初始化,因为主线程是MFC app(MFC app线程只能是STA),我不知道在哪个上下文中调用我的任务

例如:

BOOL CMyApp::InitInstance() {

      // base initialization
      CWinAppEx::InitInstance();
      AfxOleInit();

      // ... some code ...

      // PPL usage
      {
        Concurrency::task_group aTasks;

        // Task1
        aTasks.run([&](){
            HRESULT hRes = ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
            if (SUCCEEDED(hRes)) {
                Sleep(100);
                ::CoUninitialize();
            }
        });

        // Task2
        aTasks.run([&](){
            HRESULT hRes = ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
            if (SUCCEEDED(hRes)) {
                Sleep(100);
                ::CoUninitialize();
            }
        });

        // Task3
        aTasks.run([&](){
            HRESULT hRes = ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
            if (SUCCEEDED(hRes)) {
                Sleep(100);
                ::CoUninitialize();
            }
        });

        aTasks.wait();
    }
}
此代码在Windows 7/XP上正常工作。但是在Windows 8.1上,C++ 2012平台工具集任务1和2不工作,因为CONPROCELIZEXE()返回RPCYEYEXEDEDY模式错误!任务3通常由PPL core在主MFC线程上下文中调用,主MFC线程上下文是OLE,其COM已初始化为Conit_APARTMENTTHREADED,因此CoInitializeEx()返回成功的S_假代码(双重初始化)

对于任务2和任务3,PPL core创建单独的线程,这些线程在Windows 7/XP上未预先初始化为COM,因此任务第一行初始化COM成功。 但在Windows 8.1上所有“外观为”线程都预先初始化为COM,带有Conit_多线程标志,随后的Conitializex(…,Conit_APARTMENTTHREADED)调用返回错误

见鬼! 如何在Windows 8.1上定义正确的COM初始化规则?我的错在哪里? PPL不能保证任务的线程上下文,它可以是主线程,在MFC中必须是STA。我无法定义何时应该使用MTA或STA COM初始化

请帮帮我。这可能是来自2012 C++平台工具集的PPL核心代码中的错误还是PPL使用Windows 8.1的错误?

< P> <强>更新:(新代码提供)

100%正确。VC++CRT在PPL库中初始化WinRT!并在Windows 8及更高版本上执行此操作。现在所有PPL任务都是在多线程模式(MTA/Conit\u多线程模式)下为COM预先初始化的。 因此,如果您想在PPL任务中初始化COM,您应该非常小心。我为COM初始化编写了一个特殊的类,它允许您简化这个任务

namespace Concurrency {
/**
 * COM MultiThreading initialization for ConcRT
 */
class com_init
{
protected:
    const HRESULT m_hRes;
public:
    com_init(bool bInit = true) 
        : m_hRes(bInit ? (isWinRT() ? ERROR_ALREADY_INITIALIZED : CoInitializeEx(NULL, COINIT_MULTITHREADED)) : ERROR_CANCELLED)
    {}

    ~com_init()
    {
        if (SUCCEEDED(m_hRes)) {
            CoUninitialize();
        }
    }

    inline static bool isWinRT() {
        const bool bRes = (::Concurrency::GetOSVersion() == ::Concurrency::IResourceManager::Win8OrLater) && (::Concurrency::CurrentScheduler::GetPolicy().GetPolicyValue(WinRTInitialization) == ::Concurrency::InitializeWinRTAsMTA);
        return bRes;
    }
};
}
所以previos代码应该是这样的

BOOL CMyApp::InitInstance() {

  // base initialization
  CWinAppEx::InitInstance();
  AfxOleInit();

  // ... some code ...

  // PPL usage
  {
    Concurrency::task_group aTasks;

    // Task1
    aTasks.run([&](){
            const Concurrency::com_init objInitCOM;

            // ... to do COM work.
    });

    // Task2
    aTasks.run([&](){
            const Concurrency::com_init objInitCOM;

           // ... to do COM work.
    });

    // Task3
    aTasks.run([&](){
            const Concurrency::com_init objInitCOM;

           // ... to do COM work.
    });

    aTasks.wait();
}}

嗯,硬饼干。您可以在VC\crt\src\InternalContextBase.cpp的InternalContextBase::Dispatch()函数中看到它。注意对WinRT::RoInitialize(RO_INIT_多线程)的调用;这不是意外。STA线程的一个硬要求是它必须泵送一个消息循环。任务不会这样做。在桌面应用程序中初始化WinRT有什么意义?您可以在桌面应用程序中初始化Windows运行时,原因与在UWP应用程序中初始化Windows运行时的原因相同:能够使用作为Windows运行时类型公开的API。@IInspectable,是的,我现在看到了。谢谢