Valid HTML 4.01 Transitional Valid CSS Valid SVG 1.0

Me, myself & IT

Minimalist Runtime Library for Microsoft® C Compiler

Purpose

Create small(er) and fast(er) pure Win32 applications, command line alias console programs and DLLs with Microsoft’s Visual C compilers without the (bloat and overhead of the) MSVCRT runtime libraries, using only functions of the Win32 API, for use on Windows® XP and newer versions of Windows NT as well as Windows PE.

Note: the minimalist Win32 runtime library is no C runtime library, it offers (almost) no POSIX functions like isascii(), printf() or qsort(), no objects like FILE or functions like ferror() which operate on them, and no global variables like errno or stderr, but functions which replace fputchar(), printf(), putch(), puts(), putw() etc., and of course the compiler helper routines and intrinsics called from objects created with Microsoft’s Visual C compiler, plus the startup routines called from Windows’ module loader.

Prerequisites

A platform or Windows SDK for Windows XP and newer versions of Windows NT.

Preparation

Perform the following 8 (optionally 9) steps to build the minimalist Win32 runtime library from the sources and verify the build:
  1. Download the makefile NOMSVCRT.MAK into an arbitrary, preferable empty directory.

    Note: the makefile contains the sources as inline files.

  2. Run the following command line to build the object library NOMSVCRT.LIB for the I386 alias x86 processor architecture:

    NMAKE.EXE /R /F NOMSVCRT.MAK
    Note: a makefile which builds the object library for the AMD64 alias x64 processor architecture is available upon request.
  3. Download the include file NOMSVCRT.H and the ANSI C source file NOMSVCRT.C into the directory used in steps 1. and 2.

  4. Run the following command lines to build the sample GUI alias Windows application NOMSVCRT.EXE, the sample DLL NOMSVCRT.DLL and the sample CUI or CLI alias console program NOMSVCRT.COM:

    CL.EXE /I. /Zl NOMSVCRT.C
    CL.EXE /DUNICODE /I. /Zl NOMSVCRT.C
    CL.EXE /DDLL /I. /LD /Zl NOMSVCRT.C
    CL.EXE /DCONSOLE /FeNOMSVCRT.COM /I. /Zl NOMSVCRT.C
    CL.EXE /DCONSOLE /DUNICODE /FeNOMSVCRT.COM /I. /Zl NOMSVCRT.C
    Each resulting portable executable file is just 4 kB to 7 kB small.

    Note: the downloadable sample portable executable files are a bit larger, they result from the optional step 8.

  5. [Screenshot of NOMSVCRT.EXE] Start the sample application NOMSVCRT.EXE built in step 4., either per double-click or on the command line, optionally with arbitrary arguments: it displays a message box like that shown on the right.

  6. Run one of the following command lines to load the sample DLL NOMSVCRT.DLL built in step 4.:

    MSIEXEC.EXE /Y "%CD%\NOMSVCRT.DLL"
    REGSVR32.EXE "%CD%\NOMSVCRT.DLL"
    RUNDLL32.EXE "%CD%\NOMSVCRT.DLL",foobar
    Windows’ module loader executes its startup routine, which displays two message boxes like those shown below:

    [Screenshot of NOMSVCRT.DLL run via RUNDLL32.EXE] [Screenshot of NOMSVCRT.DLL run via RUNDLL32.EXE]

    Note: the error message boxes displayed from RegSvr32.exe and RunDll32.exe are expected: NOMSVCRT.DLL does neither implement any of the functions DllInstall(), DllRegisterServer() and DllUnregisterServer() called from the Regsvr32 tool, nor the Rundll32 Interface.

  7. Run the following command line to execute the console program NOMSVCRT.COM built in step 4.:

    NOMSVCRT.COM foobar\\baz
    It prints output like the following text:
    argc:		2
    argv[0]:	0x0046FB3C	NOMSVCRT.COM
    argv[1]:	0x0046FB58	foobar\\baz
    
    envp[0]:	0x008B0B18	ALLUSERSPROFILE=C:\ProgramData
    envp[1]:	0x008B0B56	APPDATA=C:\Users\Stefan\AppData\Roaming
    envp[2]:	0x008B0BA6	CommonProgramFiles=C:\Program Files (x86)\Common Files
    envp[3]:	0x008B0C14	CommonProgramFiles(x86)=C:\Program Files (x86)\Common Files
    envp[4]:	0x008B0C8C	CommonProgramW6432=C:\Program Files\Common Files
    envp[5]:	0x008B0CEE	COMPUTERNAME=H270
    envp[6]:	0x008B0D12	ComSpec=C:\Windows\system32\cmd.exe
    envp[7]:	0x008B0D5A	COPYCMD=/V /Z
    envp[8]:	0x008B0D76	DevMgr_Show_Details=*
    envp[9]:	0x008B0DA2	DevMgr_Show_NonPresent_Devices=*
    envp[10]:	0x008B0DE4	DIRCMD=/A /P /X
    envp[11]:	0x008B0E04	FP_NO_HOST_CHECK=NO
    envp[12]:	0x008B0E2C	HOMEDRIVE=C:
    envp[13]:	0x008B0E46	HOMEPATH=\Users\Stefan
    envp[14]:	0x008B0E74	LOCALAPPDATA=C:\Users\Stefan\AppData\Local
    envp[15]:	0x008B0ECA	LOGONSERVER=\\H270
    envp[16]:	0x008B0EF0	NUMBER_OF_PROCESSORS=2
    envp[17]:	0x008B0F1E	OS=Windows_NT
    envp[18]:	0x008B0F3A	Path=C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\Commands;C:\Windows\System32\WindowsPowerShell\v1.0;C:\Program Files\Microsoft SDKs\Windows\v7.0\bin
    envp[19]:	0x008B1094	PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC
    envp[20]:	0x008B1110	PROCESSOR_ARCHITECTURE=x86
    envp[21]:	0x008B1146	PROCESSOR_ARCHITEW6432=AMD64
    envp[22]:	0x008B1180	PROCESSOR_IDENTIFIER=Intel64 Family 6 Model 23 Stepping 10, GenuineIntel
    envp[23]:	0x008B1212	PROCESSOR_LEVEL=6
    envp[24]:	0x008B1236	PROCESSOR_REVISION=170a
    envp[25]:	0x008B1266	ProgramData=C:\ProgramData
    envp[26]:	0x008B129C	ProgramFiles=C:\Program Files (x86)
    envp[27]:	0x008B12E4	ProgramFiles(x86)=C:\Program Files (x86)
    envp[28]:	0x008B1336	ProgramW6432=C:\Program Files
    envp[29]:	0x008B1372	PROMPT=$P$G
    envp[30]:	0x008B138A	PSModulePath=C:\Windows\system32\WindowsPowerShell\v1.0\Modules\
    envp[31]:	0x008B140C	PUBLIC=C:\Users\Public
    envp[32]:	0x008B143A	SystemDrive=C:
    envp[33]:	0x008B1458	SystemRoot=C:\Windows
    envp[34]:	0x008B1484	TEMP=C:\Users\Stefan\AppData\Local\Temp
    envp[35]:	0x008B14CA	TMP=C:\Users\Stefan\AppData\Local\Temp
    envp[36]:	0x008B150E	USERDOMAIN=H270
    envp[37]:	0x008B152E	USERDOMAIN_ROAMINGPROFILE=H270
    envp[38]:	0x008B156C	USERNAME=Stefan
    envp[39]:	0x008B158C	USERPROFILE=C:\Users\Stefan
    envp[40]:	0x008B15C4	windir=C:\Windows
    Note: when started per double-click, i.e. in its own console window, NOMSVCRT.COM waits for a keypress before it exits and its console window closes; it beeps once and flashes its console window to indicate this wait state.
  8. Optionally download the icon file NOMSVCRT.ICO into the directory used in steps 1. to 3., then run the following command line to build the three sample executable files with (almost) all bells and whistles, i.e. including a resource containing the icon, an application manifest and version information, plus a custom DOS stub, and digitally sign them with your own X.509 certificate:

    NMAKE.EXE /R /F NOMSVCRT.MAK samples
  9. Finally move the include file NOMSVCRT.H downloaded in step 3. into one of the include directories used by the Visual C compiler, and the object library NOMSVCRT.LIB built in step 2. into one of the lib directories for the I386 alias x86 appropriate processor architecture.

