ZetCode

Windows API 中的系统函数

最后修改于 2023 年 10 月 18 日

在本 Windows API 教程中,我们将介绍系统函数。系统函数接收有关系统的信息,并以各种方式与系统通信。

屏幕尺寸

GetSystemMetrics 函数检索各种系统指标和系统配置设置。

screen_size.c
#include <windows.h>
#include <wchar.h>

#pragma comment(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;
}

该代码示例将屏幕尺寸打印到控制台。

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

程序需要 user32.lib 库才能编译。

int x = GetSystemMetrics(SM_CXSCREEN);
int y = GetSystemMetrics(SM_CYSCREEN);

我们使用 GetSystemMetrics 确定屏幕分辨率。

C:\Users\Jano\Documents\WinApi\system\ScreenSize>ScreenSize.exe
The screen size is: 1280x800

屏幕尺寸为 1280x800。

锁定工作站

LockWorkStation 锁定工作站的显示器。

lock_workstation.c
#include <windows.h>
#include <wchar.h>

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

程序需要 user32.lib 才能编译。

计算机名称

GetComputerNameEx 函数检索与本地计算机关联的 NetBIOS 或 DNS 名称。 这些名称是在系统启动时建立的。

computer_name.c
#include <windows.h>
#include <wchar.h>

int wmain(void) {

    wchar_t computerName[MAX_COMPUTERNAME_LENGTH + 1];
    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;
}

该示例将计算机名称打印到控制台。

wchar_t computerName[MAX_COMPUTERNAME_LENGTH + 1];

MAX_COMPUTERNAME_LENGTH 常量确定计算机名称的最大长度。

int r = GetComputerNameW(computerName, &size);

我们使用 GetComputerNameW 函数获取计算机的名称。 该名称存储在 computerName 数组中。

C:\Users\Jano\Documents\WinApi\system\ComputerName>ComputerName.exe
Computer name: ANDROMEDA

用户名

GetUserNameW 函数返回用户名。

username.c
#include <windows.h>
#include <Lmcons.h>
#include <wchar.h>

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

该示例将用户名打印到控制台。

#include <Lmcons.h>

Lmcons.h 文件定义了 ULEN 常量。

wchar_t username[UNLEN+1];

ULEN 常量定义用户名的最大长度。

int r = GetUserNameW(username, &len);

GetUserNameW 函数检索用户名并将其存储在 username 数组中。

C:\Users\Jano\Documents\WinApi\system\Username>username.exe
User name: Jano

当前目录

当前目录 是用户所在或正在使用的目录。在 Windows API 中,SetCurrentDirectoryW 更改当前目录,而 GetCurrentDirectoryW 检索当前目录。

current_directory.c
#include <windows.h>
#include <wchar.h>

