//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 }