原文:记CRenderTarget:DrawText()绘制中文乱码的BUG及解决办法

转载请注明出处:http://www.cnblogs.com/Ray1024

一、问题描述

在MFC中使用Direct2D有现成的方法,在Visual Studio 2010 SP1及以上环境中MFC封装了Direct2D,我们就可以更加方便、更加简洁地使用Direct2D来进行高效率绘图了,详细教程见msdnhttps://msdn.microsoft.com/zh-cn/library/gg482848.aspx
但是在实际项目中遇到一个问题:MFC项目编码方式为unicode时,CRenderTarget::DrawText()方法正常;但是编码方式为多字节编码时,CRenderTarget::DrawText()绘制中文出现乱码。如下图:
 

二、问题分析

这个问题出现之后,我设置断点定位到CRenderTarget::DrawText()调用处,F11进入afxrendertarget.cpp文件中的函数CRenderTarget::DrawText() 内部,查看函数如下:

void CRenderTarget::DrawText(const CString& strText,
const CD2DRectF& rect, CD2DBrush* pForegroundBrush,
CD2DTextFormat* textFormat,
D2D1_DRAW_TEXT_OPTIONS options,
DWRITE_MEASURING_MODE measuringMode)
{
USES_CONVERSION; if (m_pRenderTarget == NULL)
{
ASSERT(FALSE);
return;
} if (!VerifyResource(pForegroundBrush))
{
return;
} if (textFormat == NULL)
{
// Use default text format
if (m_pTextFormatDefault == NULL)
{
NONCLIENTMETRICS NonClientMetrics;
NonClientMetrics.cbSize = sizeof(NONCLIENTMETRICS); ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, NonClientMetrics.cbSize, &NonClientMetrics, 0); m_pTextFormatDefault = new CD2DTextFormat(this, NonClientMetrics.lfMenuFont.lfFaceName, (FLOAT)abs(NonClientMetrics.lfMenuFont.lfHeight));
} textFormat = m_pTextFormatDefault;
} if (!textFormat->IsValid())
{
ASSERT(FALSE);
return;
} m_pRenderTarget->DrawText(T2CW(strText), strText.GetLength(), textFormat->m_pTextFormat, &rect,
*pForegroundBrush, options, measuringMode);
}

这是CRenderTarget封装的DrawText,内部使用ID2D1RenderTarget对象调用DrawText函数,第一个参数为宽字节字符串,第二个参数为宽字节字符串的长度。

但是这里有一个问题,假如字符串为"中文中文123", 当工程编码为Unicode时,CString使用wchar_t初始化,GetLength获取的长度是7 ;当工程编码为多字节时,CString使用char初始化,GetLength获取的长度是11(因为多字节编码只能用两个ANSI字符表示一个中文字符) 。而你的工程是多字节编码,下面的第一个参数为宽字节字符串,长度为7;但是第二个参数获取到的长度却是11,所以会出现乱码 。这里应该是CRenderTarget中的一个bug,正确的第二个参数应该是第一个参数T2CW(strText)的实际长度wcslen(T2CW(strText)) 。
到这里我们验证了一个结论,这种情况下中文显示出现乱码是因为MFC中CRenderTarget类内部的一个BUG,这样我们就找到了问题的根源。
 

三、解决方案

然而,知道了这个BUG并没有什么卵用,因为afxrendertarget.cpp文件是MFC内部的只读文件,我们并不能对CRenderTarget类做任何改动(摊手)。
但是,我们可以绕个路来解决这个问题:可以使用Direct2D原生API(ID2D1RenderTarget::DrawText())来实现绘制中文,我们在这里把第二个参数改成wcslen(T2CW(strText)),就可以正常地显示中文了,如下:
CString strText(_T("中文Hello, World!"));

//pRenderTarget->DrawText(strText, rect, m_pBlackBrush, m_pTextFormat);

// 把原来的DrawText替换成这个
USES_CONVERSION;
pRenderTarget->GetHwndRenderTarget()->DrawText(
T2CW(strText),
wcslen(T2CW(strText)),
m_pTextFormat->Get(),
&D2D1::Rect(rect.left, rect.top, rect.right, rect.bottom),
m_pBlackBrush->Get());

当然,我们也可以直接改工程编码方式为Unicode编码,这样也不会出现乱码(简单粗暴,哈哈),只是有些工程出于种种原因只能用多字节编码方式,这样就可以使用上面的方法了。

搞定!

记CRenderTarget:DrawText()绘制中文乱码的BUG及解决办法的更多相关文章

  1. mysql保存中文乱码的原因和解决办法

    当你遇到这个mysql保存中文乱码问题的时候,期待找到mysql保存中文乱码的原因和解决办法这样一篇能解决问题的文章是多么激动人心.    也许30%的程序员会选择自己百度,结果发现网友已经贴了很多类 ...

  2. php中文乱码问题分析及解决办法

    中文乱码问题产生的原因,主要就是字符编码设置问题:             首先,mysql数据库安装的时候字符编码要选择正确,最好选择utf-8比较保险.如果安装时没有设置正确,找到mysql的安装 ...

  3. android studio中文乱码各种情况的解决办法

    情况一:编辑器内的中文注释乱码. 解决办法:在界面的右下角找到 UTF-8 ,单击之,在弹出的列表中选中GBK 在弹出框内选中Reload 总结:导致这样的原因是你这个.java文件本身是GBK编码的 ...

  4. plsql中文乱码显示问号的解决办法

    问题现象:  PLSQL执行sql语句,不识别中文,输出的中文标题显示成问号????. 解决办法: 1. 登陆plsql,执行sql语句,输出的中文标题显示成问号????:条件包含中文,则无数据输出: ...

  5. php substr中文乱码最有效到解决办法 转:http://blog.sina.com.cn/s/blog_49b531af0100esah.html

    (2009-07-29 12:29:38) 转载▼ 标签: php substr文乱码 网站开发 it   直接使用PHP函数substr截取中文字符可能会出现乱码,主要是substr可能硬生生的将一 ...

  6. 使用myeclipse出现中文乱码的情况以及解决办法

    一:在jsp页面使用中文在浏览器中显示的时候出现乱码,解决问题的办法: 1)直接在<mete>标签中修改charset属性为"utf-8"或者为"gb2312 ...

  7. 关于使用Ajax请求json数据,@RequestMapping返回中文乱码的几种解决办法

    一.问题描述: 使用ajax请求json数据的时候,无论如何返回的响应编码都是ISO-8859-1类型,因为统一都是utf-8编码,导致出现返回结果中文乱码情况. $.ajax({ type:&quo ...

  8. NetBeans 打开项目中文乱码最简单的解决办法

    网上各种修改配置文件,中文乱码还是没有解决,其实不是NetBeans的问题,是编辑器设置的字符集不支持中文,最简单的办法:!!! 设置新字体即可 !!!

  9. asp.net中URL参数传值中文乱码的三种解决办法

    在做Asp.Net开发的时候,参数传递中文时,经常会遇到页面乱码的问题,下面是在网上收集的相关资料,请大家参考: 解决的方法一般有3种: 1.设置web.config文件 <system.web ...

随机推荐

  1. elasticsearch 中文API 更新(五)

    更新API 你能够创建一个UpdateRequest,然后将其发送给client. UpdateRequest updateRequest = new UpdateRequest(); updateR ...

  2. 中国 SaaS 企业如何突围?这几点是关键!

    进入2019年,关于SaaS的各种言论甚嚣尘上,有人看好:“SaaS市场得大客户者得天下”,也有人唱衰:“SaaS已死,下一个”.在众说纷纭中,中国SaaS企业的成功之路迷雾重重,前期走的较早的头部S ...

  3. 深入浅出 Java Concurrency (16): 并发容器 part 1 ConcurrentMap (1)[转]

    从这一节开始正式进入并发容器的部分,来看看JDK 6带来了哪些并发容器. 在JDK 1.4以下只有Vector和Hashtable是线程安全的集合(也称并发容器,Collections.synchro ...

  4. 深入浅出 Java Concurrency (12): 锁机制 part 7 信号量(Semaphore)[转]

    Semaphore 是一个计数信号量.从概念上讲,信号量维护了一个许可集.如有必要,在许可可用前会阻塞每一个 acquire(),然后再获取该许可.每个 release() 添加一个许可,从而可能释放 ...

  5. 深入浅出 Java Concurrency (7): 锁机制 part 2 AQS[转]

    在理解J.U.C原理以及锁机制之前,我们来介绍J.U.C框架最核心也是最复杂的一个基础类:java.util.concurrent.locks.AbstractQueuedSynchronizer. ...

  6. Tool-MySQL-SQLyog:SQLyog

    ylbtech-Tool-MySQL-SQLyog:SQLyog SQLyog 是一个快速而简洁的图形化管理MYSQL数据库的工具,它能够在任何地点有效地管理你的数据库,由业界著名的Webyog公司出 ...

  7. PhoneInfoga---用于电话号码的信息收集和OSINT侦察工具

    PhoneInfoga 是仅使用免费资源扫描电话号码的最先进工具之一. 目标是首先在任何国际电话号码上收集标准信息, 如国家,地区,运营商和线路类型,并且准确性非常高. 然后在搜索引擎上搜索足迹以尝试 ...

  8. Spring cloud properties与yml配置说明

    encrypt说明 名称 默 认 描述 encrypt.fail-on-error true 标记说,如果存在加密或解密错误,进程将失败. encrypt.key 对称密钥.作为一个更强大的替代方案, ...

  9. 【vue】openshopping-vue

    这是一个基于Vue实现开箱即用H5移动端商城的单页应用 作者的开源地址是:https://github.com/yrinleung/openshopping-vue 我们一起来欣赏页面吧 看看代码有什 ...

  10. webpack打包js,css和图片

    1.webpack打包默认配置文件webpack.config.js 2.打包js文件:有这个文件并配置可以直接在cmd上webpack打包,没有这个文件要在cmd上输入 webpack main.j ...