windows 我需要在Win32中编写什么样的最低限度才能打开窗口?

zazmityj  于 2023-02-05  发布在  Windows
关注(0)|答案(2)|浏览(143)

问题:

我试图用C设置Winapi,用最少的代码显示一个简单的窗口,我如何在我的源代码格式化的方式做这件事?

问题:

下面不打开一个窗口,它只是关闭,这是为什么呢?

/* window_s.h */
typedef struct {
        WNDCLASS wc;                                                                     
        HINSTANCE hInstance;
        HWND hwnd;
} WINDOW;
/* setUpWinProc.h */
LRESULT CALLBACK WindowProc( HWND hwnd,
        UINT uMsg, WPARAM wParam,
        LPARAM lParam) { }
/* registerWindow.c */
void registerWindow(WINDOW *window) {
        const char CLASS_NAME[]
                = "Window Class Name";
        window->wc.lpfnWndProc  = WindowProc;
        window->wc.hInstance    = window->wc.hInstance;
        window->wc.lpszClassName        = CLASS_NAME;
        RegisterClass(&(window->wc));
}
/* createWindow.c */
int_fast64_t CreateWindow_(WINDOW *window) {
        window->hwnd = CreateWindowEx(
                0,              // Optional window styles
                window->wc.lpszClassName,       // Window class
                "Window",       // Window text
                WS_OVERLAPPEDWINDOW,    //Window style

                // Size and position
                CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,

                NULL,   // Parent window
                NULL,   // Menu
                window->hInstance,      // Instance handle
                NULL            // Additional application data
                );
        if (window->hwnd == NULL)
                return 0;
        return window->hwnd;
}
/* Window_Main.c */
#include <windows.h>
#include "window_s.h"
#include "setUpWinProc.h"
#include "registerWindow.c"
#include "createWindow.c"
#include <stdio.h>
int WINAPI WinMain ( HINSTANCE hInstance,
                        HINSTANCE hPrevInstance,
                        LPSTR pCmdLine,
                        int nCmdShow ) {
        WINDOW window = {{}, hInstance};
        registerWindow(&window);
        CreateWindow_(&window);
        ShowWindow(window.hwnd, nCmdShow);
}
e3bfsja2

e3bfsja21#

这是问题的一部分:

int WINAPI WinMain ( HINSTANCE hInstance,
                        HINSTANCE hPrevInstance,
                        LPSTR pCmdLine,
                        int nCmdShow ) {
        WINDOW window = {{}, hInstance};
        registerWindow(&window);
        CreateWindow_(&window);
        ShowWindow(window.hwnd, nCmdShow);
}

您认为在ShowWindow返回和WinMain本身返回之后会发生什么?(提示:程序退出)。
使用TranslateMessage + DispatchMessage将WinMain扩展到泵消息

int WINAPI WinMain ( HINSTANCE hInstance,
                        HINSTANCE hPrevInstance,
                        LPSTR pCmdLine,
                        int nCmdShow ) {

        MSG msg;

        WINDOW window = {{}, hInstance};
        registerWindow(&window);
        CreateWindow_(&window);
        ShowWindow(window.hwnd, nCmdShow);

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

然后,您的消息进程至少需要处理WM_CLOSE和WM_PAINT,并且能够将它不处理的消息转发到默认窗口进程。

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

    switch (uMsg) {
        case WM_PAINT: {
    
             PAINTSTRUCT ps;
             BeginPaint(hwnd, &ps);
             EndPaint(hwnd, &ps);
             break;
        }

        case WM_DESTROY: {
            PostQuitMessage(0);
            break;
        }

        default: {
            return DefWindowProc(hwnd, uMsg, wParam, lParam);
        }
    }

    return 0;
}

您的RegisterClass调用看起来也很可疑。让我们像这样初始化:

WNDCLASSEXW wcex = {0};
    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WindowProc;
    wcex.hInstance      = hInstance;
    wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszClassName  = szWindowClass;

    RegisterClassExW(&wcex);

如果您有Visual Studio(和版本),则会有一个默认的Win32应用程序,它生成最少的存根应用程序,而这些存根应用程序完全可以完成您试图实现的功能。请在C++项目中查找"默认Windows应用程序"或类似内容。

unftdfkk

unftdfkk2#

核心问题就在这里:

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

正如编译器警告的那样,这个函数需要返回一个值(但实际上并没有)。将其注册为窗口过程的行为是未定义的。它可能无法创建窗口;CreateWindowEx()在返回之前使用WM_NCCREATEWM_CREATE消息调用窗口过程。消息处理程序必须返回特定值才能继续创建窗口。
窗口类名也有类似的问题:它使用了一个局部变量,但是传递了一个指向它的指针。当registerWindow()返回时,CLASS_NAME消失了。类注册成功,但是当创建窗口时,对CreateWindowEx()的调用使用了垃圾作为窗口类名。
第一个修正如下:

LRESULT CALLBACK WindowProc( HWND hwnd,
        UINT uMsg, WPARAM wParam,
        LPARAM lParam) {
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

以及

void registerWindow(WINDOW *window) {
    static const char CLASS_NAME[] = "Window Class Name";
    // ...
}

这样就解决了窗口创建问题,尽管您不会长时间看到窗口(如果有的话),因为代码会立即退出WinMain()(它也需要返回一个值),从而导致进程终止。
要解决这个问题,你必须在创建窗口的线程上发送消息。下面将解决这两个问题:

int WINAPI WinMain ( HINSTANCE hInstance,
                        HINSTANCE hPrevInstance,
                        LPSTR pCmdLine,
                        int nCmdShow ) {
    WINDOW window = {{}, hInstance};
    registerWindow(&window);
    CreateWindow_(&window);
    ShowWindow(window.hwnd, nCmdShow);

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

    return msg.wParam;
}

这是最基本的要求(除非你把MessageBox()算作 “打开窗口”),但是它不允许你退出应用程序,要添加这个功能,你需要添加一个WM_DESTROY处理程序来通知消息循环结束,如下所示:

LRESULT CALLBACK WindowProc( HWND hwnd,
        UINT uMsg, WPARAM wParam,
        LPARAM lParam) {
    switch (uMsg) {
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    default:
        return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
}

相关问题