如何在 MessageBox 之后保留程序 运行

How to keep program running after MessageBox

我对在 C++ 中使用 Win32 API 进行开发还很陌生,我编写了第一个这样的程序:

The program's apperance

下面是我的代码,但如果你想构建它,那么这是我的 project archive

// The feedback interface with GUI.

#include "stdafx.h"
#include "Win32Project1.h"
#include <string>
#include <fstream>
#include <Windows.h>
#define MAX_LOADSTRING 65536
#include <strsafe.h>
HFONT defaultFont;
HWND hwnd2;
HWND Button;
HWND Help;
void ErrorExit(LPTSTR lpszFunction) //Function used for debugging
{
    // Retrieve the system error message for the last-error code

    LPVOID lpMsgBuf;
    LPVOID lpDisplayBuf;
    DWORD dw = GetLastError();

    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER |
        FORMAT_MESSAGE_FROM_SYSTEM |
        FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        dw,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR)&lpMsgBuf,
        0, NULL);

    // Display the error message and exit the process

    lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
        (lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR));
    StringCchPrintf((LPTSTR)lpDisplayBuf,
        LocalSize(lpDisplayBuf) / sizeof(TCHAR), 0);
}
LPWSTR Convert(const std::string& s)
{
    LPWSTR ws = new wchar_t[s.size() + 1]; // +1 for zero at the end
    copy(s.begin(), s.end(), ws);
    ws[s.size()] = 0; // zero at the end
    return ws;
}


LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

TCHAR Feedback[MAX_LOADSTRING];
std::string Msg;
std::string MsgTitle;
std::ofstream FeedbackFile;

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow)
{
    // Get UI font
    NONCLIENTMETRICS ncm;
    ncm.cbSize = sizeof(ncm);

    // If we're compiling with the Vista SDK or later, the NONCLIENTMETRICS struct
    // will be the wrong size for previous versions, so we need to adjust it.

    SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0);
    defaultFont = CreateFontIndirect(&(ncm.lfMessageFont));
    // Register the window class.
    std::string CLASS_NAME = "The first program!";

    WNDCLASS wc = {};

    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = L"First program!";

    RegisterClass(&wc);

    // Create the window.

    HWND hwnd = CreateWindowEx(
        WS_EX_CONTEXTHELP,                              // Optional window styles.
        L"First program!",                     // Window class
        L"The first program!",          // Window text
        WS_OVERLAPPEDWINDOW,            // Window style

                                        // Size and position
        0, 0, 640, 360,

        NULL,       // Parent window    
        NULL,       // Menu
        hInstance,  // Instance handle
        NULL        // Additional application data
    );

    if (hwnd == NULL)
    {
        return 0;
    }

    ShowWindow(hwnd, nCmdShow);

    // Create the window.

    hwnd2 = CreateWindowEx(
        WS_EX_CLIENTEDGE,              // Optional window styles.
        L"edit",                       // Window class
        L"Insert feedback here :)",    // Window text
        WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER | ES_LEFT | WS_VSCROLL | ES_MULTILINE | ES_AUTOVSCROLL,            // Window style

                                        // Size and position
        10, 50, 300, 200,

        hwnd,       // Parent window    
        (HMENU)(123),       // Menu
        (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE),  // Instance handle
        NULL        // Additional application data
    );
    Button = CreateWindowW(
        L"BUTTON",
        L"Submit feedback!",
        WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
        160, 255, 150, 20,
        hwnd,
        (HMENU) BT_PRESS,
        (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE),
        NULL
    );
    Help = CreateWindowW(
        L"BUTTON",
        L"What is this?",
        WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
        10, 280, 80, 20,
        hwnd,
        (HMENU)HELP_PRESS,
        (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE),
        NULL
    );
    SendMessage(hwnd2, WM_SETFONT, WPARAM(defaultFont), TRUE);
    SendMessage(Button, WM_SETFONT, WPARAM(defaultFont), TRUE);
    SendMessage(Help, WM_SETFONT, WPARAM(defaultFont), TRUE);

    if (hwnd2 == NULL)
    {
        return 0;
    }

    ShowWindow(hwnd2, nCmdShow);

    // Run the message loop.

    MSG msg = {};
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 0;
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_HELP:
        MessageBox(Help, L"This is my first program made by Visual Studio 2017.\nYou can type your feedback in the box and then press Submit feedback!\nYour feedback will be saved and we will read it.\n\nThanks so much for using this program. :)", L"About this program", MB_OK);
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;

    case WM_PAINT:
    {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hwnd, &ps);
        SelectObject(hdc, defaultFont);
        FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
        TextOut(hdc, 10, 5, TEXT("Hi! This is my first program made by Visual Studio 2017."), 57);
        TextOut(hdc, 10, 20, TEXT("Do you have something to tell me?"), 34);
        TextOut(hdc, 10, 35, TEXT("Just write below and I will listen. :)"), 39);
        EndPaint(hwnd, &ps);
    }
    case WM_COMMAND:
    {
        switch (wParam)
        {
        case BT_PRESS:
        {
            GetWindowText(hwnd2, Feedback, MAX_LOADSTRING);
            FeedbackFile.open("Feedback.txt", std::ios::out | std::ios::app);
            FeedbackFile << Feedback;
            FeedbackFile << "\n------------------------\n";
            FeedbackFile.close();
            LPWSTR Msg = L"Thanks for your feedback! I appreciated!";
            LPWSTR MsgTitle = L"Feedback accepted!";
            MessageBox(hwnd, Msg, MsgTitle, MB_OK);
            SendMessage(hwnd, WM_DESTROY, NULL, NULL);
        } break;
        case HELP_PRESS:
            SendMessage(hwnd, WM_HELP, 0, 0);
            break;
        }
    }
    return 0;

    }
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }

我打算让程序显示一个消息框,告诉用户有关该程序的信息,然后单击“确定”时,该框关闭,程序仍然存在。但是当点击确定按钮时,消息框消失了,程序也关闭了。 用户单击“确定”后是否仍然保留程序运行?非常感谢。

你不应该使用 SendMessage(hwnd, WM_DESTROY, NULL, NULL);这实际上是告诉程序退出。

MessageBox() 是一个阻塞调用。不需要 post 消息队列中的消息。

这将是您的新 WM_COMMAND (更新 1)

case WM_COMMAND:
    {
        switch (wParam)
        {
        case BT_PRESS:
        {
            GetWindowText(hwnd2, Feedback, MAX_LOADSTRING);
            FeedbackFile.open("Feedback.txt", std::ios::out | std::ios::app);
            FeedbackFile << Feedback;
            FeedbackFile << "\n------------------------\n";
            FeedbackFile.close();
            LPWSTR Msg = L"Thanks for your feedback! I appreciated!";
            LPWSTR MsgTitle = L"Feedback accepted!";
            MessageBox(hwnd, Msg, MsgTitle, MB_OK);
            SendMessage(hwnd2, WM_DESTROY, NULL, NULL);
        } break;
        case HELP_PRESS:
            SendMessage(hwnd, WM_HELP, 0, 0);
            break;
        }
    }

OK,经过2天的编辑和调试,我终于有了自己的答案。我想也许是消息循环

while (GetMessage(&msg, NULL, 0, 0))
{
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}

是问题所在。所以我添加了一个 BOOL 帮助并像这样编辑代码:

//Message loop in the wWinMain function
while (GetMessage(&msg, NULL, 0, 0))
{
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}

if (helped) {
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}  //Repeat the loop again if user clicked "What is this?"

//The HELP_PRESS handle in WM_COMMAND
        case HELP_PRESS:
            SendMessage(hwnd, WM_HELP, 0, 0);
            helped = true;
            break;

无论如何,非常感谢 Suraj Si486 对我的帮助。我希望这可以帮助其他遇到同样问题的编码员。再次感谢。

我看到的第一个问题是 switch 结构的某些部分缺少 break 语句。

如果 return 是一个部分的最后一个语句,这不是问题:

case WM_DESTROY:
    PostQuitMessage(0);
    return 0;
    break; // This line has no effect after a return

但是,如果既没有 break 也没有 return 语句,你就会遇到问题:

case WM_HELP:
    MessageBox(Help, ... , MB_OK);
    // break; <- This line is missing in your program!
case WM_DESTROY:
    PostQuitMessage(0);

在这种情况下,WM_DESTROY 部分将在 WM_HELP 部分之后输入。在显示 MessageBox 之后,将执行 PostQuitMessage 函数,这将停止您的程序。