Skip to content

Latest commit

 

History

History
4771 lines (3827 loc) · 175 KB

File metadata and controls

4771 lines (3827 loc) · 175 KB

CPP / C++ Notes - Windows API Programming Win32

Windows API Programming Win32

Overview

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:

  • MFC - Microsoft Foundation Classes
  • ATL - Active Template Library

Windows Only - Third party.

  • WTL - Windows Template Library - Created by Microsft and later become opensourced at 2004.
  • 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.

Idiosincrasies

  • 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, \s and 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.

Windows API Main Header Files

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.

Windows API Runtime Libraries

  • 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 …

Windows Object Code Binary Format and Scripting Languages

Native executables, shared libraries and project files.

ExtensionExecutableDescription
Binary Format
Native Code
.exePE32 or PE64Windows Executable
.dllPE32 or PE64Dynamic Linked Library - It can be Native PE32, PE64 or .NET/CLR DLL
.xllPE32 or PE64Excel native Addin (extensio or plugin). It is a dll with .xll extension.
.pydPE32 or PE64Python native module on Windows - DLL with .pyd extension instead of .dll.
.cplPE32 or PE64Control Panel Applet - Also a DLL with .cpl extension.
.sysPE32 or PE64Windows device driver (akin to Linux kernel modules)
.ocxPE32 or PE64Active Control X (DLL)
Special Files
Ntoskrnl.exePE32 or PE64Windows-NT Kernel image
hall.dllPE32 or PE64Hardware 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 ExtensionInterpreterAdvantageDescription
.batcmd.exeSimplicityBatch Script - Legacy technology from MSDOS, but still useful for small automation.
.vbs or vbeWScript.exe or cscript.exeCOM + OOPVBScript - Visual Basic Script
.js or jseJScript.exeCOM + OOP
.wcfWindows Script File - Allows using many script engines iside the same file.
.ps1 .psm1 .ps1xmlPowershellCOM + OOP + .NET + InteractivePowershell Script
.regregedit.exe-Windows registry script. Modify Windows registry when executed.

WinAPI C Data Types

Hungarian Notation

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 
PrefixTypeDescriptionVariable Name Example
bBYTE or BOOLbooleanBOOL bFlag; BOOL bIsOnFocus
ccharCharacter - 1 bytechar cLetter
wWORDword
dwDWORDdouble word
iintintegerint iNumberOfNodes
u32unsigned [int]unsigned integerunsigned u32Nodes
f or fpfloatfloat point - single precisionfInterestRate
ddoublefloat point - double precisiondRateOfReturn
nshort int
szchar* or const char*Pointer to null terminated char array.char* szButtonLabel
HHANDLEHandleHANDLE hModule; HMODULE hInstance;
p-Pointerdouble* pdwMyPointer;
lp-Long Pointerint* lpiPointer;
fn-Function pointer
lpszLong Pointer
LPLong Pointer
I-Interface (C++ interface class)class IDrawable …
S-Struct declarationstruct SContext { … }
C-Class declarationclass CUserData{ … }
m_-Private member variable name of some classm_pszFileName
s_-Static member of a classstatic 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:

General Terminology

  • 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:

Common Data Types

Data TypeDefinitionDescription
BOOLtypedef int BOOLBoolean variable true (non zero) or false (zero or 0)
BYTEtypedef unsigned char BYTEA byte, 8 bits.
CCHARtypedef char CHARAn 8-bit Windows (ANSI) character.
DWORDtypedef unsigned long DWORDA 32-bit unsigned integer. The range is 0 through 4294967295 decimal.
DWORDLONGtypedef unsigned __int64 DWORDLONG64 bits usigned int.
DWORD32typedef unsigned int DWORD32A 32-bit unsigned integer.
DWORD64typedef unsigned __int64 DWORD64A 64-bit unsigned integer.
FLOATtypedef float FLOATA floating-point variable.
INT8typedef signed char INT8An 8-bit signed integer.
INT16typedef signed short INT16A 16-bit signed integer.
INT32typedef signed int INT32A 32-bit signed integer. The range is -2147483648 through 2147483647 decimal.
INT64typedef signed __int64 INT64A 64-bit signed integer.
LPBOOLtypedef BOOL far *LPBOOL;A pointer to a BOOL.
LPBYTEtypedef BYTE far *LPBYTEA pointer to a BYTE.
LPCSTR, PCSTRtypedef __nullterminated CONST CHAR *LPCSTRpointer to a constant null-terminated string of 8-bit Windows (ANSI) characters.
LPCVOIDtypedef CONST void *LPCVOID;A pointer to a constant of any type.
LPCWSTR, PCWSTRtypedef CONST WCHAR *LPCWSTR;A pointer to a constant null-terminated string of 16-bit Unicode characters.
LPDWORDtypedef DWORD *LPDWORDA pointer to a DWORD.
LPSTRtypedef CHAR *LPSTR;A pointer to a null-terminated string of 8-bit Windows (ANSI) characters.
LPTSTRAn LPWSTR if UNICODE is defined, an LPSTR otherwise.
LPWSTRtypedef WCHAR *LPWSTR;A pointer to a null-terminated string of 16-bit Unicode characters.
PCHARtypedef CHAR *PCHAR;A pointer to a CHAR.
CHARANSI Char or char
WCHARWide character 16 bits UTF16
TCHAR-A WCHAR if UNICODE is defined, a CHAR otherwise.
UCHARtypedef unsigned char UCHAR;An unsigned CHAR.
WPARAMtypedef UINT_PTR WPARAM;A message parameter.