Dependencies

WINDOWS.H must be included before NOMSVCRT.H.

Note: the functions max() and min() are defined only when the corresponding macros are not defined; to disable their definition in WINDOWS.H define the macro NOMINMAX before including WINDOWS.H.

Limitations

Restriction

The functions PrintBuffer(), PrintChar() and PrintFormat(), which replace POSIX functions like fputchar(), printf(), putch(), puts(), putw() etc., write ASCII in ANSI console programs and UTF-16LE in Unicode console programs to their (redirected) standard output and standard error.

Note: to prevent a mix of ASCII and UTF-16LE when their output is redirected to file, in ANSI console programs the Unicode functions PrintBufferW(), PrintCharW() and PrintFormatW(), and in Unicode console programs the ANSI functions PrintBufferA(), PrintCharA() and PrintFormatA(), write nothing, but return FALSE and yield Win32 error 1288 alias ERROR_INVALID_CRUNTIME_PARAMETER instead.

Usage

// Copyright © 2004-2018, Stefan Kanthak <‍stefan‍.‍kanthak‍@‍nexgo‍.‍de‍>

// Minimalist Win32 Runtime Library for Microsoft C Compiler 20xy

#define NOMINMAX
#define STRICT
#define WIN32_LEAN_AND_MEAN

#define WINVER		0x0500
#define _WIN32_WINNT	0x0500

