mirror of
https://github.com/fumiama/go-web-wrapper.git
synced 2026-06-05 00:32:43 +08:00
262 lines
6.7 KiB
Go
262 lines
6.7 KiB
Go
//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+1(6)
|
||
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
|
||
}
|