标题
golang -- w32.go是一段使用 Windows 系统调用生成 GUI 的小例子
clq
浏览(5) +
2025-08-09 12:13:19 发表
编辑
关键字:
w32.go是一段使用 Windows 系统调用生成 GUI 的小例子。 https://gist.github.com/nathan-osman/18c2e227ad00a223b61c0b3c16d452c3 -------------------------------------------------------- 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 got a build error on this. .\win32.go:223: constant 2147483648 overflows int32. It's around "Test Window". I also received the same error: at line 223, file main.goconstant 2147483648 overflows int32 running go1.6 windows/amd64 Changing int32to int64in 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. ---- after some time the window will lost response .. Golang is scheduling the main function onto another thread. You need to lock it to the same OS thread with... runtime.LockOSThread() defer runtime.UnlockOSThread() This can be added right before the final for loop.
NEWBT官方QQ群1: 276678893
可求档连环画,漫画;询问文本处理大师等软件使用技巧;求档softhub软件下载及使用技巧.
但不可"开车",严禁国家敏感话题,不可求档涉及版权的文档软件.
验证问题说明申请入群原因即可.