Window程序编程参考资料:
Windows SDK编程:
Windows程序设计第五版
Windows系统编程:
Windows核心编程第五版
SDK:软件开发套件
SDK就是API的集合(应用程序编程接口)
应用程序分类
应用程序大体可分为以下三种,具体分为以下四种:
控制台程序 Console:是一种DOS程序,本身没有窗口,通过Windows DOS窗口执行
窗口程序:拥有自己的窗口,可以与用户交互
库程序:存放代码、数据的程序,执行文件可以从中取出代码执行和获取数据,具体有以下两种:
1.静态库程序:扩展名LIB,在编译链接程序时,将代码放入到执行文件中。
2.动态库程序:扩展名DLL,在执行文件执行时从中获取代码
应用程序对比
入口函数的角度:
控制台程序 - main
窗口程序 - WinMain
动态库程序 - DllMain
静态库程序 - 无入口函数
文件存在方式的角度:
控制台程序、窗口程序 - EXE文件
动态库程序 - DLL文件
静态库程序 - LIB文件
Windows程序入口
使用VSstudio创建win32APP项目,也可创建控制台项目,但需要在该项目添加相应的头文件
当我们创建Win32入口程序,我们会看到一个入口函数:
int APIENTRY wWinMain(
HINSTANCE hInstance, 当前程序的实例句柄,指向我们exe文件,即可执行程序
HINSTANCE hPrevInstance, 当前程序前一个实例句柄,目前该参数被废弃了
LPWSTR lpCmdLine, 命令行参数字符串,是一个以空字符结尾的字符串
int nCmdShow 窗口的显示方式,如最大化显示,最小化,由该程序的调用者所指定
)
{
retrun 0;
}
WinMain函数前的修饰符APIENTRY,其实是被使用typedef关键字重命名的,它是WINAPI,而
WINAPI也是被使用typedef重命名的,它其实就__stdcall。LPWSTR实际是对WCHAR的封装与之
类似还有LPSTR和char
hInstance 它是一个数值标识。当程序在Windows下运行时,它是唯一用于标识程序运行中的实例
(只有运行中的程序实例,才有实例句柄)。一个应用程序可以运行多个实例,每运行一个实例,
系统都会给该实例分配一个实例句柄,并通过hInstance参数传递给WinMain函数。它其实就是可
选PE头中ImageBase。
控制台程序入口
int main(int argc, const char *argv[])
argc = 参数个数
argv = 参数
字符编码不同导致的各种情况
字符编码对应数据类型的不同:
ASCII码字符在C语言中的数据类型是char
UNICODE码字符在C语言中是wchar_t
ASCII编码的main函数嵌入在可执行程序里实际是_mainCRTStartup
UNICODE编码的main函数嵌入在可执行程序里实际是 _wmainCRTStartup
字符编码对应字符串操作不同:
strlen:C++中操作ASCII编码字符时,应用的获取字符串长度的函数
wcslen; C++中操作UNICODE编码字符时,应用的获取字符串长度的函数
这两个字符编码在Windows编程中有延续但有不同,在C/C++编程中,如果想要使用windows中的
内容,需要包含头文件<windows.h>,该头文件封装了很多Windows相关方法内容
以下说明几个Windows中新的数据类型及函数:
TCHAR * tszWinBuffer; Windows中支持的字符串新类型,可以随项目属性改变而改变,如项目环境字符集从多字节转换为宽字节时,其类型也会转变,也就是说TCHAR也是个宏
_tcslen(tszWinBuffer); t意味着兼容型,也就是说_tcslen也是一个宏,根据环境决定他是什么函数,用于操作TCHAR类型,计算该字符串长度是多少,
如下以一个程序进行演示讲解:
#include <Windows.h>
#include <stdio.h>
int main()
{
char * szBuffer; 该指针指向ASCII 1字节
wchar_t * wszBuffer; 该指针指向UNICODE 2字节,当字节没有填充满时,以00截断结尾。这两个是在C++中的封装的标准类型
但在windows中,上述两个标准类型进行了二次封装,目的是在修改该类型时仍然对之前的类型应用具有兼容性
以下是Windows中的多字节和宽字节
const CHAR * szWinBuffer = "rkvir"; 对标C++中char
const WCHAR * wszWinBuffer = L"rkvir"; 对标C++中char_t
在C++中,多字节和宽字节的转换复杂,但在Windows中可以很容易转换,以下进行一个多字节转宽字节演示
CHAR szTarget[50] = { 0 };
WCHAR wszTarget[50] = { 0 }; 创建两个类型的数组
MultiByteToWideChar(CP_ACP, NULL, szWinBuffer, -1, wszTarget, 50); 多字节转宽字节,具参数可以参考F12参考文档
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,凡是需要传递字符串参数的函数,都会提供两个版本和一个宏。该函数其返回值类型是int,作用是创建一个窗口,参数依次 窗口句柄(此处填NULL)内容 标题 按钮类型
句柄:Windows中各个内核对象的一个唯一的、固定不变的ID
按钮类型:如IDYES判断是否点击确定按钮(点击返回1),IDCANCEL 判断是否点击取消按钮
(点击返回2)他们都是宏
如下便是MessageBox声明,我们从中可以了解到它随项目环境改变而改变的工作原理
#ifdef UNICODE 判断当前环境是不是Unicode
#define MessageBox MessageBoxW 如果是则调用此函数
#else
#define MessageBox MessageBoxA 如果不是调用此函数
#endif //!UNICODE
MessageBoxA(0,”内容多字节”,”标题”,MB_OK);
MessageBoxW(0,”内容宽字符”,”标题”,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);
运行程序结果显示
此时如果MB_YESNO改为MB_OK则窗口变为
改为MB_COMPOSITE则窗口变为
if (IDYES == nFlag) IDYES判断是否点击ok按钮
{
MessageBox(NULL, "OK", "Msg", MB_OK); 再次弹窗
}
else
{
MessageBox(NULL, "NO", "Msg", MB_OK); 再次弹窗
}
return 0;
}
常见API后缀有A W EX即ASCII Unicode 净化版
EX: 一个函数FunA(),此时有一个新的函数仍需要用Func这个名字,为了不影响原函数的使用,
则FunAEX,表该函数是前一个函数增强版。但为保持兼容性,前一个函数不需要修改