#include <windows.h>
…
#define IEEE754		// for floating-point routines
#include <nomsvcrt.h>
…
#ifdef DLL
// see <https://msdn.microsoft.com/en-us/library/ms682583.aspx>
// and <https://msdn.microsoft.com/en-us/library/ms682596.aspx>

BOOL	WINAPI	DllMain(HANDLE hModule,
		        DWORD  dwReason,
		        LPVOID lpReserved)
{
	…
	return TRUE;
}
#else // DLL
#ifdef CONSOLE
#ifdef UNICODE
// see <https://msdn.microsoft.com/en-us/library/6wd819wh.aspx>

int	wmain(int argc, wchar_t *argv[], wchar_t *envp[])
{
	return PrintString(STDOUT, L"Hello world!\n");
}
#else // ANSI
// see <https://msdn.microsoft.com/en-us/library/3ze4ytsc.aspx>
// and <https://msdn.microsoft.com/en-us/library/6wd819wh.aspx>

int	main(int argc, char *argv[], char *envp[])
{
	return PrintString(STDOUT, "Hello world!\n");
}
#endif // UNICODE
#else // WINDOWS
#ifdef UNICODE
// see <https://msdn.microsoft.com/en-us/library/ms633559.aspx>
// and <https://msdn.microsoft.com/en-us/library/ff381406.aspx>

INT	WINAPI	wWinMain(HINSTANCE hInstance,
		         HINSTANCE hPrevInstance,
	                 LPWSTR    lpCmdLine,
	                 INT       nCmdShow)
{
	// see <https://msdn.microsoft.com/en-us/library/ms645507.aspx>

	return MessageBoxEx(HWND_DESKTOP, L"Hello world!\n", L"NOMSVCRT", MB_OK, MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL));
}
#else // ANSI
// see <https://msdn.microsoft.com/en-us/library/ms633559.aspx>
// and <https://msdn.microsoft.com/en-us/library/ff381406.aspx>

INT	WINAPI	WinMain(HINSTANCE hInstance,
		        HINSTANCE hPrevInstance,
	                LPSTR     lpCmdLine,
	                INT       nCmdShow)
{
	// see <https://msdn.microsoft.com/en-us/library/ms645507.aspx>

	return MessageBoxEx(HWND_DESKTOP, "Hello world!\n", "NOMSVCRT", MB_OK, MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL));
}
#endif // UNICODE
#endif // CONSOLE
#endif // DLL
CL.EXE /GA /GF /Gy /Oi /Zl … ‹source›.c

