package main
import (
"fmt"
"runtime"
"syscall"
"unsafe"
)
var (
user32 = syscall.NewLazyDLL("user32.dll")
kernel32 = syscall.NewLazyDLL("kernel32.dll")
procRegisterClassExW = user32.NewProc("RegisterClassExW")
procCreateWindowExW = user32.NewProc("CreateWindowExW")
procDefWindowProcW = user32.NewProc("DefWindowProcW")
procShowWindow = user32.NewProc("ShowWindow")
procUpdateWindow = user32.NewProc("UpdateWindow")
procGetMessageW = user32.NewProc("GetMessageW")
procTranslateMessage = user32.NewProc("TranslateMessage")
procDispatchMessageW = user32.NewProc("DispatchMessageW")
procPostQuitMessage = user32.NewProc("PostQuitMessage")
procLoadCursorW = user32.NewProc("LoadCursorW")
procGetModuleHandleW = kernel32.NewProc("GetModuleHandleW")
)
const (
CS_HREDRAW = 0x0002
CS_VREDRAW = 0x0001
CW_USEDEFAULT = 0x80000000
WS_OVERLAPPEDWINDOW = 0x00CF0000
SW_SHOWDEFAULT = 10
WM_DESTROY = 0x0002
IDC_ARROW = 32512
COLOR_WINDOW = 5
)
type wndClassEx struct {
cbSize uint32
style uint32
lpfnWndProc uintptr
cbClsExtra int32
cbWndExtra int32
hInstance syscall.Handle
hIcon syscall.Handle
hCursor syscall.Handle
hbrBackground syscall.Handle
lpszMenuName *uint16
lpszClassName *uint16
hIconSm syscall.Handle
}
type point struct {
x int32
y int32
}
type msg struct {
hwnd syscall.Handle
message uint32
wParam uintptr
lParam uintptr
time uint32
pt point
}
func wndProc(hwnd syscall.Handle, msg uint32, wParam, lParam uintptr) uintptr {
switch msg {
case WM_DESTROY:
postQuitMessage(0)
return 0
}
ret, _, _ := procDefWindowProcW.Call(uintptr(hwnd), uintptr(msg), wParam, lParam)
return ret
}
func registerWindowClass(className *uint16, instance syscall.Handle, wndProcPtr uintptr) error {
wc := wndClassEx{
cbSize: uint32(unsafe.Sizeof(wndClassEx{})),
style: CS_HREDRAW | CS_VREDRAW,
lpfnWndProc: wndProcPtr,
hInstance: instance,
hCursor: loadCursor(0, IDC_ARROW),
hbrBackground: syscall.Handle(COLOR_WINDOW + 1),
lpszClassName: className,
}
atom, _, err := procRegisterClassExW.Call(uintptr(unsafe.Pointer(&wc)))
if atom == 0 {
return err
}
return nil
}
func createWindow(className, windowTitle *uint16, instance syscall.Handle) (syscall.Handle, error) {
hwnd, _, err := procCreateWindowExW.Call(
0,
uintptr(unsafe.Pointer(className)),
uintptr(unsafe.Pointer(windowTitle)),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
800,
600,
0,
0,
uintptr(instance),
0,
)
if hwnd == 0 {
return 0, err
}
return syscall.Handle(hwnd), nil
}
func showWindow(hwnd syscall.Handle, cmdShow int32) {
procShowWindow.Call(uintptr(hwnd), uintptr(cmdShow))
procUpdateWindow.Call(uintptr(hwnd))
}
func loadCursor(instance syscall.Handle, cursorID uintptr) syscall.Handle {
hCursor, _, _ := procLoadCursorW.Call(uintptr(instance), cursorID)
return syscall.Handle(hCursor)
}
func postQuitMessage(exitCode int32) {
procPostQuitMessage.Call(uintptr(exitCode))
}
func getModuleHandle() syscall.Handle {
handle, _, _ := procGetModuleHandleW.Call(0)
return syscall.Handle(handle)
}
func messageLoop() {
var m msg
for {
ret, _, err := procGetMessageW.Call(uintptr(unsafe.Pointer(&m)), 0, 0, 0)
switch int32(ret) {
case -1:
fmt.Printf("GetMessage failed: %v\n", err)
return
case 0:
return
default:
procTranslateMessage.Call(uintptr(unsafe.Pointer(&m)))
procDispatchMessageW.Call(uintptr(unsafe.Pointer(&m)))
}
}
}
func main() {
runtime.LockOSThread()
className := syscall.StringToUTF16Ptr("GoWinClass")
windowTitle := syscall.StringToUTF16Ptr("Go Windows API Window")
instance := getModuleHandle()
wndProcPtr := syscall.NewCallback(func(hwnd syscall.Handle, msg uint32, wParam, lParam uintptr) uintptr {
return wndProc(hwnd, msg, wParam, lParam)
})
if err := registerWindowClass(className, instance, wndProcPtr); err != nil {
fmt.Printf("RegisterClassEx failed: %v\n", err)
return
}
hwnd, err := createWindow(className, windowTitle, instance)
if err != nil {
fmt.Printf("CreateWindowEx failed: %v\n", err)
return
}
showWindow(hwnd, SW_SHOWDEFAULT)
messageLoop()