使用Direct2D注意事项

参考:https://docs.microsoft.com/zh-cn/windows/win32/direct2d/direct2d-quickstart

0、Direct2D目前只支持C++,对于C++来说,不建议把程序都写在main/WinMain函数或全局函数中,定义一个App类更符合C++的编程习惯。

1、在包含任何系统头文件之前,先将_WIN32_WINNT用#define设为0x0601(Win7)或以下版本,不然wincodec.h等的Win7兼容性有可能出问题。

2、在main/WinMain函数中

  1. 调用CoInitialize(wincodec.h需要用到这个东西)
  2. 调用app.Initialize()创建窗口
  3. 调用app.RunMessageLoop()进入消息循环
  4. 调用CoUninitialize

3、在Initialize的函数中

  1. 调用this->CreateDeviceIndependentResources(),这个函数创建ID2D1Factory(以及按需创建IDWriteFactory、IWICBitmapFactory等)
  2. 调用ID2D1Factory的GetDesktopDpi获取系统DPI
  3. RegisterClassEx注册窗口类(注意hbrBackground应该设置为NULL,以防止DefWindowProc使用GDI清空窗口内容导致窗口闪烁)
  4. CreateWindow创建窗口(使用CreateWindow最后一个参数传递this指针)
  5. ShowWindow显示窗口、UpdateWindow更新窗口
#pragma warning(push)
#pragma warning(disable:4996)
        m_pDirect2dFactory->GetDesktopDpi(&dpiX, &dpiY);
#pragma warning(pop)

3、WndProc中对于this指针的处理

  1. 在WM_CREATE中,传入的this指针可以从((LPCREATESTRUCT)lParam)->lpCreateParams获取
  2. 使用窗口的GWLP_USERDATA字段(使用SetWindowLongPtr和GetWindowLongPtr访问)保持this指针

4、要注意尽量避免程序崩溃,适当处理HRESULT错误码

  1. 要注意对象指针当前是否可能为NULL,当对象指针可能为NULL时,就不要使用该对象指针。一般如果创建对象的方法返回值hr表示操作成功SUCCEEDED(hr),指针一般认为是可用的,如果返回值hr表示操作失败FAILED(hr),指针一般认为有可能是NULL。
  2. HRESULT错误码不一定要全部处理。可以忽略某些无关紧要的失败;重要的但可恢复的失败需要进行处理;如果是导致程序无法继续的失败,使用exit(hr);处理即可;如果是逻辑上应该根本不可能出现的失败,使用Assert(SUCCEEDED(hr));处理。

5、在WM_PAINT中

  1. 调用pThis->OnRender();
  2. 调用ValidateRect标记窗口客户区为有效,不再触发WM_PAINT(BeginPaint加上EndPaint也有同样的效果,但这里我们不使用GDI,因此使用ValidateRect看起来更干净),一般用于静态绘制;或者调用InvalidateRect,再次触发WM_PAINT,一般用于动画绘制。

6、在OnRender()中,进行如下操作

  1. 调用this->CreateDeviceResources(),这个函数创建ID2D1HwndRenderTarget和相关的对象(如果已创建则不再创建)
  2. 调用BeginDraw
  3. SetTransform设置变换,通常设置为Matrix::Identity()
  4. Clear清空
  5. GetSize获取绘图区大小(相当于DPI无关的GetClientSize)
  6. 绘图
  7. 调用EndDraw
  8. 当EndDraw返回D2DERR_RECREATE_TARGET时,调用this->DiscardDeviceResources(),这个函数使用SafeRelease释放所有与RenderTarget相关的对象,以便下次绘图时重新创建,忽略EndDraw除这个错误码以外的错误码

7、当WM_SIZE时,调用pThis->OnResize(),这个函数调用ID2D1HwndRenderTarget的Resize调整绘图区域大小,一般忽略错误码,因为这个这个错误码会在下次EndDraw时返回

8、当WM_DISPLAYCHANGE(分辨率改变)时,调用InvalidateRect触发WM_PAINT

9、common.h或stdafx.h公共头文件

#pragma once

// 必须设为0x0601(Windows 7)或以下,否则wincodec.h对Windows 7会有兼容性问题
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0601
#endif

#ifndef UNICODE
#define UNICODE 1
#endif

#define WIN32_LEAN_AND_MEAN 1
// Windows Header Files:
#include <windows.h>

// C RunTime Header Files:
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <wchar.h>
#include <math.h>

#include <d2d1.h>
#include <d2d1helper.h>
#include <dwrite.h>
#include <wincodec.h>

template<class Interface>
inline void SafeRelease(
    Interface** ppInterfaceToRelease
)
{
    if (*ppInterfaceToRelease != NULL)
    {
        (*ppInterfaceToRelease)->Release();
        (*ppInterfaceToRelease) = NULL;
    }
}

#ifndef Assert
#if defined( DEBUG ) || defined( _DEBUG )
#define Assert(b) do {if (!(b)) {OutputDebugStringA("Assert: " #b "\n");}} while(0)
#else
#define Assert(b)
#endif //DEBUG || _DEBUG
#endif

#ifndef HINST_THISCOMPONENT
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
#define HINST_THISCOMPONENT ((HINSTANCE)&__ImageBase)
#endif
发布了29 篇原创文章 · 获赞 1 · 访问量 3407

猜你喜欢

转载自blog.csdn.net/defrag257/article/details/103375782
今日推荐