Friday, May 8, 2026

Embed .NET runtime into C# exe

When writing a C# program, if you want to bundle the .NET runtime with the application so that it can run on a Windows PC without a separate .NET installation:
  1. Create the project as "Windows Forms App", not "Windows Forms App (.NET Framework)"
  2. Use Release x64 configuration instead of only Any CPU
  3. In Visual Studio 2022, open the terminal and run:dotnet publish -c Release -r win-x64 -p:Platform=x64 --self-contained true -p:PublishSingleFile=true
  4. The published executable is located in:
  5. bin\x64\Release\net8.0-windows\win-x64\publish\
  6. The generated EXE includes the .NET runtime and can run on systems without .NET installed.
Depending on the NuGet packages used (e.g. S7NetPlus), additional DLLs may still appear in the publish folder and should also be distributed with the EXE.

Thursday, May 7, 2026

std::system Windows vs Linux

On Windows the C++ function std::system() is essentially a wrapper around the command processor (cmd.exe). When the process finishes, the exit code is passed directly back to you. If your program exits with 1, the integer returned by std::system is 1. On Linux, it might return 256.

On Linux, a single integer return value isn't just an exit code; it's a status word containing a wealth of information about how the process died. The OS packs different data into specific bit ranges. In most Linux implementations, the exit code is shifted into the high byte. This means a return code of 1 is stored as 1 << 8, which equals 256. To get back the exit code, you have to right shift the status code by 8 bits. The portable way is to use WEXITSTATUS macro.

To write code that works on both platforms, you cannot treat the return value as a raw number. You must use the decoding macros provided in <sys/wait.h> on Linux. You should always check if the process actually finished before asking for the code. Here is the safest pattern for Linux:

#include <sys/wait.h>
int status = std::system("./my_script.sh");
if (WIFEXITED(status)) {
  int exitCode = WEXITSTATUS(status); //
  std::cout << "Success! Code: " << exitCode;
} else if (WIFSIGNALED(status)) {
  int sig = WTERMSIG(status);
  std::cout << "Killed by signal: " << sig;
}