-
-
Save jan-bar/13f2ef1e671049db92768560bb106824 to your computer and use it in GitHub Desktop.
Simple Windows GUI application written in Go
This file contains hidden or 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 | |
} | |
} | |
} |
This file contains hidden or 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 ( | |
"fmt" | |
"os" | |
"syscall" | |
"unsafe" | |
) | |
func main() { | |
err := cc() | |
if err != nil { | |
panic(err) | |
} | |
} | |
/* | |
https://github.com/bbigras/go-windows-session-notifications | |
gopath\pkg\mod\golang.org\x\[email protected]\shiny\driver\internal\win32\zsyscall_windows.go | |
https://learn.microsoft.com/zh-cn/windows/console/registering-a-control-handler-function | |
*/ | |
func cc() error { | |
nm, err := syscall.UTF16PtrFromString("janbar_window") | |
if err != nil { | |
return err | |
} | |
wc := WndClass{ | |
LpSzClassName: nm, | |
LpFnWndProc: syscall.NewCallback(func(hWnd syscall.Handle, msg uint32, wParam, lParam uintptr) (rc uintptr) { | |
switch msg { | |
case 0x11: // WM_QUERY_END_SESSION | |
case 0x2B1: // WM_WTS_SESSION_CHANGE | |
default: | |
return DefWindowProc(hWnd, msg, wParam, lParam) | |
} | |
fw, _ := os.OpenFile("win.txt", os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0o666) | |
fmt.Fprintf(fw, "%X,%X,%X\n", msg, wParam, lParam) | |
fw.Close() | |
return 0 | |
}), | |
} | |
_, err = RegisterClass(&wc) | |
if err != nil { | |
return err | |
} | |
const CW_USEDEFAULT int32 = 0x80000000 - 0x100000000 | |
hw, err := CreateWindowEx(0, nm, nm, 0, | |
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, | |
0, 0, 0, 0) | |
if err != nil { | |
return err | |
} | |
_ = hw | |
var msg Msg | |
for { | |
a, err := GetMessage(&msg, 0, 0, 0) | |
if err != nil { | |
return err | |
} | |
if a > 0 { | |
TranslateMessage(&msg) | |
DispatchMessage(&msg) | |
} | |
} | |
return nil | |
} | |
var ( | |
modUser32 = syscall.NewLazyDLL("user32.dll") | |
procRegisterClassW = modUser32.NewProc("RegisterClassW") | |
procCreateWindowExW = modUser32.NewProc("CreateWindowExW") | |
procGetMessageW = modUser32.NewProc("GetMessageW") | |
procTranslateMessage = modUser32.NewProc("TranslateMessage") | |
procDispatchMessageW = modUser32.NewProc("DispatchMessageW") | |
procDefWindowProcW = modUser32.NewProc("DefWindowProcW") | |
) | |
type WndClass struct { | |
Style uint32 | |
LpFnWndProc uintptr | |
CbClsExtra int32 | |
CbWndExtra int32 | |
HInstance syscall.Handle | |
HIcon syscall.Handle | |
HCursor syscall.Handle | |
HbrBackground syscall.Handle | |
LpSzMenuName *uint16 | |
LpSzClassName *uint16 | |
} | |
func RegisterClass(wc *WndClass) (atom uint16, err error) { | |
r0, _, e1 := syscall.SyscallN(procRegisterClassW.Addr(), | |
uintptr(unsafe.Pointer(wc))) | |
atom = uint16(r0) | |
if atom == 0 { | |
if e1 != 0 { | |
err = e1 | |
} else { | |
err = syscall.EINVAL | |
} | |
} | |
return | |
} | |
func CreateWindowEx(exStyle uint32, className *uint16, windowText *uint16, | |
style uint32, x int32, y int32, width int32, height int32, | |
parent syscall.Handle, menu syscall.Handle, hInstance syscall.Handle, | |
lpParam uintptr) (hWnd syscall.Handle, err error) { | |
r0, _, e1 := syscall.SyscallN(procCreateWindowExW.Addr(), | |
uintptr(exStyle), uintptr(unsafe.Pointer(className)), | |
uintptr(unsafe.Pointer(windowText)), uintptr(style), | |
uintptr(x), uintptr(y), uintptr(width), uintptr(height), | |
uintptr(parent), uintptr(menu), uintptr(hInstance), lpParam) | |
hWnd = syscall.Handle(r0) | |
if hWnd == 0 { | |
if e1 != 0 { | |
err = e1 | |
} else { | |
err = syscall.EINVAL | |
} | |
} | |
return | |
} | |
type ( | |
Point struct { | |
X int32 | |
Y int32 | |
} | |
Msg struct { | |
HWnd syscall.Handle | |
Message uint32 | |
WParam uintptr | |
LParam uintptr | |
Time uint32 | |
Pt Point | |
} | |
) | |
func GetMessage(msg *Msg, hWnd syscall.Handle, | |
msgFilterMin uint32, msgFilterMax uint32) (ret int32, err error) { | |
r0, _, e1 := syscall.SyscallN(procGetMessageW.Addr(), | |
uintptr(unsafe.Pointer(msg)), uintptr(hWnd), | |
uintptr(msgFilterMin), uintptr(msgFilterMax)) | |
ret = int32(r0) | |
if ret == -1 { | |
if e1 != 0 { | |
err = e1 | |
} else { | |
err = syscall.EINVAL | |
} | |
} | |
return | |
} | |
func TranslateMessage(msg *Msg) (done bool) { | |
r0, _, _ := syscall.SyscallN(procTranslateMessage.Addr(), | |
uintptr(unsafe.Pointer(msg))) | |
done = r0 != 0 | |
return | |
} | |
func DispatchMessage(msg *Msg) (ret int32) { | |
r0, _, _ := syscall.SyscallN(procDispatchMessageW.Addr(), | |
uintptr(unsafe.Pointer(msg))) | |
ret = int32(r0) | |
return | |
} | |
func DefWindowProc(hWnd syscall.Handle, uMsg uint32, | |
wParam, lParam uintptr) (lResult uintptr) { | |
lResult, _, _ = syscall.SyscallN(procDefWindowProcW.Addr(), | |
uintptr(hWnd), uintptr(uMsg), wParam, lParam) | |
return | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment