登录 用户中心() [退出] 后台管理 注册
   
您的位置: 首页 >> CLQ工作室开源代码 >> 主题: golang -- w32.go是一段使用 Windows 系统调用生成 GUI 的小例子     [回主站]     [分站链接]
标题
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.






总数:0 页次:1/0 首页 尾页  
总数:0 页次:1/0 首页 尾页  


所在合集/目录



发表评论:
文本/html模式切换 插入图片 文本/html模式切换


附件:



NEWBT官方QQ群1: 276678893
可求档连环画,漫画;询问文本处理大师等软件使用技巧;求档softhub软件下载及使用技巧.
但不可"开车",严禁国家敏感话题,不可求档涉及版权的文档软件.
验证问题说明申请入群原因即可.

Copyright © 2005-2020 clq, All Rights Reserved
版权所有
桂ICP备15002303号-1