Skip to content

Instantly share code, notes, and snippets.

@sbalaji6
Forked from nathan-osman/win32.go
Created October 15, 2020 05:47
Show Gist options
  • Save sbalaji6/52742ba77b3086054787fea03fbc8904 to your computer and use it in GitHub Desktop.
Save sbalaji6/52742ba77b3086054787fea03fbc8904 to your computer and use it in GitHub Desktop.
Simple Windows GUI application written in Go
package main
import (
"log"
"syscall"
"unsafe"
)
var (
kernel32 = syscall.NewLazyDLL("kernel32.dll")
pGetModuleHandleW = kernel32.NewProc("GetModuleHandleW")
)
func getModuleHandle() (syscall.Handle, error) {
ret, _, err := pGetModuleHandleW.Call(uintptr(0))
if ret == 0 {
return 0, err
}
return syscall.Handle(ret), nil
}
var (
user32 = syscall.NewLazyDLL("user32.dll")
pCreateWindowExW = user32.NewProc("CreateWindowExW")
pDefWindowProcW = user32.NewProc("DefWindowProcW")
pDestroyWindow = user32.NewProc("DestroyWindow")
pDispatchMessageW = user32.NewProc("DispatchMessageW")
pGetMessageW = user32.NewProc("GetMessageW")
pLoadCursorW = user32.NewProc("LoadCursorW")
pPostQuitMessage = user32.NewProc("PostQuitMessage")
pRegisterClassExW = user32.NewProc("RegisterClassExW")
pTranslateMessage = user32.NewProc("TranslateMessage")
)
const (
cSW_SHOW = 5
cSW_USE_DEFAULT = 0x80000000
)
const (
cWS_MAXIMIZE_BOX = 0x00010000
cWS_MINIMIZEBOX = 0x00020000
cWS_THICKFRAME = 0x00040000
cWS_SYSMENU = 0x00080000
cWS_CAPTION = 0x00C00000
cWS_VISIBLE = 0x10000000
cWS_OVERLAPPEDWINDOW = 0x00CF0000
)
func createWindow(className, windowName string, style uint32, x, y, width, height int32, parent, menu, instance syscall.Handle) (syscall.Handle, error) {
ret, _, err := pCreateWindowExW.Call(
uintptr(0),
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(className))),
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(windowName))),
uintptr(style),
uintptr(x),
uintptr(y),
uintptr(width),
uintptr(height),
uintptr(parent),
uintptr(menu),
uintptr(instance),
uintptr(0),
)
if ret == 0 {
return 0, err
}
return syscall.Handle(ret), nil
}
const (
cWM_DESTROY = 0x0002
cWM_CLOSE = 0x0010
)
func defWindowProc(hwnd syscall.Handle, msg uint32, wparam, lparam uintptr) uintptr {
ret, _, _ := pDefWindowProcW.Call(
uintptr(hwnd),
uintptr(msg),
uintptr(wparam),
uintptr(lparam),
)
return uintptr(ret)
}
func destroyWindow(hwnd syscall.Handle) error {
ret, _, err := pDestroyWindow.Call(uintptr(hwnd))
if ret == 0 {
return err
}
return nil
}
type tPOINT struct {
x, y int32
}
type tMSG struct {
hwnd syscall.Handle
message uint32
wParam uintptr
lParam uintptr
time uint32
pt tPOINT
}
func dispatchMessage(msg *tMSG) {
pDispatchMessageW.Call(uintptr(unsafe.Pointer(msg)))
}
func getMessage(msg *tMSG, hwnd syscall.Handle, msgFilterMin, msgFilterMax uint32) (bool, error) {
ret, _, err := pGetMessageW.Call(
uintptr(unsafe.Pointer(msg)),
uintptr(hwnd),
uintptr(msgFilterMin),
uintptr(msgFilterMax),
)
if int32(ret) == -1 {
return false, err
}
return int32(ret) != 0, nil
}
const (
cIDC_ARROW = 32512
)
func loadCursorResource(cursorName uint32) (syscall.Handle, error) {
ret, _, err := pLoadCursorW.Call(
uintptr(0),
uintptr(uint16(cursorName)),
)
if ret == 0 {
return 0, err
}
return syscall.Handle(ret), nil
}
func postQuitMessage(exitCode int32) {
pPostQuitMessage.Call(uintptr(exitCode))
}
const (
cCOLOR_WINDOW = 5
)
type tWNDCLASSEXW struct {
size uint32
style uint32
wndProc uintptr
clsExtra int32
wndExtra int32
instance syscall.Handle
icon syscall.Handle
cursor syscall.Handle
background syscall.Handle
menuName *uint16
className *uint16
iconSm syscall.Handle
}
func registerClassEx(wcx *tWNDCLASSEXW) (uint16, error) {
ret, _, err := pRegisterClassExW.Call(
uintptr(unsafe.Pointer(wcx)),
)
if ret == 0 {
return 0, err
}
return uint16(ret), nil
}
func translateMessage(msg *tMSG) {
pTranslateMessage.Call(uintptr(unsafe.Pointer(msg)))
}
func main() {
className := "testClass"
instance, err := getModuleHandle()
if err != nil {
log.Println(err)
return
}
cursor, err := loadCursorResource(cIDC_ARROW)
if err != nil {
log.Println(err)
return
}
fn := func(hwnd syscall.Handle, msg uint32, wparam, lparam uintptr) uintptr {
switch msg {
case cWM_CLOSE:
destroyWindow(hwnd)
case cWM_DESTROY:
postQuitMessage(0)
default:
ret := defWindowProc(hwnd, msg, wparam, lparam)
return ret
}
return 0
}
wcx := tWNDCLASSEXW{
wndProc: syscall.NewCallback(fn),
instance: instance,
cursor: cursor,
background: cCOLOR_WINDOW + 1,
className: syscall.StringToUTF16Ptr(className),
}
wcx.size = uint32(unsafe.Sizeof(wcx))
if _, err = registerClassEx(&wcx); err != nil {
log.Println(err)
return
}
_, err = createWindow(
className,
"Test Window",
cWS_VISIBLE|cWS_OVERLAPPEDWINDOW,
cSW_USE_DEFAULT,
cSW_USE_DEFAULT,
cSW_USE_DEFAULT,
cSW_USE_DEFAULT,
0,
0,
instance,
)
if err != nil {
log.Println(err)
return
}
for {
msg := tMSG{}
gotMessage, err := getMessage(&msg, 0, 0, 0)
if err != nil {
log.Println(err)
return
}
if gotMessage {
translateMessage(&msg)
dispatchMessage(&msg)
} else {
break
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment