【DirectX学习笔记】00_创建一个Windows窗口

学习DirectX之前需要了解一下Windows编程基础,每个Windows程序需要创建一个窗体。创建窗体大致分为三步:(1)注册一个窗体类(2)创建窗体对象(3)创建消息处理函数,用来接收并处理Windows发来的消息。使用如下三个函数来完成以上的三个步骤:

RegisterClassEx(); // 注册窗口
CreateWindowEx();  // 创建窗口
ShowWindow();      // 显示窗口

关于Windows的接口可在msdn上查询。类似于win32控制台程序的main函数,Windows程序的入口点是WinMain函数。WinMain函数结构如下:

int WINAPI WinMain(
  HINSTANCE  hInstance,
  HINSTANCE  hPrevInstance, 
  LPSTR      lpCmdLine,
  int        nShowCmd
);

 其中,WINAPI是一个调用约定(#define  WINAPI  __stdcall),定义了参数出现在堆栈上的顺序:

压栈顺序:从右至左

清栈:被调用函数负责清空,称为callee cleanup

名字修饰:在函数名前加上下划线做前缀,名字后用@加上函数参数大小做后缀

【注:WINAPI就是__stdcall的#define】

WinMain参数解释
hInstance应用程序当前实例的句柄。当它被加载到内存中时,操作系统使用这个值来识别可执行文件 (EXE)。某些 Windows 功能需要实例句柄,例如加载图标或位图。
hPrevInstance应用程序前一个实例的句柄。此参数始终为NULL。
pCmdLine应用程序的命令行,不包括程序名称。
nCmdShow是一个控制窗口显示方式的标志,表示主应用程序窗口是最小化、最大化还是正常显示。

 一、注册一个窗体类

首先需要创建一个窗口类WNDCLASSEX,设置窗体的各种属性;窗口类与C++中类的概念不同,它是窗口属性的一种模板。

WNDCLASSEX结构如下:


typedef struct tagWNDCLASSEXA {
  UINT         cbSize;           // 此结构体大小
  UINT         style;            // 窗口类风格,该成员可以是Class Style的任意组合
  WNDPROC      lpfnWndProc;      // 指向窗口的指针
  int          cbClsExtra;       // 按照窗口类结构分配的额外字节数,系统将字节初始化为零
  int          cbWndExtra;       // 在窗口实例之后分配的额外字节数
  HINSTANCE    hInstance;        // 包含窗口类实例句柄
  HICON        hIcon;            // 类图标的句柄
  HCURSOR      hCursor;          // 类光标的句柄
  HBRUSH       hbrBackground;    // 类背景画笔的句柄
  LPCSTR       lpszMenuName;     // 指向以空字符结尾的字符串的指针,该字符串指定类菜单的资源名称
  LPCSTR       lpszClassName;    // 指向以空字符结尾的字符串的指针,窗口类名称
  HICON        hIconSm;          // 与窗口类关联的小图标的句柄
};

相关代码如下:

// 这个结构体用于保存窗口类相关的信息
WNDCLASSEX wc;

// 清空窗口类以供使用
ZeroMemory(&wc, sizeof(WNDCLASSEX));

// 在结构体中填写所需的窗口类信息
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = L"MyFirstWindow";
wc.hIconSm = LoadIcon(wc.hInstance, IDI_APPLICATION);

// 注册这个窗口类
if (!RegisterClassEx(&wc))
    return E_FAIL;

二、创建窗体对象

根据创建的窗口类来创建窗口。要创建窗口,需要函数:

HWND CreateWindowEx(
    DWORD      dwExStyle,    // 指定窗口的扩展样式
    LPCTSTR    lpClassName,  // 窗口类名称
    LPCTSTR    lpWindowName, // 窗口名称
    DWORD      dwStyle,      // 指定正在创建的窗口的样式
    int        x,            // 指定窗口的初始水平位置
    int        y,            // 指定窗口的初始垂直位置
    int        nWidth,       // 以设备为单位指定窗口宽度
    int        nHeight,      // 以设备为单位指定窗口高度
    HWND       hWndParent,   // 正在创建的窗口的父窗口或所有者窗口的句柄
    HMENU      hMenu,        // 菜单句柄
    HINSTANCE  hInstance,    // 要与窗口关联的模块实例的句柄
    LPVOID     lpParam       // 长指针,指向要通过WM_CREATE消息的lParam参数中
                             // 传递的CREATESTRUCT结构传递给窗口的值
);

相关代码如下:

// 创建窗口,并将返回的结果作为句柄
hWnd = CreateWindowEx(NULL,
    L"MyFirstWindow",    // 窗口类的名字
    L"Initial Window",   // 窗口的标题
    WS_OVERLAPPEDWINDOW, // 窗口的样式
    300,       // 窗口的x坐标
    300,       // 窗口的y坐标
    500,       // 窗口的宽度
    400,       // 窗口的高度
    NULL,      // 我们没有父窗口,设置为NULL
    NULL,      // 我们不使用菜单,设置为NULL
    hInstance, // 应用程序句柄
    NULL);     // 与多个窗口一起使用,设置为NULL

显示窗口

显示窗口函数:

BOOL ShowWindow(HWND hWnd,   // 创建的窗口句柄
                int nCmdShow // WinMain()函数的最后一个参数,控制窗口的显示方式
);

三、创建消息处理函数

Windows消息处理机制:Windows通过GetMessage()函数从消息队列中取得消息,使用TranslateMessage()来处理某些消息格式,然后由DispatchMessage()函数将消息派送到指定窗口,再由窗口函数WindowProc()对消息处理。流程如下:

 其中:

TranslateMessage()函数将虚拟键消息转换成字符消息;

DipatchMessage()函数将消息派送给窗口,通常情况下被用来发送GetMessage()函数获得的消息。

WindowProc()是应用程序定义,用来处理发送到窗口的消息的函数,定义如下:

LRESULT CALLBACK WindowProc ( 
HWND    hWnd,    // 指向窗口的句柄
UINT    message, // 执行消息类型
WPARAM  wParam,  // 指定其余的、消息特定的信息
LParam  lParam   // 指定其余的、消息特定的信息
);

Windows窗口初始化

完整代码:

#include <Windows.h>
// 全局变量
HINSTANCE   g_hInst = NULL;
HWND        g_hWnd = NULL;
// 函数声明
HRESULT InitWindow(HINSTANCE hInstance, int nCmdShow);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,  int nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);
    if (FAILED(InitWindow(hInstance, nCmdShow)))
        return 0;
    // 消息循环
    MSG msg = { 0 };
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return (int)msg.wParam;
}
// 注册窗口类并创建窗口
HRESULT InitWindow(HINSTANCE hInstance, int nCmdShow)
{
    // 注册窗口类
    WNDCLASSEX wc;
    ZeroMemory(&wc, sizeof(WNDCLASSEX));
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = WndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wc.lpszMenuName = NULL;
    wc.lpszClassName = L"MyFirstWindow";
    wc.hIconSm = LoadIcon(wc.hInstance, IDI_APPLICATION);
    if (!RegisterClassEx(&wc))
        return E_FAIL;
    // 创建窗口
    g_hInst = hInstance;
    RECT rc = { 0, 0, 640, 480 };
    AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE);
    g_hWnd = CreateWindow(
        L"MyFirstWindow",
        L"Initial Window",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        rc.right - rc.left,
        rc.bottom - rc.top,
        NULL,
        NULL,
        hInstance,
        NULL);
    if (!g_hWnd)
        return E_FAIL;
    ShowWindow(g_hWnd, nCmdShow);
    return S_OK;
}
// 每次当应用程序接收消息时调用这个方法
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    PAINTSTRUCT ps;
    HDC hdc;
    switch (message)
    {
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        EndPaint(hWnd, &ps);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

参考博客:

https://blog.csdn.net/weixin_34194087/article/details/92631247

https://enjoyphysics.cn/Article921

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值