Window程序编程参考资料
Windows SDK编程:
Windows程序设计第五版
Windows系统编程:
Windows核心编程第五版
SDK:软件开发套件,提供各种接口及文档,多用于桌面程序开发
接口:即API,应用程序编程接口。类似于C语言的函数
文档:对各种API的说明解释,如MSDN DOC
SDK由标准库<Windwos.h>提供,该头文件封装了很多WindowsAPI的集合(应用程序编程接口)
Win32 API就是Windows操作系统提供给我们的函数(应用编程接口)
Win32 API都有两个版本:多字节版本:函数名以A结尾。宽字节版本:函数名以W结尾
Windows编程项目属性修改:
1.属性->常规->字符集:Unicode
2.C/C++:代码生成->运行库:MTD,Spectre缓解:禁用
3.链接器->系统->子系统:窗口
Windows和C的区别
应用程序
应用程序大体可分为以下三种,具体分为以下四种:
控制台程序 Console:是一种DOS程序,本身没有窗口,通过Windows DOS窗口执行
窗口程序:拥有自己的窗口,可以与用户交互
库程序:存放代码、数据的程序,执行文件可以从中取出代码执行和获取数据,具体有以下两种:
1.静态库程序:扩展名LIB,在编译链接程序时,将代码放入到执行文件中。
2.动态库程序:扩展名DLL,在执行文件执行时从中获取代码
入口函数
控制台程序 - main
int main(int argc, const char *argv[])
argc = 参数个数
argv = 参数
窗口程序 - WinMain
int APIENTRY wWinMain(
_In_ HINSTANCE hInstance, //当前模块(程序)的实例句柄,指向当前模块在进程空间中的首地址,即加载到内存时的基地址ImageBase
_In_opt_ HINSTANCE hPrevInstance, //当前程序前一个实例句柄,目前该参数被废弃了
_In_ LPWSTR lpCmdLine, //启动这个程序时的命令行参数,是一个以空字符结尾的字符串
_In_ int nCmdShow //窗口的显示方式,如最大化显示,最小化,由该程序的调用者所指定
)
{
retrun 0;
}
WinMain函数前的修饰符APIENTRY,是WINAPI被typedef重命名的的结果,而WINAPI是__stdcall被typedef重命名的结构。
LPWSTR是对WCHAR的封装
LPSTR是对char的封装
hInstance:数值标识。当程序在Windows下运行时,它是唯一用于标识运行中的程序实例(只有运行中的程序实例,才有实例句柄)。一个应用程序可以运行多个实例,每运行一个实例,系统都会给该实例分配一个实例句柄,并通过hInstance参数传递给WinMain函数。它其实就是PE文件中可选PE头的ImageBase。
动态库程序 - DllMain
静态库程序 - 无入口函数
文件存在方式
控制台程序、窗口程序 - EXE文件
动态库程序 - DLL文件
静态库程序 - LIB文件
子系统
C/C++下的子系统为控制台
Windows下的子系统为窗口
字符编码
字符编码有如下两种:
1.ASCII编码
2.UNICODE编码
现我们来探究在C语言中两种编码有什么不同
C语言中的字符编码
数据类型的不同
ASCII码字符在C语言中的数据类型是char,大小1字节
UNICODE码字符在C语言中是wchar_t,大小2字节
程序入口的不同
C/C++中:
ASCII编码的main函数是程序编写中的入口,_mainCRTStartup是实际的程序入口
UNICODE编码的main函数是程序编写中的入口, _wmainCRTStartup是实际的程序入口
windows中:
ASCII编码的WinMain函数是程序编写中的入口,_WinMainCRTStartUp是实际的程序入口
UNICODE编码的wWinMain函数是程序编写中的入口, _wWinMainCRTStartUp是实际的程序入口
字符串操作不同
strlen:C++中操作ASCII编码字符时,应用的获取字符串长度的函数
wcslen; C++中操作UNICODE编码字符时,应用的获取字符串长度的函数
这两种字符编码的数据类型在Windows编程中有延续但有不同
Windows中的字符编码
数据类型的不同
ASCII码字符在Windows中的数据类型是CHAR
UNICODE码字符在Windows中是WCHAR
以上两种数据类型是对C语言中的char和wchar_t的二次封装,这样的好处有以下两点:
1.统一风格,增强代码可读性
2.方便跨平台移植。如果需要将已有的代码移植到别的平台,只需要修改#define
重定义那行
Windows宏字符串
TCHAR数据类型:Windows中支持的字符串新类型,也是一个宏,可以随项目字符集改变而改变,如项目环境字符集从多字节转换为宽字节时,其类型也会转变
TEXT(_T)宏:该宏的作用与TCHAR一样。
具体用法:TEXT("鼠标左键"),_T("鼠标左键")
_tcslen():Windows中支持的字符串函数。_tcslen是一个宏,可以随项目字符集改变而改变,用于操作TCHAR类型,计算该字符串长度是多少,
注意:凡是需要传递字符串参数的T前缀函数,都会提供两个版本和一个宏。
如下以一个程序进行演示讲解:
#include <Windows.h>
#include <stdio.h>
int main()
{
//C语言
char * szBuffer;
wchar_t * wszBuffer;
//Windwos
const CHAR * szWinBuffer = "rkvir"; .
const WCHAR * wszWinBuffer = L"rkvir"; //L前缀表示宽字符
//Windows中多字节转宽字节
CHAR szTarget[50] = { 0 }; //创建多字节类型的数组
WCHAR wszTarget[50] = { 0 }; //创建宽字节类型的数组
MultiByteToWideChar(CP_ACP, NULL, szWinBuffer, -1, wszTarget, 50); //多字节转宽字节
printf("%S\r\n", wszTarget);//转换后的字符类型打印时,只能应用其对应的格式化字符符。%s对应ASCII,%S对应Unicode
WideCharToMultiByte(CP_ACP, NULL, wszWinBuffer, wcslen(wszWinBuffer), szTarget, 50,NULL,NULL); //宽字节转多字节
printf("%s\r\n", szTarget);
system("pause");
return 0;
}
GetLastError函数
我们在写Win32程序的时候,当代码出错时,编译器不会报错。这时候就需要我们使用OutLastError()函数了,该函数放置于我们认为可能出错代码的下一行,该函数返回一个DWORD类型,接收了此时最后一个错误的WindowsAPI的编码,该编码我们从api文档中在OutLastError()函数中查找相应的错误api
MessageBox应用
MessageBox:实际上也是一个宏,根据项目环境选择A(多字节)还是W(宽字节)版。它是一个WIndows提供的API。
如下便是MessageBox的宏声明,我们从中可以了解到它随项目环境改变而改变的工作原理
#ifdef UNICODE //判断当前环境是不是Unicode
#define MessageBox MessageBoxW //如果是则调用此函数
#else
#define MessageBox MessageBoxA //如果不是(即ASCII)调用此函数
#endif //!UNICODE
具体函数定义如下:
int MessageBox(
[in, optional] HWND hWnd,//该窗口的父窗口句柄,如果没有填NULL
[in, optional] LPCTSTR lpText,//弹出窗口显示的内容
[in, optional] LPCTSTR lpCaption,//弹出窗口的标题
[in] UINT uType//弹出窗口的类型
);
句柄:Windows中各个内核对象的一个唯一的、固定不变的ID,类似于C语言的指针
如下是MessageBox函数不同应用场景下的变化
MessageBoxA(0,"内容多字节","标题",MB_OK);
MessageBoxW(0,L"内容宽字符",L"标题",MB_OK);
MessageBox(0,TEXT"由字符集决定“,TEXT”标题“,MB_OK);
接下来我们开始应用该函数
int APIENTRY wWinMain(_In_ HINSTANCE hInstance, Windows程序入口
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
int nFlag = MessageBox(NULL, "rkvir", "Msg", MB_YSENO);
return 0;
}
运行程序结果显示
此时如果MB_YESNO改为MB_OK则窗口变为
改为MB_COMPOSITE则窗口变为
现我们对该函数的应用进行优化
int APIENTRY wWinMain(_In_ HINSTANCE hInstance, Windows程序入口
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
int nFlag = MessageBox(NULL, "rkvir", "Msg", MB_YSENO);
if (IDYES == nFlag) //IDYES判断是否点击ok按钮
{
MessageBox(NULL, "OK", "Msg", MB_OK); //再次弹窗
}
else
{
MessageBox(NULL, "NO", "Msg", MB_OK); //再次弹窗
}
return 0;
}
此时当弹出窗口后,程序会根据我们选择的选项进行下一步的窗口弹出
API后缀
常见的API后缀有A W EX三种,分别表示ASCII Unicode 净化版
EX:现在有一个函数FunA(),如果此时要新增一个函数仍需要用FunA这个名字,为了不影响原函数的使用,则需要将新函数命名FunAEX(),表该函数是前一个函数增强版,与前函数有所区别。但为保持兼容性,前一个函数FunA()不需要修改
消息
Windows是基于消息的操作系统
MFC或者SDK的窗口都是基于消息的
作业
01.尝试使用MessageBox的各种按钮类型,并接收返回值进行应用
#include<iostream>
#include<Windows.h>
int APIENTRY wWinMain(
_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow
)
{
MessageBox(NULL, L"ASD", L"QWE", MB_OK);
MessageBox(NULL, L"ASD", L"QWE", MB_ABORTRETRYIGNORE);
MessageBox(NULL, L"ASD", L"QWE", MB_CANCELTRYCONTINUE);
MessageBox(NULL, L"ASD", L"QWE", MB_HELP);
MessageBox(NULL, L"ASD", L"QWE", MB_OKCANCEL);
MessageBox(NULL, L"ASD", L"QWE", MB_RETRYCANCEL);
return 0;
}
接下来我们简单使用前两个弹窗的返回值进行一个应用
#include<iostream>
#include<Windows.h>
int APIENTRY wWinMain(
_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow
)
{
int nFlag1 = MessageBox(NULL, L"ASD", L"QWE", MB_OK);
if (nFlag1 == IDOK)
{
MessageBox(NULL, L"OK", L"OK", MB_OK);
}
int nFlag2 = MessageBox(NULL, L"ASD", L"QWE", MB_ABORTRETRYIGNORE);//重试选项的返回值有两种,不同弹窗的重试选择返回值可能不一样
if (nFlag2 == IDABORT)
{
MessageBox(NULL, L"IDABORT", L"IDABORT", MB_OK);
}
else if (nFlag2 == IDIGNORE)
{
MessageBox(NULL, L"IDIGNORE", L"IDIGNORE", MB_OK);
}
else if (nFlag2 == IDRETRY)
{
MessageBox(NULL, L"IDRETRY", L"IDRETRY", MB_OK);
}
return 0;
}
CHAR*02.进行WCHAR与CHAR之间的互相转换,并且正确输出
#include<iostream>
#include<Windows.h>
int main()
{
const CHAR* szWinBuffer = "asd";
const WCHAR* wszWinBuffer = L"QWE";
CHAR szTarget[50] = { 0 };
WCHAR wszTarget[50] = { 0 };
MultiByteToWideChar(CP_ACP, NULL, szWinBuffer, -1, wszTarget, 50);
printf("%S", wszTarget);
WideCharToMultiByte(CP_ACP, NULL, wszWinBuffer, -1, szTarget, 50, NULL, NULL);
printf("%s", szTarget);
return 0;
}