For the printf part - it's part of the C Standard Library, which is a part of C. So the implementation of your C compiler or C Standard library can use all sort of tricks to make it work.
Let's take a simple example on how such a function can be implemented in Unix. Take putchar
(simplified here - without returning anything). It outputs one character to standard output, which has the file descriptor number 1. The operation system provides a function called "write". A program can write into a file descriptor. So, putchar can use that function:
void putchar(int c) {
unsigned char cc = c;
write(1, &cc, 1);
}
Will write 1 byte to the file descriptor 1. The write function will tell the operation system about that wish:
void write(int fd, void * ptr, size_t size) {
asm("....."
"int 0x80");
}
It will usually just contain a small block of assembly lines that raises a software interrupt (in the sample above, it's the interrupt number 0x80). The CPU will switch into kernel mode and jump to some fixed address, from which the operation system can handle that interrupt. write
will have written the system call number for write into some register and will have put the arguments into some memory location or into registers too, so that the operation system knows what to do at that point. The operation system will then send the bytes that should be written to the designated file/device (in case of stdout, it could be the terminal driver that is connected to the file descriptor), and will return from interrupt, making the CPU switch to user mode again.
That's the rough plan. There is more to it (putchar could buffer the output before doing the system call...) of course. But in principle, it works this way.
The MessageBox function too will call some system call in the end, that transfers control into the windows kernel in some or another way similar to the above explanation.