Implementation

NOMSVCRT.LIB implements the following helper routines, internal functions and intrinsics supported and used by Microsoft’s Visual C compilers.

Startup Routines

mainCRTStartup(), wmainCRTStartup(), WinMainCRTStartup(), wWinMainCRTStartup() and _DllMainCRTStartup().

Note: their command line processing and argument splitting is feature bug-compatible to the MSVCRT runtime libraries and the Win32 function CommandLineToArgvW(): an unpaired double quote " neither aborts nor yields a Win32 error like 160 alias ERROR_BAD_ARGUMENTS or 1639 alias ERROR_INVALID_COMMAND_LINE!

Note: when executed in a process with an own console window, mainCRTStartup() and wmainCRTStartup(), the console program startup routines, wait for a keypress before they exit and the console window closes; to indicate this wait state they beep once and flash their console window after the main() respectively the wmain() function returns to the startup routine.

Note: the startup routines are implemented for all processor architectures supported by Windows NT.

Stack Allocation and Runtime Checks

_alloca(), _chkstk() and __security_check_cookie().

Note: the /GS runtime check routines are implemented for all processor architectures supported by Windows NT; they raise an exception 0xC0000409 alias STATUS_STACK_BUFFER_OVERRUN when a corruption of the stack cookie is detected.

Text Output

DebugFormat(), PrintBuffer(), PrintChar(), PrintFormat() and PrintString().
The Print*() functions return a non-zero value on success; on failure they return zero and a Win32 error code for retrieval through the Win32 function GetLastError().

Note: these functions are available for ASCII and Unicode.

Buffer Manipulation

memchr(), memcmp(), memcpy(), memmove() and memset(), plus wmemchr(), wmemcmp(), wmemcpy(), wmemmove() and wmemset().

Note: for processor architectures other than I386 alias x86 and AMD64 alias x64, only the memcpy(), memset(), wmemcpy() and wmemset() routines are implemented.

ASCII String Handling

strcat(), strchr(), strcmp(), strcpy(), strlen(), strncat(), strncmp(), strnset(), strrchr(), strrev(), strset(), strstr() and _strset().

Note: the string handling routines are implemented only for the I386 alias x86 and the AMD64 alias x64 processor architectures.

Unicode String Handling

wcscat(), wcschr(), wcscmp(), wcscpy(), wcslen(), wcsncat(), wcsncmp(), wcsnset(), wcsrchr(), wcsrev(), wcsset(), wcsstr() and _wcsset().

Note: the string handling routines are implemented only for the I386 alias x86 and the AMD64 alias x64 processor architectures.

Endian Conversion

htonl(), htons(), ntohl(), ntohs() and swab().

Signed 64-bit Arithmetic

_alldiv(), _alldvrm(), _allmul(), _allrem(), _allshl() and _allshr(), plus _allrotl() and _allrotr().

Note: the multiplication routine is about 2× faster and the division routines are 4× to 6× faster than those supplied in the MSVCRT libraries; multiplication is about 10× slower than native 64-bit multiplication, while division and remainder are (on average) about 1.5× slower than native 64-bit signed division and remainder.

Unsigned 64-bit Arithmetic

_aulldiv(), _aulldvrm(), _aullrem() and _aullshr(), plus _aullmul(), _aullrotl(), _aullrotr() and _aullshl().

Note: the division routines are 4× to 6× faster than those supplied in the MSVCRT libraries; they are (on average) only 1 to 3 processor cycles slower than native 64-bit unsigned division and remainder.

Floating Point Functions

_CIacos(), _CIasin(), _CIatan(), _CIatan2(), _CIcos(), _CIcosh(), _CIexp(), _CIfmod(), _CIlog(), _CIlog10(), _CIpow(), _CIsin(), _CIsinh(), _CIsqrt(), _CItan(), _CItanh(), _ftol(), _ftol2(), _ftol2_sse(), acos(), acosh(), asin(), asinh(), atan(), atan2(), atanh(), cos(), cosh(), exp(), exp2(), fabs(), fmod(), frexp(), ldexp(), logb(), log(), log2(), log10(), pow(), remainder(), scalb(), sin(), sinh(), sqrt(), tan() and tanh(), plus acot(), acot2(), acoth(), cot(), coth() and exp10().

