-
-
Save 17twenty/431bca5c8fc62f2f697c1cb6b26daefe to your computer and use it in GitHub Desktop.
Simple Windows GUI application written in Go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 int64, 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