Windows SDK(一) 基础知识

本文介绍Windows SDK的基础知识,包括Windows程序设计、系统编程、API接口、字符集设置等,并通过示例讲解MessageBox函数的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值