这是我编写的一个包(库):
这个包实现了一些Windows API函数的golang封装。
至于说为什么不用现成的(如walk),我会另文解释。我们还是先看一看代码吧。
第1步,注册窗口类
func MyRegisterClass(hInstance winapi.HINSTANCE) (atom uint16, err error) {
var wc winapi.WNDCLASS
wc.Style = winapi.CS_HREDRAW | winapi.CS_VREDRAW
wc.PfnWndProc = WndProc
wc.CbClsExtra = 0
wc.CbWndExtra = 0
wc.HInstance = hInstance
wc.HIcon = 0
wc.HCursor, err = winapi.LoadCursorById(0, winapi.IDC_ARROW)
if err != nil {
return
}
wc.HbrBackground = winapi.COLOR_WINDOW + 1
wc.PszMenuName = ""
wc.PszClassName = "主窗口类"
wc.HIconSmall = 0
return winapi.RegisterClass(&wc)
}
第2步,创建窗口
wnd, err := winapi.CreateWindow("主窗口类", "golang windows 编程",
winapi.WS_OVERLAPPEDWINDOW, 0,
winapi.CW_USEDEFAULT, winapi.CW_USEDEFAULT, winapi.CW_USEDEFAULT, winapi.CW_USEDEFAULT,
0, 0, Inst, 0)
if err != nil {
fmt.Println("创建窗口失败")
return 0
}
fmt.Println("创建窗口成功", wnd)
winapi.ShowWindow(wnd, winapi.SW_SHOW)
winapi.UpdateWindow(wnd)
第3步,主消息循环
var msg winapi.MSG
msg.Message = winapi.WM_QUIT + 1 // 让它不等于 winapi.WM_QUIT
for winapi.GetMessage(&msg, 0, 0, 0) > 0 {
winapi.TranslateMessage(&msg)
winapi.DispatchMessage(&msg)
}
这些步骤,与用C或C++编写Windows程序没什么两样,只不过,现在的函数是golang风格。
当然,还要在相应WM_PAINT消息的时候贴图。
func WndProc(hWnd winapi.HWND, message uint32, wParam uintptr, lParam uintptr) uintptr {
var hTemp winapi.HANDLE
switch message {
case winapi.WM_CREATE:
hTemp, _ = winapi.LoadImageByName(0, "D:\\0004.bmp",
winapi.IMAGE_BITMAP, 0, 0, winapi.LR_LOADFROMFILE)
hBitmap = winapi.HBITMAP(hTemp)
case winapi.WM_PAINT:
OnPaint(hWnd)
case winapi.WM_DESTROY:
winapi.PostQuitMessage(0)
case winapi.WM_COMMAND:
OnCommand(hWnd, wParam, lParam)
default:
return winapi.DefWindowProc(hWnd, message, wParam, lParam)
}
return 0
}
func OnPaint(hWnd winapi.HWND) {
var err error
var ps winapi.PaintStruct
hdc, err := winapi.BeginPaint(hWnd, &ps)
if err != nil {
return
}
defer winapi.EndPaint(hWnd, &ps) // defer 终于有用武之地了
// HDC mdc = CreateCompatibleDC(hdc);
mdc, err := winapi.CreateCompatibleDC(hdc)
if err != nil {
return
}
defer winapi.DeleteDC(mdc)
winapi.SelectObject(mdc, winapi.HGDIOBJ(hBitmap))
winapi.BitBlt(hdc, 0, 0, 480, 640, mdc, 0, 0, winapi.SRCCOPY)
}
效果如下:
完整代码
package main
import (
"fmt"
"runtime"
"github.com/jthmath/winapi"
)
// 全局变量
var hBitmap winapi.HBITMAP
func init() {
runtime.GOMAXPROCS(runtime.NumCPU())
}
func main() {
inst, err := winapi.GetModuleHandle("")
if err != nil {
fmt.Println("获取实例失败")
return
}
r := WinMain(inst, "", 0)
fmt.Println("WinMain函数返回", r)
}
func WinMain(Inst winapi.HINSTANCE, Cmd string, nCmdShow int32) int32 {
var err error
// 1. 注册窗口类
atom, err := MyRegisterClass(Inst)
if err != nil {
fmt.Println("注册窗口类失败")
return 0
}
fmt.Println("注册窗口类成功", atom)
// 2. 创建窗口
wnd, err := winapi.CreateWindow("主窗口类", "golang windows 编程",
winapi.WS_OVERLAPPEDWINDOW, 0,
winapi.CW_USEDEFAULT, winapi.CW_USEDEFAULT, winapi.CW_USEDEFAULT, winapi.CW_USEDEFAULT,
0, 0, Inst, 0)
if err != nil {
fmt.Println("创建窗口失败")
return 0
}
fmt.Println("创建窗口成功", wnd)
winapi.ShowWindow(wnd, winapi.SW_SHOW)
winapi.UpdateWindow(wnd)
// 3. 主消息循环
var msg winapi.MSG
msg.Message = winapi.WM_QUIT + 1 // 让它不等于 winapi.WM_QUIT
for winapi.GetMessage(&msg, 0, 0, 0) > 0 {
winapi.TranslateMessage(&msg)
winapi.DispatchMessage(&msg)
}
return int32(msg.WParam)
}
func WndProc(hWnd winapi.HWND, message uint32, wParam uintptr, lParam uintptr) uintptr {
var hTemp winapi.HANDLE
switch message {
case winapi.WM_CREATE:
hTemp, _ = winapi.LoadImageByName(0, "D:\\0004.bmp",
winapi.IMAGE_BITMAP, 0, 0, winapi.LR_LOADFROMFILE)
hBitmap = winapi.HBITMAP(hTemp)
case winapi.WM_PAINT:
OnPaint(hWnd)
case winapi.WM_DESTROY:
winapi.PostQuitMessage(0)
case winapi.WM_COMMAND:
OnCommand(hWnd, wParam, lParam)
default:
return winapi.DefWindowProc(hWnd, message, wParam, lParam)
}
return 0
}
func OnPaint(hWnd winapi.HWND) {
var err error
var ps winapi.PaintStruct
hdc, err := winapi.BeginPaint(hWnd, &ps)
if err != nil {
return
}
defer winapi.EndPaint(hWnd, &ps) // defer 终于有用武之地了
// HDC mdc = CreateCompatibleDC(hdc);
mdc, err := winapi.CreateCompatibleDC(hdc)
if err != nil {
return
}
defer winapi.DeleteDC(mdc)
winapi.SelectObject(mdc, winapi.HGDIOBJ(hBitmap))
// 这个函数的第4、5个参数分别是图片的宽、高
// 为了简便起见,我直接写在了这里
// 实际项目中当然要用过程序获取一下
winapi.BitBlt(hdc, 0, 0, 480, 640, mdc, 0, 0, winapi.SRCCOPY)
}
func OnCommand(hWnd winapi.HWND, wParam uintptr, lParam uintptr) {
// 暂时不需要特殊处理 WM_COMMAND
winapi.DefWindowProc(hWnd, winapi.WM_COMMAND, wParam, lParam)
}
func MyRegisterClass(hInstance winapi.HINSTANCE) (atom uint16, err error) {
var wc winapi.WNDCLASS
wc.Style = winapi.CS_HREDRAW | winapi.CS_VREDRAW
wc.PfnWndProc = WndProc
wc.CbClsExtra = 0
wc.CbWndExtra = 0
wc.HInstance = hInstance
wc.HIcon = 0
wc.HCursor, err = winapi.LoadCursorById(0, winapi.IDC_ARROW)
if err != nil {
return
}
wc.HbrBackground = winapi.COLOR_WINDOW + 1
wc.PszMenuName = ""
wc.PszClassName = "主窗口类"
wc.HIconSmall = 0
return winapi.RegisterClass(&wc)
}