
Small, Freestanding Windows Executables - DmitryNovikov
http://nullprogram.com/blog/2016/01/31/
======
TimJYoung
Great article.

I know that the topic here is C, but I think it's interesting to point out
that Delphi (Object Pascal) has _always_ produced executables that work like
this (since 1996). With one of our database server products written using
Delphi, executables are about 3MB in size and have zero external dependencies.
You can literally copy the executable on to any Windows machine, run it (or
install it as a service to be run), and it will work.

It's kind of a whole different mindset compared to other approaches that
involve many more non-OS runtime dependencies. It certainly makes
installation/configuration support a non-issue.

~~~
padobson
.Net 3.5 has shipped with every Windows since Vista, so you can basically do
the same thing with C# or VB if you target those OSes.

With reflection[1], you can even include third party libraries directly in the
executable and access them at runtime, no installation required.

[1][https://msdn.microsoft.com/en-
us/library/ms173183.aspx](https://msdn.microsoft.com/en-
us/library/ms173183.aspx)

~~~
Someone1234
But the topic is specifically freestanding executables, not compatibility in
general. If it utilises an external DLL, or library then it isn't
freestanding, as a .Net 3.5 program typically isn't (although I think
Microsoft has a .Net native compiler now, but I don't know if that can be
configured to push external dependencies into the executable package).

Don't misunderstand, I like .Net, I just think you've misunderstood what is
being discussed.

~~~
padobson
From the Windows 7 user's perpsective, there's no difference.

It's understood that this article is meant to discuss zero-install
applications that require nothing more than the standard C library.

That said, if you're making and marketing software (as I would expect a few
visitors of this thread might) and looking to accomplish something
functionally similar with your C# or VBScript dev team, my comment can be
helpful - which is why I wrote it.

I've shipped a number of sub-5MB applications this way.

~~~
Someone1234
> It's understood that this article is meant to discuss zero-install
> applications that require nothing more than the standard C library.

No, they are zero install, including NOT requiring a C library. No libraries
at all. They're communicating directly with kernel32 from userland.

On Windows that's as "bare metal" as a non-driver can really get.

------
mschaef
I think the thing I like the best about this article is that it forces you to
take a C development environment and break it down into more pieces than is
usual.

One of my formative software development experiences was developing firmware
for small embedded hardware back in the late-90's. We had a 4MHz 80188EB, 128K
RAM, 512K ROM, and a handful of pretty raw I/O hardware. Despite the 'unusual'
nature of the software we were building, our main compiler was the real-mode C
compiler from Borland C++ 4.5.

Our RTOS/standard library was a collection of four C files maintained by our
senior team that we compiled along with everything else. The most unusual part
of the build process was that we took the linker output and ran it through a
locater that used it to generate an image file for a firmware burn.

It was really quite gratifying to see how much of the usual baggage associated
with HLL development was unnecessary. It made software seem a lot less magical
and a lot easier to understand, both of which have been helpful over the
years.

