← Learn

Introduction to Windows API

Author
Moise Medici
Updated
23 Jan 2026 · Completed

Windows API Documentation

The purpose of this page is to go through some of the Windows API concepts, how these functions are called, how errors are handled, and some naming conventions that Microsoft uses that are not always immediately clear.

The Windows documentation related to their API is generally clear, but it helps to understand how to read it. For example, consider the documentation for CreateThread 1.

It starts by explaining what the function does, followed by the syntax to use to call it:

HANDLE CreateThread(
[in, optional] LPSECURITY_ATTRIBUTES lpThreadAttributes,
[in] SIZE_T dwStackSize,
[in] LPTHREAD_START_ROUTINE lpStartAddress,
[in, optional] __drv_aliasesMem LPVOID lpParameter,
[in] DWORD dwCreationFlags,
[out, optional] LPDWORD lpThreadId
);

There is the return type (HANDLE, more on this later), followed by the name of the function (for instance CreateThread or CreateProcess 2) and the list of arguments it accepts.
Each argument has an in/out annotation and possibly optional. The in defines that this parameter is passed as an argument to the function and the value is never changed by the function but only used. out, on the other hand, are always pointers and are used to allow the caller of the function to extract data that the function defines. For example, in CreateThread the return value is a HANDLE to the thread, but the caller might need to get the ID of the thread. C does not allow returning multiple values, so the usual convention is to have the return value of a function be an error code or a handle, and additional data are returned in the out pointers. The caller can then take the value pointed to by the pointer and use it. It is optional because if the caller doesn’t need to use it, they can avoid passing it to the function.

Functions can have multiple out arguments like CryptDecrypt 3. This function also introduces another possibility: arguments that are both input and output.

BOOL CryptDecrypt(
[in] HCRYPTKEY hKey,
[in] HCRYPTHASH hHash,
[in] BOOL Final,
[in] DWORD dwFlags,
[in, out] BYTE *pbData,
[in, out] DWORD *pdwDataLen
);

In this case, pbData is the buffer containing the bytes that need to be decrypted, and pdwDataLen is the number of bytes. When the decryption function is executed, the decrypted data is saved in pbData and the new size in pdwDataLen.

The documentation then continues with arguments which are pretty straightforward. One point worth noting is that some arguments, usually with the flags word in the name, allow multiple values to be passed separated by the | (bitwise OR) operator. Arguments separated by the OR operator are meant to be read as “both x and y”. For example, two of the available flags for the CreateFile function are GENERIC_READ and GENERIC_WRITE. To request both read and write access to the file, the flags would be specified as GENERIC_READ | GENERIC_WRITE.

The return value section of the documentation defines what the returned value means; only the return value, not the out arguments. This section often includes details on the error codes that are returned and how to access them. This is discussed later.

The remark section might be useful at times, but mostly for developers, as it includes specific information about the function. For example, CreateFile seems to be used to create a file, however it does support opening a file as well. The remark section explains why and the capabilities available.