MFC第五天 Unicode软件开发 MFC框架构成与封装类原理

news2024/12/23 1:54:42

文章目录

  • Unicode软件开发
    • 以Unicode为字符集的记事本软件开发
  • MFC框架构成与封装类原理
    • 示例代码如下:

Unicode软件开发

Unicode软件开发时需要遵循以下规则:使用中可尽量使用自适应版本。

 Unicode软件开发:
a)微软的软件工程现在默认使用Unicode(UTF16位小端),尤其是Windows图形化软件工程。
b)Unicode软件工程下,常量的定义使用L"xxxx",ANSI使用“XXX”;
c)微软的跟字符串打交道的API都会定义两套:例如:
#ifdef UNICODE
#define SetDlgItemText  SetDlgItemTextW
#else
#define SetDlgItemText  SetDlgItemTextA
#endif // !UNICODE
d)C语言库函数跟字符串打交道的,全部重写Unicode版本。
比如:
char *strcat(
   char *strDestination,
   const char *strSource 
);
wchar_t *wcscat(
   wchar_t *strDestination,
   const wchar_t *strSource 
);

TCHAR类型:

a)窄字符串:typedef const char* LPCSTR; 
b)宽字符串:typedef const wchar_t* LPCWSTR; 
c)自适应字符串:typedef TCHAR* LPCTSTR;

#ifdef  UNICODE                     // r_winnt
typedef wchar_t TCHAR;
typedef const wchar_t* LPCTSTR;
#else
typedef char TCHAR;
typedef const char* LPCTSTR;
#endif

以Unicode为字符集的记事本软件开发

主函数Main.cpp 主要是把ANSI和UTF8编码转换成为Unicode16

#define  _CRT_SECURE_NO_WARNINGS
#include<windows.h>
#include"resource.h"
#include<stdio.h>

void ConvertBig(LPSTR p);
bool CheckUtf8(LPCSTR p);
wchar_t* ANSIToUnicode(const char* str);
wchar_t* UTF8ToUnicode(const char* str);

void ParseText(HWND hwndDlg, LPSTR p)
{
	wchar_t* q = nullptr;
	switch (*(WORD*)p)
	{
	case 0xFFFE:  //BE 大端   大端与小端之间完全颠倒 每个字节之间完全的进行反转 翻转以后就说小端的代码 
		ConvertBig(p);
	case 0xFEFF:	//LE 小端
		SetDlgItemText(hwndDlg, IDC_TEXT, (LPCTSTR)p+2);
		delete[] q;
		return;
	case 0xBBEF: //UTF8 BOM
		if (p[2] == (char)0xBF)
		{
			q = UTF8ToUnicode(p + 3);
			SetDlgItemText(hwndDlg, IDC_TEXT, q);
			delete[] q;
			return;
		}
		return;
	}
	if (CheckUtf8(p))
	{
		q = UTF8ToUnicode(p);
		SetDlgItemText(hwndDlg, IDC_TEXT, q);
		delete[] q;
	}
	else
	{
		q = ANSIToUnicode(p);
		SetDlgItemText(hwndDlg, IDC_TEXT, q);
		delete[] q;
	}
		
}
int GetFileSize(FILE* pf)
{
	long m = ftell(pf);
	fseek(pf, 0, SEEK_END);
	long n = ftell(pf);
	fseek(pf, m, SEEK_SET);
	return n;
}
void ReadTextFile(HWND hwndDlg, LPCTSTR sFile)
{
	FILE* pf = _wfopen(sFile, L"rb");
	if (!pf)
		return;
	int nSize = GetFileSize(pf);
	if (nSize > 0)
	{
		char* p = new char[nSize + 2];
		auto n = fread(p, 1, nSize, pf);
		p[n] = 0;
		p[n + 1] = 0;
		ParseText(hwndDlg, p);
		//	SetDlgItemText(hwndDlg, IDC_TEXT, p);
		delete[] p;
	}
	fclose(pf);
}

