For this, you gain nothing by writing 64-bit code -- you might as well stick to 32-bit code.
If you want output to a MessageBox, it could look like this:
.386
.MODEL flat, stdcall
MessageBoxA PROTO near32 stdcall, window:dword, text:near32,
        windowtitle:near32, style:dword
.stack 8192
.data
message db "Hello World!", 0
windowtitle   db "Win32 Hello World.", 0
.code
main proc
        invoke MessageBoxA, 0, near32 ptr message, near32 ptr windowtitle, 0
        ret
main endp
        end main
If you want output to the console, it's (strangely enough) a bit more complex:
.386
.MODEL flat, stdcall
getstdout = -11
WriteFile PROTO NEAR32 stdcall,     \
        handle:dword,                   \
    buffer:ptr byte,        \
        bytes:dword,                    \
        written: ptr dword,             \
        overlapped: ptr byte
GetStdHandle PROTO NEAR32, device:dword
ExitProcess PROTO NEAR32, exitcode:dword
.stack 8192
.data
message db "Hello World!"
msg_size equ $ - offset message
.data?
written  dd ?
.code
main proc   
    invoke GetStdHandle, getstdout
    invoke WriteFile,                   \
           eax,                         \
           offset message,              \
           msg_size,                    \
           offset written,              \
           0
    invoke ExitProcess, 0
main endp
        end main
In theory, moving to 64 bit code doesn't make a lot of difference -- for example, you can use the same functions in both. In reality, it's a bit painful, because the calling convention for 64-bit code is somewhat complex, and you can't use MASM's invoke for 64-bit code. Working code wouldn't be a whole lot more complex, but getting the code working probably would be a bit more work. The general idea is that for 64-bit code, you allocate space on the stack for all your parameters, but the first N parameters that are small enough to fit, go in registers.