DirectX 使用 Vortice 从零开始控制台创建 Direct2D1 窗口修改颜色( 二 )


using D3D = Vortice.Direct3D;using D3D11 = Vortice.Direct3D11;using DXGI = Vortice.DXGI;using D2D = Vortice.Direct2D1;其他的引用代码如下
using System.Runtime.CompilerServices;using System.Runtime.InteropServices;using System.Runtime.Versioning;using Windows.Win32.Foundation;using Windows.Win32.UI.WindowsAndMessaging;using static Windows.Win32.PInvoke;using static Windows.Win32.UI.WindowsAndMessaging.PEEK_MESSAGE_REMOVE_TYPE;using static Windows.Win32.UI.WindowsAndMessaging.WNDCLASS_STYLES;using static Windows.Win32.UI.WindowsAndMessaging.WINDOW_STYLE;using static Windows.Win32.UI.WindowsAndMessaging.WINDOW_EX_STYLE;using static Windows.Win32.UI.WindowsAndMessaging.SYSTEM_METRICS_INDEX;using static Windows.Win32.UI.WindowsAndMessaging.SHOW_WINDOW_CMD;using Vortice.DCommon;using Vortice.Mathematics;using AlphaMode = Vortice.DXGI.AlphaMode;由于本文使用的项目 , 在 csproj 项目文件设置了使用 ImplicitUsings 属性 , 加上对 System 等命名空间的默认引用,这里就不需要再写对默认命名空间的引用
加上 Win32 定义为了创建 Win32 窗口以及初始化创建 DX 对象,就需要使用一些 Win32 函数 。使用 Win32 函数之前 , 需要对 Win32 函数进行定义 。本文使用 Microsoft.Windows.CsWin32 库来辅助编写 Win32 函数的定义
在安装了 Microsoft.Windows.CsWin32 库 , 即可新建一个 NativeMethods.txt 的文件,在这个文件里面,一行一个函数或 Win32 类型名,即可自动使用源代码生成的方式创建定义
新建一个 NativeMethods.txt 文件 , 在这个文件里面写上需要使用的 Win32 函数,内容如下
GetModuleHandlePeekMessageTranslateMessageDispatchMessageGetMessageRegisterClassExWDefWindowProcLoadCursorPostQuitMessageCreateWindowExWDestroyWindowShowWindowGetSystemMetricsAdjustWindowRectExGetClientRectGetWindowRectIDC_ARROWWM_KEYDOWNWM_KEYUPWM_SYSKEYDOWNWM_SYSKEYUPWM_DESTROYWM_QUITWM_PAINTWM_CLOSEWM_ACTIVATEAPPVIRTUAL_KEY完成了初始化准备之后,接下来就可以开始编写代码
创建窗口本文使用控制台项目,在创建 Win32 窗口,需要使用到很多 Win32 窗口创建的细节代码,但本文更侧重如何使用 DX 的知识,因此关于 Win32 创建窗口的逻辑,大部分都会略过
在开始创建 Win32 窗口之前,先准备一些参数
设置窗口的尺寸
SizeI clientSize = new SizeI(1000, 1000);再给窗口定义一个标题
// 窗口标题var title = "Demo";var windowClassName = "lindexi doubi";配置窗口的 Win32 样式,这个样式的内容没啥固定的,可以根据自己的需求来,也可以乱来,不离谱就好
// 窗口样式,窗口样式含义请执行参阅官方文档,样式只要不离谱,自己随便写,影响不大WINDOW_STYLE style = WS_CAPTION |WS_SYSMENU |WS_MINIMIZEBOX |WS_CLIPSIBLINGS |WS_BORDER |WS_DLGFRAME |WS_THICKFRAME |WS_GROUP |WS_TABSTOP |WS_SIZEBOX;根据上面设置的窗口尺寸,尝试根据样式算出实际可用的尺寸
var rect = new RECT{right = clientSize.Width,bottom = clientSize.Height};// Adjust according to window stylesAdjustWindowRectEx(&rect, style, false, WS_EX_APPWINDOW);接着算出窗口显示的坐标和尺寸,这个逻辑非核心逻辑,也可以自己随意写一个坐标 。本文将尝试让窗口显示在屏幕中间
int x = 0;int y = 0;int windowWidth = rect.right - rect.left;int windowHeight = rect.bottom - rect.top;// 随便,放在屏幕中间好了 。多个显示器?忽略int screenWidth = GetSystemMetrics(SM_CXSCREEN);int screenHeight = GetSystemMetrics(SM_CYSCREEN);x = (screenWidth - windowWidth) / 2;y = (screenHeight - windowHeight) / 2;准备完成,开始创建窗口
var hInstance = GetModuleHandle((string)null);fixed (char* lpszClassName = windowClassName){PCWSTR szCursorName = new((char*)IDC_ARROW);var wndClassEx = new WNDCLASSEXW{cbSize = (uint)Unsafe.SizeOf<WNDCLASSEXW>(),style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC,// 核心逻辑,设置消息循环lpfnWndProc = new WNDPROC(WndProc),hInstance = (HINSTANCE)hInstance.DangerousGetHandle(),hCursor = LoadCursor((HINSTANCE)IntPtr.Zero, szCursorName),hbrBackground = (Windows.Win32.Graphics.Gdi.HBRUSH)IntPtr.Zero,hIcon = (HICON)IntPtr.Zero,lpszClassName = lpszClassName};ushort atom = RegisterClassEx(wndClassEx);if (atom == 0){throw new InvalidOperationException($"Failed to register window class. Error: {Marshal.GetLastWin32Error()}");}}// 创建窗口var hWnd = CreateWindowEx(WS_EX_APPWINDOW,windowClassName,title,style,x,y,windowWidth,windowHeight,hWndParent: default,hMenu: default,hInstance: default,lpParam: null);获取到的 hWnd 将会在接下来被 DX 挂上
但愿大家知道 hWnd 是啥意思
既然创建出了窗口了 , 那就显示出来吧

推荐阅读