void onDropFile(HWND hwndDlg, HDROP hDrop)
{
	TCHAR s[MAX_PATH];
	int nCount = DragQueryFile(hDrop, 0, s, _countof(s));  //取第一个文件名 如果要去最后一个,先求出总数再ncount-1

	//SetDlgItemText(hwndDlg, IDC_TEXT, s);
	ReadTextFile(hwndDlg, s);
	DragFinish(hDrop);
} 

INT_PTR CALLBACK theProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg)
	{
	case WM_DROPFILES:
		onDropFile(hwndDlg, (HDROP)wParam);
		break;
	case WM_COMMAND:
	{
		switch (LOWORD(wParam))
		{
		case IDCANCEL:
			EndDialog(hwndDlg, 88);
			break;
		}
	}
	}
	return 0;
}
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
	UINT_PTR n = DialogBox(hInstance, (LPCWSTR)IDD_MAIN_DLG, NULL, theProc);
	return 0;
}

codec.cpp编码格式转换
需要了解utf8编码规则

UTF-8编码规则如下:
如果字符的Unicode码值范围是U+0000至U+007F(即0~127),则使用一个字节表示,最高位为0。
如果字符的Unicode码值范围是U+0080至U+07FF(即128~2047),则使用两个字节表示,最高位为110,第二高位为10。
如果字符的Unicode码值范围是U+0800至U+FFFF(即2048~65535),则使用三个字节表示,最高位为1110,第二高位为10,第三高位为10。
如果字符的Unicode码值范围是U+10000至U+10FFFF(即65536~1114111),则使用四个字节表示,最高位为11110,第二高位为10,第三高位为10,第四高位为10

#include<windows.h>
bool CheckUtf8(LPCSTR p) //检查是否为utf8不带bom头格式
{
    auto q = p;
    while (*p)
    {
        BYTE c = *p;
        BYTE x = 0x80;
        int n = 0;
        while ((c & x) == x)
            ++n, x >>= 1;
        if (n == 1 || n > 4)
            return false;
        ++p;
        while (--n>0)
        {
            c = *p++;
            if (c >> 6 != 2) //00000010 把这个数直接左移6位 看他的高位是不是10
                return false;
        }
    }
    return true;
}
void ConvertBig(LPSTR p)
{
    while (*(WORD*)p) //双字节的0结尾结束
    {
      /*  CHAR c = *p;
        *p = p[1];
        p[1] = c;*/

        *p = *p ^ p[1];     //没有中间变量的   反转
        p[1] = *p ^ p[1];
        *p = *p ^ p[1];
        p += 2;
    }
}

char* UnicodeToANSI(const wchar_t* str)
{
    int n = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL); //第一次求长度   带L是Unicode的格式
    auto p = new char[n + 1];
    n =  WideCharToMultiByte(CP_ACP, 0, str, -1, p, n, NULL, NULL); //第二次填充 p, n 你申请的空间,边界限制
    p[n] = 0; //结尾
    return p;
} //算出长度 申请空间 填充长度

wchar_t* ANSIToUnicode(const char* str)
{
    wchar_t n = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
    auto p = new wchar_t[n + 1];
    MultiByteToWideChar(CP_ACP, 0, str, -1, p, n);
    return p;
}

wchar_t* UTF8ToUnicode(const char* str)
{
    int n = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
    auto p = new wchar_t[n + 1];
    n = MultiByteToWideChar(CP_UTF8, 0, str, -1,p, n);
    p[n] = 0;
    return p;
}
char* UTF8ToANSI(const char* str)
{
    auto p = UTF8ToUnicode(str);
    auto q= UnicodeToANSI(p);
    delete[] p;
    return q;
}

针对void ConvertBig(LPSTR p)函数相应释义
在这里插入图片描述


MFC框架构成与封装类原理

1、MFC框架构建:
要使用MFC静态链接库,链接器中要选择 窗口 (/SUBSYSTEM:WINDOWS)
a)必须派生CWinApp类
b)并且重写虚函数InitInstance,作为MFC的框架入口函数。
c)必须在全局区申请一个派生类对象。
在这里插入图片描述
在这里插入图片描述
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4fVZs6xv-1687351587792)(null)]

