【问题标题】:How should one update/return value from a callback function?一个回调函数应该如何更新/返回值?
【发布时间】:2013-12-13 22:23:51
【问题描述】:

我已通过以下方式注册回调: SetWindowLongW(hWindow, GWL_WNDPROC, (LONG)WindowCallback);

我在那里毫无问题地接收消息。我在回调中有 if() 样式代码,如下所示:

if (MSG == 1)
{

   *boolptr = true;
   ...
} else if(MSG == 2) {
  if (*boolptr == true)
    return;

   // do stuff
}

变量是这样定义的(全局,在#includes right..下)

volatile bool         boolVar = false;
volatile bool*        volatile boolptr = &boolVar;

如果我在 main() 中等待 *boolptr 为 TRUE,一切都很好,但如果我在应该更改的同一个回调中等待它,它就不起作用。显然我不明白这里的一些概念,所以我寻求帮助或解释为什么它不起作用。

值为 2 的 MSG 总是先到达,然后在处理一些值为 1 的 MSG 之后。一段时间后会发生同样的事情,但我不想做同样的处理并浪费 CPU 周期,因此我需要知道 MSG 是否[1] 正在关注它并返回。希望你能理解我。

谢谢!

【问题讨论】:

  • 您的问题有点令人困惑——您所说的“等待”是什么意思?您列出的代码没有在标志上等待。但是,如果您的“等待”类似于 while (*boolptr) Sleep(1000);那么您的 WndProc 将不会查看 MSG(1),除非您在循环中使用 DoEvents。另一个原因可能是 MSG(2) 从未被解雇。
  • 考虑消除 bool 和 bool* 变量。而是使用 PreviousMSG 变量。这应该让您只用一个 if 语句来检查感兴趣的条件。
  • @Codism,我需要等待,因为第一次运行我需要处理 MSG[2] 部分中的代码,所以我等待几秒钟期待 MSG[1],如果没有收到我做MSG[2] 中的处理。但是,如果我确实收到了它并且我知道我收到了(我设置了消息框),我就无法捕获该布尔值。希望你现在明白了。
  • @ScottMcP-MVP,MSDN 上有什么参考资料吗?如果答案正确,我可以将其设置为一个。
  • MSDN 不相关 - 它只是带有您创建的变量的程序逻辑。 if(MSG == 2 && PreviousMSG == 1) { PreviousMSG = 2; return;} 如果这是您要检测的情况。

标签: c++ c windows multithreading callback


【解决方案1】:

你的描述遗漏了很多细节,但我想我明白你想要什么。 CreateWindow() API 函数的最后一个参数可用于将指向回调的指针传递给某个外部变量:

// MAKE SURE this variable stays in scope throughout the lifetime of your window !
// Make it global or static
bool myVar;  

// let's create an overlapped window of some class with size 400 x 300 
HWND hWnd = CreateWindow("My class name", "My Title", 
    WS_VISIBLE | WS_BORDER| WS_OVERLAPPED | WS_CAPTION |
    WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
    0,0, 400, 300, NULL, NULL, GetModuleHandle(NULL), &myVar);

然后在回调中,在 WM_CREATE 消息中访问它:

// ... start of your callback

// get a pointer to your variable here and use it in all messages
// *except* WM_CREATE that sets it during window instance creation
bool *pMyVar = (bool *)GetWindowLongPtr(hWnd, GWLP_USERDATA);

switch(uMsg)
{
    case WM_CREATE:
    {
        // get your pointer from the CREATESTRUCT passed in
        // and store it in the user data area of your window class
        // note: your WNDCLASS should have its cbWndExtra = sizeof(void *);
        CREATESTRUCT *pC = (CREATESTRUCT *)lParam;
        SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG)pC->lpCreateParams);
        // .... 
    }
    break;

    case 1 :  // VERY bad choice for a message, use WM_USER+1 instead
        *pMyVar = true;
    break;
// ... rest of your callback

这是你想要的吗?

编辑:好的,这是你想看的课程:

class MyClass
{
public:
    MyClass() : _hasRun(false) { }

    void DoStuff(HWND hW, UINT uMsg)
    {
        if (!_hasRun)
        {
            _hasRun = true;
            // ... do your work here, you have the window handle and the message
        }
    }

private:
    bool _hasRun;
};

现在,在您的 main 中创建此类的一个实例并将其保存在静态或全局变量中:

MyClass *pC = new MyClass;

然后,将它传递给我在开头显示的回调,然后始终调用它。 DoStuff 成员函数将检查消息并根据消息的内容执行您想要的操作,一次。即使您将其保存在全局中并始终从回调中调用此全局,其功能也是相同的。

// ... callback code before you handle any message
pC->DoStuff(hWnd, uMsg);
// ... rest of callback code

【讨论】:

  • 我没有像你那样创建窗口,因此我不处理 WM_CREATE msg。我因此陷入了僵局。我是否应该更改 CreateWindow 调用?其他一切都有意义。
  • 此方法创建一个无模式窗口,其余代码继续执行,然后您可以进入消息循环。如果您正在创建一个模态窗口(例如 MessageBox),那么调用将不会返回,因为它会创建自己的消息循环,直到窗口被销毁。您使用哪种方法,为什么会陷入僵局?此外,回调中的每条消息都必须执行并返回到消息循环,以便可以处理其他消息。如果你在回调中进入一个等待循环,你当前的线程将冻结,直到你从回调中返回。
  • 我想我不能使用你的解决方案,WM_CREATE 是 0x1,即使我让它工作,它也不会在我的情况下工作。任何其他解决方案(与创建窗口无关) CreateWindowEx(NULL, "tooltips_class32", NULL, NULL, 5, 5, 1, 2, NULL, NULL, GetModuleHandle(NULL), NULL);
  • 所以从技术上讲,我不能这样做,因为我需要等待几秒钟才能获得可能的 MSG[1]?好吧,我不能在回调本身中做到这一点。作为记录,我在两种 MSG 案例中都有 MessageBox() 调用,它们都一个接一个地显示。这是我认为的正常行为。
  • 我想你可以。在上面的 WM_CRETE 中,您可以添加这一行 bool *pVar = (bool *)GetWindowLongPtr(hWnd, GWLP_USERDATA);在 SetWindowLongPtr(...) 调用之后,然后执行 *pVar = true;那里。这相当于您的代码。然后替换 case 1: as I type it,用你的其他消息和测试。但是,在一个线程中,windows 使用消息循环对其窗口进行协作多任务处理,因此您需要从回调中返回而不是在那里等待。可以使用计时器 (WM_TIMER) 来实现等待,以计算自您将值设置为“真”以来已经过去了多少时间。
猜你喜欢
  • 2017-09-10
  • 2022-11-19
  • 2019-11-05
  • 1970-01-01
  • 2019-09-03
  • 2011-03-06
  • 1970-01-01
  • 1970-01-01
  • 2018-07-13
相关资源
最近更新 更多