可以在没有消息循环的情况下运行Windows应用程序吗?

3

我有一个非常老的应用程序,让我感到惊讶的是,这个应用程序在没有消息循环(GetMessagePeekMessage)的情况下运行。

这是怎么可能的呢?

来自Visual Studio的编辑示例:

HINSTANCE g_hInstance = NULL;

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow);

ATOM _RegisterClass(HINSTANCE hInstance);

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR    lpCmdLine,
                     int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    _RegisterClass(hInstance);

    InitInstance(hInstance, SW_NORMAL);

    return 0;
}

ATOM _RegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEXA wcex = {0};
    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.style          = CS_SAVEBITS;
    wcex.lpfnWndProc    = WndProc;
    wcex.hInstance      = hInstance;
    wcex.lpszClassName  = "TEST_CLASS";

    ATOM a = 0;

    a =  RegisterClassExA(&wcex);

    return a;
}

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
    HWND hWnd;

    g_hInstance = hInstance; // Store instance handle in our global variable

    hWnd = CreateWindowA("TEST_CLASS", "TEST_WINDOW", WS_OVERLAPPEDWINDOW,
        0, 0, 0, 0, NULL, NULL, hInstance, NULL);

    if (!hWnd)
    {
        return FALSE;
    }

     SendMessageW(hWnd, WM_USER, 111, 0);

    return TRUE;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    int wmId, wmEvent;
    PAINTSTRUCT ps;
    HDC hdc;

    switch (message)
    {
    case WM_CREATE:
        OutputDebugStringA("Create called.\n");
        break;

case WM_USER:
    {
        if (wParam == 111)
        {

            OutputDebugStringA("User called.\n");
        }
    }
            break;

    case WM_DESTROY:
        OutputDebugStringA("Destroy called.\n");
        break;

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

调试输出:

调用了Create函数。 调用了User函数。 调用了Destroy函数。 程序“[2152] Test.exe: Native”已退出,代码为0(0x0)。


应用程序是否创建一个窗口? - CodeCaster
1
它是用什么语言编写的?它使用了哪些框架?它是如何创建主窗口的? - CodeCaster
1
这是不可能的,你只是还没有找出它是如何做到的。要么它是一个DOS应用程序,你把一个命令窗口误认为了Windows窗口。 - Roger Rowland
1
它运行并完成,而不显示窗口。我看不到任何消息处理。WM_CREATE作为CreateWindow的结果传递给您的WindowProc,但这并不意味着您有一个消息循环。 - Roger Rowland
我对Win32不是很熟悉,但这段代码似乎是告诉Windows使用你的WindowProc,导致回调函数被每个消息调用,而不是在你自己的消息循环中进行翻译和分发。 - CodeCaster
显示剩余3条评论
1个回答

4
这是预期行为。 CreateWindow 调用 SendMessage 发送 WM_NCCREATEWM_CREATE 给正在创建的窗口。 SendMessage 的行为如下(引自 MSDN):
"If the specified window was created by the calling thread, the window procedure is called immediately as a subroutine."
您的程序调用 CreateWindow,随后调用您的窗口过程(在收到 WM_CREATE 时输出 "Create called"),然后返回。它验证窗口句柄是否非空,这是正确的,并返回退出代码 0 而不是进入消息泵。
它没有输出 "Destroy called"(可能是您预期的),因为那并没有发生。窗口没有被销毁(好吧,最终会被操作系统销毁),程序只是退出了。
关于已编辑的代码:
新代码在调用 SendMessageW 时有所不同,它再次直接调用窗口过程。因此,即使没有消息泵,也会接收到用户消息。
似乎销毁消息现在也通过了,这显然有点令人惊讶。不确定原因是什么。
请注意,窗口是使用 "A" 函数创建的,因此通常不建议调用 "W" 函数(尽管在这里似乎 "起作用")。

有趣,看看我修改过的例子,仍然没有循环,那么WM_USER是如何传递的呢? - user2120666
2
WM_USER是如何传递的?你是直接发送消息。尝试使用PostMessage来发布消息,你会发现消息不会被接收到。 - Paul

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接