字符编码
字符编码方式
- 字符编码从上个世纪到现在出现了大致
4
种编码:
ASC
编码:7
位二进制代表一个字符串,这128位字符包含了字母
、数字
以及一些符号。
ASCII
编码:为了在欧洲推广计算机,所以又出现了ASCII
编码,8
位代表一个字符。并且前128
个与前面的ASC
编码一样。出现了一个代码页ID
,根据代码页ID
的不同将后面的128
个字符换成对应国家的文字
DBCS
编码:主要是适配亚洲
的文字编码,单双字节混合编码,英文字母按照1
字节编码,象形文字等按照2
字节编码
UNICODE
编码:被称为万国码,基本上把全世界所有语言都收录了。
- 这里主要详细说明
DBCS
和UNICODE
编码,其中UNICODE
有UTF-8
、UTF-16
、UTF-32
,如果在Windows
下一般是UTF-16
,而在Linux
下一般是UTF-8
:

宽字节字符
在windows
编程中有一个新的数据类型,该类型为宽字节字符
,关键字为wchar_t
每个字符占2
个字节
char
:每个字符占1个字节
wchar_t
:实际是unsigned short
类型,定义时,需要增加L
,通知编译器按照双字节编译字符串,采用UNICODE
编码。(无论是英文字母还是汉字都是占用两个字节)
需要使用支持wchar_t
函数操作宽字节字符串。例如:
1 2 3
| wchar_t* pwszText = L"Hello wchar"; wprintf(L"%s\n",pwszText);
|
TCHAR宏定义
- 由于宽字节字符和正常的字节字符有的时候会混淆,所以为了统一微软做了一个
TCHAR
的宏定义,该宏定义如下:
1 2 3 4 5 6 7 8 9 10
|
#ifdef UNICODE typedef wchar_t TCHAR; #define __TEXT(quote) L## quote #else typedef char TCHAR; #define __TEXT(quote) quote #endif
|
UNICODE字符打印
wprintf
对UNICODE
字符打印支持不完善,在Windows
下使用WriteConsole API
打印UNICODE
字符GetStdHandle
1 2 3 4 5 6 7 8 9 10 11 12 13
| #include<Windows.h> #include<stdio.h>
void PrintUnicode() { const wchar_t* pszText = L"阿斯代理商打马赛克代码卢萨卡代码"; wprintf(L"%s\n", pszText); } int main() {
PrintUnicode(); return 0; }
|

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| #include<Windows.h> #include<stdio.h> void PrintUnicode() { const wchar_t* pszText = L"阿斯代理商打马赛克代码卢萨卡代码"; HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); WriteConsole(hOut,pszText,wcslen(pszText),NULL,NULL);
} int main() { PrintUnicode(); return 0; }
|
出现如下乱码的原因是选用多字节字符,如果使用默认的UTF
就能正确输出。

例子
- 现在约定一下创建一个新项目的基本步骤,先创建一个新的项目,然后将其设置为启动项


如果是设置为Unicode
编译器会默认有Unicode
宏定义,如果使用多字节字符集编译器就不会默认Unicode
宏定义,这主要是因为Window是有大量的系统调用函数的参数是TCHAR*
、const TCHAR*
类型。

