写这个博客的目的仅仅是为自己编程学习过程中作一些总结,时不时来回顾,里面也有没搞明白的,希望在今后积累够后,回来看看能够豁然开朗
1、消息及消息队列:操作系统是将感知到的事件传递给应用程序。
操作系统给出了消息结构体MSG: 和哪一个窗口相关,消息本身是什么,消息的附加参数是什么,消息发生投递的时间是什么,消息投递时当前光标的位置
typedef struct tagMSG { HWND hwnd; UINT message; //用一个整数标示一个消息,定义了宏用来表示数字,如按键消息,鼠标左键下按 WM_LBUTTONDOWN这个宏来表示数字就比较好记忆, WPARAM wParam; //变量类型整数,指示消息的附加信息,具体的按键信息:如键盘按键的ASCIA码,获取具体字符 LPARAM lParam; <span style="font-family: Arial, Helvetica, sans-serif;">//变量类型整数,指示消息的附加信息</span> DWORD time; //32位整数,doubleWord POINT pt; // 当信息别投递时,当前光标的位置, } MSG;
句柄(HANDLE),资源的标示,包括图标(HICON)、光标(HCurSOR)、窗口(HWND)、应用程序实例句柄(HINSTANCE)等
即给各种资源一个标示号,操作系统方便管理。
如HWND,是一个窗口句柄,操作系统通过这个句柄可以管理这个窗口的内容。操作系统是用句柄去索引的内存当中的资源。
2、每一个应用程序,操作系统都会为其建立一个消息队列,先进先出的缓冲区
3、Windows程序的入口函数
int WINAPI WinMain( HINSTANCE hInstance, // handle to current instance 应用程序实例句柄,代表 HINSTANCE hPrevInstance, // handle to previous instance LPSTR lpCmdLine, // command line LP STR 指向字符串的指针 int nCmdShow // show state );
4、窗口创建
a、设计一个窗口类;
b、注册窗口类;
c、创建窗口;
d、显示及更新窗口
#include "stdafx.h" #include <Windows.h> #include <stdio.h> #pragma(lib, "MSVCRTD.lib"); LRESULT CALLBACK WinSunProc(HWND hwnd, //窗口句柄 UINT wMsg, //message identifier WPARAM wParam, // first message parameter LPARAM lParam); //second message parameter int WINAPI WinMain(HINSTANCE hInstance, //应用程序实例句柄 HINSTANCE hPrevInstance, //先前应用程序的句柄 LPSTR lpCmdLine, // int nCmdShow) { //设计一个窗口类 WNDCLASS wndcls; wndcls.cbClsExtra = 0; wndcls.cbWndExtra = 0; wndcls.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); wndcls.hCursor = LoadCursor(NULL, IDC_CROSS); wndcls.hIcon = LoadIcon(NULL,IDI_ERROR); wndcls.hInstance = hInstance; wndcls.lpfnWndProc = WinSunProc; //代码在VC6中没问题. 因为它的代码没有按可编译为UNICODE版本的方式写,而VS2005之后版本默认是UNICODE编码的.所以所有使用到字串的地方都会出错. //方法:修改VS2005之后版本的设置:选择你的项目->属性->常规->设置为不使用UNICODE,发现设置为多字节字符集也可以。发现用VS2005打开VC6的源代码,转换后是使用的多字节字符集。 // 在VS2008,vs2010中,项目->属性->常规->字符集:改为“使用多字节字符集”即可 //error C2440: “=”: 无法从“const char [11]”转换为“LPCWSTR”类问题 wndcls.lpszClassName = "tranning"; //wndClass.lpszClassName =L"DIRECTX11BookWindowClass";即在字符串的前面添加一个大写L。这样可以实现将字符串转换为宽字符集。 wndcls.lpszMenuName = NULL; wndcls.style = CS_HREDRAW | CS_VREDRAW; //注册窗口类 RegisterClass(&wndcls); //创建一个窗口 HWND hwnd; //创建一个句柄,代表这窗口标识符 // DWORD dwStyle 窗口类型 hwnd = CreateWindow("tranning", "仿生机器人实验室",WS_OVERLAPPEDWINDOW, 0, 0, 600, 400, NULL, NULL, hInstance, NULL); //显示窗口 ShowWindow(hwnd,SW_SHOWNORMAL); UpdateWindow(hwnd); //消息响应函数 MSG msg; while (GetMessage(&msg,NULL,0,0)) //第二个参数句柄设置为空,希望获取所有函数的消息 { TranslateMessage(&msg); //消息转换,如将WM_KEYDOWN和WM_KEYUP转换成一个char 消息,并且投递到消息队列当中 DispatchMessage(&msg); //将收到的消息传递到窗口的回调函数,在窗口过程函数当中处理,理解为将消息送给操作系统再由操作系统去调用回调函数 } return 0; } //窗口过程函数 //回调函数,
//CALLBACK 是标准调用约定_stdcall
LRESULT CALLBACK WinSunProc(HWND hwnd, //窗口句柄 UINT wMsg, //message identifier WPARAM wParam, // first message parameter LPARAM lParam) //second message parameter { switch(wMsg) { case WM_CHAR: char szChar[20]; sprintf(szChar,"char is %d", wParam); break; case WM_LBUTTONDOWN: MessageBox(hwnd,"mouse clicked", "fangsheng",0); HDC hdc; //device contacts , 提供这个接口,可以不用理会外设驱动怎么回事 hdc = GetDC(hwnd); TextOut(hdc, 0, 50, "Windows程序设计基础", strlen("Windows程序设计基础")); ReleaseDC(hwnd,hdc); break; case WM_PAINT: //窗口重绘函数 HDC hdc1; PAINTSTRUCT ps; hdc1 = BeginPaint(hwnd,&ps); TextOut(hdc1, 0, 0, "程序设计基础", strlen("程序设计基础")); EndPaint(hwnd, &ps); break; case WM_CLOSE: if(IDYES == MessageBox(hwnd, "是否真的结束?","Windows程序设计基础",0)) { DestroyWindow(hwnd); //销毁窗口 } break; case WM_DESTROY: PostQuitMessage(0); // 投递一个WM_QUIT的消息到线程的消息队列当中,并且立即返回 终止消息发送,式消息循环终止,从而实现退出程序 break; default: return DefWindowProc(hwnd,wMsg,wParam,lParam); //其它消息由操作系统默认处理 } return 0; }
运行时遇到问题:
1、//error C2440: “=”: 无法从“const char [11]”转换为“LPCWSTR”类问题代码在VC6中没问题. 因为它的代码没有按可编译为UNICODE版本的方式写,而VS2005之后版本默认是UNICODE编码的.所以所有使用到字串的地方都会出错.
//方法:修改VS2005之后版本的设置:选择你的项目->属性->常规->设置为不使用UNICODE,发现设置为多字节字符集也可以。发现用VS2005打开VC6的源代码,转换后是使用的多字节字符集。// 在VS2008,vs2010中,项目->属性->常规->字符集:改为“使用多字节字符集”即可
2、MSVCRTD.lib(crtexe.obj) : error LNK2019: 无法解析的外部符号 _main,该符号在函数 ___tmainCRTStartup 中被引用
在项目属性-连接器-系统- 子系统 , 将: /subsytem:console 改为/ subsystem:windows 至于为什么这么改,我就不是太清楚,
一开始在vs2010建立工程是默认控制台工程,我将里头main函数直接删除,并且输入以上代码,就出现这个问题。
_stdcall 与 cdcall 的区别
调用约定,一种是标准调用约定,一种是C语言的调用约定
定义的参数传递的顺序,还有堆栈清除有些差异
除了可变参数API 函数调用,其他都是_stdcall
VC++ 默认是cdcall,,在vc++调用_stdcall API函数时必须在声明函数时,加入_stdcall标示