System functions in Windows API
last modified October 18, 2023
In this part of the Windows API tutorial, we cover system functions. System functions receive information about the system and communicate with the system in various ways.
Screen size
The GetSystemMetrics
function retrieves various system metrics and
system configuration settings.
#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; }
The code example prints the screen size to the console.
#pragma comment(lib, "user32.lib")
The program needs the user32.lib
library to compile.
int x = GetSystemMetrics(SM_CXSCREEN); int y = GetSystemMetrics(SM_CYSCREEN);
We determine the screen resolution with the GetSystemMetrics
.
C:\Users\Jano\Documents\WinApi\system\ScreenSize>ScreenSize.exe The screen size is: 1280x800
The screen size is 1280x800.
Locking workstation
The LockWorkStation
locks the workstation's display.
#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; }
The program needs the user32.lib
to compile.
Computer name
The GetComputerNameEx
function retrieves a NetBIOS or DNS name
associated with the local computer. The names are established at system startup.
#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; }
The example prints the computer name to the console.
wchar_t computerName[MAX_COMPUTERNAME_LENGTH + 1];
The MAX_COMPUTERNAME_LENGTH
constant determines the maximum length
of the computer name.
int r = GetComputerNameW(computerName, &size);
We get the name of the computer with the GetComputerNameW
function. The name is stored into the computerName
array.
C:\Users\Jano\Documents\WinApi\system\ComputerName>ComputerName.exe Computer name: ANDROMEDA
Username
The GetUserNameW
function returns the user name.
#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; }
The example prints the username to the console.
#include <Lmcons.h>
The Lmcons.h
file has the definition of
the ULEN
constant.
wchar_t username[UNLEN+1];
The ULEN
constant defines the maximum length of the username.
int r = GetUserNameW(username, &len);
The GetUserNameW
function retrieves
the username and stores it into the username
array.
C:\Users\Jano\Documents\WinApi\system\Username>username.exe User name: Jano
Current directory
Current directory is a directory in which the user is located or it is
working it. In Windows API, the SetCurrentDirectoryW
changes the current directory and the GetCurrentDirectoryW
retrieves the current directory.
#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; }
In the code example, we change and print the current working directory. The program receives one command line argument—the directory to change into.
#define BUFSIZE MAX_PATH
We use the MAX_PATH
constant, which defines the maximum length of a
system path.
if (argc != 2) { wprintf(L"Usage: %ls <dir>\n", argv[0]); return 1; }
An error message is printed if we do not pass an argument to the program.
DWORD r = SetCurrentDirectoryW(argv[1]);
We use the SetCurrentDirectoryW
to change to the directory, which
is passed as an argument.
r = GetCurrentDirectoryW(BUFSIZE, buf);
We get the current working directory with the GetCurrentDirectoryW
function call.
if (r > BUFSIZE) { wprintf(L"Buffer too small; needs %d characters\n", r); return 1; }
If the returned value is bigger than BUFSIZE
, the
buffer was too small.
Windows version
The Version Helper functions can be used to determine the current OS version.
#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; }
We use the Version Helper functions to determine the OS version.
#include <VersionHelpers.h>
The helper functions are declared in the VersionHelpers.h
file.
//if (IsWindows10OrGreater()) { // wprintf(L"This is Windows 10+"); // }
At the time of the writing, Pelles C did not have the
IsWindows10OrGreater
defined in its SDK.
if (IsWindows8Point1OrGreater()) { wprintf(L"This is Windows 8.1+\n"); }
The IsWindows8Point1OrGreater
returns true if
the current version is Windows 8.1 or greater.
C:\Users\Jano\Documents\WinApi\system\WindowsVersion>WindowsVersion.exe This is Windows 7
Memory
The GlobalMemoryStatusEx
retrieves information about the system's
current usage of both physical and virtual memory.
#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; }
The program prints statistics about memory usage to the console.
MEMORYSTATUSEX mem = {0};
The GlobalMemoryStatusEx
function stores information about memory
status in the MEMORYSTATUSEX
structure.
int r = GlobalMemoryStatusEx(&mem);
The GlobalMemoryStatusEx
function is executed;
the information is stored in the structure.
wprintf(L"Memory in use: %ld percent\n", mem.dwMemoryLoad);
The dwMemoryLoad
member specifies the approximate percentage of
physical memory in use.
wprintf(L"Total physical memory: %lld\n", mem.ullTotalPhys);
The ullTotalPhys
member specifies the actual physical memory in
bytes.
wprintf(L"Free physical memory: %lld\n", mem.ullAvailPhys);
The ullTotalPhys
member specifies the amount of physical memory
currently available in bytes.
wprintf(L"Total virtual memory: %lld\n", mem.ullTotalVirtual);
The ullTotalVirtual
member specifies the amount of the total
virtual memory in bytes.
wprintf(L"Free virtual memory: %lld\n", mem.ullAvailVirtual);
The ullAvailVirtual
member specifies the amount of available
virtual memory in bytes.
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
Known Folders
Since Windows Vista, a new system is used for identifying important directories in Windows. It is known as Known Folders. Known folders uses a set of GUID (Globally unique identifier) values for referencing important folders.
The SHGetKnownFolderPath
function retrieves the full path of a
known folder identified by the folder's id.
#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; }
The example determines the full path to the user's Documents directory. We need
to add shell32.lib
and ole32.lib
to the project
libraries.
#include <initguid.h>
Due to some internal API issues, we need to include the initguid.h
file; otherwise, the example does not compile. It fails with the
Unresolved external symbol 'FOLDERID_Documents'
error.
HRESULT hr = SHGetKnownFolderPath(&FOLDERID_Documents, 0, NULL, &path);
The SHGetKnownFolderPath
is used to determine the path to the
Documents directory.
if (SUCCEEDED(hr)) { wprintf(L"%ls\n", path); }
The SUCCEEDED
macro can be used to determine whether the function
call succeeded.
CoTaskMemFree(path);
At the end, it is necessary to free the allocated memory with the
CoTaskMemFree
function.
C:\Users\Jano\Documents\WinApi\system\DocumentsDir>DocumentsDir.exe C:\Users\Jano\Documents
Drive names
The GetLogicalDriveStringsW
function fills a buffer with strings
that specify valid drives in the system.
#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; }
The example prints valid drives in the system.
wchar_t LogicalDrives[MAX_PATH] = {0};
A drive name is a path type, so a MAX_PATH
constant is relevant for
its maximum length. The LogicalDrives
is an array of strings which
serves as a buffer for the GetLogicalDriveStringsW
function.
DWORD r = GetLogicalDriveStringsW(MAX_PATH, LogicalDrives);
The GetLogicalDriveStringsW
is called. The buffer is filled with
null-terminated strings, which represent device names. The first parameter of
the function is the maximum size of the specified buffer. The buffer is the
second parameter.
wchar_t *SingleDrive = LogicalDrives; while (*SingleDrive) { wprintf(L"%ls\n", SingleDrive); SingleDrive += wcslen(SingleDrive) + 1; }
We go through the array of device names and print them to the console.
C:\Users\Jano\Documents\WinApi\system\GetDrives>GetDrives.exe C:\ D:\
There are two drives on the system: C:\
and D:\
.
Free space
The GetDiskFreeSpaceExW
retrieves information about the amount of
space available on a disk volume. The function gives three pieces of
information: the total amount of space, the free amount of space, and the free
space available to the user that is associated with the calling thread.
#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; }
The example examines disk space on the C:\
drive.
unsigned __int64 freeCall, total, free;
The amounts are expressed in bytes; these can be very large numbers. The
unsigned __int64
type is used, which is a positive 64-bit integer
capable of storing very large values.
int r = GetDiskFreeSpaceExW(L"C:\\", (PULARGE_INTEGER) &freeCall, (PULARGE_INTEGER) &total, (PULARGE_INTEGER) &free);
The GetDiskFreeSpaceExW
is called.
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));
The three amounts are printed to the console with the wprintf
function. The values are expressed in 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 speed
The CPU speed can be determined by examining a registry value. The value is
written to registry during installation. We need to query the
HARDWARE\DESCRIPTION\System\CentralProcessor\0
key.
#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; }
The example determines the CPU speed.
long r = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0, KEY_READ, &key);
The RegOpenKeyExW
function is used to open the provided registry
key.
r = RegQueryValueExW(key, L"~MHz", NULL, NULL, (LPBYTE) &mhz, &BufSize);
The value is read with the RegQueryValueExW
function.
r = RegCloseKey(key);
The RegCloseKey
closes the registry handle.
C:\Users\Jano\Documents\WinApi\system\CpuSpeed>CpuSpeed.exe CPU speed: 2394 MHz
In this part of the Windows API tutorial, we have worked with several system functions.