1 2 3 4 5 6 7 8 9 10 11 12 13
| #include<Windows.h> #include<stdio.h> void C_char() { char* pszText = "hello char"; printf("%s\n", pszText); } int main() { C_char(); getchar(); return 0; }
|

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| #include<Windows.h> #include<stdio.h> void C_char() { const char* pszText = "hello char"; printf("%s\n", pszText); }
void W_char() { const wchar_t* pszText = L"hello wchar"; int len = wcslen(pszText); wprintf(L"%s %d\n", pszText, len); }
int main() { W_char(); getchar(); return 0; }
|

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| #include<Windows.h> #include<stdio.h>
void C_char() { const char* pszText = "hello char"; printf("%s\n", pszText); }
void W_char() { const wchar_t* pszText = L"hello wchar"; int len = wcslen(pszText); wprintf(L"%s %d\n", pszText, len); }
void T_char() { const TCHAR * pszText = __TEXT("hello txt"); #ifdef UNICODE wprintf(L"%s\n", pszText); #else printf("单:%s\n", pszText); #endif } int main() { T_char(); getchar(); return 0; }
|

Windows窗口程序
- 接下来手敲一个Windows窗口程序,完全了解一下Windows窗口程序的创建过程。
- 总体概括一下Window窗口程序的创建过程(这个过程会接触到一些比较陌生的名词,之后会详细的说明):
- 定义WinMain函数
- 定义窗口处理函数(自定义,处理消息)
- 注册窗口类(向操作系统写入一些数据)
- 创建窗口(内存中创建窗口)
- 显示窗口(绘制窗口的图像)
- 消息循环(获取/翻译/派发消息)
- 消息处理
简单创建一个Windows程序
1 2 3 4 5 6
| #include<windows.h>
int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns, LPSTR IpCmdLine, int nCmdShow) { return 0; }
|
1 2 3 4 5 6 7 8 9 10 11
| #include<windows.h>
LRESULT CALLBACK WndProce(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM IParam) { return DefWindowProc(hWnd, msgID, wParam, IParam); }
int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns, LPSTR IpCmdLine, int nCmdShow) { return 0; }
|
- 接下来就是在
WinMain
函数中注册一个窗口,也就是填写一些关于窗口的数据,并将数据写入到内核里面去。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| #include<windows.h>
LRESULT CALLBACK WndProce(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM IParam) { return DefWindowProc(hWnd, msgID, wParam, IParam); }
int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns, LPSTR IpCmdLine, int nCmdShow) { WNDCLASS wc = { 0 }; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 3); wc.hCursor = NULL; wc.hIcon = NULL; wc.hInstance = hIns; wc.lpfnWndProc = WndProce; wc.lpszClassName = "Main"; wc.lpszMenuName = NULL; wc.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wc); return 0 }
|
- 接下来就是在内存创建窗口,也就是申请一块内存,将窗口的数据放到里面。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| #include<windows.h>
LRESULT CALLBACK WndProce(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM IParam) { return DefWindowProc(hWnd, msgID, wParam, IParam); }
int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns, LPSTR IpCmdLine, int nCmdShow) { WNDCLASS wc = { 0 }; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 8); wc.hCursor = NULL; wc.hIcon = NULL; wc.hInstance = hIns; wc.lpfnWndProc = WndProce; wc.lpszClassName = "Main"; wc.lpszMenuName = NULL; wc.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wc);
HWND hWnd = CreateWindow("Main", "window", WS_OVERLAPPEDWINDOW, 100, 100, 500, 500, NULL, NULL, hIns, NULL); return 0; }
|
- 接下来就是根据
CreateWindow()
写入到内存中的数据在电脑屏幕上显示窗口。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| #include<windows.h>
LRESULT CALLBACK WndProce(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM IParam) { return DefWindowProc(hWnd, msgID, wParam, IParam); }
int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns, LPSTR IpCmdLine, int nCmdShow) { WNDCLASS wc = { 0 }; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 8); wc.hCursor = NULL; wc.hIcon = NULL; wc.hInstance = hIns; wc.lpfnWndProc = WndProce; wc.lpszClassName = "Main"; wc.lpszMenuName = NULL; wc.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wc);
HWND hWnd = CreateWindow("Main", "window", WS_OVERLAPPEDWINDOW, 500, 100, 500, 500, NULL, NULL, hIns, NULL);
ShowWindow(hWnd, SW_SHOW); UpdateWindow(hWnd); return 0; }
|
- 然后就是消息循环,窗口处理完肯定要保持显示状态,像上面那个代码窗口一画完就退出程序,窗口就会消失。
- 而正常来说窗口一般都有输入框、点击按钮、鼠标移动到那个图标上,这些都是用户对窗口的一些操作,消息处理基本上就是处理这些。
- 在处理消息之前首先需要接收消息,而接收消息肯定要窗口要一直显示用户才能对窗口操作,所以需要使用一个
while
循环,然窗口一直显示,消息一直在接收和翻译,最后会给用户自定义的窗口处理函数来处理一些用户对窗口的操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| #include<windows.h>
LRESULT CALLBACK WndProce(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM IParam) { return DefWindowProc(hWnd, msgID, wParam, IParam); }
int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns, LPSTR IpCmdLine, int nCmdShow) { WNDCLASS wc = { 0 }; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 8); wc.hCursor = NULL; wc.hIcon = NULL; wc.hInstance = hIns; wc.lpfnWndProc = WndProce; wc.lpszClassName = "Main"; wc.lpszMenuName = NULL; wc.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wc);
HWND hWnd = CreateWindow("Main", "window", WS_OVERLAPPEDWINDOW, 500, 100, 500, 500, NULL, NULL, hIns, NULL);
ShowWindow(hWnd, SW_SHOW); UpdateWindow(hWnd);
MSG nMsg = { 0 }; while (GetMessage(&nMsg, NULL, 0, 0)) { TranslateMessage(&nMsg); DispatchMessage(&nMsg); }
return 0; }
|
- 最后一步就是消息处理了(最后一步这里不多说),就举个例子比如你对窗口的某个按钮做了点击操作,此时自定义的函数就要做相关的一些操作。或者是点击关闭按钮,表示程序退出,这时需要调用一个窗口退出函数来退出,否则该程序就算你关了窗口,程序也会在后台一直运行。
- 最终的效果如下:

注册窗口类