我需要一些关于如何为具有消息泵处理窗口消息的MFC DLL实现C语言接口的指导。 MFC DLL派生自public CWinApp
,并使用从CAsyncSocket
派生的类来处理与远程应用程序的TCP / IP连接。如何对CWinApp
对象进行访问,以便MFC DLL导出的C可调用函数能够以线程安全和Windows兼容的方式访问CWinApp
对象的功能?
这是一个复杂的多线程Windows应用程序,由几个混合了C和C ++的DLL组成。一些DLL是基于MFC的DLL,主exe是基于对话框的MFC应用程序。在关闭应用程序时,我们使用WM_QUIT
向主窗口句柄发送PostMessage()
消息,在大多数情况下,应用程序将关闭并退出。
使用_beginthreadex()
函数启动各种线程。
但是在某些情况下,我们看到应用程序挂起,因为在各种窗口中仍然显示,但应用程序不再响应。使用Visual Studio附加到进程,然后从“调试”菜单执行“全部中断”,将出现一个警告对话框,指出“进程似乎已死锁(或未运行任何用户模式代码)。所有线程都已停止。”。< / p>
在线程显示中,大多数线程似乎位于0x7c90e514
位置,这似乎是对WaitForSingleObject()
的调用的结果。在执行信号量请求时,我们使用WaitForSingleObject()
作为使用Windows信号量API的一部分。有一些线程的起源我不确定,虽然它们可能来自我们在另一个MFC DLL中使用的几个COM对象。
我们还注意到,有时当应用程序关闭时,命令shell窗口突然出现,会显示不同的秒数,然后消失。我们并不总是看到这种行为。当我们看到显示的窗口时,应用程序不会挂起。我会对这种行为的可能解释感兴趣。
但是,一个基于Windows MFC的DLL的线程在函数_AfxActivationWndProc()
内,它似乎是窗口消息处理的处理程序。当从Debug菜单中完成Break All时,看起来该线程是当前线程,但是我认为它被挂起(调试器的Threads窗口的Suspend列中的1)。调用堆栈显示此函数是通过CCmdTarget::InternalRelease().
我认为问题在于,在某些情况下,某些线程的消息泵被WaitForSingleObject()
的调用阻止,并且窗口消息到达时消息泵未泵送,而MFC DLL是由于引用计数没有正确递减,试图完成并CCmdTarget::InternalRelease()
被阻止完成。
似乎挂起的特定MFC DLL正在使用从CAsyncSocket
MFC类派生的类来实现远程应用程序与此应用程序一起发送和接收数据的接口。 MFC DLL使用C接口公开一组函数。这样一个函数的一个例子是主应用程序调用以提供MFC DLL的机制,当消息通过来自远程应用程序的TCP / IP连接到达时,MFC DLL将异步消息发送到主应用程序窗口:
CONNENGINE_API int fnConnEngineSetWindowHandleExt (CONNENGINEHANDLE hConnEngineSocket, HWND hWinHandle, UINT wReceiveMsgId, UINT wSocketCloseMsgId)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
theApp.m_hWinHandle = hWinHandle;
theApp.m_wReceiveMsgId = wReceiveMsgId;
theApp.m_wSocketCloseMsgId = wSocketCloseMsgId;
if (theApp.m_ListenSocket != 0) {
theApp.m_ListenSocket->SetWindowHandleExt (hWinHandle, wReceiveMsgId, wSocketCloseMsgId);
}
return 0;
}
CONNENGINE_API
是包含文件中的已定义常量,如下所示:
#ifdef CONNENGINE_EXPORTS
#define CONNENGINE_API __declspec(dllexport)
#else
#define CONNENGINE_API __declspec(dllimport)
#endif
我们在一个包含文件中有这个,其中函数声明使用带有警卫的extern "C"
构造,以允许包含在C和C ++源文件中。
#if defined(__cplusplus)
extern "C" {
#endif
// function declarations
CONNENGINE_API int fnConnEngineSetWindowHandleExt (CONNENGINEHANDLE hConnEngineSocket, HWND hWinHandle, UINT m_wReceiveMsgId, UINT m_wSocketCloseMsgId);
#if defined(__cplusplus)
};
#endif
该文件包含在MFC DLL源文件中,包含以下语句,以便DLL导出函数。
#define CONNENGINE_EXPORTS
#include "ConnEngine.h"
MFC DLL创建一个listen
套接字以等待连接请求,当它进入时,创建一个工作套接字来处理实际的I / O.一次只有一个连接。
还有其他线程也使用基于MFC的DLL,它具有用于安全事务处理的嵌入式COM或Active-X控件以及设备接口。包含COM对象的基于MFC的DLL使用类似的接口技术。
我的主要问题是,如何使用Windows消息泵来处理Windows消息以获取其功能的MFC DLL导出将由_beginthreadex()
启动的线程使用的C可调用函数?如何托管COM对象的MFC DLL导出功能?
文档链接
Difference between Afxbeginthread and CreateThread
How to exit Win32 Application via API
What does AFX_MANAGE_STATE(AfxGetStaticModuleState()) do exactly