1. 18

To solve a personal annoyance.

  1. 13

    14Kb for a 32 bit Windows executable that uses no C library functions and doesn’t need to parse any arguments? This is a real peeve of mine - 90% of the code in that program isn’t doing anything useful.

    I added this to the end:

    VOID __cdecl mainCRTStartup() { ExitProcess(main()); }

    And compiled without the CRT (using Visual Studio 2008 compiler):

    cl /Os sss.c /nodefaultlib kernel32.lib user32.lib

    The resulting binary is 2048 bytes. Most of that is overhead too - it contains 134 bytes of code, and 210 bytes of read only data, which is mainly to specify DLL imports. That makes 344 bytes of 2048 that’s related to the program. This happens because there’s 1Kb of executable headers, and the two sections are aligned at 512 bytes, so the result is 2048.

    1. 2

      Normally I develop for embedded Linux so 14 kb is a lot there. But for windows, it hadn’t occurred to me that this is large. Which is to say, I never do windows development so the latter part of your comment doesn’t tell my anything. I understand that the size can be smaller, but why then is it so large by default from gcc?

      1. 13

        It’s large because main() isn’t the entrypoint. The entrypoint is a hidden function, mainCRTStartup, which calls main(). That function does things like parse the command line string from GetCommandLine() into argc/argv. But it also ends up implementing a global exception handler, piles of initialization for CRT provided global variables, TLS initialization, NLS support, initializing synchronization for multithreaded access to CRT state you’re not using, etc. Those features in turn end up needing DLL imports of their own, so your program has more functions to link against. And, those features will end up needing memory.

        I don’t think this is really any different on Linux. CRT overhead exists, although it obviously varies depending on configuration. Since I’m using VS2008 for these tests, I can use its CRT as a DLL and I get a 5.5Kb binary, and statically linking I get a 36.5Kb binary. The latter is interesting just because it contains all the goop that the CRT is doing, making its true cost very visible. For example, this binary has 6140 bytes of writable global variables (of which your program has none), 6862 bytes of constant data, and it imports both VirtualAlloc and HeapAlloc so it’s going to allocate more memory on top of that. Heck, it imports 57 functions from kernel32.dll, and those function names are going to be part of the 6862 bytes of constant data. Part of those are LoadLibrary/GetProcAddress, so it can load more than just what the import table specifies; grovelling through the binary shows it can load .NET (mscoree.dll) on demand.

        After writing that first comment, I was thinking a bit more about memory. One other non-obvious thing is that a console program on Windows is really a superset of a GUI program, because it needs to keep a corresponding conhost process, which this program makes invisible, but it’s still there. A GUI program doesn’t need that, which also eliminates two functions from the import table and some code to invoke them. After making that change (/subsystem:windows), it’s now 100 bytes of code and 138 bytes of data, with exactly one import from kernel32 (Sleep) and one from user32 (SendInput.) This program ends up with a private working set of 344 Kb on my system (although that value is essentially all kernel32/user32 so it’s heavily OS version dependent.)

        Also, with all of the random CRT functions removed, it becomes possible to determine how much stack space it needs and shrink the stack. On my system, I can run this program with a 4Kb stack, which is insane, but the result is a commit of 528Kb.

        1. 1

          Thank you for the comprehensive explanation. I’m not sure if I can replicate it just yet, but I’m going to experiment a bit more on Windows.

      2. 1

        Aside from this, defining WIN32_LEAN_AND_MEAN, WIN32_EXTRA_LEAN, VC_LEANMEAN and VC_EXTRALEAN might help, and if you want to go completely overkill, you can always use an executable packer

      3. 2

        Thank you so much for this, especially the binaries! Due to the acquisition of my employer, my newly-assigned Win10 system forces the screensaver at five minutes at idle. Your simple, but elegant, solution should work just fine for me (I hope) and I appreciate the efforts. :)

        1. 2

          Bit off-topic, but: I understand that you suffer with such miserable OS, but the policies and measures like this one make some sense and you might be made responsible if you circumvent the policy and something happened. If I would be e.g. reading a documentation for a several minutes without moving mouse or pressing a button, I might use such utility, but I would not leave it turned on permanently. If someone misuses your computer, it would be your fault.

          1. 2

            Of course. But when I switch between several systems for different tasks in my locked office, it makes sense to use a tool like this, else I have to remember to flick the mouse myself every four minutes and fifty-nine seconds. It takes several minutes to login to these systems, too. :/

            1. 2

              Several minutes!?

        2. 2

          You can change this line:

          add_executable(ScreenSaverStopper main.cpp)


          add_executable(ScreenSaverStopper WIN32 main.cpp)

          so that the compiler will change the subsystem to ‘GUI’ instead of ‘console’. This way you can skip the ShowWindow() call, because the console window will not be created by default.

          You can also do it in a non-portable way. For MinGW:

          set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++ -Wl,--subsystem,windows")
          1. 1

            Thanks. So many bloated apps around, nice to see someone stick to the Unix philosophy

            1. 4

              In unix-like systems with X Window we do not have to simulate keyboard or mouse events – we have an API or command line tools for preventing screensaver.

              XScreenSaverSuspend: temporarily suspends the screensaver and DPMS timer if suspend is ‘True’, and restarts the timer if suspend is ‘False’.

              xdg-screensaver: Suspends the screensaver and monitor power management. WindowID must be the X Window ID of an existing window of the calling application. The window must remain in existence for the duration of the suspension.

              1. 3

                Windows has such APIs as well (e.g. SetThreadExecutionState with the ES_DISPLAY_REQUIRED flag), but also ways to override these APIs (such as security policies) if the device owner (!= device user) really wants the password prompt to hide whatever is shown after x minutes of inactivity.

                1. 1

                  X Windows really doesn’t have a concept of a secure screensaver, like Windows has.


                  Maybe this has changed in Wayland.

                2. 2

                  P.S. When talking about „Unix philosophy“:

                  There is more Unix-nature in one line of shell script than there is in ten thousand lines of C.

                  Maybe this one-liner:

                  while true; do echo "mouse_move +1 0"; echo "mouse_move -1 0"; sleep 60; done | qemu-system-i386 -hda guest-vm-image.qcow2 -monitor stdio

                  I have not tested it much, but it seems working. And it runs on the host side – thus it does not require any changes in the guest VM or running any commands there. The OS inside the VM is unable to detect, whether it is simulated key/mouse event or whether the user is moving the mouse, because the events come through exactly the same channel (from the outside of the VM).

                3. 1

                  This seems to be for Windows only? Can you really not disable the screensaver on Windows anymore, such that you need something like this?

                  1. 5

                    In some business environments, screensavers are forced through a device management policy to save energy, and are configured in a way that doesn’t allow unprivileged users to modify the setting. This utility circumvents that restriction.

                    1. 1

                      I see, thanks for explaining why this is a problem for some folks!

                    2. 2

                      As the comment of @dstaley says, at work I can run Visual Studio and it’s compiled executables, but not adjust the screensaver settings. They are managed via GPO by the central IT Dept. But my windows is a VM, so after logging in to my Linux system I have to login again on the VM.

                      1. 2

                        Then it makes sense.

                        (I expect that you lock your GNU/Linux screen properly and systematically)

                        BTW: if you use qemu, you can simulate the keypresses or mouse moves using qemu monitor – thus it could be a single-line shell script running in your GNU/Linux without need of compiling and running inside the guest VM.

                        1. 1

                          Yes, a special key on my keyboard is mapped to CTRL+L to lock kde, a timeout as well and a Bluetooth proximity script.

                    3. 1

                      TIL there’s an F24 key code.

                      1. 1

                        What, your keyboard doesn’t look like this?!

                      2. 1

                        I did this exact thing (F24 key and all) with a Visual Basic script I wrote at my previous job for the same reason.

                        Apologies for not being helpful and posting it here, I didn’t keep any files from that time. But mentioning it here because it’s an effective way to suppress the screen saver even if you can’t run downloaded executable files.

                        1. 1

                          I’ve been using an existing piece of software that does the exact same thing for years: https://www.zhornsoftware.co.uk/caffeine/

                          1. 1

                            There are many tools that do this indeed. Before, I always used Noise: https://www.dcmembers.com/skrommel/download/noise/