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

文章目录

  • 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);
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot 实现 PDF 添加水印有哪些方案?

简介 PDF&#xff08;Portable Document Format&#xff0c;便携式文档格式&#xff09;是一种流行的文件格式&#xff0c;它可以在多个操作系统和应用程序中进行查看和打印。在某些情况下&#xff0c;我们需要对 PDF 文件添加水印&#xff0c;以使其更具有辨识度或者保护其版…

前端项目工程化搭建

ESLint 在开发过程中&#xff0c;需要遵循一些规范&#xff0c;可以使用下面的工具来配置不同项目需要遵循的规范&#xff0c;来帮助我们检查错误、约束开发过程。 ESLint 配置 使用 Taro CLI 创建的项目&#xff0c;会自动生成 .eslintrc 文件。只需要在这个文件的 rules 配…

Android逆向解析加壳与脱壳技术

加壳 加壳是指在 APK 文件中插入额外的代码或数据&#xff0c;使得原始代码难以被分析和反编译。通常加壳是为了保护软件的知识产权或者防止逆向工程。下面是 Android 加壳的一般流程&#xff1a; 选择加壳工具&#xff1a;选择合适的加壳工具进行加壳&#xff0c;比如市面上…

K8S:二进制安装K8S(单台master)安装etcd和master

系列文章目录 文章目录 系列文章目录一、安装K8S1.系统初始化配置2.部署docker引擎3.部署etcd集群 二、1.2. 总结 一、安装K8S 1.系统初始化配置 注意&#xff1a;该操作在所有node节点上进行&#xff0c;为k8s集群提供适合的初始化部署环境 #所有节点执行 systemctl stop f…

POJ - 2287 Tian Ji -- The Horse Racing

题目来源 2287 -- Tian Ji -- The Horse Racing (poj.org) 题目描述 田忌赛马是中国历史上一个著名的故事。 这个故事发生在2300年前&#xff0c;田忌是齐国的一个大官&#xff0c;他喜欢和齐王以及其他公子赛马。 田忌和齐王都有三类马&#xff0c;分别是下等马&#xff0…

【Vue】学习笔记-创建Vue3.0工程

创建Vue3.0工程 使用vue-cli创建查看vue/cli版本&#xff0c;确保vue/cli版本在4.5.0以上安装或者升级你的vue/cli创建启动 使用vite创建创建工程进入工程目录安装依赖运行 使用vue-cli创建 官方文档&#xff1a;https://cli.vuejs.org/zh/guide/creating-a-project.html#vue-…

BioXFinder生物数据库

BioXFinder是目前国内第一个也是国内唯一一个生物信息数据库&#xff0c;由享融智云公司精心研发&#xff0c;主要针对生物科研工作者的综合性生物数据检索及分析平台&#xff0c;汇集了核酸、蛋白、蛋白结构、代谢通路和信号通路信息&#xff0c;解决海外数据访问难、访问慢的…

【新星计划·2023】Linux是什么?它与Windows有什么区别?

作者&#xff1a;Insist-- 个人主页&#xff1a;insist--个人主页 作者会持续更新网络知识和python基础知识&#xff0c;期待你的关注 目录 一、Linux是什么&#xff1f; 二、Linux的应用领域 1、服务器领域 2、嵌入式领域 3、虚拟化 三、Linux的未来 1、云计算 2、大数…

玩转ChatGPT:回答审稿人问题

一、写在前面 前段时间一篇时间序列预测的文章返修&#xff0c;还挺幸运的&#xff0c;给了个小修。 不过问题也问得有点刁钻&#xff0c;应该是个行家。 想到手头有小Chat&#xff0c;打算使用TA来辅助我回答审稿人问题。 以下展示仅仅提供一个工作流和思路&#xff0c;具体…

高级SQL语句

目录 MySQL 高级(进阶) SQL 语句函数数学函数&#xff1a;聚合函数字符串函数&#xff1a; 连接查询inner join(内连接)&#xff1a;left join(左连接)&#xff1a;right join(右连接)&#xff1a; CREATE VIEW&#xff08;视图&#xff09;UNION&#xff08;联集&#xff09;C…

