1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: 2024 The Ebitengine Authors
3
4package main
5
6import (
7 "runtime"
8 "structs"
9 "syscall"
10 "unsafe"
11
12 "github.com/ebitengine/purego"
13)
14
15const (
16 WS_OVERLAPPEDWINDOW = 0x00000000 | 0x00C00000 | 0x00080000 | 0x00040000 | 0x00020000 | 0x00010000
17 CW_USEDEFAULT = ^0x7fffffff
18 SW_SHOW = 5
19 WM_DESTROY = 2
20)
21
22type (
23 ATOM uint16
24 HANDLE uintptr
25 HINSTANCE HANDLE
26 HICON HANDLE
27 HCURSOR HANDLE
28 HBRUSH HANDLE
29 HWND HANDLE
30 HMENU HANDLE
31)
32
33type WNDCLASSEX struct {
34 _ structs.HostLayout
35 Size uint32
36 Style uint32
37 WndProc uintptr
38 ClsExtra int32
39 WndExtra int32
40 Instance HINSTANCE
41 Icon HICON
42 Cursor HCURSOR
43 Background HBRUSH
44 MenuName *uint16
45 ClassName *uint16
46 IconSm HICON
47}
48
49type RECT struct {
50 _ structs.HostLayout
51 Left, Top, Right, Bottom int32
52}
53
54type POINT struct {
55 _ structs.HostLayout
56 X, Y int32
57}
58
59type MSG struct {
60 _ structs.HostLayout
61 Hwnd HWND
62 Message uint32
63 WParam uintptr
64 LParam uintptr
65 Time uint32
66 Pt POINT
67}
68
69var (
70 GetModuleHandle func(modulename *uint16) HINSTANCE
71 RegisterClassEx func(w *WNDCLASSEX) ATOM
72 CreateWindowEx func(exStyle uint, className, windowName *uint16,
73 style uint, x, y, width, height int, parent HWND, menu HMENU,
74 instance HINSTANCE, param unsafe.Pointer) HWND
75 AdjustWindowRect func(rect *RECT, style uint, menu bool) bool
76 ShowWindow func(hwnd HWND, cmdshow int) bool
77 GetMessage func(msg *MSG, hwnd HWND, msgFilterMin, msgFilterMax uint32) int
78 TranslateMessage func(msg *MSG) bool
79 DispatchMessage func(msg *MSG) uintptr
80 DefWindowProc func(hwnd HWND, msg uint32, wParam, lParam uintptr) uintptr
81 PostQuitMessage func(exitCode int)
82)
83
84func init() {
85 // Use [syscall.NewLazyDLL] here to avoid external dependencies (#270).
86 // For actual use cases, [golang.org/x/sys/windows.NewLazySystemDLL] is recommended.
87 kernel32 := syscall.NewLazyDLL("kernel32.dll").Handle()
88 purego.RegisterLibFunc(&GetModuleHandle, kernel32, "GetModuleHandleW")
89
90 // Use [syscall.NewLazyDLL] here to avoid external dependencies (#270).
91 // For actual use cases, [golang.org/x/sys/windows.NewLazySystemDLL] is recommended.
92 user32 := syscall.NewLazyDLL("user32.dll").Handle()
93 purego.RegisterLibFunc(&RegisterClassEx, user32, "RegisterClassExW")
94 purego.RegisterLibFunc(&CreateWindowEx, user32, "CreateWindowExW")
95 purego.RegisterLibFunc(&AdjustWindowRect, user32, "AdjustWindowRect")
96 purego.RegisterLibFunc(&ShowWindow, user32, "ShowWindow")
97 purego.RegisterLibFunc(&GetMessage, user32, "GetMessageW")
98 purego.RegisterLibFunc(&TranslateMessage, user32, "TranslateMessage")
99 purego.RegisterLibFunc(&DispatchMessage, user32, "DispatchMessageW")
100 purego.RegisterLibFunc(&DefWindowProc, user32, "DefWindowProcW")
101 purego.RegisterLibFunc(&PostQuitMessage, user32, "PostQuitMessage")
102
103 runtime.LockOSThread()
104}
105
106func main() {
107 className, err := syscall.UTF16PtrFromString("Sample Window Class")
108 if err != nil {
109 panic(err)
110 }
111 inst := GetModuleHandle(className)
112
113 wc := WNDCLASSEX{
114 Size: uint32(unsafe.Sizeof(WNDCLASSEX{})),
115 WndProc: syscall.NewCallback(wndProc),
116 Instance: inst,
117 ClassName: className,
118 }
119
120 RegisterClassEx(&wc)
121
122 wr := RECT{
123 Left: 0,
124 Top: 0,
125 Right: 320,
126 Bottom: 240,
127 }
128 title, err := syscall.UTF16PtrFromString("My Title")
129 if err != nil {
130 panic(err)
131 }
132 AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, false)
133 hwnd := CreateWindowEx(
134 0, className,
135 title,
136 WS_OVERLAPPEDWINDOW,
137 CW_USEDEFAULT, CW_USEDEFAULT, int(wr.Right-wr.Left), int(wr.Bottom-wr.Top),
138 0, 0, inst, nil,
139 )
140 if hwnd == 0 {
141 panic(syscall.GetLastError())
142 }
143
144 ShowWindow(hwnd, SW_SHOW)
145
146 var msg MSG
147 for GetMessage(&msg, 0, 0, 0) != 0 {
148 TranslateMessage(&msg)
149 DispatchMessage(&msg)
150 }
151}
152
153func wndProc(hwnd HWND, msg uint32, wparam, lparam uintptr) uintptr {
154 switch msg {
155 case WM_DESTROY:
156 PostQuitMessage(0)
157 }
158 return DefWindowProc(hwnd, msg, wparam, lparam)
159}