Windows Coding

#本文根据VC驿站的教程和资料进行的学习#

项目的创建:

VS2019中选择新建,然后选择Windows桌面应用程序即可创建一个Windows下的APP编程

程序的入口:

与普通的C++编程类似,Windows编程也需要一个程序的入口(类似于C++中的main函数),我们知道普通的C++编程有这样一个程序的框架:

#include<iostream>

using namespace std;

int main()
{
    return 0;
}

那么相应的,Windows编程也有这样一个程序框架:

#include<Windows.h>
#include<tchar.h>

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE PreInstance, char* lpCmdLine, int nShowCmd)
{
	
	return 0;
}

可以看见这里的程序入口函数WinMain与普通的C++不同,他拥有参数,分别是前面两个HINSTANCE(暂不理解这是个什么类型的数据,根据格式要求书写在这里),后面就是命令行参数和窗口显示参数(规定是否需要以窗口形式出现在我们的屏幕中)

结尾还是一个常规的return 0

第一个程序:

仍然是经典的Hello World,如下:

#include<Windows.h>
#include<tchar.h>

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE PreInstance, char* lpCmdLine, int nShowCmd)
{
	MessageBox(NULL, _T("Hello World!"), _T("Title"), MB_OK);
	return 0;
}
MessageBox:

即提示框函数,也就是往屏幕输出一个提示框,而我们可以自定输出的内容:

示例:

MessageBox(NULL, _T("Hello World!"), _T("Title"), MB_OK);

这里的第一个参数是消息框拥有的窗口。如果为NULL,则消息框没有拥有窗口。

第二个参数就是消息框的内容。

第三个参数是消息框的标题

第四个参数是指定一个决定对话框的内容和行为的位标志集。此参数可以为下列标志组中标志的组合,也就是用户可对消息框的操作,下面这个参数的一些用法:

按钮参数

MB_OK:默认值。有一个确认按钮在里面。

MB_YESNO:有是和否在里面。

MB_ABORTRETRYIGNORE:有Abort(放弃),Retry(重试)和Ignore(跳过)

MB_YESNOCANCEL:消息框含有三个按钮:Yes,No和Cancel

MB_RETRYCANCEL:有Retry(重试)和Cancel(取消)

MB_OKCANCEL:消息框含有两个按钮:OK和Cancel

第四个参数后面可以加上一个按位或的标识来加入一个图标参数,图标参数具体有以下这些:

MB_ICONEXCLAMATION:一个惊叹号出现在消息框

MB_ICONWARNING:一个惊叹号出现在消息框

MB_ICONINFORMATION: 一个圆圈中小写字母i组成的图标出现在消息框

MB_ICONASTERISK: 一个圆圈中小写字母i组成的图标出现在消息框

MB_ICONQUESTION: 一个问题标记图标出现在消息框

MB_ICONSTOP:一个停止消息图标出现在消息框

MB_ICONERROR:一个停止消息图标出现在消息框

MB_ICONHAND: 一个停止消息图标出现在消息框

调用约定:

调用约定(Calling Convention)是指在程序设计语言中为了实现函数调用而建立的一种协议。这种协议规定了该语言的函数中的参数传送方式、参数是否可变和由谁来处理堆栈等问题。不同的语言定义了不同的调用约定。

在C++中,为了允许操作符重载和函数重载,C++编译器往往按照某种规则改写每一个入口点的符号名,以便允许同一个名字(具有不同的参数类型或者是不同的作用域)有多个用法,而不会打破现有的基于C的链接器。这项技术通常被称为名称改编(Name Mangling)或者名称修饰(Name Decoration)。许多C++编译器厂商选择了自己的名称修饰方案。

因此,为了使其它语言编写的模块(如Visual Basic应用程序、Pascal或Fortran的应用程序等)可以调用C/C++编写的DLL的函数,必须使用正确的调用约定来导出函数,并且不要让编译器对要导出的函数进行任何名称修饰。

调用约定用来:(一)处理决定函数参数传送时入栈和(二)出栈的顺序(由调用者还是被调用者把参数弹出栈),以及(三)编译器用来识别函数名称的名称修饰约定等问题。

1、__cdecl
__cdecl是C/C++和MFC程序默认使用的调用约定,也可以在函数声明时加上__cdecl关键字来手工指定。采用__cdecl约定时,函数参数按照从右到左的顺序入栈,并且由调用函数者把参数弹出栈以清理堆栈。因此,实现可变参数的函数只能使用该调用约定。由于每一个使用__cdecl约定的函数都要包含清理堆栈的代码,所以产生的可执行文件大小会比较大。__cdecl可以写成_cdecl。

2、__stdcall
__stdcall调用约定用于调用Win32 API函数。采用__stdcal约定时,函数参数按照从右到左的顺序入栈,被调用的函数在返回前清理传送参数的栈,函数参数个数固定。由于函数体本身知道传进来的参数个数,因此被调用的函数可以在返回前用一条ret n指令直接清理传递参数的堆栈。__stdcall可以写成_stdcall。

3、__fastcall
__fastcall约定用于对性能要求非常高的场合。__fastcall约定将函数的从左边开始的两个大小不大于4个字节(DWORD)的参数分别放在ECX和EDX寄存器,其余的参数仍旧自右向左压栈传送,被调用的函数在返回前清理传送参数的堆栈。__fastcall可以写成_fastcall。

调试设置:

可以更改vs2013的工程配置。也就是传递给 WinMain 函数的 lpCmdLine 参数;

在这里插入图片描述

常用数据类型:

宽窄字节:

开始之前首先了解一下宽字节和窄字节,通俗的讲宽窄字节就是char类型的扩展与不扩展状态,是为了适应逐渐增多的字符类型而产生的扩展后的储存结构。

在Windows中,采用的是Unicode,在每次储存字符时都用到两个char(即两个字节)。但是为编程方便,Windows定义了一种新的数据类型:wchar_t,其原型是unsigned short,也就是两个字节的空间。

现在版本的VS之中基本都是默认支持Unicode

下面是几种宽窄字节数据类型:

● 窄字节:
char、char * 、const char *
CHAR、(PCHAR、PSTR、LPSTR)、LPCSTR

● Unicode 宽字节:
wchar_t、wchar_t * 、const wchar_t *
WCHAR、(PWCHAR、PWSTR、LPWSTR)、LPCWSTR

● T 通用类型:
TCHAR、(TCHAR * 、PTCHAR、PTSTR、LPTSTR)、LPCTSTR

其中:P代表指针的意思,STR代表字符串的意思,L是长指针的意思,在WIN32平台下可以忽略,C代表const常量的意思,W代表wide宽字节的意思,T可以理解为通用类型的意思,
就是可以根据工程中是否定义_UNICODE 宏,来判断当前工程的编码类型是宽字节还是窄字节,之后分别定义成不同的类型,比如:TCHAR 类型,如果工程中定义了_UNICODE 宏,那么就表明工程是宽字节编码,他最终就被定义成 wchar_t 类型,如果工程中没有定义_UNICODE 宏,就表明工程当前是窄字节编码,那么 TCHAR 被最终定义成 char 类型。

通过对这些新数据类型的观察可以得知,这些新数据类型都是来源于C/C++中原有的数据类型

Windows数据类型命名规律:

基本数据类型包括:BYTE,CHAR,WORD,SHORT,INT等。

指针类型的命名方式一般是在前面加一个LP或者P(指针的英文单词pointer的首字母)

句柄类型一般是在前面加一个H(handle)。句柄类型与指针非常相似,但是跟指针不同的是他只允许调用一部分API函数

无符号类型一般以U开头(unsigned)。

常量一般用C开头(const)。

字符串类型保持为STR。
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

两个API函数:

文件自动下载:

URLDonwloadToFile

其功能大概是指从指定URL地址读取内容并将读取到的内容保存到特定的文件里。语法格式如下:

HRESULT URLDownloadToFile( 
    LPUNKNOWN pCaller,
    LPCTSTR szURL,
    LPCTSTR szFileName,
    DWORD dwReserved,
    LPBINDSTATUSCALLBACK lpfnCB
);

示例:

HRESULT hert = URLDownloadToFile(NULL, _T("https://avatar.cctry.com/uc_server/data/avatar/000/00/00/51_avatar_middle.jpg"), _T("D:\\123.png"), 0, NULL);

返回值:

S_OK : 成功下载;
E_OUTOFMEMORY:缓冲区长度不够,或者没有足够的内存来完成下载的操作;
INET_E_DOWNLOAD_FAILURE:指定的资源或者回调接口有问题。

参数组成

pCaller:Pointer to the controlling IUnknown interface of the calling Microsoft ActiveX component (if the caller is an ActiveX component).
//该参数为 ActiveX 控件的接口指针,如果当前程序不是 ActiveX 控件则写 NULL 就可以了。

szURL
Pointer to a string value containing the URL to be downloaded. Cannot be set to NULL.
//该参数为要下载的 url 地址,不能为空。

szFileName
Pointer to a string value containing the name of the file to create for bits that come from the download.
//下载文件后,保存的文件名字,包含文件的具体路径信息。

dwReserved
Reserved. Must be set to 0.
//保留字段,必需为0。

lpfnCB
Pointer to the caller’s IBindStatusCallback interface. URLDownloadToFile calls this interface’s IBindStatusCallback::OnProgress method on a connection activity, including the arrival of data. IBindStatusCallback::OnDataAvailable is never called.
//下载进度状态回调接口的指针。如果要实时监视下载文件的状态那么就要用到这个参数了。

所需要的库支持:

Minimum supported clientWindows XP
Minimum supported serverWindows 2000 Server
ProductInternet Explorer 3.0
HeaderUrlmon.h
LibraryUrlmon.lib
DLLUrlmon.dll
Unicode and ANSI namesURLDownloadToFileW (Unicode) and URLDownloadToFileA (ANSI)

自动执行文件:

ShellExecuteEx

可以使用 ShellExecuteEx 打开文件或执行程序,这是被微软重新封装过后的函数,并不是标准的Windows API,而是一个shell API,语法格式如下:

BOOL ShellExecuteEx(
  _Inout_ SHELLEXECUTEINFO *pExecInfo
);

参数:

这个API函数只有一个参数,即是SHELLEXECUTEINFO 结构体,其结构定义如下:

typedef struct _SHELLEXECUTEINFO
{
  DWORD    cbSize;//结构大小,sizeof(SHELLEXECUTEINFO)
  ULONG     fMask;//指定结构成员的有效性
  HWND      hwnd;//父窗口句柄或出错时显示错误父窗口的句柄,可以为 NULL
  LPCTSTR   lpVerb;//指定该函数的执行动作
  LPCTSTR   lpFile;//操作对象路径
  LPCTSTR   lpParameters;//执行参数,可以为 ULL
  LPCTSTR   lpDirectory;//工作目录,可以为 NULL
  int             nShow;//显示方式
  HINSTANCE hInstApp;//如果设置了 SEE_MASK_NOCLOSEPROCESS ,并且调用成功则该值大于32,调用失败者被设置错误值
  LPVOID     lpIDList;//ITEMIDLIST结构的地址,存储成员的特别标识符,当fMask不包括SEE_MASK_IDLIST或SEE_MASK_INVOKEIDLIST时该项被忽略
  LPCTSTR   lpClass;//指明文件类别的名字或GUID,当fMask不包括SEE_MASK_CLASSNAME时该项被忽略
  HKEY        hkeyClass;//获得已在系统注册的文件类型的Handle,当fMask不包括SEE_MASK_HOTKEY时该项被忽略
  DWORD   dwHotKey;//程序的热键关联,低位存储虚拟关键码(Key Code),高位存储修改标志位(HOTKEYF_),当fmask不包括SEE_MASK_HOTKEY时该项被忽略

  union
  {
    HANDLE hIcon;//取得对应文件类型的图标的Handle,当fMask不包括SEE_MASK_ICON时该项被忽略
    HANDLE hMonitor;//将文档显示在显示器上的Handle,当fMask不包括SEE_MASK_HMONITOR时该项被忽略
  } DUMMYUNIONNAME;

  HANDLE    hProcess;//指向新启动的程序的句柄。若fMask不设为SEE_MASK_NOCLOSEPROCESS则该项值为NULL。
                     //但若程序没有启动,即使fMask设为SEE_MASK_NOCLOSEPROCESS,该值也仍为NULL。
                     //如果没有新创建进程,也会为空

} SHELLEXECUTEINFO, *LPSHELLEXECUTEINFO;

示例:

SHELLEXECUTEINFO shellinfo = { 0 };
	shellinfo.cbSize = sizeof(SHELLEXECUTEINFO);
	shellinfo.lpVerb = _T("open");
	shellinfo.lpFile = _T("calc.exe");
	shellinfo.nShow = SW_SHOW;
	
	BOOL RET = ShellExecuteEx(&shellinfo);

fMask 用于指定结构成员的内容和有效性,可为下列值的组合:

● SEE_MASK_DEFAULT (0)默认
● SEE_MASK_CLASSNAME 使用 lpClass 参数,如果 SEE_MASK_CLASSKEY 也有效,则用后者
● SEE_MASK_CLASSKEY 使用 hkeyClass 参数
● SEE_MASK_IDLIST 使用 lpIDList 参数
● SEE_MASK_INVOKEIDLIST 使用选定项目的快捷菜单 IContextMenu 接口处理程序
● SEE_MASK_ICON 使用 hIcon 给出的菜单,不能与 SEE_MASK_HMONITOR 共用,Vista之后
● SEE_MASK_HOTKEY 使用 dwHotKey 参数
● SEE_MASK_NOCLOSEPROCESS 如果执行之后需要返回进程句柄,或者等待执行完毕的话,则需要指定该参数,从结构参数意义可以看到 hProcess 和 hInstApp 都依赖该选项
● SEE_MASK_CONNECTNETDRV 验证共享并连接到驱动器号
● SEE_MASK_NOASYNC 不等待操作完成,直接返回,会创建一个后台线程运行。
● SEE_MASK_FLAG_DDEWAIT 弃用,使用 SEE_MASK_NOASYNC
● SEE_MASK_DOENVSUBST 环境变量会被展开
● SEE_MASK_FLAG_NO_UI 出现错误,不显示错误消息框,比如不会弹出找不到文件之类的窗口,直接返回失败
● SEE_MASK_UNICODE UNICODE 程序
● SEE_MASK_NO_CONSOLE 继承父进程的控制台,而不是创建新的控制台,与 CREATE_NEW_CONSOLE 相反
● SEE_MASK_ASYNCOK 执行在后台线程,调用立即返回
● SEE_MASK_NOQUERYCLASSSTORE 弃用
● SEE_MASK_HMONITOR 使用 hmonitor,不能与 SEE_MASK_ICON 共存
● SEE_MASK_NOZONECHECKS 不执行区域检查
● SEE_MASK_WAITFORINPUTIDLE 创建新进程后,等待进程变为空闲状态再返回,超时时间为1分钟
● SEE_MASK_FLAG_LOG_USAGE 跟踪应用程序启动次数
● SEE_MASK_FLAG_HINST_IS_SITE

lpVerb 参数与 ShellExecute 的 lpOperation 参数一致:
edit 用编辑器打开 lpFile 指定的文档,如果 lpFile 不是文档,则会失败
explore 浏览 lpFile 指定的文件夹
find 搜索 lpDirectory 指定的目录
open 打开 lpFile 文件,lpFile 可以是文件或文件夹
print 打印 lpFile,如果 lpFile 不是文档,则函数失败
properties 显示属性
runas 请求以管理员权限运行,比如以管理员权限运行某个exe
NULL 执行默认”open”动作

nShow 与 ShellExecute 的该参数一致:
● SW_HIDE 隐藏窗口,活动状态给令一个窗口
● SW_MINIMIZE 最小化窗口,活动状态给令一个窗口
● SW_RESTORE 用原来的大小和位置显示一个窗口,同时令其进入活动状态
● SW_SHOW 用当前的大小和位置显示一个窗口,同时令其进入活动状态
● SW_SHOWMAXIMIZED 最大化窗口,并将其激活
● SW_SHOWMINIMIZED 最小化窗口,并将其激活
● SW_SHOWMINNOACTIVE 最小化一个窗口,同时不改变活动窗口
● SW_SHOWNA 用当前的大小和位置显示一个窗口,不改变活动窗口
● SW_SHOWNOACTIVATE 用最近的大小和位置显示一个窗口,同时不改变活动窗口
● SW_SHOWNORMAL 与SW_RESTORE相同

如果设置了 SEE_MASK_NOCLOSEPROCESS ,调用成功则 hInstApp 返回大于32的值,调用失败会返回:
● SE_ERR_FNF (2) 文件未找到
● SE_ERR_PNF (3) 路径未找到
● SE_ERR_ACCESSDENIED (5) 拒绝访问
● SE_ERR_OOM (8) 内存不足
● SE_ERR_DLLNOTFOUND (32) 动态库未找到
● SE_ERR_SHARE (26) 无法共享打开的文件
● SE_ERR_ASSOCINCOMPLETE (27) 文件关联信息不完整
● SE_ERR_DDETIMEOUT (28) 操作超时
● SE_ERR_DDEFAIL (29) 操作失败
● SE_ERR_DDEBUSY (30) DDE 操作忙
● SE_ERR_NOASSOC (31) 文件关联不可用

返回值:
函数执行成功,返回 TRUE ,否则返回 FALSE ,可使用 GetLastError 获取错误码。

● ERROR_FILE_NOT_FOUND 文件不存在
● ERROR_PATH_NOT_FOUND 路径不存在
● ERROR_DDE_FAIL DDE(动态数据交换)失败
● ERROR_NO_ASSOCIATION 未找到与指定文件拓展名关联的应用
● ERROR_ACCESS_DENIED 拒绝访问
● ERROR_DLL_NOT_FOUND 未找到dll
● ERROR_CANCELLED 功能提示用户提供额外信息,但是用户取消请求。
● ERROR_NOT_ENOUGH_MEMORY 内存不足
● ERROR_SHARING_VIOLATION 发生共享冲突

所需要的库:

Minimum supported clientWindows XP [desktop apps only]
Minimum supported serverWindows 2000 Server [desktop apps only]
Target PlatformWindows
Headershellapi.h
LibraryShell32.lib
DLLShell32.dll (version 3.51 or later)

返回值:

函数执行成功,返回 TRUE ,否则返回 FALSE ,可使用 GetLastError 获取错误码。

● ERROR_FILE_NOT_FOUND 文件不存在
● ERROR_PATH_NOT_FOUND 路径不存在
● ERROR_DDE_FAIL DDE(动态数据交换)失败
● ERROR_NO_ASSOCIATION 未找到与指定文件拓展名关联的应用
● ERROR_ACCESS_DENIED 拒绝访问
● ERROR_DLL_NOT_FOUND 未找到dll
● ERROR_CANCELLED 功能提示用户提供额外信息,但是用户取消请求。
● ERROR_NOT_ENOUGH_MEMORY 内存不足
● ERROR_SHARING_VIOLATION 发生共享冲突

文件的删除、复制与重命名:

文件的删除:

DeleteFile

其功能即为删除指定存在的文件。语法格式如下:

BOOL WINAPI DeleteFile(
  _In_  LPCTSTR lpFileName
);

也有专门用于删除只读文件的API函数,语法如下:

BOOL DeleteReadOnlyFile(LPCTSTR lpFileName)
{

    DWORD dwRet = GetFileAttributes(lpFileName);
    if (dwRet == INVALID_FILE_ATTRIBUTES) return FALSE;

    if (dwRet & FILE_ATTRIBUTE_READONLY)
    {
        dwRet &= ~FILE_ATTRIBUTE_READONLY;
        SetFileAttributes(lpFileName, dwRet);
    }

    return DeleteFile(lpFileName);
}