OpenAI ChatGPT 使用示例(程序员)

作为一个程序员&#xff0c;当知道ChatGPT出来之后或者GPT3出来的时候&#xff0c;我是有喜有忧&#xff0c;喜的是它可以帮我写代码&#xff0c;重构代码&#xff0c;写注释&#xff0c;写测试&#xff0c;&#xff0c;。哇&#xff0c;听起来好刺激&#xff0c;我可以从此以后…

探索安卓内容提供者:构建、访问和管理数据【复习】

文章目录 一 ContentProvider1.1 数据模型- **ContentProvider 使用基于数据库模型的简单表格来提供需要共享的数据**&#xff0c;在该表格中&#xff0c;每一表示一条记录&#xff0c;而每一列代表特定类型和含义的数据&#xff0c;并且其中每一条数据记录都包含一个名为“_ID…

数字图像处理 基于matlab、opencv计算图像的梯度方向和梯度幅值

一、图像的梯度 1、简述 图像可以被视为标量场(即二维函数)。 通过微分将标量场转换为矢量场。 梯度是一个向量,描述了在x或y方向上移动时,图像变化的速度。我们使用导数来回答这样的问题,图像梯度的大小告诉图像变化的速度,而梯度的方向告诉图像变化最…

【C++学习】C++入门 | 引用 | 引用的底层原理 | auto关键字 | 范围for(语法糖)

写在前面&#xff1a; 上一篇文章我介绍了缺省参数和函数重载&#xff0c; 探究了C为什么能够支持函数重载而C语言不能&#xff0c; 这里是传送门&#xff0c;有兴趣可以去看看&#xff1a;http://t.csdn.cn/29ycJ 这篇我们继续来学习C的基础知识。 目录 写在前面&#x…

图像金字塔

​ 图像金字塔是由一幅图像的多个不同分辨率的子图构成的图像集合。是通过一个图像不断的降低采样率产生的&#xff0c;最小的图像可能仅仅有一个像素点。下图是一个图像金子塔的示例。从图中可以看到&#xff0c;图像金字塔是一系列以金字塔形状排列的、自底向上分辨率逐渐降低…

【数字图像处理】3.对比度增强

目录 3.1 灰度直方图 3.2 线性变换 3.3 直方图正规化 3.4 伽马变换 3.5 全局直方图均衡化 3.6 CLAHE 对比度增强是图像增强的一种&#xff0c;它主要解决的是图像的灰度级范围较小造成的对比度较低的问题&#xff0c;目的是将图像的灰度级增强到指定范围&#xff0c;使得…

实战:用docker-compose容器化springboot项目

文章目录 前言技术积累docker-compose定义docker-compose文件参数docker-compose命令 实战演示1、创建挂载路径2、编写docker-compose.yml3、启动并管理容器 写在最后 前言 前面我们学习和实战了用dockerfile构建镜像&#xff0c;通过镜像可以任意在docker环境容器化部署项目。…

Opencv-C++笔记 (7) : opencv-文件操作XML和YMAL文件

文章目录 一、概述二、文件操作三、打开文件四、写入五、读写个人源码 一、概述 除了图像数据之外&#xff0c;有时程序中的尺寸较小的Mat类矩阵、字符串、数组等 数据也需要进行保存&#xff0c;这些数据通常保存成XML文件或者YAML文件。本小节中将介绍如何利用OpenCV 4中的函…

神经网络:卷积操作

当谈到计算机视觉中的网络模型结构时&#xff0c;卷积操作是其中一个关键的组成部分。卷积操作是一种基于局部区域的操作&#xff0c;它在计算机视觉中用于图像处理和特征提取。 卷积操作的原理如下&#xff1a; 给定一个输入图像和一个称为卷积核&#xff08;或滤波器&#x…

【ARIMA-SSA-LSTM】合差分自回归移动平均方法-麻雀优化-长短期记忆神经网络研究(Python代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…