一、准备窗体
1、描述窗体(画图纸)
注册一个窗口,windows已经为我们准备好了一个类,直接传入参数即可塑造一个自己想要的窗口了;
WNDCLASSEX cDx12Windows;
cDx12Windows.cbSize = sizeof(WNDCLASSEX);
cDx12Windows.cbClsExtra = 0;
cDx12Windows.cbWndExtra = 0;
cDx12Windows.hbrBackground = nullptr;
cDx12Windows.hCursor = nullptr;
cDx12Windows.hIcon = nullptr;
cDx12Windows.hIconSm = NULL;
cDx12Windows.hInstance = i_hInstance;
cDx12Windows.lpszClassName = L"Dx12Test";
cDx12Windows.lpszMenuName = nullptr;
cDx12Windows.style = CS_VREDRAW | CS_HREDRAW;
cDx12Windows.lpfnWndProc = WindowMessgeProc;
WNDCLASS 结构包含了窗口类的属性信息:
typedef struct {
UINT cbSize; //确定该对象实际占用多大内存
UINT style; //描述窗体风格
WNDPROC lpfnWndProc; //指向窗口过程(消息处理函数)的指针
int cbClsExtra; //确定是否需要额外共享空间
int cbWndExtra; //确定是否需要额外不共享空间
HINSTANCE hInstance; //提供一个实例的句柄
HICON hIcon; //窗口的磁盘图标
HCURSOR hCursor; //窗口内鼠标指针的样式
HBRUSH hbrBackground; //确定窗口的背景
LPCSTR lpszMenuName; //窗口菜单名字
LPCSTR lpszClassName; //窗口名字
HICON hIconSm; //窗口的左上图标
} WNDCLASS, *pWNDCLASS;
a、cbSize:UINT类型,用来确定该对象实际占用多大内存;
b、style:UINT类型,描述窗体风格,用来确定怎么绘制窗口,垂直和水平重绘等,常用的包括
CS_VREDRAW(当窗口水平方向的宽度变化时重绘整个窗口)、
CS_HREDRAW(当窗口水平方向的宽度变化时重绘整个窗口)、
CS_OWNDC(独占设备描述表)、
CS_SAVEBITS(保存窗口覆盖区)、
CS_DBCLKS(允许两次连续按动)、
CS_BYTEALLGNCLIENT(鼠标用户区域按字节对齐显示)、
CS_BYTEALLGNWINDOW(鼠标用户窗口按字节对齐显示)、
CS_NOCLOSE(系统菜单中没有CLOSE菜单项)等。
c、lpfnWndProc:WNDPROC(回调函数)类型,指向窗口过程(消息处理函数)的指针。必须使用CallWindowProc函数调用窗口过程。
d、cbClsExtra:int类型,用来确定是否需要额外空间,且该类生成的所有窗口共享该附加空间;
e、cbWndExtra:int类型,用来确定是否需要额外空间,且每实例化一个窗口都有这么一个不共享的附加空间。
f、hInstance:HINSTANCE类型,提供一个实例的句柄,该实例包含类的窗口过程。
g、hIcon:HICON类型,给窗口一个类图标的句柄(必须是图标资源的句柄),,用来确定应用程序放在磁盘上显示的图标。如果此成员为 NULL,则系统会提供默认图标。
h、hCursor:HCURSOR类型, 给窗口一个鼠标指针的句柄(必须为一个指针资源的句柄),如果hCursor为NULL,只要移入窗口的鼠标都会被改为window预设的样式。
i、hbrBackground:HBRUSH类型,给窗口一个类背景画笔的句柄(可以是用于绘制背景的画笔的句柄,也可以是颜色值,且颜色值必须是以下标准系统颜色之一)。 如果为 NULL,则每当请求应用程序在其工作区中绘制时,都必须绘制自己的背景。 若要确定是否必须绘制背景,应用程序可以处理WM_ERASEBKGND消息或测试 BeginPaint 函数填充的 PAINTSTRUCT 结构的 fErase 成员。
j、lpszMenuName:LPCTSTR类型,指向以 null 结尾的字符串的指针,该字符串指定类菜单的资源名称,因为名称显示在资源文件中。 如果使用整数来标识菜单,请使用 MAKEINTRESOURCE 宏。 如果此成员为 NULL,则属于此类的窗口没有默认菜单。
k、lpszClassName:LPCTSTR类型,用来确定窗口名字(最大长度为 256,超限则RegisterClassEx 函数将失败);
l、hIconSm:HICON类型,给窗口一个类图标的句柄(必须是图标资源的句柄),用来确定应用程序显示在左上角的图标。如果此成员为 NULL,则系统会提供默认图标。
2、注册窗体(提交图纸给工厂)
接口用于检测显示适配器功能和分配资源;
ATOM aRegisterReturn = RegisterClassEx(&cDx12Windows);
if (!aRegisterReturn)
{
return FALSE;
}
其具体的创建方法是通过D3D12CreateDevice函数创建:
ATOM RegisterClassEx(
[in] const WNDCLASSEXW *unnamedParam1
);
a、unnamedParam1:一个指向WNDCLASSEX结构的长指针,在传递给函数之前,必须使用合理的类属性来填充此结构。
b、ATOM:函数返回值,如果函数成功,则返回值是可唯一识别所注册类别的类别Atom,如果此函数失败,则传回值为零。
二、创建窗体
向工厂下单一个窗体,让windows实例化。
HWND hDx12WindowsHandle = CreateWindowEx(
NULL,
L"Dx12Test",
L"Dx12Test",
WS_OVERLAPPEDWINDOW,
0, 0,
500, 300,
NULL,
nullptr,
i_hInstance,
NULL
);
ShowWindow函数,本来是用于调整指定窗口状态的函数:
HWND CreateWindowEx(
DWORD dwExStyle, //窗口的扩展风格(加强版专有)
LPCTSTR lpClassName, //已经注册的窗口类名称
LPCTSTR lpWindowName,//窗口标题栏的名字
DWORD dwStyle, //窗口的基本风格
int x, //窗口左上角水平坐标位置
int y, //窗口左上角垂直坐标位置
int nWidth, //窗口的宽度
int nHeight, //窗口的高度
HWND hWndParent, //窗口的父窗口句柄
WMENU hMenu, //窗口的菜单句柄
HINSTANCE hInstance, //应用程序实例句柄
LPVOID lpParam //窗口创建时附加参数
); //创建成功返回窗口句柄
三、显示窗口
根据图纸造好窗口之后,就要把窗口显示出来了。
HWND hDx12WindowsHandle ;
ShowWindow(hDx12WindowsHandle , SW_MAXIMIZE);
ShowWindow函数,本来是用于调整指定窗口状态的函数:
BOOL ShowWindow(
[in] HWND hWnd,
[in] int nCmdShow
);
a、hWnd:HWND类型,需要显示的窗口的句柄。
b、nCmdShow:int类型,用于控制窗口的显示方式,常用类型为
SW_HIDE 隐藏窗口并激活另一个窗口。
SW_SHOWNORMAL(SW_NORMAL) 激活并显示窗口。 如果窗口最小化、最大化或排列,系统会将其还原到其原始大小和位置。 应用程序应在首次显示窗口时指定此标志。
SW_SHOWMINIMIZED 激活窗口并将其显示为最小化窗口。
SW_SHOWMAXIMIZED(SW_MAXIMIZE)激活窗口并显示最大化的窗口。
SW_SHOWNOACTIVATE 以最近的大小和位置显示窗口。 此值类似于SW_SHOWNORMAL,只是窗口未激活。
SW_SHOW 激活窗口并以当前大小和位置显示窗口。
SW_MINIMIZE 最小化指定的窗口,并按 Z 顺序激活下一个顶级窗口。
SW_SHOWMINNOACTIVE 将窗口显示为最小化窗口。 此值类似于SW_SHOWMINIMIZED,但窗口未激活。
SW_SHOWNA 以当前大小和位置显示窗口。 此值类似于 SW_SHOW,只是窗口未激活。
SW_RESTORE 激活并显示窗口。 如果窗口最小化、最大化或排列,系统会将其还原到其原始大小和位置。 还原最小化窗口时,应用程序应指定此标志。
SW_SHOWDEFAULT 根据启动应用程序的程序传递给 CreateProcess 函数的 STARTUPINFO 结构中指定的SW_值设置显示状态。
SW_FORCEMINIMIZE最小化窗口,即使拥有窗口的线程没有响应。 仅当最小化不同线程的窗口时,才应使用此标志。
四、刷新窗体
窗口是脏的,刷新一下;
HWND hDx12WindowsHandle ;
UpdateWindow(hDx12WindowsHandle );
UpdateWindow 函数是更新窗口的客户区,主要通过发送 WM_PAINT 消息来实现的:
BOOL UpdateWindow(
[in] HWND hWnd
);
a、hWnd:是要更新窗口客户区的窗口句柄;
五、全流程与代码
创建新项目即可。
添加一个cpp文件。
修改项目属性,从黑框的控制台,变成窗口。
继续添加一组文件,专门用于处理dx12窗口。
添加如下代码:
Dx12Window.h
#include <wrl.h>
BOOL CreateDx12Window(HINSTANCE i_hInstance, HWND& o_hHandle);
Dx12Window.cpp
#include"Dx12Window.h"
LRESULT CALLBACK WindowMessgeProc(HWND i_hHwnd, UINT i_iMsg, WPARAM i_wParam, LPARAM i_lParam)
{
switch (i_iMsg)
{
case WM_CLOSE:
PostQuitMessage(0);
return 0;
}
//交给windows自己处理完成
return DefWindowProc(i_hHwnd, i_iMsg, i_wParam, i_lParam);
}
BOOL CreateDx12Window(HINSTANCE i_hInstance, HWND& o_hHandle)
{
WNDCLASSEX cDx12Windows;
cDx12Windows.cbSize = sizeof(WNDCLASSEX);
cDx12Windows.cbClsExtra = 0;
cDx12Windows.cbWndExtra = 0;
cDx12Windows.hbrBackground = nullptr;
cDx12Windows.hCursor = nullptr;
cDx12Windows.hIcon = nullptr;
cDx12Windows.hIconSm = NULL;
cDx12Windows.hInstance = i_hInstance;
cDx12Windows.lpszClassName = L"Dx12Test";
cDx12Windows.lpszMenuName = nullptr;
cDx12Windows.style = CS_VREDRAW | CS_HREDRAW;
cDx12Windows.lpfnWndProc = WindowMessgeProc;
ATOM aRegisterReturn = RegisterClassEx(&cDx12Windows);
if (!aRegisterReturn)
{
return FALSE;
}
HWND hDx12WindowsHandle = CreateWindowEx(
NULL,
L"Dx12Test",
L"Dx12Test",
WS_OVERLAPPEDWINDOW,
0, 0,
500, 300,
NULL,
nullptr,
i_hInstance,
NULL
);
if (!hDx12WindowsHandle)
{
return FALSE;
}
ShowWindow(hDx12WindowsHandle, SW_SHOW);
UpdateWindow(hDx12WindowsHandle);
o_hHandle = hDx12WindowsHandle;
return TRUE;
}
Dx12TestMian.cpp
#include "Dx12Window.h"
int WINAPI WinMain(
HINSTANCE i_hInstance, //应用程序当前运行的实例的句柄,这是系统给该实例的一个唯一标识符,是一个数值
HINSTANCE i_PrevInstance, //当前实例的前一个实例的句柄。在Win32环境下,这个参数总是NULL
PSTR i_lpCmdLine, //一个以空终止的字符串,指定传递给应用程序的命令行参数,可在工程设置中调整
int i_iCmdShow //窗口如何显示
)
{
HWND hDx12WindowsHandle;
if (!CreateDx12Window(i_hInstance, hDx12WindowsHandle))
{
return 1;
}
system("pause");//暂停一下
return 1;
}
小窗口效果如下: