November 28, 2023

In this non-perfect example we interface with Windows Operating System to provide a functionality to print characters to standard output stream.

If you see some major issues, memory leaks or have better ideas, do not hesitate: improve this code and repost here.

Core highlight:

  • This example uses WriteFile() Win32 API function with GetStdHandle(STD_OUTPUT_HANDLE).

How to use:

  • This is a complete program, you can copy and paste into .d source file
  • Run using rdmd yoursourcefile.d
version (Windows) @system @nogc:

// Example: Barebones print() function using Win32 Windows API
// Prints to standard output

import core.stdc.stdio : printf;

import core.sys.windows.winbase : GetStdHandle, STD_OUTPUT_HANDLE;
	
// Dlang headers are lacking function argument names to take advantage of : notation.
// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-writefile#syntax
// https://github.com/dlang/dmd/blob/a423208c7a5607a5af5e6b307f85179b7a8e9c20/druntime/src/core/sys/windows/winbase.d#L2073

extern(Windows) {
	import core.sys.windows.basetsd : HANDLE;
	import core.sys.windows.windef  : BOOL, PCVOID, DWORD, PDWORD;
	import core.sys.windows.winbase : LPOVERLAPPED;

	BOOL WriteFile(HANDLE hFile, PCVOID lpBuffer, DWORD nNumberOfBytesToWrite, PDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped);
}

// print() becomes recursive if used inside print() itself
// prevent recursion inside print by passing insideItself argument

void print(string message = "\n", bool debugmode = false, bool insideItself = false) @trusted @nogc{
	
	uint bytesWritten;
	WriteFile(
		hFile: GetStdHandle(STD_OUTPUT_HANDLE),
		lpBuffer: message.ptr,
		nNumberOfBytesToWrite: message.length,
		lpNumberOfBytesWritten: &bytesWritten,
		lpOverlapped: null
	);
	if (insideItself) return;
	if (debugmode) {
		print("\nNumberOfBytesToWrite: ", insideItself: true);
		print(convertUintToString(message.length), insideItself: true);
		
		print("\nNumberOfBytesWritten: ", insideItself: true);
		print(convertUintToString(bytesWritten), insideItself: true);
	}
	
}

string convertUintToString(uint n) @nogc {
    import std.conv;
    import std.experimental.allocator;
    import std.experimental.allocator.mallocator;
    alias a = Mallocator.instance;
    auto s = a.makeArray(n.toChars);
	return cast(string)s;

}

void main(){
	print("HelloWorld", debugmode: true);
	
	print("\nExample: ");
	print("\nPrinting integer: ");
	print(convertUintToString(5));
	
}

Expected output:

HelloWorld
NumberOfBytesToWrite: 10
NumberOfBytesWritten: 10
Example:
Printing integer: 5