2、如何在MFC窗口中接收消息呢?
a)所有MFC的窗口都对应一个系统的派生类,包括:对话框类、控件类,框架和视图等等;
b)消息的接收必须在派生类内,使用消息映射机制实现。
c)消息机制就是MFC内部管理消息循环,在窗口派生类中建立消息与成员函数的关联;
d)MFC类向导第一页是控件编号,选择不同控件对应不同的消息;
e)MFC类向导第二页是主窗口消息,包括WM_MOUSEMOVE,WM_DROPFILES等。
在这里插入图片描述
消息映射机制
在这里插入图片描述

3、MFC的窗口类库封装:
a)所有的窗口类(包括:对话框类、控件类,框架和视图等等)都由CWnd类同一的窗口基类派生。
b)CWnd类内部有核心成员变量HWND m_hWnd,就如同CSocket类内部有核心成员SOCKET m_hSocket;
c)CWnd类几乎封装所有跟HWND打交道的API,

例如:
void CWnd::SetWindowText(LPCTSTR lpszString)
{
   SetWindowText(m_hWnd, lpszString);
}

void CWnd::MoveWindow(int x, int y, int nWidth, int nHeight, BOOL bRepaint)
{
	ASSERT(::IsWindow(m_hWnd) );
	MoveWindow(m_hWnd, x, y, nWidth, nHeight, bRepaint);
}

示例代码如下:

CApp.h

#pragma once
#include<afxwin.h>
#include "CMainDlg.h"
class CApp :public CWinApp
{
	BOOL InitInstance()
	{
		CMainDlg dlg;
		dlg.DoModal();
		return 0;
	}
};

CApp.cpp

#include "CApp.h"
CApp theApp;

CMainDlg.h

#pragma once
#include "afxdialogex.h"


// CMainDlg 对话框

class CMainDlg : public CDialogEx
{
	DECLARE_DYNAMIC(CMainDlg)
public:
	CMainDlg(CWnd* pParent = nullptr);   // 标准构造函数
	virtual ~CMainDlg();
// 对话框数据
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_MAIN_DLG };
#endif

protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

	DECLARE_MESSAGE_MAP()
public:
	afx_msg void OnMouseMove(UINT nFlags, CPoint point);
	afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
	afx_msg void OnClickedAdd();
};

CMainDlg.cpp

// CMainDlg.cpp: 实现文件
#include "afxdialogex.h"
#include "CMainDlg.h"
#include "resource.h"
// CMainDlg 对话框
IMPLEMENT_DYNAMIC(CMainDlg, CDialogEx)

CMainDlg::CMainDlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_MAIN_DLG, pParent)
{

}

CMainDlg::~CMainDlg()
{
}

void CMainDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}


BEGIN_MESSAGE_MAP(CMainDlg, CDialogEx)  //消息映射机制 管理所有消息的连接桥
	ON_WM_MOUSEMOVE()
	ON_WM_LBUTTONDOWN()
	ON_BN_CLICKED(IDC_ADD, &CMainDlg::OnClickedAdd)
END_MESSAGE_MAP()

// CMainDlg 消息处理程序

void CMainDlg::OnMouseMove(UINT nFlags, CPoint point)
{
	CString str;
	str.Format(L"x=%d,y=%d", point.x, point.y);
	SetWindowText(str);
	if (MK_LBUTTON &nFlags)
	{
		str += "左键按下";
	}
	if (MK_RBUTTON & nFlags)
	{
		str += "右键按下";
	}
	if (MK_SHIFT & nFlags)
	{
		str += "SHIFT键按下";
	}
	SetWindowText(str);
	CDialogEx::OnMouseMove(nFlags, point);
}

void CMainDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
	CString str;
	str.Format(L"x=%d,y=%d", point.x, point.y);
//	MessageBox(str, L"点击");
	CDialogEx::OnLButtonDown(nFlags, point);
}

