用 Go 在 Windows 下创建窗口并显示图片

这是我编写的一个包:

github.com/jthmath/winapi

这个包实现了一些 Windows API 函数的 Go 封装。

 

先看一看代码吧。

 

第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.Menu = uint16(0)
    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 编写 Windows 程序没什么两样,只不过,现在的函数是 Go 风格。

 

当然,还要在相应 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)
}

效果如下:

200439_oFH7_2321748.jpg

 

完整代码

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.Menu = uint16(0)
    wc.PszClassName = "主窗口类"
    wc.HIconSmall = 0

    return winapi.RegisterClass(&wc)
}

转载于:https://my.oschina.net/jthmath/blog/466207

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值