C++ Windows编程预备(MFC)
##前言
写这篇文章目的是为了让大家知道学习MFC之前用到的知识,方便后面能很容易理解windows编程,MFC的文件结构以及框架。
##Windows程序设计基础
- Dos与Windows
首先可以简单区分一下Windows与Dos,学了Windows操作系统,我们都知道Windows是可以在同一时间运行多个程序的,而Dos界面下这是一个过程接一个的。Windows中窗口是Windows程序的基本单元,Windows程序的运行过程就是窗口内部、窗口之间及窗口与用户之间的信息交换过程。
- 事件驱动
事件是指人们应用计算机的过程中发生的操作,如移动鼠标。
- 消息响应
每发生一个事件,就会产生一个与之对应的特定消息,该消息会被Windows系统捕获,然后将通过此消息调用执行与之对应的程序代码,实现相应的程序功能。
- 系统消息队列
由Windows系统维护管理的消息队列,每当有消息发生时,该消息将首先被存入系统消息队列。
- 应用程序消息队列
Windows系统会为每个应用程序建立一个独立的消息队列,用于存放该应用程序的消息。
消息循环:每个应用程序都有一个循环机构,该循环机构则不断地重复查看程序自身的消息队列,如果列中有消息,就将其取出并执行相应的消息处理代码,这个处理消息的循环机构称为消息循环
- 事件驱动与消息循环原理*(注:此处为重点,前面概念就是为了解释原理)*
程序启动->等待用户操作程序窗口->操作引发事件产生消息->windows捕获分析(系统消息列)->程序消息队列->循环获取消息->窗口处理函数处理消息->实现程序功能。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SN0C9DDB-1650768261873)(//img-blog.youkuaiyun.com/20180314223204555?watermark/2/text/Ly9ibG9nLmNzZG4ubmV0L0Jvc3RvblJheUFsZW4=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)]
- Windows程序的组成
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SEOdKIik-1650768261875)(//img-blog.youkuaiyun.com/20180314225025375?watermark/2/text/Ly9ibG9nLmNzZG4ubmV0L0Jvc3RvblJheUFsZW4=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)]
##Windows程序设计的常用数据结构
- 句柄
句柄是整个Windows编程的基础。一个句柄是指Windows使用的一个唯一的整数值,是一个4字长(32位无符号整数)的数值,用于标识应用程序中不同的对象和同类对象中不同的实例。总的来说就是应用程序通过句柄能够访问相应的对象信息。 - 数据类型
数据结构跟编程语言里面都差不多。 - 点和矩形区域
坐标,长宽,颜色有固定的结构体来描述。 - 消息结构
typedef struct tagMSG {
HWND hwnd; //消息发向的窗口句柄
UINT message; //消息标识符, WPARAM
LPARAM lParam; //32位的消息参数,值因消息异
DWORD time; //消息放入消息队列的时间
POINT pt; //消息放入消息队列的鼠标位置。
} MSG;
##Windows程序的基本结构
WinMain ( ) : 必有且仅有一个。是程序执行的入口点,类似于C程序中的main函数
窗口函数 : 每个窗口对应一个窗口函数,以响应该程序窗口中发生的事件消息。
##Windows程序的控制流程(重点)
-
WinMain->程序启动->等待用户操作程序窗口->操作引发事件产生消息->windows捕获分析(系统消息列)->程序消息队列->循环获取消息->窗口处理函数处理消息->实现程序功能。
-
WinMain:调用API函数定义并注册窗口类,创建程序窗口,显示窗口,建立消息循环
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ykJIsnrB-1650768261875)(//img-blog.youkuaiyun.com/20180319173906326?watermark/2/text/Ly9ibG9nLmNzZG4ubmV0L0Jvc3RvblJheUFsZW4=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)]
##Windows程序的数据输出
这里以图形为例
1、程序首先获取设备环境句柄
2、通过该句柄调用图形设备接口的绘图函数绘图。
3、绘图函数所绘制的图形被Windows系统提供的设备驱动程序转换成具体物理设备的绘图函数,从而在具体硬件设备上绘制出图形。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MJs8Vv4o-1650768261876)(//img-blog.youkuaiyun.com/20180319222907987?watermark/2/text/Ly9ibG9nLmNzZG4ubmV0L0Jvc3RvblJheUFsZW4=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)]
根据进程id和模块名称获取模块基址
PVOID GetProcessImageBase3(DWORD dwProcessId, const TCHAR* moduleName)//dwProcessId就是程序的标识符
{
PVOID pProcessImageBase = NULL;
//打开进程, 获取进程句柄
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
if (NULL == hProcess)
{
return pProcessImageBase;
}
// 遍历进程模块,
HMODULE hModule[100] = { 0 };
DWORD dwRet = 0;
BOOL bRet = EnumProcessModules(hProcess, (HMODULE*)(hModule), sizeof(hModule), &dwRet);
if (FALSE == bRet)
{
CloseHandle(hProcess);
return pProcessImageBase;
}
int iSel = 0;
for (int i = 0; i < (dwRet / sizeof(HMODULE)); i++)
{
TCHAR szModName[MAX_PATH];
// Get the full path to the module's file.
if (GetModuleFileNameEx(hProcess, hModule[i], szModName,
sizeof(szModName) / sizeof(TCHAR)))
{
// 遍历模块名,与传入的模块名比较,相同则记录序号(只比较文件名,不比较路径,注意文件名带扩展名)
basic_string<TCHAR, char_traits<TCHAR>, allocator<TCHAR> >
str(szModName);
if (str.find_last_of('\\') >= 0)
str = str.substr(str.find_last_of(_T("\\"))+1);
if (_tcsicmp(str.c_str(), moduleName) == 0)
{
iSel = i;
break;
}
_tprintf(TEXT("\t%s (0x%08X)\n"), szModName, hModule[i]);
}
}
// 获取指定名称模块的加载基址,未找到则返回第0个
pProcessImageBase = hModule[iSel];
// 关闭句柄
CloseHandle(hProcess);
return pProcessImageBase;
}
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
PVOID p = GetProcessImageBase3(12124, _T("devenv.exe"));//12124改成你的devenv.exe的pid
return 0;
}