Note: the floating point routines are implemented only for the I386 alias x86 processor architecture; they use the algebraic, arithmetic, transcendental and trigonometric functions of the processor’s builtin IEEE–754 FPU.

POSIX Functions

calloc(), free(), malloc() and realloc().

Miscellaneous Functions

Int32x32To64(), UInt32x32To64(), Int32x32Div32(), Int32x32Rem32(), Int64Div32(), Int64Rem32(), UInt32x32Div32(), UInt32x32Rem32(), UInt64Div32(), UInt64Rem32(), abs(), labs(), llabs(), max(), lmax(), llmax(), min(), lmin(), llmin(), sgn(), lsgn(), llsgn(), lzcnt32(), lzcnt64(), tzcnt32() and tzcnt64().

Note: most of these functions are defined __inline in NOMSVCRT.H.

Download

… the makefile NOMSVCRT.MAK to build the object library NOMSVCRT.LIB for the I386 alias x86 processor architecture, the optional icon file NOMSVCRT.ICO to build the resource file NOMSVCRT.RES, the include file NOMSVCRT.H, and the ANSI C source file NOMSVCRT.C to build the sample Windows application NOMSVCRT.EXE, the sample DLL NOMSVCRT.DLL, and the sample console program NOMSVCRT.COM, …

Authenticity and Integrity

The sample Windows application NOMSVCRT.EXE, the sample DLL NOMSVCRT.DLL, and the sample console program NOMSVCRT.COM are digitally signed using an X.509 certificate issued by WEB.DE TrustCenter E-Mail Certification Authority.
Serial number of the certificate
73780985
0x0465CEF9
Fingerprint of the certificate
MD5: 33 33 6e 1d 26 18 a7 c2 be 87 11 68 05 2c 70 09
SHA-1: 8c 5b 75 21 40 41 77 ac 54 13 13 02 06 6b b0 69 10 2e 83 0e
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEA6ipnm9vAs63w+TM+9UcG1yQ8CRIxMz/tTXry9MCbeHpkiM/qdPaRWlwVTW2j
PhC81xwIPZXgE1FE4DgE1eImb33DG2YfEBY/ARpMaGUnme+85WmExWWc/YMUAaHOMYQ3TQDX
0V/7yuhfa9Uc29ljtQ2AB0MjhXTJvGguvZZTI5A3rcN4+AKwmETdYH+8OQKMU2s+2H9CVfaD
waX0aj9CeibGNooLTgDchzCBIC5J47qHned/3ZqnMDjYCv3Yc1HNgcbM+ZKzPoD8jShb/ptI
wWPo9s00KEs9ti68RsmejqKovAmdLSzFLGARbue2uiqs4piJkxI0LS5+NTTPyZjsSwIDAQAB
-----END RSA PUBLIC KEY-----
Download and install the CA and root X.509 certificates of WEB.DE to validate and verify the digital signature.

Note: due to its counter signature alias timestamp the digital signature remains valid past the X.509 certificates expiration date!

Contact

If you miss anything here, have additions, comments, corrections, criticism or questions, want to give feedback, hints or tipps, report broken links, bugs, errors, inaccuracies, omissions, vulnerabilities or weaknesses, …:
don’t hesitate to contact me and feel free to ask, comment, criticise, flame, notify or report!

Use the X.509 certificate to send S/MIME encrypted mail.

Notes: I dislike HTML (and even weirder formats too) in email, I prefer to receive plain text.
I also expect to see a full (real) name as sender, not a nickname!
Emails in weird formats and without a proper sender name are likely to be discarded.
I abhor top posts and expect inline quotes in replies.

Terms and Conditions

By using this site, you signify your agreement to these terms and conditions. If you do not agree to these terms and conditions, do not use this site!
Copyright © 1995–2018 • Stefan Kanthak • <‍stefan‍.‍kanthak‍@‍nexgo‍.‍de‍>