【问题标题】:MessageBox() returning 0 when called from Win32 button press从 Win32 按钮按下时调用 MessageBox() 返回 0
【发布时间】:2017-08-10 04:27:27
【问题描述】:

我刚接触 Win32 GUI 编程一周,所以我有信心/希望这很简单。为了您的考虑,我在下面提供了我的代码示例。

简单地说,我的应用程序会监视另一个应用程序是否打开,以便我可以修改该应用程序的内存。我已将此初始检查放置在我的 UI 循环器的顶部,如下所示,它只会运行一次(在这种情况下,用户只能取消并且应用程序关闭,或者执行通过 if 语句恢复,其中 hWndApp 具有赋值):

if (!hWndApp) {
    appCheck();
}

如果我启动我的应用程序而另一个应用程序没有运行,appCheck(); 会触发并且由此产生的执行瀑布会相应地起作用:会出现一个消息框(如果用户单击“重试”则会继续出现)直到另一个找到应用程序的窗口。如果用户单击“取消”,则应用程序退出并且一切正常。如果他们在其他应用程序运行时单击“重试”,那么我的应用程序将完成在屏幕上的绘制并且执行正常。

有趣的事情在我下次调用 appCheck(); 时开始(当点击两个按钮之一时发生)如果另一个应用程序已打开,则关闭

在调试时(通过 Visual Studio 2017),当另一个应用程序打开、然后关闭时,我分配给 MessageBox() 调用的变量等于 0,然后如下:

  1. 按下按钮拨打appCheck();
  2. 然后在if 语句中调用getProcessHandleAndPID();,因为找不到窗口
  3. 然后在while 循环中调用AppCheckMessageBox();,因为找不到窗口
  4. 然后调试器指向AppCheckMessageBox(); 内部的第一行,即整个int msgboxID = MessageBox();
  5. 按F11(Step Into),由于msgboxID的值为0,所以触发switch语句中的default选项后,没有窗口显示并且应用程序存在(表明MessageBox()调用失败,所以我尝试了在exit(EXIT_FAILURE) 之前调用GetLastError(),但无济于事。

我不确定我的错误在哪里,但我已经找到了许多解决方案,但都没有成功。最后,如果您看到下面的任何变量看起来名称错误或未声明,这完全是由于我修改了这篇文章的代码以试图概括/缩短它。我可能遗漏了一些全局变量声明等。

感谢您提供的任何帮助/指导!我现在对此束手无策……哈哈。

//--------------------------------------------------
// Function to get process handle and PID of app  /
//------------------------------------------------
void getProcessHandleAndPID()
{
    hWndApp = FindWindow(NULL, _T("NameOfApplication"));

    while (!hWndApp) {
        AppCheckMessageBox();
    }
    //Much more code here
}

//---------------------------------
// Function to show message box  /
//-------------------------------
int AppCheckMessageBox()
{
    int msgboxID = MessageBox(
        NULL, //I tried making this hWndApp as well, but no difference
        (LPCWSTR)L"Cancel to exit or start the app and click Retry.",
        (LPCWSTR)L"Application Not Found!",
        MB_ICONSTOP | MB_RETRYCANCEL | MB_SYSTEMMODAL | MB_SETFOREGROUND
    );

    switch (msgboxID)
    {
    case IDCANCEL:
        exit(EXIT_FAILURE);
    case IDRETRY:
        getProcessHandleAndPID();
        break;
    default:
        //GetLastError();
        exit(EXIT_FAILURE);
    }

    return msgboxID;
}

//------------------------------------------------
// Function to check if application is running  /
//----------------------------------------------
void appCheck() {
    if (!FindWindow(NULL, _T("NameOfApplication"))) {
        getProcessHandleAndPID();
    }
}

//--------------------------------------------------
// Function to get process handle and PID of app  /
//------------------------------------------------
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    if (!hWndApp) {
        appCheck();
    }

    switch (message)
    {
    case WM_PAINT:
        //Code here
        break;

    case WM_CREATE:
        //Code here
        break;

    case WM_COMMAND:
        switch (HIWORD(wParam))
        {
            case BN_CLICKED:
                if (LOWORD(wParam) == BTN_ENABLE) {
                    appCheck();
                //Do stuff with button press
            }
                if (LOWORD(wParam) == BTN_DISABLE) {
                    appCheck();
                //Do stuff with button press
            }
            break;
        }
        break;

    case WM_DESTROY:
        PostQuitMessage(0);
        break;

    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
        break;
    }

    return 0;
}

【问题讨论】:

  • WndProc 会为传递到您窗口的每条消息调用。每次发生这种情况时,您都会显示一个对话框,该对话框将导致更多消息。因此,无休止的消息框对话框。
  • 感谢您的评论,大卫。因此,请记住这一点,您对我应该如何或在何处绑定该按钮功能以使其不会导致错误有什么建议吗?我需要在调用 appCheck() 之前指定一些东西吗?单击按钮,或者我可以/应该将该呼叫包装在什么东西中?我真的很想知道如何最好地将某些逻辑与 Win32 中的 UI 循环器联系起来。顺便说一句,我开始努力解决这个问题,所以它可能会为我揭开很多神秘面纱:winprog.org/tutorial/index.html
  • 我真的不知道你想要达到什么目的。
  • 您可能知道更好的解决方法。我的总体目标是让我的应用程序始终检查某个其他应用程序是否正在运行。如果不是,则让用户知道。最初,我虽然会创建一个线程来监控,然后相应地更新 UI 中的标签。我无法让它正常工作,所以我转而使用消息框来通知用户。我目前在应用程序启动时将该检查绑定一次,并且每次用户单击一个按钮时。当他们单击按钮并且找不到应用程序时,我的问题就出现了。
  • 好吧,我根本不会使用轮询。我会倾听新进程。

标签: c++ winforms winapi messagebox win32gui


【解决方案1】:

不是真正的答案,但对于 cmets 来说太长了:

  1. 这不是您的真实代码。缺少很多东西,有不匹配的大括号会阻止编译等。如果需要帮助,请始终显示您的真实代码。
  2. 正如大卫所说,每次收到消息时都拨打appCheck() 是错误的做法。如果您想在窗口打开后调用一次,请在进入消息循环之前执行此操作。
  3. 您的代码是不必要的递归(getProcessHandleAndPID() 调用 AppCheckMessageBox(),后者调用 getProcessHandleAndPID(),后者调用...)并且可能导致堆栈溢出。

【讨论】:

  • 感谢您的回复。 1. 修复示例中的大括号问题。如帖子中所述,我从数百行代码中获取了相关的 sn-p,因此我没有将其全部粘贴。编译不是问题。 2. 我认为,这正好解决了问题。我的总体目标是始终检查某个其他应用程序是否正在运行,然后相应地让用户知道。我希望这是一个更新 UI 中标签的线程,但我无法确定这一点。 3. 如果用户单击“重试”并且仍然找不到其他应用程序,这是故意显示“重试/取消”窗口的行为。
  • 您可以简单地重构以实现该结果而无需递归。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-23
  • 1970-01-01
  • 2012-03-31
相关资源
最近更新 更多