编码类型
多字节编码:
目前市场主流使用的还是多字节编码字符集。
多字节编码字符集,对于不同的字符集,所使用的内存空间大小不同,英文单词使用一个字节,汉字使用2个或者三个字节表示。
这种情况下很有可能会出现解析的时候错位,导致乱码
unicode编码:
unico编码字符集,把所有的字符都使用2个字节。可以有效避免错位的问题
vs环境中的字符
在vs中有两种字符类型,单字节的char和双字节的wchar_t。
当使用wchar_t的字符串字面值的时候,需要用L在字符串前声明,告知编译器字符串使用unicode编译
wchar_t szText = L"hello";
在vs中提供了char和wchar_t的兼容方法
TCHAR 这是一个条件编译的结果
#ifdef UNICODE
typedef WCHAR TCHAR,*PTCHAR
#define _TEXT(quote) L##quote
#else
tyoedef char TCHAR,*PTCHAR
#define _TEXT(quote) quote
#endif
所以,当程序有对UNICODE宏定义,那么使用TCHAR类型的时候,使用的就是UNICODE编码
反之,当程序没有定义UNICODE,那么TCHAR代表的就是char类型
窗口程序
一个完整的窗口类型,由以下几个部分组成
1、窗口程序的入口函数WinMain
2、消息处理函数
3、注册窗口类
4、创建窗口
5、显示窗口
6、消息循环
7、消息处理(也就是消息处理函数)
按照上述过程,给以给出一个最基本的窗口程序的框架
-------------------
#include
HINSTANCE g_hInstance;
LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam) {
switch (message) {
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(hWnd,message,wParam,lParam);
}
void Register(LPSTR lpClassName) {
WNDCLASSEX wec = { 0 };
wec.cbSize = sizeof(wec);
wec.cbClsExtra = 0;
wec.cbWndExtra = 0;
wec.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wec.hCursor = NULL;
wec.hIcon = NULL;
wec.hIconSm = NULL;
wec.hInstance = g_hInstance;
wec.lpfnWndProc = WndProc;
wec.lpszClassName = lpClassName;
wec.lpszMenuName = NULL;
wec.style = CS_HREDRAW | CS_VREDRAW;
RegisterClassEx(&wec);
}
HWND CreateWind(LPSTR lpClassName,LPSTR lpWindowName) {
HWND hWnd = CreateWindowEx(0,
lpClassName,
lpWindowName,
WS_OVERLAPPEDWINDOW,
100,
100,
700,
500,
NULL,
NULL,
g_hInstance,
NULL
);
return hWnd;
}
void Display(HWND hWnd) {
ShowWindow(hWnd,SW_SHOW);
UpdateWindow(hWnd);
}
void Message(void) {
MSG nMsg = { 0 };
while (GetMessage(&nMsg, NULL, 0, 0)) {
TranslateMessage(&nMsg);
DispatchMessage(&nMsg);
}
}
int CALLBACK WinMain(HINSTANCE hInstance ,HINSTANCE prevInstance,LPSTR lpCmdLine,int nComShow) {
Register("MyClass");
HWND hWnd = CreateWind("MyClass", "Window");
Display(hWnd);
Message();
return 0;
}
-------------------
窗口类的风格:
CS_GLOBALCLASS - 应用程序全局窗口类
CS_BYTEALIGNCLIENT - 窗口客户区的水平位置8倍数对齐
CS_BYTEALIGNWINDOW - 窗口的水平位置8倍数对齐
CS_HREDRAW - 当窗口水平变化时,窗口重新绘制
CS_VREDRAW - 当窗口垂直变化时,窗口重新绘制
CS_CLASSDC - 该类型的窗口,都是有同一个绘图(DC)设备
CS_PARENTDC - 该类型的窗口,使用它的父窗口的绘图(DC)设备
CS_OWNDC - 该类型的窗口,每个窗口都使用自己的绘图(DC)设备
CS_SAVEBITS - 允许窗口保存成图(位图),提高窗口的绘图效率,但是耗费内存资源
CS_DBLCLKS - 允许窗口接收鼠标双击
CS_NOCLOSE - 窗口没有关闭按钮
窗口类的注册:
自定义窗口类,必须通过注册函数将其向系统注册,系统窗口类,系统会进行注册,就不需要用户手动注册。
窗口类的分类:
窗口类可以分为应用程序的局部窗口类,全局部窗口类,系统窗口类。
通过窗口类的窗口类风格参数的选项 CS_GLOBALCLASS,可以决定这个窗口类是否声明为全局窗口类。
窗口的创建过程:
当一个窗口发起创建的时候,会根据参数中窗口类名称先到局部窗口类中寻找,如果找到了,再用当前进程句柄和窗口类匹配。成功就用这个窗口类继续创建窗口,如果失败,就到全局窗口类中寻找,如果还是失败,就到系统窗口类中寻找。在全局和系统窗口类中匹配时,不要求当前进程句柄匹配。
创建子窗口:
创建子窗口时,需要将窗口基本风格中加上WS_CHILD|WS_VISIBLE 前者表示子窗口,后者表示显示。
还要将父窗口句柄的参数填写。
代码如下:
----------
#include
HINSTANCE g_hInstance;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
void Register(LPSTR lpClassName) {
WNDCLASSEX wec = { 0 };
wec.cbSize = sizeof(wec);
wec.cbClsExtra = 0;
wec.cbWndExtra = 0;
wec.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wec.hCursor = NULL;
wec.hIcon = NULL;
wec.hIconSm = NULL;
wec.hInstance = g_hInstance;
wec.lpfnWndProc = WndProc;
wec.lpszClassName = lpClassName;
wec.lpszMenuName = NULL;
wec.style = CS_HREDRAW | CS_VREDRAW;
RegisterClassEx(&wec);
}
HWND CreateWind(LPSTR lpClassName, LPSTR lpWindowName) {
HWND hWnd = CreateWindowEx(0,
lpClassName,
lpWindowName,
WS_OVERLAPPEDWINDOW,
100,
100,
700,
500,
NULL,
NULL,
g_hInstance,
NULL
);
return hWnd;
}
HWND CreateChild(HWND fWnd,LPSTR lpWindowName) {
HWND hWnd = CreateWindowEx(0,"EDIT",lpWindowName, WS_OVERLAPPEDWINDOW|WS_CHILD|WS_VISIBLE,0,0,200,200,fWnd,NULL,g_hInstance,NULL);
return hWnd;
}
void Display(HWND hWnd) {
ShowWindow(hWnd, SW_SHOW);
UpdateWindow(hWnd);
}
void Message(void) {
MSG nMsg = { 0 };
while (GetMessage(&nMsg, NULL, 0, 0)) {
TranslateMessage(&nMsg);
DispatchMessage(&nMsg);
}
}
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, LPSTR lpCmdLine, int nComShow) {
Register("MyClass");
HWND hWnd = CreateWind("MyClass", "Window");
CreateChild(hWnd, "Child");
Display(hWnd);
Message();
return 0;
}
----------
窗口类附加数据缓存区和窗口附加数据缓存区的使用
窗口类附件数据缓存区是可用于基于同一个窗口类创建的两个窗口之间进行通讯的。
而窗口缓存区,则可以用于一个窗口内的其他部分进行通讯,例如,通过定时器消息,每隔一段时间向窗口缓存区中写入坐标,再由重绘消息从窗口缓存区中取出作处理。
1 定义数据空间的大小
int cbClsExtra - 一般定义为4字节倍数 200
2 存入数据
DWORD SetClassLong(
HWND hWnd,
int nIndex,
LONG dwNewLong
);返回旧数据
3 读取数据
DWORD GetClassLong(
HWND hWnd,
int nIndex
); 返回获取值
1 定义数据空间的大小
int cbWndExtra;
2 存入数据
LONG SetWindowLong(
HWND hWnd,
int nIndex,
LONG dwNewLong
);
3 读取数据
LONG GetWindowLong(
HWND hWnd,
int nIndex
);
一个小球再窗口内反弹
代码如下:
----------
#include
#include
HINSTANCE g_hInstance;
HANDLE g_hOutput;
int Rec = 100;
int Der = 0x010001;
const int xStep = 2;
const int yStep = 2;
int StepCout[4][2] = {{-xStep,-yStep},{xStep,-yStep},{xStep,yStep},{-xStep,yStep}};
int NextStep[2] = {0};
int MoveTime = 1;
void OnCreate(HWND hWnd){
SetTimer(hWnd,1,MoveTime,NULL);
}
void OnPaint(HWND hWnd){
int x = (int)GetWindowLong(hWnd,0);
int y = (int)GetWindowLong(hWnd,4);
PAINTSTRUCT ps = {0};
HDC hdc = BeginPaint(hWnd,&ps);
Ellipse(hdc,x,y,x+Rec,y+Rec);
EndPaint(hWnd,&ps);
}
void Calculate(HWND hWnd,int &x,int &y){
if(0 == x && 0 == y){
x += (int)HIWORD(Der);
y += (int)LOWORD(Der);
NextStep[0] = StepCout[2][0];
NextStep[1] = StepCout[2][1];
}
else{
int tempx = x + NextStep[0];
int tempy = y + NextStep[1];
RECT Cli = {0};
GetClientRect(hWnd,&Cli);
if(0 > tempx){
if(NextStep[1] > 0){
NextStep[0] = StepCout[2][0];
NextStep[1] = StepCout[2][1];
}
else{
NextStep[0] = StepCout[1][0];
NextStep[1] = StepCout[1][1];
}
}
else if(Cli.right < tempx + Rec){
if(NextStep[1] >0){
NextStep[0] = StepCout[3][0];
NextStep[1] = StepCout[3][1];
}
else{
NextStep[0] = StepCout[0][0];
NextStep[1] = StepCout[0][1];
}
}
if(0 > tempy){
if(NextStep[0] > 0){
NextStep[0] = StepCout[2][0];
NextStep[1] = StepCout[2][1];
}
else{
NextStep[0] = StepCout[3][0];
NextStep[1] = StepCout[3][1];
}
}
else if(Cli.bottom < tempy + Rec){
if(NextStep[0] >0){
NextStep[0] = StepCout[1][0];
NextStep[1] = StepCout[1][1];
}
else{
NextStep[0] = StepCout[0][0];
NextStep[1] = StepCout[0][1];
}
}
}
x = x + NextStep[0];
y = y + NextStep[1];
}
void OnTimer(HWND hWnd,WPARAM wParam){
int x = (int)GetWindowLong(hWnd,0);
int y = (int)GetWindowLong(hWnd,4);
Calculate(hWnd,x,y);
SetWindowLong(hWnd,0,x);
SetWindowLong(hWnd,4,y);
InvalidateRect(hWnd,NULL,TRUE);
char szText[256] = {0};
sprintf(szText,"Paint(%d,%d)\n",x,y);
WriteConsole(g_hOutput,szText,sizeof(szText),NULL,NULL);
}
LRESULT CALLBACK WndProc(HWND hWnd,UINT msgID,WPARAM wParam,LPARAM lParam){
switch(msgID){
case WM_TIMER:
OnTimer(hWnd,wParam);
break;
case WM_PAINT:
OnPaint(hWnd);
break;
case WM_CREATE:
OnCreate(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(hWnd,msgID,wParam,lParam);
}
void Register(LPSTR lpClassName,WNDPROC WndProc){
WNDCLASSEX wce = {0};
wce.cbSize = sizeof(wce);
wce.cbClsExtra = 0;
wce.cbWndExtra = 8;
wce.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wce.hCursor = NULL;
wce.hIcon = NULL;
wce.hIconSm = NULL;
wce.hInstance = g_hInstance;
wce.lpfnWndProc = WndProc;
wce.lpszClassName = lpClassName;
wce.lpszMenuName = NULL;
wce.style = CS_HREDRAW|CS_VREDRAW;
RegisterClassEx(&wce);
}
HWND CreateMain(LPSTR lpClassName,LPSTR lpWndName){
HWND hWnd = CreateWindowEx(0,lpClassName,lpWndName,WS_OVERLAPPEDWINDOW,100,100,700,500,NULL,NULL,g_hInstance,NULL);
SetWindowLong(hWnd,0,0);
SetWindowLong(hWnd,4,0);
return hWnd;
}
void display(HWND hWnd){
ShowWindow(hWnd,SW_SHOW);
UpdateWindow(hWnd);
}
void Message(void){
MSG nMsg = {0};
while(GetMessage(&nMsg,NULL,0,0)){
TranslateMessage(&nMsg);
DispatchMessage(&nMsg);
}
}
int CALLBACK WinMain(HINSTANCE hInstance,HINSTANCE hPrevIn,LPSTR lpCmdLine,int nShowCmd){
AllocConsole();
g_hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
g_hInstance = hInstance;
Register("MyClass",WndProc);
HWND wHnd = CreateMain("MyClass","Window");
display(wHnd);
Message();
return 0;
}
----------