Windows API

365bet世界杯 2025-07-08 16:33:35 admin

简介

Windows API

本教程是纯Windows API教程,不包含MFC,使用的是C99标准。

Windows API是创建Windows应用程序的接口,要使用Windows API就要先下载Windows SDk(Software Development Kit,软件开发环境),SDK包括头文件,函数库,样例,文档和工具等。

Windows API是由C和C++写的,被分为以下几个部分:

基础服务

安全

绘图

用户接口

多媒体

Windows shell

网络

基础服务提供了文件系统,设备,进程,线程,注册表,以及错误处理等功能。

安全提供了函数,接口,对象和其他的认证,版权等安全相关的元素。

绘图提供了图形输出到屏幕,打印机及其他输出设备的功能。

用户接口提供了创建窗口和部件的功能。

多媒体提供了视频,音频等输出设备。

Windows Shell提供了由操作系统提供的shell功能。

网络提供了网络服务。

Windows API的官方实现是在动态库里(DLLS),例如kenel32.dll,user32.dll,gdi32.dll,shell32.dll是在Windows system目录下。

也有第三方的Windows API:最常见的就是Wine工程和ReactOS工程。

Windows API是一个动态实体,函数的数量每年都在增长。

Pelles C

教程里使用的是Palles C,我用的是VS2017.

MSDN

两个好的参考资料:Desktop App Development Documentation 和 Windows API list

主函数

main

主函数是C语言编程的一个进入点,然而他不是第一个运行的程序。

在C运行库中,程序开始的第一个函数叫做mainCRTStartup(),他负责初始化内存管理,文件I/O,以及参数调用等,之后mainCRTStartuo()将会调用main(),以下是main函数的函数原型:

int main (void);

int main(int argc,char **argv);

int main(int argc,char *argv[]);

样例:

#include

int main(void)

{

puts("This is a classic C Program.");

return 0;

}

wmain

前面的main函数原型只能接收 ASCII 字符,如果我们想让程序从命令行接收宽字符,就需要使用wmain:

int wmain(void);

int wmain(int argc,wchar_t **argv);

int wmain(int argc, wchar_t *argv[]);

样例;

这个程序在命令行使用宽字符,并输出命令行的第一个参数,众所周知,第0个参数是程序的运行目录。

#include

#include

#include

int wmain(int argc, wchar_t **argv) { //wchar_t类型即宽字符类型

setlocale(LC_ALL,"zh_CN.UTF-8"); //设置语言环境

PDWORD cChars = NULL;

HANDLE std = GetStdHandle(STD_OUTPUT_HANDLE); //获取标准输出的句柄

if (std == INVALID_HANDLE_VALUE) { //如果我们收到的返回代码是错误值INVALID_HANDLE_VALUE,

wprintf(L"Cannot retrieve standard output handle\n (%d)",

GetLastError()); //就输出一条错误信息,并输出错误代码

}

if (argv[1]) {

WriteConsoleW(std, argv[1], wcslen(argv[1]), cChars, NULL); //向控制台输出宽字符串

}

CloseHandle(std); //关闭标准输出的句柄

return 0;

}

如果想要输入命令行参数,可以在VS2017中右侧,解决方案资源量管理器->右键->属性-> 调试->命令参数,输入汉字即可。

_tmain 函数原型

_tmain()函数是微软的扩展函数,通过定义一个UNICODE宏来判断创建main()函数还是wmain()函数。

在过去,要创建这两个函数都需要创建,现在只需要一个宏就解决了,但是目前程序最通用的方式还是UNICODE程序。

以下是_tmain()的函数原型,其中,TCHAR宏用于转换char或者wchar_t,通过UNICODE宏控制:

int _tmain(void);

int _tmain(int argc,TCHAR **argv);

int _tmain(int argc,TCHAR *argv[]);

以下是一个程序样例:

#define _UNICODE //该宏用于C运行库转换

#define UNICODE ////该宏用于Windows头文件转换

#include //这个头文件定义了TCHAR宏,TCHAR宏受UNICODE宏影响

#include //为_tmain和_tcslen宏引入头文件,他们的转换受_UNICODE影响

int _tmain(int argc, TCHAR *argv[]) {

PDWORD cChars = NULL;

HANDLE std = GetStdHandle(STD_OUTPUT_HANDLE);

if (std == INVALID_HANDLE_VALUE) {

_tprintf(L"Cannot retrieve standard output handle\n (%d)",

GetLastError());

}

if (argv[1]) {

WriteConsole(std, argv[1], _tcslen(argv[1]), cChars, NULL);

}

CloseHandle(std);

return 0;

}

WinMain

以上是控制台主函数,现在我们介绍图形用户界面的主函数:

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

PWSTR pCmdLine, int nCmdShow);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

LPSTR lpCmdLine, int nCmdShow);

int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

LPTSTR lpCmdLine, int nCmdShow);

其中,pCmdLine是命令行参数。

如果进入点是WinMain()函数时,那么程序开始于WinMainCRTStartup();

如果进入点是wWinMain()函数,那么程序开始于wWinMainCRTStartup().

下面是一个样例,在屏幕上显示一个弹窗:

#include

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

PWSTR szCmdLine, int CmdShow) {

MessageBoxW(NULL, szCmdLine, L"Title", MB_OK);

return 0;

}

系统函数

系统函数用于接收系统信息并和系统通信。

屏幕尺寸

GetSystemMetrics() 用于查看系统指标和系统设定。

下面是一个例子,用于输出屏幕尺寸:

#include

#include

#pragma comment(lib, "user32.lib") //编译需要user32.lib库

int wmain(void) {

int x = GetSystemMetrics(SM_CXSCREEN);

int y = GetSystemMetrics(SM_CYSCREEN);

wprintf(L"The screen size is: %dx%d\n", x, y);

return 0;

}

锁屏

#include

#include

#pragma comment(lib, "user32.lib")

int wmain(void) {

int r = LockWorkStation();

if( r == 0 ) {

wprintf(L"LockWorkStation() failed %d\n", GetLastError());

return 1;

}

return 0;

}

电脑名

GetComputerNameEx()用于检测NETBIOS和DNS名。

#include

#include

int wmain(void) {

wchar_t computerName[MAX_COMPUTERNAME_LENGTH + 1]; //MAX_COMPUTERNAME_LENGTH定义了电脑名的最大长度

DWORD size = sizeof(computerName) / sizeof(computerName[0]);

int r = GetComputerNameW(computerName, &size);

if (r == 0) {

wprintf(L"Failed to get computer name %ld", GetLastError());

return 1;

}

wprintf(L"Computer name: %ls\n", computerName);

return 0;

}

用户名

#include

#include //ULEN定义

#include

int wmain(void) {

wchar_t username[UNLEN+1];

DWORD len = sizeof(username) / sizeof(wchar_t);

int r = GetUserNameW(username, &len);

if (r == 0) {

wprintf(L"Failed to get username %ld", GetLastError());

return 1;

}

wprintf(L"User name: %ls\n", username);

return 0;

}

当前目录

SetCurrentDirectoryW() 用于设置当前目录;GetCurrentDirectoryW()用于获取当前目录。

在下面的样例中,我们输出了当前目录,并通过命令行参数改变了当前目录。

#include

#include

#define BUFSIZE MAX_PATH