void CMainDlg::OnClickedAdd()
{
	CString str;
	GetDlgItemText(IDC_LEFT, str);
	double fLeft=_tstof(str);

	GetDlgItemText(IDC_RIGHT, str);
	double fRight = _tstof(str);

	double fResult = fLeft + fRight;
	str.Format(L"%g", fResult);
	SetDlgItemText(IDC_RESULT, str);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/671901.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【MYSQL篇】mysql中相关锁和MVCC详解

文章目录 前言MVCC1、第一个事务2、第二个事务3、第三个事务4、第四个事务5、第五个事务 InnoDB 常见的几种锁机制共享锁排它锁意向锁记录锁间隙锁临键锁 小结 前言 数据库的锁是在多线程高并发的情况下用来保证数据稳定性和一致性的一种机制。MySQL 根据底层存储引擎的不同&a…

OpenGL

需要继承的两个类 #include <QOpenGLWidget> #include <QOpenGLFunctions_3_3_Core> class OpenGLWidget : public QOpenGLWidget,public QOpenGLFunctions_3_3_Core { Q_OBJECT public: explicit OpenGLWidget(QWidget *parent nullptr); virtual vo…

如何看待调查称半数年轻人存款不足10万?

文章目录 一、目前的存款在哪一个区间&#xff1f;你觉得存款难吗&#xff1f;2.1 自己的状态2.2 对理财的看法和态度 二、谈谈我为存款做出过哪些努力&#xff1f;三、除了个人因素外&#xff0c;有哪些因素影响到了年轻人的存款能力和存款意愿&#xff1f;四、要攒够多少存款…

【数据库原理与实践】CS系的实验期末考题(20222023)

2022&#xff1a; 学校管理数据库涉及四个关联表结构&#xff1a; 学生表 Student(Sno,Sname,Sdate,Ssex) &#xff0c;其中Sno学生编号&#xff0c;Sname学生姓名&#xff0c;Sdate出生年月&#xff0c;Ssex学生性别 。 课程表 Course(Cno,Cname,Tno) &#xff0c;其中Cno课…

(写自己语言的练手级应用)JSON(JavaScript Object Notation) 产生式(BNF)

写自己的开发语言时&#xff0c;很多人都会拿JSON当第一个练习对象 开源net json FJSON 解析工具https://dbrwe.blog.csdn.net/article/details/107611540?spm1001.2014.3001.5502 <json> :: <object> | <array> <object> :: "{" [ <me…

【OJ比赛日历】快周末了,不来一场比赛吗? #06.23-06.29 #13场

CompHub[1] 实时聚合多平台的数据类(Kaggle、天池…)和OJ类(Leetcode、牛客…&#xff09;比赛。本账号会推送最新的比赛消息&#xff0c;欢迎关注&#xff01; 以下信息仅供参考&#xff0c;以比赛官网为准 目录 2023-06-23&#xff08;周五&#xff09; #5场比赛2023-06-24…

k8s中如何修改pod中mysql的连接数

(方法一) 临时更改设置最大连接数据&#xff08;建议先临时修改&#xff0c;项目没有问题之后再进行永久修改&#xff09; 使用Navicat连接上数据库&#xff0c;点击连接名——点击新建查询—— 查看最大连接数 show variables like ‘’%max_connections%‘’; 查看当前用户使…

vue中注册组件的两种方式(全局注册 局部注册)

vue 是一个完全支持组件化开发的框架&#xff0c; 组件之间可以进行相互的引用。vue 中组件的引用原则&#xff1a;先注册后使用。 1. 组件的注册 组件之间可以进行相互的引用&#xff0c;例如&#xff1a; 注册组件的的方式&#xff1a;分为“全局注册”和“局部注册”两种…

Git Bash 上传本地文件到Gitee(AI助力解决问题)

前言 消失了将近一个月&#xff0c;预祝大家端午节快乐&#xff01; 这篇文章主要介绍下在上传本地项目到gitee时出现的问题&#xff0c;以及借助AI解决问题。 Gitee是一个基于 Git 的代码托管和开发协作平台&#xff0c;它提供了代码仓库、代码审查、持续集成/持续部署 (CI/C…

开关电源——DCDC变换器设计

开关电源——DCDC变换器设计 对于DCDC变换器来说&#xff0c;最重要的部分也是唯一一个磁学元件——电感需要考虑。 直流传递函数 正如之前我们所说&#xff0c;电感电流在开关导通的时候增加的电流必须等于在开关关断时候的减少的电流&#xff0c;即在一个工作周期中不积累…

支付宝性能测试案例分析

双11过程当中&#xff0c;促销开启的第一分钟内支付宝的交易总额就突破了一亿元&#xff0c;短时间内大量用户涌入的情况下&#xff0c;如何保证用户的支付顺畅&#xff0c;是对支付宝应用系统的一个极大的挑战。 一、性能测试支付宝场景介绍 双11过程当中&#xff0c;促销开启…

企业级ChatGPT开发的三大核心内幕及案例实战(三)

企业级ChatGPT开发的三大核心内幕及案例实战(三) 2.3 Notion 问答对话AI案例演示及源码分析 Gavin老师:NLP_Matrix_Space 如图2-2所示,我们先看一下Notion 问答对话AI案例的效果。你问一个问题,它会进行回答,然后它会告诉你,信息来源在什么地方,要看具体的信息,可以…

ICLR 2023 | RevCol:给神经网络架构增加了一个维度!大模型架构设计新范式

点击蓝字 关注我们 关注并星标 从此不迷路 计算机视觉研究院 公众号ID&#xff5c;计算机视觉研究院 学习群&#xff5c;扫码在主页获取加入方式 论文地址&#xff1a;https://arxiv.org/pdf/2212.11696.pdf 项目代码&#xff1a;https://github.com/megvii-research/RevCol 计…

MySQL进阶SQL语句

目录 1.select&#xff08;显示表格中一个或数个字段的所有数据记录&#xff09; 2.distinct&#xff08;不显示重复的数据记录&#xff09; 3.where&#xff08;有条件查询&#xff09; 4.and 、or&#xff08;且、或&#xff09; 5. in&#xff08;显示已知的值的数据记…

Goby 漏洞发布|Weaver OA PluginViewServlet Authentication Bypass Vulnerability

漏洞名称&#xff1a;泛微OA办公系统 PluginViewServlet 认证绕过漏洞 English Name&#xff1a;Weaver OA PluginViewServlet Authentication Bypass Vulnerability CVSS core: 8.0 影响资产数&#xff1a;45034 漏洞描述&#xff1a; 泛微OA 是一款专业强大的多功能办公…

直播回顾:HVV经验分享与重保整体解决方案

6月15日&#xff0c;Coremail联合北京钛星数安科技有限公司举办【HVV经验分享与重保整体解决方案发布】直播分享会。 直播会上Coremail安全团队和钛星数安的刘平平老师为大家带来重保时期的防御实战经验&#xff0c;帮助企业充分做好重保的安全准备工作&#xff0c;安稳度过重保…

uniapp中如何给下拉框动态绑值

前言&#xff1a; 在项目中我们会经常遇到新增的功能&#xff0c;而新增的页面中就会有输入框、下拉框、文本域、日期选择框等等。那么在uniapp是如何给下拉框中调用接口动态绑值的呢&#xff1f;请往下看 &#x1f4a8; &#x1f497; uView官网&#xff1a;介绍 | uView 2.0…

kettle开发-Day39-超好用AI+算力组合-算力提升器

前言&#xff1a; 上一节我们提到采用标记新旧数据的数据状态来快速整理需对比的数据&#xff0c;再选择性插入更新来保证数据的完整性。强强联合&#xff0c;保证了数据的高效和可用。 但是日常中&#xff0c;也存在部分场景&#xff0c;我们表输入是没有唯一性主键的&#xf…

计算机服务器数据库中了Devos后缀勒索病毒怎么办,记住以下步骤!

近期&#xff0c;我接到许多企业的求助&#xff0c;企业的用友财务软件遭受了Devos后缀勒索病毒的攻击&#xff0c;导致企业的用友财务账套被加密&#xff0c;许多重要的数据都无法正常读取&#xff0c;给公司的正常运营和数据安全带来了严重威胁。一旦企业被devos勒索病毒攻击…