#define BUFSIZE MAX_PATH

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

    wchar_t buf[BUFSIZE];

    if (argc != 2) {

        wprintf(L"Usage: %ls <dir>\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;
}

在代码示例中,我们更改并打印当前工作目录。该程序接收一个命令行参数——要更改到的目录。

#define BUFSIZE MAX_PATH

我们使用 MAX_PATH 常量,该常量定义系统路径的最大长度。

if (argc != 2) {

    wprintf(L"Usage: %ls <dir>\n", argv[0]);
    return 1;
}

如果我们没有向程序传递参数,则会打印一条错误消息。

DWORD r = SetCurrentDirectoryW(argv[1]);

我们使用 SetCurrentDirectoryW 更改为作为参数传递的目录。

r = GetCurrentDirectoryW(BUFSIZE, buf);

我们使用 GetCurrentDirectoryW 函数调用获取当前工作目录。

if (r > BUFSIZE) {

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

如果返回值大于 BUFSIZE,则缓冲区太小。

Windows 版本

可以使用版本帮助程序函数来确定当前的操作系统版本。

windows_version.c
#include <windows.h>
#include <wchar.h>
#include <VersionHelpers.h>

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

我们使用版本帮助程序函数来确定操作系统版本。

#include <VersionHelpers.h>

帮助程序函数在 VersionHelpers.h 文件中声明。

//if (IsWindows10OrGreater()) {

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

在撰写本文时,Pelles C 的 SDK 中未定义 IsWindows10OrGreater

if (IsWindows8Point1OrGreater()) {
    wprintf(L"This is Windows 8.1+\n");
}

如果当前版本是 Windows 8.1 或更高版本,则 IsWindows8Point1OrGreater 返回 true。

C:\Users\Jano\Documents\WinApi\system\WindowsVersion>WindowsVersion.exe
This is Windows 7

Memory

GlobalMemoryStatusEx 检索有关系统当前对物理内存和虚拟内存的使用情况的信息。

memory.c
#include <windows.h>
#include <wchar.h>

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

该程序将有关内存使用情况的统计信息打印到控制台。

MEMORYSTATUSEX mem = {0};

GlobalMemoryStatusEx 函数将有关内存状态的信息存储在 MEMORYSTATUSEX 结构中。

int r = GlobalMemoryStatusEx(&mem);

执行 GlobalMemoryStatusEx 函数;信息存储在该结构中。

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

dwMemoryLoad 成员指定物理内存的近似百分比。

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

ullTotalPhys 成员指定以字节为单位的实际物理内存。

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

ullTotalPhys 成员指定当前可用的物理内存量(以字节为单位)。

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

ullTotalVirtual 成员指定虚拟内存的总量(以字节为单位)。

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

ullAvailVirtual 成员指定可用虚拟内存的量(以字节为单位)。

C:\Users\Jano\Documents\WinApi\system\Memory>Memory.exe
Memory in use: 47 percent
Total physical memory: 4226072576
Free physical memory: 2229788672
Total virtual memory: 8796092891136
Free virtual memory: 8796052586496

已知文件夹

自 Windows Vista 以来,用于识别 Windows 中重要目录的新系统。它被称为 已知文件夹。已知文件夹使用一组 GUID(全局唯一标识符)值来引用重要文件夹。

SHGetKnownFolderPath 函数检索由文件夹 ID 标识的已知文件夹的完整路径。

documents_dir.c
#include <windows.h>
#include <initguid.h>
#include <KnownFolders.h>
#include <ShlObj.h>
#include <wchar.h>

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

该示例确定用户“文档”目录的完整路径。我们需要将 shell32.libole32.lib 添加到项目库中。

#include <initguid.h>

由于某些内部 API 问题,我们需要包含 initguid.h 文件;否则,该示例不会编译。它会因 Unresolved external symbol 'FOLDERID_Documents' 错误而失败。

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

SHGetKnownFolderPath 用于确定“文档”目录的路径。

if (SUCCEEDED(hr)) {
    wprintf(L"%ls\n", path);
}

SUCCEEDED 宏可用于确定函数调用是否成功。

CoTaskMemFree(path);

最后,有必要使用 CoTaskMemFree 函数释放已分配的内存。

C:\Users\Jano\Documents\WinApi\system\DocumentsDir>DocumentsDir.exe
C:\Users\Jano\Documents

驱动器名称

GetLogicalDriveStringsW 函数使用指定系统中有效驱动器的字符串填充缓冲区。

get_drives.c
#include <windows.h>
#include <wchar.h>

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

该示例打印系统中有效的驱动器。

wchar_t LogicalDrives[MAX_PATH] = {0};

驱动器名称是一种路径类型,因此 MAX_PATH 常量与其最大长度相关。LogicalDrives 是一个字符串数组,用作 GetLogicalDriveStringsW 函数的缓冲区。

DWORD r = GetLogicalDriveStringsW(MAX_PATH, LogicalDrives);

调用 GetLogicalDriveStringsW。 缓冲区填充以 null 结尾的字符串,这些字符串表示设备名称。 函数的第一个参数是指定缓冲区的最大大小。 缓冲区是第二个参数。

wchar_t *SingleDrive = LogicalDrives;

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

    SingleDrive += wcslen(SingleDrive) + 1;
}

我们遍历设备名称的数组,并将它们打印到控制台。

C:\Users\Jano\Documents\WinApi\system\GetDrives>GetDrives.exe
C:\
D:\

系统上有两个驱动器:C:\D:\

可用空间

GetDiskFreeSpaceExW 检索有关磁盘卷上可用空间量的信息。 该函数提供了三条信息:总空间量、可用空间量和与调用线程关联的用户的可用空间。

free_disk_space.c
#include <windows.h>
#include <wchar.h>

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

该示例检查 C:\ 驱动器上的磁盘空间。

unsigned __int64 freeCall,
                 total,
                 free;

数量以字节为单位表示;这些数字可能非常大。 使用 unsigned __int64 类型,它是一个能够存储非常大值的正 64 位整数。

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

调用 GetDiskFreeSpaceExW

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

这三个数量使用 wprintf 函数打印到控制台。 这些值以 MB 为单位表示。

C:\Users\Jano\Documents\WinApi\system\FreeDiskSpace>FreeDiskSpace.exe
Available space to caller: 20377 MB
Total space: 69999 MB
Free space on drive: 20377 MB

CPU 速度

可以通过检查注册表值来确定 CPU 速度。 该值在安装期间写入注册表。 我们需要查询 HARDWARE\DESCRIPTION\System\CentralProcessor\0 键。

cpu_speed.c
#include <windows.h>
#include <wchar.h>

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

该示例确定 CPU 速度。

long r = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
    L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0, KEY_READ, &key);

RegOpenKeyExW 函数用于打开提供的注册表项。

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

该值使用 RegQueryValueExW 函数读取。

r = RegCloseKey(key);

RegCloseKey 关闭注册表句柄。

C:\Users\Jano\Documents\WinApi\system\CpuSpeed>CpuSpeed.exe
CPU speed: 2394 MHz

在本 Windows API 教程中,我们使用了几个系统函数。