【问题标题】:Callback implementation using Windows message loop使用 Windows 消息循环的回调实现
【发布时间】:2011-12-28 14:09:19
【问题描述】:

我有 C++ 库 (Win32 Console),我在其中使用计时器实现了异步函数。异步方法返回设备信息。

我创建了一个单独的线程“定时器线程”来创建一个隐藏窗口,然后我调用SetTimer(),然后调用实现的消息循环。

当计时器到期时,它会启用回调。

当我在控制台应用程序中使用该库时,它运行良好。

MFC 应用程序中,我正在发布消息以在回调触发时更新用户界面。发布消息无效。

如果我删除库中的消息循环,它在 MFC 应用程序中工作正常。

我得出的结论是:

我猜这个问题是由于两个消息循环,一个 MFC(主线程)和 TimerThread 消息循环。所以当回调被调用,后续的PostMessage导致TimerThread消息循环,在MFC(主线程)消息循环中不报。

如果我删除 TimerThread 消息循环,那么它在 MFC 应用程序中工作正常,但在控制台应用程序中无法工作。

我该如何克服这个问题?

class IDeviceEnumerationCallback
{
     public:
         virtual void onDeviceDiscovered(DeviceInfo* pDeviceInfo,unsigned short nNoOfDevice) = 0;
};

class IDeviceDiscovery
{
    public:
        virtual int InitialiseDiscovery(IDeviceEnumerationCallback*) = 0;

        virtual void UnInitialiseDiscovery() = 0;

        virtual int EnumerateDevice() = 0;
};

class CDeviceDiscovery:IDeviceDiscovery
{
    //Implementation
}

在 MFC/控制台应用程序中,我正在实现 IDeviceEnumerationCallback 以获取回调。

我正在使用 Bonjour API 来枚举设备,并且 Bonjour API 中的所有方法都是回调。

我正在等待一段时间来使用 Bonjour API 枚举设备,然后在 400 毫秒后说我正在调用回调以返回结果。在调用回调的 MFC 应用程序中,我正在做一个PostMessage() 来更新用户界面。

之前我尝试不使用 Windows 消息泵。我有一个SetTimer 函数,它与MFC 应用程序一起工作,但对于控制台应用程序,回调永远不会被调用,所以我在这里实现了一个消息泵。现在它不适用于 MFC 应用程序。

【问题讨论】:

  • 将消息从一个线程发布到另一个线程/消息循环管理的窗口应该没问题。假设句柄是正确的,则应使用消息 OK 调用 WindowProc。 PostMessage() 返回什么?
  • SetTimer 以扭曲和容易出错而闻名。消息不会发布,而是仅在您调用GetMessage 时创建,但不会在队列中已经有高优先级消息时创建(不是开玩笑!)。使用可等待的计时器。

标签: c++ winapi mfc callback


【解决方案1】:

首先,没有理由做你所做的事情:创建一个单独的线程,然后在其中创建一个窗口,设置窗口计时器,运行消息循环,响应 WM_TIMER 消息并调用回调。

如果您创建“自己的”线程 - 您实际上并不需要所有这些。您可以使用Sleep(或WaitForXXXX,如果您想要一个中止选项)实现一个简单的循环,然后调用您的回调。

通常会创建一个带有计时器的隐藏窗口,以避免创建额外的线程。也就是说,在操作 GUI(并因此运行消息循环)的线程中,您创建一个窗口,它将由消息循环提供服务。实际上,这是您可以在 MFC 应用程序中执行的操作。

但是,正如您所说,您需要 MFC 和控制台应用程序的通用代码。

在 MFC 应用程序中,我正在发布消息以更新 UI 时 回调触发器。发布消息不工作。

你所说的“diung post message”到底是什么意思?消息应发布到特定窗口或线程。在第一种情况下,它被分派给窗口过程,而在第二种情况下,消息循环实现负责处理消息。

如果您将消息发布到特定窗口 - 您如何获得它的句柄 (HWND)?它是您应用的主窗口 (AfxGetMainWnd) 吗?在 MFC 创建主窗口之后或更早之前,您的线程开始工作的是什么?

我问所有这些问题是因为你似乎是一个新手(没有冒犯),而且这些都是典型的错误。

【讨论】:

    【解决方案2】:

    问题是您不应该创建隐藏窗口并使用SetTimer,而是应该使用 MFC 工作线程功能进行后台工作。

    //You create a thread  like so.
    // you need a CMyObject only if you need to pass any information
    //to the thread function.
    CMyObject *pNewObject = new CMyObject;
    AfxBeginThread(MyThreadProc, pNewObject);
    
    
    //This function will be run in separate thread
    UINT MyThreadProc( LPVOID pParam )
    {
        //The parameter that was passed to this function
        CMyObject* pObject = (CMyObject*)pParam;
    
        while( 1 )
        {
            //add your code to do stuff.
    
            Sleep(5000); //or whatever your SetTimer interval was 
        }
    
        return 0;   // thread completed successfully
    }
    

    【讨论】:

    • MFC 应用程序是用于测试库的独立应用程序。告诉我应该如何使用回调函数实现库
    • 用MFC创建“隐藏”窗口应该绝对没有问题
    • @valdo 我同意但不知道 OP 代码的详细信息,我猜他在保持两个消息泵运行时遇到问题。
    • @parapura rajkumar:我猜问题在于将消息发布到正确的窗口并指定正确的消息处理程序
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-04
    • 2011-07-06
    • 2013-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多