-
-
Save nathan-osman/18c2e227ad00a223b61c0b3c16d452c3 to your computer and use it in GitHub Desktop.
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 | |
} | |
} | |
} |
I also received the same error:
at line 223, file main.goconstant 2147483648 overflows int32
running go1.6 windows/amd64
Changing int32
to int64
in line 53 solves this (might not be the best solution):
x, y, width, height int32
--> x, y, width, height int64
I'm sorry for off topic, but what editor is that? Looks pretty :)
@waspoza i'm pretty sure it is atom (from github) with go-plus plugin
Yup atom for sure @waspoza
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.
Pretty cool.
Using the windows api documentation, a more complex gui app is possible.
Changing
int32
toint64
in line 53 solves this (might not be the best solution):
x, y, width, height int32
-->x, y, width, height int64
x, y, width, height int32
--> x, y, width, height uint32
looks like it works too
I confirmed that both of them had worked well.
x, y, width, height int32 --> x, y, width, height uint32
x, y, width, height int32 --> x, y, width, height int64
Anyway this is just what I want to know, Cool.
Awesome! Thanks for posting this. It's working fine. The only change required was updating int32 to int64 for parameter within CreateWindow function.
I got a build error on this.
.\win32.go:223: constant 2147483648 overflows int32
. It's around"Test Window"
.