1
0
mirror of https://github.com/fumiama/go-web-wrapper.git synced 2026-06-05 00:32:43 +08:00
Files
go-web-wrapper/main_windows.go
源文雨 28dca5ac1e init
2025-07-16 22:59:58 +09:00

262 lines
6.7 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//go:build windows
package main
import (
"runtime"
"syscall"
"unsafe"
)
func main() {
runtime.LockOSThread()
// ① 隐藏控制台窗口(如果存在)
hConsole, _, _ := procGetConsoleWindow.Call()
if hConsole != 0 {
procShowWindow.Call(hConsole, SW_HIDE)
}
// ② 获取当前模块句柄
hInstance, _, _ = procGetModuleHandleW.Call(0)
// ③ 注册窗口类
className := syscall.StringToUTF16Ptr("MyWindowClass")
wndClass := WNDCLASSEX{
CbSize: uint32(unsafe.Sizeof(WNDCLASSEX{})),
Style: 0,
LpfnWndProc: syscall.NewCallback(WndProc),
CbClsExtra: 0,
CbWndExtra: 0,
HInstance: hInstance,
HIcon: 0,
HCursor: 0,
// 背景色使用 COLOR_WINDOW+16
HbrBackground: uintptr(6),
LpszMenuName: nil,
LpszClassName: className,
HIconSm: 0,
}
ret, _, err := procRegisterClassExW.Call(uintptr(unsafe.Pointer(&wndClass)))
if ret == 0 {
panic("RegisterClassExW failed: " + err.Error())
}
// ④ 创建窗口
windowTitle := syscall.StringToUTF16Ptr(WindowTitle)
hWnd, _, err := procCreateWindowExW.Call(
0,
uintptr(unsafe.Pointer(className)),
uintptr(unsafe.Pointer(windowTitle)),
WS_OVERLAPPEDWINDOW&^WS_THICKFRAME, // 移除 WS_THICKFRAME 样式
100, 100, 400, 150, // 窗口位置和大小
0, 0,
hInstance,
0,
)
if hWnd == 0 {
panic("CreateWindowExW failed: " + err.Error())
}
// ⑤ 创建控件:文本框和按钮
createControls(hWnd)
// 显示并更新窗口
procShowWindow.Call(hWnd, SW_SHOW)
procUpdateWindow.Call(hWnd)
// ⑥ 消息循环
var msg MSG
for {
ret, _, _ := procGetMessageW.Call(uintptr(unsafe.Pointer(&msg)), 0, 0, 0)
if ret == 0 { // 收到 WM_QUIT 消息
break
}
procDispatchMessageW.Call(uintptr(unsafe.Pointer(&msg)))
}
}
func createControls(parent uintptr) {
// 创建宋体字体
font := createFont("宋体")
// 创建一个不可编辑的文本框,显示 "正在展示"
editClass := syscall.StringToUTF16Ptr("EDIT")
text := syscall.StringToUTF16Ptr("正在展示: " + Endpoint)
editHWnd, _, _ := procCreateWindowExW.Call(
0,
uintptr(unsafe.Pointer(editClass)),
uintptr(unsafe.Pointer(text)),
uintptr(WS_CHILD|WS_VISIBLE|ES_CENTER),
10, 20, 370, 40,
parent,
0,
hInstance,
0,
)
// 设置宋体字体
procSendMessageW.Call(editHWnd, WM_SETFONT, font, 1)
// 创建按钮控件,显示“按钮”,并指定控制 ID 为 ID_BUTTON_OPEN
buttonClass := syscall.StringToUTF16Ptr("BUTTON")
buttonText := syscall.StringToUTF16Ptr("打开页面")
buttonHWnd, _, _ := procCreateWindowExW.Call(
0,
uintptr(unsafe.Pointer(buttonClass)),
uintptr(unsafe.Pointer(buttonText)),
uintptr(WS_CHILD|WS_VISIBLE|BS_DEFPUSHBUTTON),
10, 70, 365, 30,
parent,
uintptr(ID_BUTTON_OPEN), // 这里设置按钮的ID
hInstance,
0,
)
// 设置宋体字体
procSendMessageW.Call(buttonHWnd, WM_SETFONT, font, 1)
}
// 窗口和控件样式、消息常量
const (
WS_OVERLAPPEDWINDOW = 0x00CF0000 // 标准窗口样式(包含标题栏、系统菜单、可调整大小等)
WS_CHILD = 0x40000000 // 子窗口样式
WS_VISIBLE = 0x10000000 // 可见样式
WS_BORDER = 0x00800000 // 边框样式
WS_CAPTION = 0x00C00000 // 标题栏样式
WS_SYSMENU = 0x00080000 // 系统菜单样式
WS_THICKFRAME = 0x00040000 // 可调整大小的边框样式
BS_DEFPUSHBUTTON = 0x00000001 // 默认按钮样式
ES_CENTER = 0x00000001
SW_HIDE = 0
SW_SHOW = 5
WM_DESTROY = 0x0002
WM_COMMAND = 0x0111
WM_SETFONT = 0x0030
)
const (
// 定义一个退出按钮的ID
ID_BUTTON_OPEN = 1001
)
// 结构体定义,与 WIN32 相同
type POINT struct {
X int32
Y int32
}
type MSG struct {
Hwnd uintptr
Message uint32
WParam uintptr
LParam uintptr
Time uint32
Pt POINT
}
type WNDCLASSEX struct {
CbSize uint32
Style uint32
LpfnWndProc uintptr
CbClsExtra int32
CbWndExtra int32
HInstance uintptr
HIcon uintptr
HCursor uintptr
HbrBackground uintptr
LpszMenuName *uint16
LpszClassName *uint16
HIconSm uintptr
}
var (
// 加载 DLL
user32 = syscall.NewLazyDLL("user32.dll")
kernel32 = syscall.NewLazyDLL("kernel32.dll")
shell32 = syscall.NewLazyDLL("shell32.dll")
gdi32 = syscall.NewLazyDLL("gdi32.dll")
// 接口函数
procDefWindowProcW = user32.NewProc("DefWindowProcW")
procDispatchMessageW = user32.NewProc("DispatchMessageW")
procGetMessageW = user32.NewProc("GetMessageW")
procRegisterClassExW = user32.NewProc("RegisterClassExW")
procCreateWindowExW = user32.NewProc("CreateWindowExW")
procShowWindow = user32.NewProc("ShowWindow")
procUpdateWindow = user32.NewProc("UpdateWindow")
procPostQuitMessage = user32.NewProc("PostQuitMessage")
procSendMessageW = user32.NewProc("SendMessageW")
procGetModuleHandleW = kernel32.NewProc("GetModuleHandleW")
procGetConsoleWindow = kernel32.NewProc("GetConsoleWindow")
shellExecute = shell32.NewProc("ShellExecuteW")
procCreateFontIndirectW = gdi32.NewProc("CreateFontIndirectW")
)
var hInstance uintptr
// 窗口过程函数,处理窗口消息
func WndProc(hWnd uintptr, msg uint32, wParam, lParam uintptr) uintptr {
switch msg {
case WM_COMMAND:
// 当点击控件时wParam 的低 16 位为控件 ID
if uint16(wParam) == ID_BUTTON_OPEN {
// 调用 ShellExecuteW 打开默认浏览器
// 第一个参数为 0 表示没有窗口句柄,最后一个参数指定需要打开的 URL
url := "http://" + Endpoint
shellExecute.Call(0,
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr("open"))),
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(url))),
0,
0,
1) // 1 表示普通窗口打开
return 0
}
case WM_DESTROY:
procPostQuitMessage.Call(0)
return 0
default:
ret, _, _ := procDefWindowProcW.Call(hWnd, uintptr(msg), wParam, lParam)
return ret
}
return 0
}
// 创建指定字体(如宋体)
func createFont(fontName string) uintptr {
font := &struct {
Height int32
Width int32
Escapement int32
Orientation int32
Weight int32
Italic byte
Underline byte
StrikeOut byte
CharSet byte
OutPrecision byte
ClipPrecision byte
Quality byte
PitchAndFamily byte
FaceName [32]uint16
}{}
font.Height = 20 // 字体高度
font.Weight = 800 // 字体粗细
font.CharSet = 1 // 默认字符集
font.OutPrecision = 4 // 输出精度
font.ClipPrecision = 2 // 裁剪精度
font.Quality = 1 // 质量
font.PitchAndFamily = 0x31 // 字体类型
copy(font.FaceName[:], syscall.StringToUTF16(fontName))
hFont, _, _ := procCreateFontIndirectW.Call(uintptr(unsafe.Pointer(font)))
return hFont
}