# Windows API 中的系统函数

> 原文： [http://zetcode.com/gui/winapi/system/](http://zetcode.com/gui/winapi/system/)

在 Windows API 教程的这一部分中，我们介绍了系统函数。 系统函数接收有关系统的信息并以各种方式与系统通信。

## 屏幕大小

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

`screen_size.c`

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

```

该代码示例将屏幕大小输出到控制台。

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

```

该程序需要`user32.lib`库进行编译。

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

```

我们用`GetSystemMetrics()`确定屏幕分辨率。

```c
C:\Users\Jano\Documents\Pelles C Projects\system\ScreenSize>ScreenSize.exe
The screen size is: 1280x800

```

屏幕大小为`1280x800`。

## 锁定工作站

`LockWorkStation()`锁定工作站的显示。

`lock_workstation.c`

```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`

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

```

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

```c
wchar_t computerName[MAX_COMPUTERNAME_LENGTH + 1];

```

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

```c
int r = GetComputerNameW(computerName, &size);

```

我们使用`GetComputerNameW()`函数获得计算机的名称。 名称存储在`computerName`数组中。

```c
C:\Users\Jano\Documents\Pelles C Projects\system\ComputerName>ComputerName.exe
Computer name: ANDROMEDA

```

我们运行代码示例。

## 用户名

`GetUserNameW()`函数返回用户名。

`username.c`

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

```

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

```c
#include <Lmcons.h>

```

`Lmcons.h`文件具有`ULEN`常量的定义。

```c
wchar_t username[UNLEN+1];

```

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

```c
int r = GetUserNameW(username, &len);

```

`GetUserNameW()`函数检索用户名并将其存储到`username`数组中。

```c
C:\Users\Jano\Documents\Pelles C Projects\system\Username>username.exe
User name: Jano

```

这是`username.exe`程序的示例输出。

## 当前目录

当前目录是用户所在或正在使用的目录。 在 Windows API 中，`SetCurrentDirectoryW()`更改当前目录，`GetCurrentDirectoryW()`检索当前目录。

`current_directory.c`

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

```

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

```c
#define BUFSIZE MAX_PATH

```

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

```c
if(argc != 2) {

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

```

如果我们不将参数传递给程序，则会显示一条错误消息。

```c
DWORD r = SetCurrentDirectoryW(argv[1]);

```

我们使用`SetCurrentDirectoryW()`切换到目录，该目录作为参数传递。

```c
r = GetCurrentDirectoryW(BUFSIZE, buf);

```

通过`GetCurrentDirectoryW()`函数调用获取当前的工作目录。

```c
if (r > BUFSIZE) {

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

```

如果返回的值大于`BUFSIZE`，则缓冲区太小。

## Windows 版本

版本帮助器函数可用于确定当前的操作系统版本。

`windows_version.c`

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

```

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

```c
#include <VersionHelpers.h>

```

辅助函数在`VersionHelpers.h`文件中声明。

```c
//if (IsWindows10OrGreater()) {

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

```

在撰写本文时，Pelles C 在其 SDK 中尚未定义`IsWindows10OrGreater()`。

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

```

如果当前版本为 Windows 8.1 或更高版本，则`IsWindows8Point1OrGreater()`返回 true。

```c
C:\Users\Jano\Documents\Pelles C Projects\system\WindowsVersion>WindowsVersion.exe
This is Windows 7

```

这是程序的示例输出。

## 内存

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

`memory.c`

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

```

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

```c
MEMORYSTATUSEX mem = {0};

```

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

```c
int r = GlobalMemoryStatusEx(&mem);

```

`GlobalMemoryStatusEx()`函数被执行； 信息存储在结构中。

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

```

`dwMemoryLoad`成员指定正在使用的物理内存的大约百分比。

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

```

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

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

```

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

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

```

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

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

```

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

```c
C:\Users\Jano\Documents\Pelles C Projects\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`

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

```

该示例确定用户的`Documents`目录的完整路径。 我们需要将`shell32.lib`和`ole32.lib`添加到项目库中。

```c
#include <initguid.h>

```

由于某些内部 API 问题，我们需要包含`initguid.h`文件； 否则，该示例将无法编译。 它失败，并显示`Unresolved external symbol 'FOLDERID_Documents'`错误。

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

```

`SHGetKnownFolderPath()`用于确定文档目录的路径。

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

```

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

```c
CoTaskMemFree(path);

```

最后，必须使用`CoTaskMemFree()`函数释放分配的内存。

```c
C:\Users\Jano\Documents\Pelles C Projects\system\DocumentsDir>DocumentsDir.exe
C:\Users\Jano\Documents

```

这是`DocumentsDir.exe`程序的示例输出。

## 驱动器名称

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

`get_drives.c`

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

```

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

```c
wchar_t LogicalDrives[MAX_PATH] = {0};

```

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

```c
DWORD r = GetLogicalDriveStringsW(MAX_PATH, LogicalDrives);

```

`GetLogicalDriveStringsW()`被调用。 缓冲区中填充了以零结尾的字符串，这些字符串代表设备名称。 该函数的第一个参数是指定缓冲区的最大大小。 缓冲区是第二个参数。

```c
wchar_t *SingleDrive = LogicalDrives;

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

    SingleDrive += wcslen(SingleDrive) + 1;
}

```

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

```c
C:\Users\Jano\Documents\Pelles C Projects\system\GetDrives>GetDrives.exe
C:\
D:\

```

系统上有两个驱动器：`C:\`和`D:\`。

## 可用空间

`GetDiskFreeSpaceExW()`检索有关磁盘卷上可用空间量的信息。 该函数提供三段信息：总空间量，可用空间量以及与调用线程关联的用户可用的可用空间。

`free_disk_space.c`

```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:\`驱动器上的磁盘空间。

```c
unsigned __int64 freeCall,
                 total,
                 free;

```

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

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

```

`GetDiskFreeSpaceExW()`被调用。

```c
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
C:\Users\Jano\Documents\Pelles C Projects\system\FreeDiskSpace>FreeDiskSpace.exe
Available space to caller: 20377 MB
Total space: 69999 MB
Free space on drive: 20377 MB

```

这是`FreeDiskSpace.exe`程序的示例输出。

## CPU 速度

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

`cpu_speed.c`

```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 速度。

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

```

`RegOpenKeyExW()`函数用于打开提供的注​​册表项。

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

```

通过`RegQueryValueExW()`函数读取该值。

```c
r = RegCloseKey(key);

```

`RegCloseKey()`关闭注册表句柄。

```c
C:\Users\Jano\Documents\Pelles C Projects\system\CpuSpeed>CpuSpeed.exe
CPU speed: 2394 MHz

```

这是`CpuSpeed.exe`程序的示例输出。

在 Windows API 教程的这一部分中，我们使用了一些系统函数。
