1

我只是在学习使用 winapi 创建一个 gui,但我遇到了一个问题。我可以创建一个这样的窗口

#include "stdafx.h"
#include <windows.h>

int main()
{
    HWND hwnd = CreateWindow(L"STATIC",NULL,WS_VISIBLE|WS_SYSMENU|WS_CAPTION,0,0,600,600,NULL,NULL,NULL,NULL);
    UpdateWindow(hwnd);
    MSG msg;

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

    _gettch();
}

但是单击关闭按钮时窗口不会关闭,并且窗口不能拖动或移动。我想知道如何启用窗口的这些功能。

4

1 回答 1

1

普通窗口没有静态窗口,您应该尝试查找如何使用 RegisterWindowEx 注册和处理您自己的类,然后使用相同的类名创建一个窗口。您必须拥有自己的窗口过程才能处理消息。系统注册的所有窗口类都运行自己的默认窗口程序,据我所知,它们都没有处理 WM_CLOSE (即关闭按钮),这就是您无法关闭它的原因。

对你来说,主窗口总是使用类似 WS_OVERLAPPEDWINDOW 的东西,这样就可以清楚地知道它是否可以,并从中消除你不需要的标志。

你如何设置它:

WNDCLASSEX wndcls;
HWND hMainWnd;

// Register your own window class
    ZeroMemory(&wndcls,sizeof(WNDCLASSEX));
    wndcls.cbSize=sizeof(WNDCLASSEX);
    wndcls.style=CS_VREDRAW+CS_HREDRAW;
    wndcls.lpfnWndProc=&appWndFunc;
    wndcls.hInstance=hInstance;
    wndcls.hIcon=hMainIcon;     // or just LoadIcon(hInstance,MAKEINTRESOURCE(IDI_MAIN_ICON))
    wndcls.hIconSm=hMainIcon;
    wndcls.hCursor=LoadCursor((HINSTANCE)NULL,IDC_ARROW);
    wndcls.hbrBackground=(HBRUSH)COLOR_APPWORKSPACE;
    wndcls.lpszClassName="myWndClass";
    if (RegisterClassEx(&wndcls)==0)
    {
        // failed to register class name
        return false;
    }

// Create window with your own class
    hMainWnd=CreateWindowEx(0,\
                            "myWndClass","widnow title",\
                            WS_OVERLAPPEDWINDOW|WS_VISIBLE,\
                            0,\
                            0,\
                            250,\
                            250,\
                            hMainWnd,NULL,hInstance,NULL);

    if (hMainWnd==(HWND)NULL)
    {
        // failed to create main window
        return false;
    }

然后你的主循环:

bool bAppMainLoop=false
while(!bAppMainLoop)
{
    WaitMessage();
    while(PeekMessage(&emsg,NULL,0,0,PM_NOREMOVE))
    {
        if(GetMessage(&emsg,NULL,0,0)==0)
        {
            bAppMainLoop=true;
            break;
        }
        TranslateMessage(&emsg);
        DispatchMessage(&emsg);
    }
}

这比通常的设置要多一些,所以让我解释一下,为了不烧毁 CPU,你等待带有 WaitMessage 的消息,它会阻塞直到发生某些事情,比如移动窗口、单击、绘画等。PeekMessage 将返回 true如果有消息,那么在 while 循环中调用它会确保它耗尽消息队列,如果 GetMessage 返回 0,它将获取消息,这意味着您的应用程序调用了 PostQuitMessage(0),因此在消息中找到了 WM_QUIT循环,这意味着是时候脱离消息循环了。其余的 Translate and Dispatch 就如其名。

最后,您需要自己的窗口过程:

LRESULT CALLBACK appWndFunc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
    if (uMsg==WM_CLOSE)
    {
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hWnd,uMsg,wParam,lParam);
}

DefWindowProc 对于处理来自系统的所有常见消息是必不可少的,因此您无需在此处处理这些消息。您只需响应当您想要关闭窗口时发送的 WM_CLOSE 消息并将退出消息发布到您将捕获并退出的消息循环中。

附加信息:不需要释放你的东西,因为 Windows 会为你这样做,所以下次启动程序时它不会被锁定,但至少在你的主循环之后取消注册你的窗口类是一个好习惯。

顺便说一句,这是错误的主要功能:WinMain是正确的。另外,为了避免更多错误,请确保您编译 Windows GUI 应用程序。

于 2013-10-26T14:51:54.140 回答