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
主函数Main.cpp 主要是把ANSI和UTF8编码转换成为Unicode16
#define _CRT_SECURE_NO_WARNINGS
#include
#include"resource.h"
#include
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
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)函数相应释义
1、MFC框架构建:
要使用MFC静态链接库,链接器中要选择 窗口 (/SUBSYSTEM:WINDOWS)
a)必须派生CWinApp类
b)并且重写虚函数InitInstance,作为MFC的框架入口函数。
c)必须在全局区申请一个派生类对象。
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
#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);
}