Other data types

HANDLE32 bits integer used as a handle
HDCHandle to device context
HWND32-bit unsigned integer used as handle to a window
LONG
LPARAM
LPSTR
LPVOIDGeneric pointer similar to void*
LRESULT
UINTUnsigned integer
WCHAR16-bit Unicode character or Wide-Character
WPARAM
HINSTANCE

References

General:

Windows Programming:

SAL - Source Code Annotation Language

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 AnnotatioDescription
_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:

Character Encoding in WinAPI - ANSI x utf8 x utf16 (wchar_t)

Overview

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.
TypeDefinition
LPSTRchar*
LPCSTRconst char*
LPWSTRwchar_t*
LPCWSTRconst wchar_t*
LPTSTRTCHAR*
LPCTSTRconst 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
);

Unicode UTF8 X Wide Unicode C-strign functions

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.

charwchar_t - Wide character
UTF8UTF16 - Wide UnicodeDescription
strlenwcslenGet string length
strcmpwcscmpComparre string
strcpywcsncpyCopy N-characters from one string to another
strcatwcscatConcatenat string
strtodwcstodConvert 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

Example - ANSI X Unicode and Windows API

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 _UNICODE must 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):

images/messagebox-ansi1.png

Output of MessageBoxW (success):

images/messabox-unicode1.png

Example - Using Windows API with UTF8

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.

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.exe

Compilation 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

images/output-messageboxUTF8.png

Example - Setting Console to UTF8

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.exe

Compiling 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.exe

images/windows-console-ansi-mode.png

images/windows-console-unicode-utf8.png

See:

CODE - Display information about current process

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.exe

Running 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\experiments

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

CODE - List processes

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:

CODE - Show all DLLs or modules load by a process

This example program shows all modules, aka DLLs (Dynamic Linked Libraries) loaded by some process given its PID.

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

CODE - List directory files

Program for listing directories, similar to U*nix’s ls or Windows’ dir usign Win32 API.

Source:

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 sucessfully

Parts

  • 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:

CODE - Enumerate Logical Drivers

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:\, 

CODE - Launching and controlling sub-processes

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:

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++14

Main 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 gracefully

Command 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 gracefully

Class 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 ===== // 

Windows Socket - Winsock

Overview

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.lib
  • Ws2_32.dll

Main System Calls

Creating a socket:

  • af : Address familty
    • PF_INET
    • AF_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_INET and can be set to 0.
  • Return: Socket handler and returns the constant INVALID_SOCKET on failure.
System CallTargetDescription
socket()client or server socketCreate a socket
listen()server socketServer socket listen for incoming connections.
accept()server socketMake a server socket ccept a connection from a client socket.
connect()client socketStablish a connection from a client socket to a server socket.
send()client or server socketSend data to socket
sednto()client or server socketSend data to non connected socket
recev()client or server socketReceives data/bytes from connected socket
recevfrom()client or server socketReceives data from non connected socket
shutdown()client or server socketDisables send and receive on socket
closesocket()client or server socketClose 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_ERROR for connection failure.
int connect(SOCKET s, LPSOCKADDR lpName, int nNameLen);

Byte Ordering FunctionsBeej’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:

CODE - Show IPv4 address of a hostname

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 = 2

CODE - Basic Socket Client

Setup and usage

Source:

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_32

Usage:

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:9090

STEP 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 9090

STEP 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 shell

Parts

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

WinlNet and UrlMon - Windows high level APIs for HTTP and FTP protocol

Overview

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

Example

Source:

Compiling and running:

Compile with MSVC:

$ cl.exe winlNet-basic.cpp /EHsc /Zi /nologo /Fe:winlNet.exe

Compile with Mingw/GCC:

$ g++ winlNet-basic.cpp -o winlNet-basic.exe -lwininet -lurlmon -std=c++14

Running:

$ 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:07

Parts

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

Reference

Graphical User Interfaces - WinAPI

Minimal GUI Program - “hello world”

Overview

This code contains a minimal graphical user interface with Windows API.

Source:

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

Running:

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.

images/gui-program-basic1.png

Parts

Main Function
  • 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.

images/DebugView-systinternals1.png

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.");
Windows Procedure and WinMessageToString

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 __stdcall calling 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_CREATE message; when the user clicks at the close button at top right corner, the operating system sends a message WM_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:
// 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());	
... ... ... 

images/DebugView-window-messages-events.png

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

GUI Without WinMain

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.

int WINAPI WinMain(
        // Handle to current application isntance 
        HINSTANCE hInstance,
        HINSTANCE hPrevInstance,
        // Command line 
        LPSTR     lpCmdLine,
        int       nCmdShow
        ){
   ... .... ... 
     return 0;
 }
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:

images/gui-program-console-subsystem.png

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

Compiling 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,windows

Loading DLLs - shared libraries at runtime

Example 1 - Basic Dynamic Loading

This example demonstrates how to dynamic load functions from a shared library at runtime with WinAPIs Loadlibrary, GetProcAddress and FreeLibrary.

Source:

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:
      1. Directory where is the underlying application
      2. System directory - %SystemRoot%\system32 or C:\Windows\System32\
      3. Current Working Directory (CWD) - Note: The process current working directory may not be the same as the application.
      4. 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), __stdcall and __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.txt

Command 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 .text

Further Reading:

Example 2 - Dynamic loading using a class

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:

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

Install Development Tools and Compilers

C++ Compilers

Install GCC/Mingw + a couple of GNU tools

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:

Install Visual Studio + Microsft MSVC C++ Compiler

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 visualcppbuildtools

Visual C++ 2017 - Visual Studio 2017 Build Tools 15.2.26430.20170650

$ choco install hoco install visualstudio2017buildtools 

IDEs and Text Editors

Install Visual Studio Code

Package: https://chocolatey.org/packages/vscode

$ choco install -y vscode

More:

Install Codeblocks

Package: https://chocolatey.org/packages/codeblocks

$ choco install -y codeblocks
Install QTCreator Standalone

Install QTCreator quasi-IDE. This ‘IDE’ can work with CMake projects and provides code completion on the fly, without any configuration.

$ choco install -y qtcreator 

Essential Windows Instrospection and Debugging Tools

Install SysInternals

SysInterals - https://chocolatey.org/packages/sysinternals

$  choco install sysinternals 

Process Explorer - https://chocolatey.org/packages/procexp

$ choco install procexp 

Install CMDER Terminal Emulator

CMDER Is decent ANSI/VT100 compliant terminal emulator which supports ANI Escape sequences, ANSI colors and Emacs Keybindigns used on bash.

$ choco install cmder 

COM, OLE and RPC Views

Oleview.exe
  • 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.exe

For 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"
RPCView
  • “A free and powerful tool to explore and decompile all RPC functionalities present on a Microsoft system.”
  • http://rpcview.org/
API Monitor - Monitor WinAPI and system calls

“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.”

Other Tools

Install JOM - NMake Clone

JOM is a NMake clone created by the QT company which allows faster and parallel building:

$ choco install jom

Install IDA Free Disassembler

IDA - Free - Famous Disassembler - https://chocolatey.org/packages/ida-free

$ choco install ida-free 

Windows Configurations

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,EditEnvironmentVariables

Adding 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.exe

This 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.txt

Windows 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.

ToolCommand
System Settings
Edit Environment Variablesrundll32.exe sysdm.cpl,EditEnvironmentVariables
Windows Registryregedit
System Configuration Utilitymsconfig
Security Centerwscui.cpl
Servicesservices.msc
Shared Foldersfsmgmt.msc
System Informationmsinfo32
Stored User Names and PasswordsRundll32.exe keymgr.dll,KRShowKeyMgr
System Properties / Remote TabRundll32.exe shell32.dll,Control_RunDLL Sysdm.cpl,,5
Component Services - COM, DCOMcomexp.msc
Device Managerdevmgmt.msc
Utilities
Task managertaskmgr
Backup and Restore Utilitysdclt
Tool for taking screenshotsnippingtool
Certificate Managercertmgr.msc
Encrypt File SYstem Wizardrekeywiz
Remote Desktopmstsc

Note:

  • Any executable in %PATH% variable can be called without .exe extension, for instance, $ notepad.exe can be called with $ notepad.

WINAPI Map

Misc.

Source Codes:

General:

Header Files

Windows header files collected in a GIST:

Common HRESULT values

Reference: Common HRESULT Values - Windows applications | Microsoft Docs

NameDescriptionValue
S_OKOperation successful0x00000000
E_ABORTOperation aborted0x80004004
E_ACCESSDENIEDGeneral access denied error0x80070005
E_FAILUnspecified failure0x80004005
E_HANDLEHandle that is not valid0x80070006
E_INVALIDARGOne or more arguments are not valid0x80070057
E_NOINTERFACENo such interface supported0x80004002
E_NOTIMPLNot implemented0x80004001
E_OUTOFMEMORYFailed to allocate necessary memory0x8007000E
E_POINTERPointer that is not valid0x80004003
E_UNEXPECTEDUnexpected failure0x8000FFFF

Typedefs

WINAPI (several headers)

  • Macro used fro main function entry point.
#define WINAPI __stdcall

CALLBACK macro used for Window procedure callback.

#define CALLBACK __stdcall

Boolean (WinBase.h)

#define FALSE 0
#define TRUE  1

Handle 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
  ... ... ... 

Console

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

Memory Allocation

  • 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.”

File

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

Handle - Kernel “Objects”

Process Creation

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

Process Information

DWORD GetCurrentProcessId();
HANDLE GetCurrentProcess();

Process Manipulation

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

GUI _ Graphical User Interface

GDI - Graphics Device Interface

Functions:

Common Dialogs

Dynamic Linking or Runtime Linking

  • 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

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.