------
baq
it's nice to see people are still trying to do this. i remember the shock when
i was a whippersnapper and seen WinAPI programming in assembly for the first
time (e.g.
[http://stackoverflow.com/a/1029093/38749](http://stackoverflow.com/a/1029093/38749)).

------
jibsen
I've played around with replacing the C library with something more
lightweight for small programs (WCRT), but one issue is that you end up with
executables that get flagged by some AV software for being "unusual".

I think unless you have a specific need for a small executable, it is usually
not worth it.

------
yyin
Is the author aware of the posix dll in the SUA subsystem?

Control Panel, Add or Remove System Features, select SUA. Windows 7 Enterprise
has it and maybe other versions.

Linking against this library works for me. It may or may not work for others,
but there's only one way to find out: try it.

MS is trying to make it go away (for the second time) so expect that people to
tell you it does not work and not to use it. Whatever.

Alternatively I agree with the commenter who suggested Delphi. It just works,
same as it did in the 90's. I still use an older version from that era. Works
beautifully.

------
jarjoura
This OP is struggling to use MinGW, why not install VS2015 or just install
Microsoft's version of clang? True, that will depend on the latest version of
msvcrt.dll, but at least your source code will remain cross-platform.

As far as I know, clang should compile anything gcc would compile.

~~~
mrec
IIRC, it's not trivial to link to msvcrt.dll in VS. In older versions I think
you needed to download the Windows Driver Kit to get an import lib, and since
Win8 I don't think even that supplies it any more.

Ref: [https://kobyk.wordpress.com/2007/07/20/dynamically-
linking-w...](https://kobyk.wordpress.com/2007/07/20/dynamically-linking-with-
msvcrtdll-using-visual-c-2005/)

------
amadvance
I don't get the issue with msvcrt.dll. It's available in all Windows
installations, so for my concern, MinGW produces freestanding applications,
because nothing additional needs to be installed.

~~~
drv
In practice, this is probably correct (Microsoft cares a lot about backward
compatibility, and many programs depend on MSVCRT.DLL).

However, the official word from Microsoft is that MSVCRT.DLL is only intended
for operating system components to use, not user applications. For example,
see Raymond Chen's blog on the subject. [1]

[1]
[https://blogs.msdn.microsoft.com/oldnewthing/20140411-00/?p=...](https://blogs.msdn.microsoft.com/oldnewthing/20140411-00/?p=1273)

~~~
cesarb
The problem is that their official word changed.

As that link itself says, MSVCRT.DLL was the C library for several versions of
their official C compiler. That is, it had always been intended for both
operating system components and user applications. A quick Wikipedia search
tells me that this was true until 2002, which is when MSVC 7 was released.

Wikipedia also tells me that MinGW (which is probably the main source of
programs linking to MSVCRT.DLL nowadays) was first released in 1998, so their
use of MSVCRT.DLL as the global C library was correct. It's not MinGW's fault
that Microsoft changed their mind.

------
to3m
I wrote a program using similar principles: [https://github.com/tom-
seddon/kbswitch](https://github.com/tom-seddon/kbswitch) (two versions, one
for 32-bit Windows XP, one for Windows XP or later with any bitness)

The EXEs are indeed pretty small:

    
    
        ~/github/kbswitch % ls -l `find . -name '*.exe' -or -name '*.dll'`
        -rw-r--r--  1 tom  staff   5120  1 Feb 13:50 ./kbswitch/kbswitch.exe
        -rw-r--r--  1 tom  staff  11264  1 Feb 13:50 ./kbswitch2/bin/kbswitch2.exe
        -rw-r--r--  1 tom  staff   5120  1 Feb 13:50 ./kbswitch2/bin/kbswitch2_dll_x64.dll
        -rw-r--r--  1 tom  staff   5120  1 Feb 13:50 ./kbswitch2/bin/kbswitch2_dll_x86.dll
        -rw-r--r--  1 tom  staff   6144  1 Feb 13:50 ./kbswitch2/bin/kbswitch2_helper_x64.exe
        -rw-r--r--  1 tom  staff   5120  1 Feb 13:50 ./kbswitch2/bin/kbswitch2_helper_x86.exe
    

VC++ makes freestanding programs no easier than gcc. (A good reminder that a C
implementation consists of all the libraries that come with it, and not just a
compiler that generates code.) Issues I recall having when putting this
together (which was a few years ago now so I may have forgotten something):

\- As with gcc, you need to fiddle with the linker settings to stop it
including the stack check stuff

\- Floating point is a bit hit or miss and using it can cause VC++ to generate
calls to its helper library (I vaguely recall also getting similar stuff when
using 64-bit ints)

\- VC++ will generate calls to memset when default-initializing structs

\- VC++ will spot many types of implementation of memset, remove them, and
replace calls to them with calls to memset (particularly tiresome when trying
to fix the last problem)

\- the Windows headers include a number of handy-looking functions that seem
just the ticket for working without the CRT, but a lot of them, once I
followed through all the #ifdefs, ended up just being #defines for the
corresponding CRT function

So I haven't bothered doing this for any programs since. I've heard of some
people working typically without the CRT, and they seem pretty happy, but I
didn't think it was worth the effort just to provide a tiny EXE with no non-
system dependencies.

Regarding the size, I don't think it's a huge benefit these days - for small
programs, where this stuff makes the EXE noticeable smaller, you're just not
saving much. An EXE written like this might be 10K; the same EXE dynamically
linked with the CRT, ~20K; the same EXE statically linked with the CRT, ~90K.
That difference just isn't very important any more.

And regarding the lack of external dependencies, if you need that, you can
statically link with everything (please do your own research regarding
licensing and security ramifications). I think that provides you with
basically all of the useful benefits of the above approach, for a fraction the
effort.

