Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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
}
}
}
@mrichman

This comment has been minimized.

Copy link

commented Jun 23, 2016

I got a build error on this. .\win32.go:223: constant 2147483648 overflows int32. It's around "Test Window".

image

@sgravitz

This comment has been minimized.

Copy link

commented Jun 23, 2016

I also received the same error:
at line 223, file main.goconstant 2147483648 overflows int32

running go1.6 windows/amd64

@valkiril

This comment has been minimized.

Copy link

commented Jun 23, 2016

Changing int32to int64in line 53 solves this (might not be the best solution):

x, y, width, height int32 --> x, y, width, height int64

@waspoza

This comment has been minimized.

Copy link

commented Jun 23, 2016

@mrichman

I'm sorry for off topic, but what editor is that? Looks pretty :)

@javierprovecho

This comment has been minimized.

Copy link

commented Jun 23, 2016

@waspoza i'm pretty sure it is atom (from github) with go-plus plugin

@myleshorton

This comment has been minimized.

Copy link

commented Jun 24, 2016

Yup atom for sure @waspoza

@pdouglasssi

This comment has been minimized.

Copy link

commented Jun 24, 2016

I don't know GO, but 2147483648 is 0x80000000, if an unsigned 32 bit integer (or even signed, if larger, eg. int64).

Presumably the setting of cSW_USE_DEFAULT = 0x80000000 is meant to be equivalent tocSW_USE_DEFAULT = -1 (or maybe -0 or -2147483647).

The locations it is used (specifying x, y, width, height, etc. are signed int32's (again suggesting that -1 means default).
I would assume that rather than inserting the bit pattern 0x80000000 (i.e. "10000000000000000000000000000000" where the leftmost bit is the sign flag, the checker at least (and maybe the interpreter/compiler) is either: type guessing and storing the no-type-specified constant (lines 37-39) cSW_USE_DEFAULT = 0x80000000 as either uint32 or int64 and therefore choking on assigning it to an int32 when it gets to the function, or: converting it to a number 2147483648 in some intermediary representation and then checking if that will fit into the int32 (which it won't, thus overflow).

Try changing cSW_USE_DEFAULT = 0x80000000 to cSW_USE_DEFAULT = -1 or casting the constant as an uint32.

I expect somewhere there is documentation that says something along the lines of "Values specified in hex default to unsigned int64" or "... unsigned int of the minimum size to hold the value" or something like that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.