int wmain(int argc, wchar_t **argv) {

wchar_t buf[BUFSIZE];

if(argc != 2) {

wprintf(L"Usage: %ls

\n", argv[0]);

return 1;

}

DWORD r = SetCurrentDirectoryW(argv[1]);

if (r == 0) {

wprintf(L"SetCurrentDirectoryW() failed (%ld)\n", GetLastError());

return 1;

}

r = GetCurrentDirectoryW(BUFSIZE, buf);

if (r == 0) {

wprintf(L"GetCurrentDirectoryW() failed (%ld)\n", GetLastError());

return 1;

}

if (r > BUFSIZE) {

wprintf(L"Buffer too small; needs %d characters\n", r);

return 1;

}

wprintf(L"Current directory is: %ls\n", buf);

return 0;

}

Windows版本

通过版本辅助函数可以检测当前的系统版本。

#include

#include

#include

int wmain(void) {

//if (IsWindows10OrGreater()) {

// wprintf(L"This is Windows 10+");

// }

if (IsWindows8Point1OrGreater()) {

wprintf(L"This is Windows 8.1+\n");

} else if (IsWindows8OrGreater()) {

wprintf(L"This is Windows 8\n");

} else if (IsWindows7OrGreater ()) {

wprintf(L"This is Windows 7\n");

} else if (IsWindowsVistaOrGreater ()) {

wprintf(L"This is Windows Vista\n");

} else if (IsWindowsXPOrGreater()) {

wprintf(L"This is Windows XP\n");

}

return 0;

}

内存

GlobalMemoryStatusEx() 函数用于检测当前系统的物理内存和虚拟内存。

#include

#include

int wmain(void) {

MEMORYSTATUSEX mem = {0};

mem.dwLength = sizeof(mem);

int r = GlobalMemoryStatusEx(&mem);

if (r == 0) {

wprintf(L"Failed to memory status %ld", GetLastError());

return 1;

}

wprintf(L"Memory in use: %ld percent\n", mem.dwMemoryLoad);

wprintf(L"Total physical memory: %lld\n", mem.ullTotalPhys);

wprintf(L"Free physical memory: %lld\n", mem.ullAvailPhys);

wprintf(L"Total virtual memory: %lld\n", mem.ullTotalVirtual);

wprintf(L"Free virtual memory: %lld\n", mem.ullAvailVirtual);

return 0;

}

Known Folders

从Windows Vista开始,使用了新的系统来标识重要的目录,它叫做Known Folders。Known Folders使用一组GUID(Globally unique identifier) 来索引重要的文件夹。

SHGetKnownFolderPath()函数通过GUID返回全路径。

#include

#include //由于一些内部API的问题,不包含这个编译时会报错

#include

#include

#include

int wmain(void) {

PWSTR path = NULL;

HRESULT hr = SHGetKnownFolderPath(&FOLDERID_Documents, 0, NULL, &path);

if (SUCCEEDED(hr)) {

wprintf(L"%ls\n", path);

}

CoTaskMemFree(path); //释放内存

return 0;

}

驱动名

使用GetLogicalDriveStringsW()函数来获取磁盘驱动名,他返回一个驱动路径的buffer:

#include

#include

int wmain(void) {

wchar_t LogicalDrives[MAX_PATH] = {0};

DWORD r = GetLogicalDriveStringsW(MAX_PATH, LogicalDrives);

if (r == 0) {

wprintf(L"Failed to get drive names %ld", GetLastError());

return 1;

}

if (r > 0 && r <= MAX_PATH) {

wchar_t *SingleDrive = LogicalDrives;

while(*SingleDrive) {

wprintf(L"%ls\n", SingleDrive);

SingleDrive += wcslen(SingleDrive) + 1;

}

}

return 0;

}

剩余空间

函数GetDiskFreeSpaceExW() 用于检测磁盘的用量信息。他返回三条信息:空间总量,剩余空间总量,剩余可用空间总量,下面的样例检测c盘的空间情况:

#include

#include

int wmain(void) {

unsigned __int64 freeCall,

total,

free;

int r = GetDiskFreeSpaceExW(L"C:\\", (PULARGE_INTEGER) &freeCall,

(PULARGE_INTEGER) &total, (PULARGE_INTEGER) &free);

if (r == 0) {

wprintf(L"Failed to get free disk space %ld", GetLastError());

return 1;

}

wprintf(L"Available space to caller: %I64u MB\n", freeCall / (1024*1024));

wprintf(L"Total space: %I64u MB\n", total / (1024*1024));

wprintf(L"Free space on drive: %I64u MB\n", free / (1024*1024));

return 0;

}

CPU速度

CPU速度通过检测注册表的值来检测,需要查询HARDWARE\DESCRIPTION\System\CentralProcessor\0 key

#include

#include

int wmain(void) {

DWORD BufSize = MAX_PATH;

DWORD mhz = MAX_PATH;

HKEY key;

long r = RegOpenKeyExW(HKEY_LOCAL_MACHINE,

L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0, KEY_READ, &key);

if (r != ERROR_SUCCESS) {

wprintf(L"RegOpenKeyExW() failed %ld", GetLastError());

return 1;

}

r = RegQueryValueExW(key, L"~MHz", NULL, NULL, (LPBYTE) &mhz, &BufSize);

if (r != ERROR_SUCCESS) {

wprintf(L"RegQueryValueExW() failed %ld", GetLastError());

return 1;

}

wprintf(L"CPU speed: %lu MHz\n", mhz);

r = RegCloseKey(key);

if (r != ERROR_SUCCESS) {

wprintf(L"Failed to close registry handle %ld", GetLastError());

return 1;

}

return 0;

}

字符串

C语言中是没有字符串数据类型的。字符串本质是一个字符型数组,无论什么时候我们说到字符串,都是指字符串数组。

我们有五个处理字符串的API,包括CRT和Windows API的:

ANSI C standard functions

Security enhanced CRT functions

Windows API kernel and user functions

Windows API Shell Lightweight Utility functions

Windows API StrSafe functions

ANSI C 字符串函数

CRT函数调用了Windwos API函数,因此会有一点小开销,这些函数虽然实现了字符串函数但是有一些限制,当不被正确使用时,会造成安全问题,当执行失败时不会返回错误值。

#include

#include

#define STR_EQUAL 0

int wmain(void) {

wchar_t str1[] = L"There are 15 pines";

wprintf(L"The length of the string is %lld characters\n", wcslen(str1)); //输出宽字符串的数量

wchar_t buf[20];

wcscpy(buf, L"Wuthering"); //将字符串拷贝到buffer

wcscat(buf, L" heights\n"); //向buffer中添加字符串

wprintf(buf);

if (wcscmp(L"rain", L"rainy")== STR_EQUAL) { //比较字符串

wprintf(L"rain and rainy are equal strings\n");

} else {

wprintf(L"rain and rainy are not equal strings\n");

}

return 0;

}

安全提高的CRT函数

安全提高的CRT函数不是标准函数而是微软的扩展函数。

这些函数验证了参数,buffer大小,字符串空检测以及提供了强化的错误报告。

安全提高的CRT函数都有一个_s后缀:

#include

#include

#define BUF_LEN 25

int wmain(void) {

wchar_t str1[] = L"There are 15 pines";

const int MAX_CHARS = 50;

size_t count = wcsnlen_s(str1, MAX_CHARS);

wprintf(L"The length of the string is %ld characters\n", count);

wchar_t buf[BUF_LEN] = {0};

int r = wcscpy_s(buf, BUF_LEN, L"Wuthering");

if (r != 0) {

wprintf(L"wcscpy_s() failed %ld", r);

}

r = wcscat_s(buf, BUF_LEN, L" heights\n");

if (r != 0) {

wcscat_s(L"wcscat_s() failed %ld", r);

}

wprintf_s(buf);

return 0;

}

内核和用户字符串函数

这些函数只用于Windows系统,他们比CRT更轻量。

内核级字符串函数根植于Windows内核开发,他们以字母l为前缀。

字符串长度

TODO.

日期和时间

TODO.

窗口

在Windows中,一切都是窗口,主窗口、按钮,静态文本甚至是图标,都是一个窗口,静态文本只不过是一个特殊窗口。

样例

simplewindow.c

#include

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

PWSTR pCmdLine, int nCmdShow) {

MSG msg;

HWND hwnd;

WNDCLASSW wc;

wc.style = CS_HREDRAW | CS_VREDRAW;

wc.cbClsExtra = 0;

wc.cbWndExtra = 0;

wc.lpszClassName = L"Window";

wc.hInstance = hInstance;

wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);

wc.lpszMenuName = NULL;

wc.lpfnWndProc = WndProc;

wc.hCursor = LoadCursor(NULL, IDC_ARROW);

wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);

RegisterClassW(&wc);

hwnd = CreateWindowW(wc.lpszClassName, L"Window",

WS_OVERLAPPEDWINDOW | WS_VISIBLE,

100, 100, 350, 250, NULL, NULL, hInstance, NULL);

ShowWindow(hwnd, nCmdShow);

UpdateWindow(hwnd);

while (GetMessage(&msg, NULL, 0, 0)) {

DispatchMessage(&msg);

}

return (int) msg.wParam;

}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg,

WPARAM wParam, LPARAM lParam) {

switch(msg) {

case WM_DESTROY:

PostQuitMessage(0);

break;

}

return DefWindowProcW(hwnd, msg, wParam, lParam);

}

参考链接:

https://zetcode.com/gui/winapi/

相关文章

角逐的意思

cos240度等于多少

男的带什么聚财运气好?男人招财吉祥饰品!