- 有一次开发WTL窗口时,使用GDI的CMemoryDC来绘制中文文字显示不出来,但是文字改为英文就绘制出来的,确认字符集,字体,坐标都没问题,那是什么情况?
-
在开发WTL程序时, 我们有时候会容易混合使用GDI和GDI+,比如使用GDI的CDC的方法RoundRect绘制圆角矩形,而GDI+没有类似的方法。同样,使用GDI+轻松绘制png图片,而GDI绘制需要繁琐的转换。但是,实际上,微软MSDN文档说明GDI和GDI+是不能混用的,上边的绘制不出来中文就是混用导致的结果之一。
-
微软的文档说明 GDI 和 GDI + 之间的互操作性 介绍了4种需要互操作性的情况,我们最常用的就是第三种情况在 GDI HDC 上使用 GDI +. 也就是说在创建Gdiplus::Graphics(HDC)之后如果需要使用HDC,那么有两种方式:
2.1. 请先销毁Graphics再使用HDC.
2.2. 使用Graphics.GetHDC()来创建新的HDC,之后直到调用Graphics.ReleaseHDC()之前不要使用Graphics对象.
您可以通过使用采用 HDC 作为参数的图形构造函数来协助在 HDC 上使用 GDI +。 可以使用此方法在 HDC 上绘制 Graphics 类的绘图成员。 将 Graphics 对象附加到 HDC 后,不应在 HDC 上执行任何 GDI 操作,直到 Graphics 对象损坏或超出范围。 如果在 HDC 上需要 GDI 输出,请先销毁 Graphics 对象,然后再使用原始 HDC 或使用 Graphics::GetHDC() 获取新的 hdc,然后按照本文前面所述的规则进行互操作,同时对 GDI + 对象使用 gdi。例子
- 以下例子说明如何使用GDI和GDI+混用的方式,它是微软官方说明的第三种情况,也有3种用法。
// View.h : interface of the CView class // / #pragma once #includeView.cpp#include class CView : public CWindowImpl { public: DECLARE_WND_CLASS(NULL) BOOL PreTranslateMessage(MSG* pMsg); BEGIN_MSG_MAP_EX(CView) MSG_WM_CREATE(OnCreate) MSG_WM_DESTROY(OnDestroy) MESSAGE_HANDLER(WM_PAINT, OnPaint) END_MSG_MAP() LRESULT OnPaint(UINT , WPARAM , LPARAM , BOOL& ); int OnCreate(LPCREATESTRUCT lpCreateStruct); void PaintImage(CDC& cdc,CRect& rect); void OnDestroy(); private: Gdiplus::Font* font_; HFONT font_normal_; Gdiplus::Bitmap* bitmap_; };
// View.cpp : implementation of the CView class // / #include "stdafx.h" #include "resource.h" #include截图 下载地址#include #include #include "View.h" using namespace std; using namespace Gdiplus; static HFONT GetHFONT(int em,int charset = DEFAULT_CHARSET, bool bold = false,const wchar_t* fontName = L"Arial") { LOGFONT lf; memset(&lf, 0, sizeof(LOGFONT)); // zero out structure lf.lfHeight = em; // request a 8-pixel-height font lf.lfCharSet = charset; lstrcpy(lf.lfFaceName,fontName); // request a face name "Arial" if(bold) lf.lfWeight = FW_BOLD; else lf.lfWeight = FW_NORMAL; HFONT font = ::CreateFontIndirect(&lf); return font; } static Gdiplus::Font* GetGDIFont(HDC hdc,int em,int charset = DEFAULT_CHARSET, bool bold = false,const wchar_t* fontName = L"Arial") { LOGFONT lf; memset(&lf, 0, sizeof(LOGFONT)); // zero out structure lf.lfHeight = em; // request a 8-pixel-height font lf.lfCharSet = charset; lstrcpy(lf.lfFaceName,fontName); // request a face name "Arial" if(bold) lf.lfWeight = FW_BOLD; else lf.lfWeight = FW_NORMAL; return new Gdiplus::Font(hdc,&lf); } int CView::OnCreate(LPCREATESTRUCT lpCreateStruct) { auto one = GetDC(); font_ = GetGDIFont(one,16); ReleaseDC(one); font_normal_= GetHFONT(16); bitmap_ = new Bitmap(L"res\toolbar.bmp"); return 0; } BOOL CView::PreTranslateMessage(MSG* pMsg) { pMsg; return FALSE; } void CView::PaintImage(CDC& cdc,CRect& rect) { static std::wstring title(L"学院课程: C++17语言特性和标准库-第一部"); static std::wstring url(L"https://edu.csdn.net/course/detail/30136"); CSize size; cdc.GetTextExtent(title.c_str(),title.size(),&size); CRect rectText(CPoint(100,130),size); cdc.DrawText(title.c_str(),title.size(),rectText,DT_LEFT); // 2. 可以用大括号进行包括graphics进行绘制,当语句块结束时,graphics会销毁. // 接着再使用原HDC. { Gdiplus::Graphics graphics(cdc); graphics.DrawImage(bitmap_,100,180); // 混淆GDI+和GDI方式3 // 如果需要使用HDC,通过GetHDC()方法来锁定graphics,之后再通过方法ReleaseHDC释放锁定graphics. auto hdc = graphics.GetHDC(); CDCHandle dc(hdc); rectText.MoveToY(200); dc.DrawText(title.c_str(),title.size(),rectText,DT_LEFT); graphics.ReleaseHDC(hdc); graphics.DrawImage(bitmap_,100,220); } cdc.GetTextExtent(url.c_str(),url.size(),&size); rectText = CRect(CPoint(100,160),size); cdc.DrawText(url.c_str(),url.size(),rectText,DT_LEFT); } void CView::OnDestroy() { delete font_; DeleteObject(font_normal_); } // 第三种情况. hdc作为Graphics的参数传入,在Graphics销毁之前不要使用hdc. LRESULT CView::OnPaint(UINT , WPARAM , LPARAM , BOOL& ) { CPaintDC dc(m_hWnd); CMemoryDC mdc(dc,dc.m_ps.rcPaint); mdc.SelectFont(font_normal_); CRect rect; GetClientRect(&rect); mdc.FillSolidRect(rect,RGB(255,255,255)); static std::wstring temp(L"https://blog.csdn.net/infoworld"); // 混淆GDI+和GDI方式1. PaintImage(mdc,rect); // 混淆GDI+和GDI方式2,放到最后再使用graphics绘制. Graphics graphics(mdc); RectF rectf_text; rectf_text.X = 100; rectf_text.Y = 100; graphics.MeasureString(temp.c_str(),temp.size(),font_,rectf_text,&rectf_text); auto sf = StringFormat::GenericDefault(); Color color; color.SetFromCOLORREF(RGB(0,0,0)); SolidBrush sb(color); graphics.DrawString(temp.c_str(),temp.size(),font_,rectf_text,sf,&sb); return 0; }
项目代码
参考- 中文有些翻译的不正确,可以结合英文看。比如这句
如果在 HDC 上需要 GDI 输出,请先销毁 Graphics 对象,然后再使用原始 HDC 或使用 Graphics::GetHDC() 获取新的 hdc...
原英文是:
If GDI output is required on the HDC, either destroy the Graphics object before using the original HDC or use Graphics::GetHDC() to get a new HDC...
应该是:
如果在 HDC 上需要 GDI 输出,请先销毁 Graphics 对象,然后再使用原始 HDC; 或者使用 Graphics::GetHDC() 获取新的 hdc...
GDI 和 GDI + 之间的互操作性
Interoperability between GDI and GDI+


![[ATL/WTL] [ATL/WTL]](http://www.mshxw.com/aiimages/31/909165.png)
