【问题标题】:C++ How does Allegro or SDL create window?C++ Allegro 或 SDL 如何创建窗口?
【发布时间】:2011-01-02 12:11:11
【问题描述】:

Allegro 或 SDL 是如何为 Windows 创建窗口的,如何自己做?

我正在尝试为游戏编写 WinApi 包装器,但是当我看到基本的 WinApi 模板并想将其包装成这样的东西时,我完全迷失了

init();
while()
{
   update();
}
exit();

【问题讨论】:

  • 令人讨厌的血腥平台细节。你不想知道。 (提示:它们都是开源的,为什么不查一下而不是问呢?)
  • 我去过,但我觉得它很神奇,尤其是因为它是 C 而不是 OO C++。

标签: c++ winapi window


【解决方案1】:

他们使用CreateWindowEx。一个非常简单的创建窗口的 WinAPI 应用程序看起来有点像这样:

#include <Windows.h>
// If you're using MSVC, this is the easiest HINSTANCE. Other compilers
// get it from WinMain and pass in to constructor.
extern "C" IMAGE_DOS_HEADER __ImageBase;
HINSTANCE hInstance = (HINSTANCE)&__ImageBase;
class Window {
    HWND hWnd;
    static LRESULT __stdcall WindowProc(
        HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
        if (Window* ptr = reinterpret_cast<Window*>(GetWindowLongPtr(hWnd, GWLP_USERDATA)))
            return ptr->DoMessage(hWnd, message, wParam, lParam);
        else
            return DefWindowProc(hWnd, message, wParam, lParam);    
    }
    LRESULT DoMessage(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
         switch(msg) {
         case WM_DESTROY:
             PostQuitMessage(0);
             return 0;
         }
         return DefWindowProc(hWnd, msg, wParam, lParam);
    }
public:
    bool DoMessages() {
        MSG msg;
        while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
            // Translate the message and dispatch it to WindowProc()
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        if (msg.message == WM_QUIT) {
            return false;
        }
        return true;
    }
    Window() {
        WNDCLASSEX wc;
        // clear out the window class for use
        ZeroMemory(&wc, sizeof(WNDCLASSEX));
        // fill in the struct with the needed information
        wc.cbSize = sizeof(WNDCLASSEX);
        wc.style = CS_HREDRAW | CS_VREDRAW;
        wc.lpfnWndProc = WindowProc;
        wc.hInstance = hInstance;
        wc.hCursor = LoadCursor(NULL, IDC_ARROW);
        wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
        wc.lpszClassName = L"WindowClass1";

        RegisterClassEx(&wc);
        // create the window and use the result as the handle
        hWnd = CreateWindowEx(NULL,
            L"WindowClass1",    // name of the window class
            L"Wide::Development",   // title of the window
            WS_OVERLAPPEDWINDOW,    // window style. Always windowed for now.
            0,    // x-position of the window
            0,    // y-position of the window
            1,    // width of the window
            1,    // height of the window
            NULL,    // we have no parent window, NULL
            NULL,    // we aren't using menus, NULL
            hInstance,    // application handle
            NULL);

        ShowWindow(hWnd, SW_MAXIMIZE); // Snap our window to the user's desktop res, minus taskbar etc.
        SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
        SetWindowPos(hWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); // Make sure that our WindowLongPtr is updated.
    }
};
int main() {
    Window window;
    while(window.DoMessages()) {
        // Do app updates, or sleep() if you're mostly waiting on user input
        Sleep(50);
    }
    // When DoMessages() returns false, the window was destroyed, so return.
}

您可以查看 MSDN 文档以获取有关这些函数的作用的更多信息。本质上,它所做的只是创建一个非常简单的最大化非全屏窗口,注册输入,当窗口被销毁时,退出应用程序。你会注意到我实际上将输入转发到了 Window 对象,所以这个最基本的框架是面向对象的,如果你愿意,你可以在这里玩继承,只是不要忘记 WindowLongPtr 函数使用 void*并且不是类型安全的。

还值得一提的是,在 MSVC 等一些编译器上,如果您 #include &lt;Windows.h&gt;,他们希望您使用 WinMain 入口点,而不是 main()。

游戏渲染和更新代码通常比 WinAPI 更加复杂和困难,所以我会找一本关于 DirectX9.0c 或 DirectX10 的书。

【讨论】:

  • “一个非常简单的 WinAPI 应用程序......”哇。谢谢 SDL、Allegro 等。
  • @delnan:我不明白。那东西必须少于一百行,如果你开始弄乱继承,它的绝大多数都是可重用的。
  • @delnan 这就是 Windows 编程的魅力 :-) @DeadMG 太好了,它解决了我的全部问题!非常感谢! :-)
  • 可以轻松很多。您可以通过GetModuleHandle(NULL) 获取HINSTANCE。当您只在一个地方使用它时,为什么要存储它?前 4 行不见了。你为什么在打电话给ptr-&gt;WindowProc 之前检查ptr?它不应该是NULL。鲁棒性不算数:如果它获得随机值,那么它不太可能是随机的NULL。我看到的唯一原因是因为您在SetWindowLongPtr 之前调用了ShowWindow。这可能是一个错误。 WNDCLASSEX wc 初始化可以更短,使用 ` = { sizeof(wc), CS_HREDRAW | CS_VREDRAW, ... }` 初始化器。 Sleep(5) 错了,删除。
  • @MSalters:谢谢,但我可以看出你的经验并不多。例如,CreateWindowEx 在它像 WM_CREATE 一样返回之前将消息发送到 WindowProc,更不用说在 SetWindowPos 更新 LongPtr 之前。如果您查看 GetWindowLongPtr 的文档,它会说如果它尚未设置 - 比如说,因为 CreateWindowEx 尚未返回 - 那么返回值为 NULL。为什么使用GetModuleHandle(NULL)?使用 __ImageBase 更干净、更容易、更快。我只在一个地方使用它,但如果你继续使用它,你可能会在不止一个地方使用它。
猜你喜欢
  • 1970-01-01
  • 2020-10-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-11
  • 1970-01-01
  • 2011-10-12
  • 1970-01-01
相关资源
最近更新 更多