我需要一些指导如何实现具有消息泵处理窗口消息的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应用程序 . 当关闭应用程序时,我们使用 PostMessage()
向主窗口句柄发送 WM_QUIT
消息,在大多数情况下,应用程序将关闭并退出 .
使用 _beginthreadex()
函数启动各种线程 .
但是在某些情况下,我们看到应用程序挂起,因为在各种窗口中仍然显示,但应用程序不再响应 . 使用Visual Studio附加到进程,然后从“调试”菜单执行“全部中断”,将出现一个警告对话框,指出“进程似乎已死锁(或未运行任何用户模式代码) . 所有线程都已停止 . ”
查看线程显示,大多数线程似乎位于 0x7c90e514
位置,这似乎是对 WaitForSingleObject()
的调用的结果 . 在执行信号量请求时,我们使用 WaitForSingleObject()
作为使用Windows信号量API的一部分 . 有一些线程的起源我不确定,虽然它们可能来自我们在另一个MFC DLL中使用的几个COM对象 .
我们还注意到,有时当应用程序关闭时,突然出现的命令shell窗口会显示不同的秒数,然后消失 . 我们并不总是看到这种行为 . 当我们看到显示的窗口时,应用程序不会挂起 . 我会对这种行为的可能解释感兴趣 .
但是,一个基于Windows MFC的DLL的线程在函数_1558024中,它似乎是窗口消息处理的处理程序 . 当从Debug菜单中完成Break All时,看起来该线程是当前线程,但是我认为它被挂起(调试器的Threads窗口的Suspend列中的1) . 调用堆栈显示此函数是通过 CCmdTarget::InternalRelease().
的调用链调用的
我认为问题在于,在某些情况下,某些线程的消息泵被 WaitForSingleObject()
的调用阻止,并且窗口消息到达时消息泵未泵送,而MFC DLL正在尝试完成并执行 CCmdTarget::InternalRelease()
由于引用计数未正确递减而被阻止完成 .
似乎挂起的特定MFC DLL正在使用从 CAsyncSocket
MFC类派生的类来实现远程应用程序与此应用程序一起发送和接收数据的接口 . MFC DLL使用C接口公开一组函数 . 这样一个函数的一个例子是主应用程序调用以提供MFC DLL的机制,当消息通过来自远程应用程序的TCP / IP连接到达时,向主应用程序窗口发送异步消息:
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导出将由线程使用的C可调用函数那是用 _beginthreadex()
开始的?如何托管COM对象的MFC DLL导出功能?
Documentation links
Difference between Afxbeginthread and CreateThread
How to exit Win32 Application via API
What does AFX_MANAGE_STATE(AfxGetStaticModuleState()) do exactly