The Windows API is very low level and obviously-Windows only, therefore it makes sense in most of cases to take advantage of higher libraries which encapsulates this API in a C++-friendly. Some of those libraries are:
Windows Only - Microsft:
Windows Only - Third party.
- WTL - Windows Template Library - Created by Microsft and later
become opensourced at 2004.
- Web site: http://wtl.sourceforge.net/
- Win32++ - “Win32++ is a C++ library used to build windows applications. Win32++ is a free alternative to MFC. It has the added advantage of being able to run on a wide range of free compilers, including Visual Studio Community, and the MinGW compiler provided with CodeBlocks and Dev-C++.”
Cross-Platform:
- QT Framework - QT is not only a cross platform GUI library, it
also provides all sort of cross platform libraries for databases,
sockets, text parsing, OpenGL, XML and so on.
- Supported on: Windows, MacOSX, Linux, Android, iOS and many other operating systems.
- wxWidgets - Just a well known GUI library.
- Supported on: Windows, Linux, OSX.
- Poco - Framework - A collection of cross-platform libraries for network: HTTP protocol, FTP, ICMP; database access - SQLite, MySQL, ODBC and MongoDB; Standardized human-readable data exchange formats - JSON and XML; Zip compression; SSL and crypto utils.
- Hungarian Notation
- Non standard types:
- LPSTRING, WORD, DWORD, BOOL, LPVOID …
- Paths: Unlike in U*nix-like operating systems which are written
with (/) forward slash, in Windows paths are written with
backward slash (\) needs to be escaped with double backward slash (\)
since is slash is used for escape characters such as CR
\n,\sand so on. Thus, a Windows path such as"C:\Users\sombody\file.exe"must be written as “C:\Users\sombody\file.exe”. - Different Calling Conventions in the same OS:
__stdcall__cdecl__fastcall
- Characters - ANSI X Unicode in API.
- Windows API uses 16-bits Unicode wide characters (wchar_t) instead of 8 bits Unicode UTF-8 which is common in most modern Unix-like Oses such as Linux, BSD and MacOSX.
- Windows API functions generally has two versions, an ANSI version with suffix ‘A’ and a wide unicode version with suffix ‘W’. For instance the API CreateDirectory, has an ANSI version (which uses char) and does not work with UTF8 characteres such as ‘ã’, ‘õ’, ‘ç’, ’ 我’, ‘Ж’ and so on. And an wide unicode version using wide character (wchar_t) CreateDirectoryW.
- Many string types
- Many C-runtimes and entry points.
- Functions has many parameters which makes them pretty complex. The only way to understand the API is to compile and run small specific examples.
- Not all system calls are documented like open source OSes such as Linux or BSD.
Most used headers:
- #include <windows.h>
- #include <wchar.h> - Wide Characters - UTF16 chars
- #include <tchar.h>
- #include <global.h>
- #include <nsfbd.h>
Other useful header files:
- windows.h
- Basic header file of Windows API
- WinError.h
- Error codes and strings
- tchar.h
- Provides the macro _T(…) and TEXT(…) for Unicode/ANSI string encoding handling.
- wchar.h
- Wide Character - UTF16 or wchar
- global.h
- ntfsb.h
- Winsock2.h
- Network sockets
- Winbase.h
- Windows types definitions
- WinUser.h
- Windows Messages
- ShellAPI.h
- Shell API
- ShFolder.h
- Folder definitions
- Commdlg.h
- Commom Controls (COM based)
- Dlgs.h
- Dialog definitions
- IUnknown.h
- COM header
- conio.h
- Console Input/Output functions - it is heritage grom MSDOS.
- kernel32.dll
- Low level NTDLL wrappers.
- user32.dll
- User interface primitives used by graphical programs with menus, toolboxes, prompts, windows ..
- shell.dll
- gdi32.dll
- Basic drawing primitives.
- ole32.dll
- MSVCRT.DLL
- Implementation of the C standard library stdlib.
- advapi.dll
- Contains functions for system-related tasks such as registry and registry handling.
WS_32.DLL- Winsock2 library contains a socket implementation.
- Ntdll.dll
- Interface to Kernel. Not used by Windows programs directly.
- Wininet.dll
- Provides high level network APIs, for instance, HttpOpenRequest, FtpGetFile …
Native executables, shared libraries and project files.
| Extension | Executable | Description |
| Binary Format | ||
|---|---|---|
| Native Code | ||
| .exe | PE32 or PE64 | Windows Executable |
| .dll | PE32 or PE64 | Dynamic Linked Library - It can be Native PE32, PE64 or .NET/CLR DLL |
| .xll | PE32 or PE64 | Excel native Addin (extensio or plugin). It is a dll with .xll extension. |
| .pyd | PE32 or PE64 | Python native module on Windows - DLL with .pyd extension instead of .dll. |
| .cpl | PE32 or PE64 | Control Panel Applet - Also a DLL with .cpl extension. |
| .sys | PE32 or PE64 | Windows device driver (akin to Linux kernel modules) |
| .ocx | PE32 or PE64 | Active Control X (DLL) |
| Special Files | ||
| Ntoskrnl.exe | PE32 or PE64 | Windows-NT Kernel image |
| hall.dll | PE32 or PE64 | Hardware Abstraction Layer (HAL) |
| Compilation Binary Files | ||
| .obj | - | Object file -> Input to linker before building an executable. |
| .pdb | - | Program Debug Database => Contains executable or DLL debugging symbols. |
| .lib | - | Oject File Library or import library |
| .exp | - | Exports Library File |
| .RES | - | Compiled resource script |
| Source and Project Files | ||
| .def | - | Export Definition File |
| .sln | - | Visual Studio Solution (Project file). |
| .rs | - | Resource script - for embedding files into the executable. |
Scripting Languages Files:
| File Extension | Interpreter | Advantage | Description |
|---|---|---|---|
| .bat | cmd.exe | Simplicity | Batch Script - Legacy technology from MSDOS, but still useful for small automation. |
| .vbs or vbe | WScript.exe or cscript.exe | COM + OOP | VBScript - Visual Basic Script |
| .js or jse | JScript.exe | COM + OOP | |
| .wcf | Windows Script File - Allows using many script engines iside the same file. | ||
| .ps1 .psm1 .ps1xml | Powershell | COM + OOP + .NET + Interactive | Powershell Script |
| .reg | regedit.exe | - | Windows registry script. Modify Windows registry when executed. |
Windows API uses the Hungarian notation which was intruduced by Charles Simonyi at Microsoft and Xerox PARC. This notation uses a prefix to denote the variable type.
Notes and remarks:
- Many sources advises against this notation and nowadays many IDEs can provide a variable type by just hovering the mouse over it.
- Understanding the notation can help to reason about the Windows API.
- The HN notation is not standardized.
Form:
TYPE-PREFIX + NAME + QUALIFIER
| Prefix | Type | Description | Variable Name Example |
|---|---|---|---|
| b | BYTE or BOOL | boolean | BOOL bFlag; BOOL bIsOnFocus |
| c | char | Character - 1 byte | char cLetter |
| w | WORD | word | |
| dw | DWORD | double word | |
| i | int | integer | int iNumberOfNodes |
| u32 | unsigned [int] | unsigned integer | unsigned u32Nodes |
| f or fp | float | float point - single precision | fInterestRate |
| d | double | float point - double precision | dRateOfReturn |
| n | short int | ||
| sz | char* or const char* | Pointer to null terminated char array. | char* szButtonLabel |
| H | HANDLE | Handle | HANDLE hModule; HMODULE hInstance; |
| p | - | Pointer | double* pdwMyPointer; |
| lp | - | Long Pointer | int* lpiPointer; |
| fn | - | Function pointer | |
| lpsz | Long Pointer | ||
| LP | Long Pointer | ||
| I | - | Interface (C++ interface class) | class IDrawable … |
| S | - | Struct declaration | struct SContext { … } |
| C | - | Class declaration | class CUserData{ … } |
| m_ | - | Private member variable name of some class | m_pszFileName |
| s_ | - | Static member of a class | static int s_iObjectCount |
Examples in Windows API - Function Create Process:
BOOL WINAPI CreateProcess(
_In_opt_ LPCTSTR lpApplicationName, // const char*
_Inout_opt_ LPTSTR lpCommandLine, // char*
_In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, //
_In_ BOOL bInheritHandles,
_In_ DWORD dwCreationFlags,
_In_opt_ LPVOID lpEnvironment,
_In_opt_ LPCTSTR lpCurrentDirectory,
_In_ LPSTARTUPINFO lpStartupInfo,
_Out_ LPPROCESS_INFORMATION lpProcessInformation
);- dwCreationFlags => (dw) prefix Indicates that the variable is a DWORD (int)
- lpEnvironment => (lp - Long Pointer) Indicates that variable is a void pointer => (LPVOID = void* )
- lpApplicationName => Indicates that the variable is a pointer to char or (LPCSTR = const char*)
Furthere Reading:
- Coding Conventions: The Hungarian Notation
- Why I prefer to use the Hungarian Notation
- Hungarian Notation
- Just Say mNo to Hungarian Notation - Jake Wharton
- Hungarian Notation
- Hungarian Notation
- Handle - Is a unsigned integer number assigned to processes,
windows, buttons, resources and etc. Actually, it is an opaque
pointer to some system data structure (Kernel Object), similar to
Unix’s file descriptor pointer. The purpose of using handles or
opaque pointer is to hide the implementation of those data
structures allowing implementators to change their inner working
without disrupting application developers. This approach gives a
pseudo object-oriented interface to the Windows API. See also:
- Note: A handle can be an obfuscated pointer exposed as an integer, void pointer void* (also opaque pointer) or ordinary opaque pointer (pointer to a C-struct or class which implementation is not exposed).
- Types of Kernel Objects (Handle is a numeric value related to the
pointer to kernel object C-struct). The name “object” comes from
the idea that it is possible to access the kernel data structure
pointer by the handle using the Win32 API functions. It works in a
similar way to classical object oriented programming where the data
structure and internal representation can only be accessed by the
class methodos.
- Symbolic Link
- Process
- A running program, executable. A process has its own address space, data, stack and heap.
- Job
- Group of processes managed as group.
- File
- Open file or I/O device.
- Token
- Security token used by many Win32 functions.
- Event
- Synchronization object used for notification.
- Threads
- Smallest unit of execution within a process.
- Semaphore
- Mutex
- Timer
- Object which provides notification after a certain period is elapsed.
References:
- Opaque pointer - Wikipedia - Note: Opaque pointer is also called “handle classes”, “pimpl idiom”, “Compiler-firewall”, “d-pointer” in C++.
- Handle (computing) - Wikipedia
- c++ - win32 application aren’t so object oriented and why there are so many pointers? - Stack Overflow
- Object-oriented techniques in C Dmitry Frank
- Object-oriented design patterns in the kernel, part 1
| Data Type | Definition | Description |
|---|---|---|
| BOOL | typedef int BOOL | Boolean variable true (non zero) or false (zero or 0) |
| BYTE | typedef unsigned char BYTE | A byte, 8 bits. |
| CCHAR | typedef char CHAR | An 8-bit Windows (ANSI) character. |
| DWORD | typedef unsigned long DWORD | A 32-bit unsigned integer. The range is 0 through 4294967295 decimal. |
| DWORDLONG | typedef unsigned __int64 DWORDLONG | 64 bits usigned int. |
| DWORD32 | typedef unsigned int DWORD32 | A 32-bit unsigned integer. |
| DWORD64 | typedef unsigned __int64 DWORD64 | A 64-bit unsigned integer. |
| FLOAT | typedef float FLOAT | A floating-point variable. |
| INT8 | typedef signed char INT8 | An 8-bit signed integer. |
| INT16 | typedef signed short INT16 | A 16-bit signed integer. |
| INT32 | typedef signed int INT32 | A 32-bit signed integer. The range is -2147483648 through 2147483647 decimal. |
| INT64 | typedef signed __int64 INT64 | A 64-bit signed integer. |
| LPBOOL | typedef BOOL far *LPBOOL; | A pointer to a BOOL. |
| LPBYTE | typedef BYTE far *LPBYTE | A pointer to a BYTE. |
| LPCSTR, PCSTR | typedef __nullterminated CONST CHAR *LPCSTR | pointer to a constant null-terminated string of 8-bit Windows (ANSI) characters. |
| LPCVOID | typedef CONST void *LPCVOID; | A pointer to a constant of any type. |
| LPCWSTR, PCWSTR | typedef CONST WCHAR *LPCWSTR; | A pointer to a constant null-terminated string of 16-bit Unicode characters. |
| LPDWORD | typedef DWORD *LPDWORD | A pointer to a DWORD. |
| LPSTR | typedef CHAR *LPSTR; | A pointer to a null-terminated string of 8-bit Windows (ANSI) characters. |
| LPTSTR | An LPWSTR if UNICODE is defined, an LPSTR otherwise. | |
| LPWSTR | typedef WCHAR *LPWSTR; | A pointer to a null-terminated string of 16-bit Unicode characters. |
| PCHAR | typedef CHAR *PCHAR; | A pointer to a CHAR. |
| CHAR | ANSI Char or char | |
| WCHAR | Wide character 16 bits UTF16 | |
| TCHAR | - | A WCHAR if UNICODE is defined, a CHAR otherwise. |
| UCHAR | typedef unsigned char UCHAR; | An unsigned CHAR. |
| WPARAM | typedef UINT_PTR WPARAM; | A message parameter. |
| HANDLE | 32 bits integer used as a handle |
| HDC | Handle to device context |
| HWND | 32-bit unsigned integer used as handle to a window |
| LONG | |
| LPARAM | |
| LPSTR | |
| LPVOID | Generic pointer similar to void* |
| LRESULT | |
| UINT | Unsigned integer |
| WCHAR | 16-bit Unicode character or Wide-Character |
| WPARAM | |
| HINSTANCE |
General:
Windows Programming:
- The Windows OS Win32 programming tutorial: notes, references and C/Win32 program examples on data type, system error, notation, handles and objects
- Seneca | Computer Studies | Introduction to Game Programming
- The Complete Guide to C++ Strings, Part II - String Wrapper Classes - CodeProject
Annotation such as __In__ or __Out__ commonly found on Windows API
documetation, as shown in the code below, is called SAL - Source Code
Annotation language. In a C code, it is hard to figure out which
parameters are used to return values or are read-only used only as
input. The SAL solves this problem by declaring which function
parameters are input, read-only and which parameters are output.
SAL is the Microsoft source code annotation language. By using source code annotations, you can make the intent behind your code explicit. These annotations also enable automated static analysis tools to analyze your code more accurately, with significantly fewer false positives and false negatives.
– http://msdn.microsoft.com/en-us/library/hh916383.aspx
HANDLE CreateRemoteThreadEx(
__in__ HANDLE hProcess,
__in__ LPSECURITY_ATTRIBUTES lpThreadAttributes,
__in__ SIZE_T dwStackSize,
__in__ LPTHREAD_START_ROUTINE lpStartAddress,
__in__ LPVOID lpParameter,
__in__ DWORD dwCreationFlags,
__in__ LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList,
__out__ LPDWORD lpThreadId
);
DWORD WINAPI FormatMessage(
_In_ DWORD dwFlags,
_In_opt_ LPCVOID lpSource,
_In_ DWORD dwMessageId,
_In_ DWORD dwLanguageId,
_Out_ LPTSTR lpBuffer,
_In_ DWORD nSize,
_In_opt_ va_list *Arguments
);
To allow those annotations in the source code, it is necessary to add the header #include <sal.h>. This SAL annotation is not standard among C++ compilers and is not defined by any C or C++ standard, as a result, the annotations only works on MSVC - Microsoft Visual C++ Compiler. This feature can be implemented in a portable way with macros.
SAL Fundamentals:
| SAL Annotatio | Description |
|---|---|
_In_ | Input parameter - read only argument no modified inside the by the function. |
| Generally has the const qualifier such as const char*. | |
_In_Out_ | Optional input parameter, can be ignored by passing a null pointer. |
_Out_ | Output paramenter - Argument is written by the called function. It is generally a pointer. |
_Out_opt_ | Optional output parameter. Can be ignored by setting it to null pointer. |
_Inout_ | Data is passed to the function and pontentially modified. |
_Outptr_ | Output to caller. The value returned by written to the parameter is pointer. |
_Outptr_opt_ | Optional output pointer to caller, can be ignored by passing NULL pointer. |
Note: if the parameter is not annotated with _opt_ the caller is not
supposed to pass a NULL pointer, otherwise the parameter must be
annotated with _In_opt_, _Out_opt_ and etc.
Usage example:
- This annotation enhances the readability by telling reader which parameters are input and which parameters are output or used for returning values.
File: sal1.cpp
#include <sal.h> // Microsft's Source Code Annotation Language
#include <iostream>
// Computes elementwise product of two vectors
void vector_element_product(
_In_ size_t size,
_In_ const double xs[],
_In_ const double ys[],
_Out_ double zs[]
){
for(int i = 0; i < size; i++){
zs[i] = xs[i] * ys[i];
}
}
void showArray(size_t size, double xs[]){
std::cout << "(" << size << ")[ ";
for(int i = 0; i < size; i++){
std::cout << xs[i] << " ";
}
std::cout << "] ";
}
int main(){
double xs [] = {4, 5, 6, 10};
double ys [] = {4, 10, 5, 25};
double zs [4];
vector_element_product(4, xs, ys, zs);
std::cout << "xs = "; showArray(4, xs); std::cout << "\n";
std::cout << "ys = "; showArray(4, ys); std::cout << "\n";
std::cout << "zs = "; showArray(4, zs); std::cout << "\n";
}Compiling:
- MSVC (CL.EXE):
$ cl.exe sal1.cpp /nologo /Fe:sal1-a.exe && sal1-a.exe
sal1.cpp
C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.12.25827\include\xlocale(313): warning C4530: C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc
xs = (4)[ 4 5 6 10 ]
ys = (4)[ 4 10 5 25 ]
zs = (4)[ 16 50 30 250 ]- Mingw/G++
$ g++ sal1.cpp -o sal1-b.exe -std=c++11 && sal1-b.exe
xs = (4)[ 4 5 6 10 ]
ys = (4)[ 4 10 5 25 ]
zs = (4)[ 16 50 30 250 ]Note: It doesn’t work on Linux or other OSes. But it can be implemented with header files.
Open Source SAL Implementation:
- Source-code annotation language (SAL) compatibility header -
https://github.com/nemequ/salieri
- “Salieri is a header which provides definitions for Microsoft’s source-code annotation language (SAL). Simply drop the header into your code and use it instead of including <sal.h> directly, and you can use SAL annotations even if you want your program to be portable to compilers which don’t support it.”
- “SAL provides lots of annotations you can use to describe the behavior of your program. There is a Best Practices and Examples (SAL) page on MSDN if you want to get a very quick idea of how it works, but the basic idea is that you end up with something like this:”
References:
- Understanding SAL - Visual Studio | Microsoft Docs
- Annotating Function Parameters and Return Values
- Using SAL Annotations to Reduce C-C++ Code Defects
- Best Practices and Examples (SAL)
- What is In in C++? - Stack Overflow
- Preventing bugs, and improving code quality with Microsoft SAL (Part 2, custom preconditions for structs & objects) | Alexander Riccio
- SQLite Source Code Annotated with SAL - https://github.com/ariccio/SQLite-Test-SAL and Using SAL in the SQLite API | Alexander Riccio
- SAL Annotations: Don’t Hate Me Because I’m Beautiful – OSR
Unlike Linux, MacOSX and BSD where the API supports unicode UTF-8, the Windows API only supports ANSI enconding (char) and UTF16 or Unicode with 2 bytes per character wchar_t.
Macros and types for enconding portability
The following macros are widely used by Windows API for portability between ANSI and Unicode:
- Strings:
- std::string (UTF8 enconding) - Ordinary string (aka multi-byte string)
- std::wstring (UTF-16 enconding) - Wide string - string defined as array of wide characters wchar_t.
- TCHAR (Header: <tchar.h>) - When the UNICODE is defined TCHAR becomes wchar_t, otherwise, it becomes char.
#ifdef _UNICODE
typedef wchar_t TCHAR;
#else
typedef char TCHAR;
#endif- String Literal _T or TEXT macro.
#ifdef _UNICODE
#define _T(str) L##str
#define TEXT(c) L##str
#else
#define _T(str) str
#define TEXT(str) str
#endif- Character array type definition:
String Literals
- Utf-8 string literal (narrow characters or multibyte string) - cannot be used with Windows APIs as they will interpret those string literals as ANSI, thus not all characters will be represented.
| Type | Definition | |
|---|---|---|
| LPSTR | char* | |
| LPCSTR | const char* | |
| LPWSTR | wchar_t* | |
| LPCWSTR | const wchar_t* | |
| LPTSTR | TCHAR* | |
| LPCTSTR | const TCHAR* | |
"UTF8 - Unicode 8 bits multi-byte literal";
// Note: It doesn't work with Windows APIs (Windows specific functions)
char utf8_text [] = "Random text in Chinese script (UTF8): 读写汉字1";- Utf-16 string literal (wide characters - wchar_t). Windows Unicode APIs or functions only works with wide characters (wchar_t).
L"UTF16 Wchar wide chracters literal";
wchar_t utf16_text [] = L"Random text in Chinese script (UTF16): 读写汉字1";- String prefixed with _T or TEXT. If Unicode is defined the string literal becomes an unicode UTF16 string literal and prefix ‘L’ is added to the string, otherwise nothing happens.
TCHAR text [] = _T("Random text in Chinese script 读写汉字1");
// OR
TCHAR text [] = TEXT("Random text in Chinese script 读写汉字1");If UNICODE is not defined, it becomes:
char text [] = "Random text in Chinese script 读写汉字1";If Unicode is defined, it becomes:
wchar_t text [] = L"Random text in Chinese script 读写汉字1";Windows APIs - ANSI X Unicode version
Almost every function in Windows API such as CreateDirectory has an ANSI and Unicode UTF16 (with wide chars wchar_t) version. The ANSI version of CreateDirectory API is CreateDirectoryA (suffix A) and the unicode version is CreateDirectoryW. The API CreateDirectory is expanded to CreateDirectoryW if #define UNICODE preprocessor flag is not defined, otherwise it is expanded to CreateDirectoryA.
- ANSI Version:
BOOL CreateDirectoryA(
LPCSTR /* const char */ lpPathName,
LPSECURITY_ATTRIBUTES lpSecurityAttributes
);- Unicode Version:
BOOL CreateDirectoryW(
LPCWSTR /* const wchar_t* */ lpPathName,
LPSECURITY_ATTRIBUTES lpSecurityAttributes
);In C++, it is better and safer to use std::string (UTF8 string) or std::wstring (wchar_t) wide unicode string since they can be modified at runtime and can take care of memory allocation and deallocation. However, it is worth knowing the C-functions for the purposing of reading and understanding Windows API codes which are mostly written in C rather than C++.
The following C-functions are widely used on many C-codes for Windows and Unix-like operating systems. Nowadays, the APIs of most Unix-like operating systems uses unicode UTF8 (char) by default, while most low level Windows API only supports Wide unicode (wchar_t). Windows.
| char | wchar_t - Wide character | |
| UTF8 | UTF16 - Wide Unicode | Description |
|---|---|---|
| strlen | wcslen | Get string length |
| strcmp | wcscmp | Comparre string |
| strcpy | wcsncpy | Copy N-characters from one string to another |
| strcat | wcscat | Concatenat string |
| strtod | wcstod | Convert wide string to double |
Signature of Wide unicode functions:
- Length of wide string
size_t wcslen (const wchar_t* wcs);- Copy wide string
wchar_t* wcscpy (wchar_t* destination, const wchar_t* source);- Concatenate wide string
wchar_t* wcscat (wchar_t* destination, const wchar_t* source- Source Code: src/windows/winapi-enconding1.cpp
- Gist: winapi-enconding1.cpp
Compiling with GCC:
# Build
$ g++ winapi-encoding1.cpp -o out-gcc.exe -std=c++14
# Compile
$ out-gcc.exe Compiling with MSVC:
- Note: If there is any unicode literal in the source, such as some text in Chinese or Hidi script, it is necessary to compile with the options (/source-charset:utf-8 /execution-charset:utf-8), otherwise the
# Build
$ cl.exe winapi-encoding1.cpp user32.lib /EHsc /Zi /nologo /source-charset:utf-8 /execution-charset:utf-8 \
/Fe:out-msvc.exe
# Run
$ out-msvc.exe Headers:
- To enable the expansion to unicode versions of WinAPIs, the flags
UNICODE and
_UNICODEmust be enabled. For instance, if those flags are enabled CreateDirectory is expanded to CreateDirectoryW and TCHAR is expanded to wchar_t. Otherwise, CreateDirectory is expanded to CreateDirectoryA and TCHAR to char. - Note: The unicode flags must be defined before any windows specific header such as <windows.h> or <tchar.h>.
#include <fstream>
#include <string>
#include <sstream>
// Enable Unicode version of Windows API compile with -DWITH_UNICODE
#ifdef WITH_UNICODE
#define UNICODE
#define _UNICODE
#endif
#include <windows.h>
#include <tchar.h>Experiment 1 - Print to console:
// ===========> EXPERIMENT 1 - Print to Console ============//
std::cout << "\n ===>>> EXPERIMENT 1: Print to terminal [ANSI/UTF8] <<<=== " << std::endl;
{
std::cout << " [COUT] Some text example - указан - 读写汉字1 " << "\n";
std::wcout << L" [WCOUT] Some text example - указан - 读写汉字1 " << L"\n";
}Output:
- This piece of code fails because the Windows’ console (cmd.exe) cannot print unicode text by default. It needs to be configured before printing unicode, otherwise it will print garbage.
===>>> EXPERIMENT 1: Print to terminal [ANSI/UTF8] <<<
[COUT] Some text example - указан - 读写汉字
[WCOUT] Some text example -
Experiment 2 - Print to File
// ===========> EXPERIMENT 2 - Print to File ============//
std::cout << "\n ===>>> EXPERIMENT 2: Write non ANSI Chars to File <<<=== " << "\n";
std::stringstream ss;
ss << " Text in Cyrllic Script: Если указан параметр " << "\n"
<< " Text in Chinese Script: 读写汉字1 " << "\n"
<< "\n";
auto dfile = std::ofstream("logging.txt");
dfile << ss.str() << std::flush;Output: file - loggin.txt
- By opening the file logging.txt with notepad.exe, it is possible view all characters as show in the following block.
Text in Cyrllic Script: Если указан параметр
Text in Chinese Script: 读写汉字1
Experiment 3 - WinAPI - CreateDirectory
This code experiment attempts to create 3 directories:
- Directory: directoryANSI-读写汉字1 with CreateDirectoryA function (ANSI version of the underlying API)
- Directory: directoryWCHAR-读写汉字 with CreateDirectoryW (Unicode version of the API).
- Directory: directoryTCHAR-读写汉字 with CreateDirectory macro which is expanded to CreateDirectoryW when UNICODE is defined, othewise it is expanded to CreateDirectoryA.
// ===========> EXPERIMENT 4 - WinAPI - CreateDirectory ============//
std::cout << "\n ===>>> EXPERIMENT 3: WinAPI CreateDirectory <<<=== " << std::endl;
{ // -- ANSI Version of CreateDirectory API
bool res;
res = CreateDirectoryA("directoryANSI-读写汉字1", NULL);
std::cout << "Successful 1 ?= " << std::boolalpha << res << std::endl;
}
{ // -- Unicode (UTF16) - Wide character version of CreateDirectory API
bool res;
res = CreateDirectoryW(L"directoryWCHAR-读写汉字", NULL);
std::cout << "Successful 2 ?= " << std::boolalpha << res << std::endl;
}
{
// -- TCHAR Version Wide character version of CreateDirectory API
bool res;
#ifdef UNICODE
std::cout << " [INFO] UNICODE (UTF16) CreateDirectory expanded to CreateDirectoryW" << std::endl;
#else
std::cout << " [INFO] ANSI CreateDirectory expanded to CreateDirectoryA" << std::endl;
#endif
res = CreateDirectory(_T("directoryTCHAR-读写汉字"), NULL);
std::cout << "Successful 3 ?= " << std::boolalpha << res << std::endl;
}Output when compiling without -DWITH_UNICODE:
$ g++ winapi-encoding1.cpp -o out-gcc.exe -std=c++14 && out-gcc.exe
... .... ...
===>>> EXPERIMENT 3: WinAPI CreateDirectory <<<===
Successful 1 ?= true
Successful 2 ?= true
[INFO] ANSI CreateDirectory expanded to CreateDirectoryA
Successful 3 ?= true
... .... ... Directories created:
- [FAILED]
directoryANSI-读写汉å—1 - [SUCCESS]
directoryWCHAR-读写汉字- Only the Unicode (CreateDirectoryW) function works, the ANSI function CreateDirectoryA fails even if the string is encoded with UTF-8.
- [FAILED]
directoryTCHAR-读写汉å—- Without UNICODE flag, CreateDirectory expands to CreateDirectoryA.
Output when compiling without -DWITH_UNICODE:
$ g++ winapi-encoding1.cpp -o out-gcc.exe -std=c++14 -DWITH_UNICODE && out-gcc.exe
... .... ... ... ...
===>>> EXPERIMENT 3: WinAPI CreateDirectory <<<===
Successful 1 ?= true
Successful 2 ?= true
[INFO] UNICODE (UTF16) CreateDirectory expanded to CreateDirectoryW
Successful 3 ?= true
... .... ... ... ... Directories created:
- [FAILED]
directoryANSI-读写汉å—1 - [SUCCESS]
directoryWCHAR-读写汉字 - [SUCCESS]
directoryTCHAR-读写汉字
Experiment 4 - WinAPI MessageBox function.
// ===========> EXPERIMENT 4 - WinAPI - MessageBox ============//
std::cout << "\n ===>>> EXPERIMENT 4: MessageBox <<<=== " << std::endl;
DWORD const infoboxOptions = MB_OK | MB_ICONINFORMATION | MB_SETFOREGROUND;
// Text in UTF8 => Note => Windows API doesn't work with UTF8
// or multi-byte characters as the API treats the chars as they were ANSI.
char narrowText [] = "Some chinese text não inglês 读写汉字 - 学中文";
// Unicode text in UTF16
wchar_t wideText [] = L"Some chinese text não inglês 读写汉字 - 学中文";
MessageBoxA( 0, narrowText, "ANSI (narrow) text:", infoboxOptions );
MessageBoxW( 0, wideText, L"Unicode (wide) text:", infoboxOptions );Output of MessageBoxA (failure, it cannot deal with unicode UTF-8 chars):
Output of MessageBoxW (success):
This example presents how to create wrappers for WinAPI with UTF8 enconding and std::string instead of using UTF16 wide unicode wchar_t string or wstring. It is better to use UTF8 with WinAPI since UTF8 is supported on more systems than UTF16 (wide unicode) and UTF8 also enhances the interoperability.
- Source Code: src/windows/winapi-utf8.cpp
- Gist:
Functions for wide unicode UTF16 to UTF8 conversion and vice-versa: (Credits: https://gist.github.com/pezy/8571764 )
- Convert wide unicode string (std::wstring) to utf8 (std::string)
auto utf8_encode(const std::wstring &wstr) -> std::string
{
int size_needed = WideCharToMultiByte(
CP_UTF8, 0, &wstr[0],
(int)wstr.size(), NULL, 0, NULL, NULL);
std::string strTo(size_needed, 0);
WideCharToMultiByte(
CP_UTF8, 0, &wstr[0],
(int)wstr.size(), &strTo[0], size_needed, NULL, NULL);
return strTo;
}- Convert std::string (UTF8) to std::wstring
// Convert an UTF8 string to a wide Unicode String
// Credits: https://gist.github.com/pezy/8571764
auto utf8_decode(const std::string &str) -> std::wstring
{
int size_needed = MultiByteToWideChar(
CP_UTF8, 0,
&str[0], (int)str.size(), NULL, 0);
std::wstring wstrTo(size_needed, 0);
MultiByteToWideChar(
CP_UTF8, 0, &str[0],
(int) str.size(), &wstrTo[0], size_needed);
return wstrTo;
}- Wrapper for function GetUserName (GetUserNameW) which returns the user name encoded with UTF16. The unicode API is used because the ANSI versio GetUserNameA (which uses char*) would fail if the user name was written with non-ANSI characters or had any accent such as ‘ã’, ‘ó’, ‘í’ and ‘ç’.
// Requires: <windows.h>, <winbase.h> and <Lmcons.h>
auto getUserName() -> std::string
{
DWORD size = UNLEN + 1;
std::wstring buffer(size, 0x00);
//BOOL GetUserNameW(LPWSTR lpBuffer, LPDWORD pcbBuffer);
GetUserNameW(&buffer[0], &size);
buffer.resize(size - 1);
return utf8_encode(buffer);
}- Wrapper for function messageBox which encapsulates the complexity of the MessageBoxW wide unicode api.
auto messageBox(const std::string& title, const std::string& text) -> void
{
DWORD const infoboxOptions =
MB_OK | MB_ICONINFORMATION | MB_SETFOREGROUND;
::MessageBoxW(
0
,utf8_decode(text).c_str()
,utf8_decode(title).c_str()
,infoboxOptions
);
}
Main function:
std::cout << "USER NAME = " << getUserName() << std::endl;
std::string message = "Text with unicode UTF8 - 读写汉字1 - Если указан параметр ";
std::string title = "Title in UTF8 الْحُرُوف الْعَرَبِيَّة";
messageBox(title, message);
return 0;Compilation with MSVC:
$ cl.exe winapi1-utf8.cpp /EHsc /Zi /nologo /Fe:out.exe user32.lib advapi32.lib
$ out.exeCompilation with GCC:
# Compile
$ g++ winapi1-utf8.cpp -o out-gcc.exe -std=c++14
# Compile and run
$ g++ winapi1-utf8.cpp -o out-gcc.exe -std=c++14 && out-gcc.exe
# Run
$ out-gcc.exe Output:
USER NAME = archbox- Source Code: src/windows/console-utf8.cpp
- Gist: console-utf8.cpp
The class ConsoleUTF8 uses RAII - Resource Acquisition is Initialization for setting the console to UTF8 and restoring it when a class object goes out scope.
// Uses RAII for setting console to UTF8
// and restoring its previous settings.
class ConsoleUTF8{
public:
// Constructor saves context
ConsoleUTF8(){
m_config = ::GetConsoleOutputCP();
::SetConsoleOutputCP(CP_UTF8);
std::perror(" [TRACE] Console set to UTF8");
}
// Destructor restores context
~ConsoleUTF8(){
std::perror(" [TRACE] Console restored.");
::SetConsoleOutputCP(m_config);
}
private:
unsigned int m_config;
};Class ExitPrompt uses RAII for asking the user to type RETURN to exit in order to allow its output to be ovserved by blocking the program from exiting immediately when it is invoked by clicking the executable.
struct ExitPrompt{
~ExitPrompt(){
std::puts(" >>> Enter RETURN to exit");
std::cin.get();
}
};Main function:
#ifdef UTF8
auto utf8Console = ConsoleUTF8();
#endif
//auto codePage = ::SetConsoleOutputCP(CP_UTF8);
auto exitPrompt = ExitPrompt();
std::puts("Testing Console output with UTF8");
std::puts("--------------------------------");
std::puts("Text with UTF8 - SÃO JOÃO - ");
std::puts("Japanese Kanji - 漢字 ; Japanese Hiragrama - 平仮名 ");
std::puts("Cyrllic Script - Sputnik = Спутник-1");
std::puts("Greek/Latin Script = Α α, Β β, Γ γ, Δ δ, Ε ε, Ζ ζ, Η η, Θ θ");
//::SetConsoleOutputCP(codePage);
return 0;Compiling with MSVC:
// Compile and run with UTF8 flag disabled
$ cl.exe console-utf8.cpp /EHsc /Zi /nologo /Fe:out.exe && out.exe
// Compile and run with UTF8 flag disabled // Compile run with UTF8 flag enabled
$ cl.exe console-utf8.cpp /EHsc /Zi /nologo /Fe:out.exe -DUTF8 && out.exeCompiling with Mingw/GCC:
// Compile and run with UTF8 flag disabled
g++ console-utf8.cpp -o out-gcc.exe -std=c++14 -Wall && out-gcc.exe
// Compile and run with UTF8 flag disabled
g++ console-utf8.cpp -o out-gcc.exe -std=c++14 -Wall -DUTF8 && out-gcc.exeSee:
- WINAPI - SetConsoleOutputCP function - Windows Console | Microsoft Docs
- WINAPI - GetConsoleOutputCP function - Windows Console | Microsoft Docs
- How to output unicode in C++ without _setmode - Stack Overflow
- 10. Operating systems — Programming with Unicode
Print information about current process and copy itself to desktop directory.
File: src/windows/currentProcess.cpp
Compile: MSVC
$ cl.exe currentProcess.cpp /EHsc /Zi /nologo /Fe:currentProcess.exe && currentProcess.exeRunning on console (from cmd.exe or cmder terminal):
$ currentProcess.exe
=========== Current Process Info ========
PID = 5712
hProc = 0x00007FF65D890000
Executable path = C:\Users\archbox\Desktop\experiments\currentProcess.exe
Current path = c:\Users\archbox\Desktop\experimentsRunning program by clicking on it:
- If program checks whether it was launched by click, it waits for the user to type RETURN before terminating.
=========== Current Process Info ========
PID = 6916
hProc = 0x00007FF72C300000
Executable path = C:\Users\archbox\Desktop\experiments\currentProcess.exe
Current path = C:\Users\archbox\Desktop\experiments
==> Type RETURN to exit.Code:
- Function: isInOwnConsole - returns true if program was launched by click. Returns false if it was launched from any type console such as cmd.exe or cmder.
// Return true if program was launched by clicking on it,
// return false if this program was launched from command line.
auto isInOwnConsole() -> bool {
DWORD procIDs[2];
DWORD maxCount = 2;
DWORD result = GetConsoleProcessList((LPDWORD)procIDs, maxCount);
return result != 1;
}- Lambda function ExecutablePath - Returns the path of some process executable given its PID (Process ID).
auto ExecutablePath = [](int pid){
HANDLE hProc = OpenProcess( PROCESS_QUERY_INFORMATION
| PROCESS_VM_READ, FALSE, pid );
// Get process file path
std::string process_path(MAX_PATH, 0);
DWORD size = MAX_PATH;
QueryFullProcessImageNameA(hProc, 0, &process_path[0], &size);
process_path.resize(size);
CloseHandle(hProc);
return process_path;
};- Lambda function CurrentDirectory - returns current directory.
auto CurrentDirectory = []{
DWORD size = ::GetCurrentDirectory(0, nullptr);
assert(size != 0);
std::string path(size + 1, 0x00);
size = ::GetCurrentDirectory(path.size(), &path[0]);
path.resize(size);
return path;
};- Main function:
// Get current process ID
DWORD pid = GetCurrentProcessId();
// Return module handle of current process
HMODULE hProc = GetModuleHandleA(nullptr);
// Get process module
std::cout << "=========== Current Process Info ========" << std::endl;
std::cout << "PID = " << pid << std::endl;
std::cout << "hProc = 0x" << hProc << std::endl;
std::cout << "Executable path = " << ExecutablePath(pid) << std::endl;
std::cout << "Current path = " << CurrentDirectory() << std::endl;
// Copy itself to Desktop
CopyFile(ExecutablePath(pid).c_str(), "C:\\Users\\archbox\\Desktop\\appinfo.exe", false) ;
// Stop program from exiting if it was launched by clicking on it.
if(!isInOwnConsole()){
std::cout << "\n ==> Type RETURN to exit." << std::endl;
std::cin.get();
}
return EXIT_SUCCESS;This code prints to stdout (console) and to a file the list of running processes in current machine:
Source:
Parts:
- Function which prints all processes to any output stream:
// Show all processes in current machine
auto showProcessInfo(std::ostream& os) -> int {
// Get snapshot with process listing.
HANDLE hProcessSnapShot =
CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
// Instnatiate process' entry structure.
PROCESSENTRY32 ProcessEntry = { 0 };
ProcessEntry.dwSize = sizeof( ProcessEntry );
BOOL Return = FALSE;
Return = Process32First( hProcessSnapShot, &ProcessEntry );
// Returns -1 if process failed
if(!Return ) { return -1;}
do { // print process' data
os << "EXE File = " << ProcessEntry.szExeFile << "\n"
<< "PID = " << ProcessEntry.th32ProcessID << "\n"
<< "References = " << ProcessEntry.cntUsage << "\n"
<< "Thread Count = " << ProcessEntry.cntThreads << "\n"
<< "-----------------------------------------------\n";
}
while( Process32Next( hProcessSnapShot, &ProcessEntry ));
// Close handle releasing resource.
CloseHandle( hProcessSnapShot );
return 1;
}
- Main function:
// Log file
auto plog = std::ofstream("process-log.txt");
// Print all processes to stdout.
showProcessInfo(std::cout);
// Write all processes to file
showProcessInfo(plog);
// Flush buffer - force data to be written to file.
plog.flush();
std::cout << "\n ==> Type return to exit." << std::endl;
std::cin.get();
return 0;- Compiling and running:
# Build
$ cl.exe showProcesses.cpp /EHsc /Zi /nologo /Fe:showProcesses.exe
# Run:
$ showProcesses
# Run
$ showProcesses.exe - Output:
$ showProcesses.exe
... ... ... ...
-----------------------------------------------
EXE File = Registry
PID = 68
References = 0
Thread Count = 3
-----------------------------------------------
EXE File = smss.exe
PID = 308
References = 0
Thread Count = 2
-----------------------------------------------
EXE File = csrss.exe
PID = 412
References = 0
Thread Count = 10
-----------------------------------------------
EXE File = wininit.exe
PID = 484
References = 0
Thread Count = 1
-----------------------------------------------
... ... ...
API DOCS:
- CreateToolhelp32Snapshot function | Microsoft Docs
- Process32First function | Microsoft Docs
- Process32FirstW function | Microsoft Docs
This example program shows all modules, aka DLLs (Dynamic Linked Libraries) loaded by some process given its PID.
- Source: src/windows/showModulesDLL.cpp
- Gist: showModulesDLL.cpp
Compile with MSVC (cl.exe)
$ cl.exe showModulesDLL.cpp /EHsc /Zi /nologo /Fe:showModulesDLL.exe Compile with MingW/GCC:
$ g++ showModulesDLL.cpp -o showModulesDLL.exe -std=c++14 -lpsapi Running:
- List PID of all processes
# Get PID of all processes
$ tasklist
... ... ... ... ... ... ... ... ... ... ... ...
svchost.exe 88 Services 0 5,920 K
dllhost.exe 4572 Console 1 9,520 K
notepad.exe 5272 Console 1 14,048 K
vctip.exe 3564 Console 1 10,920 K
svchost.exe 1112 Services 0 5,572 K
svchost.exe 2996 Services 0 7,140 K
SearchProtocolHost.exe 5636 Services 0 11,964 K
SearchFilterHost.exe 1832 Services 0 6,104 K
mspdbsrv.exe 3416 Console 1 5,888 K
... ... ... ... ... ... ... ... ... ... ... ... ... ... - Show DLLs loaded by process dllhost.exe (PID 4572)
$ showModulesDLL.exe 4572
Process base name = DllHost.exe
Process path = C:\Windows\System32\dllhost.exe
00007FF734720000 C:\WINDOWS\system32\DllHost.exe
00007FFBFA8C0000 C:\WINDOWS\SYSTEM32\ntdll.dll
00007FFBF98C0000 C:\WINDOWS\System32\KERNEL32.
00007FFBF78C0000 C:\WINDOWS\System32\KERNELBASE.d
00007FFBF6C90000 C:\WINDOWS\System32\ucrtbase.dll
00007FFBF7EE0000 C:\WINDOWS\System32\combase.dll
... ... ... ... ... ... ... ... ... ... ... ...
00007FFBEDBA0000 C:\WINDOWS\SYSTEM32\iertutil.
00007FFBF65C0000 C:\WINDOWS\SYSTEM32\CRYPTBASE.DL
Parts:
- Class ResourceHandler<HANDLER> is a RAII (Resource Aquisition Is Initialization) for any generic resource which may not be a pointer such as an integer for a file descriptor.
template<class HANDLER>
class ResourceHandler
{
public:
using Disposer = std::function<void (HANDLER)>;
ResourceHandler(HANDLER hnd, Disposer disposer)
: m_hnd(hnd), m_fndisp(disposer)
{ }
auto get() -> HANDLER {
return m_hnd;
}
~ResourceHandler(){
m_fndisp(m_hnd);
}
// Disable copy-constructor and copy-assignment operator
ResourceHandler(const ResourceHandler&) = delete;
auto operator= (const ResourceHandler&) -> ResourceHandler& = delete;
// Move member functios
ResourceHandler(ResourceHandler&& rhs)
: m_hnd(rhs.m_hnd),
m_fndisp(rhs.m_fndisp){ }
auto operator= (ResourceHandler&& rhs){
std::swap(this->m_hnd, rhs.m_hnd);
this->m_fndisp = rhs->m_fndisp;
}
private:
HANDLER m_hnd;
Disposer m_fndisp;
};Namespace WProcess contains functions for querying processes:
namespace WProcess{
using ModuleConsumer = std::function<auto (HMODULE, const std::string&) -> void>;
auto GetName(HANDLE hProc) -> std::string;
auto GetExecutablePath(HANDLE hProc) -> std::string;
auto ForEachModule(HANDLE hProc, ModuleConsumer FunIterator) -> void;
}Main function
- Get PID (Process ID) as program argument.
DWORD pid;
DWORD flags = PROCESS_QUERY_INFORMATION | PROCESS_VM_READ;
try{
pid = std::stoi(argv[1]);
} catch(const std::invalid_argument& ex){
std::cerr << "Error invalid PID" << std::endl;
return EXIT_FAILURE;
}
// Automatically closes this handle when it goes out of scope.
auto hProc = ResourceHandler<HANDLE>{
::OpenProcess(flags, FALSE, pid),
::CloseHandle
};Print process name:
std::cout << "Process base name = "
<< WProcess::GetName(hProc.get())
<< std::endl; Print path to executable:
std::cout << "Process path = "
<< WProcess::GetExecutablePath(hProc.get())
<< std::endl;Print all DLLs used by the process:
using ModuleConsumer = std::function<auto (HMODULE, const std::string&) -> void>;
// Print all DLLs used by some process
WProcess::ForEachModule(
hProc.get(),
[](HMODULE hmod, const std::string& path) -> void
{
std::cout << std::setw(10) << hmod
<< std::setw(5) << " "
<< std::left << std::setw(45) << path
<< "\n";
}
);Functions in namespace WProcess
- WProcess::GetName
auto GetName(HANDLE hProc) -> std::string {
std::wstring basename(MAX_PATH, 0);
int n1 = ::GetModuleBaseNameW(hProc, NULL, &basename[0], MAX_PATH);
basename.resize(n1);
return utf8_encode(basename);
}- WProcess::GetExecutablePath
auto GetExecutablePath(HANDLE hProc) -> std::string {
std::wstring path(MAX_PATH, 0);
int n2 = ::GetModuleFileNameExW(hProc, NULL, &path[0], MAX_PATH);
path.resize(n2);
return utf8_encode(path);
}- WProcess::ForEachModule
auto ForEachModule(HANDLE hProc, ModuleConsumer FunIterator) -> void {
HMODULE hMods[1024];
DWORD cbNeeded;
if (::EnumProcessModules(hProc, hMods, sizeof(hMods), &cbNeeded)){
int n = cbNeeded / sizeof(HMODULE);
std::wstring path(MAX_PATH, 0);
for(int i = 0; i < n; i++){
DWORD nread = ::GetModuleFileNameExW(hProc, hMods[i], &path[0], MAX_PATH);
path.resize(nread);
if(nread) FunIterator(hMods[i], utf8_encode(path));
}
}
}Program for listing directories, similar to U*nix’s ls or Windows’ dir usign Win32 API.
Source:
- File: src/windows/listFiles.cpp
- Gist: listFiles.cpp
Compiling:
- MSVC
$ cl.exe listFiles.cpp /EHsc /Zi /nologo /Fe:listFiles.exe - Mingw/GCC
$ g++ listFiles.cpp -o listFiles.exe -std=c++14 Usage:
$ listFiles.exe "C:\*"
[TRACE] Console set to UTF8
directoryPath = C:\*
=> $GetCurrent
=> $Recycle.Bin
... . ... ... .... .. .. ...
=> pagefile.sys
=> PerfLogs
=> Program Files
=> Program Files (x86)
... ... ... ...
=> Users
=> Windows
=> Windows10Upgrade
[LOG] Handler <hFile> closed OK.
[LOG] End sucessfully
[TRACE] Console restored.
$ listFiles.exe "E:\*"
[TRACE] Console set to UTF8
directoryPath = E:\*
[LOG] Handler <hFile> closed OK.
=> Error code = 3
=> Error message = The system cannot find the path specified.
[TRACE] Console restored.
$ listFiles.exe "C:\windows\system32\*.dll" 2> log
directoryPath = C:\windows\system32\*.dll
=> aadauthhelper.dll
=> aadcloudap.dll
=> aadjcsp.dll
=> aadtb.dll
=> aadWamExtension.dll
=> AboutSettingsHandlers.dll
=> AboveLockAppHost.dll
... ... ... ...
[LOG] End sucessfullyParts
- Function: getLastErrorAsString - Returns a human readable std::string description of GetLastError().
// Print human-readable description of GetLastError() - Error Code
// Source: https://stackoverflow.com/questions/1387064 Requires:
// <string>, <sstream>, <windows.h>,
auto getLastErrorAsString() -> std::string {
//Get the error message, if any.
DWORD errorMessageID = ::GetLastError();
if(errorMessageID == 0)
return std::string();
LPSTR messageBuffer = nullptr;
static const DWORD flags =
FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_IGNORE_INSERTS;
size_t size = FormatMessageA(
flags,
NULL,
errorMessageID,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPSTR)&messageBuffer, 0, NULL);
auto message = std::string(messageBuffer, size);
auto ss = std::stringstream(message);
auto line = std::string{};
std::getline(ss, line, '\r');
//Free the buffer.
LocalFree(messageBuffer);
return line;
}- Function EnumereFiles encapsulates the WinAPIs FindFileFirstW and FindNextFileW. This function iterate over files of some directory and applies an Enumerator function taking a string (file name) and returning a boolean. The iteration continues until the enumerator function returns false.
using FileEnumerator = std::function<bool (const std::string&)>;
/** Enumerate files of some directory util enumerator function (callback) returns false.
* - path - Directory path to be listed
* - Enumerator - Functions which consumes a string (file listed) and returns bool.
* this function returns false when it is no longer interested in
* being called. When it returns false the iteration stops.
*
* - Return - Returns error code from GetLastError(). If it is successful,
* the function returns ERROR_SUCCESS.
*/
auto EnumerateFiles(const std::string& path, FileEnumerator Enumerator) -> int {
WIN32_FIND_DATAW fdata;
HANDLE hFind = INVALID_HANDLE_VALUE;
// Ensure that resource hFind is always disposed.
auto close_hFind = CloseHandleRAAI(std::bind(CloseHandleLog, hFind, "hFile"));
hFind = FindFirstFileW(utf8_decode(path).c_str(), &fdata);
if(hFind == INVALID_HANDLE_VALUE)
return GetLastError();
do { //Consumer function
if(!Enumerator(utf8_encode(fdata.cFileName))) break;
} while(FindNextFileW(hFind, &fdata) != 0);
return ERROR_SUCCESS;
}Main function:
if(argc < 2){
std::cerr << "Usage: " << argv[0] << " " << "[PATH]" << std::endl;
return EXIT_FAILURE;
}
auto utf8Console = ConsoleUTF8();
auto directoryPath = std::string{argv[1]};
std::cout << "directoryPath = " << directoryPath << "\n";
int count = 0;
// Show 50 first files.
int status = EnumerateFiles(
directoryPath,
[&count](const auto& file){
std::cout << " => " << file << "\n";
if(count++ < 50)
return true;
else
return false;
});
if(status != ERROR_SUCCESS){
std::cout << " => Error code = " << ::GetLastError() << std::endl;
std::cout << " => Error message = " << getLastErrorAsString() << std::endl;
return EXIT_FAILURE;
}
std::puts(" [LOG] End sucessfully");
return EXIT_SUCCESS;WinAPIs used:
This code enumerates all logical drivers in the current Windows machine, for instance, C:, D:, E: … and so on.
Source:
Main Function:
std::puts("Logical Drivers or Disks found in the current installation");
std::puts("------------------------------------------------");
EnumerateLogicalDriver(
[](const std::string& name){
std::cout << "Driver = " << name << std::endl;
});
auto driverList1 = LogicalDriverList<std::deque>();
std::cout << " *=> Driver list in STL container std::deque = ";
for(const auto& d: driverList1){ std::cout << d << ", "; }
std::cout << std::endl;;
auto driverList2 = LogicalDriverList<std::vector>();
std::cout << " *=> Driver list in STL container std::vector = ";
for(const auto& d: driverList2){ std::cout << d << ", "; }
std::cout << std::endl;;
return 0;Function EnumerateDriver:
- Takes a function as argument which consumes the logical driver names passed as string.
using DriverEnumerator = std::function<auto (std::string) -> void>;
auto EnumerateLogicalDriver(DriverEnumerator Consumer) -> void
{
size_t size = ::GetLogicalDriveStringsA(0, nullptr);
std::string buffer(size, 0x00);
::GetLogicalDriveStringsA(buffer.size(), &buffer[0]);
std::stringstream ss{buffer};
while(std::getline(ss, buffer, '\0') && !buffer.empty())
Consumer(buffer);
}Function LogicalDriverList;
- Templated functions which takes an STL container as type argument. It allows choosing the type of stl container which will be returned.
// Remember: Template always in header files The user can choose the
// type of container used to return the computer drivers.
template<template<class, class> class Container = std::vector>
auto LogicalDriverList()
-> Container<std::string, std::allocator<std::string>>
{
Container<std::string, std::allocator<std::string>> list{};
EnumerateLogicalDriver(
[&](const std::string& name){
list.push_back(name);
});
return list;
}Program output:
# Compiling and running with MingW/GCC
$ g++ GetLogicalDrivers.cpp -std=c++1z -o out.exe && out.exe
Logical Drivers or Disks found in the current installation
------------------------------------------------
Driver = C:\
Driver = D:\
*=> Driver list in STL container std::deque = C:\, D:\,
*=> Driver list in STL container std::vector = C:\, D:\, This sample program contains a class process builder which encapsulates the complexity of Windows API process. It can be used for launching processes, streaming process output line by line, wait for process execution, get PID and also terminate the subprocess.
Source:
- File: src/windows/winprocess.cpp
- GIST: winprocess.cpp
Compiling MSVC:
$ cl.exe winprocess.cpp /EHsc /Zi /nologo /Fe:winprocess.exe Compiling Mingw/GCC:
$ g++ winprocess.cpp -o winprocess.exe -Wall -Wextra -std=c++14Main function
The main function accepts a single argument which can be test0, test1, test2, test3 and test4. Each argument tests a different action.
int main(int argc, char** argv){
if(argc < 2){
std::cerr << "Usage: " << argv[0] << " [test0 | test1 | test2 | test3 | test4 ]" << std::endl;
return EXIT_FAILURE;
}
auto tryExit = [&argc, &argv](std::function<int ()> Action) -> void {
try {
// End current process with exit code returned
// from function
int status = Action();
std::cerr << "[SUCCESS] End gracefully";
std::exit(status);
} catch(const std::runtime_error& ex)
{
std::cerr << "[ERROR ] " << ex.what() << std::endl;
std::exit(1);
}
};
/** Stream process output to stdout line by line. Print line read form subprocess
* output as soon as it arrives. */
if(std::string(argv[1]) == "test0")
tryExit([]{
auto p = ProcessBuilder();
p.SetProgram("ping 8.8.8.8");
std::puts("Stream output of process ping to stdout.");
p.StreamLines([](std::string line){
std::cout << " line = " << line << std::endl;
return true;
});
return EXIT_SUCCESS;
});
/** Read whole process output and then print it to console and to a file.
* run $ dir . at path C:\\windows\\system32, read the whole process output
* as string printing it and saving it to a log file. (output.log)
*/
if(std::string(argv[1]) == "test1")
... ... ... ...
std::cerr << "Error: invalid option " << std::endl;
return EXIT_FAILURE;
}Command test0
The command test0 stream process (ping.exe) output line by line read from the sub-process as soon as the process prints the line.
if(std::string(argv[1]) == "test0")
tryExit([]{
auto p = ProcessBuilder();
p.SetProgram("ping 8.8.8.8");
std::puts("Stream output of process ping to stdout.");
p.StreamLines([](std::string line){
std::cout << " line = " << line << std::endl;
return true;
});
return EXIT_SUCCESS;
});Output: $ winprocess.exe test0
$ winprocess.exe test0
Stream output of process ping to stdout.
line =
line = Pinging 8.8.8.8 with 32 bytes of data:
line = Reply from 8.8.8.8: bytes=32 time=105ms TTL=127
line = Reply from 8.8.8.8: bytes=32 time=106ms TTL=127
line = Reply from 8.8.8.8: bytes=32 time=105ms TTL=127
line = Reply from 8.8.8.8: bytes=32 time=106ms TTL=127
line =
line = Ping statistics for 8.8.8.8:
line = Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
line = Approximate round trip times in milli-seconds:
line = Minimum = 105ms, Maximum = 106ms, Average = 105ms
[SUCCESS] End gracefully
Command test1
Runs the process $ dir . (dir.exe) at the directory
C::\Windows\\System32\\, reads the whole process output containing the
directory listening saving it to a string and writing it to a file named
output.log.
if(std::string(argv[1]) == "test1")
tryExit([]{
std::puts("Get output of tasklist.");
auto p = ProcessBuilder("dir .");
p.SetCWD("C:\\windows\\system32");
std::cout << "Process output = " << std::endl;
auto out = p.GetOutput();
std::cout << out << std::endl;
std::ofstream fs("output.log");
fs << " ==>>> Process output = " << "\n";
fs << " +=================+ " << "\n";
fs << out;
return EXIT_SUCCESS;
});Output: $ winprocess.exe test1
$ winprocess.exe test1
... ... ... ...
wwanprotdim.dll
wwansvc.dll
wwapi.dll
xbgmengine.dll
xbgmsvc.exe
xboxgipsvc.dll
xboxgipsynthetic.dll
xcopy.exe
xh-ZA
xmlfilter.dll
xmllite.dll
... .... ... .... ... .... Command test2
Launch a process (for window subsystem), notepad.exe and wait for its termination.
if(std::string(argv[1]) == "test2")
tryExit([]{
std::puts("Launch process and wait for its termination");
auto p = ProcessBuilder("notepad");
p.Run();
std::cout << "Waiting for process termination" << std::endl;
p.Wait();
std::cout << "Process terminated. OK." << std::endl;
return EXIT_SUCCESS;
}); Output: $ winprocess.exe test2
- The sub-process notepad.exe (window subsystem) is launched and then the program waits for its termination.
$ winprocess.exe test2
Launch process and wait for its termination
Waiting for process termination
Process terminated. OK.
[SUCCESS] End gracefullyCommand test3
Launch sub-process notepad.exe without waiting and waits for user to type RETURN. When user types this key, the process is terminated.
if(std::string(argv[1]) == "test3")
tryExit([]{
std::puts("Launch process and wait for its termination");
auto p = ProcessBuilder("notepad");
p.Run();
std::cout << "Enter RETURN to terminate process => PID = " << p.GetPID() << std::endl;
std::cin.get();
p.Terminate();
std::cout << " Process terminated OK.";
return EXIT_SUCCESS;
});Output:
$ winprocess.exe test3
Launch process and wait for its termination
Enter RETURN to terminate process => PID = 2324
Process terminated OK.[SUCCESS] End gracefullyClass ProcessBuilder
//========= File: ProcessBuilder.hpp - Header ===================//
/** Requires: <iostream> <string>, <functional> <vector> <windows.h> */
class ProcessBuilder
{
private:
// Program to be run
std::string m_program;
// Arguments passed to the program
std::vector<std::string> m_args = {};
// If this flag is true, the program is launched on console
bool m_console = true;
std::string m_cwd;
STARTUPINFO m_si = { sizeof(STARTUPINFO)};
PROCESS_INFORMATION m_pi;
public:
using SELF = ProcessBuilder&;
using LineConsumer = std::function<bool (std::string)>;
ProcessBuilder() = default;
ProcessBuilder(const std::string& program, const std::vector<std::string>& args = {});
ProcessBuilder(const ProcessBuilder&) = delete;
auto operator=(const ProcessBuilder&) = delete;
~ProcessBuilder();
ProcessBuilder(ProcessBuilder&& rhs);
auto operator=(ProcessBuilder&& rhs) -> SELF;
auto SetProgram(const std::string& program) -> SELF;
auto SetConsole(bool flag) -> SELF;
/** Set process directory.
* @param path - Process directory path.
*/
auto SetCWD(const std::string& path) -> SELF;
/** Start process without waiting for its termination. */
auto Run() -> bool;
auto Wait() -> void;
// Start process and wait for its termination.
auto RunWait() -> bool;
auto GetPID() -> DWORD;
auto Terminate() -> bool;
auto isRunning() -> bool;
auto StreamLines(LineConsumer consumer) -> bool;
auto GetOutput() -> std::string;
private:
auto ReadLineFromHandle(HANDLE hFile) -> std::pair<bool, std::string>;
}; //========= End of Class ProcessBuilder ===== // Winsock API
- Winsock 1.x - Adapation from BSD Berkley Socket API used by most Unix-like operating systems.
- Winsock 2.x - Provides new features:
- Overlapped IO
- Asynchrnous calls and callbacks
- Layered service provided - LSP architechture.
- Note: Unlike Unix implementation of sockets - BSD sockets, Winsocks API doesn’t allow read/write operations with sockets as they where files, as a result, casting to file pointer from <stdio.h> doesn’t work and leads to the program crashing at runtime. However, socket can be casted to Windows HANDLES and manipulated with Win32 File IO functions.
- Note: Windows Sockets are not portable and specific to only Windows, so in order to write an operating system agnostic network code, it is necessary to use an high level network library such as Boost-ASIO library or POCO frameworks.1
Headers and Libraries
- <windows.h>
- <winsock2.h>
Library:
Ws2_32.libWs2_32.dll
Main System Calls
Creating a socket:
- af : Address familty
PF_INETAF_INET- IP Protocol
- type: Connection-oriented (TCP) or Datagra-oriented (UDP)
SOCK_STREAM- (TCP) Connection-Oriented.SOCK_DGRAM- (UDP) Datagram-Oriented.
- protocol: Unecessary when the af is
AF_INETand can be set to 0. - Return: Socket handler and returns the constant
INVALID_SOCKETon failure.
| System Call | Target | Description |
|---|---|---|
| socket() | client or server socket | Create a socket |
| listen() | server socket | Server socket listen for incoming connections. |
| accept() | server socket | Make a server socket ccept a connection from a client socket. |
| connect() | client socket | Stablish a connection from a client socket to a server socket. |
| send() | client or server socket | Send data to socket |
| sednto() | client or server socket | Send data to non connected socket |
| recev() | client or server socket | Receives data/bytes from connected socket |
| recevfrom() | client or server socket | Receives data from non connected socket |
| shutdown() | client or server socket | Disables send and receive on socket |
| closesocket() | client or server socket | Close a socket, closing the connection. |
SOCKET socket(int af, int type, int protocol)Socket-Client Function
- s - socket object created with the function socket.
- lpName - Hostname of machine to be connected, IP address.
- nNameLen -
sizeof(struct sockaddr_in) - RETURN: Returns 0 to indicate a successfull connection and
SOCKET_ERRORfor connection failure.
int connect(SOCKET s, LPSOCKADDR lpName, int nNameLen);Byte Ordering Functions – Beej’s Guide to Network Programming
- htons() - Host to network short
- htonl() - Host ot network long
- ntohs() - Network to Host Short
- ntohl() - Network to host long
Data Structure hostent
struct hostent {
// Official name of the host (PC).
char FAR * h_name;
// A NULL -terminated array of alternate names.
char FAR * FAR *h_aliases;
// The type of address being returned; for Windows Sockets this is always PF_INET.
short h_addrtype;
// The length, in bytes, of each address; for PF_INET, this is always 4.
short h_length;
// A NULL-terminated list of addresses for the host. Addresses are returned in network byte order.
char FAR * FAR *h_addr_list;
};Data Structure in_addr
/*
* Internet address (old style... should be updated)
*/
struct in_addr {
union {
struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
struct { u_short s_w1,s_w2; } S_un_w;
u_long S_addr;
} S_un;Data structures - sockaddr and sockaddr_6
See: https://www.tenouk.com/Winsock/Winsock2example7.html
- IPv4
struct sockaddr {
ushort sa_family;
char sa_data[14];
};
struct sockaddr_in {
short sin_family;
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};- IPv6
struct sockaddr_in6 {
short sin6_family;
u_short sin6_port;
u_long sin6_flowinfo;
struct in6_addr sin6_addr;
u_long sin6_scope_id;
};
typedef struct sockaddr_in6 SOCKADDR_IN6;
typedef struct sockaddr_in6 *PSOCKADDR_IN6;
typedef struct sockaddr_in6 FAR *LPSOCKADDR_IN6;Data Structure WSAData
Before using Winsocks, it is necessary to initialize the library with the function WSAStartup and the data structure WSDATA. After the program has finished its execution, it necessary to run WSACleanup function.
typedef struct WSAData {
WORD wVersion;
WORD wHighVersion;
char szDescription[WSADESCRIPTION_LEN+1];
char szSystemStatus[WSASYS_STATUS_LEN+1];
unsigned short iMaxSockets;
unsigned short iMaxUdpDg;
char FAR* lpVendorInfo;
} WSADATA, *LPWSADATA; Example:
WSADATA wd;
// Intialize with Winsocks 1.0
WSAStartup(MAKEWORD(1, 0), &wd);
// Intialize with Winsocks 2.0
WSAStartup(MAKEWORD(2, 2), &wd);
// Intialize with Winsocks 2.0
WSAStartup(MAKEWORD(2, 0), &wd);References:
- Windows Programming/Winsock - Wikibooks, open books for an open world
- An introduction to Windows socket/Winsock 2/Windows network programming tutorial with practical C program examples
- Receive full data with recv socket function in C – BinaryTides
- Beej’s Guide to Network Programming
- Winsock Socket Programming
File: showIP.cpp
/* Show IPV4 Address of a given hostname
*===================================*/
#include <iostream>
#include <string.h>
#include <windows.h>
int main(int argc, char *argv[])
{
if(argc != 2){
std::cerr << "Usage: " << argv[0] << " <hostname> " << std::endl;
return EXIT_FAILURE;
}
// Initialize Winsock 2.2
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
hostent* host = gethostbyname(argv[1]);
char *ip = inet_ntoa(*reinterpret_cast<in_addr*>(*host->h_addr_list));
std::cout << " ipv4 Address = " << ip << std::endl;
std::cout << " hostname = " << host->h_name << std::endl;
std::cout << " Address type = " << host->h_addrtype << std::endl;
WSACleanup();
return EXIT_SUCCESS;
}
Compiling and runnign with MSVC:
$ cl.exe showIP.cpp /EHsc /Zi /nologo /Fe:out.exe ws2_32.lib && showip.exe Compiling and runnign with Mingw/GCC:
$ g++ showIP.cpp -o showip.exe -std=c++11 -lws2_32 && showip.exe Running:
$ showip.exe
Usage: showip.exe <hostname>
$ showip.exe www.google.co
ipv4 Address = 172.217.29.110
hostname = www3.l.google.com
Address type = 2
$ showip.exe www.yandex.com
ipv4 Address = 213.180.204.62
hostname = www.yandex.com
Address type = 2
$ showip.exe www.bing.ca
ipv4 Address = 204.79.197.219
hostname = a-0016.a-msedge.net
Address type = 2Source:
Build
- MSVC:
$ cl.exe client-socket-shell1.cpp /EHsc /Zi /nologo - Mingw/GCC
λ g++ client-socket-shell1.cpp -o winsock-client-shell1.exe -std=c++1z -lws2_32Usage:
STEP 1 - Set up a server with netcat from local computer or remote machine. In this case netcat is set up from a Linux box.
- Note: The IP address from the server side can be obtained with the command $ ipconfig on Windows NT and $ ifconfig on Linux, Android, MacOSX, BSD and so on.
$ nc -v -l 9090
Ncat: Version 7.60 ( https://nmap.org/ncat )
Ncat: Generating a temporary 1024-bit RSA key. Use --ssl-key and --ssl-cert to use a permanent one.
Ncat: SHA-1 fingerprint: 00D2 1683 8C75 26DC 74CD 6B3C 52BF D3DE 1FD0 18F5
Ncat: Listening on :::9090
Ncat: Listening on 0.0.0.0:9090STEP 2 - Connect to server from Windows by runnign the client program.
λ client-socket-shell1.exe
Usage: client-socket-shell1.exe [HOSTNAME or ADDRESS] [PORT]
λ client-socket-shell1.exe 192.168.18.90 9090
[SERVER SENT] >>If the netcat server is running in the same machine, the address is 127.0.0.1 or localhost and the command for connecting to the server is:
λ client-socket-shell1.exe localhost 9090
# OR:
λ client-socket-shell1.exe 127.0.0.1 9090STEP 3 - Send commands to client program from server terminal (netcat).
$ nc -v -l 9090
Ncat: Version 7.60 ( https://nmap.org/ncat )
Ncat: Generating a temporary 1024-bit RSA key. Use --ssl-key and --ssl-cert to use a permanent one.
Ncat: SHA-1 fingerprint: 00D2 1683 8C75 26DC 74CD 6B3C 52BF D3DE 1FD0 18F5
Ncat: Listening on :::9090
Ncat: Listening on 0.0.0.0:9090
Ncat: Connection from 192.168.18.161.
Ncat: Connection from 192.168.18.161:50278.
[CLIENT] Connected to server OK.
[CLIENT SHELL]>> => [ECHO]
[CLIENT SHELL]>>
STEP 4 - Type any commands from server side and they will be to the client side which will echo it back to the server.
Ncat: Connection from 192.168.18.161.
Ncat: Connection from 192.168.18.161:50278.
[CLIENT] Connected to server OK.
[CLIENT SHELL]>> => [ECHO]
[CLIENT SHELL]>> command arg0 arg1 arg2 arg3
=> [ECHO] command arg0 arg1 arg2 arg3
[CLIENT SHELL]>> ls -la
=> [ECHO] ls -la
[CLIENT SHELL]>> cd /
=> [ECHO] cd /
[CLIENT SHELL]>> uname -a
=> [ECHO] uname -a
[CLIENT SHELL]>> reverse shell - echo shell
=> [ECHO] reverse shell - echo shell
[CLIENT SHELL]>> exit
=> [ECHO] exit
[CLIENT] Disconnect gracefully - OK.STEP 5 - Output in the client terminal (Windows):
λ client-socket-shell1.exe 192.168.18.90 9090
[SERVER SENT] >>
[SERVER SENT] >> command arg0 arg1 arg2 arg3
[SERVER SENT] >> ls -la
[SERVER SENT] >> cd /
[SERVER SENT] >> uname -a
[SERVER SENT] >> reverse shell - echo shellGet client socket configuration from command line:
int main(int argc, char** argv){
if(argc < 3){
std::cerr << "Usage: " << argv[0] << " [HOSTNAME or ADDRESS] [PORT]" << std::endl;
return EXIT_FAILURE;
}
// Client configuration
const char* host = argv[1];
unsigned int port = std::stoi(argv[2]);
... ... ... ... ... ... ... ... ...Start up Winsock data structure:
- Note: WSAStartup(0x0202, &wsadata) => Intializes Winsock 2.2 API.
//Start up Winsock…
WSADATA wsadata;
int error = WSAStartup(0x0202, &wsadata);
if(error){
std::cerr << "Error: failed to initialize WinSock." << std::endl;
return EXIT_FAILURE;
}Create client socket:
// Create client socket
SOCKET client = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(client == INVALID_SOCKET){
std::cerr << "Error, I cannot create socket" << std::endl;
return EXIT_FAILURE;
}
SOCKADDR_IN addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(host);
addr.sin_port = htons(port);Attemp to connect to server and exit if there is any failure:
// Attemp to connect to server and exit on failure.
int connval = connect(client, reinterpret_cast<sockaddr*>(&addr), sizeof(addr));
if(connval == SOCKET_ERROR){
std::cerr << "Error: cannot connect to server." << std::endl;
//Returns status code other than zero
return EXIT_FAILURE;
}Send message “[CLIENT] Connected to server OK” to server once the client is connected:
std::string msgClientConnect = " [CLIENT] Connected to server OK.\n";
::send(client, msgClientConnect.c_str(), msgClientConnect.size(), 0);
std::string msg = " [CLIENT SHELL]>> ";
std::string echo;Main loop:
- Send prompt string to server “[CLIENT SHELL]>> ”
- Receive command from server typed in the server terminal by the user.
- Echo command back to server.
- If server send command “exit”, the client exits the main loop and diconnets from server sending the message ” [CLIENT] Disconnect gracefully - OK”.
bool flag = true;
while(flag){
::send(client, msg.c_str(), msg.size(), 0);
// Create a buffer with 2024 bytes or 2kb
std::string buffer(2024, 0);
//Returns the number of received bytes
int n = ::recv(client, &buffer[0], buffer.size()-1, 0);
echo = " => [ECHO] " + buffer + "\n";
::send(client, echo.c_str(), echo.size(), 0);
if(WSAGetLastError() == SOCKET_ERROR){
std::cerr << "Disconnected OK." << std::endl;
flag = false;
break;
} else {
buffer.resize(n);
if(buffer == "exit\n" ){
std::string exitMessage = " [CLIENT] Disconnect gracefully - OK.\n";
::send(client, exitMessage.c_str(), exitMessage.size(), 0);
std::cerr << "[LOG] I got an exit message. Shutdowing socket now!" << "\n";
std::cerr << "[LOG] Gracefully disconnecting application" << "\n";
std::cerr.flush();
break;
}
std::cout << " [SERVER SENT] >> " << buffer ; //<< std::endl;
// Force writing buffer to the stdout
std::cout.flush();
}
}Cleanup Winsock, release resource and exit application.
std::cerr << "Finished." << std::endl;
::closesocket(client);
::WSACleanup();
// Returns status code 0
return EXIT_SUCCESS;Windows provides many ready-to-use high level APIs for accessing most used internet procols such as Http and Ftp, which makes easier to deal with those protocols without reiventing the whell and caring about their implementation or low level details. Those APIs are exposed through the DLLs wininet.dll and urlmon.dll.
See: WinINet Functions | Microsoft Docs
Functions in wininet.dll
- InternetOpen
- Initializes Winnet environment. This function must be called before any other Winnet function.
HINTERNET WINAPI InternetOpen(
LPCTSTR lpszAgent,
DWORD dwAccessType,
LPCTSTR lpszProxyName,
LPCTSTR lpszProxyBypass,
DWORD dwFlags
);- InternetConnect
- Starts new HTTP or FTP session
HINTERNET InternetConnect(
HINTERNET hInternet,
LPCTSTR lpszServerName,
INTERNET_PORT nServerPort,
LPCTSTR lpszUsername,
LPCTSTR lpszPassword,
DWORD dwService,
DWORD dwFlags,
DWORD_PTR dwContext
);- HttpOpenRequest
- HttpQueryInfo
- HttpAddRequestHeaders
- HttpSendRequest
- HttpSendRequest
- InternetReadFile
- InternetCloseHandle
- Close internet connection and ends any ongoing operation.
BOOL InternetCloseHandle(
HINTERNET hInternet
);- InternetReadFile
BOOL InternetReadFile(
HINTERNET hFile,
LPVOID lpBuffer,
DWORD dwNumberOfBytesToRead,
LPDWORD lpdwNumberOfBytesRead
);Source:
- File: src/windows/winlNet-basic.cpp
- GIST: winlNet-basic.pp
Compiling and running:
Compile with MSVC:
$ cl.exe winlNet-basic.cpp /EHsc /Zi /nologo /Fe:winlNet.exeCompile with Mingw/GCC:
$ g++ winlNet-basic.cpp -o winlNet-basic.exe -lwininet -lurlmon -std=c++14Running:
$ winlNet-basic.exe
Download successful OK.
Download failed.
{
"args": {},
"headers": {
"Cache-Control": "no-cache",
"Connection": "close",
"Host": "www.httpbin.org",
"User-Agent": "Fake browser"
},
"origin": "177.36.10.17",
"url": "http://www.httpbin.org/get"
}
Öa/�
Compilation finished at Mon Sep 3 09:53:07Parts
- Function downloadFile - Wrappers WinlNet function URLDownloadToFileA (ANSI version of URLDownloadToFile) to make it more C++-friendly. This function just downloads a file from a URL.
HRESULT downloadFile(std::string url, std::string file){
HRESULT hr = URLDownloadToFileA(
// (pCaller) Pointer to IUknown instance (not needed)
NULL
// (szURL) URL to the file that will be downloaded
,url.c_str()
// (szFileName) File name that the downloaded file will be saved.
,file.c_str()
// (dwReserved) Reserverd - always 0
,0
// (lpfnCB) Status callback
,NULL
);
return hr;
}Tests HTTP GET request to http:://www.httpbin.org/get
void testHTTPRequest(){
// Reference: http://www.cplusplus.com/forum/beginner/75062/
HINTERNET hConnect = InternetOpen("Fake browser",INTERNET_OPEN_TYPE_PRECONFIG,NULL, NULL, 0);
if(!hConnect){
std::cerr << "Error: Connection Failure.";
return;
}
HINTERNET hAddr = InternetOpenUrl(
hConnect
,"http://www.httpbin.org/get"
,NULL
,0
,INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_KEEP_CONNECTION
,0
);
if ( !hAddr )
{
DWORD errorCode = GetLastError();
std::cerr << "Failed to open URL" << '\n' << "Error Code = " << errorCode;
InternetCloseHandle(hConnect);
return;
}
// Buffer size - 4kb or 4096 bytes
char bytesReceived[4096];
DWORD NumOfBytesReceived = 0;
while(InternetReadFile(hAddr, bytesReceived, 4096, &NumOfBytesReceived) && NumOfBytesReceived )
{
std::cout << bytesReceived;
}
InternetCloseHandle(hAddr);
InternetCloseHandle(hConnect);
} // --- EoF testHTTPRequest() --- //
Main function:
// ================== File Download ========================= //
//
HRESULT hr;
hr = downloadFile("http://httpbin.org/image/jpeg", "image.jpeg");
if(SUCCEEDED(hr))
std::cout << "Download successful OK." << '\n';
else
std::cout << "Download failed." << '\n';
hr = downloadFile("httpxpabin.org/image/jpeg-error", "image2.jpeg");
if(SUCCEEDED(hr))
std::cout << "Download sucessful OK." << '\n';
else
std::cout << "Download failed." << '\n';
//=============== HTTP Protocol ===================================//
//
testHTTPRequest();
if(!launchedFromConsole()){
std::cout << "Type RETURN to exit" << std::endl;
std::cin.get();
}
return 0;- http - WinInet C++ Wrapper - Code Review Stack Exchange
- Using WinInet.dll for Data Exchange between Terminals via the Internet - MQL5 Articles
- Введение в WinInet (In Russian.)
- IEWinINet API,WinInet的异步使用方法 - 金石开 - 博客园
- Using the WinInet API to access the internet from Visual Basic 6 - Le Kevin
- WinInet API Programming
This code contains a minimal graphical user interface with Windows API.
Source:
- File: src/windows/gui-basic1.cpp
- GIST: gui-basic1.cpp
Compiling:
- MSVC
# Build
$ cl.exe gui-basic1.cpp /EHsc /Zi /nologo /Fe:gui-basic1.exe user32.lib gdi32.lib - Mingw/GCC:
$ g++ gui-basic1.cpp -o gui-basic1.exe -std=c++1z -g -lgdi32 -luser32Running:
The executable gui-basic1.exe can be run by clicking on it or by launching it from console (cmd.exe). However, it will not open any console and program statements for printing to stdout will have no effect since the program was compiled for the Windows subsystem rather than for the console subsystem.
- Window subsystem entry point
The entry point of a GUI program is no longer the main function, it is now
the WinMain function which is the entry point of the window
subsystem. The name ‘WINAPI’ is just a macro which is expanded to
__stdcall, a calling convention qualifier.
Parameters:
- hInstance => Handler to current program.
- hPrevInstance => Legacy and used for backward compatibility reasons.
- lpCmdLine => Command line
- nCmdShow =>
int WINAPI WinMain(
// Handle to current application isntance
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
// Command line
LPSTR lpCmdLine,
int nCmdShow
){
... .... ...
return 0;
}- Logging with OutputDebugString
It is not possible to visualize the output printed to stdout or stderr of a program compiled for the Window subystem since no terminal is opened and even launching the program in the console (cmd.exe or cmder) does not print anything. A workaround to this hurdle is to print to a file or redirect stdout or stderr to a file stream. Another better solution is to use the API OutputDebugString as its output is sent to shared memory and can be captured with the DebugView (download) sysinternals tool.
int WINAPI WinMain( ... ){
OutputDebugString("Starting WinMain Application");
std::puts("It will not print to Console - Starting WinMain Application");
... ... ...
OutputDebugString("Registered Window Class OK.");
... ...
OutputDebugString(" [INFO] Exiting application. OK.");
// Success status code
return 0;
}The sysinternal tool DebugView is useful for debugging and visualizing logging of any program not able to print to console such as graphical programs compiled to window subsystem, DLL (Dynamic Linked Libraries), services (aka daemons), servers and etc.
Intialize Window class structure:
// ---------- Within WinMain function ----------//
//Window class name must be unique
const char wincClassName [] = "NameOfWindow";
// Win32 Window class structure
WNDCLASSEX wc;
// Win32 message structure
MSG Msg;
// Name to identify the class with.
wc.lpszClassName = wincClassName;
//Pointer to the window procedure for this window class.
wc.lpfnWndProc = windowProcedure;
// 1 - Register Windows Size
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
//Amount of extra data allocated for this class in memory. Usually 0
wc.cbClsExtra = 0;
//Amount of extra data allocated in memory per window of this type. Usually 0.
wc.cbWndExtra = 0;
//Handle to application instance (that we got in the first parameter of WinMain()).
wc.hInstance = hInstance;
// Large (usually 32x32) icon shown when the user presses Alt+Tab.
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
// Cursor that will be displayed over our window.
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
// Background Brush to set the color of our window.
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); // (HBRUSH) CreateSolidBrush(RGB(10, 20, 30)); //
// Background Brush to set the color of our window.
wc.lpszMenuName = NULL;
// Small (usually 16x16) icon to show in the taskbar and in the top left corner of the window.
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
OutputDebugString("Registered Window Class OK.");Register Window Class:
if(!RegisterClassEx(&wc)) {
MessageBox(NULL,
"Window Registration Failed!",
"Error!",
MB_ICONEXCLAMATION | MB_OK);
//Error status code
return -1;
}
std::cout << "Class Registered" << std::endl;Create Window object (hwnd - which is a handler to window object)
int width = 500, height = 400;
int pos_left = 400, pos_top = 100;
HWND hwnd = CreateWindowA(
wc.lpszClassName,
"Title of Window",
WS_OVERLAPPEDWINDOW,
pos_left,
pos_top,
width,
height,
nullptr,
nullptr,
hInstance,
nullptr
);
OutputDebugString(" [INFO] Window created OK");Display Window:
ShowWindow(hwnd, nCmdShow);
std::cout << "nCmdShow = " << nCmdShow << std::endl;
UpdateWindow(hwnd);Start message loop and processing events:
- The message loops receives messages (akas event) from the operating systems and relays them to the window procedure function or callback which processes the message. In most graphical programs, the program is not in control of the control flow, instead the operating system or window system which calls the program by sending events to it.
//---- Message Loop ----------//
while(GetMessage(&Msg, NULL, 0, 0) > 0 ){
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}Print message when program ends:
OutputDebugString(" [INFO] Exiting application. OK.");Whenever the window is minimized, moved or resized or dragged, the operating system sends messages to the program by calling the registered window procedure (callback), in this case the function windowProcedure is called whenever an event happens.
In this type of event-driven program, the program does not manage the control the control flow, instead is the operating system which determines the controls by sending events and the program only responds the events.
Notes:
- The name ‘CALLBACK’ is just a macro for
__stdcallcalling convention. - The parameter hwnd is the Window handler and is the Window registered in the WinMain function.
- The parameter msg is the message sent by the operating system
whenever an event happens, when the Window is created, it sends a
WM_CREATEmessage; when the user clicks at the close button at top right corner, the operating system sends a messageWM_CLOSE. - As in any event-driven GUI API, no blocking function calls or any function call which can take any significant dealay should be executed inside the Window Procedure or callback as it is supposed to return as fast as possible. Otherwise, the GUI will freeze and become unresponsive while the blocking call is being executed. Those blocking calls such as read line from console, download file, process a huge file and so on should be carried out in another thread or that will compromise the GUI usability.
- The full list of messages that the operating sytem can sed can be
found at:
- List Of Windows Messages - https://wiki.winehq.org/List_Of_Windows_Messages
- List of Windows Messages - https://autohotkey.com/docs/misc/SendMessageList.htm
- List of windows messages with their description WM
// Window Procedure - Process window messages or events
LRESULT CALLBACK windowProcedure (
HWND hwnd // Window Handle (Window object)
,UINT msg // Window Message
,WPARAM wParam // Additional message information
,LPARAM lParam // Additional message information
){
// Variable initialized one.
static auto ignored_messages = std::set<UINT>{
WM_MOUSEMOVE, WM_NCHITTEST, WM_SETCURSOR, WM_IME_NOTIFY
};
// Ignore messages which can flood the logging
// if(msg != WM_MOUSEMOVE && msg != WM_NCMOUSEMOVE
// && msg != WM_QUIT && msg != WM_NCHITTEST )
if(ignored_messages.find(msg) == ignored_messages.end())
OutputDebugString(WinMessageToString(msg).c_str());
... ... ... ... ... ... ... ... ... ... ... ...
// Process messages
switch(msg)
{
case WM_CREATE:
SetWindowTextA(hwnd, "Change Window Title");
OutputDebugString(" [INFO] Window created. OK.");
break;
case WM_CLOSE:
OutputDebugString(" [INFO] Window closed. OK.");
DestroyWindow(hwnd);
break;
}
...
return 0;
}Full message (events) processing:
// Process messages
switch(msg)
{
case WM_CREATE:
SetWindowTextA(hwnd, "Change Window Title");
OutputDebugString(" [INFO] Window created. OK.");
break;
case WM_CLOSE:
OutputDebugString(" [INFO] Window closed. OK.");
DestroyWindow(hwnd);
break;
case WM_DESTROY:
OutputDebugString(" [INFO] Exiting application. OK.");
PostQuitMessage(0);
break;
case WM_MOVE:
std::cerr << " [INFO] Move window." << std::endl;
break;
case WM_PAINT:
{
// GDI - Graphics Devices Interface Here
//--------------------------------------------
PAINTSTRUCT ps;
HDC hdc;
// std::cerr << " [INFO] Windown painting" << std::endl;
hdc = BeginPaint(hwnd, &ps);
std::string text = "Hello world Window!";
TextOutA(hdc, 125, 200, text.c_str(), text.size());
Ellipse(hdc, 100, 100, 160, 160);
Rectangle(hdc, 100, 100, 160, 160);
EndPaint(hwnd, &ps);
}
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}Paint message and GDI - Graphics Device Interface
- The paint message is sent to the program whenever the window is moved, resized, minimized, maximized, overlaped and so on. This case WM_PAINT statement uses GDI for drawing a text and square to the screen.
case WM_PAINT:
{
// GDI - Graphics Devices Interface Here
//--------------------------------------------
PAINTSTRUCT ps;
HDC hdc;
// std::cerr << " [INFO] Windown painting" << std::endl;
hdc = BeginPaint(hwnd, &ps);
std::string text = "Hello world Window!";
TextOutA(hdc, 125, 200, text.c_str(), text.size());
Ellipse(hdc, 100, 100, 160, 160);
Rectangle(hdc, 100, 100, 160, 160);
EndPaint(hwnd, &ps);
}Function WinMessageToString - this function called in the beggining of the window procedure takes a WM message as parameter and returns a human-readable description of the message code as parameter. The window procedure uses this function and the WinAPI function OutputDebugString to log the received messages (events) which can visualized with the DebugView sysinteral tool.
// Window Procedure - Process window messages or events
LRESULT CALLBACK windowProcedure ( ... ){
// Variable initialized one.
static auto ignored_messages = std::set<UINT>{
WM_MOUSEMOVE, WM_NCHITTEST, WM_SETCURSOR, WM_IME_NOTIFY
};
// Ignore messages which can flood the logging
// if(msg != WM_MOUSEMOVE && msg != WM_NCMOUSEMOVE
// && msg != WM_QUIT && msg != WM_NCHITTEST )
if(ignored_messages.find(msg) == ignored_messages.end())
OutputDebugString(WinMessageToString(msg).c_str());
... ... ... Function WinMessageToString
/** Get a human-readable description of a Windows message as a
* string */
auto WinMessageToString(UINT msg) -> std::string {
/** Database of Windows messages - full list of messages here:
* https://wiki.winehq.org/List_Of_Windows_Messages
*/
static auto WindowMessages = std::map<UINT, std::string>{
{1, "WM_CREATE"}, {2, "WM_DESTROY"}, {5, "WM_SIZE"},
{6, "WM_ACTIVATE"}, {13, "WM_SIZE"}, {22, "WM_SETVISIBLE"},
{23, "WM_ENABLE"}, {29, "WM_PAINT"}, {3, "WM_MOVE"}, {30, "WM_CLOSE"},
{32, "WM_SETCURSOR"}, {72, "WM_FULLSCREEN"}, {85, "WM_COPYDATA"},
{512, "WM_MOUSEMOVE"},{132, "WM_NCHITTEST"}, {641, "WM_IME_SETCONTEXT"},
{8, "WM_KILLFOCUS"}, {134, "WM_NCACTIVATE"}, {28, "WM_ACTIVATEAPP"},
{160, "WM_NCMOUSEMOVE"}, {161, "WM_NCLBUTTONDOWN"},
{36, "WM_GETMINMAXINFO"}, {642, "WM_IME_NOTIFY"}, {433, "WM_CAPTURECHANGED"},
{534, "WM_MOVING"}, {674, "WM_NCMOUSELEAVE"}, {675, "WM_MOUSELEAVE"},
{532, "WM_SIZING"}, {533, "WM_CAPTURECHANGED"}, {127, "WM_GETICON"},
{20, "WM_ERASEBKGND"}, {70, "WM_WINDOWPOSCHANGING"}, {71, "WM_WINDOWPOSCHANGED"},
{273, "WM_COMMAND"}, {274, "WM_SYSCOMMAND"}, {275, "WM_TIMER"}, {513, "WM_LBUTTONDOWN"},
{514, "WM_LBUTTONUP"}
};
// Code for debugging messages sent to Window
static std::stringstream ss;
ss.str("");
ss << " [TRACE] WNPROC Message => "
<< " Code = " << msg;
if(WindowMessages.find(msg) != WindowMessages.end())
ss << " ; Message = " << WindowMessages[msg];
else
ss << " ; Message = Unknown ";
return ss.str();
}This code presents a minimal Win32 GUI graphical user interface without the WinMain function entry point.
Source:
This code is similar to the previous example, the difference is the changing of the entry point function from non-standard WinMain to main.
- Before - gui-basic1.cpp
int WINAPI WinMain(
// Handle to current application isntance
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
// Command line
LPSTR lpCmdLine,
int nCmdShow
){
... .... ...
return 0;
}- After - gui-without-winmain.cpp
int main(int argc, char** argv){
//---- Get WinMain Parameters ----//
HINSTANCE hInstance = GetModuleHandle(NULL);
STARTUPINFO si;
GetStartupInfo(&si);
int nCmdShow = si.wShowWindow;
... ... ... ...
return 0
}Compiling with MSVC for console subsystem
Produces: gui-without-winmain.exe
When the user clicks at the application’s executable file, a terminal is opened alongside the window where it is possible to view the printed messages.
$ cl.exe gui-without-winmain.cpp /EHsc /Zi /nologo user32.lib gdi32.lib By clicking at the program the Window is opened with a terminal:
Compiling with MSVC for window subsystem
When the program is compiled for the window subsystem, no terminal is opened as any Window’s GUI application.
$ cl.exe gui-without-winmain.cpp /EHsc /Zi /nologo /link /subsystem:windows /entry:mainCRTStartup user32.lib gdi32.lib Note: the compiler flags.
- /subsystem:windows => Compiles for Windows subsystem no terminal is opened. It actually, just changes a flag in the PE32 executable file.
- /entry:mainCRTStartup => Changes program entry-point
Compiling with Mingw/GCC for console subsystem
Any program is compiled for the console subystem by default.
$ g++ gui-without-winmain.cpp -o gui-without-winmain.exe -std=c++1z -g -lgdi32 -luser32Compiling with Mingw/GCC for window subsystem
The flag (-Wl,-subsystem,windows) is required for compiling sources to the windows subsystem.
$ g++ gui-without-winmain.cpp -o gui-without-winmain.exe -std=c++1z -g -lgdi32 -luser32 -Wl,-subsystem,windowsThis example demonstrates how to dynamic load functions from a shared library at runtime with WinAPIs Loadlibrary, GetProcAddress and FreeLibrary.
Source:
- File: src/windows/dynamic-loading1.cpp
- GIST: dynamic-loading1.cpp
Types of loading:
- Implicit loading (static loading) - the DLL is linked at compile-time and the application doesn’t refer to the DLL file directly.
- Explicit loading (dynamic loading) - the DLL is linked at runtime or loaded at runtime and the application refer to the DLL file and its function explicitly using the WinAPIs - LoadLibrary, GetProcAddress and FreeLibrary.
This code loads the function URLDownloadToFile at runtime from the DLL (Dynamically Linked Library) or shared library urlmon.dll. This function is used to donwload the image file from the URL http://httpbin.org/image/jpeg as file1.jpeg and file2.jpeg.
Signature of URLDownloadToFileW (wide unicode version) of URLDownloadToFile.
HRESULT URLDownloadToFile(
LPUNKNOWN pCaller,
LPCTSTR szURL,
LPCTSTR szFileName,
_Reserved_ DWORD dwReserved,
LPBINDSTATUSCALLBACK lpfnCB
);
HRESULT URLDownloadToFileW(
LPUNKNOWN pCaller,
LPCWSTR szURL,
LPCWSTR szFileName,
_Reserved_ DWORD dwReserved,
LPBINDSTATUSCALLBACK lpfnCB
);Compiling and running with MSVC:
$ cl.exe dynamic-linking1.cpp /EHsc /Zi /nologo /Fe:out.exe && out.exe
dynamic-linking1.cpp
[INFO] DLL Loaded OK
============ EXPERIMENT 1 ===================
[INFO] Function loaded OK
[INFO] Download successful OK.
============ EXPERIMENT 2 ===================
[INFO] Download successful OK.
[INFO] Application ended gracefully. OK.Compiling and running with Mingw/GCC (GNU C/C++ Compiler):
$ g++ dynamic-loading1.cpp -o out2.exe -std=c++1z && out2.exe
[INFO] DLL Loaded OK
============ EXPERIMENT 1 ===================
[INFO] Function loaded OK
[INFO] Download successful OK.
============ EXPERIMENT 2 ===================
[INFO] Download successful OK.
[INFO] Application ended gracefully. OK.
Parts inside the main function
- Function parameters that will be used later.
// Wide-unicode strings
std::wstring fileURL = L"http://httpbin.org/image/jpeg";
std::wstring file1 = L"download-file1.jpeg";
std::wstring file2 = L"download-file2.jpeg"; - Load shared library (aka module) urlmon.dll at runtime using LoadLibraryW API
and perform error checking and exiting the application on
error. The mentioned DLL is loaded into the current process address space.
- Note: If the application is 64 bits, the DLL must be compiled for 64 bits, otherwise it will not work. The same happens if the application is 32 bits.
- Signature: HMODULE LoadLibraryW (LPCWSTR lpLibFileName);
- The file urlmon.dll is at
C:\Windows\System32\urlmon.dll. - If the extension of the DLL is omitted, the function automatically appends .dll to the file name, therefore it is also possible to load the DLL using just “urlmon” instead of “urlmon.dll”.
- If the DLL is provided without absolute path as
C:\Windows\System32\urlmon.dll, the DLL is searched in the following order:- Directory where is the underlying application
- System directory -
%SystemRoot%\system32orC:\Windows\System32\ - Current Working Directory (CWD) - Note: The process current working directory may not be the same as the application.
- Directories listed in the $PATH environment variable.
// Wide unicode version for LoadLibrary API
HMODULE hLib = ::LoadLibraryW(L"urlmon.dll");
if(hLib == nullptr){
std::cerr << " [ERROR] Error: failed to load shared library" << std::endl;
// Early return on Error.
return EXIT_FAILURE;
}
std::cerr << " [INFO] DLL Loaded OK" << std::endl;- Loading function - In order to load the function
URLDownloadToFileW, it is necessary to know: the function symbol
and its its exact type signature and calling convention. In
general, the symbol has the same name of the function to be
loaded. Windows Applications and DLLs of 32 bits supports the
calling conventions
__cdecl(default),__stdcalland__fastcall. Windows applications and DLLs of 64 bits have always the same calling conventions__cdecl. The default calling convention can be omitted in the function signature.
Function pointer type alias (FunptrType) with must type signature of the function URLDownloadToFileW:
// C+11 type alias for function pointer
using FunptrType =
HRESULT (__cdecl *)(LPUNKNOWN, LPCWSTR, LPCWSTR, DWORD, LPBINDSTATUSCALLBACK);
// __cdecl can be omited
// HRESULT (__cdecl *)(LPUNKNOWN, LPCWSTR, LPCWSTR, DWORD, LPBINDSTATUSCALLBACK);
// Alternative 2 for type alias (C++98/03)
typedef HRESULT (__cdecl * FunptrTypeTypedef)(LPUNKNOWN, LPCWSTR, LPCWSTR, DWORD, LPBINDSTATUSCALLBACK);Function is loaded using the WinAPI GetProcAddress
- Signature: FARPROC GetProcAddress(HMODULE hModule, LPCSTR lpProcName);
FARPROC hFunc = ::GetProcAddress(hLib, "URLDownloadToFileW");
if(hFunc == nullptr){
std::cerr << " [Error] Failed to load function from DLL" << std::endl;
return EXIT_FAILURE;
}
std::cerr << " [INFO] Function loaded OK" << std::endl;The value hFunc must be casted to a function type before usage:
- Note: It is alos possible to use C-style casting. However, it is not encouraged as this type of casting is not explicit as reinterpret_cast which communicates the that operation is unsafe and that it can lead to undefined behavior.
// Functin Pointer
FunptrType URLDownloadToFileFunPTR = reinterpret_cast<FunptrType>(hFunc); - Perform experiment 1 - Use function pointer URLDownloadToFileFunPTR ,which points to the function URLDownloadToFileW, to perform a download of the image http://httpbin.org/image/jpeg and save it to file download-file1.jpeg.
HRESULT result1 = URLDownloadToFileFunPTR(nullptr, fileURL.c_str(), file1.c_str(), 0, nullptr);
if(SUCCEEDED(result1))
std::cerr << " [INFO] Download successful OK. " << std::endl;
else
std::cerr << " [ERROR] Download failure. " << std::endl;- Experiment 2 - This piece of code is similar to the previous
one. However, it uses a different syntax for the function pointer.
- Note: The function pointer DownloadFile points to the function URLDownloadToFileW.
std::cout << "============ EXPERIMENT 2 ===================" << std::endl;
// Same cast as reinterpret_cast
void* hFunc2 = (void*) ::GetProcAddress(hLib, "URLDownloadToFileW");
// Omit error checking if(hFunct2 == nullptr){ ... }
// Note: Calling convention __cdecl can be omitted
using URLDownloadToFileW_t =
auto __cdecl (LPUNKNOWN, LPCWSTR, LPCWSTR, DWORD, LPBINDSTATUSCALLBACK) -> HRESULT;
// auto (LPUNKNOWN, LPCWSTR, LPCWSTR, DWORD, LPBINDSTATUSCALLBACK) -> HRESULT;
auto DownloadFile = reinterpret_cast<URLDownloadToFileW_t*>(hFunc2);
HRESULT hresult2 = DownloadFile(nullptr, fileURL.c_str(), file2.c_str(), 0, nullptr);
if(SUCCEEDED(result1))
std::cerr << " [INFO] Download successful OK. " << std::endl;
else
std::cerr << " [ERROR] Download failure. " << std::endl;- Release acquired resource hLib. This operation is unsafe and prone to resource leaking, therefore the code would be safer and more robust if it used RAII (Resource Acquisition Is Initialization) idiom for releasing the resouce.
::FreeLibrary(hLib);
std::cerr << " [INFO] Application ended gracefully. OK." << std::endl;Show symbols (functions) exported by DLL urmon.dll
- Open the MSVC developer shell prompt and use the following commands:
# Print to console
$ dumpbin /exports C:\Windows\System32\urlmon.dll
# Or print to file redirecting the stdout to a file result.txt
$ dumpbin /exports C:\Windows\System32\urlmon.dll > C:\Users\archbox\Desktop\result.txtCommand output:
$ dumpbin /exports C:\Windows\System32\urlmon.dll > C:\Users\archbox\Desktop\result.txt
Microsoft (R) COFF/PE Dumper Version 14.12.25835.0
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file C:\Windows\System32\urlmon.dll
File Type: DLL
Section contains the following exports for urlmon.dll
00000000 characteristics
F6A98BC3 time date stamp
0.00 version
100 ordinal base
481 number of functions
132 number of names
ordinal hint RVA name
121 0 000718E0 AsyncGetClassBits
122 1 000AE7A0 AsyncInstallDistributionUnit
123 2 000A0CD0 BindAsyncMoniker
124 3 000CF110 CAuthenticateHostUI_CreateInstance
125 4 000AF130 CDLGetLongPathNameA
126 5 000AF150 CDLGetLongPathNameW
127 6 00107B70 CORPolicyProvider
128 7 000AE830 CoGetClassObjectFromURL
129 8 000AED90 CoInstall
130 9 00035E90 CoInternetCanonicalizeIUri
131 A 00035FB0 CoInternetCombineIUri
... ... ... ... ... ... ... ... ... ... ... ...
227 71 000E48C0 URLDownloadA
228 72 000EDF10 URLDownloadToCacheFileA
229 73 000EE090 URLDownloadToCacheFileW
230 74 000EE200 URLDownloadToFileA
231 75 0006D300 URLDownloadToFileW
232 76 000E4920 URLDownloadW
233 77 000EE350 URLOpenBlockingStreamA
234 78 000EE430 URLOpenBlockingStreamW
235 79 000EE540 URLOpenPullStreamA
236 7A 000EE610 URLOpenPullStreamW
237 7B 000EE6E0 URLOpenStreamA
... ... ... ... ... ... ... ... ... ... ... ...
Summary
D000 .data
1000 .didat
1000 .isoapis
F000 .pdata
3D000 .rdata
3000 .reloc
52000 .rsrc
117000 .textFurther Reading:
- WinAPIS: LoadLibraryW, GetProcAddress and FreeLibrary.
- https://github.com/numpy/numpy/wiki/windows-dll-notes
- The LoadLibrary Explorer
- Dynamic-Link Library Search Order
- Dynamic-Link Library Data
- Dynamic-Link Library Redirection
- Dynamic-Link Library Security
- 15.17. ctypes — A foreign function library for Python — Python 2.7.15 documentation
This code uses a class DLLoader to load a shared library hiding the complexity and implementation detail. It also uses RAII for ensuring that the resource is released.
Source:
- File: src/windows/dynamic-loading2.cpp
- GIST: dynamic-loading2.cpp
Build and run with MSVC
$ cl.exe dynamic-loading2.cpp /EHsc /Zi /nologo /Fe:out.exe && out.exe
dynamic-loading2.cpp
[INFO] DLL loaded OK.
===== Experiment 1 ===========
[INFO] Function URLDownloadToFileW loaded OK.
[INFO] Download successful OK.
===== Experiment 2 ===========
[INFO] Download successful OK.
[INFO] DLL handler released OK.Build and run with Mingw/GCC
$ g++ dynamic-loading2.cpp -std=c++14 -g -o out-gcc.exe && out-gcc.exe
[INFO] DLL loaded OK.
===== Experiment 1 ===========
[INFO] Function URLDownloadToFileW loaded OK.
[INFO] Download successful OK.
===== Experiment 2 ===========
[INFO] Download successful OK.
[INFO] DLL handler released OK.Parts
Main function - Load Library:
// Wide-unicode strings
std::wstring fileURL = L"http://httpbin.org/image/jpeg";
std::wstring file1 = L"download-file1.jpeg";
std::wstring file2 = L"download-file2.jpeg";
auto dll = DLLLoader("urlmon.dll");
if(!dll){
std::cerr << "[Error] failed to load DLL." << std::endl;
return EXIT_FAILURE;
}
std::cerr << "[INFO] DLL loaded OK." << std::endl;
Main function - Experiment 1:
std::cout << "===== Experiment 1 =========== " << std::endl;
auto URLDownloadToFileW =
dll.GetFunction<HRESULT (LPUNKNOWN,
LPCWSTR,
LPCWSTR,
DWORD,
LPBINDSTATUSCALLBACK)>("URLDownloadToFileW");
if(URLDownloadToFileW == nullptr){
std::cerr << "[Error] failed to load function. " << std::endl;
return EXIT_FAILURE;
}
std::cerr << "[INFO] Function URLDownloadToFileW loaded OK. " << std::endl;
HRESULT result1 = URLDownloadToFileW(nullptr, fileURL.c_str(), file1.c_str(), 0, nullptr);
if(SUCCEEDED(result1))
std::cerr << " [INFO] Download successful OK. " << std::endl;
else
std::cerr << " [ERROR] Download failure. " << std::endl; Main function - Experiment 2:
std::cout << "===== Experiment 2 =========== " << std::endl;
// Note: Calling convention __cdecl can be omitted
using URLDownloadToFileW_t =
HRESULT (*) (LPUNKNOWN, LPCWSTR, LPCWSTR, DWORD, LPBINDSTATUSCALLBACK);
auto URLDownloadToFileW2 =
dll.GetFunction<URLDownloadToFileW_t>("URLDownloadToFileW");
HRESULT result2 =
URLDownloadToFileW(nullptr, fileURL.c_str(), file2.c_str(), 0, nullptr);
if(SUCCEEDED(result2))
std::cerr << " [INFO] Download successful OK. " << std::endl;
else
std::cerr << " [ERROR] Download failure. " << std::endl;
return 0;Class DLLoader:
//========== File: DLLLoader.hpp =======//
class DLLLoader
{
private:
HMODULE m_hLib;
std::string m_file;
public:
DLLLoader(const std::string& file);
DLLLoader(const DLLLoader&) = delete;
DLLLoader(DLLLoader&& rhs);
~DLLLoader();
auto operator=(const DLLLoader&) = delete;
auto operator=(DLLLoader&& rhs);
auto GetFile() const -> std::string;
auto IsLoaded() const -> bool;
operator bool() const;
template<class FunctionSignature>
auto GetFunction(const std::string& functionName ) const -> FunctionSignature*
{
if(m_hLib == nullptr)
return nullptr;
FARPROC hFunc = ::GetProcAddress(m_hLib, functionName.c_str());
if(hFunc == nullptr)
return nullptr;
return reinterpret_cast<FunctionSignature*>(hFunc);
}
};Member functions of class DLLoader:
///==== Implementations - file: DLLoader.hpp =======//
DLLLoader::DLLLoader(const std::string& file):
m_file(file),
m_hLib(::LoadLibraryA(file.c_str()))
{
}
// Move CTOR
DLLLoader::DLLLoader(DLLLoader&& rhs):
m_hLib(std::move(rhs.m_hLib)),
m_file(std::move(rhs.m_file))
{
}
auto DLLLoader::operator=(DLLLoader&& rhs)
{
std::swap(this->m_hLib, rhs.m_hLib);
std::swap(this->m_file, rhs.m_file);
}
DLLLoader::~DLLLoader()
{
std::cerr << " [INFO] DLL handler released OK." << std::endl;
if(m_hLib != nullptr)
::FreeLibrary(m_hLib);
}
auto DLLLoader::GetFile() const -> std::string
{
return m_file;
}
auto DLLLoader::IsLoaded() const -> bool
{
return m_hLib == nullptr;
}
DLLLoader::operator bool() const
{
return m_hLib != nullptr;
}
Migw - gcc/g++ GNU C/C++ Compiler ported for Windows - mingw
Tools:
- gcc => GNU C compiler
- g++ => GNU C++ compiler
- gfortran => GNU Fortran Compiler
$ choco install -f mingw Note the tools are installed at: C:\tools\mingw64\bin\
Check installed tools:
λ dir C:\tools\mingw64\bin
Volume in drive C has no label.
Volume Serial Number is CEFD-3D70
Directory of C:\tools\mingw64\bin
12/28/2015 08:49 PM <DIR> .
12/28/2015 08:49 PM <DIR> ..
12/28/2015 05:51 PM 1,003,008 addr2line.exe
12/28/2015 05:51 PM 1,029,120 ar.exe
12/28/2015 05:51 PM 1,781,248 as.exe
12/28/2015 07:32 PM 1,812,480 c++.exe
12/28/2015 05:51 PM 1,001,472 c++filt.exe
12/28/2015 07:32 PM 1,810,944 cpp.exe
12/28/2015 05:51 PM 1,061,888 dlltool.exe
12/28/2015 05:51 PM 55,296 dllwrap.exe
12/28/2015 05:51 PM 3,037,696 dwp.exe
12/28/2015 05:51 PM 41,984 elfedit.exe
12/28/2015 07:32 PM 1,812,480 g++.exe
12/28/2015 07:32 PM 62,464 gcc-ar.exe
12/28/2015 07:32 PM 61,952 gcc-nm.exe
12/28/2015 07:32 PM 61,952 gcc-ranlib.exe
12/28/2015 07:32 PM 1,809,920 gcc.exe
12/28/2015 07:32 PM 1,391,616 gcov-tool.exe
12/28/2015 07:32 PM 1,409,536 gcov.exe
12/28/2015 08:47 PM 58,333 gdb.exe
12/28/2015 08:47 PM 7,786,103 gdborig.exe
12/28/2015 08:47 PM 412,003 gdbserver.exe
12/28/2015 07:34 PM 57,856 gendef.exe
12/28/2015 07:34 PM 75,264 genidl.exe
12/28/2015 07:34 PM 31,232 genpeimg.exe
12/28/2015 07:32 PM 1,811,968 gfortran.exe
12/28/2015 05:51 PM 1,069,568 gprof.exe
12/28/2015 05:51 PM 1,419,264 ld.bfd.exe
12/28/2015 05:51 PM 1,419,264 ld.exe
12/28/2015 05:51 PM 4,806,144 ld.gold.exe
12/28/2015 07:33 PM 37,888 libatomic-1.dll
12/28/2015 07:33 PM 82,944 libgcc_s_seh-1.dll
12/28/2015 07:33 PM 1,293,312 libgfortran-3.dll
12/28/2015 07:33 PM 112,640 libgomp-1.dll
12/28/2015 07:33 PM 17,920 libgomp-plugin-host_nonshm-1.dll
12/28/2015 07:33 PM 333,824 libquadmath-0.dll
12/28/2015 07:33 PM 19,968 libssp-0.dll
12/28/2015 07:33 PM 1,424,896 libstdc++-6.dll
12/28/2015 07:33 PM 16,384 libvtv-0.dll
12/28/2015 07:33 PM 16,384 libvtv_stubs-0.dll
12/28/2015 07:33 PM 83,456 libwinpthread-1.dll
12/28/2015 08:49 PM 219,648 mingw32-make.exe
12/28/2015 05:51 PM 1,013,760 nm.exe
12/28/2015 05:51 PM 1,171,456 objcopy.exe
12/28/2015 05:51 PM 2,101,760 objdump.exe
12/28/2015 05:51 PM 1,029,120 ranlib.exe
12/28/2015 05:51 PM 490,496 readelf.exe
12/28/2015 05:51 PM 1,004,032 size.exe
12/28/2015 05:51 PM 1,003,520 strings.exe
12/28/2015 05:51 PM 1,171,456 strip.exe
12/28/2015 07:35 PM 437,760 widl.exe
12/28/2015 05:51 PM 1,027,072 windmc.exe
12/28/2015 05:51 PM 1,115,648 windres.exe
12/28/2015 07:32 PM 1,812,480 x86_64-w64-mingw32-c++.exe
12/28/2015 07:32 PM 1,812,480 x86_64-w64-mingw32-g++.exe
12/28/2015 07:32 PM 1,809,920 x86_64-w64-mingw32-gcc-5.3.0.exe
12/28/2015 07:32 PM 62,464 x86_64-w64-mingw32-gcc-ar.exe
12/28/2015 07:32 PM 61,952 x86_64-w64-mingw32-gcc-nm.exe
12/28/2015 07:32 PM 61,952 x86_64-w64-mingw32-gcc-ranlib.exe
12/28/2015 07:32 PM 1,809,920 x86_64-w64-mingw32-gcc.exe
12/28/2015 07:32 PM 1,811,968 x86_64-w64-mingw32-gfortran.exe
59 File(s) 62,660,535 bytes
2 Dir(s) 19,433,713,664 bytes free
See:
Installing Visual Studio building tools directly is hassle as Microsoft doesn’t provide an easy and quick way to install it as Linux development tools which can be quick installed by using the command line and trusted repositories. However chocolately package manager provides a Linux-like solution to install those development tools in an automatic and seamlessly way.
Visual Studio Build Tools 2015 - Visual C++ Build Tools 2015 14.0.25420.1
$ choco install visualcppbuildtoolsVisual C++ 2017 - Visual Studio 2017 Build Tools 15.2.26430.20170650
$ choco install hoco install visualstudio2017buildtools Package: https://chocolatey.org/packages/vscode
$ choco install -y vscodeMore:
- Code Runner - Visual Studio Marketplace - Compile and run single file. However, it is not so fast and flexible as Emacs’ M-x compile.
- Building your C++ application with Visual Studio Code | Visual C++ Team Blog
Package: https://chocolatey.org/packages/codeblocks
$ choco install -y codeblocksInstall QTCreator quasi-IDE. This ‘IDE’ can work with CMake projects and provides code completion on the fly, without any configuration.
$ choco install -y qtcreator SysInterals - https://chocolatey.org/packages/sysinternals
$ choco install sysinternals Process Explorer - https://chocolatey.org/packages/procexp
$ choco install procexp CMDER Is decent ANSI/VT100 compliant terminal emulator which supports ANI Escape sequences, ANSI colors and Emacs Keybindigns used on bash.
$ choco install cmder - Oleview.exe => Tool for viewing system COM Components. It comes with Visual studio tools. It can be launched from development prompt by typing oleview.exe
# Tested for MSVC - 2017 tools:
C:\Users\archbox > where oleview
C:\Program Files (x86)\Windows Kits\10\bin\10.0.17763.0\x64\oleview.exeFor MSVC - 2017, it can be launched directly by running oleview.exe with absolute path:
Windows Key + R + "C:\Program Files (x86)\Windows Kits\10\bin\10.0.17763.0\x64\oleview.exe"
- “A free and powerful tool to explore and decompile all RPC functionalities present on a Microsoft system.”
- http://rpcview.org/
“Monitor is a free software that lets you monitor and control API calls made by applications and services. Its a powerful tool for seeing how applications and services work or for tracking down problems that you have in your own applications.”
JOM is a NMake clone created by the QT company which allows faster and parallel building:
$ choco install jomIDA - Free - Famous Disassembler - https://chocolatey.org/packages/ida-free
$ choco install ida-free Editing Evironemnt Variables
In order to be able to launch tools from command line just by typing their name, such as MSBuild.exe or cmake.exe, the directories where are those tools need to be in the $PATH variable. This variable can be edited by using the control panel or the following command which opens the control panel at editing environment variables tab:
$ rundll32.exe sysdm.cpl,EditEnvironmentVariablesAdding tools to the %PATH% Environment Variables
STEP 1: Open the developer prompt:
**********************************************************************
** Visual Studio 2017 Developer Command Prompt v15.5.6
** Copyright (c) 2017 Microsoft Corporation
**********************************************************************
[vcvarsall.bat] Environment initialized for: 'x64'STEP 2: Get the directory where is the executable, for instance, MSBuild.
C:\Users\archbox\source> where msbuild
C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\MSBuild.exe
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exeThis directory(aka path) is: C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin
STEP 3: Add this directory found at STEP 2 to %PATH% environment variable.
Just open the environment variables tab with the following command and add the path found at STEP 2.
- $ rundll32.exe sysdm.cpl,EditEnvironmentVariables
Now MSBuild can be launched directly from any tool or console without specifying its path.
A faster way to collect thoses paths is to redirect the output of command where to a text file.
cd %USERPROFILE%\Desktop
$ where msbuild >> paths.txt
$ where nmake >> paths.txt
$ where dumpbin >> paths.txtWindows Tools which can be opened at command line
Those tools listed in the following table can be opened with Windows Key + R or just by typing them at terminal.
| Tool | Command | |
|---|---|---|
| System Settings | ||
| Edit Environment Variables | rundll32.exe sysdm.cpl,EditEnvironmentVariables | |
| Windows Registry | regedit | |
| System Configuration Utility | msconfig | |
| Security Center | wscui.cpl | |
| Services | services.msc | |
| Shared Folders | fsmgmt.msc | |
| System Information | msinfo32 | |
| Stored User Names and Passwords | Rundll32.exe keymgr.dll,KRShowKeyMgr | |
| System Properties / Remote Tab | Rundll32.exe shell32.dll,Control_RunDLL Sysdm.cpl,,5 | |
| Component Services - COM, DCOM | comexp.msc | |
| Device Manager | devmgmt.msc | |
| Utilities | ||
| Task manager | taskmgr | |
| Backup and Restore Utility | sdclt | |
| Tool for taking screenshot | snippingtool | |
| Certificate Manager | certmgr.msc | |
| Encrypt File SYstem Wizard | rekeywiz | |
| Remote Desktop | mstsc | |
Note:
- Any executable in %PATH% variable can be called without .exe extension, for instance, $ notepad.exe can be called with $ notepad.
Source Codes:
- Repository: https://github.com/Microsoft/Windows-classic-samples
- Windows Registry - RegExplorer.c
- Windows Service - Service.c
- Repository: https://github.com/strobejb/winspy/ (Winspy++ Tool) for inspecting Windows Messages.
General:
- https://www.pinvoke.net/
- Note: Lists of Windows API functions grouped by system DLLs. It has better discoverability and usability than MSDN docs.
- kernel32.dll
- advapi32.dll
- wininet.dll - High level functions for Http and Ftp protocol.
- Win32 Structured Exception Handler
- Calling WinRT Components from a Win32 process via the Desktop Bridge
Windows header files collected in a GIST:
- Windows.h -
- winreg.h - raw
- Registry API.
- sal.h - raw
- Source annotation language.
- winuser.h - raw
- Graphical User Interface header.
- wtypes.h - raw
- Basic types definitions.
- winbase.h - raw
- Kernel Functions
Reference: Common HRESULT Values - Windows applications | Microsoft Docs
| Name | Description | Value |
|---|---|---|
| S_OK | Operation successful | 0x00000000 |
| E_ABORT | Operation aborted | 0x80004004 |
| E_ACCESSDENIED | General access denied error | 0x80070005 |
| E_FAIL | Unspecified failure | 0x80004005 |
| E_HANDLE | Handle that is not valid | 0x80070006 |
| E_INVALIDARG | One or more arguments are not valid | 0x80070057 |
| E_NOINTERFACE | No such interface supported | 0x80004002 |
| E_NOTIMPL | Not implemented | 0x80004001 |
| E_OUTOFMEMORY | Failed to allocate necessary memory | 0x8007000E |
| E_POINTER | Pointer that is not valid | 0x80004003 |
| E_UNEXPECTED | Unexpected failure | 0x8000FFFF |
WINAPI (several headers)
- Macro used fro main function entry point.
#define WINAPI __stdcallCALLBACK macro used for Window procedure callback.
#define CALLBACK __stdcallBoolean (WinBase.h)
#define FALSE 0
#define TRUE 1Handle types - (opaque pointers) - (WinBase.h)
typedef void* HANDLE;
typedef void* HMODULE;
typedef void* HINSTANCE;
typedef void* HTASK;
typedef void* HKEY;
typedef void* HDESK;
typedef void* HMF;
typedef void* HEMF;
typedef void* HPEN;
typedef void* HRSRC;
typedef void* HSTR;
typedef void* HWINSTA;
typedef void* HKL;
typedef void* HGDIOBJ;
typedef HANDLE HDWP;
typedef HANDLE* LPHANDLE;Graphical Hadles - used by GUI functions. (WinBase.h)
typedef void* HWND;
typedef void* HMENU;
typedef void* HACCEL;
typedef void* HBRUSH;
typedef void* HFONT;
typedef void* HDC;
typedef void* HICON;
typedef void* HRGN;
typedef void* HMONITOR;HRESULT macros and definitions (winerror.h)
#define SUCCEEDED(hr) (((HRESULT)(hr)) >= 0)
#define FAILED(hr) (((HRESULT)(hr)) < 0)
#define HRESULT_CODE(hr) ((hr) & 0xFFFF)
#define HRESULT_FACILITY(hr) (((hr) >> 16) & 0x1fff)
#define HRESULT_SEVERITY(hr) (((hr) >> 31) & 0x1)
// Create an HRESULT value from component pieces
#define MAKE_HRESULT(sev,fac,code) \
((HRESULT) (((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code))) )
#define _HRESULT_TYPEDEF_(_sc) _sc
#define _HRESULT_TYPEDEF_(_sc) ((HRESULT)_sc)
#define E_UNEXPECTED _HRESULT_TYPEDEF_(0x8000FFFFL)
#define E_NOTIMPL _HRESULT_TYPEDEF_(0x80004001L)
#define E_OUTOFMEMORY _HRESULT_TYPEDEF_(0x8007000EL)
#define E_INVALIDARG _HRESULT_TYPEDEF_(0x80070057L)
#define E_NOINTERFACE _HRESULT_TYPEDEF_(0x80004002L)
#define E_POINTER _HRESULT_TYPEDEF_(0x80004003L)
#define E_HANDLE _HRESULT_TYPEDEF_(0x80070006L)
#define E_ABORT _HRESULT_TYPEDEF_(0x80004004L)
#define E_FAIL _HRESULT_TYPEDEF_(0x80004005L)
#define E_ACCESSDENIED _HRESULT_TYPEDEF_(0x80070005L)
#define E_NOTIMPL _HRESULT_TYPEDEF_(0x80000001L)
#define E_OUTOFMEMORY _HRESULT_TYPEDEF_(0x80000002L)
#define E_INVALIDARG _HRESULT_TYPEDEF_(0x80000003L)
#define E_NOINTERFACE _HRESULT_TYPEDEF_(0x80000004L)
#define E_POINTER _HRESULT_TYPEDEF_(0x80000005L)
#define E_HANDLE _HRESULT_TYPEDEF_(0x80000006L)
#define E_ABORT _HRESULT_TYPEDEF_(0x80000007L)
#define E_FAIL _HRESULT_TYPEDEF_(0x80000008L)
#define E_ACCESSDENIED _HRESULT_TYPEDEF_(0x80000009L)
#define E_PENDING _HRESULT_TYPEDEF_(0x8000000AL)
#define E_BOUNDS _HRESULT_TYPEDEF_(0x8000000BL)
#define E_CHANGED_STATE _HRESULT_TYPEDEF_(0x8000000CL)
#define E_ILLEGAL_STATE_CHANGE _HRESULT_TYPEDEF_(0x8000000DL)
#define E_ILLEGAL_METHOD_CALL _HRESULT_TYPEDEF_(0x8000000EL)
Window Messages (Winuser.h)
... ...
#define WM_NULL 0x0000
#define WM_CREATE 0x0001
#define WM_DESTROY 0x0002
#define WM_MOVE 0x0003
#define WM_SIZE 0x0005
#define WM_ACTIVATE 0x0006
#define WM_SETFOCUS 0x0007
#define WM_KILLFOCUS 0x0008
#define WM_ENABLE 0x000A
#define WM_SETREDRAW 0x000B
#define WM_SETTEXT 0x000C
#define WM_GETTEXT 0x000D
#define WM_GETTEXTLENGTH 0x000E
#define WM_PAINT 0x000F
#define WM_CLOSE 0x0010
#define WM_DEVMODECHANGE 0x001B
#define WM_ACTIVATEAPP 0x001C
#define WM_FONTCHANGE 0x001D
#define WM_TIMECHANGE 0x001E
#define WM_CANCELMODE 0x001F
#define WM_SETCURSOR 0x0020
#define WM_MOUSEACTIVATE 0x0021
#define WM_CHILDACTIVATE 0x0022
#define WM_QUEUESYNC 0x0023
#define WM_GETMINMAXINFO 0x002
#define WM_COPYDATA 0x004A
#define WM_CANCELJOURNAL 0x004B
... ... ... APIs:
- GetConsoleCP
- MSDN: “Retrieves the input code page used by the console associated with the calling process. A console uses its input code page to translate keyboard input into the corresponding character value.”
- GetConsoleTitle
- “Retrieves the title for the current console window.”
- AttachConsole
- MSDN: “Attaches the calling process to the console of the specified process.”
- AllocConsole -
- MSDN: “Allocates a new console for the calling process.”
- FreeConsole
- MSDN: “Detaches the calling process from its console.”
Console Information
- Heap Functions - Windows applications | Microsoft Docs
- HeapAlloc
- MSDN: “Allocates a block of memory from a heap. The allocated memory is not movable.”
- HeapCreate
- MSDN: “Creates a private heap object that can be used by the calling process. The function reserves space in the virtual address space of the process and allocates physical storage for a specified initial portion of this block.”
Ref:
CreateFile.
HANDLE CreateFile(
LPCTSTR lpFileName, // pointer to name of the file
DWORD dwDesiredAccess, // access (read-write) mode
DWORD dwShareMode, // share mode
LPSECURITY_ATTRIBUTES lpSecurityAttributes, // pointer to security descriptor
DWORD dwCreationDistribution, // how to create
DWORD dwFlagsAndAttributes, // file attributes
HANDLE hTemplateFile // handle to file with attributes to copy
); ReadFile:
BOOL ReadFile(
HANDLE hFile, // handle of file to read
LPVOID lpBuffer, // address of buffer that receives data
DWORD nNumberOfBytesToRead, // number of bytes to read
LPDWORD lpNumberOfBytesRead, // address of number of bytes read
LPOVERLAPPED lpOverlapped // address of structure for data
);
WriteFile:
BOOL WriteFile(
HANDLE hFile, // handle to file to write to
LPCVOID lpBuffer, // pointer to data to write to file
DWORD nNumberOfBytesToWrite, // number of bytes to write
LPDWORD lpNumberOfBytesWritten, // pointer to number of bytes written
LPOVERLAPPED lpOverlapped // pointer to structure needed for overlapped I/O
);Copy File:
BOOL CopyFile(
LPCTSTR lpExistingFileName, // name of an existing file
LPCTSTR lpNewFileName, // name of new file
BOOL bFailIfExists // operation if file exists
);
Delete File:
BOOL DeleteFile(
LPCTSTR lpFileName // file name
);Move File:
BOOL MoveFile(
LPCTSTR lpExistingFileName, // file name
LPCTSTR lpNewFileName // new file name
);Create Directory:
BOOL CreateDirectory(
LPCTSTR lpPathName, // directory name
LPSECURITY_ATTRIBUTES lpSecurityAttributes // SD
);Remove Directory:
BOOL RemoveDirectory(
LPCTSTR lpPathName // directory name
);- system, _wsystem
- Note: This functions always shows a console window.
// ANSI
int system(const char* command);
// Wide-unicode version
int _wsystem(const wchar_t* command);FILE *_popen(
const char *command,
const char *mode
);
FILE *_wpopen(
const wchar_t *command,
const wchar_t *mode
);- CreateProcessA (ANSI Version)
- MSDN: “Creates a new process and its primary thread. The new process runs in the security context of the calling process.”
BOOL CreateProcessA(
LPCSTR lpApplicationName, // const char*
LPSTR lpCommandLine, // char*
LPSECURITY_ATTRIBUTES lpProcessAttributes, // SECURITY_ATTRIBUTES*
LPSECURITY_ATTRIBUTES lpThreadAttributes, // SECURITY_ATTRIBUTES*
BOOL bInheritHandles, //
DWORD dwCreationFlags, // DWORD - int
LPVOID lpEnvironment, // void*
LPCSTR lpCurrentDirectory, // const char*
LPSTARTUPINFOA lpStartupInfo, // STARTUPINFOA*
LPPROCESS_INFORMATION lpProcessInformation // PROCESS_INFORMATION*
);- CreateProcessW (wide Unicode version)
BOOL CreateProcessW(
LPCWSTR lpApplicationName, // const wchar_t*
LPWSTR lpCommandLine, // wchar_t*
LPSECURITY_ATTRIBUTES lpProcessAttributes, // SECURITY_ATTRIBUTES*
LPSECURITY_ATTRIBUTES lpThreadAttributes, // SECURITY_ATTRIBUTES*
BOOL bInheritHandles, // C++ bool
DWORD dwCreationFlags, // DWORD / int
LPVOID lpEnvironment, // void*
LPCWSTR lpCurrentDirectory, // const wchar_t*
LPSTARTUPINFOW lpStartupInfo, // STARTUPINFOW*
LPPROCESS_INFORMATION lpProcessInformation // PPROCESS_INFORMATION*
);DWORD GetCurrentProcessId();- GetCurrentProcess
- Returns handle to current process.
HANDLE GetCurrentProcess();- CreateProcessA and CreateProcessW
- MSDN: “Creates a new process and its primary thread. The new process runs in the security context of the calling process.”
- TerminateProcess
- MSDN: “Terminates the specified process and all of its threads.”
BOOL TerminateProcess(
HANDLE hProcess,
UINT uExitCode
);- OpenProcess
- MSDN: “Opens an existing local process object.”
HANDLE OpenProcess(
DWORD dwDesiredAccess,
BOOL bInheritHandle,
DWORD dwProcessId
);- ReadProcessMemory
- MSDN: “Reads data from an area of memory in a specified process. The entire area to be read must be accessible or the operation fails.”
BOOL WINAPI ReadProcessMemory(
_In_ HANDLE hProcess,
_In_ LPCVOID lpBaseAddress,
_Out_ LPVOID lpBuffer,
_In_ SIZE_T nSize,
_Out_ SIZE_T *lpNumberOfBytesRead
);- CreateRemoteThread
- MSDN: “Use the CreateRemoteThreadEx function to create a thread that runs in the virtual address space of another process and optionally specify extended attributes.”
HANDLE CreateRemoteThread(
HANDLE hProcess,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
SIZE_T dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId
);Functions:
- LoadLibraryA and LoadLibraryW
- MSDN: “Loads the specified module into the address space of the calling process. The specified module may cause other modules to be loaded.”
// ANSI API
HMODULE LoadLibraryA( LPCSTR lpLibFileName);
// Unicode API
HMODULE LoadLibraryW(LPCWSTR lpLibFileName);- GetProcAddress
- MSDN: “Retrieves the address of an exported function (function pointer) or variable from the specified dynamic-link library (DLL).”
FARPROC GetProcAddress(HMODULE hModule, LPCSTR lpProcName);- FreeLibrary
- MSDN: “Frees the loaded dynamic-link library (DLL) module and, if necessary, decrements its reference count. When the reference count reaches zero, the module is unloaded from the address space of the calling process and the handle is no longer valid.”
BOOL FreeLibrary(HMODULE hLibModule);Books:
- Mark Russinovitch et al - Windows Internals - 5th edition - Microsft Press 2000.
- Windows Operating System Internals Curriculum Development Kit, developed by David A. Solomon and Mark E. Russinovich with Andreas Polze.
- Penny Orwick and Guy Smith. Developing Drivers with Windows Driver Foundation.
- Charles Petzold: Windows Programming - Microsoft Press.
- Visual Basic - Programmer’s Guide to the Win32 API, The Authoritative Solution by Dan Appleman
- Johnson M. Hart, Win32 System Programming: A Windows® 2000 -
Application Developer’s Guide, 2nd Edition, Addison -
Wesley, 2000.
- Note: This book discusses select Windows programming problems and addresses the problem of portable programming by comparing Windows and Unixapproaches.
- Jeffrey Richter, Programming Applications for Microsoft Windows,
4th Edition, Microsoft Press, September 1999.
- Note: This book provides a comprehensive discussion of the Windows API suggested reading.








