我们在与“当前MFC状态”和线程相关的基于MFC的应用程序中存在问题。在主线程中我们调用VisualManager,因为我们想要有花哨的工具栏。该调用最终位于CMFCVisualManagerOffice2007::OnUpdateSystemColors
内的afxvisualmanageroffice2007.cpp
函数中,该函数通过调用AfxSetResourceHandle
函数来更改“当前资源句柄”。此函数获取“当前模块状态”并将“当前资源句柄”从MyApp.exe
更改为mfc140u.dll
。这很好,因为VisualManager的资源位于该DLL中,并且在所有情况下更改都将恢复为MyApp.exe
。
然而,不好的是我们在调用VisualManager之前生成一个新线程(通过使用AfxBeginThread
),这个线程需要从字符串表中加载一些字符串(通过使用CString
类),但它有时不这样做。它失败了,因为有关于AFX_MODULE_STATE::m_hCurrentResourceHandle
变量的主线程的竞争。线程期望将其设置为MyApp.exe
,但主线程将其更改为mfc140u.dll
并返回,“当前资源句柄”实际上是一个全局变量。
所以,我的问题是:1)我们在管理基于MFC的线程时是否做了明显错误的事情?我们应该以某种方式复制或保护“模块状态”,以便我们的新线程能够免受主线程所做的更改吗?应该瞄准MFC创建像每线程变量/状态的东西? 2)我认为微软在这里是错误的,改变实际上是一个全局变量并拧紧其他线程的期望,VisualManager应该获取句柄并将其作为参数传递给它的所有函数。我是对的吗?
编辑:
大家好@iinspectable,@ cha,我有更新,抱歉花了这么长时间。重现步骤:打开Visual Studio 2015 Update 3,通过向导创建新的MFC应用程序,确保它具有"项目样式"和#34;视觉风格和颜色"被选为" Office"和#34; Office 2007(蓝色主题)"。从MSVS文件夹中打开文件afxvisualmanageroffice2007.cpp
,并将4个断点放入CMFCVisualManagerOffice2007::OnUpdateSystemColors
函数中,并调用AfxSetResourceHandle
。在新创建的项目文件夹中打开文件MFCApplication1.cpp
,并在CMFCApplication4App::InitInstance
之前将此代码[1]放入CMainFrame* pMainFrame = new CMainFrame;
函数中,将断点放入此线程proc。
现在在调试模式下构建并运行这个MFC应用程序,在每个断点命中,使用冻结线程并从Threads窗口解冻线程函数,这样你就可以在CMFCVisualManagerOffice2007::OnUpdateSystemColors
函数中间安排主线程了使用AfxSetResourceHandle
函数和CStringT::LoadString
之前的工作线程设置全局变量。现在,加载字符串将失败,因为它在mfc140ud.dll
内查找它而不是使用资源链和MFCApplication1.exe
。
我相信这是微软的错误(暂时改变全局变量),我的代码库充满了无辜的CString::LoadString
调用,这些调用依赖于使用各种插件精心构建的资源链DLL和最后的.exe。如果这不是微软的错误,那么依靠MFC为我提供可用的资源链是我的错误。我需要创建自己的类似资源链的功能,并在从资源加载字符串和其他东西时随处使用它。
// [1]
AFX_THREADPROC thread_proc = [](LPVOID pParam){
CString str;
str.LoadString(IDS_CAPTION_TEXT);
UINT ret = 0;
return ret;
};
::AfxBeginThread(thread_proc, (LPVOID)nullptr);
// Same result with ::AfxBeginThread(CRuntimeClass*) overload.