这里使用了一个获取文件属性的API函数:GetFileAttributes,给定文件路径,可以获取文件文件的属性掩码值。例如代码中 dwRet,这个属性掩码包含了该文件的所有属性,是按照位运算来的。如:只读属性、隐藏属性等多个属性,所以我们这里面进行了判断,如果包含 FILE_ATTRIBUTE_READONLY 只读属性,那么就将该属性去掉,之后再调用 SetFileAttributes 设置文件的新属性。之后再调用 DeleteFile 将文件删除。

示例:

BOOL ret = DeleteFile(_T("D:\\test.txt"));

参数组成:

lpFileName
必选项,指定要删除文件的路径。

返回值:

函数执行成功,返回 TRUE ,否则返回 FALSE ,可使用 GetLastError 获取错误码。

备注:如果程序尝试删除一个不存在的文件,GetLastError 返回 ERROR_FILE_NOT_FOUND。如果文件是只读的,则 GetLastError 返回 ERROR_ACCESS_DENIED。

所需库支持:

Minimum supported clientWindows XP [desktop apps | UWP apps]
Minimum supported serverWindows Server 2003 [desktop apps | UWP apps]
Target PlatformWindows
Headerfileapi.h (include Windows.h)
LibraryKernel32.lib
DLLKernel32.dll

文件的复制:

CopyFile

其功能即是拷贝指定存在的文件到目标路径文件。语法格式如下:

BOOL CopyFile(
  LPCTSTR lpExistingFileName,
  LPCTSTR lpNewFileName,
  BOOL    bFailIfExists
);

参数组成:

lpExistingFileName:要拷贝的源文件的路径
lpNewFileName:要拷贝到的目标文件的路径
bFailIfExists:传递TRUE:如果目标文件已经存在,不拷贝,CopyFile 返回 FALSE,
传递 FALSE,如果目标文件已经存在,覆盖目标文件

返回值:

函数执行成功,返回 TRUE ,否则返回 FALSE ,可使用 GetLastError 获取错误码。

文件的移动(重命名):

MoveFile

其功能是可以使用 MoveFile 移动一个已存在的文件或者文件夹到新的位置。也可以用于修改文件名以及后缀语法格式如下:

BOOL MoveFile(
  LPCTSTR lpExistingFileName,
  LPCTSTR lpNewFileName
);

示例:

BOOL ret = CopyFile(_T("D:\\test.txt"), _T("D:\\666\\yms.txt"), TRUE);

参数:

lpExistingFileName:要移动的源文件或者文件夹的路径
lpNewFileName:要移动到的目标文件或者文件夹的路径

返回值:

函数执行成功,返回 TRUE ,否则返回 FALSE ,可使用 GetLastError 获取错误码。

错误码的获取:

GetLastError

这也是一个内置的API函数,用于获取当前面的API函数执行错误时产生的错误码,它的函数原型如下:

DWORD GetLastError(VOID);

示例:

DWORD dwerror = GetLastError();

无参数,返回值DWORD对应错误码的值,不同的错误码值对应不同的错误情况。下面是一个例子:

在这里插入图片描述

tips:

最好使用Windows提供的错误码的宏,而不是直接使用它的数值,因为数值可能在后面改变,而宏是不会改变的

对应的宏可以在win32的宏定义中查找

文件的创建、打开与关闭:

文件的创建与打开:

CreateFile

创建或打开文件或 I/O 设备。常用的 I/O 设备有:文件,文件流,目录,物理磁盘,卷,控制台缓冲区,磁带驱动器,通信资源,邮筒和管道。

该函数通过传入参数的不同判断是要创建一个文件还是要打开一个已经存在的文件

该函数返回一个句柄,该句柄可用于根据文件或设备以及指定的标志和属性访问文件或设备以获取各种类型的 I/O。

语法格式如下:

HANDLE WINAPI CreateFile(
  _In_     LPCTSTR               lpFileName,
  _In_     DWORD                 dwDesiredAccess,
  _In_     DWORD                 dwShareMode,
  _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  _In_     DWORD                 dwCreationDisposition,
  _In_     DWORD                 dwFlagsAndAttributes,
  _In_opt_ HANDLE                hTemplateFile
);

示例:

HANDLE ret =  CreateFile(_T("D:\\study of C++\\Windows Coding.md"), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

参数组成:

lpFileName

也就是文件的路径,有长度限制

要创建或打开的文件或设备的名称。 可以在这个名字中使用正斜杠(/)或反斜杠(\)【注意/是转义符号】。在该函数的ANSI版本中,该名称的长度仅限于MAX_PATH字符。要将此限制扩展为32,767个宽字符,请调用该函数的Unicode版本并将“\?\”添加到路径中。

dwDesiredAccess

将要执行的读写操作的权限设置。

  1. 0:不希望从设备读取数据或向设备写入数据。如果只想改变设备的配置(如:修改文件的时间戳),可以传0
  2. GENERIC_READ:允许对设备进行只读访问
  3. GENERIC_WRITE:允许对设备进行只写访问,该选项并没有隐含 GENERIC_READ标志

如果既要读操作也要写操作,那么就用一个 | (按位或)将读写的两个参数连接起来

dwShareMode
文件或设备的请求共享模式。

通俗的讲就是当首先调用这个API函数打开文件之后,如果有其他的函数也要打开该文件时,对其他程序的读写权限进行限制操作。

  1. 0: 要求独占对设备的访问。如果设备已经打开,CreateFile 调用会失败;如果成功地打开了设备,后续的 CreateFile 调用会失败
  2. FILE_SHARE_READ:如果有其他对象要用该设备,我们要求它们不得修改设备的数据;如果设备已经以写入方式或独占方式打开,那么CreateFile调用会失败。
  3. FILE_SHARE_WRITE:如果有其他内核对象要使用该设备,则要求它们不得读取设备的数据
  4. FILE_SHARE_DELETE: 当对文件进行操作的时候,我们不关心文件是否被逻辑删除或移动。在Windows内部,系统会先将文件标记为待删除,然后当该文件所有已打开的句柄都被关闭的时候,再将其真正的删除

lpSecurityAttributes

安全描述符,一般传递NULL。

dwCreationDisposition

采取存在或不存在的文件或设备的操作。

也就是对路径内的文件进行什么操作的参数。

  1. CREATE_NEW : 告诉CreateFile创建一个新文件,如果同名文件已经存在,那么 CreateFile调用会失败
  2. CREATE_ALWAYS:告诉CreateFile无论同名是否存在都创建新文件,若文件存在,则覆盖
  3. OPEN_EXISTING:告诉CreateFile打开一个已有的文件或设备,如果文件或设备不存在,那么CreateFile调用会失败
  4. OPEN_ALWAYS:告诉CreateFile打开一个已有的文件,如果文件存在,那么CreateFile会直接打开文件,如果不存在,则会创建一个新文件
  5. TRUNCATE_EXISTING:告诉CreateFile打开一个已有的文件并将文件大小截断为0字节,如果文件不存在,那么CreateFile调用会失败(相当于清空文件内容

dwFlagsAndAttributes

允许我们设置一些标志来微调与设备之间的通信;
如果设备是一个文件,我们还能够设置文件的属性。

这个参数可以传递的值和代表的功能很多,这里不一一列举,又需要再查。这里放常用的几个属性:

参数功能
FILE_ATTRIBUTE_ENCRYPTED文件是经过加密的
FILE_ATTRIBUTE_ARCHIVE应用程序用该标志来将文件标记为待备份或待删除。当CreateFile创建一个新文件时,会自动设置该标志
FILE_ATTRIBUTE_HIDDEN文件是隐藏的。它不会出现在通常的目录清单中
FILE_ATTRIBUTE_NORMAL文件没有其他属性。只有单独使用的时候,这个标志才有效
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED内容索引服务(content indexing service)不会对文件进行索引
FILE_ATTRIBUTE_OFFLINE文件虽然存在,但文件内容已经被转移到脱机存储中
FILE_ATTRIBUTE_READONLY文件只读
FILE_ATTRIBUTE_SYSTEM文件是操作系统的一部分,专供操作系统使用
FILE_ATTRIBUTE_TEMPORARY文件数据只会使用一小段时间。为了将访问时间降至最低,会尽量将文件数据保存在内存中

hTemplateFile

具有 GENERIC_READ 访问权限的模板文件的有效句柄。模板文件为正在创建的文件提供文件属性和扩展属性。该参数一般是NULL

返回值:

如果函数成功,则返回值的是指定文件、设备、命名管道或邮件插槽的句柄;
如果函数失败,则返回值为 INVALID_HANDLE_VALUE。 要获得扩展的错误信息,请调用GetLastError。

tips:

这个函数的返回值是一个句柄(handle),其实handle就类似与这个文件操作的代号,在后面,我们可以通过句柄对文件进行操作。

文件句柄的关闭:

CloseHandle

关闭一个内核对象。其中包括文件、文件映射、进程、线程、安全和同步对象等等。
在 CreateThread 成功之后会返回一个 hThread 的线程句柄,且内核对象的计数加1,CloseHandle之后,引用计数减1,当变为0时,系统删除该内核对象。
若在线程执行完之后,没有调用CloseHandle,在进程执行期间,将会造成内核对象的泄露,相当于句柄泄露,但不同于内存泄露,这势必会对系统的效率带来一定程度上的负面影响。但当进程结束退出后,系统会自动清理这些资源。其语法格式如下:

BOOL CloseHandle(
  HANDLE hObject
);

示例:

BOOL ret = CloseHandle(handle_vlaue); 

参数组成:

hObject:代表一个已经打开的对象句柄,例如:文件句柄,线程句柄,进程句柄等。

返回值:

TRUE:执行成功;
FALSE:执行失败,可以调用 GetLastError() 获得具体的执行失败原因。

获取文件大小:

GetFileSize:

顾名思义即是获得文件大小,该函数用于获取指定文件的大小(长度),以字节为单位。语法如下:

DWORD GetFileSize(
  HANDLE  hFile,
  LPDWORD lpFileSizeHigh
);

示例:

	HANDLE ret =  CreateFile(_T("D:\\test\\yms.txt"), GENERIC_READ , FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (ret != INVALID_HANDLE_VALUE)
	{
		//MessageBox(NULL, _T("ok"), _T("title"), MB_OK);
		DWORD sizehigh = 0;
		DWORD han = GetFileSize(ret, &sizehigh); //后面这个指针储存大小数据高32位的值
		LONGLONG lFileszie = ((LONGLONG)sizehigh << 32) | han; //强转为64位数据后左移32位再与低32位数据组合成一个完整的64位数据

		TCHAR filesize[128] = { 0 };
		_stprintf(filesize, _T("size of the file: %d"), han);
		MessageBox(NULL, filesize, _T("title"), NULL);
		CloseHandle(ret);
	}

参数:

hFile:待获取大小的文件句柄,该文件句柄必须具有 GENERIC_READ 或 GENERIC_WRITE 访问权限。

lpFileSizeHigh:指向一个 DWORD 变量的指针,该变量用于接收文件大小高端(第32-63位)部分的值。若不需获取这部分的值,该参数可以为 NULL 。(也就是超过32位大小的那部分值,也就是超过4GB的部分)

返回值:

如果函数调用成功,返回值为文件大小的低端(第0-31位)的值,如果 lpFileSizeHigh 参数不为 NULL ,该参数对应的变量包含文件大小的高端(第32-63位)部分的值。
如果函数调用失败,并且 lpFileSizeHigh 参数为 NULL ,则返回值为 INVALID_FILE_SIZE 。要获取更多错误信息,请调用 GetLastError 函数。
如果函数调用失败,并且 lpFileSizeHigh 参数不为 NULL ,返回值为 INVALID_FILE_SIZE ,调用 GetLastError 函数返回的错误代码为 NO_ERROR 以外的值。

GetFileSizeEx:

和 GetFileSize 函数的功能基本一致,该函数也是用于获取指定文件的大小(长度),以字节为单位!函数声明如下:

BOOL GetFileSizeEx(
  HANDLE         hFile,
  PLARGE_INTEGER lpFileSize
);

使用实例:

HANDLE ret =  CreateFile(_T("D:\\test\\yms.txt"), GENERIC_READ , FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (ret != INVALID_HANDLE_VALUE)
	{
		LARGE_INTEGER getfile = { 0 };
		BOOL han = GetFileSizeEx(ret, &getfile);

		TCHAR filesize[128] = { 0 };
		_stprintf(filesize, _T("size of the file: %lld"), getfile.QuadPart);
		MessageBox(NULL, filesize, _T("title"), NULL);
		CloseHandle(ret);
	}

注意要先有一个LARGE_INTERGER 的联合体指针,缓冲区的格式化字符串要变更为lld(longlong型)。

参数组成:

hFile:待获取大小的文件句柄,该文件句柄必须具有 GENERIC_READ 或 GENERIC_WRITE 访问权限。

lpFileSize: 输出参数,指向储存文件大小的一个 LARGE_INTEGER 联合体

LARGE_INTERGER的构成如下:

#if defined(MIDL_PASS)
typedef struct _LARGE_INTEGER {
#else // MIDL_PASS
typedef union _LARGE_INTEGER {
    struct {
        DWORD LowPart;
        LONG HighPart;
    } DUMMYSTRUCTNAME;
    struct {
        DWORD LowPart;
        LONG HighPart;
    } u;
#endif //MIDL_PASS
    LONGLONG QuadPart;
} LARGE_INTEGER;

返回值:

函数执行成功,返回TRUE
函数执行失败,返回FALSE,获取更多错误信息,请调用 GetLastError 函数。

文件的读写:

文件写操作:

WriteFile

从文件指针指向的位置开始将数据写入到一个文件中, 且支持同步和异步操作。
如果文件打开方式没有指明 FILE_FLAG_OVERLAPPED,当程序调用成功时,它将实际写入文件的字节数保存lpNumberOfBytesWriten 指明的地址空间中。
如果文件要交互使用的话,当函数调用完毕时要记得调整文件指针。函数声明如下:

BOOL WriteFile(
  HANDLE       hFile,
  LPCVOID      lpBuffer,
  DWORD        nNumberOfBytesToWrite,
  LPDWORD      lpNumberOfBytesWritten,
  LPOVERLAPPED lpOverlapped
);

使用实例:

		int num = 111;
		char c = 'y';
		DWORD realwrite = 0;
		BOOL bret = WriteFile(ret, &num, sizeof(int), &realwrite, NULL);
		if (bret)
		{
			MessageBox(NULL, _T("ok"), _T("title"), MB_OK);
		}
		else
		{
			DWORD dwerror = GetLastError();
			MessageBox(NULL, _T("fall"), _T("title"), MB_OK);
		}
		CloseHandle(ret);

参数组成:

**hFile:**需要写入数据的已打开的文件句柄,这个句柄所关联的文件必须拥有 GENERIC_WRITE 访问权限属性的文件;
**lpBuffer:**要写入到文件的缓冲区首地址;
**nNumberOfBytesToWrite:**要写入数据的字节数量。如写入零字节,表示什么都不写入,但会更新文件的“上一次修改时间”;
**lpNumberOfBytesWritten:**实际写入文件的字节数量,此变量是用来返回的 ;
**lpOverlapped:**倘若在指定 FILE_FLAG_OVERLAPPED 标志的前提下打开文件,指针不能为空,这个参数就必须引用一个特殊的结构。那个结构定义了一次异步写操作。否则,该参数应置为空;

tips:

在写入文本文件时,如果内容为中文或其他符号,则会出现乱码的情况,这是由于编码方式设置的问题,在创建文本文档时一般默认为ANSI编码方式,而VS的编码方式是Unicode。需要在执行写操作时写入一个Unicode编码方式的前缀,如下:

         DWORD dwWrite = 0;
		wchar_t szbuf[] = _T("我真美,与自然融合之美!");
		static const BYTE unicodehead[] = { 0xFF, 0xFE };
		WriteFile(ret, &unicodehead, sizeof(unicodehead), &dwWrite, NULL);
		BOOL Bret = WriteFile(ret, &szbuf, sizeof(szbuf), &dwWrite, NULL);
		CloseHandle(ret);

文件读操作:

ReadFile

从文件指针指向的位置开始将文件数据读入内存中, 且支持同步和异步操作。
如果文件打开方式没有指明 FILE_FLAG_OVERLAPPED 的话,当程序调用成功时,它将实际读出文件的字节数保存到 lpNumberOfBytesRead 指明的地址空间中。
从文件中读出数据,与 C语言的 fread函数相比,这个函数要灵活的多,适用的场景也很多。该函数能够操作通信设备、管道、套接字以及邮槽。

函数声明如下:

BOOL ReadFile (
    HANDLE hFile,
    LPVOID lpBuffer,
    DWORD nNumberOfBytesToRead,
    LPDWORD lpNumberOfBytesRead,
    LPOVERLAPPED lpOverlapped
);

使用实例:

HANDLE ret = CreateFile(_T("D:\\test\\yms.txt"), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
			int ret_num = 0;
			DWORD acRead;
			BOOL Rret = ReadFile(ret, &ret_num, sizeof(ret_num), &acRead, NULL);
			FlushFileBuffers(ret);

参数组成:

hFile:需要读入数据的文件指针,这个指针指向的文件必须是 GENERIC_READ 访问属性的文件;
lpBuffer:接收读入文件数据的缓冲区;
nNumberOfBytesToRead:指定要读取的字节数;
lpNumberOfBytesRead:指向一个DWORD类型变量的指针,用来接收实际读取的字节数(实际读取的字节数很可能比要读取的字节数小);
lpOverlapped:OVERLAPPED 结构体指针,如果文件是以 FILE_FLAG_OVERLAPPED 方式打开的话,那么这个指针就不能为 NULL。FILE_FLAG_OVERLAPPED 允许对文件进行重叠操作,或者说异步操作。

返回值:

函数调用成功,返回TRUE,
调用失败,返回FALSE。

tips:

在完成文件写入后,准备写入的数据并没有直接进入到对应的文件当中,而是在缓存当中(也就是缓冲区之中)。我们学刷新文件内存才能让这些数据实际的进入文件之中。这里需要用到一个API函数:FlushFileBuffers 也就是刷新文件缓冲区的意思,使用如下:

FlushFileBuffers(ret);

这里面还涉及到一个文件指针的问题,下面会解释。

文件指针:

文件指针的用途:

主要用于文件的读写

打开一个文件之后,默认与之产生了一个内部的记录文件位置的指针,用于指示当前读写位置。完成读写操作后,指针会自动后移,读写了多少字节,指针就会向后移动多少字节。

SetFilePointer:

使用 SetFilePointer 函数设置文件当前的读写位置。其函数声明如下:

DWORD SetFilePointer(
  HANDLE hFile,
  LONG   lDistanceToMove,
  PLONG  lpDistanceToMoveHigh,
  DWORD  dwMoveMethod
);

使用实例:

HANDLE ret = CreateFile(_T("D:\\test\\yms.txt"), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
char ret_str[32] = { 0 };
int ret_num = 0;
student s2;
DWORD acRead;
SetFilePointer(ret, sizeof(int) + sizeof(char), NULL, FILE_BEGIN);
BOOL Rret = ReadFile(ret, &ret_str, sizeof(ret_str), &acRead, NULL);
Rret = ReadFile(ret, &s2, sizeof(s2), &acRead, NULL);

参数组成:

hFile:已打开的文件句柄,必须拥有 GENERIC_READ 或者 GENERIC_WRITE 访问权限;
lDistanceToMove:低32位的有符号的(有负有正)的值,指定要移动文件指针的字节数。如果lpDistanceToMoveHigh不为NULL,则lpDistanceToMoveHigh和lDistanceToMove将形成一个指定要移动的距离的单个64位有符号值。 如果lpDistanceToMoveHigh为NULL,则lDistanceToMove是一个32位有符号值。 lDistanceToMove的正值在文件中向前移动文件指针,负值则向后移动文件指针。
lpDistanceToMoveHigh:指向要移动的有符号64位距离的高32位。 如果你不需要高位的32位,这个指针必须设置为NULL。 当非NULL时,该参数还接收文件指针新值的高位DWORD。
dwMoveMethod:设置文件指针的移动起点的位置:FILE_BEGIN=>从文件头开始往后移动,FILE_CURRENT=>从文件的当前指针位置开始移动,FILE_END=>从文件尾部开始往前移动(从后往前移的话前面的移动距离应该是负数)。

返回值:

如果SetFilePointer函数成功并且lpDistanceToMoveHigh为NULL,则返回值是新文件指针的低位DWORD。 如果lpDistanceToMoveHigh不为NULL,则函数返回新文件指针的低位DWORD,并将新文件指针的高位DWORD放入该参数指向的LONG中。
如果函数失败并且lpDistanceToMoveHigh为NULL,则返回值为INVALID_SET_FILE_POINTER。 要获得扩展的错误信息,请调用GetLastError。
如果函数失败,并且lpDistanceToMoveHigh非空,则返回值为INVALID_SET_FILE_POINTER。 但是,由于INVALID_SET_FILE_POINTER是新文件指针的低位DWORD的有效值,因此必须检查GetLastError以确定是否发生错误。 如果发生错误,GetLastError返回非NO_ERROR值。
如果新文件指针的值为负值,则函数失败,文件指针不移动,GetLastError返回的代码为ERROR_NEGATIVE_SEEK

SetFilePointerEx:

上一个函数的扩展使用,与getfilesizeex相同,避免了设置文件大小大于4G时高位的数字的传输,使用large_integer这个联合体来代替,函数声明如下:

BOOL SetFilePointerEx(
        HANDLE    hFile,
        LARGE_INTEGER    liDistanceToMove,
        PLARGE_INTEGER    pliNewFilePointer,
        DWORD    dwMoveMethod
);

使用实例:

int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
        //打开文件
        HANDLE hFile = CreateFile(_T("D:\\notepad.exe"), GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
        if (hFile == INVALID_HANDLE_VALUE)
        {
                MessageBox(NULL, _T("文件打开失败!"), _T("Tip"), MB_OK);
                return -1;
        }

        DWORD dwFileSize = GetFileSize(hFile, NULL);

        //设置文件指针
        LARGE_INTEGER lDistance = { 0 };
        lDistance.QuadPart = dwFileSize;
        SetFilePointerEx(hFile, lDistance, NULL, FILE_BEGIN);

        int num = 123;
        DWORD dwRealWrite = 0;
        BOOL bRet = WriteFile(hFile, &num, sizeof(int), &dwRealWrite, NULL);
        if (bRet)
        {
                MessageBox(NULL, _T("数据写入成功!"), _T("Tip"), MB_OK);
        }
        else
        {
                MessageBox(NULL, _T("数据写入失败!"), _T("Tip"), MB_OK);
        }

        CloseHandle(hFile);

        
        hFile = CreateFile(_T("D:\\notepad.exe"), GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
        if (hFile == INVALID_HANDLE_VALUE)
        {
                MessageBox(NULL, _T("文件打开失败!"), _T("Tip"), MB_OK);
                return -1;
        }

        //从文件中读数据
        int ret_num = 0;
        DWORD dwRealRead = 0;

        //设置文件指针
        LARGE_INTEGER lDistance2 = { 0 };
        int MoveSize = sizeof(int) * -1;
        lDistance2.QuadPart = MoveSize;
        SetFilePointerEx(hFile, lDistance2, NULL, FILE_END);
        bRet = ReadFile(hFile, &ret_num, sizeof(ret_num), &dwRealRead, NULL);
        if (bRet)
        {
                MessageBox(NULL, _T("数据读取成功!"), _T("Tip"), MB_OK);
        }
        else
        {
                MessageBox(NULL, _T("数据读取失败!"), _T("Tip"), MB_OK);
        }

        CloseHandle(hFile);
        return 0;
}

参数组成:

hFile:已打开的文件句柄,必须拥有 GENERIC_READ 或者 GENERIC_WRITE 访问权限;
liDistanceToMove:标识文件指针要移动多少个字节;
pliNewFilePointer:系统会在pliNewFilePointer参数指向的 LARGE_INTEGER 结构体中保存文件指针的新值;
dwMoveMethod:标识移动文件指针的三种方式,FILE_BEGIN、FILE_CURRENT、FILE_END,

返回值:

函数执行成功返回TRUE,函数执行失败返回FALSE,获得更多错误信息请调用:GetLastError

CreateDirectory:

CreateDirectory 函数创建一个新的单一层级的目录。 如果底层文件系统支持文件和目录的安全性,则该函数将指定的安全描述符应用于新目录。
如需自动建立多层级目录请使用:MakeSureDirectoryPathExists 函数。函数声明如下:

BOOL CreateDirectory(
  LPCTSTR lpPathName,
  LPSECURITY_ATTRIBUTES lpSecurityAttributes
);

这里注意这个函数只能用于创建已存在目录下的单层及目录(也就是只能创建一个子目录)

使用实例:

CreateDirectory(_T("D:\\2"), NULL);

参数组成:

lpPathName:指向一个以空字符结尾的字符串,指定要创建的目录的路径。
lpSecurityAttributes:指向SECURITY_ATTRIBUTES结构的指针。 该结构的lpSecurityDescriptor成员为新目录指定安全描述符。 如果lpSecurityAttributes为NULL,则该目录将获取默认的安全描述符。 目标文件系统必须支持文件和目录的安全性才能使此参数有效。

返回值:

如果函数成功,返回值为TRUE。
如果函数失败,返回值为FALSE。 要获得更多的错误信息,请调用GetLastError。

扩展:

_tcscpy(pszSrc, lpPathName):针对不定字符串的拷贝,与strcpy功能类似。

_tcstok:同样的,通用情况下的切片获取。与string中的split类似,以给定的分隔符获取对应区间的切片,比如:

CString str = _T("192.168.89.125");

TCHAR seps[] = _T(".");

TCHAR* token = _tcstok( (LPTSTR)(LPCTSTR)str, seps );

这样即可获取对应的192 168 89 125这些切片

第一次调用的时候,函数会忽略出现在strToken串开始的分隔符,返回找到的Token指针,用空字符(NULL character )替换掉已经查找到的部分(包括分隔符)并把“新”串保存到一个Static变量中(系统来完成);

如果下次调用时第一个参数为NULL的话,函数从Static变量中取出串,根据分隔符得到并返回新Token,用空字符(NULL character )替换掉已经查找到的部分(包括分隔符)并重新保存“新”串;

如此循环,直到循环条件结束。

_tcscat(szPath, pToken):通用的字符串衔接功能,将后面的ptoken衔接到szpath后面,pToken可以为一个指针,与 _tcsok配合使用

自定义一个创建多级目录的函数:

BOOL CreateDeepDirectory(LPCTSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes)
{
        if (PathFileExists(lpPathName)) return TRUE;

        TCHAR szPath[MAX_PATH] = { 0 };
        TCHAR pszSrc[MAX_PATH] = { 0 };
        _tcscpy(pszSrc, lpPathName);
        TCHAR* pToken = _tcstok(pszSrc, _T("\"));
        while (pToken)
        {
                _tcscat(szPath, pToken);
                _tcscat(szPath, _T("\"));
                if (!PathFileExists(szPath))
                {
                      if (!CreateDirectory(szPath, lpSecurityAttributes)) return FALSE;
                }

                pToken = _tcstok(NULL, _T("\"));
        }

        return TRUE;
}

RemoveDirectory:

RemoveDirectory 函数删除一个现有的不包含任何文件的空目录。要删除非空目录请调用:SHFileOperation

函数声明如下:

BOOL RemoveDirectory(
  LPCTSTR lpPathName
);

参数组成:

lpPathName:指向一个以空字符结尾的字符串,指定要删除的目录的路径。 路径必须指定一个空目录,并且调用进程必须具有对目录的删除访问权限。

返回值:

如果函数成功,返回值为TRUE。
如果函数失败,返回值为FALSE。 要获得更多的错误信息,请调用GetLastError。

文件的遍历与查找:

FindFirstFile:

根据文件名查找文件。该函数到一个文件夹(包括子文件夹)去搜索指定文件,如果要使用附加属性去搜索文件的话 可以使用FindFirstFileEx函数。函数声明如下:

HANDLE FindFirstFile(
  LPCTSTR             lpFileName,
  LPWIN32_FIND_DATA lpFindFileData
);

参数组成:

lpFileName:要搜索的文件名,支持通配符:
C:\Windows*.* //在C:\Windows目录中查找所有文件;
C:\Windows\System32*.dll //在 C:\Windows\System32 目录中查找所有dll类型的文件;
C:\Windows\System.ini //在 C:\Windows 目录中查找 System.ini 文件;
C:\Windows\a???.* //在 C:\Windows 目录中查找所有以a开头的文件名长度为4个字符的文件;
Test.dat //在当前目录查找 Test.dat 文件
. //在当前目录查找所有文件

lpFindFileData:WIN32_FIND_DATA 类型,该结构用于装载与找到的文件有关的信息。该结构可用于后续的遍历与搜索。

结构WIN32_FIND_DATA的成员变量里包含了文件的各个属性:

typedef struct _WIN32_FIND_DATA
{
        DWORD dwFileAttributes;                //文件属性
        FILETIME ftCreationTime;                //文件创建时间
        FILETIME ftLastAccessTime;                //文件最后一次访问时间
        FILETIME ftLastWriteTime;                //文件最后一次修改时间
        DWORD nFileSizeHigh;                        //文件长度高32位
        DWORD nFileSizeLow;                        //文件长度低32位
        DWORD dwReserved0;                        //系统保留
        DWORD dwReserved1;                        //系统保留
        TCHAR cFileName[MAX_PATH];        //长文件名
        TCHAR cAlternateFileName[14];        //8.3格式文件名
} WIN32_FIND_DATA, *PWIN32_FIND_DATA;

在使用这个结构时不能手工修改这个结构中的任何数据,结构对于开发人员来说只能作为一个只读数据,其所有的成员变量都会由系统完成填写。

当用dwFileAttributes获取文件属性时可以获得一下值:

属性值属性说明
FILE_ATTRIBUTE_ARCHIVE标示一个文件(或目录)是一个存档文件(或目录)
FILE_ATTRIBUTE_COMPRESSED标示一个文件(或目录)是一个压缩文件(或目录) 用于文件时:该文件中所有的记录都是经过压缩的 用于目录时:在该目录下新建文件或子目录时会默认进行压缩
FILE_ATTRIBUTE_DEVICE未使用
FILE_ATTRIBUTE_DIRECTORY此句柄被视为一个目录
FILE_ATTRIBUTE_ENCRYPTED标示一个文件(或目录)是一个加密文件(或目录) 用于文件时:该文件中所有的记录都是经过加密的,包括读写操作 用于目录时:在该目录下新建文件或子目录时会默认进行加密
FILE_ATTRIBUTE_HIDDEN标示一个文件(或目录)是一个隐藏文件(或目录)
FILE_ATTRIBUTE_NORMAL标示一个文件(或目录)不具有其他属性,此属性只能单独使用
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED标示一个文件不可被内容索引服务索引
FILE_ATTRIBUTE_OFFLINE标示一个文件是脱机文件,该文件中的内容无法直接使用 如果某个文件具有该属性,请不要轻易修改此属性,它可能是某些远程存储服务程序的存储文件
FILE_ATTRIBUTE_READONLY标示一个文件(或目录)是一个只读文件(或目录) 用于文件时:只能读取文件内容,无法修改或删除 用于目录时:该目录无法删除
FILE_ATTRIBUTE_REPARSE_POINT标示一个文件(或目录)拥有相关的重新解析点,比如用mklink创建的硬链接(hardLink)或符号链接(symbolic link)
FILE_ATTRIBUTE_SPARSE_FILE标示一个文件是稀疏文件
FILE_ATTRIBUTE_SYSTEM标示一个文件(或目录)是一个系统文件(或目录)
FILE_ATTRIBUTE_TEMPORARY标示一个文件是临时文件
FILE_ATTRIBUTE_VIRTUAL标示一个文件是系统文件

返回值:

如果函数成功,返回一个 HANDLE 类型的文件搜索句柄,搜索/遍历完成后,应用 FindClose 函数关闭这个句柄;
如果函数失败,返回值为 INVALID_HANDLE_VALUE。 要获得更多的错误信息,请调用GetLastError。

FindNextFile:

可以用来遍历目录或文件,判断当前目录下是否有下一个目录或文件。函数声明如下:

BOOL FindNextFile(
  HANDLE             hFindFile,
  LPWIN32_FIND_DATA lpFindFileData
);

参数组成:

hFindFile:上一次查找返回的搜索文件句柄
lpFindFileData:WIN32_FIND_DATA 类型,该结构用于装载与找到的文件有关的信息。该结构可用于后续的遍历与搜索。

返回值:

如果函数成功,返回值为 TRUE;
如果函数失败,返回值为 FALSE,如果不再有与指定条件相符的文件,调用 GetLastError 会返回 ERROR_NO_MORE_FILES 错误码,要获得更多的错误信息,请调用GetLastError。

字符串的转化:

WideCharToMultiByte

参考网址:https://www.cnblogs.com/vranger/p/3793123.html

获取磁盘分区信息:

GetLogicalDriveStrings:

获取一个字串,其中包含了当前所有逻辑驱动器的根驱动器路径。函数声明如下:

DWORD GetLogicalDriveStrings(
  DWORD  nBufferLength,
  LPTSTR lpBuffer
);

使用实例:

		TCHAR* rSize = new TCHAR[ret + 10];
		ZeroMemory(rSize, (ret + 10) * sizeof(TCHAR));
		ret = GetLogicalDriveStrings(ret + 10, rSize);

参数说明:

nBufferLength:
lpBuffer 指针指向的字符串缓冲区的以 TCHAR 字符为单位的最大长度,不包括结尾的 0 结束符。如果该参数传递0,lpBuffer 就没有用处了。

lpBuffer:
指向一个字符串缓冲区的首地址,用于接收返回的字符串内容,每个驱动器之间以1个0结束符为间隔,总体结束以2个0结束符为标志。

返回值:

如果函数执行成功,返回实际拷贝到 lpBuffer 指针指向的字符串缓冲区的字符数,不包括 0 结束符。
如果 lpBuffer 指针指向的字符串缓冲区大小不够,返回值返回实际需要的字符串缓冲区的空间长度,这个长度肯定会比传入的 nBufferLength 长。
如果函数执行失败,返回值是0,想要获得更多的错误信息,请调用 GetLastError 函数获取。

GetDriveType:

用来确定磁盘驱动器的类型,是可移动的、固定的、CD-ROM、RAM磁盘还是网络驱动器。函数声明 如下:

UINT GetDriveType(
  LPCTSTR lpRootPathName
);

使用实例:

UINT type = GetDriveType(szDrive);

参数说明:

lpRootPathName:
分区的根目录,字符串结尾要带上反斜线 \,如果该参数传递 NULL,函数使用当前目录的根目录为准。

返回值;

返回值为该磁盘分区的类型,可能有以下值:
DRIVE_UNKNOWN(0):未知的磁盘类型
DRIVE_NO_ROOT_DIR(1):说明 lpRootPathName 是无效的
DRIVE_REMOVABLE(2):可移动磁盘
DRIVE_FIXED(3):固定磁盘
DRIVE_REMOTE(4):网络磁盘
DRIVE_CDROM(5):光驱
DRIVE_RAMDISK(6):为RAM

Windows的窗口程序:

窗口程序创建流程:

  1. 注册窗口类,指定窗口类的名称与窗口回调函数
  2. 创建窗口,指定注册窗口类,窗口大小
  3. 显示窗口
  4. 开始消息循环
  5. 窗口函数中处理窗口消息

RegisterClassEx:

为随后在调用 Createwindow 函数和 CreatewindowEx 函数中使用的窗口注册一个窗口类。语法格式如下:

ATOM WINAPI RegisterClassEx(
  const WNDCLASSEX *lpwcx
);

参数说明:

**Ipwcx:**指向一个 WNDCLASSEX 结构的指针。在传递给这个函数之前,必须在结构内填充适当的类的属性。
WNDCLASSEX 属于一个窗口类,WNDCLASSEX 中最重要的成员莫过于lpfnWndProc了。前缀 lpfn 表示该成员是一个指向函数的指针。该函数就是窗口函数,或者说处理窗口消息的回调函数。
每一个窗口类必须有一个窗口函数,当 Windows 把属于特定窗口的消息发送给该窗口时,该窗口的窗口类负责处理所有的消息,如键盘消息或鼠标消息。由于窗口函数差不多智能地处理了所有的窗口消息循环,所以您只要在其中加入消息处理过程即可。

WNDCLASSEX 结构体原型:

typedef struct tagWNDCLASSEX {
  UINT      cbSize;
  UINT      style;
  WNDPROC   lpfnWndProc;
  int       cbClsExtra;
  int       cbWndExtra;
  HINSTANCE hInstance;
  HICON     hIcon;
  HCURSOR   hCursor;
  HBRUSH    hbrBackground;
  LPCTSTR   lpszMenuName;
  LPCTSTR   lpszClassName;
  HICON     hIconSm;
} WNDCLASSEX, *PWNDCLASSEX;

1、cbSize:
WNDCLASSEX 的大小。我们可以用sizeof(WNDCLASSEX)来获得准确的值。
2、style:
从这个窗口类派生的窗口具有的风格。您可以用“or”操作符来把几个风格或到一起。
3、lpfnWndProc: (这个参数非常重要,它是消息队列的处理函数)
窗口处理函数的指针。

这个函数在程序中作为一个回调函数供系统调用,下面是一个编写示例:

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	PAINTSTRUCT ps;
	HDC hdc;
	TCHAR greeting[] = _T("你好,世界!");

	switch (uMsg)
	{
	case WM_PAINT:
		hdc = BeginPaint(hwnd, &ps);
		TextOut(hdc, 5, 5, greeting, _tcslen(greeting));
		EndPaint(hwnd, &ps);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hwnd, uMsg, wParam, lParam);
		break;
	}
	return 0;
}

HWND hWnd : 事件引起消息发生的那个窗口。
UINT message: 消息的ID,它是32位值,指明了消息类型。
WPARAM wParam : 32位值,包含附加信息,决定于消息的种类。例如键盘的哪个键代码。
LPARAM lParam: 32位值

4、cbClsExtra:
指定紧跟在窗口类结构后的附加字节数。
5、cbWndExtra:
指定紧跟在窗口实例的附加字节数。如果一个应用程序在资源中用CLASS伪指令注册一个对话框类时,则必须把这个成员设成DLGWINDOWEXTRA。
6、hInstance:
本模块的实例句柄。
7、hIcon:
图标的句柄。
8、hCursor:
光标的句柄。
9、hbrBackground:
背景画刷的句柄。
10、lpszMenuName:
指向菜单的指针。
11、lpszClassName:
指向类名称的指针。
12、hIconSm:
和窗口类关联的小图标。如果该值为NULL。则把hIcon中的图标转换成大小合适的小图标。

返回值:

如果函数成功,返回这个窗口类型的标识号;如果函数失败,返回值为FALSE。若想获得更多错误信息,请调用GetLastError函数。

CreateWindow:

创建一个重叠窗口,弹出窗口或子窗口。 它指定窗口类,窗口标题,窗口样式,以及(可选)窗口的初始位置和大小。 该函数还指定窗口的父级或所有者(如果有)以及窗口的菜单。
除了CreateWindow支持的样式之外,要使用扩展的窗口样式,请使用CreateWindowEx函数。函数说明:

HWND WINAPI CreateWindow(
  LPCTSTR   lpClassName,
  LPCTSTR   lpWindowName,
  DWORD     dwStyle,
  int       x,
  int       y,
  int       nWidth,
  int       nHeight,
  HWND      hWndParent,
  HMENU     hMenu,
  HINSTANCE hInstance,
  LPVOID    lpParam
);

参数说明:

lpClassName:
指向一个空结束的字符串或整型数atom。如果该参数是一个整型量,它是由此前调用theGlobalAddAtom函数产生的全局量。这个小于0xC000的16位数必须是lpClassName参数字的低16位,该参数的高位必须是0。
如果lpClassName是一个字符串,它指定了窗口的类名。这个类名可以是任何用函数RegisterClass注册的类名,或是任何预定义的控制类名。请看说明部分的列表。

lpWindowName:
指向一个指定窗口名的空结束的字符串指针。
如果窗口风格指定了标题条,由lpWindowName指向的窗口标题将显示在标题条上。当使用Createwindow函数来创建控制例如按钮,选择框和静态控制时,可使用lpWindowName来指定控制文本。

dwStyle:
指定创建窗口的风格。该参数可以是下列窗口风格的组合再加上说明部分的控制风格。风格意义:
WS_BORDER:创建一个带边框的窗口。
WS_CAPTION:创建一个有标题框的窗口(包括WS_BORDER风格)。
WS_CHILD:创建一个子窗口。这个风格不能与WS_POPUP风格合用。
WS_CHILDWINDOW:与WS_CHILD相同。
WS_CLIPCHILDREN:当在父窗口内绘图时,排除子窗口区域。在创建父窗口时使用这个风格。
WS_CLIPSIBLINGS:排除子窗口之间的相对区域,也就是,当一个特定的窗口接收到WM_PAINT消息时,WS_CLIPSIBLINGS 风格将所有层叠窗口排除在绘图之外,只重绘指定的子窗口。如果未指定WS_CLIPSIBLINGS风格,并且子窗口是层叠的,则在重绘子窗口的客户区时,就会重绘邻近的子窗口。
WS_DISABLED:创建一个初始状态为禁止的子窗口。一个禁止状态的窗口不能接受来自用户的输入信息。
WS_DLGFRAME:创建一个带对话框边框风格的窗口。这种风格的窗口不能带标题条。
WS_GROUP:指定一组控制的第一个控制。这个控制组由第一个控制和随后定义的控制组成,自第二个控制开始每个控制,具有WS_GROUP风格,每个组的第一个控制带有WS_TABSTOP风格,从而使用户可以在组间移动。用户随后可以使用光标在组内的控制间改变键盘焦点。
WS_HSCROLL:创建一个有水平滚动条的窗口。
WS_ICONIC:创建一个初始状态为最小化状态的窗口。与WS_MINIMIZE风格相同。
WS_MAXIMIZE:创建一个初始状态为最大化状态的窗口。
WS_MAXIMIZEBOX:创建一个具有最大化按钮的窗口。该风格不能与WS_EX_CONTEXTHELP风格同时出现,同时必须指定WS_SYSMENU风格。
WS_OVERLAPPED:产生一个层叠的窗口。一个层叠的窗口有一个标题条和一个边框。与WS_TILED风格相同。
WS_OVERLAPPEDWINDOW:创建一个具有WS_OVERLAPPED,WS_CAPTION,WS_SYSMENU WS_THICKFRAME,WS_MINIMIZEBOX,WS_MAXIMIZEBOX风格的层叠窗口,与WS_TILEDWINDOW风格相同。
WS_POPUP:创建一个弹出式窗口。该风格不能与WS_CHILD风格同时使用。
WS_POPUPWINDOW:创建一个具有WS_BORDER,WS_POPUP,WS_SYSMENU风格的窗口,WS_CAPTION和WS_POPUPWINDOW必须同时设定才能使窗口某单可见。
WS_SIZEBOX:创建一个可调边框的窗口,与WS_THICKFRAME风格相同。
WS_SYSMENU:创建一个在标题条上带有窗口菜单的窗口,必须同时设定WS_CAPTION风格。
WS_TABSTOP:创建一个控制,这个控制在用户按下Tab键时可以获得键盘焦点。按下Tab键后使键盘焦点转移到下一具有WS_TABSTOP风格的控制。
WS_THICKFRAME:创建一个具有可调边框的窗口,与WS_SIZEBOX风格相同。
WS_TILED:产生一个层叠的窗口。一个层叠的窗口有一个标题和一个边框。与WS_OVERLAPPED风格相同。
WS_TILEDWINDOW:创建一个具有WS_OVERLAPPED,WS_CAPTION,WS_SYSMENU, WS_THICKFRAME,WS_MINIMIZEBOX,WS_MAXIMIZEBOX风格的层叠窗口。与WS_OVERLAPPEDWINDOW风格相同。
WS_VISIBLE:创建一个初始状态为可见的窗口。
WS_VSCROLL:创建一个有垂直滚动条的窗口。

x:
指定窗口的初始水平位置。对一个层叠或弹出式窗口,X参数是屏幕坐标系的窗口的左上角的初始X坐标。对于子窗口,x是子窗口左上角相对父窗口客户区左上角的初始X坐标。如果该参数被设为CW_USEDEFAULT则系统为窗口选择缺省的左上角坐标并忽略Y参数。CW_USEDEFAULT只对层叠窗口有效,如果为弹出式窗口或子窗口设定,则X和y参数被设为零。

y:
指定窗口的初始垂直位置。对一个层叠或弹出式窗口,y参数是屏幕坐标系的窗口的左上角的初始y坐标。对于子窗口,y是子窗口左上角相对父窗口客户区左上角的初始y坐标。对于列表框,y是列表框客户区左上角相对父窗口客户区左上角的初始y坐标。如果层叠窗口是使用WS_VISIBLE风格位创建的并且X参数被设为CW_USEDEFAULT,则系统将忽略y参数。

nWidth:
以设备单元指明窗口的宽度。对于层叠窗口,nWidth或是屏幕坐标的窗口宽度或是CW_USEDEFAULT。若nWidth是CW_USEDEFAULT,则系统为窗口选择一个缺省的高度和宽度:缺省宽度为从初始X坐标开始到屏幕的右边界,缺省高度为从初始Y坐标开始到目标区域的顶部。CW_USEDEFAULT只对层叠窗口有效;如果为弹出式窗口和子窗口设定CW_USEDEFAULT标志则nWidth和nHeight被设为零。

nHeight:
以设备单元指明窗口的高度。对于层叠窗口,nHeight是屏幕坐标的窗口宽度。若nWidth被设为CW_USEDEFAULT,则系统忽略nHeight参数。

hWndParent:
指向被创建窗口的父窗口或所有者窗口的句柄。若要创建一个子窗口或一个被属窗口,需提供一个有效的窗口句柄。这个参数对弹出式窗口是可选的。Windows NT 5.0;创建一个消息窗口,可以提供HWND_MESSAGE或提供一个己存在的消息窗口的句柄。

hMenu:
菜单句柄,或依据窗口风格指明一个子窗口标识。对于层叠或弹出式窗口,hMenu指定窗口使用的菜单:如果使用了菜单类,则hMenu可以为NULL。对于子窗口,hMenu指定了该子窗口标识(一个整型量),一个对话框使用这个整型值将事件通知父类。应用程序确定子窗口标识,这个值对于相同父窗口的所有子窗口必须是唯一的。

hlnstance:
与窗口相关联的模块实例的句柄。(也就是入口函数参数中的那一个实例句柄)

lpParam:
指向一个值的指针,该值传递给窗口WM_CREATE消息。该值通过在IParam参数中的CREATESTRUCT结构传递。如果应用程序调用CreateWindow创建一个MDI客户窗口,则lpParam必须指向一个CLIENTCREATESTRUCT结构。
返回值:如果函数成功,返回值为新窗口的句柄:如果函数失败,返回值为NULL。若想获得更多错误信息,请调用GetLastError函数。

备注:
在返回前,CreateWindow给窗口过程发送一个WM_CREATE消息。对于层叠,弹出式和子窗口,CreateWindow给窗口发送WM_CREATE,WM_GETMINMAXINFO和WM_NCCREATE消息。消息WM_CREATE的IParam参数包含一个指向CREATESTRUCT结构的指针。如果指定了WS_VISIBLE风格,CreateWindow向窗口发送所有需要激活和显示窗口的消息。

ShowWindow:

该函数设置指定窗口的显示状态。函数声明如下:

BOOL ShowWindow(
  HWND hWnd,
  int  nCmdShow
);

参数说明:

**hWnd:**指窗口句柄;
**nCmdShow:**指定窗口如何被显示。如果发送应用程序的程序提供了 STARTUPINFO 结构,则应用程序第一次调用 ShowWindow 时该参数被忽略。否则,在第一次调用ShowWindow函数时,该值应为在函数WinMain中nCmdShow参数。
在随后的调用中,该参数可以为下列值之一:
**SW_FORCEMINIMIZE:**在 WindowNT 5.0 中最小化窗口,即使拥有窗口的线程被挂起也会最小化。在从其他线程最小化窗口时才使用这个参数。nCmdShow = 11。
**SW_HIDE:**隐藏窗口并激活其他窗口。nCmdShow = 0。
**SW_MAXIMIZE:**最大化指定的窗口。nCmdShow = 3。
**SW_MINIMIZE:**最小化指定的窗口并且激活在Z序中的下一个顶层窗口。nCmdShow = 6。
**SW_RESTORE:**激活并显示窗口。如果窗口最小化或最大化,则系统将窗口恢复到原来的尺寸和位置。在恢复最小化窗口时,应用程序应该指定这个标志。nCmdShow = 9。
**SW_SHOW:**在窗口原来的位置以原来的尺寸激活和显示窗口。nCmdShow = 5。
**SW_SHOWDEFAULT:**依据在STARTUPINFO结构中指定的SW_FLAG标志设定显示状态,STARTUPINFO 结构是由启动应用程序的程序传递给CreateProcess函数的。nCmdShow = 10。
SW_SHOWMAXIMIZED:激活窗口并将其最大化。nCmdShow = 3。
SW_SHOWMINIMIZED:激活窗口并将其最小化。nCmdShow = 2。
SW_SHOWMINNOACTIVE:窗口最小化,激活窗口仍然维持激活状态。nCmdShow = 7。
SW_SHOWNA:以窗口原来的状态显示窗口。激活窗口仍然维持激活状态。nCmdShow = 8。
SW_SHOWNOACTIVATE:以窗口最近一次的大小和状态显示窗口。激活窗口仍然维持激活状态。nCmdShow = 4。
SW_SHOWNORMAL:激活并显示一个窗口。如果窗口被最小化或最大化,系统将其恢复到原来的尺寸和大小。应用程序在第一次显示窗口的时候应该指定此标志。nCmdShow = 1。

返回值:

如果窗口之前可见,则返回值为非零。如果窗口之前被隐藏,则返回值为零。

GetMessage:

调用线程的消息队列里取得一个消息并将其放于指定的结构。此函数可取得与指定窗口联系的消息和由PostThreadMessage寄送的线程消息。此函数接收一定范围的消息值。GetMessage不接收属于其他线程或应用程序的消息。获取消息成功后,线程将从消息队列中删除该消息。函数会一直等待直到有消息到来才有返回值。(用人话说就是获取消息的函数),函数声明如下:

BOOL GetMessage(
  LPMSG lpMsg,
  HWND  hWnd,
  UINT  wMsgFilterMin,
  UINT  wMsgFilterMax
);

参数说明:

lpMsg:指向MSG结构的指针,该结构从线程的消息队列里接收消息信息。
hWnd:取得其消息的窗口的句柄。当其值取NULL时,GetMessage为任何属于调用线程的窗口检索消息,线程消息通过PostThreadMessage寄送给调用线程。
wMsgFilterMin:指定被检索的最小消息值的整数。
wMsgFilterMax:指定被检索的最大消息值的整数。

返回值:

如果函数取得 WM_QUIT 之外的其他消息,返回非零值。如果函数取得 WM_QUIT 消息,返回值是零。如果出现了错误,返回值是-1。
例如,当hWnd是无效的窗口句柄或lpMsg是无效的指针时。若想获得更多的错误信息,请调用GetLastError函数。

TranslateMessage:

用于将虚拟键消息转换为字符消息。函数声明如下:

BOOL TranslateMessage(
  const MSG *lpMsg
);

参数说明:

IpMsg:指向含有消息的MSG结构的指针,该结构里含有用函数GetMessage或PeekMessage从调用线程的消息队列里取得的消息信息。

返回值:

如果消息被转换(即,字符消息被寄送到调用线程的消息队列里),返回非零值。如果消息是WM_KEYDOWN,WM_KEYUP WM_SYSKEYDOWN或WM_SYSKEYUP,返回非零值,不考虑转换。如果消息没被转换(即,字符消息没被寄送到调用线程的消息队列里),返回值是零。

备注:此函数不修改由参数IpMsg指向的消息。
WM_KEYDOWN 和 WM_KEYUP 组合产生一个 WM_CHAR 或 WM_DEADCHAR 消息。
WM_SYSKEYDOWN 和 WM_SYSKEYUP 组合产生一个 WM_SYSCHAR 或 WM_SYSDEADCHAR 消息。TranslateMessage为 那些由键盘驱动器映射为ASCll字符的键产生 WM_CHAR 消息。
如果应用程序为其他用途处理虚拟键消息,不应调用 TranslateMessage。例如,如果调用 TranslateAccelerator 返回一个非零值,应用程序不应调用 TranslateMessage。

TranslateMessage 只能用于转换调用 GetMessage 或 PeekMessage 接收的消息。

DispatchMessage:

该函数分发一个消息给窗口程序。通常消息从 GetMessage 函数获得或者 TranslateMessage 函数传递的。消息被分发到回调函数(过程函数),作用是消息传递给操作系统,然后操作系统去调用我们的回调函数,也就是说我们在窗体的过程函数中处理消息。函数声明如下:

LRESULT DispatchMessage(
  const MSG *lpMsg
);

参数说明;

lpmsg:指向含有消息的MSG结构的指针。

窗口控件的创建与响应:

1.一般是在winmian函数中创建完父窗口后才能再调用createwindow来创建子控件

2.在窗口创建之后,显示之前,即调用CreateWindow创建主窗口在显示之前,窗口的进程函数会受到WM_CREATE的消息,此时再来创建子窗口或者子控件(这个是常用方式)

创建一个子控件:

这里创建一个按钮:

case WM_CREATE: //这里创建子控件
	{
		UINT ibutton_1 = 200;
		MessageBox(NULL, _T("create successfully"), _T("title"), MB_OK);
		//MessageBox(hwnd, _T("create successfully"), _T("title"), MB_OK);
		CreateWindow(WC_BUTTON, _T("buttons"), WS_CHILD | BS_PUSHBUTTON | WS_VISIBLE, 100, 100, 50, 50, hwnd, (HMENU)ibutton_1, NULL, NULL);
	}

注意创建子控件一定是在接收到wm_create消息的时候,由于子控件本质上也是一窗口,所以这里的创建模式与创建父窗口的时候差不多。

但是要注意几个地方:在createWindow的hMnue参数中要传入一个子窗口标识,我们是用uint类型创建的,但是这里应该传入的是一个HMNUE的类型,所以要强制转换一下。

控件的响应:

上面创建一个按钮空间后,当我们要对点击按钮之后的事情进行响应的话,就要在Switch语句中再加入一个消息操作:

	case WM_COMMAND:
	{
		UINT ID = LOWORD(wParam);
		UINT Mcode = HIWORD(wParam); //控件通知码
		if (Mcode == BN_CLICKED && ID == ibutton_1)
		{
			MessageBox(hwnd, _T("click"), _T("title"), MB_OK);
		}
	}
	break;

wParam参数其实就是传入消息的ID以及控件操作码,分别在他低32位和高32位上,所以只要检索到对应的操作码和ID就可以对点击时间进行响应。

作业里面的几个控件操作函数:

	HWND edit_1 =  CreateWindow(WC_EDIT, _T("自定义可编辑文本框"), WS_CHILDWINDOW | WS_BORDER | WS_VISIBLE | ES_AUTOHSCROLL, 260, 100, 180, 30, hwnd,(HMENU) iedit_1, NULL, NULL);

创建一个可以编辑的文本框

SetWindowText(GetDlgItem(hwnd, ibutton_1),timeBuffer);

SetWindowText:动态改变窗口标题

GetDlgItem:根据窗口ID和其父窗口获得指向窗口句柄的指针。

GetDlgItemText(hwnd, iedit_1, editBuffer, 256);

获取对应窗口ID(先前创建的可编辑文本框中的内容)中的文本内容
(过程函数),作用是消息传递给操作系统,然后操作系统去调用我们的回调函数,也就是说我们在窗体的过程函数中处理消息。函数声明如下:

LRESULT DispatchMessage(
  const MSG *lpMsg
);

参数说明;

lpmsg:指向含有消息的MSG结构的指针。

窗口控件的创建与响应:

1.一般是在winmian函数中创建完父窗口后才能再调用createwindow来创建子控件

2.在窗口创建之后,显示之前,即调用CreateWindow创建主窗口在显示之前,窗口的进程函数会受到WM_CREATE的消息,此时再来创建子窗口或者子控件(这个是常用方式)

创建一个子控件:

这里创建一个按钮:

case WM_CREATE: //这里创建子控件
	{
		UINT ibutton_1 = 200;
		MessageBox(NULL, _T("create successfully"), _T("title"), MB_OK);
		//MessageBox(hwnd, _T("create successfully"), _T("title"), MB_OK);
		CreateWindow(WC_BUTTON, _T("buttons"), WS_CHILD | BS_PUSHBUTTON | WS_VISIBLE, 100, 100, 50, 50, hwnd, (HMENU)ibutton_1, NULL, NULL);
	}

注意创建子控件一定是在接收到wm_create消息的时候,由于子控件本质上也是一窗口,所以这里的创建模式与创建父窗口的时候差不多。

但是要注意几个地方:在createWindow的hMnue参数中要传入一个子窗口标识,我们是用uint类型创建的,但是这里应该传入的是一个HMNUE的类型,所以要强制转换一下。

控件的响应:

上面创建一个按钮空间后,当我们要对点击按钮之后的事情进行响应的话,就要在Switch语句中再加入一个消息操作:

	case WM_COMMAND:
	{
		UINT ID = LOWORD(wParam);
		UINT Mcode = HIWORD(wParam); //控件通知码
		if (Mcode == BN_CLICKED && ID == ibutton_1)
		{
			MessageBox(hwnd, _T("click"), _T("title"), MB_OK);
		}
	}
	break;

wParam参数其实就是传入消息的ID以及控件操作码,分别在他低32位和高32位上,所以只要检索到对应的操作码和ID就可以对点击时间进行响应。

作业里面的几个控件操作函数:

	HWND edit_1 =  CreateWindow(WC_EDIT, _T("自定义可编辑文本框"), WS_CHILDWINDOW | WS_BORDER | WS_VISIBLE | ES_AUTOHSCROLL, 260, 100, 180, 30, hwnd,(HMENU) iedit_1, NULL, NULL);

创建一个可以编辑的文本框

SetWindowText(GetDlgItem(hwnd, ibutton_1),timeBuffer);

SetWindowText:动态改变窗口标题

GetDlgItem:根据窗口ID和其父窗口获得指向窗口句柄的指针。

GetDlgItemText(hwnd, iedit_1, editBuffer, 256);

获取对应窗口ID(先前创建的可编辑文本框中的内容)中的文本内容

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值